# 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