Compare commits

...

10 Commits

Author SHA1 Message Date
nub31
ffebc6de45 ... 2025-12-31 01:43:22 +01:00
nub31
68458ffca5 ... 2025-12-31 01:40:02 +01:00
nub31
c364f7d019 ... 2025-12-31 01:38:06 +01:00
nub31
8a81bb0c87 ... 2025-12-31 01:35:43 +01:00
nub31
3e54b53f4b ... 2025-12-31 01:34:28 +01:00
nub31
f1c055db2a ... 2025-12-31 01:32:07 +01:00
nub31
c062a6fb34 ... 2025-12-30 23:25:56 +01:00
nub31
9fd2d0ca6d upgrade multiboot2 header 2025-12-30 23:07:39 +01:00
nub31
a9b25c5b9e ... 2025-12-30 22:27:01 +01:00
nub31
d15609e5c0 ... 2025-12-30 22:25:51 +01:00
11 changed files with 354 additions and 165 deletions

View File

@@ -1,67 +1,8 @@
#include "console.h"
#include "multiboot2.h"
#include "pmm.h"
#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 size_t 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 kmain(uptr multiboot_info) {
find_memory_regions(multiboot_info);
// We are now in long mode with kernel pages and vga buffer identity mapped
void x86_64_main() {
console_clear();
pmm_init();
}

31
src/boot/multiboot2.c Normal file
View File

@@ -0,0 +1,31 @@
#include "multiboot2.h"
#include "symbols.h"
#include "util.h"
// [size:4][reserved:4][data:N]
#define INFO_DATA_OFFSET 8
#define TAG_TYPE_OFFSET 0
#define TAG_SIZE_OFFSET 4
void *multiboot_get_tag(u32 type) {
uptr current = get_multiboot_info() + INFO_DATA_OFFSET;
while (true) {
u32 tag_type = *(u32*)(current + TAG_TYPE_OFFSET);
u32 tag_size = *(u32*)(current + TAG_SIZE_OFFSET);
if (tag_type == MULTIBOOT_TAG_TYPE_END) {
break;
}
if (tag_type == type) {
return (void*)current;
}
// note(nub31): Each tag is aligned to 8 bytes
current = ALIGN_UP(current + tag_size, 8);
}
return NULL;
}

View File

@@ -19,9 +19,7 @@
*/
#pragma once
#define MULTIBOOT_BOOTLOADER_MAGIC 0x36d76289
#define MULTIBOOT_TAG_ALIGN 8
#include <def.h>
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
@@ -44,30 +42,19 @@
#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_ADDRESS 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
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
typedef struct {
u32 type;
u32 size;
} multiboot_tag;
char cmdline[0];
} multiboot_tag_cmdline;
typedef struct {
u32 type;
u32 size;
char string[0];
} multiboot_tag_string;
char bootloader_name[0];
} multiboot_tag_bootloader_name;
typedef struct {
u32 type;
@@ -92,8 +79,14 @@ typedef struct {
u32 sub_partition;
} multiboot_tag_bootdev;
#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 {
u64 base_address;
u64 base_addr;
u64 length;
u32 type;
u32 reserved;
@@ -124,10 +117,16 @@ typedef struct {
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
typedef struct {
u8 red;
u8 green;
u8 blue;
} multiboot_color;
typedef struct {
u32 type;
u32 size;
u64 framebuffer_address;
u64 framebuffer_addr;
u32 framebuffer_pitch;
u32 framebuffer_width;
u32 framebuffer_height;
@@ -199,13 +198,13 @@ typedef struct {
u32 type;
u32 size;
u8 rsdp[0];
} multiboot_tag_old_acpi;
} multiboot_tag_acpi_old;
typedef struct {
u32 type;
u32 size;
u8 rsdp[0];
} multiboot_tag_new_acpi;
} multiboot_tag_acpi_new;
typedef struct {
u32 type;
@@ -236,5 +235,95 @@ typedef struct {
typedef struct {
u32 type;
u32 size;
u32 load_base_address;
} multiboot_tag_load_base_address;
u32 load_base_addr;
} multiboot_tag_load_base_addr;
void *multiboot_get_tag(u32 type);
static inline multiboot_tag_cmdline *multiboot_get_cmdline() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_CMDLINE);
}
static inline multiboot_tag_bootloader_name *multiboot_get_bootloader_name() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME);
}
static inline multiboot_tag_module *multiboot_get_module() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_MODULE);
}
static inline multiboot_tag_basic_meminfo *multiboot_get_basic_meminfo() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_BASIC_MEMINFO);
}
static inline multiboot_tag_bootdev *multiboot_get_bootdev() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_BOOTDEV);
}
static inline multiboot_tag_mmap *multiboot_get_mmap() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_MMAP);
}
static inline size_t get_mmap_entry_count(multiboot_tag_mmap *mmap) {
return (mmap->size - 16) / mmap->entry_size;
}
static inline multiboot_tag_vbe *multiboot_get_vbe() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_VBE);
}
static inline multiboot_tag_framebuffer *multiboot_get_framebuffer() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_FRAMEBUFFER);
}
static inline multiboot_tag_elf_sections *multiboot_get_elf_sections() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_ELF_SECTIONS);
}
static inline multiboot_tag_apm *multiboot_get_apm() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_APM);
}
static inline multiboot_tag_efi32 *multiboot_get_efi32() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_EFI32);
}
static inline multiboot_tag_efi64 *multiboot_get_efi64() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_EFI64);
}
static inline multiboot_tag_smbios *multiboot_get_smbios() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_SMBIOS);
}
static inline multiboot_tag_acpi_old *multiboot_get_acpi_old() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_ACPI_OLD);
}
static inline multiboot_tag_acpi_new *multiboot_get_acpi_new() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_ACPI_NEW);
}
static inline multiboot_tag_network *multiboot_get_network() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_NETWORK);
}
static inline multiboot_tag_efi_mmap *multiboot_get_efi_mmap() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_EFI_MMAP);
}
static inline bool multiboot_get_efi_bs() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_EFI_BS) != NULL;
}
static inline multiboot_tag_efi32_ih *multiboot_get_efi32_ih() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_EFI32_IH);
}
static inline multiboot_tag_efi64_ih *multiboot_get_efi64_ih() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_EFI64_IH);
}
static inline multiboot_tag_load_base_addr *multiboot_get_load_base_addr() {
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR);
}

116
src/boot/pmm.c Normal file
View File

@@ -0,0 +1,116 @@
#include "pmm.h"
#include "util.h"
#include "panic.h"
#include "multiboot2.h"
#include "symbols.h"
#include <def.h>
#define PAGE_SIZE 4096
#define MAX_PHYS_MEM GiB(128)
#define MAX_PAGES (MAX_PHYS_MEM / PAGE_SIZE)
#define BITMAP_SIZE ((MAX_PAGES + 63) / 64)
static u64 pmm_bitmap[BITMAP_SIZE];
static inline void bitmap_set(size_t bit) {
pmm_bitmap[bit / 64] |= (1ULL << (bit % 64));
}
static inline void bitmap_clear(size_t bit) {
pmm_bitmap[bit / 64] &= ~(1ULL << (bit % 64));
}
static inline int bitmap_test(size_t bit) {
return pmm_bitmap[bit / 64] & (1ULL << (bit % 64));
}
static inline size_t to_page(uptr addr) {
if (addr % PAGE_SIZE != 0) {
boot_panic("Address is not page aligned");
}
return addr / PAGE_SIZE;
}
static inline uptr to_addr(size_t page) {
return page * PAGE_SIZE;
}
static void clear_range(size_t start_page, size_t end_page) {
if (start_page >= MAX_PAGES) {
return;
}
if (end_page > MAX_PAGES) {
end_page = MAX_PAGES;
}
for (size_t j = start_page; j < end_page; ++j) {
bitmap_clear(j);
}
}
static void set_range(size_t start_page, size_t end_page) {
if (start_page >= MAX_PAGES) {
return;
}
if (end_page > MAX_PAGES) {
end_page = MAX_PAGES;
}
for (size_t j = start_page; j < end_page; ++j) {
bitmap_set(j);
}
}
void pmm_init() {
for (size_t i = 0; i < BITMAP_SIZE; i++) {
pmm_bitmap[i] = U64_MAX;
}
multiboot_tag_mmap *mmap = multiboot_get_mmap();
if (mmap == NULL) {
boot_panic("No memory map found");
}
for (size_t i = 0; i < get_mmap_entry_count(mmap); ++i) {
multiboot_mmap_entry entry = mmap->entries[i];
if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) {
size_t start_page = to_page(ALIGN_DOWN(entry.base_addr, PAGE_SIZE));
size_t end_page = to_page(ALIGN_UP(entry.base_addr + entry.length, PAGE_SIZE));
clear_range(start_page, end_page);
}
}
size_t start_page = to_page(ALIGN_DOWN(get_kernel_start(), PAGE_SIZE));
size_t end_page = to_page(ALIGN_UP(get_kernel_end(), PAGE_SIZE));
set_range(start_page, end_page);
}
void *pmm_alloc_page() {
for (size_t i = 0; i < MAX_PAGES; ++i) {
if (!bitmap_test(i)) {
bitmap_set(i);
return (void*)to_addr(i);
}
}
boot_panic("Out of physical memory");
}
void pmm_free_page(void *addr) {
size_t page = to_page((uptr)addr);
if (page >= MAX_PAGES) {
boot_panic("Trying to free page beyond physical memory limit");
}
if (!bitmap_test(page)) {
boot_panic("Page is already free");
}
bitmap_clear(page);
}

5
src/boot/pmm.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
void pmm_init();
void *pmm_alloc_page();
void pmm_free_page(void *addr);

View File

@@ -1,7 +1,8 @@
global _start
global multiboot_info
extern kernel_start
extern kernel_end
extern kmain
extern x86_64_main
%define MAGIC 0xe85250d6
%define ARCH 0x0
@@ -21,10 +22,6 @@ header:
dd 8
.end:
section .data
align 8
multiboot_info: dq 0
%define PRESENT 1 << 7
%define NOT_SYS 1 << 4
%define EXEC 1 << 3
@@ -58,6 +55,11 @@ gdt:
dq gdt
section .bss
%define MULTIBOOT_INFO_MAX_SIZE 1024 * 64
align 8
multiboot_info: resb MULTIBOOT_INFO_MAX_SIZE
align 16
stack:
.bottom:
@@ -79,29 +81,38 @@ _start:
cmp eax, BOOTLOADER_MAGIC
jne .halt
; Save pointer to info gathered by multiboot
mov [multiboot_info], ebx
; Copy multiboot structure to kernel owned memory
mov esi, ebx
mov eax, [esi]
cmp eax, MULTIBOOT_INFO_MAX_SIZE
ja .halt
mov edi, multiboot_info
mov ecx, eax
cld
rep movsb
; Tell the cpu where the pages area
mov edi, pml4t
mov cr3, edi
%define PT_PRESENT 1
%define PT_READABLE 2
%define PT_PRESENT 1
%define PT_RW 2
; pml4t[0] -> pdpt
mov edi, pdpt
or edi, PT_PRESENT | PT_READABLE
or edi, PT_PRESENT | PT_RW
mov [pml4t], edi
; pdpt[0] -> pdt
mov edi, pdt
or edi, PT_PRESENT | PT_READABLE
or edi, PT_PRESENT | PT_RW
mov [pdpt], edi
; pdt[0] -> pt
mov edi, pt
or edi, PT_PRESENT | PT_READABLE
or edi, PT_PRESENT | PT_RW
mov [pdt], edi
%define ENTRIES_PER_PT 512
@@ -113,7 +124,7 @@ _start:
mov edi, pt
mov ebx, kernel_start
and ebx, 0xfffff000
or ebx, PT_PRESENT | PT_READABLE
or ebx, PT_PRESENT | PT_RW
mov eax, kernel_end
sub eax, kernel_start
@@ -127,6 +138,17 @@ _start:
add edi, SIZEOF_PT_ENTRY
loop .set_pt_entry
; note(nub31): Vga buffer is already page aligned
%define VGA_BUFFER 0xb8000
; Identity map vga buffer
mov ebx, VGA_BUFFER
or ebx, PT_PRESENT | PT_RW
mov edi, pt
add edi, VGA_BUFFER / PAGE_SIZE * SIZEOF_PT_ENTRY
mov [edi], ebx
%define CR4_PAE_ENABLE 1 << 5
; Enable pae
@@ -169,8 +191,8 @@ start64:
mov ss, ax
mov rsp, stack.top
mov rdi, [multiboot_info]
call kmain
mov rdi, multiboot_info
call x86_64_main
.halt:
cli
hlt

19
src/boot/symbols.c Normal file
View File

@@ -0,0 +1,19 @@
#include "symbols.h"
extern u8 kernel_start[];
uptr get_kernel_start() {
return (uptr)&kernel_start;
}
extern u8 kernel_end[];
uptr get_kernel_end() {
return (uptr)&kernel_end;
}
extern u8 multiboot_info[];
uptr get_multiboot_info() {
return (uptr)&multiboot_info;
}

7
src/boot/symbols.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include <def.h>
uptr get_kernel_start();
uptr get_kernel_end();
uptr get_multiboot_info();

View File

@@ -1,8 +1,9 @@
#pragma once
static inline u32 align(u32 num, u32 alignment) {
return (num + alignment - 1) & ~(alignment - 1);
}
#include <def.h>
#define ALIGN_UP(value, alignment) ((value + alignment - 1) / alignment * alignment)
#define ALIGN_DOWN(value, alignment) (value - (value % alignment))
static inline void hlt() {
asm("hlt");

View File

@@ -53,19 +53,7 @@ typedef signed long long i64;
#define U64_MIN 0x0
#define U64_MAX 0xffffffffffffffffULL
#define I8_C(x) x
#define U8_C(x) x##U
#define I16_C(x) x
#define U16_C(x) x##U
#define I32_C(x) x
#define U32_C(x) x##U
#define I64_C(x) x##LL
#define U64_C(x) x##ULL
#define KiB(count) (U64_C(count) * U64_C(1024))
#define MiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024))
#define GiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024) * U64_C(1024))
#define TiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024) * U64_C(1024) * U64_C(1024))
#define KiB(count) (count##ULL * 1024##ULL)
#define MiB(count) (count##ULL * KiB(1024))
#define GiB(count) (count##ULL * MiB(1024))
#define TiB(count) (count##ULL * GiB(1024))

View File

@@ -83,55 +83,25 @@ void itoa64(i64 value, char *buffer) {
}
void uitoa64(u64 value, char *buffer) {
char *p = buffer;
char tmp[20];
int i = 0;
if (value == 0) {
*p++ = '0';
*p = '\0';
buffer[0] = '0';
buffer[1] = '\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;
}
while (value > 0) {
tmp[i++] = '0' + (value % 10);
value /= 10;
}
*p = '\0';
for (int j = 0; j < i; j++) {
buffer[j] = tmp[i - j - 1];
}
buffer[i] = '\0';
}
void uitoa64_hex(u64 value, char *buffer) {