This commit is contained in:
nub31
2025-12-30 01:36:52 +01:00
parent dae0f9e852
commit 532d3e7b48
11 changed files with 309 additions and 238 deletions

View File

@@ -4,6 +4,8 @@ SECTIONS
{
. = 2M;
kernel_start = .;
.text :
{
*(.multiboot)

View File

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

View File

@@ -27,3 +27,4 @@ void console_putchar(char character, u8 color);
void console_clear();
void kprintf(const char *fmt, ...);
void kvprintf(const char *fmt, va_list args);

View File

@@ -1,154 +0,0 @@
#include <def.h>
#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);
}
}

View File

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

20
src/boot/panic.c Normal file
View File

@@ -0,0 +1,20 @@
#include "panic.h"
#include "console.h"
#include "util.h"
#include <def.h>
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();
}
}

3
src/boot/panic.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void boot_panic(const char *fmt, ...);

74
src/boot/start.c Normal file
View File

@@ -0,0 +1,74 @@
#include <def.h>
#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);
}
}

13
src/boot/util.h Normal file
View File

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

View File

@@ -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 {
*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];
}
buffer[pos] = '\0';
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;
}
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';
}

View File

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