A custom x86_64 operating system with UEFI bootloader, GPT partition support, and FAT16 filesystem.
- UEFI Boot: Modern UEFI bootloader instead of legacy BIOS
- 64-bit Long Mode: Full x86_64 support with 4-level paging
- GPT Partitions: GUID Partition Table support
- FAT16 Filesystem: File I/O with FAT16 support
- Graphics: Framebuffer graphics with BMP image support
- Process Management: Task switching and ELF executable support
- Kernel Heap: Dynamic memory allocation
- Interrupts: IDT, IRQs, and system calls (int 0x80)
You need a x86_64-elf cross-compiler. Follow the OSDev Wiki GCC Cross-Compiler guide to build one.
Quick setup:
export PREFIX="$HOME/opt/cross"
export TARGET=x86_64-elf
export PATH="$PREFIX/bin:$PATH"Add these to your ~/.bashrc or ~/.zshrc to make them permanent:
echo 'export PREFIX="$HOME/opt/cross"' >> ~/.bashrc
echo 'export TARGET=x86_64-elf' >> ~/.bashrc
echo 'export PATH="$PREFIX/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcVerify installation:
x86_64-elf-gcc --version
x86_64-elf-ld --versionClone the EDK2 repository:
cd ~
git clone https://github.com/tianocore/edk2.git
cd edk2
git submodule update --initBuild EDK2 BaseTools:
make -C BaseTools
source edksetup.shConfigure EDK2 for 64-bit compilation by editing Conf/target.txt:
ACTIVE_PLATFORM = MdeModulePkg/MdeModulePkg.dsc
TARGET_ARCH = X64
TOOL_CHAIN_TAG = GCC5
Install required packages (Ubuntu/Debian):
sudo apt-get install build-essential nasm qemu-system-x86 gdb parted dosfstoolsmy-os/
├── kernel/ # Kernel source code
│ ├── src/ # C and assembly source files
│ ├── programs/ # User programs (shell, echo, etc.)
│ ├── data/ # Resources (fonts, images)
│ ├── Makefile # Kernel build configuration
│ └── build.sh # Kernel build script (called by main build)
└── edk2/ # UEFI bootloader (place inside EDK2 repo)
├── MyOS.c # UEFI bootloader implementation
├── MyOS.inf # EDK2 module definition
├── build.sh # Main build script (builds everything)
└── run.sh # QEMU launch script
Copy or symlink the edk2 directory from this project into your EDK2 repository:
# From the my-os directory
cd /path/to/my-os
cp -r edk2 ~/edk2/MdeModulePkg/Application/MyOS
# OR create a symlink
ln -s /path/to/my-os/edk2 ~/edk2/MdeModulePkg/Application/MyOSAdd MyOS to the EDK2 build by editing ~/edk2/MdeModulePkg/MdeModulePkg.dsc:
Find the [Components] section and add:
[Components]
# ... existing components ...
MdeModulePkg/Application/MyOS/MyOS.inf
Navigate to the MyOS UEFI application directory and run the main build script:
cd ~/edk2/MdeModulePkg/Application/MyOS
./build.shThis script will:
- Build the EDK2 UEFI application (MyOS.efi)
- Build the kernel and user programs
- Create a 700MB disk image (
bin/os.img) - Set up GPT partitions:
- Partition 1: EFI System Partition (ESP)
- Partition 2: MyOS filesystem (FAT16, label: MYOSFS)
- Copy the kernel, programs, and resources to the filesystem
- Install the UEFI bootloader
The easiest way to run after building:
cd ~/edk2/MdeModulePkg/Application/MyOS
./run.shThis will automatically launch QEMU with the correct settings.
Alternatively, run QEMU manually:
cd ~/edk2/MdeModulePkg/Application/MyOS
qemu-system-x86_64 -drive file=bin/os.img,format=raw -m 512M -cpu qemu64 -bios /usr/share/ovmf/OVMF.fdNote: You need OVMF (UEFI firmware for QEMU). Install it:
sudo apt-get install ovmfTerminal 1 (run QEMU with GDB server):
qemu-system-x86_64 -drive file=bin/os.img,format=raw -m 512M -cpu qemu64 \
-bios /usr/share/ovmf/OVMF.fd -s -STerminal 2 (connect GDB):
cd ~/edk2/MdeModulePkg/Application/MyOS/../../my-os/kernel
gdb
(gdb) target remote :1234
(gdb) add-symbol-file build/kernelfull.o 0x100000
(gdb) break kernel_main
(gdb) continue-
Write the image to a USB drive:
sudo dd if=bin/os.img of=/dev/sdX bs=4M status=progress sync
Replace
/dev/sdXwith your USB drive (check withlsblk) -
Boot from the USB drive (enable UEFI boot in BIOS/UEFI settings)
Files on Partition 2 (MYOSFS):
kernel.bin- The kernel binaryshell.elf- Shell program (ELF format)echo.elf- Echo test programblank.elf- Blank test programsimple.bin- Simple test binarybackgrnd.bmp- Background image (8.3 filename format)
Important: FAT16 without LFN support requires 8.3 filenames (max 8 chars + 3 extension).
To rebuild everything (UEFI bootloader, kernel, and disk image):
cd ~/edk2/MdeModulePkg/Application/MyOS
./build.shIf you only need to rebuild the kernel without recreating the disk:
cd /path/to/my-os/kernel
./build.shcd /path/to/my-os/kernel/programs/shell
makecd /path/to/my-os/kernel
make cleanMake sure the cross-compiler is in your PATH:
export PATH="$HOME/opt/cross/bin:$PATH"
x86_64-elf-gcc --versionRun the EDK2 setup script:
cd ~/edk2
source edksetup.shUnmount any stale mounts:
sudo umount /mnt/d
sudo losetup -D # Detach all loop devicesMake sure you're loading the correct symbol file:
add-symbol-file /path/to/my-os/kernel/build/kernelfull.o 0x100000Ensure filename follows 8.3 format (8 chars max for name, 3 for extension). Your FAT16 implementation doesn't support long filenames.
- Bootloader: UEFI application (MyOS.efi) loads kernel at 0x100000
- Kernel: 64-bit kernel with 4-level paging (PML4)
- Memory: Physical memory mapped via E820, kernel heap allocator
- Filesystems: FAT16 support with GPT partition table
- Graphics: Direct framebuffer access with double-buffering
- Tasks: Process switching with separate page tables per process
- System Calls: Software interrupt 0x80 for kernel services
This is a personal OS project for learning. Feel free to fork and experiment!
This project is licensed under the MIT License - see the LICENSE.md file for details.