{"id":51157122,"url":"https://github.com/mohnkhan/myos-simple","last_synced_at":"2026-06-26T11:01:49.019Z","repository":{"id":366419907,"uuid":"1276193452","full_name":"mohnkhan/MyOS-Simple","owner":"mohnkhan","description":"A five-stage, bare-metal x86 operating-system tutorial: from a 512-byte 16-bit boot sector to a 32-bit protected-mode C kernel with an interactive shell, CMOS real-time clock, cooperative scheduler, and fixed-point calculator. Freestanding NASM + GCC, boots on QEMU or Virtualbox","archived":false,"fork":false,"pushed_at":"2026-06-21T18:17:37.000Z","size":244,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-21T19:20:37.978Z","etag":null,"topics":["assembly","bare-metal","bios","bootloader","bootsector","c","freestanding","gdt","kernel","low-level","nasm","operating-system","osdev","protected-mode","qemu","real-mode","systems-programming","tutorial","vga","x86"],"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/mohnkhan.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-21T16:53:46.000Z","updated_at":"2026-06-21T18:19:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mohnkhan/MyOS-Simple","commit_stats":null,"previous_names":["mohnkhan/myos-simple"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/mohnkhan/MyOS-Simple","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohnkhan%2FMyOS-Simple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohnkhan%2FMyOS-Simple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohnkhan%2FMyOS-Simple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohnkhan%2FMyOS-Simple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mohnkhan","download_url":"https://codeload.github.com/mohnkhan/MyOS-Simple/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohnkhan%2FMyOS-Simple/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34813782,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","bare-metal","bios","bootloader","bootsector","c","freestanding","gdt","kernel","low-level","nasm","operating-system","osdev","protected-mode","qemu","real-mode","systems-programming","tutorial","vga","x86"],"created_at":"2026-06-26T11:01:48.016Z","updated_at":"2026-06-26T11:01:49.009Z","avatar_url":"https://github.com/mohnkhan.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MyOS-Simple\n\nA progressive, bare-metal x86 operating-system tutorial in five self-contained\nstages. Each stage is a complete, bootable image; each one adds exactly one\nlayer of capability on top of the previous. Read them in order and you watch an\noperating system assemble itself from a single 512-byte boot sector into a\nprotected-mode C system with a command shell, a real-time clock, a cooperative\nprocess model, and a fixed-point calculator.\n\nNothing here depends on an existing OS at runtime. Every image boots on the bare\nmachine (or QEMU) with only the BIOS beneath it.\n\n\u003e 📖 **Documentation:** A full companion wiki — concept deep-dives, per-stage\n\u003e walkthroughs, a reference section (memory map, I/O ports, GDT bits, scancode\n\u003e tables, command reference), and how-to guides — is on the\n\u003e [**GitHub Wiki**](https://github.com/mohnkhan/MyOS-Simple/wiki), mirrored in-repo\n\u003e under [`wiki/`](wiki/).\n\n\n## Contents\n\n- [The five stages](#the-five-stages)\n- [What it looks like](#what-it-looks-like)\n- [What each stage teaches](#what-each-stage-teaches)\n- [Design rationale](#design-rationale)\n- [Architecture and memory layout](#architecture-and-memory-layout)\n- [Prerequisites](#prerequisites)\n- [Build and verification](#build-and-verification)\n- [Quick start](#quick-start)\n- [Repository layout](#repository-layout)\n- [Conventions shared across the C stages](#conventions-shared-across-the-c-stages)\n- [Known limitations](#known-limitations)\n- [License](#license)\n\n\n## The five stages\n\n| # | Directory | Mode | Language | Lines (core) | Capability introduced |\n|---|-----------|------|----------|--------------|-----------------------|\n| 1 | `helloworld-os-asm`   | 16-bit real        | NASM      | 69 / 193 | Boot, print via BIOS, color + keyboard variant |\n| 2 | `helloworld-os-c`     | 32-bit protected   | C + NASM  | 370 C    | Bootloader, GDT, real-to-protected switch, C kernel, direct VGA |\n| 3 | `os-c-with-shell`     | 32-bit protected   | C + NASM  | 307 C    | Port-polled keyboard, interactive command shell (5 commands) |\n| 4 | `helloworld-os-c-v2`  | 32-bit protected   | C + NASM  | 2084 C   | RTC/CMOS clock, process model, calculator, tab-completion, aliases (20 commands) |\n| 5 | `helloworld-os-c-v3`  | 32-bit protected   | C + NASM  | 1894 C   | Consolidated command set (18 commands), committed build artifacts |\n\nLine counts are the core source of each stage: for stage 1 the monochrome and\ncolor assembly variants; for the C stages the kernel/shell plus the `process`\nand `rtc` modules where present. The complexity gradient runs from 69 lines of\nassembly that print a string to a ~1,900-line C system that tells the time, runs\ncooperative tasks, and evaluates expressions, all without a standard library.\n\n\n## What it looks like\n\nCaptured from QEMU. Each image is the unmodified output of the corresponding\nstage's `make run`.\n\nStage 1 — monochrome boot sector (`make run`):\n\n![Stage 1: monochrome Hello World](docs/img/stage1-asm-mono.png)\n\nStage 1 — color/keyboard boot sector (`make run-color`):\n\n![Stage 1: Colorful Hello World OS](docs/img/stage1-asm-color.png)\n\nStage 2 — first C kernel in protected mode, direct VGA, polled keyboard:\n\n![Stage 2: Advanced Keyboard Demo OS](docs/img/stage2-c-kernel.png)\n\nStage 3 — the interactive command shell:\n\n![Stage 3: SimpleShell prompt](docs/img/stage3-shell.png)\n\nStage 4 — shell with the CMOS real-time clock:\n\n![Stage 4: shell with date/time](docs/img/stage4-clock-shell.png)\n\nStage 5 — the stabilized release, shell plus live system time:\n\n![Stage 5: stabilized release](docs/img/stage5-release.png)\n\n\n## What each stage teaches\n\n1. **Stage 1 — the boot-sector contract.** What the firmware actually requires:\n   a 512-byte sector loaded to `0x7C00`, the `0xAA55` signature, 16-bit real\n   mode, and the BIOS text/keyboard services (`int 0x10`, `int 0x16`). The color\n   variant introduces VGA attribute bytes.\n2. **Stage 2 — crossing into protected mode.** The Global Descriptor Table and\n   segment descriptors, enabling protection via the `CR0.PE` bit, the far jump\n   that flushes the prefetch and loads `CS`, linking freestanding code to a fixed\n   load address, and writing the VGA framebuffer from C.\n3. **Stage 3 — talking to hardware directly.** Polled 8042 keyboard I/O on ports\n   `0x60`/`0x64`, Set-1 scancode decoding, and a hand-written command\n   parser/dispatcher with no `libc` behind it.\n4. **Stage 4 — what an OS actually does.** Reading the CMOS real-time clock and\n   converting BCD fields, a process control block driven by a cooperative\n   round-robin scheduler, fixed-point arithmetic without an FPU math library, and\n   shell ergonomics (history, tab-completion, aliases).\n5. **Stage 5 — stabilize and ship.** Consolidating the command surface, dropping\n   the experimental detours, and committing the built binaries so the artifact\n   that boots is the artifact in the repository.\n\n\n## Design rationale\n\nEach stage exists to answer the question the previous stage raised:\n\n1. **What is actually underneath a \"Hello, World\"?** Strip away the runtime\n   entirely. The BIOS loads the first 512 bytes of the disk to physical address\n   `0x7C00`, executes them in 16-bit real mode, and the only services available\n   are BIOS interrupts. The whole program fits in the boot sector and ends with\n   the `0xAA55` signature the firmware checks for.\n2. **How do we write the OS in a language we can grow?** Getting to C is the\n   hard part, not the C itself: a hand-written bootloader installs a Global\n   Descriptor Table, sets the protection-enable bit in `CR0`, far-jumps into\n   32-bit protected mode, and calls a C entry point linked at a fixed address.\n3. **How do we make the kernel interactive?** Read the keyboard controller\n   directly (polling I/O ports `0x60`/`0x64`), decode scancodes, and dispatch a\n   small command interpreter. There is no `libc`, so string handling and the\n   prompt are written by hand.\n4. **What does an operating system actually do?** Read wall-clock time from the\n   CMOS RTC, model processes with a control block and a scheduler, perform\n   fixed-point arithmetic without a math library, and make the shell ergonomic\n   (history, tab-completion, aliases).\n5. **How do we stabilize and ship?** Lock the command surface, drop the\n   experimental detours, and commit the actual built binaries so the artifact\n   that boots is the artifact in the repository.\n\n\n## Architecture and memory layout\n\nAll C stages share the same physical memory plan. Paging is never enabled, so\nthese are physical addresses throughout.\n\n```\n physical address\n 0x00000  +-------------------------------+\n          | Real-mode IVT + BIOS data     |\n 0x00500  +-------------------------------+\n          | (free low memory)             |\n 0x01000  +-------------------------------+  \u003c- kernel loaded here; linker places\n          | Kernel image (.text/.data)    |     .text at 0x1000, exec starts here\n          |   ...                         |\n 0x07C00  +-------------------------------+  \u003c- BIOS loads the 512-byte boot\n          | Boot sector (512 B, 0xAA55)   |     sector here and runs it (real mode)\n 0x07E00  +-------------------------------+\n          | (free)                        |\n 0x90000  +-------------------------------+  \u003c- protected-mode stack top\n          | Stack (grows downward)        |     (ESP/EBP), below the BIOS area\n          +-------------------------------+\n 0xB8000  +-------------------------------+  \u003c- VGA text framebuffer, 80x25 cells,\n          | Video memory (char + attr)    |     each cell = char byte + attr byte\n 0xC0000  +-------------------------------+\n```\n\nThe boot path from power-on to the C entry point:\n\n```\n BIOS power-on self-test\n        |\n        v\n Load first sector (512 B) to 0x7C00, verify 0xAA55, jump in   [16-bit real mode]\n        |\n        v\n boot.asm: set DS/ES/SS and SP; BIOS int 0x13 (CHS) reads the\n           kernel sectors from disk into 0x1000\n        |\n        v\n boot.asm: cli; lgdt [gdt_descriptor]; set CR0.PE = 1;\n           far jump CODE_SEG:protected_entry\n        |\n        v\n reload data selectors with DATA_SEG; ESP = EBP = 0x90000       [32-bit protected mode]\n        |\n        v\n call 0x1000 -\u003e kernel_entry.asm (_start) -\u003e kernel_main()/shell_main()   [C]\n        |\n        v\n kernel writes VGA at 0xB8000, polls keyboard at 0x60/0x64, runs forever\n```\n\n\n## Prerequisites\n\nThe build is a freestanding 32-bit (`i386`) toolchain plus an emulator. On a\n64-bit host you need the 32-bit multilib support for GCC.\n\nDebian / Ubuntu:\n\n```sh\nsudo apt update\nsudo apt install nasm gcc gcc-multilib binutils make qemu-system-x86\n```\n\nFedora:\n\n```sh\nsudo dnf install nasm gcc glibc-devel.i686 libgcc.i686 binutils make qemu-system-x86\n```\n\nArch:\n\n```sh\nsudo pacman -S nasm gcc lib32-glibc binutils make qemu-system-x86\n```\n\nComponent roles:\n\n- **nasm** — assembles boot sectors (`-f bin`, flat binary) and the 32-bit\n  kernel entry stub (`-f elf32`).\n- **gcc** — compiles the C kernel as freestanding 32-bit code (`-m32`).\n- **ld** (binutils) — links the kernel to a fixed load address via `linker.ld`\n  (`-m elf_i386`).\n- **make** — drives each stage's build.\n- **coreutils** — `cat` concatenates boot sector + kernel; `truncate` pads the\n  image to a whole number of sectors.\n- **qemu-system-x86_64** — boots the raw disk image.\n\n\n## Build and verification\n\nEvery stage builds with `make` and boots in QEMU. The current tree was verified\nagainst the following toolchain; older or newer versions generally work, but\nthese are the exact versions the build is known-good on:\n\n| Component | Version tested |\n|-----------|----------------|\n| nasm      | 2.16.01 |\n| gcc       | 13.3.0 (with `-m32` multilib) |\n| ld        | 2.42 (GNU Binutils) |\n| qemu      | 8.2.2 (`qemu-system-x86_64`) |\n| make      | 4.3 |\n\nVerified state: all five stages compile cleanly; all ten disk images carry a\nvalid `0xAA55` boot signature in their boot sector and boot in QEMU. Each stage's\nbootloader reads a fixed number of sectors sized to its kernel:\n\n| Stage | Image | Sectors loaded by `boot.asm` |\n|-------|-------|------------------------------|\n| 2 | `helloworld-os-c`    | 16 |\n| 3 | `os-c-with-shell`    | 15 |\n| 4 | `helloworld-os-c-v2` | 39 |\n| 5 | `helloworld-os-c-v3` | 39 |\n\n\n## Quick start\n\nEach directory is independent and ships its own `Makefile` with consistent verbs:\n\n```sh\ncd helloworld-os-asm     # or any other stage\nmake                     # build the bootable image(s)\nmake run                 # boot the primary image in QEMU\nmake clean               # remove build artifacts\nmake help                # list available targets\n```\n\nThe C stages also provide:\n\n```sh\nmake run-simple          # boot the pure-assembly \"simple\" image\nmake debug               # boot under QEMU with a GDB stub (-s -S) on :1234\n```\n\nStage 1 additionally provides `make run-color` for the color/keyboard variant.\n\nTo build every stage in one pass:\n\n```sh\nfor d in helloworld-os-asm helloworld-os-c os-c-with-shell \\\n         helloworld-os-c-v2 helloworld-os-c-v3; do\n    make -C \"$d\" clean \u0026\u0026 make -C \"$d\"\ndone\n```\n\n\n## Repository layout\n\n```\nMyOS-Simple/\n├── README.md                 This file.\n├── LICENSE                   MIT license.\n├── docs/img/                 Screenshots used in this README.\n├── helloworld-os-asm/        Stage 1 — pure assembly.\n├── helloworld-os-c/          Stage 2 — C kernel in protected mode.\n├── os-c-with-shell/          Stage 3 — interactive shell.\n├── helloworld-os-c-v2/       Stage 4 — clock, processes, calculator.\n└── helloworld-os-c-v3/       Stage 5 — stabilized release.\n```\n\nEach stage directory contains its own `README.md` documenting that stage in\ndetail. Stages 4 and 5 additionally ship `README_SHELL.md`, a complete\ncommand reference for the shell.\n\n\n## Conventions shared across the C stages\n\nThese hold for stages 2-5 and are documented once here rather than repeated:\n\n- **Load address.** The bootloader loads the kernel to physical `0x1000` and the\n  linker script places `.text` at `0x1000`, so execution begins at the first\n  byte of the kernel image.\n- **Stack.** Protected-mode `ESP`/`EBP` are initialized to `0x90000`, comfortably\n  below the kernel and above the BIOS data area.\n- **GDT.** A minimal three-entry table: a null descriptor, a flat ring-0 code\n  segment, and a flat ring-0 data segment, each spanning the full 4 GiB with\n  4 KiB granularity (`0xCF` flags). No paging is enabled.\n- **Display.** Text is written directly to VGA memory at `0xB8000`; each cell is\n  a character byte followed by an attribute byte (`background \u003c\u003c 4 | foreground`).\n- **Keyboard.** Input is read by polling the 8042 controller: status port\n  `0x64`, data port `0x60`. Scancodes are translated through the tables in\n  `keyboard.h`.\n- **Freestanding C.** Compiled with `-ffreestanding -nostdlib -nostdinc\n  -fno-builtin -fno-stack-protector -fno-pic -fno-pie`. There is no C runtime;\n  the assembly entry stub calls the kernel's C entry point directly.\n\n\n## Known limitations\n\n- Real-mode disk loading uses BIOS `int 0x13` with CHS addressing and assumes\n  the kernel occupies contiguous sectors starting at sector 2 of the boot media.\n- The process model (stage 4+) is cooperative: tasks must call `process_yield()`.\n  There is no timer-driven preemption and no memory protection between tasks.\n- RTC reads are not synchronized against the update-in-progress flag, so a read\n  that races a CMOS update may momentarily return an inconsistent field.\n- Images are sized for QEMU; running on physical hardware may require adjusting\n  the sector count loaded by the bootloader.\n\n\n## License\n\nReleased under the MIT License. See [LICENSE](LICENSE) for the full text.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmohnkhan%2Fmyos-simple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmohnkhan%2Fmyos-simple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmohnkhan%2Fmyos-simple/lists"}