{"id":17685654,"url":"https://github.com/ghaiklor/ghaiklor-os-gcc","last_synced_at":"2025-04-28T15:54:37.718Z","repository":{"id":66126853,"uuid":"58062244","full_name":"ghaiklor/ghaiklor-os-gcc","owner":"ghaiklor","description":"Simple operating system with its own bootloader, drivers for screen and keyboard, libc (for educational purposes)","archived":false,"fork":false,"pushed_at":"2016-06-02T07:50:47.000Z","size":107,"stargazers_count":121,"open_issues_count":2,"forks_count":16,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-28T15:54:32.700Z","etag":null,"topics":["assembly","assembly-files","boot-sector","boot-signature","cpu","driver","drivers","gcc","ghaiklor-os-gcc","kernel","kernel-entry","os"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ghaiklor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-04T15:16:14.000Z","updated_at":"2025-01-20T00:28:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"b17ffb44-bc87-49d5-9b03-f9102627cc57","html_url":"https://github.com/ghaiklor/ghaiklor-os-gcc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fghaiklor-os-gcc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fghaiklor-os-gcc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fghaiklor-os-gcc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghaiklor%2Fghaiklor-os-gcc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ghaiklor","download_url":"https://codeload.github.com/ghaiklor/ghaiklor-os-gcc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251342718,"owners_count":21574243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembly","assembly-files","boot-sector","boot-signature","cpu","driver","drivers","gcc","ghaiklor-os-gcc","kernel","kernel-entry","os"],"created_at":"2024-10-24T10:28:36.895Z","updated_at":"2025-04-28T15:54:37.684Z","avatar_url":"https://github.com/ghaiklor.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ghaiklor-os-gcc\n\nThis is not a **REAL** operation system.\nIt's just a simple operation system created in educational purposes.\n\nThe main goal I'm following is to learn how OS is working from the ground up.\nStarting from the own boot sector, hardware and software interrupts, own drivers.\n\nRepository is suffixed with gcc because I'm planning to write another one simple OS with Rust.\nSo, I hope, there will be _ghaiklor-os-gcc_ and _ghaiklor-os-rustc_.\n\n## Demo\n\n| Hello, World                                                                                                |\n| ----------------------------------------------------------------------------------------------------------- |\n| ![OS](https://cloud.githubusercontent.com/assets/3625244/15702861/fcdd8794-27ea-11e6-8e42-1700f8ba3905.gif) |\n\n## Roadmap\n\n- Boot sector:\n  - Reads the kernel from disk into memory (**DONE**)\n  - Describes Global Descriptor Table (**DONE**)\n  - Switches to 32-bit Protected Mode (**DONE**)\n  - Checks if CPU support 64-bit Long Mode and switches into (**DONE**)\n  - In case, if 64-bit Long Mode isn't supported, fallback into 32-bit (**DONE**)\n  - Gives execution to kernel (**DONE**)\n- Kernel:\n  - Kernel entry in assembly, which calls extern kernel_main() in C (**DONE**)\n  - Low-level I/O functions: _port_byte_in_, _port_byte_out_ and similar (**DONE**)\n  - Interrupt Descriptor Table (**DONE**)\n  - Interrupt Service Routines and their mapping to IDT (**DONE**)\n  - Handling Interrupt Requests (IRQ) (**DONE**)\n  - Handling IRQ0 of Programmable Interval Timer (**DONE**)\n- Drivers:\n  - _screen_ driver implements printing to the screen (**DONE**)\n  - _keyboard_ driver listen for IRQ1 interrupt and handle it (**DONE**)\n- Shell:\n  - Implement simple echo shell (**DONE**)\n\n## Project Structure\n\n- [__boot__](./boot) - source code related to boot sector\n- [__cpu__](./cpu) - source code related to specific CPU architecture\n- [__drivers__](./drivers) - source code related to drivers implementation\n- [__include__](./include) - header files for common cases\n- [__kernel__](./kernel) - source code related to kernel\n- [__libc__](./libc) - source code of common libraries\n\n## Makefile\n\n_ghaiklor-os-gcc_ consists of two files in raw binary format: _boot.bin_ and _kernel.bin_.\nThey are located in _boot/boot.bin_ and _kernel/kernel.bin_ accordingly after compile.\n\n_boot.bin_ is compiled via _nasm_.\nMakefile takes _boot/boot.asm_ and calls `nasm boot/boot.asm -f bin -o boot/boot.bin`.\n_nasm_ handles includes from sub-folders itself, so __all__ assembly files will be compiled to binary.\nNothing else, simple.\n\n_kernel.bin_ is compiled via cross-compiler _gcc_ and _ld_ that you must install.\nTake a look into [Development Environment](#development-environment) section.\nAfter cross-compiler is installed, we can take sources from _cpu_, _drivers_, _include_, _kernel_ and _libc_ folders recursively.\nAll *.c* files are compiled via `gcc`.\nCompiled object files are used for compiling _kernel.bin_ then, via _ld_ -\n`ld -o kernel/kernel.bin -Ttext 0x1000 \u003cOBJ_FILES\u003e --oformat binary`.\n\n_os-image.bin_ is ~~compiled~~ concatenate of _boot.bin_ and _kernel.bin_.\nEasily achieved with `cat boot/boot.bin kernel/kernel.bin \u003e os-image.bin`.\n\n## Development Environment\n\nI'd wrote `bootstrap.sh` script, that you can run.\nIt will install all the needed dependencies for your host machine.\n\n```shell\nbash bootstrap.sh\n```\n\n## How it works?\n\n### BIOS\n\nWhen a computer is switched on or reset, it runs through a series of diagnostics called POST - Power-On-Self-Test.\nThis sequence culminates in locating a bootable device, such as a floppy, cdrom or a hard disk.\n\nA device is bootable if it carries a boot sector with the byte sequence `0x55`, `0xAA` in bytes 511 and 512 respectively.\nWhen the BIOS finds such a boot sector, it is loaded into memory at `0x0000:0x7C00`.\n\n### Boot Sector\n\n#### Boot Signature\n\nA simple implementation of bootable device:\n\n```asm\njmp $\n\ntimes 510 - ($-$$) db 0\ndw 0xAA55\n```\n\n`$ - $$` results in `CURRENT_POINTER - START_POINTER`.\nThat way we are calculating how long our boot record is.\nAfterwards, we are substract 510 from it and filling with zeros, getting the 512 bytes boot record with boot sector signature.\n\nFor instance, we have `$ - $$` equal to 100.\nSo, we have `510 - 100 = 410` free bytes.\nWe are filling these 410 bytes with zeros.\nAnd the last two bytes 511 and 512 are bootable signature which we are filling with `dw 0xAA55`.\n\nDone! We have our bootable device and can replace our `jmp $` with any code you like.\n\n[Boot Sector Implementation](./boot/boot.asm)\n\n#### Real Mode\n\nAt the beginning our code is running in Real Mode.\n\nReal Mode is a simplistic 16-bit mode that is present on all x86 processors.\nReal Mode was the first x86 mode design and was used by many early operating systems.\nFor compatibility purposes, all x86 processors begin execution in Real Mode.\n\nWhat's bad and good in Real Mode?\n\nCons\n- Less than 1 MB of RAM is available for use.\n- There is no hardware-based memory protection (GDT), nor virtual memory.\n- There is no built in security mechanisms to protect against buggy or malicious applications.\n- The default CPU operand length is only 16 bits.\n- The memory addressing modes provided are more restrictive than other CPU modes.\n- Accessing more than 64k requires the use of segment register that are difficult to work with.\n\nPros\n- The BIOS installs device drivers to control devices and handle interrupt.\n- BIOS functions provide operating systems with a advanced collection of low level API functions.\n- Memory access is faster due to the lack of descriptor tables to check and smaller registers.\n\nDue to the many limitations and problems that Real Mode has, we need to switch to Protected Mode.\n\n#### Protected Mode\n\nProtected Mode is the main operating mode of modern Intel processors since the 80286.\nIt allows working with several virtual address spaces, each of which has a maximum of 4 GB of addressable memory.\n\nSince CPU initialized by the BIOS starts in Real Mode, switching to Protected Mode prevents you from using most of the BIOS interrupts.\nBefore switching to Protected Mode, you have to disable interrupts, including NMI, enable A20 line and load Global Descriptor Table.\n\nAlgorithm for switching to Protected Mode:\n\n```asm\ncli\nlgdt [gdt_descriptor]\nmov eax, cr0\nor eax, 0x1\nmov cr0, eax\njmp CODE_SEG:init_pm\n```\n\n[Implementation for switching to PM](./boot/pm/switch_to_pm.asm)\n\n[Global Descriptor Table](./boot/pm/gdt.asm)\n\nBut, we can go further...\n\n#### Long Mode\n\nWhat is long mode and why set it up?\n\nSince the introduction of the x86-64 processors a new mode has been introduced as well, which is called Long Mode.\nLong Mode basically consists out of two sub modes which are the actual 64-bit mode and compatibility mode (32-bit).\n\nWhat we are interested in is simply the 64-bit mode as this mode provides a lot of new features such as:\n\n- Registers being extended to 64-bit (rax, rcx, rdx, etc...);\n- Eight new general-purpose registers (r8 - r15);\n- Eight new multimedia registers (xmm8 - xmm15);\n\nBefore switching into Long Mode, we **must** check if CPU supports this mode.\nIn case, if CPU doesn't support Long Mode, we need to fallback to Protected Mode.\n\n[Detect if Long Mode supports](./boot/lm/detect_lm.asm)\n\n[If so, switch to Long Mode](./boot/lm/switch_to_lm.asm)\n\n#### Loading the Kernel\n\nAll these modes are great, but we can't write an operating system in 512 bytes.\nSo, our boot sector **must** know how to load our compiled kernel from hard disk.\n\nWhen we are in Real Mode, we can use BIOS interrupts for reading from the disk.\nIn our case, is `INT 13,2 - Read Disk Sectors`.\n\nHow to use it?\n\n```asm\n;; al = number of sectors to read (1 - 128)\n;; ch = track/cylinder number\n;; cl = sector number\n;; dh = head number\n;; dl = drive number\n;; bx = pointer to buffer\nmov ah, 0x02\nmov al, 15\nmov ch, 0x00\nmov cl, 0x02\nmov dh, 0x00\nmov dl, 0\nmov bx, KERNEL_OFFSET_IN_MEMORY\nint 0x13\n```\n\nThis code results into reading from hard disk into address `KERNEL_OFFSET_IN_MEMORY`.\nIt reads 15 sectors starting from the second one and stores it by address `KERNEL_OFFSET_IN_MEMORY`.\n\nSince our compiled OS image is a concatenation of boot sector and kernel,\nand we know that our boot sector is 512 bytes, we can be sure, that our kernel starts in second sector.\n\nWhen reading is successfully completed, we can call instruction at our `KERNEL_OFFSET_IN_MEMORY` and give execution to the kernel.\n\n```asm\ncall KERNEL_OFFSET_IN_MEMORY\njmp $\n```\n\n[Implementation for Disk Read](./boot/disk/disk_read.asm)\n\n#### Summary about Boot Sector\n\nWe can draw a line here about our boot sector.\nThe flow is simple:\n\n- BIOS detects our image as bootable since [boot signature](#boot-signature);\n- Load the kernel from disk into memory via [INT 13,2](#loading-the-kernel);\n- Switch to [Protected Mode](#protected-mode);\n- Check if we can switch into [Long Mode](#long-mode) with fallback into Protected Mode;\n- Give execution to kernel via simple `call` instruction;\n\nAt this step, our boot sector finished its work and starts working with the kernel.\n\nYou can navigate through [boot sources](./boot) and try to get how it works.\n\n### Kernel\n\n#### Kernel Entry in Assembly\n\nWhen we are calling instruction by address, we can got a few problems.\nWe can't sure, that instruction by address is a `kernel_main()`.\nSolution is simple.\n\nWe can write a sub-routine that is attached to the start of the kernel code.\nThis sub-routine call extern function of our kernel - `kernel_main()`.\nWhen object files will be linked together, this call will be translated into call of our `kernel_main()`.\n\n```asm\nglobal _start\n\n[bits 32]\n[extern kernel_main]\n\n_start:\n  call kernel_main\n  jmp $\n```\n\n[Kernel Entry Implementation](./boot/kernel_entry.asm)\n\n#### Kernel Entry in C\n\nAt this step, we have an entry-point to our `kernel_main()` method.\nAnd that is our entry-point for entire kernel.\n\nI think, is boring to explain how `#include` works and what happens in our `kernel_main()`.\nYou easily can follow the methods that I'm calling from it.\n\n[Kernel Entry in C](./kernel/kernel.c)\n\n### Building\n\n#### Building the Boot Sector\n\nThat is the simplest part.\n\nWe need to build `boot/boot.bin` image in raw binary format.\nTo do so, we call `nasm` assembler with special flags.\n\n```shell\nnasm boot/boot.asm -f bin -o boot/boot.bin\n```\n\nIt results into raw binary format that you can run via qemu.\n\nAt this step, we have working compiled boot sector.\n\n#### Building the Kernel\n\nWe need to build the all sources from all folders recursively, except the `boot` folder.\n\nAll C files are compiled to object files via `gcc` and Assembly files via `nasm`:\n\n```shell\ngcc -g -ffreestanding -Wall -Wextra -fno-exceptions -m32 -std=c11 -c \u003cSOURCE\u003e -o \u003cOBJ_FILE\u003e\nnasm \u003cSOURCE\u003e -f elf -o \u003cOBJ_FILE\u003e\n```\n\nIt results into all needed object files for linking to raw binary format.\nAll what's left to do is link them together via `ld`:\n\n```shell\nld -o kernel/kernel.bin -Ttext 0x1000 kernel/kernel_entry.o \u003cOBJ_FILES\u003e --oformat binary\n```\n\nNote that `kernel/kernel_entry.o` at first place since we have an issue with calling the `kernel_main()`.\nThis way, we guarantee that first instruction will be called from our `boot/kernel_entry.asm`.\n\nAfter all, we have compiled kernel image in raw binary format.\n\n#### Building the OS image\n\nSince, our boot sector and kernel is raw binary formats, we can just concatenate them.\n\n```shell\ncat boot/boot.bin kernel/kernel.bin \u003e os-image.bin\n```\n\nNow, we can run `os-image.bin` via `qemu-system-i386`.\nBIOS trying to locate bootable sector, find out our `boot/boot.bin` and sees signature.\nStarts executing our Assembly code at `boot/boot.bin` which loads our `kernel/kernel.bin` via INT 13,2 into memory and executes it.\n\nThat's how it all works together.\nFeel free to navigate through the [project](#project-structure), thanks :smiley_cat:\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 Eugene Obrezkov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghaiklor%2Fghaiklor-os-gcc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fghaiklor%2Fghaiklor-os-gcc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghaiklor%2Fghaiklor-os-gcc/lists"}