-
-
Notifications
You must be signed in to change notification settings - Fork 5
Boot Process
From GRUB handing off control to a logged-in desktop. Every stage below is real code you can follow: kernel/boot.asm for stages 1–2, kernel_main() in kernel/kernel.c for stages 3–6.
See also: Architecture, Memory Management, SMP, GUI Subsystem, Security
boot.asm publishes two Multiboot headers: a Multiboot 1 header (0x1BADB002) kept for compatibility, and a Multiboot 2 header (0xE85250D6), which is what the generated grub.cfg actually uses:
menuentry 'NyxOS' {
multiboot2 /boot/nyx-kernel.bin
boot
}
GRUB loads the kernel, leaves the CPU in 32-bit protected mode, and jumps to _start with the boot magic in EAX and the info-structure pointer in EBX. Both are stashed immediately, because the long-mode climb clobbers general registers.
-
cli; saveEAX/EBX(Multiboot magic and info pointer) - Set up a minimal 32-bit GDT
- Confirm long-mode support via
CPUIDleaf0x80000001 - Enable PAE in
CR4 - Build temporary page tables — PML4 → PDPT → two page directories covering the low 128 MB with 2 MB pages
- Load
CR3 - Set
EFER.LME - Enable paging (
CR0.PG) — the CPU is now in long mode - Load the 64-bit GDT (ring-0 code/data + ring-3 code/data)
- Far jump to reload
CS, then load the data segment registers - Point
RSPat the 128 KB.bssboot stack - Zero BSS and call
kernel_main(magic, mboot_ptr)
The boot stack is 128 KB and is placed before the page tables in
.bss. It was 16 KB and sat directly below them, so a deep compositor redraw chain could overflow into the live page tables and corrupt them — a bug that presented as crashes at unrelated addresses.
Initialisation runs in a fixed order, because each step depends on the ones above it. The 23-step progress bar on the splash screen is driven by bootsplash_update() calls threaded through this sequence.
Early — no memory manager yet
init_screen() → clear_screen() → init_gdt() → init_idt() → init_isr()
→ init_irq() → init_serial() → enable_sse_fpu()
Memory
The Multiboot info block is parsed here. For Multiboot 2 the memory-map tag is copied out entry by entry (base, length, type) and handed to the allocator, so the physical allocator honours real firmware holes instead of assuming a flat region.
init_memory(mem_total, mmap, mmap_count) → init_paging() → enable_smep_smap()
Core services
init_apic() → init_heap() → slab_init_all() → smp_init()
smp_init() runs here — before the timer — because the IST allocation below needs to know how many cores are online.
Display
vbe_init() → fb_init(w, h, bpp, lfb) → bootsplash_init()
If no VBE framebuffer can be set, the kernel stays in text mode and later drops to the serial shell instead of the desktop.
Per-CPU exception stacks
One double-fault and one NMI IST stack per online core (8 KB each), so a fault on one core cannot scribble on another core's exception stack.
Scheduling, syscalls, filesystems
init_timer(1000) → init_keyboard() → init_process() → ensure_idle_process()
→ smp_start_ap_threads() → init_syscalls() → cpu_install_gs_base(0)
→ setup_syscall_msrs() → [allocate syscall kernel stack]
→ init_vfs() → init_load_modules() → init_ext2()
cpu_install_gs_base() must run before anything can issue a syscall: the entry stub reaches its per-CPU scratch slots through GS and has no spare register to find them any other way.
Network
init_net() → tcp_init() → tcp_echo_init() → [auto-DHCP if a NIC is present]
Auto-DHCP leases an address at boot so ping, httpget and Selene Browser work without a manual dhcp. It is skipped entirely when no NIC is present, so a diskless/netless boot never stalls.
Devices and interrupts
init_background_tasks() → mouse_init() → speaker_init() → sb16_init()
→ rtc read → irq_install_handler(1, 5, 12)
→ ioapic_redirect_irq(2, 32, apic_id) → ioapic_unmask_irq(2)
→ irq_unmask(1|5|12) → sti
The PIT arrives on I/O APIC pin 2, not pin 0 — QEMU's ACPI interrupt-source override remaps ISA IRQ 0. Unmasking pin 0 was a no-op, which is why
tick_countstayed at zero for several releases.
Userspace
initramfs_load() → initramfs_boot() → shared_libc_load() → [register /init.elf]
→ ext2 probe/mount at /mnt
shared_libc_load() maps the single prelinked libc.so that every user program links against (see Userspace).
Roughly five seconds: the NyxOS crescent-moon logo, a starfield, a spinner, and a 23-step progress bar whose captions come from the bootsplash_update() calls above. Fades to black before the login screen.
auth_setup() then login_screen(), drawn straight to the linear framebuffer (no back buffer). The screen offers a username/password card and a create-account panel with profile-picture selection.
- Credentials live in
/etc/passwdon the EXT2 disk, one line per user:user:salt_hex:iterations:hex_hash:avatar - Hashing is PBKDF2-HMAC-SHA256, 10 000 iterations, with a random 8-byte per-user salt
-
LOGIN_MAX_ATTEMPTSis 3, after which the screen enters a lockout cooldown - With no EXT2 disk attached, an in-memory fallback account is used so the machine still boots
See Security for the threat model.
create_process("compositor", compositor_run, 0) // registered with the scheduler
loop:
fb_use_lfb_direct(); login_screen()
compositor_init(); compositor_run()
if (!compositor_logout_requested) break
The compositor comes up with 10 desktop icons, a taskbar, a Start menu and 4 workspaces. Choosing Log out from the taskbar user menu returns to the login screen without rebooting — compositor_init() frees the previous session's windows first, so the next user starts on a clean desktop.
If no framebuffer was available, launch_shell() runs the kernel shell over serial instead. See Shell.
NyxOS v6.4.363 · GPL v2 · GitHub · uselessalter on Discord · nyxos@inbox.lv
NyxOS Wiki
Getting started
Kernel
Storage & network
Graphics & apps
Userspace
HOWTO
- HOWTO-Add-a-system-call
- HOWTO-Write-a-userspace-program
- HOWTO-Add-a-shell-command
- HOWTO-Add-a-GUI-application
Reference
- Syscall-Reference
- Command-Reference
- Hardware-Reference
- Format-Reference
- Kernel-Data-Structures
- Source-Tree-Reference
Project