Memory map

Kernel-side static memory map

Kernel-side fixed-physical regions, all reached through the kernel direct map at virt DIRECT_MAP_BASE + phys (= 0xFF800000 + phys at the current base; or via the kmap window for frames above the direct-map ceiling). The “in kernel.bin?” column flags whether the bytes occupy the on-disk image (yes) or live as bare frames reserved by frame_reserve_range (no). Addresses from kernel_stack onward are derived from KERNEL_RESERVED_BASE = page_align(0x20000 + sizeof(kernel.bin)); example values shown are for the current build (~29 KB kernel).

Two narrow frame_reserve_range calls at boot pin only the regions the kernel still owns: the libbboeos target frame at 0x10000 (one 4 KB page) and 0x20000..(FRAME_BITMAP_PHYS + frame_bitmap_bytes) (kernel image + KERNEL_RESERVED_BASE region; the bitmap end is runtime, sized by frame_init from E820). Everything else in conventional low memory — IVT/BDA at 0..0x4FF, 0x600..0x7BFF gap, MBR landing zone at 0x7C00..0x7DFF, dead post-MBR boot code at 0x7E00..0xDFFF, the unused page-0xE region, and the boot stack at 0x9F000 — stays in the bitmap allocator’s free pool. The build script asserts that KERNEL_RESERVED_BASE + 0x23000 < 0xA0000 (worst-case stack + boot PD + first kernel PT + 128 KB bitmap at the FRAME_PHYSICAL_LIMIT cap) so the kernel-side regions never cross the VGA aperture under any RAM size.

Update this table when adding a new fixed-phys region so newcomers can find every slot in one place.

Phys range Kernel-virt Size Symbol / purpose In kernel.bin?
0x00010000..0x00010FFF n/a 4 KB libbboeos (shared user-virt frame; per-program PDs alias it user-side) no
0x00020000..0x00020001 0xFF820000..0xFF820001 2 B jmp short high_entry trampoline (offset 0 of kernel.bin) yes
0x00020002 0xFF820002 1 B boot_disk (BIOS drive number, written by boot.asm post-load) yes
0x00020003..0x00020004 0xFF820003..0xFF820004 2 B directory_sector (LBA of first directory sector) yes
0x00020008.. 0xFF820008.. ~29 KB kernel.bin high_entry and resident kernel code (on-disk image; BSS lives below KERNEL_RESERVED_BASE, see next row) yes
KERNEL_LOAD_PHYS + .text_size..KERNEL_RESERVED_BASE 0xFF82xxxx.. ~55 KB (today: 0xDF58) kernel BSS — hand-written kernel.asm/entry.asm reservations (program_state_a/b/c, parent_iret_frame, tss_data, FD slot, pipeline flags, OOM pending pointers, sector_buffer_storage, etc.) and cc.py-emitted zero-init globals from build/kernel-c/**/*.kasm (_g_pipe_pool, _g_vga_scrollback_*, audio rings, etc.); declared section .bss nobits in kernel/arch/x86/kernel.asm so the bytes do not ride on disk; zero-filled by high_entry after the kernel-stack poison-fill, before lidt. make_os.sh reads kernel_bss_start / kernel_bss_end from build/kernel.map and adds the extent to KERNEL_RESERVED_BASE so the kernel stacks (next row) do not overlap. no
KERNEL_RESERVED_BASE.. 0xFF838000.. (≈) 3 × 1 KB three ring-0 kernel stacks (kernel_stack = slot_a, kernel_stack_b = pipeline cmd1, kernel_stack_c = pipeline cmd2); KERNEL_STACK_BYTES = 0x400. KERNEL_RESERVED_BASE = page_align(0x20000 + kernel_size + bss_size); each stack poison-filled with 0xDEADBEEF at boot for high-water tracking no
~0x39000..0x39FFF 0xFF839000.. (≈) 4 KB boot PD (BOOT_PD_PHYS = page_align(KERNEL_RESERVED_BASE + 3 * KERNEL_STACK_BYTES); the page-align pad covers the sub-page slack left by three 1 KB stacks); freed back to the bitmap pool by high_entry after kernel_idle_pd takes over the CR3-target role. The slot is then just a regular conventional frame — the bitmap allocator can hand it out for user pages. no
~0x3A000..0x3AFFF 0xFF83A000.. 4 KB first kernel PT (FIRST_KERNEL_PT_PHYS = BOOT_PD_PHYS + 0x1000) no
~0x3B000.. 0xFF83B000.. runtime, ≤ 128 KB frame_bitmap (size set by frame_init from the highest type=1 E820 base, clamped to FRAME_PHYSICAL_LIMIT ≈ 4 GB — -m 1 pays ~20 bytes, -m 1024 pays 32 KB, -m 4096 pays 128 KB; frame_init fills the storage before any allocator call, so the bytes don’t ride on disk inside kernel.bin) no
FRAME_BITMAP_PHYS + frame_bitmap_bytes 0xFF800000 + same end of the kernel reserve sweep — runtime ceiling, equals 0x3B000 + 20 B on -m 1, 0x3B000 + 32 KB on -m 1024, and 0x3B000 + 128 KB on -m 4096 (these offsets shift with kernel.bin + BSS size; see the build-time derivation); everything past this in conventional RAM is owned by the bitmap allocator (subject to E820’s reserved regions, including the VGA aperture at 0xA0000..0xFFFFF)
dynamic dynamic 4 KB (ext2 only) ext2 directory-window frame — allocated by ext2_init only when the superblock magic matches; holds ext2_search_blk’s sliding 2-sector directory window (1 KB used in the 4 KB frame; the upper 3 KB sits unused — no sub-page allocator). bbfs systems never spend this frame; ext2_sd_buffer stays NULL. sector_buffer (the 512 B scratch every disk read writes through) now lives in the kernel BSS as sector_buffer_storage (see the BSS row above), unconditionally available on every boot. ext2_init treats frame_alloc failure here as a hard panic. no
dynamic dynamic 4 KB NIC scratch frame — allocated by network_initialize only when an NE2000 NIC is detected; sliced into four named pointers (net_receive_buffer at offset 0, net_transmit_buffer at 1536, arp_table at 3072, udp_buffer at 3168), 3.4 KB used inside the 4 KB frame. Sessions without a NIC leave the four pointers at 0 and never spend the frame. The ARP-table slice is zero-filled at init (lookup/add keys on [entry] == 0 for empty slots); the other slices are fully overwritten on each use no
dynamic dynamic 4 KB kernel_idle_pd — a kernel-only PD allocated by high_entry post-PT-alloc. Kernel-half (PDEs FIRST_KERNEL_PDE..1023) copy-imaged from the boot PD; user-half (PDEs 0..FIRST_KERNEL_PDE-1) zero. Used as the canonical kernel-half PDE source for address_space_create, as CR3 between programs, and as the CR3-swap target during address_space_destroy. kernel_idle_pd_phys (entry.asm BSS) holds its phys. Replaces the boot PD’s permanent-frame role; the boot PD’s frame is freed back to the bitmap pool once the idle PD takes over no
dynamic dynamic 4 KB kmap window PT (kmap_pt_phys) — allocated by kmap_init after the idle PD takes over. Installed at kernel_idle_pd[1023] so every per-program PD inherits the window through address_space_create’s kernel-half copy-image. Holds the PTEs for the KMAP_SLOT_COUNT = 4 slots at virt 0xFFC00000..0xFFC03FFF; kmap_map/kmap_unmap write and clear them on demand to alias frames above FRAME_DIRECT_MAP_LIMIT no

User-side virtual layout

Per per-program PD; same shape for every program PD that address_space_create builds.

User-virt range Size Purpose
0x00000000..0x00000FFF 4 KB NULL guard — not mapped (PTE[0] absent so *(int *)0 raises #PF)
0x00010000..0x00010FFF 4 KB libbboeos (FUNCTION_PRINT_STRING, FUNCTION_DIE, …)
0x08048000.. program-sized program text + BSS (Linux ELF-shaped load address)
0xFF7E0000..0xFF7EFFFF 64 KB unmapped (stack guard region)
0xFF7F0000..0xFF7FFFFF 64 KB user stack (16 pages, top at USER_STACK_TOP)
0xFF800000 USER_STACK_TOP (one past end of stack; equals user/kernel boundary = KERNEL_VIRT_BASE)
0xFF800000..0xFFBFFFFF 4 MB kernel direct map (PDE 1022 = FIRST_KERNEL_PDE, copy-imaged from kernel_idle_pd)
0xFFC00000..0xFFFFFFFF 4 MB kmap window (PDE 1023, copy-imaged from kernel_idle_pd); only the first KMAP_SLOT_COUNT = 4 PTEs are ever used at runtime

This site uses Just the Docs, a documentation theme for Jekyll.