Memory & Paging
Outdated “no paging” docs were removed. nexOS now enables paging (CR3 + CR0.PG) with an identity map and a bitmap page allocator (kmalloc/kfree). This page describes the current kernel.c:page_init/mem_init implementation.
Contents[hide] |
Address-space model
logical addr --> [GDT: base 0] --> linear addr --> [paging: identity] --> physical addr
flat, 4 GiB, ring 0 CR3 = page_directory, CR0.PG = 1
Segmentation is flat; paging provides the mapping. Low memory is identity-mapped so existing bootloader addresses (0x5000 block, 0x8000 kernel, 0x200000 backbuffer) keep working after CR0.PG is set.
Page tables
kernel.c reserves five 4 KiB-aligned tables:
static u32 page_directory[1024] __attribute__((aligned(4096))); static u32 pt0[1024], pt1[1024], pt2[1024], pt3[1024]; // 0-16 MiB identity static u32 pt_lfb[1024]; // framebuffer window #define PAGE_SIZE 0x1000 #define NUM_PAGES 4096 // 4096 x 4 KiB = 16 MiB managed #define HEAP_START_PAGE 1024 // heap starts at 4 MiB
page_init(): pt0[i] = (i*0x1000) | 0x03; // 0x000000-0x3FFFFF present+rw pt1[i] = (0x400000 + i*0x1000)|0x03; // 0x400000-0x7FFFFF pt2[i] = (0x800000 + i*0x1000)|0x03; // 0x800000-0xBFFFFF pt3[i] = (0xC00000 + i*0x1000)|0x03; // 0xC00000-0xFFFFFF page_directory[0..3] = pt0..pt3 | 0x03; // LFB: if VBE base >= 0x1000000, map 4 MiB window at its 4 MiB-aligned base // mov page_directory -> CR3; set CR0 bit 31 (0x80000000)
Flags 0x03 = present + read/write, supervisor only. No user pages, no NX, no PAE. The LFB window is only installed when the framebuffer lives high (typical for VESA linear buffers); low VGA fallback (0xA0000) is already covered by pt0.
Physical allocator
A 512-byte bitmap (mem_bitmap[NUM_PAGES/8]) tracks 4096 pages. Pages below HEAP_START_PAGE (first 4 MiB: kernel, tables, BIOS area) are marked used at boot; the rest is heap.
mem_init(): zero bitmap, mark pages 0..1023 used.
kmalloc(size): pages = ceil(size/4096); first-fit scan from page 1024;
mark used, return (page * 0x1000). Returns 0 on failure.
kfree(ptr): unmark single page (caller frees whole pages; no coalescing
beyond bitmap bits, no free-list).
There is also a tiny snprintf (supports %x %d %s %c) used for terminal and browser status lines. It is freestanding — no libc.
Bootloader parameter block
16 bytes at 0x5000, written by boot.asm, read by vbe_init():
#define VBE_LFB (*(u32 volatile *)0x5000) #define VBE_WIDTH (*(u16 volatile *)0x5004) #define VBE_HEIGHT (*(u16 volatile *)0x5006) #define VBE_PITCH (*(u16 volatile *)0x5008) #define VBE_BPP (*(u8 volatile *)0x500A) #define VBE_RED_POS (*(u8 volatile *)0x500B) #define VBE_GRN_POS (*(u8 volatile *)0x500C) #define VBE_BLU_POS (*(u8 volatile *)0x500D)
| Offset | Size | Field | Source |
|---|---|---|---|
| 0x00 | 4 | LFB address | ModeInfo +0x28 |
| 0x04 | 2 | width | ModeInfo +0x12 |
| 0x06 | 2 | height | ModeInfo +0x14 |
| 0x08 | 2 | pitch | ModeInfo +0x10 |
| 0x0A | 1 | bpp | ModeInfo +0x19 |
| 0x0B–0x0D | 1+1+1 | R/G/B field positions | ModeInfo +0x20/0x22/0x24 |
Framebuffer & double buffering
Rendering targets an off-screen frame at 0x200000 (BACKBUFFER_ADDR), then blits to the real LFB once per frame to avoid flicker. Recent work added fast fills (32-bit writes for 32bpp) and bulk present.
render_desktop(): lfb = (u8*)0x200000; // draw everything to back buffer draw_desktop_icons(); draw_window(); draw_terminal(); ... for (row < scr_h) memcpy(back+row*pitch -> front+row*pitch); lfb = front_lfb; // restore
Pixel formats
| bpp | Encoding | Write |
|---|---|---|
| 32 / 24 | RGB888 (field-position shifted) | 4-byte fast path (32bpp) or 3 bytes LE |
| 16 | RGB565 | u16 at base + x*2 |
| 8 | raw index | base[x] |