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.
This commit is contained in:
lordtet 2025-07-05 04:36:39 -04:00
parent 53198515c8
commit 472f91fe14
8 changed files with 95 additions and 25 deletions

View file

@ -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

View file

@ -7,8 +7,15 @@
#define KMULTIBOOT_H
#include <stdint.h>
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

View file

@ -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

View file

@ -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 = .;
}

View file

@ -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);
}

View file

@ -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';

View file

@ -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);
}
}

View file

@ -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.