Compare commits

...

8 Commits

Author SHA1 Message Date
nub31
dd3dbc3ab1 ... 2025-09-07 01:27:22 +02:00
nub31
ff12b6abf2 Remove true/false/bool since it is a compuler keyword in c23 2025-09-07 00:42:22 +02:00
nub31
a018dfd471 some lib docs 2025-09-07 00:22:54 +02:00
nub31
8cc90d6f2f ... 2025-09-07 00:08:31 +02:00
nub31
4f55956fee ... 2025-09-06 22:07:17 +02:00
nub31
45a9023bab ... 2025-09-06 21:21:59 +02:00
nub31
130e271461 only identity map the start of the kernel 2025-09-06 20:22:51 +02:00
nub31
46bc977104 .. 2025-09-06 19:45:33 +02:00
36 changed files with 427 additions and 259 deletions

19
.clangd
View File

@@ -1,19 +0,0 @@
CompileFlags:
Add:
- "-target"
- "x86_64-unknown-none"
- "-ffreestanding"
- "-fno-builtin"
- "-fno-common"
- "-Wall"
- "-Wextra"
- "-Wshadow"
- "-fno-strict-aliasing"
- "-nostdinc"
- "-nostdlib"
- "-I"
- "/home/oliste/repos/nub-os/src"
- "-I"
- "/home/oliste/repos/nub-os/src/kernel"
- "-I"
- "/home/oliste/repos/nub-os/src/arch"

28
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,28 @@
{
"version": 4,
"configurations": [
{
"name": "kernel",
"defines": [
"DEBUG",
"true=1", // https://github.com/microsoft/vscode-cpptools/issues/10696
"false=0" // https://github.com/microsoft/vscode-cpptools/issues/10696
],
"includePath": [
"src/lib"
],
"intelliSenseMode": "linux-gcc-x64",
"compilerPath": "/usr/bin/x86_64-elf-gcc",
"cStandard": "c23",
"compilerArgs": [
"-m64",
"-ffreestanding",
"-nostdinc",
"-nostdlib",
"-Wall",
"-Wextra",
"-Wshadow"
]
}
]
}

19
.vscode/settings.json vendored
View File

@@ -18,6 +18,23 @@
"system_error": "c",
"std.h": "c",
"panic.h": "c",
"pmm.h": "c"
"pmm.h": "c",
"array": "cpp",
"string_view": "cpp",
"initializer_list": "cpp",
"ranges": "cpp",
"span": "cpp",
"valarray": "cpp",
"alloc.h": "c",
"arch.h": "c",
"def.h": "c",
"assert.h": "c",
"io.h": "c",
"mem.h": "c",
"string.h": "c",
"kernel.h": "c",
"printf.h": "c",
"vmm.h": "c",
"console.h": "c"
}
}

View File

@@ -3,29 +3,28 @@ ENTRY(_start)
SECTIONS
{
. = 2M;
kernel_start = .;
.text BLOCK(4K) : ALIGN(4K)
.text :
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
.rodata :
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
.data :
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
.bss :
{
*(COMMON)
*(.bss)
}
kernel_end = .;
}
}

View File

@@ -2,9 +2,15 @@ CC = x86_64-elf-gcc
LD = x86_64-elf-ld
AS = nasm
CFLAGS = -m64 -ffreestanding -nostdinc -nostdlib -fno-builtin -Wall -Wextra -Wshadow -std=c11 -I src -I src/kernel -I src/arch -g
LDFLAGS = -g
ASFLAGS = -f elf64 -g -F dwarf
# Modify these settings here for defines and debug info
CFLAGS = -g -D DEBUG
LDFLAGS = -g
ASFLAGS = -g -F dwarf
# Do not modify
CFLAGS += -m64 -ffreestanding -nostdinc -nostdlib -Wall -Wextra -Wshadow -std=c23 -I src/lib
LDFLAGS +=
ASFLAGS += -f elf64
SRC_C := $(shell find src -name '*.c')
SRC_ASM := $(shell find src -name '*.asm')

View File

@@ -1,8 +1,11 @@
#include "arch.h"
#include "console.h"
#include "mem/pmm.h"
#include "mem/vmm.h"
#include "panic.h"
#include "util.h"
#include <arch.h>
#include <def.h>
#include <printf.h>
static void arch_halt()
{
@@ -19,9 +22,9 @@ static void arch_enable_interrupts()
enable_interrupts();
}
static void arch_panic(const char* msg)
static void arch_panic()
{
panic(msg);
panic();
}
static void arch_console_putchar(char c)
@@ -34,13 +37,45 @@ static void arch_console_clear()
console_clear();
}
static u64 arch_get_page_size()
static size_t arch_get_page_size()
{
return PAGE_SIZE;
}
void* arch_alloc(size_t page_count)
{
u64 virtual_address = vmm_alloc_address(page_count);
for (size_t i = 0; i < page_count; i++)
{
u64 physical_address = pmm_alloc();
if (!physical_address)
{
printf("Out of physical memory");
panic();
}
vmm_map(physical_address, virtual_address + (i * PAGE_SIZE), PTE_PRESENT | PTE_WRITABLE);
}
return (void*)virtual_address;
}
void arch_free(void* virtual_address, size_t page_count)
{
for (size_t i = 0; i < page_count; i++)
{
u64 physical_address = vmm_unmap((u64)virtual_address + (i * PAGE_SIZE));
pmm_free(physical_address);
}
vmm_free_address((u64)virtual_address, page_count);
}
static const arch_mem_api_t arch_mem_api = {
.get_page_size = arch_get_page_size,
.alloc = arch_alloc,
.free = arch_free,
};
static const arch_console_api_t arch_console_api = {

View File

@@ -1,6 +1,7 @@
global _start
global pml4
extern x86_64_main
extern kernel_end
%define FLAGS 0b10
%define MAGIC 0x1BADB002
@@ -43,6 +44,8 @@ section .data
dd 0
multiboot_magic:
dd 0
kernel_page_count:
dd 0
section .text
bits 32
@@ -98,10 +101,18 @@ section .text
mov eax, pd
or eax, 0x03
mov [pdpt], eax
; Map first 32 2mb pages for the kernel for a total of 64mb
; Calculate how many 2mb pages we need to identity map
mov ecx, kernel_end
add ecx, 0x1FFFFF ; Page align end of kernel
shr ecx, 21 ; ecx now holds the required pages
; Save the page count so we can pass it to c later
mov [kernel_page_count], ecx
; Identity map the 0x0 to kernel_end
mov edi, pd
mov eax, 0x83
mov ecx, 32
.setup_pd:
mov [edi], eax
add eax, 0x200000
@@ -150,6 +161,7 @@ section .text
; Finally, we call in to c
mov edi, [multiboot_magic]
mov esi, [multiboot_info]
mov edx, [kernel_page_count]
call x86_64_main
.hang:
hlt

View File

@@ -1,6 +1,6 @@
#pragma once
#include "std.h"
#include <def.h>
#define VGA_BLACK 0
#define VGA_BLUE 1

View File

@@ -1,5 +1,6 @@
#include "exceptions.h"
#include "../panic.h"
#include <printf.h>
static const char* exception_messages[32] = {
"divide by zero",
@@ -39,5 +40,5 @@ static const char* exception_messages[32] = {
void handle_exception(const isr_frame_t* frame)
{
printf("exception[%d]: %s, error code: %d\n", frame->int_no, exception_messages[frame->int_no], frame->err_code);
panic("An unhandled exception occurred");
panic();
}

View File

@@ -1,5 +1,6 @@
#include "irq.h"
#include "../util.h"
#include <printf.h>
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21

View File

@@ -1,6 +1,8 @@
#include "isr.h"
#include "exceptions.h"
#include "irq.h"
#include <def.h>
#include <printf.h>
void handle_isr(const isr_frame_t* frame)
{

View File

@@ -1,6 +1,6 @@
#pragma once
#include "std.h"
#include <def.h>
typedef struct
{

View File

@@ -1,32 +1,35 @@
#include "console.h"
#include "interrupts/idt.h"
#include "interrupts/irq.h"
#include "kernel.h"
#include "mem/pmm.h"
#include "mem/vmm.h"
#include "panic.h"
#include "util.h"
#include <printf.h>
void x86_64_main(u32 magic, multiboot_info_t* info)
extern void kernel_main();
void x86_64_main(u32 magic, multiboot_info_t* info, u32 kernel_page_count)
{
console_clear();
if (magic != 0x2BADB002)
{
panic("Multiboot magic does not match\n");
printf("Multiboot magic does not match\n");
panic();
}
if (info == NULL)
{
panic("Multiboot info is NULL\n");
printf("Multiboot info is NULL\n");
panic();
}
idt_init();
remap_pic();
enable_interrupts();
pmm_init(info);
vmm_init();
pmm_init(kernel_page_count, info);
vmm_init(kernel_page_count);
kernel_main();
}

View File

@@ -1,5 +1,7 @@
#include "pmm.h"
#include "x86_64/panic.h"
#include "../panic.h"
#include <mem.h>
#include <printf.h>
typedef struct
{
@@ -7,12 +9,6 @@ typedef struct
size_t length;
} memory_region_t;
typedef struct
{
memory_region_t* regions;
size_t num_regions;
} memory_map_t;
#define USABLE_REGION_SIZE 32
static memory_region_t usable_regions[USABLE_REGION_SIZE];
@@ -22,13 +18,13 @@ static size_t num_regions = 0;
#define BITMAP_SIZE (BITMAP_PAGE_COUNT / 8)
static u8 page_bitmap[BITMAP_SIZE];
static u64 total_pages = 0;
void pmm_init(multiboot_info_t* info)
void pmm_init(u32 kernel_page_count, multiboot_info_t* info)
{
if (!(info->flags & (1 << 6)))
{
panic("Invalid memory map given by bootloader\n");
printf("Invalid memory map given by bootloader\n");
panic();
}
u64 offset = 0;
@@ -68,10 +64,9 @@ void pmm_init(multiboot_info_t* info)
for (u64 page = start_page; page < start_page + num_pages; page++)
{
if (page < BITMAP_SIZE * 8)
if (page < BITMAP_PAGE_COUNT)
{
page_bitmap[page / 8] &= ~(1 << (page % 8));
total_pages++;
}
else
{
@@ -81,21 +76,16 @@ void pmm_init(multiboot_info_t* info)
}
}
// Mark first 32 pages (64mb) as unusable since it is reserved by the bootloader
// todo(nub31): This should be revisited. Maybe do a higher half kernel?
for (u64 page = 0; page < 32; page++)
// The kernel was identity mapped by the kernel, so those bits should be marked as unavailable
for (u64 page = 0; page < kernel_page_count; page++)
{
if (page < BITMAP_PAGE_COUNT)
if (page >= BITMAP_PAGE_COUNT)
{
if (!(page_bitmap[page / 8] & (1 << (page % 8))))
{
page_bitmap[page / 8] |= (1 << (page % 8));
}
}
else
{
panic("Bitmap is not large enough to hold the bootloader reserved memory");
printf("Bitmap is not large enough to hold the memory reserved by the kernel");
panic();
}
page_bitmap[page / 8] |= (1 << (page % 8));
}
}
@@ -131,7 +121,7 @@ void pmm_free(u64 physical_address)
else
{
printf("Physical address %x is already free", physical_address);
panic("Failed to free physical address");
panic();
}
}
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include "std.h"
#include "x86_64/multiboot.h"
#include "../multiboot.h"
#include <def.h>
// todo(nub31): Fixed at 2mb for now, might add support for 4k pages later
#define PAGE_SIZE MiB(2)
@@ -10,10 +10,10 @@
// The value must be a multible of 8
#define MAX_MEMORY GiB(64)
void pmm_init(multiboot_info_t* info);
void pmm_init(u32 kernel_page_count, multiboot_info_t* info);
// Low level function to allocate a 2mb physical page and return the physical address
// Return value 0 indicates out of memory
// A return value 0 indicates out of memory
u64 pmm_alloc();
// Low level function to free a 2mb physical page

View File

@@ -1,6 +1,7 @@
#include "vmm.h"
#include "../panic.h"
#include "pmm.h"
#include "x86_64/panic.h"
#include <printf.h>
#define PML4_INDEX(addr) (((addr) >> 39) & 0x1FF)
#define PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF)
@@ -8,77 +9,97 @@
#define PTE_MASK 0x000FFFFFFFFFF000ULL
#define PTE_PRESENT (1ULL << 0)
#define PTE_WRITABLE (1ULL << 1)
#define PTE_USER (1ULL << 2)
#define PTE_PS (1ULL << 7)
#define BITMAP_PAGE_COUNT (ADDRES_SPACE_SIZE / PAGE_SIZE)
#define BITMAP_SIZE (BITMAP_PAGE_COUNT / 8)
static u8 page_bitmap[BITMAP_SIZE];
static u64 total_pages = 0;
static u64 free_pages = 0;
extern u64 pml4[];
void vmm_init()
void vmm_init(u32 kernel_page_count)
{
// Mark first 32 pages (64mb) as unusable since it is reserved by the bootloader
// todo(nub31): This should be revisited. Maybe do a higher half kernel?
for (u64 page = 0; page < 32; page++)
// The kernel was identity mapped when we entered long mode,
// so those virtual addresses should be marked as unavailable
for (u64 page = 0; page < kernel_page_count; page++)
{
if (page < BITMAP_PAGE_COUNT)
if (page >= BITMAP_PAGE_COUNT)
{
if (!(page_bitmap[page / 8] & (1 << (page % 8))))
{
page_bitmap[page / 8] |= (1 << (page % 8));
}
}
else
{
panic("Bitmap is not large enough to hold the bootloader reserved memory");
printf("Bitmap is not large enough to hold the addresses reserved by the kernel");
panic();
}
page_bitmap[page / 8] |= (1 << (page % 8));
}
}
u64 vmm_alloc_address(size_t page_count)
{
for (size_t i = 0; i < BITMAP_SIZE; i++)
size_t total_pages = BITMAP_PAGE_COUNT;
for (size_t start_page = 0; start_page <= total_pages - page_count; start_page++)
{
if (page_bitmap[i] != 0xFF)
bool found_block = true;
for (size_t i = 0; i < page_count; i++)
{
for (int bit = 0; bit < 8; bit++)
size_t page = start_page + i;
size_t byte_index = page / 8;
size_t bit_index = page % 8;
if (page_bitmap[byte_index] & (1 << bit_index))
{
if (!(page_bitmap[i] & (1 << bit)))
{
page_bitmap[i] |= (1 << bit);
free_pages--;
return ((i * 8 + bit) * PAGE_SIZE);
}
found_block = false;
start_page = page;
break;
}
}
if (found_block)
{
for (size_t i = 0; i < page_count; i++)
{
size_t page = start_page + i;
size_t byte_index = page / 8;
size_t bit_index = page % 8;
page_bitmap[byte_index] |= (1 << bit_index);
}
return start_page * PAGE_SIZE;
}
}
return 0;
}
u64 vmm_free_address(u64 virtual_address, size_t page_count)
void vmm_free_address(u64 virtual_address, size_t page_count)
{
u64 page = virtual_address / PAGE_SIZE;
if (page < BITMAP_SIZE * 8)
u64 start_page = virtual_address / PAGE_SIZE;
if (start_page + page_count > BITMAP_PAGE_COUNT)
{
if (page_bitmap[page / 8] & (1 << (page % 8)))
printf("Virtual address range exceeds bitmap bounds\n");
panic();
}
for (size_t i = 0; i < page_count; i++)
{
size_t page = start_page + i;
size_t byte_index = page / 8;
size_t bit_index = page % 8;
if (!(page_bitmap[byte_index] & (1 << bit_index)))
{
page_bitmap[page / 8] &= ~(1 << (page % 8));
free_pages++;
}
else
{
printf("Virtual address %x is already free", virtual_address);
panic("Failed to free virtual address");
printf("Virtual address 0x%x (page %u) is already free\n", virtual_address + (i * PAGE_SIZE), page);
panic();
}
}
for (size_t i = 0; i < page_count; i++)
{
size_t page = start_page + i;
size_t byte_index = page / 8;
size_t bit_index = page % 8;
page_bitmap[byte_index] &= ~(1 << bit_index);
}
}
static u64 create_2mb_pte(u64 physical_address, u32 flags)
@@ -86,7 +107,7 @@ static u64 create_2mb_pte(u64 physical_address, u32 flags)
if (physical_address & (PAGE_SIZE - 1))
{
printf("Physical address not page aligned (0x%x)\n", physical_address);
panic("Failed to create PTE");
panic();
}
return (physical_address & PTE_MASK) | flags | PTE_PS;
@@ -103,7 +124,7 @@ void vmm_map(u64 physical_address, u64 virtual_address, u32 flags)
{
// todo(nub31): Dynamically create a pdpt table
printf("PDPT not present at PML4 index %u\n", pml4_idx);
panic("Failed to map virtual to physical page");
panic();
}
u64* pdpt_physical_address = (u64*)(pdpt & PTE_MASK);
@@ -112,7 +133,7 @@ void vmm_map(u64 physical_address, u64 virtual_address, u32 flags)
{
// todo(nub31): Dynamically create a pd table
printf("PD not present at PDPT index %u\n", pdpt_idx);
panic("Failed to map virtual to physical page");
panic();
}
u64* pd_physical_address = (u64*)(pd & PTE_MASK);
@@ -121,7 +142,7 @@ void vmm_map(u64 physical_address, u64 virtual_address, u32 flags)
if (entry & PTE_PRESENT)
{
printf("Virtual address 0x%x is already mapped\n", virtual_address);
panic("Failed to map virtual to physical page");
panic();
}
pd_physical_address[pd_idx] = create_2mb_pte(physical_address, flags);
@@ -137,7 +158,7 @@ u64 vmm_unmap(u64 virtual_address)
if (!(pdpt_entry & PTE_PRESENT))
{
printf("PDPT not present at PML4 index %llu\n", pml4_idx);
panic("Failed to unmap virtual address");
panic();
}
u64* pdpt_physical_address = (u64*)(pdpt_entry & PTE_MASK);
@@ -145,14 +166,14 @@ u64 vmm_unmap(u64 virtual_address)
if (!(pd_entry & PTE_PRESENT))
{
printf("PD not present at PDPT index %llu\n", pdpt_idx);
panic("Failed to unmap virtual address");
panic();
}
u64* pd_physical_address = (u64*)(pd_entry & PTE_MASK);
if (!(pd_physical_address[pd_idx] & PTE_PRESENT))
{
printf("Virtual address 0x%llx is not mapped\n", virtual_address);
panic("Failed to unmap virtual address");
panic();
}
u64 physical_address = pd_physical_address[pd_idx] & PTE_MASK;
@@ -161,33 +182,4 @@ u64 vmm_unmap(u64 virtual_address)
__asm__ volatile("invlpg (%0)" : : "r"(virtual_address) : "memory");
return physical_address;
}
void* vmm_alloc(size_t page_count)
{
u64 virtual_address = vmm_alloc_address(page_count);
for (size_t i = 0; i < page_count; i++)
{
u64 physical_address = pmm_alloc();
if (!physical_address)
{
panic("Out of physical memory");
}
vmm_map(physical_address, virtual_address + (i * PAGE_SIZE), PTE_PRESENT | PTE_WRITABLE);
}
return (void*)virtual_address;
}
void vmm_free(void* virtual_address, size_t page_count)
{
for (size_t i = 0; i < page_count; i++)
{
u64 physical_address = vmm_unmap((u64)virtual_address + (i * PAGE_SIZE));
pmm_free(physical_address);
}
vmm_free_address((u64)virtual_address, page_count);
}

View File

@@ -1,24 +1,27 @@
#pragma once
#include "std.h"
#include <def.h>
// Defines the theoretical max virtual memory space the kernel can allocate
// The value must be a multible of 8
#define ADDRES_SPACE_SIZE GiB(64)
void vmm_init();
#define PTE_PRESENT (1ULL << 0)
#define PTE_WRITABLE (1ULL << 1)
#define PTE_USER (1ULL << 2)
#define PTE_PS (1ULL << 7)
void vmm_init(u32 kernel_page_count);
// Allocates a free page aligned block of virtual addresses
// A return value 0 indicates that there were not blocks
// found which is large enought for the amount of pages requested
u64 vmm_alloc_address(size_t page_count);
// Frees a block of virtual addresses previously allocated via `vmm_alloc_address`
// Only use this function for pages mapped via `vmm_alloc_address`
u64 vmm_free_address(u64 virtual_address, size_t page_count);
void vmm_free_address(u64 virtual_address, size_t page_count);
// Low level function to map a virtual address to a physical address
void vmm_map(u64 physical_address, u64 virtual_address, u32 flags);
// Low level function to unmap a virtual address from a physical address
u64 vmm_unmap(u64 virtual_address);
// Allocates and maps `page_count` continuous pages and returns the virtual address of the first page
void* vmm_alloc(size_t page_count);
// Frees the pages allocated via `vmm_alloc` at the specified virtual address
// Only use this function for pages mapped via `vmm_alloc`
void vmm_free(void* virtual_address, size_t page_count);
u64 vmm_unmap(u64 virtual_address);

View File

@@ -1,9 +1,8 @@
#include "panic.h"
#include "util.h"
void panic(const char* msg)
void panic()
{
printf(msg);
disable_interrupts();
halt();
}

View File

@@ -1,3 +1,3 @@
#pragma once
void panic(const char* msg);
void panic();

View File

@@ -1,6 +1,6 @@
#pragma once
#include "std.h"
#include <def.h>
enum
{

49
src/kernel/alloc.c Normal file
View File

@@ -0,0 +1,49 @@
#include "alloc.h"
#include <assert.h>
typedef struct block_header
{
size_t size;
bool is_free;
struct block_header* next;
struct block_header* prev;
u8 data[];
} block_header_t;
static block_header_t* heap_start = NULL;
#define HEADER_SIZE sizeof(block_header_t)
static block_header_t* find_free_block(size_t size)
{
block_header_t* current = heap_start;
while (current != NULL)
{
if (current->is_free && current->size >= size)
{
return current;
}
current = current->next;
}
return NULL;
}
void* malloc(size_t size)
{
// Align to pointer size
size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
block_header_t* block = find_free_block(size);
block->is_free = false;
return (u8*)block + HEADER_SIZE;
}
void free(void* ptr)
{
block_header_t* block = (block_header_t*)((u8*)ptr - HEADER_SIZE);
assert(block->is_free, "Block is already free");
block->is_free = true;
}

6
src/kernel/alloc.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "def.h"
void* malloc(size_t size);
void free(void* ptr);

View File

@@ -1,11 +1,12 @@
#include "kernel.h"
#include "arch.h"
#include "std.h"
#include <arch.h>
#include <printf.h>
void kernel_main()
{
printf("Welcome to nub OS :)\n");
arch_api.enable_interrupts();
printf("Welcome to nub OS :)\n");
printf("Kernel has exited\n");
arch_api.halt();
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "std.h"
#include <def.h>
typedef void (*arch_console_putchar_t)(char c);
typedef void (*arch_console_clear_t)();
@@ -11,14 +11,18 @@ typedef struct
const arch_console_clear_t clear;
} arch_console_api_t;
typedef u64 (*arch_mem_get_page_size_t)();
typedef size_t (*arch_mem_get_page_size_t)();
typedef void* (*arch_mem_alloc_t)(size_t page_count);
typedef void (*arch_mem_free_t)(void* virtual_address, size_t page_count);
typedef struct
{
const arch_mem_get_page_size_t get_page_size;
const arch_mem_alloc_t alloc;
const arch_mem_free_t free;
} arch_mem_api_t;
typedef void (*arch_panic_t)(const char*);
typedef void (*arch_panic_t)();
typedef void (*arch_enable_interrupts_t)();
typedef void (*arch_disable_interrupts_t)();
typedef void (*arch_halt_t)();

17
src/lib/assert.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <arch.h>
#include <printf.h>
// Make sure `arch_api.panic` and `arch_api.console.putchar` is intialized if calling from architecure-specific code.
// Will be compiled out if `DEBUG` is not defined.
static inline void assert(bool condition, const char* msg)
{
#if DEBUG
if (!condition)
{
printf(msg);
arch_api.panic();
}
#endif
}

67
src/lib/def.h Normal file
View File

@@ -0,0 +1,67 @@
#pragma once
typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#ifndef NULL
#define NULL ((void*)0)
#endif
typedef unsigned long size_t;
typedef unsigned long uintptr_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
#define I8_MIN (-128)
#define I8_MAX 127
#define U8_MIN 0x0
#define U8_MAX 0xff
#define I16_MIN (-32768)
#define I16_MAX 32767
#define U16_MIN 0x0
#define U16_MAX 0xffff
#define I32_MIN (-2147483647 - 1)
#define I32_MAX 2147483647
#define U32_MIN 0x0
#define U32_MAX 0xffffffffU
#define I64_MIN (-9223372036854775807LL - 1)
#define I64_MAX 9223372036854775807LL
#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))

6
src/lib/mem.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include <def.h>
void memset(void* destination, u8 value, size_t length);
void memcpy(void* destination, void* source, size_t length);

View File

@@ -1,5 +1,25 @@
#include "arch.h"
#include "printf.h"
#include <arch.h>
#include <def.h>
#include <string.h>
// Make sure `arch_api.console.putchar` is intialized if calling from architecure-specific code.
//
// Supported formats:
// - `d`: i64 (decimal)
// - `u`: u64 (decimal)
// - `x`: u64 (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 printf(const char* fmt, ...)
{
va_list args;

4
src/lib/printf.h Normal file
View File

@@ -0,0 +1,4 @@
#pragma once
// In arch code, make sure arch_api.console.putchar is set up befire calling
void printf(const char* fmt, ...);

View File

@@ -25,6 +25,10 @@ void reverse(char* str, size_t length)
}
}
// ```c
// char buffer[21];
// itoa64(-1234, buffer);
// ```
void itoa64(i64 value, char* buffer)
{
char temp[21];
@@ -34,7 +38,7 @@ void itoa64(i64 value, char* buffer)
if (value < 0)
{
negative = 1;
if (value == INT64_MIN)
if (value == I64_MIN)
{
const char* min_str = "9223372036854775808";
for (i = 0; min_str[i] != '\0'; i++)
@@ -54,7 +58,7 @@ void itoa64(i64 value, char* buffer)
return;
}
if (!(negative && value == INT64_MIN))
if (!(negative && value == I64_MIN))
{
while (value > 0)
{
@@ -75,6 +79,10 @@ void itoa64(i64 value, char* buffer)
buffer[j] = '\0';
}
// ```c
// char buffer[21];
// uitoa64(1234, buffer);
// ```
void uitoa64(u64 value, char* buffer)
{
char temp[21];

View File

@@ -1,10 +1,10 @@
#pragma once
#include "std.h"
#include <def.h>
int strcmp(const char* a, const char* b);
void reverse(char* str, size_t length);
void uitoa64(u64 value, char* buffer);
void itoa64(i64 value, char* buffer);
void uitoa64(u64 value, char* buffer);
void uitoa64_hex(u64 value, char* buffer);

View File

@@ -1,6 +0,0 @@
#pragma once
#include "stdlib/def.h"
#include "stdlib/io.h"
#include "stdlib/mem.h"
#include "stdlib/string.h"

View File

@@ -1,68 +0,0 @@
#pragma once
typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#ifndef NULL
#define NULL ((void*)0)
#endif
typedef unsigned long size_t;
typedef unsigned long uintptr_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
#define INT8_MIN (-128)
#define INT8_MAX 127
#define UINT8_MAX 0xff
#define INT16_MIN (-32768)
#define INT16_MAX 32767
#define UINT16_MAX 0xffff
#define INT32_MIN (-2147483647 - 1)
#define INT32_MAX 2147483647
#define UINT32_MAX 0xffffffffU
#define INT64_MIN (-9223372036854775807LL - 1)
#define INT64_MAX 9223372036854775807LL
#define UINT64_MAX 0xffffffffffffffffULL
#define INT8_C(x) x
#define UINT8_C(x) x##U
#define INT16_C(x) x
#define UINT16_C(x) x##U
#define INT32_C(x) x
#define UINT32_C(x) x##U
#define INT64_C(x) x##LL
#define UINT64_C(x) x##ULL
#define INTMAX_C(x) x##LL
#define UINTMAX_C(x) x##ULL
#define KiB(count) ((u64)count * 1024)
#define MiB(count) (KiB((u64)count) * 1024)
#define GiB(count) (MiB((u64)count) * 1024)
#define TiB(count) (GiB((u64)count) * 1024)

View File

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

View File

@@ -1,6 +0,0 @@
#pragma once
#include "std.h"
void memset(void* destination, u8 value, size_t length);
void memcpy(void* destination, void* source, size_t length);