From 472f91fe14967f2a3a2403e211371e692f4e39e0 Mon Sep 17 00:00:00 2001 From: lordtet Date: Sat, 5 Jul 2025 04:36:39 -0400 Subject: [PATCH] Started work on memory map, added printf features Printf now has long (64-bit), char, and % literal support. I haven't written anything specific for shorts yet but if you cast it to an int on the way in, it'll work anyway, so whatever. --- include/io.h | 4 +-- include/kmultiboot.h | 21 ++++++++++----- include/kttools.h | 2 +- linker.ld | 6 ++++- src/io.c | 61 ++++++++++++++++++++++++++++++++++++-------- src/kttools.c | 2 +- src/main.c | 22 ++++++++++++++-- src/multiboot.s | 2 +- 8 files changed, 95 insertions(+), 25 deletions(-) diff --git a/include/io.h b/include/io.h index bab752c..16cf5a5 100644 --- a/include/io.h +++ b/include/io.h @@ -19,8 +19,8 @@ extern char_writer_t* default_output; int putc(char_writer_t*, char); int print(char_writer_t*, const char*); int println(char_writer_t*, const char*); -int printhex(char_writer_t*, uint32_t); -int prindec(char_writer_t*, uint32_t out); +int printhex(char_writer_t*, uint64_t); +int prindec(char_writer_t*, uint64_t out); int printf(char_writer_t*, const char* fmt, ...); #endif diff --git a/include/kmultiboot.h b/include/kmultiboot.h index e47f467..8e10641 100644 --- a/include/kmultiboot.h +++ b/include/kmultiboot.h @@ -7,8 +7,15 @@ #define KMULTIBOOT_H #include +typedef struct multiboot_mmap_entry { + uint32_t entry_size; //size of this struct entry + uint64_t addr; //physical location of memory + uint64_t mem_size; //size of the memory block + uint32_t type; +} __attribute__((packed)) mb_mmap_entry_t; -typedef struct { + +typedef struct mb_info_s { uint32_t flags; uint32_t mem_lower; uint32_t mem_upper; @@ -16,13 +23,13 @@ typedef struct { uint32_t cmdline; uint32_t mods_count; uint32_t mods_addr; + uint32_t syms[4]; + uint32_t mmap_length; + uint32_t mmap_addr; } mb_info_t; -typedef struct multiboot_mmap_entry { - uint32_t ssize; //size of the entry - uint64_t addr; //physical location of memory - uint64_t msize; - uint32_t type; -} __attribute__((packed)) mb_mmap_entry_t; + +extern uint8_t _kernel_start; +extern uint8_t _kernel_end; #endif diff --git a/include/kttools.h b/include/kttools.h index 69ae1cb..cbdd3a0 100644 --- a/include/kttools.h +++ b/include/kttools.h @@ -21,6 +21,6 @@ * @return No return value * */ -void i_to_str(uint32_t num, char* buf, int size, int radix); +void i_to_str(uint64_t num, char* buf, int size, int radix); #endif diff --git a/linker.ld b/linker.ld index 2978099..b4a188e 100644 --- a/linker.ld +++ b/linker.ld @@ -5,9 +5,10 @@ SECTIONS { /*start me at 1Mb because below that is x86 essential stuff, which we dont want to be written on top of.*/ . = 1M; + + _kernel_start = .; /* we're going to maintain 4K alignment - apparently useful for paging, and i'm not complaining about the lost space anyway. */ - /*our multiboot header from start.s - has to go at the beginning of the executable so the bootloader knows we're loadable.*/ /*executable section*/ .text BLOCK(4K) : ALIGN(4K) @@ -37,4 +38,7 @@ SECTIONS *(.bss) *(.idt) } + + _kernel_end = .; + } diff --git a/src/io.c b/src/io.c index c1e2bfc..3b1c424 100644 --- a/src/io.c +++ b/src/io.c @@ -4,15 +4,21 @@ char_writer_t* default_output = 0; -int printhex(char_writer_t* writer, uint32_t out) { - char buff[9]; - i_to_str(out, buff, 9, 0x10); +int printnum(char_writer_t* writer, int radix, uint64_t out) { + char buff[65]; + i_to_str(out, buff, 65, radix); return print(writer, buff); } -int printdec(char_writer_t* writer, uint32_t out) { - char buff[11]; - i_to_str(out, buff, 11, 10); +int printhex(char_writer_t* writer, uint64_t out) { + char buff[17]; + i_to_str(out, buff, 17, 0x10); + return print(writer, buff); +} + +int printdec(char_writer_t* writer, uint64_t out) { + char buff[21]; + i_to_str(out, buff, 21, 10); return print(writer, buff); } @@ -48,23 +54,58 @@ int println(char_writer_t* writer, const char* out) { */ int printf(char_writer_t* writer, const char* fmt, ...) { + //borrowed (stole) a lot of ideas for this from the linux implementation (thanks!) va_list args; va_start(args, fmt); int ret = 0; + uint64_t num = 0; + int radix = 9; + char qualifier = '\0'; while(*fmt) { if(*fmt == '%') { fmt++; + if(*fmt == 'l') { + qualifier = *fmt; + fmt++; + } switch(*fmt) { + case '%': + ret = putc(writer, '%'); + fmt++; + continue; + case 'c': + ret = putc(writer, va_arg(args, int)); + fmt++; + continue; + case 's': + ret = print(writer, va_arg(args, char*)); + fmt++; + continue; + //Integer definitions. case 'X': ret = print(writer, "0x"); case 'x': - ret = printhex(writer, va_arg(args,uint32_t)); + radix = 0x10; break; - case 'd': - ret = printdec(writer, va_arg(args,uint32_t)); + case 'u': + radix = 10; break; - + case 'b': + radix = 0b10; + break; + } + + if(qualifier == 'l'){ + num = va_arg(args, uint64_t); + qualifier = 0; + } + else { + num = va_arg(args, unsigned int); + } + + ret = printnum(writer, radix, num); + } else { ret = putc(writer,*fmt); } diff --git a/src/kttools.c b/src/kttools.c index c774308..8bd5b13 100644 --- a/src/kttools.c +++ b/src/kttools.c @@ -12,7 +12,7 @@ -void i_to_str(uint32_t num, char* buf, int size, int radix) { +void i_to_str(uint64_t num, char* buf, int size, int radix) { //null terminate the string if(num == 0){ buf[0] = '0'; diff --git a/src/main.c b/src/main.c index 534b79c..9035a4f 100644 --- a/src/main.c +++ b/src/main.c @@ -35,10 +35,9 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info) serial_init(&serial_ctx); //AND OUR DEFAULT OUTPUT IS: - default_output = default_vga; + default_output = default_COM; printf(default_output, "Entry eax:%X\n", multiboot_magic); - if(multiboot_magic != 0x2BADB002) { println(default_output, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!"); return; @@ -47,5 +46,24 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info) } printf(default_output, "MEM_LOWER:%X\n", multiboot_info->mem_lower); printf(default_output, "MEM_UPPER:%X\n", multiboot_info->mem_upper); + + //Let's get out memory map. + + if(!(multiboot_info->flags & (1<<6))){ + printf(default_output, "No mmap supplied by multiboot flags!"); + return; + } + + printf(default_output, "lol:%X", multiboot_info->flags); + int mmap_end = (uint32_t)multiboot_info->mmap_addr + multiboot_info->mmap_length; + + for(mb_mmap_entry_t* entry = (mb_mmap_entry_t*)multiboot_info->mmap_addr; + (int)entry < mmap_end; + entry = (mb_mmap_entry_t*)((int)entry + entry->entry_size + sizeof(entry->entry_size))) { + + printf(default_output,"__MMAP_ENTRY__:\nSTART_ADDR:%X\nSIZE:%X\nTYPE:%u\n",(uint32_t)entry->addr, (uint32_t)entry->mem_size, entry->type); + + } + } diff --git a/src/multiboot.s b/src/multiboot.s index e05ef8a..cf4b858 100644 --- a/src/multiboot.s +++ b/src/multiboot.s @@ -1,7 +1,7 @@ ;multiboot for GRUB to boot it. Ideally stage01_bootloader will be able to support the multiboot standard. ;regardless of who's doing it, we have to set the required stuff MB_MAGIC equ 0x1BADB002 ; bytes that bootloader will use to find this place -MB_FLAGS equ (1 << 0) | (1 << 1) ; flags request the following from the bootloader: maintain page boundaries + provide a memory map +MB_FLAGS equ (1 << 0) | (1 << 1); flags request the following from the bootloader: maintain page boundaries + provide a memory map MB_CHECKSUM equ (0 - (MB_MAGIC + MB_FLAGS)) ; Fails if checksum doesn't pass. Kind of arbitrary, but required.