From: Tulio A M Mendes Date: Sat, 14 Feb 2026 04:17:00 +0000 (-0300) Subject: fix: cmdline parser, VBE framebuffer, VA collision, ring3 test, code audit X-Git-Url: https://projects.tadryanom.me/docs/static/gitweb.js?a=commitdiff_plain;h=c3dbe0e902f5afc1cf4f607f8260882a0279217b;p=AdrOS.git fix: cmdline parser, VBE framebuffer, VA collision, ring3 test, code audit - fix(cmdline): don't skip token 0 when GRUB2+Multiboot2 omits kernel path GRUB2 may pass only arguments (e.g. 'ring3') without the kernel path. The parser now only skips token 0 if it starts with '/'. - feat(vbe): add Multiboot2 framebuffer request tag to boot.S Requests 1024x768x32 linear framebuffer from GRUB (optional flag=1). Add fb_type field to boot_info for detecting framebuffer vs text mode. VGA text console conditionally disabled when linear framebuffer active. - fix(va): hal_mm_map_physical_range used 0xE0000000 (KVA_FRAMEBUFFER) This caused the initrd mapping to be destroyed when VBE mapped the framebuffer at the same VA. Moved to KVA_PHYS_MAP at 0xDC000000. - fix(ring3): run ring3 test in own kernel thread instead of PID 0 x86_usermode_test_start() enters ring3 via iret and never returns. Previously hidden because ring3 flag was never recognized (cmdline bug). - feat(console): wire console= cmdline parameter to console subsystem Supports console=serial, console=vga, console=ttyS0, console=tty0. - refactor: use KVA_FRAMEBUFFER from kernel_va_map.h in vbe.c - cleanup: replace inline extern rtc_unix_timestamp with #include rtc.h - fix(multiboot2): remove break after MODULE tag to scan ALL tags Build: clean. cppcheck: clean. Tests: 20/20 smoke, 47/47 host unit. --- diff --git a/include/kernel/boot_info.h b/include/kernel/boot_info.h index 5696d6b..e61c26b 100644 --- a/include/kernel/boot_info.h +++ b/include/kernel/boot_info.h @@ -18,6 +18,7 @@ struct boot_info { uint32_t fb_width; uint32_t fb_height; uint8_t fb_bpp; + uint8_t fb_type; /* 0=indexed, 1=direct RGB (linear), 2=EGA text */ }; #endif diff --git a/include/kernel_va_map.h b/include/kernel_va_map.h index 3360b99..b5c3505 100644 --- a/include/kernel_va_map.h +++ b/include/kernel_va_map.h @@ -24,6 +24,8 @@ * 0xC0400000 LAPIC MMIO (1 page) * 0xC8000000 .. Kernel stacks (guard + 8KB per thread) * 0xD0000000 .. Kernel heap (10 MB) + * 0xDC000000 .. Initrd / generic phys mapping (up to 64 MB) + * 0xE0000000 .. Framebuffer mapping (up to 16 MB) */ /* IOAPIC (arch/x86/ioapic.c) */ @@ -53,4 +55,10 @@ /* LAPIC (arch/x86/lapic.c) */ #define KVA_LAPIC 0xC0400000U +/* Initrd / generic physical range mapping (hal/x86/mm.c) */ +#define KVA_PHYS_MAP 0xDC000000U + +/* Framebuffer (drivers/vbe.c) — up to 16 MB for large resolutions */ +#define KVA_FRAMEBUFFER 0xE0000000U + #endif diff --git a/src/arch/x86/arch_early_setup.c b/src/arch/x86/arch_early_setup.c index e709647..371e84d 100644 --- a/src/arch/x86/arch_early_setup.c +++ b/src/arch/x86/arch_early_setup.c @@ -44,6 +44,7 @@ static uint32_t multiboot_copy_size; bi.fb_width = 0; bi.fb_height = 0; bi.fb_bpp = 0; + bi.fb_type = 0; if (mbi_phys) { uint32_t total_size = *(volatile uint32_t*)mbi_phys; @@ -68,9 +69,10 @@ static uint32_t multiboot_copy_size; tag = (struct multiboot_tag*)((uint8_t*)tag + ((tag->size + 7) & ~7))) { if (tag->type == MULTIBOOT_TAG_TYPE_MODULE) { const struct multiboot_tag_module* mod = (const struct multiboot_tag_module*)tag; - bi.initrd_start = mod->mod_start; - bi.initrd_end = mod->mod_end; - break; + if (!bi.initrd_start) { + bi.initrd_start = mod->mod_start; + bi.initrd_end = mod->mod_end; + } } if (tag->type == MULTIBOOT_TAG_TYPE_CMDLINE) { const struct multiboot_tag_string* s = (const struct multiboot_tag_string*)tag; @@ -83,6 +85,7 @@ static uint32_t multiboot_copy_size; bi.fb_width = fb->framebuffer_width; bi.fb_height = fb->framebuffer_height; bi.fb_bpp = fb->framebuffer_bpp; + bi.fb_type = fb->framebuffer_type; } } } diff --git a/src/arch/x86/arch_platform.c b/src/arch/x86/arch_platform.c index 5ef8248..e73d9fa 100644 --- a/src/arch/x86/arch_platform.c +++ b/src/arch/x86/arch_platform.c @@ -80,7 +80,7 @@ static void userspace_init_thread(void) { } } - kprintf("[ELF] starting /bin/init.elf\n"); + kprintf("[ELF] starting %s\n", init_path); kprintf("[ELF] user_range_ok(entry)=%c user_range_ok(stack)=%c\n", user_range_ok((const void*)entry, 1) ? '1' : '0', @@ -100,14 +100,21 @@ static void userspace_init_thread(void) { #endif int arch_platform_setup(const struct boot_info* bi) { - (void)bi; #if defined(__i386__) vmm_init(); - vga_init(); - vga_set_color(0x0A, 0x00); - console_enable_vga(1); - kprintf("[AdrOS] Kernel Initialized (VGA).\n"); + /* Enable VGA text console only if we are NOT in linear framebuffer mode. + * When GRUB provides a linear framebuffer (fb_type==1), the VGA text + * buffer at 0xB8000 is inactive — serial console carries all output. */ + if (!bi || bi->fb_type != 1) { + vga_init(); + vga_set_color(0x0A, 0x00); + console_enable_vga(1); + kprintf("[AdrOS] Kernel Initialized (VGA text mode).\n"); + } else { + kprintf("[AdrOS] Kernel Initialized (framebuffer %ux%ux%u, VGA text disabled).\n", + (unsigned)bi->fb_width, (unsigned)bi->fb_height, (unsigned)bi->fb_bpp); + } syscall_init(); @@ -167,8 +174,13 @@ int arch_platform_start_userspace(const struct boot_info* bi) { #endif } +static void ring3_test_thread(void) { + x86_usermode_test_start(); + for (;;) hal_cpu_idle(); +} + void arch_platform_usermode_test_start(void) { #if defined(__i386__) - x86_usermode_test_start(); + process_create_kernel(ring3_test_thread); #endif } diff --git a/src/arch/x86/boot.S b/src/arch/x86/boot.S index 341d4d4..a3a064c 100644 --- a/src/arch/x86/boot.S +++ b/src/arch/x86/boot.S @@ -20,6 +20,20 @@ multiboot_header_start: .long MB_ARCH .long multiboot_header_end - multiboot_header_start .long 0x100000000 - (MB_MAGIC + MB_ARCH + (multiboot_header_end - multiboot_header_start)) + + /* Framebuffer request tag (type 5, optional) */ + .align 8 +fb_tag_start: + .word 5 /* type: framebuffer */ + .word 1 /* flags: optional (boot even if unavailable) */ + .long fb_tag_end - fb_tag_start + .long 1024 /* preferred width */ + .long 768 /* preferred height */ + .long 32 /* preferred depth (bpp) */ +fb_tag_end: + + /* End tag */ + .align 8 .word 0, 0 .long 8 multiboot_header_end: diff --git a/src/drivers/vbe.c b/src/drivers/vbe.c index 4c4ebf7..55cace1 100644 --- a/src/drivers/vbe.c +++ b/src/drivers/vbe.c @@ -6,6 +6,7 @@ #include "uaccess.h" #include "console.h" #include "utils.h" +#include "kernel_va_map.h" #include @@ -27,7 +28,7 @@ int vbe_init(const struct boot_info* bi) { g_vbe.size = g_vbe.pitch * g_vbe.height; uint32_t pages = (g_vbe.size + 0xFFF) >> 12; - uintptr_t virt_base = 0xE0000000U; + uintptr_t virt_base = KVA_FRAMEBUFFER; for (uint32_t i = 0; i < pages; i++) { vmm_map_page((uint64_t)(g_vbe.phys_addr + i * 0x1000), diff --git a/src/hal/x86/mm.c b/src/hal/x86/mm.c index 158a8ed..c927adc 100644 --- a/src/hal/x86/mm.c +++ b/src/hal/x86/mm.c @@ -1,6 +1,7 @@ #include "hal/mm.h" #include "vmm.h" +#include "kernel_va_map.h" #include @@ -9,7 +10,7 @@ int hal_mm_map_physical_range(uintptr_t phys_start, uintptr_t phys_end, uint32_t if (phys_end < phys_start) phys_end = phys_start; - const uintptr_t virt_base = 0xE0000000U; + const uintptr_t virt_base = KVA_PHYS_MAP; uintptr_t phys_start_aligned = phys_start & ~(uintptr_t)0xFFF; uintptr_t phys_end_aligned = (phys_end + 0xFFF) & ~(uintptr_t)0xFFF; diff --git a/src/kernel/cmdline.c b/src/kernel/cmdline.c index 43469ae..a1029e1 100644 --- a/src/kernel/cmdline.c +++ b/src/kernel/cmdline.c @@ -113,11 +113,18 @@ void cmdline_parse(const char* raw) { return; } - /* Token 0 is the kernel path — skip it. - * Process remaining tokens. */ + /* Token 0 may be the kernel path (e.g. "/boot/adros-x86.bin") — + * skip it only if it looks like a path. GRUB2 with Multiboot2 + * does NOT always include the kernel path in the cmdline string; + * it may pass only the arguments (e.g. "ring3" or "init=/bin/sh"). */ + int start_idx = 0; + if (ntokens > 0 && tokens[0][0] == '/') { + start_idx = 1; + } + int after_separator = 0; - for (int i = 1; i < ntokens; i++) { + for (int i = start_idx; i < ntokens; i++) { const char* tok = tokens[i]; /* Check for "--" separator */ diff --git a/src/kernel/init.c b/src/kernel/init.c index d86ab48..39dffb4 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -166,6 +166,22 @@ int init_start(const struct boot_info* bi) { /* Parse kernel command line (Linux-like triaging) */ cmdline_parse(bi ? bi->cmdline : NULL); + /* Apply console= parameter: serial, vga, or both (default) */ + const char* con = cmdline_get("console"); + if (con) { + if (strcmp(con, "serial") == 0 || strcmp(con, "ttyS0") == 0) { + console_enable_uart(1); + console_enable_vga(0); + kprintf("[CONSOLE] output: serial only\n"); + } else if (strcmp(con, "vga") == 0 || strcmp(con, "tty0") == 0) { + console_enable_uart(0); + console_enable_vga(1); + kprintf("[CONSOLE] output: VGA only\n"); + } else { + kprintf("[CONSOLE] unknown console=%s, using both\n", con); + } + } + if (bi && bi->initrd_start) { uintptr_t initrd_virt = 0; if (hal_mm_map_physical_range((uintptr_t)bi->initrd_start, (uintptr_t)bi->initrd_end, diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 25ad284..c7b5738 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -27,6 +27,7 @@ #include "arch_signal.h" #include "arch_syscall.h" #include "arch_process.h" +#include "rtc.h" #include @@ -1731,7 +1732,6 @@ static int syscall_clock_gettime_impl(uint32_t clk_id, struct timespec* user_tp) struct timespec tp; if (clk_id == CLOCK_REALTIME) { - extern uint32_t rtc_unix_timestamp(void); tp.tv_sec = rtc_unix_timestamp(); tp.tv_nsec = 0; } else {