From 532d3e7b483c45ee7bf417d2ce67436b746892fd Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 30 Dec 2025 01:36:52 +0100 Subject: [PATCH] ... --- linker/x86_64.ld | 2 + src/boot/console.c | 67 +++++++++++++----- src/boot/console.h | 3 +- src/boot/entry.c | 154 ----------------------------------------- src/boot/multiboot2.h | 37 +++++++--- src/boot/panic.c | 20 ++++++ src/boot/panic.h | 3 + src/boot/start.c | 74 ++++++++++++++++++++ src/boot/util.h | 13 ++++ src/shared/string.c | 156 ++++++++++++++++++++++++++++-------------- src/shared/string.h | 18 ++++- 11 files changed, 309 insertions(+), 238 deletions(-) delete mode 100644 src/boot/entry.c create mode 100644 src/boot/panic.c create mode 100644 src/boot/panic.h create mode 100644 src/boot/start.c create mode 100644 src/boot/util.h diff --git a/linker/x86_64.ld b/linker/x86_64.ld index 1c416ea..39ed68b 100644 --- a/linker/x86_64.ld +++ b/linker/x86_64.ld @@ -4,6 +4,8 @@ SECTIONS { . = 2M; + kernel_start = .; + .text : { *(.multiboot) diff --git a/src/boot/console.c b/src/boot/console.c index 0c01893..1e54a14 100644 --- a/src/boot/console.c +++ b/src/boot/console.c @@ -104,19 +104,7 @@ void console_clear() { // - `x`: u32 (hex) // - `c`: char (ascii) // - `s`: char* (ascii string) -// -// ```c -// printf( -// "The answer is %d is located at offset %x in file %s", -// 42, -// 0x2000 -// "hitchhiker.txt" -// ); -// ``` -void kprintf(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - +void kvprintf(const char *fmt, va_list args) { bool should_format = false; for (size_t i = 0; fmt[i] != '\0'; i++) { @@ -135,25 +123,46 @@ void kprintf(const char *fmt, ...) { console_putchar(character, VGA_DEFAULT_COLOR); } else if (fmt[i] == 'd') { u32 val = va_arg(args, u32); - char buf[21]; - itoa(val, buf); + char buf[ITOA32_BUFSIZE]; + itoa32(val, buf); for (size_t j = 0; buf[j] != '\0'; j++) { console_putchar(buf[j], VGA_DEFAULT_COLOR); } } else if (fmt[i] == 'u') { u32 val = va_arg(args, u32); - char buf[21]; - uitoa(val, buf); + char buf[UITOA32_BUFSIZE]; + uitoa32(val, buf); for (size_t j = 0; buf[j] != '\0'; j++) { console_putchar(buf[j], VGA_DEFAULT_COLOR); } } else if (fmt[i] == 'x') { u32 val = va_arg(args, u32); - char buf[17]; - uitoa_hex(val, buf); + char buf[UITOA32_HEX_BUFSIZE]; + uitoa32_hex(val, buf); for (size_t j = 0; buf[j] != '\0'; j++) { console_putchar(buf[j], VGA_DEFAULT_COLOR); } + } else if (fmt[i] == 'D') { + i64 val = va_arg(args, i64); + char buf[ITOA64_BUFSIZE]; + itoa64(val, buf); + for (size_t j = 0; buf[j] != '\0'; j++) { + console_putchar(buf[j], VGA_DEFAULT_COLOR); + } + } else if (fmt[i] == 'U') { + u64 val = va_arg(args, u64); + char buf[UITOA64_BUFSIZE]; + uitoa64(val, buf); + for (size_t j = 0; buf[j] != '\0'; j++) + console_putchar(buf[j], VGA_DEFAULT_COLOR); + + } else if (fmt[i] == 'X') { + u64 val = va_arg(args, u64); + char buf[UITOA64_HEX_BUFSIZE]; + uitoa64_hex(val, buf); + for (size_t j = 0; buf[j] != '\0'; j++) + console_putchar(buf[j], VGA_DEFAULT_COLOR); + } else { console_putchar(fmt[i], VGA_DEFAULT_COLOR); } @@ -163,6 +172,26 @@ void kprintf(const char *fmt, ...) { console_putchar(fmt[i], VGA_DEFAULT_COLOR); } } +} +// Supported formats: +// - `d`: i32 (decimal) +// - `u`: u32 (decimal) +// - `x`: u32 (hex) +// - `c`: char (ascii) +// - `s`: char* (ascii string) +// +// ```c +// printf( +// "The answer is %d is located at offset %x in file %s", +// 42, +// 0x2000 +// "hitchhiker.txt" +// ); +// ``` +void kprintf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + kvprintf(fmt, args); va_end(args); } \ No newline at end of file diff --git a/src/boot/console.h b/src/boot/console.h index 5aaf878..5453eea 100644 --- a/src/boot/console.h +++ b/src/boot/console.h @@ -26,4 +26,5 @@ void console_putchar(char character, u8 color); void console_clear(); -void kprintf(const char *fmt, ...); \ No newline at end of file +void kprintf(const char *fmt, ...); +void kvprintf(const char *fmt, va_list args); \ No newline at end of file diff --git a/src/boot/entry.c b/src/boot/entry.c deleted file mode 100644 index 0bf128a..0000000 --- a/src/boot/entry.c +++ /dev/null @@ -1,154 +0,0 @@ -#include -#include "console.h" -#include "multiboot2.h" - -static inline void hlt() { - asm("hlt"); -} - -static inline void cli() { - asm("cli"); -} - -void kpanic(const char *message) { - kprintf("panic: %s\n", message); - while (true) { - cli(); - hlt(); - } -} - -u32 align(u32 num, u32 alignment) { - return (num + alignment - 1) & ~(alignment - 1); -} - -void c_start(u32 magic, uptr multiboot_info) { - console_clear(); - - if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { - kpanic("Magic is wrong"); - } - - uptr next = multiboot_info + 8; - - while (true) { - multiboot_tag *tag = (multiboot_tag*)next; - - if (tag->type == MULTIBOOT_TAG_TYPE_END) { - break; - } - - switch (tag->type) { - case MULTIBOOT_TAG_TYPE_CMDLINE: { - multiboot_tag_string *tag_cmdline = (multiboot_tag_string*)tag; - kprintf("cmdline: %s\n", tag_cmdline->string); - break; - } - case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: { - multiboot_tag_string *tag_bootloader = (multiboot_tag_string*)tag; - kprintf("bootloader: %s\n", tag_bootloader->string); - break; - } - case MULTIBOOT_TAG_TYPE_MODULE: { - multiboot_tag_module *tag_module = (multiboot_tag_module*)tag; - kprintf("MULTIBOOT_TAG_TYPE_MODULE\n"); - break; - } - case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: { - multiboot_tag_basic_meminfo *tag_basic_meminfo = (multiboot_tag_basic_meminfo*)tag; - kprintf("MULTIBOOT_TAG_TYPE_BASIC_MEMINFO\n"); - break; - } - case MULTIBOOT_TAG_TYPE_BOOTDEV: { - multiboot_tag_bootdev *tag_bootdev = (multiboot_tag_bootdev*)tag; - kprintf("MULTIBOOT_TAG_TYPE_BOOTDEV\n"); - break; - } - case MULTIBOOT_TAG_TYPE_MMAP: { - multiboot_tag_mmap *tag_mmap = (multiboot_tag_mmap*)tag; - kprintf("MULTIBOOT_TAG_TYPE_MMAP\n"); - break; - } - case MULTIBOOT_TAG_TYPE_VBE: { - multiboot_tag_vbe *tag_vbe = (multiboot_tag_vbe*)tag; - kprintf("MULTIBOOT_TAG_TYPE_VBE\n"); - break; - } - case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: { - multiboot_tag_framebuffer *tag_framebuffer = (multiboot_tag_framebuffer*)tag; - kprintf("MULTIBOOT_TAG_TYPE_FRAMEBUFFER\n"); - break; - } - case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: { - multiboot_tag_elf_sections *tag_elf_sections = (multiboot_tag_elf_sections*)tag; - kprintf("MULTIBOOT_TAG_TYPE_ELF_SECTIONS\n"); - break; - } - case MULTIBOOT_TAG_TYPE_APM: { - multiboot_tag_apm *tag_apm = (multiboot_tag_apm*)tag; - kprintf("MULTIBOOT_TAG_TYPE_APM\n"); - break; - } - case MULTIBOOT_TAG_TYPE_EFI32: { - multiboot_tag_efi32 *tag_efi32 = (multiboot_tag_efi32*)tag; - kprintf("MULTIBOOT_TAG_TYPE_EFI32\n"); - break; - } - case MULTIBOOT_TAG_TYPE_EFI64: { - multiboot_tag_efi64 *tag_efi64 = (multiboot_tag_efi64*)tag; - kprintf("MULTIBOOT_TAG_TYPE_EFI64\n"); - break; - } - case MULTIBOOT_TAG_TYPE_SMBIOS: { - multiboot_tag_smbios *tag_smbios = (multiboot_tag_smbios*)tag; - kprintf("MULTIBOOT_TAG_TYPE_SMBIOS\n"); - break; - } - case MULTIBOOT_TAG_TYPE_ACPI_OLD: { - multiboot_tag_old_acpi *tag_old_acpi = (multiboot_tag_old_acpi*)tag; - kprintf("MULTIBOOT_TAG_TYPE_ACPI_OLD\n"); - break; - } - case MULTIBOOT_TAG_TYPE_ACPI_NEW: { - multiboot_tag_new_acpi *tag_new_acpi = (multiboot_tag_new_acpi*)tag; - kprintf("MULTIBOOT_TAG_TYPE_ACPI_NEW\n"); - break; - } - case MULTIBOOT_TAG_TYPE_NETWORK: { - multiboot_tag_network *tag_network = (multiboot_tag_network*)tag; - kprintf("MULTIBOOT_TAG_TYPE_NETWORK\n"); - break; - } - case MULTIBOOT_TAG_TYPE_EFI_MMAP: { - multiboot_tag_efi_mmap *tag_efi_mmap = (multiboot_tag_efi_mmap*)tag; - kprintf("MULTIBOOT_TAG_TYPE_EFI_MMAP\n"); - break; - } - case MULTIBOOT_TAG_TYPE_EFI_BS: { - // note(nub31): Just a flag, no data - break; - } - case MULTIBOOT_TAG_TYPE_EFI32_IH: { - multiboot_tag_efi32_ih *tag_efi32_ih = (multiboot_tag_efi32_ih*)tag; - kprintf("MULTIBOOT_TAG_TYPE_EFI32_IH\n"); - break; - } - case MULTIBOOT_TAG_TYPE_EFI64_IH: { - multiboot_tag_efi64_ih *tag_efi64_ih = (multiboot_tag_efi64_ih*)tag; - kprintf("MULTIBOOT_TAG_TYPE_EFI64_IH\n"); - break; - } - case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: { - multiboot_tag_load_base_addr *tag_load_base_addr = (multiboot_tag_load_base_addr*)tag; - kprintf("MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR\n"); - break; - } - default: { - kpanic("Unhandled multiboot tag"); - break; - } - } - - next = align(next + tag->size, MULTIBOOT_TAG_ALIGN); - } -} diff --git a/src/boot/multiboot2.h b/src/boot/multiboot2.h index a95a1d8..a6396b8 100644 --- a/src/boot/multiboot2.h +++ b/src/boot/multiboot2.h @@ -1,3 +1,22 @@ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ #pragma once #define MULTIBOOT_BOOTLOADER_MAGIC 0x36d76289 @@ -25,7 +44,7 @@ #define MULTIBOOT_TAG_TYPE_EFI_BS 18 #define MULTIBOOT_TAG_TYPE_EFI32_IH 19 #define MULTIBOOT_TAG_TYPE_EFI64_IH 20 -#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDRESS 21 typedef struct { u8 red; @@ -69,15 +88,15 @@ typedef struct { u32 type; u32 size; u32 biosdev; - u32 slice; - u32 part; + u32 partition; + u32 sub_partition; } multiboot_tag_bootdev; typedef struct { - u64 addr; - u64 len; + u64 base_address; + u64 length; u32 type; - u32 zero; + u32 reserved; } multiboot_mmap_entry; typedef struct { @@ -108,7 +127,7 @@ typedef struct { typedef struct { u32 type; u32 size; - u64 framebuffer_addr; + u64 framebuffer_address; u32 framebuffer_pitch; u32 framebuffer_width; u32 framebuffer_height; @@ -217,5 +236,5 @@ typedef struct { typedef struct { u32 type; u32 size; - u32 load_base_addr; -} multiboot_tag_load_base_addr; + u32 load_base_address; +} multiboot_tag_load_base_address; diff --git a/src/boot/panic.c b/src/boot/panic.c new file mode 100644 index 0000000..0eb2c6b --- /dev/null +++ b/src/boot/panic.c @@ -0,0 +1,20 @@ +#include "panic.h" +#include "console.h" +#include "util.h" +#include + +void boot_panic(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + kprintf("panic: "); + kvprintf(fmt, args); + kprintf("\n"); + + va_end(args); + + while (true) { + cli(); + hlt(); + } +} \ No newline at end of file diff --git a/src/boot/panic.h b/src/boot/panic.h new file mode 100644 index 0000000..c04f2f4 --- /dev/null +++ b/src/boot/panic.h @@ -0,0 +1,3 @@ +#pragma once + +void boot_panic(const char *fmt, ...); \ No newline at end of file diff --git a/src/boot/start.c b/src/boot/start.c new file mode 100644 index 0000000..fd6171a --- /dev/null +++ b/src/boot/start.c @@ -0,0 +1,74 @@ +#include +#include "console.h" +#include "multiboot2.h" +#include "panic.h" +#include "util.h" + +static void *multiboot_find_tag(uptr multiboot_info, u32 type) { + uptr next = multiboot_info + 8; + + while (true) { + multiboot_tag *tag = (multiboot_tag*)next; + + if (tag->type == MULTIBOOT_TAG_TYPE_END) { + return NULL; + } + + if (tag->type == type) { + return tag; + } + + next = align(next + tag->size, MULTIBOOT_TAG_ALIGN); + } +} + +#define MAX_REGIONS 64 + +typedef struct { + u64 base_address; + u64 length; +} region; + +extern uptr kernel_start; +extern uptr kernel_end; + +static region regions[MAX_REGIONS] = {0}; +static u32 region_count = 0; + +static void find_memory_regions(uptr multiboot_info) { + multiboot_tag_mmap *tag = multiboot_find_tag(multiboot_info, MULTIBOOT_TAG_TYPE_MMAP); + if (tag == NULL) { + boot_panic("Multiboot did not provide mmap tag"); + } + + u32 entry_count = (tag->size - 16) / tag->entry_size; + u8 *entry_ptr = (u8*)tag->entries; + + for (u32 i = 0; i < entry_count; ++i) { + multiboot_mmap_entry *entry = (multiboot_mmap_entry*)entry_ptr; + + if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) { + if (region_count >= MAX_REGIONS) { + boot_panic("Too many memory regions"); + } + + regions[region_count++] = (region){ entry->base_address, entry->length }; + } + + entry_ptr += tag->entry_size; + } +} + +void c_start(u32 magic, uptr multiboot_info) { + console_clear(); + + if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { + boot_panic("Expected bootloader magic 0x%x, but got 0x%x", MULTIBOOT_BOOTLOADER_MAGIC, magic); + } + + find_memory_regions(multiboot_info); + + for (u32 i = 0; i < region_count; ++i) { + kprintf("base: 0x%X, length: 0x%X\n", regions[i].base_address, regions[i].length); + } +} \ No newline at end of file diff --git a/src/boot/util.h b/src/boot/util.h new file mode 100644 index 0000000..361ca39 --- /dev/null +++ b/src/boot/util.h @@ -0,0 +1,13 @@ +#pragma once + +static inline u32 align(u32 num, u32 alignment) { + return (num + alignment - 1) & ~(alignment - 1); +} + +static inline void hlt() { + asm("hlt"); +} + +static inline void cli() { + asm("cli"); +} \ No newline at end of file diff --git a/src/shared/string.c b/src/shared/string.c index dedb8d7..af3d313 100644 --- a/src/shared/string.c +++ b/src/shared/string.c @@ -21,49 +21,18 @@ void reverse(char *str, size_t length) { } } -void itoa(i32 value, char *buffer) { - char temp[21]; - int i = 0, j = 0; - int negative = 0; - +void itoa32(i32 value, char *buffer) { if (value < 0) { - negative = 1; - if (value == I32_MIN) { - const char *min_str = "9223372036854775808"; - for (i = 0; min_str[i] != '\0'; i++) - temp[i] = min_str[i]; - i = 19; - } else { - value = -value; - } + *buffer++ = '-'; + value = -value; } - if (value == 0 && !negative) { - buffer[0] = '0'; - buffer[1] = '\0'; - return; - } - - if (!(negative && value == I32_MIN)) { - while (value > 0) { - temp[i++] = '0' + (value % 10); - value /= 10; - } - } - - if (negative) { - temp[i++] = '-'; - } - - while (i > 0) { - buffer[j++] = temp[--i]; - } - buffer[j] = '\0'; + uitoa32((u32)value, buffer); } -void uitoa(u32 value, char *buffer) { - char temp[21]; - int i = 0, j = 0; +void uitoa32(u32 value, char *buffer) { + char tmp[11]; + int i = 0; if (value == 0) { buffer[0] = '0'; @@ -72,20 +41,20 @@ void uitoa(u32 value, char *buffer) { } while (value > 0) { - temp[i++] = '0' + (value % 10); + tmp[i++] = '0' + (value % 10); value /= 10; } - while (i > 0) { - buffer[j++] = temp[--i]; - } - buffer[j] = '\0'; + for (int j = 0; j < i; j++) + buffer[j] = tmp[i - j - 1]; + + buffer[i] = '\0'; } -void uitoa_hex(u32 value, char *buffer) { - const char *digits = "0123456789abcdef"; - char temp[17]; - int pos = 0; +void uitoa32_hex(u32 value, char *buffer) { + static const char hex[] = "0123456789abcdef"; + char tmp[9]; + int i = 0; if (value == 0) { buffer[0] = '0'; @@ -93,13 +62,96 @@ void uitoa_hex(u32 value, char *buffer) { return; } - while (value > 0 && pos < 16) { - temp[pos++] = digits[value & 0xF]; + while (value > 0) { + tmp[i++] = hex[value & 0xF]; value >>= 4; } - for (int i = 0; i < pos; i++) { - buffer[i] = temp[pos - i - 1]; + for (int j = 0; j < i; j++) + buffer[j] = tmp[i - j - 1]; + + buffer[i] = '\0'; +} + +void itoa64(i64 value, char *buffer) { + if (value < 0) { + *buffer++ = '-'; + value = -value; } - buffer[pos] = '\0'; + + uitoa64((u64)value, buffer); +} + +void uitoa64(u64 value, char *buffer) { + char *p = buffer; + + if (value == 0) { + *p++ = '0'; + *p = '\0'; + return; + } + + static const u64 powers[] = { + 10000000000000000000ULL, + 1000000000000000000ULL, + 100000000000000000ULL, + 10000000000000000ULL, + 1000000000000000ULL, + 100000000000000ULL, + 10000000000000ULL, + 1000000000000ULL, + 100000000000ULL, + 10000000000ULL, + 1000000000ULL, + 100000000ULL, + 10000000ULL, + 1000000ULL, + 100000ULL, + 10000ULL, + 1000ULL, + 100ULL, + 10ULL, + 1ULL + }; + + bool started = false; + + for (int i = 0; i < 20; i++) { + u64 power = powers[i]; + u32 digit = 0; + + while (value >= power) { + value -= power; + digit++; + } + + if (digit || started) { + *p++ = '0' + digit; + started = true; + } + } + + *p = '\0'; +} + +void uitoa64_hex(u64 value, char *buffer) { + static const char hex[] = "0123456789abcdef"; + char tmp[17]; + int i = 0; + + if (value == 0) { + buffer[0] = '0'; + buffer[1] = '\0'; + return; + } + + while (value > 0) { + tmp[i++] = hex[value & 0xF]; + value >>= 4; + } + + for (int j = 0; j < i; j++) + buffer[j] = tmp[i - j - 1]; + + buffer[i] = '\0'; } \ No newline at end of file diff --git a/src/shared/string.h b/src/shared/string.h index 943fa8d..aae3bcc 100644 --- a/src/shared/string.h +++ b/src/shared/string.h @@ -5,6 +5,18 @@ int strcmp(const char *a, const char *b); void reverse(char *str, size_t length); -void itoa(i32 value, char *buffer); -void uitoa(u32 value, char *buffer); -void uitoa_hex(u32 value, char *buffer); \ No newline at end of file +#define ITOA32_BUFSIZE 12 +#define UITOA32_BUFSIZE 11 +#define UITOA32_HEX_BUFSIZE 9 + +#define ITOA64_BUFSIZE 21 +#define UITOA64_BUFSIZE 21 +#define UITOA64_HEX_BUFSIZE 17 + +void itoa32(i32 value, char *buffer); +void uitoa32(u32 value, char *buffer); +void uitoa32_hex(u32 value, char *buffer); + +void itoa64(i64 value, char *buffer); +void uitoa64(u64 value, char *buffer); +void uitoa64_hex(u64 value, char *buffer);