diff options
| author | Arseney300 <Arseney300@gmail.com> | 2026-03-29 02:07:17 +0700 |
|---|---|---|
| committer | Arseney300 <Arseney300@gmail.com> | 2026-04-08 01:19:07 +0700 |
| commit | 4912796d2e88c6eb5d02fbf0fb9c39f8c9f7cd4c (patch) | |
| tree | 9ee8110e2c090c888f23797cda56c7e2df531695 /doc/develop/overall.md | |
bastion: initial implementation
ready project skeleton
dual-arch build system with Linux-config style configuration
UEFI EFI stub loader (PE32+) for x86_64 and AArch64
ELF64 kernel parser
Temporary framebuffer console
freestanding string and c++ abi stubs
For now, kernel boots, prints banner, memory map and go halt
Diffstat (limited to 'doc/develop/overall.md')
| -rw-r--r-- | doc/develop/overall.md | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/doc/develop/overall.md b/doc/develop/overall.md new file mode 100644 index 0000000..0ea2508 --- /dev/null +++ b/doc/develop/overall.md @@ -0,0 +1,123 @@ +# Overall stages of developen BastionOS kernel + +## I Phase +UEFI boot + +My main task here is create bootable efi application. + + +First kernel booting stage is running PE32+ efi binary. It calls UEFI Boot Services to get the memory map, framebuffer(GOP) and ACPI/device_tree_pointer (for arm64 if it will supports dts). Then it loads my ELF kernel into memory and jumps to it after calling ExitBootServices(). +GNU-EFI (https://github.com/ncroxon/gnu-efi.git) should help me somehow to do it. + + +So, what we need to have after uefi: +1) Physical memory map (which regions are usable) +2) Framebuffer address and pitch (for console) +3) RSDP pointer (for ACPI table parsing) +4) Device Tree pointer (for arm) +5) Kernel's own physical/virtual address + +## II Phase +Arch-Specific CPU setup + +# For x86_64 +- Load a GDT (minimal: null, kernel code64, kernel data, user code64, user data, TSS) +- Set up IDT - 256 entries, wire ISR stubs in assembly, that push error codes uniformly, then call dispatch_interrupt(InterruptFrame&) handler +- Configure paging: PML4 page table hierarchy, higher-half kernel mapping(canonical address like 0xFFFF800000000000+), recursive or direct-map strategy for page table self-reference +- Enable and configure the local APIC + I/O APIC (from MADT ACPI table), replace the legacy PIC + +# For AArch64: +- Set up exception vectors(VBAR_EL1) - 4 exception types x 4 source levels = 16 vectors +- Configure the MMU: TCR_EL1, MAIR_EL1, TTBR0_EL1/ TTBR1_EL1 (user/kernel split), 4-level page tables (4KB granule, 48-bit VA) +- Set up the GIC(Generic Interrupt Controller) v2 or v3 from device tree info + + +Because of using c++ as main language i can create abstraction for it: +``` +namespace arch { + void init_interrupts(); + void enable_interrupts(); + void disable_interrupts(); + void set_page_table(PhysAddr root); + void invalidate_page(VirtAddr addr); + [[noreturn]] void halt(); +} +``` + + +## III Phase + +### PMM - Physical Memory Manager +- Parse the boot memory map (that we did in I phase), build a buddy allocator or bitmap allocator over free regions +- Track allocation in page-sized (4KiB) granules +- Provide alloc_page() / free_page functions + +### VMM - Virtual Memory Manager +- Implement VirtualAddressSpace object, that wraps a page table root +- Operations map(VirtAddr, PhysAddr, flags), unmap(VirtAddr), translate(VirtAddr) -> PhysAddr +- Kernel its own address space; each process will get one later +- Both archs use 4-level tables with similar structure - abstract the entry format + +### Kernel Heap +- Implement a slab allocator or a simple kmalloc/kfree on tho of the VMM +- Overload global operator new/delete to use it - this unlocks C++ STL + + +## IV Phase +### Timer +- x86_64: APIC Timer (calibrated against HPET or PIT) or TSC deadline mode +- AArch64: Generic Timer (CNTPCT_EL0, CNTP_TVAL_EL0) + +### Scheduler +- At begining, i want to use simple round-robit with a reade one queue +- Each task has: a kernel stack, saved register context, an address space +- Context switch is arch-specific assembly: save/restore registers + swap stack pointer + swap page table root (the best arch for context switching is still riscV with only one simple command, x86 will be very hard(considering Linux code), but if i will not use hash it can be easy and understandable) +- Preemption via timer interrupt + +## V Phase +### ELF Parser +- Parse ELF64 header, validate e_ident magic, check EM_X86_64 or EM_AARCH64 +- Iterate program headers(PT_LOAD segments), map them into the process address space at their p_vaddr with correct permissions (rwx from p_flags) +- Set entry point from e_entry + +### Userspace transition +- Allocate a user stack, set up the initial stack frame (argc, argv, envp, auxv) +- x86_64: sysretq or iretq to ring3 +- aarch64: eret to EL0 + +### SysCall +- x86_64: syscall/sysret via MSRr(LSTAR, STAR, SFMASK) +- aarch64: svc instruction, handled in the EL1 syncronous exception vector +- Define a syscall table - start with basic write(), read(), exit(), mmap(), fork()/spawn()/clone() + + +## VI Phase +### Essential drivers +- UART/Serial +- Framebuffer console +- USB keyboard (or PS/2 for qemu testing) +- Virtio-blk (block device in QEMU - much simpler than AHCI/NVMe) + +### Filesystem +- Implement a VFS layer (struct Inode, struct File, open()/read()/write()/close()) +- Start with in-memory initramfs (USTAR or CPIO) baked into the boot image +- Later: ext2 read support (very simple) +- Later: normal ext4 +- Sometime: fat +- Never: ntfs + +## VII Phase +## dynamic linking and shared libs +## porting full libc (or mlibc, that designed for hobby kernels) +## do full POSIX support + +## VIII Phase +### Network (virtio-net + tcp/ip stack) + +## IX Phase +### multicore/SMP + +## X Phase +## Window drawing + + |
