This commit is contained in:
nub31
2025-12-28 20:05:47 +01:00
parent 7702949534
commit dae0f9e852
15 changed files with 474 additions and 96 deletions

39
src/boot/boot.asm Normal file
View File

@@ -0,0 +1,39 @@
global _start
extern c_start
%define MAGIC 0xe85250d6
%define ARCH 0x0
%define LENGTH (header.end - header.start)
section .multiboot
align 8
header:
.start:
dd MAGIC
dd ARCH
dd LENGTH
dd -(MAGIC + ARCH + LENGTH)
; end tag
dw 0
dw 0
dd 8
.end:
section .bss
align 4096
stack:
.bottom:
resb 1024 * 16
.top:
section .text
_start:
mov esp, stack.top
push ebx
push eax
call c_start
add esp, 8
.halt:
cli
hlt
jmp .halt

168
src/boot/console.c Normal file
View File

@@ -0,0 +1,168 @@
#include "console.h"
#include <string.h>
#define ROWS 25
#define COLUMNS 80
typedef struct {
u8 character;
u8 color;
} vga_char_t;
static vga_char_t *vga_buffer = (vga_char_t *)0xb8000;
static u8 cursor_row = 0;
static u8 cursor_col = 0;
void console_putchar(char c, u8 color) {
switch (c) {
case '\n': {
cursor_row += 1;
cursor_col = 0;
break;
}
case '\r': {
cursor_col = 0;
break;
}
case '\t': {
u8 remainder = 4 - (cursor_col % 4);
cursor_col += remainder;
break;
}
case '\b': {
if (cursor_col > 0) {
cursor_col -= 1;
} else if (cursor_row > 0) {
cursor_row -= 1;
cursor_col = 0;
for (int col = COLUMNS - 1; col >= 0; col--) {
vga_char_t cell = vga_buffer[cursor_row * COLUMNS + col];
if (cell.character != ' ') {
cursor_col = col;
break;
}
}
}
vga_buffer[cursor_row * COLUMNS + cursor_col] = (vga_char_t){
.character = ' ',
.color = VGA_DEFAULT_COLOR,
};
break;
}
default: {
vga_buffer[COLUMNS * cursor_row + cursor_col] = (vga_char_t){
.character = c,
.color = color,
};
cursor_col += 1;
break;
}
}
if (cursor_col >= COLUMNS) {
cursor_col = 0;
cursor_row += 1;
}
if (cursor_row >= ROWS) {
for (size_t row = 1; row < ROWS; row++) {
for (size_t col = 0; col < COLUMNS; col++) {
vga_buffer[COLUMNS * (row - 1) + col] = vga_buffer[COLUMNS * row + col];
}
}
for (size_t col = 0; col < COLUMNS; col++) {
vga_buffer[COLUMNS * (ROWS - 1) + col] = (vga_char_t){
.character = ' ',
.color = VGA_DEFAULT_COLOR,
};
};
cursor_row = ROWS - 1;
}
}
void console_clear() {
for (size_t row = 0; row < ROWS; row++) {
for (size_t col = 0; col < COLUMNS; col++) {
vga_buffer[COLUMNS * row + col] = (vga_char_t){
.character = ' ',
.color = VGA_DEFAULT_COLOR,
};
}
}
cursor_row = 0;
cursor_col = 0;
}
// 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);
bool should_format = false;
for (size_t i = 0; fmt[i] != '\0'; i++) {
if (should_format) {
should_format = false;
if (fmt[i] == '%') {
console_putchar('%', VGA_DEFAULT_COLOR);
} else if (fmt[i] == 's') {
const char *str = va_arg(args, const char *);
for (size_t j = 0; str[j] != '\0'; j++) {
console_putchar(str[j], VGA_DEFAULT_COLOR);
}
} else if (fmt[i] == 'c') {
char character = (char)va_arg(args, u32);
console_putchar(character, VGA_DEFAULT_COLOR);
} else if (fmt[i] == 'd') {
u32 val = va_arg(args, u32);
char buf[21];
itoa(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);
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);
for (size_t j = 0; buf[j] != '\0'; j++) {
console_putchar(buf[j], VGA_DEFAULT_COLOR);
}
} else {
console_putchar(fmt[i], VGA_DEFAULT_COLOR);
}
} else if (fmt[i] == '%') {
should_format = true;
} else {
console_putchar(fmt[i], VGA_DEFAULT_COLOR);
}
}
va_end(args);
}

29
src/boot/console.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <def.h>
#define VGA_BLACK 0
#define VGA_BLUE 1
#define VGA_GREEN 2
#define VGA_CYAN 3
#define VGA_RED 4
#define VGA_MAGENTA 5
#define VGA_BROWN 6
#define VGA_LIGHT_GRAY 7
#define VGA_DARK_GRAY 8
#define VGA_LIGHT_BLUE 9
#define VGA_LIGHT_GREEN 10
#define VGA_LIGHT_CYAN 11
#define VGA_LIGHT_RED 12
#define VGA_LIGHT_MAGENTA 13
#define VGA_YELLOW 14
#define VGA_WHITE 15
#define VGA_COLOR(fg, bg) (fg | bg << 4)
#define VGA_DEFAULT_COLOR VGA_COLOR(VGA_LIGHT_GRAY, VGA_BLACK)
void console_putchar(char character, u8 color);
void console_clear();
void kprintf(const char *fmt, ...);

154
src/boot/entry.c Normal file
View File

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

6
src/boot/grub.cfg Normal file
View File

@@ -0,0 +1,6 @@
menuentry "nub-os" {
multiboot2 /boot/nub-os
}
set default="nub-os"
set timeout=0

221
src/boot/multiboot2.h Normal file
View File

@@ -0,0 +1,221 @@
#pragma once
#define MULTIBOOT_BOOTLOADER_MAGIC 0x36d76289
#define MULTIBOOT_TAG_ALIGN 8
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_TAG_TYPE_VBE 7
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT_TAG_TYPE_APM 10
#define MULTIBOOT_TAG_TYPE_EFI32 11
#define MULTIBOOT_TAG_TYPE_EFI64 12
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT_TAG_TYPE_NETWORK 16
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
#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
typedef struct {
u8 red;
u8 green;
u8 blue;
} multiboot_color;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
typedef struct {
u32 type;
u32 size;
} multiboot_tag;
typedef struct {
u32 type;
u32 size;
char string[0];
} multiboot_tag_string;
typedef struct {
u32 type;
u32 size;
u32 mod_start;
u32 mod_end;
char cmdline[0];
} multiboot_tag_module;
typedef struct {
u32 type;
u32 size;
u32 mem_lower;
u32 mem_upper;
} multiboot_tag_basic_meminfo;
typedef struct {
u32 type;
u32 size;
u32 biosdev;
u32 slice;
u32 part;
} multiboot_tag_bootdev;
typedef struct {
u64 addr;
u64 len;
u32 type;
u32 zero;
} multiboot_mmap_entry;
typedef struct {
u32 type;
u32 size;
u32 entry_size;
u32 entry_version;
multiboot_mmap_entry entries[0];
} multiboot_tag_mmap;
typedef struct {
u32 type;
u32 size;
u16 vbe_mode;
u16 vbe_interface_seg;
u16 vbe_interface_off;
u16 vbe_interface_len;
u8 vbe_control_info[512];
u8 vbe_mode_info[256];
} multiboot_tag_vbe;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
typedef struct {
u32 type;
u32 size;
u64 framebuffer_addr;
u32 framebuffer_pitch;
u32 framebuffer_width;
u32 framebuffer_height;
u8 framebuffer_bpp;
u8 framebuffer_type;
u16 reserved;
union {
struct {
u16 framebuffer_palette_num_colors;
multiboot_color framebuffer_palette[0];
};
struct {
u8 framebuffer_red_field_position;
u8 framebuffer_red_mask_size;
u8 framebuffer_green_field_position;
u8 framebuffer_green_mask_size;
u8 framebuffer_blue_field_position;
u8 framebuffer_blue_mask_size;
};
};
} multiboot_tag_framebuffer;
typedef struct {
u32 type;
u32 size;
u32 num;
u32 entsize;
u32 shndx;
char sections[0];
} multiboot_tag_elf_sections;
typedef struct {
u32 type;
u32 size;
u16 version;
u16 cseg;
u32 offset;
u16 cseg_16;
u16 dseg;
u16 flags;
u16 cseg_len;
u16 cseg_16_len;
u16 dseg_len;
} multiboot_tag_apm;
typedef struct {
u32 type;
u32 size;
u32 pointer;
} multiboot_tag_efi32;
typedef struct {
u32 type;
u32 size;
u64 pointer;
} multiboot_tag_efi64;
typedef struct {
u32 type;
u32 size;
u8 major;
u8 minor;
u8 reserved[6];
u8 tables[0];
} multiboot_tag_smbios;
typedef struct {
u32 type;
u32 size;
u8 rsdp[0];
} multiboot_tag_old_acpi;
typedef struct {
u32 type;
u32 size;
u8 rsdp[0];
} multiboot_tag_new_acpi;
typedef struct {
u32 type;
u32 size;
u8 dhcpack[0];
} multiboot_tag_network;
typedef struct {
u32 type;
u32 size;
u32 descr_size;
u32 descr_vers;
u8 efi_mmap[0];
} multiboot_tag_efi_mmap;
typedef struct {
u32 type;
u32 size;
u32 pointer;
} multiboot_tag_efi32_ih;
typedef struct {
u32 type;
u32 size;
u64 pointer;
} multiboot_tag_efi64_ih;
typedef struct {
u32 type;
u32 size;
u32 load_base_addr;
} multiboot_tag_load_base_addr;