Compare commits

..

10 Commits

Author SHA1 Message Date
nub31
a3822dd350 basic memory management 2025-09-06 00:59:52 +02:00
nub31
bcf05c055e ... 2025-09-05 23:59:59 +02:00
nub31
2aa44eaa51 ... 2025-09-05 21:43:41 +02:00
nub31
0f6b66a486 ... 2025-09-05 21:41:00 +02:00
nub31
8e986807df ... 2025-09-03 19:25:58 +02:00
nub31
bb923621f9 better api 2025-09-03 19:22:53 +02:00
nub31
b7bbccca73 ... 2025-09-03 18:38:02 +02:00
nub31
f05e7c9e64 ... 2025-09-03 18:31:10 +02:00
nub31
0583c8c1a3 ... 2025-09-03 17:43:23 +02:00
nub31
0b8ee325aa ... 2025-09-03 17:20:00 +02:00
45 changed files with 559 additions and 550 deletions

View File

@@ -12,4 +12,8 @@ CompileFlags:
- "-nostdinc"
- "-nostdlib"
- "-I"
- "/home/oliste/repos/nub-os/src/stdlib"
- "/home/oliste/repos/nub-os/src"
- "-I"
- "/home/oliste/repos/nub-os/src/kernel"
- "-I"
- "/home/oliste/repos/nub-os/src/arch"

18
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdb",
"request": "attach",
"name": "Attach to QEMU",
"executable": "${workspaceFolder}/.build/kernel/kernel",
"target": "localhost:1234",
"remote": true,
"cwd": "${workspaceRoot}",
"gdbpath": "/usr/bin/gdb",
"autorun": [
"b _start"
]
}
]
}

8
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"files.associations": {
"bitset": "c",
"algorithm": "c",
"format": "c",
"multiboot.h": "c"
}
}

View File

@@ -31,5 +31,5 @@ qemu-system-x86_64 -cdrom .build/nub-os.iso
```sh
qemu-system-x86_64 -s -S -cdrom .build/nub-os.iso
gdb -tui .build/kernel -ex "target remote localhost:1234"
gdb -tui .build/kernel/kernel -ex "target remote localhost:1234"
```

View File

@@ -3,6 +3,7 @@ ENTRY(_start)
SECTIONS
{
. = 2M;
kernel_start = .;
.text BLOCK(4K) : ALIGN(4K)
{
@@ -25,4 +26,6 @@ SECTIONS
*(COMMON)
*(.bss)
}
kernel_end = .;
}

View File

@@ -2,7 +2,7 @@ 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/stdlib -g
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
@@ -17,13 +17,13 @@ iso: .build/nub-os.iso
clean:
@rm -r .build 2>/dev/null || true
.build/nub-os.iso: .build/kernel grub.cfg
.build/nub-os.iso: .build/kernel/kernel grub.cfg
mkdir -p .build/nub-os/boot/grub
cp grub.cfg .build/nub-os/boot/grub
cp .build/kernel .build/nub-os/boot/
cp .build/kernel/kernel .build/nub-os/boot/
grub-mkrescue -o .build/nub-os.iso .build/nub-os/
.build/kernel: $(OBJS)
.build/kernel/kernel: $(OBJS)
$(LD) $(LDFLAGS) -T linker.ld -o $@ $^
.build/%.o: src/%.c

View File

@@ -1,21 +1,20 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "std.h"
typedef void (*arch_panic_t)(const char*);
typedef void (*arch_putchar_t)(char c);
typedef void (*arch_enable_interrupts_t)();
typedef void (*arch_disable_interrupts_t)();
typedef void (*arch_halt_t)();
typedef struct
{
uint64_t base_address;
size_t length;
} memory_region_t;
arch_panic_t panic;
arch_putchar_t putchar;
arch_enable_interrupts_t enable_interrupts;
arch_disable_interrupts_t disable_interrupts;
arch_halt_t halt;
} arch_api_t;
typedef struct
{
memory_region_t* regions;
size_t num_regions;
} memory_map_t;
extern memory_map_t memory_map;
void panic();
void put_char(char character);
extern arch_api_t arch_api;

View File

@@ -1,5 +1,6 @@
global _start
extern entry
global pml4
extern x86_64_main
%define FLAGS 0b10
%define MAGIC 0x1BADB002
@@ -107,7 +108,7 @@ section .text
add edi, 8
loop .setup_pd
; Load cr3 with the address of pml4
; Tell the cpu where pml4 is
mov eax, pml4
mov cr3, eax
@@ -149,7 +150,7 @@ section .text
; Finally, we call in to c
mov edi, [multiboot_magic]
mov esi, [multiboot_info]
call entry
call x86_64_main
.hang:
hlt
jmp .hang

View File

@@ -1,22 +1,21 @@
#include "vga.h"
#include <stddef.h>
#include "console.h"
#define ROWS 25
#define COLUMNS 80
typedef struct
{
uint8_t character;
uint8_t color;
u8 character;
u8 color;
} vga_char_t;
static vga_char_t* vga_buffer = (vga_char_t*)0xb8000;
static uint8_t cursor_row = 0;
static uint8_t cursor_col = 0;
static u8 cursor_row = 0;
static u8 cursor_col = 0;
void vga_put_char(char character, uint8_t color)
void console_put_char(char c, u8 color)
{
switch (character)
switch (c)
{
case '\n':
{
@@ -31,7 +30,7 @@ void vga_put_char(char character, uint8_t color)
}
case '\t':
{
uint8_t remainder = 4 - (cursor_col % 4);
u8 remainder = 4 - (cursor_col % 4);
cursor_col += remainder;
break;
}
@@ -66,7 +65,7 @@ void vga_put_char(char character, uint8_t color)
default:
{
vga_buffer[COLUMNS * cursor_row + cursor_col] = (vga_char_t){
.character = character,
.character = c,
.color = color,
};
cursor_col += 1;
@@ -102,7 +101,7 @@ void vga_put_char(char character, uint8_t color)
}
}
void vga_clear()
void console_clear()
{
for (size_t row = 0; row < ROWS; row++)
{

View File

@@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include "std.h"
#define VGA_BLACK 0
#define VGA_BLUE 1
@@ -21,5 +21,5 @@
#define VGA_DEFAULT_COLOR VGA_LIGHT_GRAY | VGA_BLACK << 4
void vga_put_char(char character, uint8_t color);
void vga_clear();
void console_put_char(char character, u8 color);
void console_clear();

View File

@@ -1,44 +0,0 @@
#include "../../kernel.h"
#include "../arch.h"
#include "interrupts/idt.h"
#include "interrupts/irq.h"
#include "mmap.h"
#include "multiboot.h"
#include "util.h"
#include "vga.h"
#include <stdint.h>
#include <stdio.h>
void entry(uint32_t magic, multiboot_info_t* info)
{
if (magic != 0x2BADB002)
{
printf("Multiboot magic does not match\n");
panic();
}
if (info == NULL)
{
printf("Multiboot info is NULL\n");
panic();
}
vga_clear();
idt_init();
remap_pic();
map_memory(info);
enable_interrupts();
main();
}
void panic()
{
printf("Kernel panic!\n");
disable_interrupts();
halt();
}
void put_char(char character)
{
vga_put_char(character, VGA_DEFAULT_COLOR);
}

View File

@@ -1,5 +1,5 @@
#include "exceptions.h"
#include "../../arch.h"
#include "../panic.h"
static const char* exception_messages[32] = {
"divide by zero",
@@ -39,5 +39,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();
panic("An unhandled exception occurred");
}

View File

@@ -2,7 +2,4 @@
#include "isr.h"
typedef void (*exception_handler_t)(const isr_frame_t*);
void handle_exception(const isr_frame_t* frame);
void register_exception_handler(uint8_t irq, exception_handler_t handler);
void handle_exception(const isr_frame_t* frame);

View File

@@ -8,20 +8,6 @@
static irq_handler_t irq_handlers[16] = {0};
bool cpu_has_apic()
{
uint32_t eax, edx;
cpuid(1, &eax, &edx);
return (edx & CPUID_FEAT_EDX_APIC) != 0;
}
void enable_apic()
{
uint64_t apic_base = rdmsr(0x1B);
apic_base |= (1 << 11);
wrmsr(0x1B, apic_base);
}
void remap_pic()
{
outb(PIC1_COMMAND, 0x11);
@@ -40,13 +26,7 @@ void remap_pic()
outb(PIC2_DATA, 0);
}
void disable_pic()
{
outb(PIC1_DATA, 0xFF);
outb(PIC2_DATA, 0xFF);
}
void register_irq_handler(uint8_t irq, irq_handler_t handler)
void register_irq_handler(u8 irq, irq_handler_t handler)
{
if (irq >= 16)
{
@@ -60,7 +40,7 @@ void register_irq_handler(uint8_t irq, irq_handler_t handler)
void handle_irq(const isr_frame_t* frame)
{
uint8_t irq = frame->int_no - 32;
u8 irq = frame->int_no - 32;
if (irq_handlers[irq])
{

View File

@@ -1,13 +1,9 @@
#pragma once
#include "isr.h"
#include <stdbool.h>
typedef void (*irq_handler_t)(const isr_frame_t*);
void remap_pic();
void disable_pic();
bool cpu_has_apic();
void enable_apic();
void handle_irq(const isr_frame_t* frame);
void register_irq_handler(uint8_t irq, irq_handler_t handler);
void register_irq_handler(u8 irq, irq_handler_t handler);

View File

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

View File

@@ -1,23 +1,12 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#include "std.h"
typedef struct
{
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t int_no;
uint64_t err_code;
uint64_t rip, cs, rflags, rsp, ss;
} __attribute__((packed)) isr_frame_t;
static inline void enable_interrupts()
{
__asm__ volatile("sti");
}
static inline void disable_interrupts()
{
__asm__ volatile("cli");
}
u64 r15, r14, r13, r12, r11, r10, r9, r8;
u64 rbp, rdi, rsi, rdx, rcx, rbx, rax;
u64 int_no;
u64 err_code;
u64 rip, cs, rflags, rsp, ss;
} __attribute__((packed)) isr_frame_t;

View File

@@ -1,107 +0,0 @@
// #include "keyboard.h"
// #include "interrupts.h"
// #include "util.h"
// #include <stddef.h>
// #define SCANCODE_LEFT_SHIFT 42
// #define SCANCODE_RIGHT_SHIFT 54
// #define SCANCODE_CAPS_LOCK 58
// #define KEYBOARD_HANDLERS_LENGTH 32
// unsigned const char us_keymap[128] = {
// 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w',
// 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h',
// 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
// 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// 0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// };
// unsigned const char us_keymap_shift[128] = {
// 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t', 'Q', 'W',
// 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H',
// 'J', 'K', 'L', ':', '"', '~', 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
// 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// 0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// };
// bool shift = false;
// bool caps_lock = false;
// // todo(nub): make dynamic when a memory allocator is implemented
// static keyboard_handler_t keyboard_handlers[KEYBOARD_HANDLERS_LENGTH];
// static size_t handler_index = 0;
// char scan_code_to_ascii(uint8_t scan_code)
// {
// if (scan_code >= 128)
// {
// return 0;
// }
// if ((!caps_lock && shift) || (caps_lock && !shift))
// {
// return us_keymap_shift[scan_code];
// }
// else
// {
// return us_keymap[scan_code];
// }
// }
// void handle_keyboard(const isr_frame_t* frame)
// {
// uint8_t code = inb(0x60);
// uint8_t scan_code = code & 0x7F;
// bool pressed = (code & 0x80) == 0;
// switch (scan_code)
// {
// case SCANCODE_LEFT_SHIFT:
// case SCANCODE_RIGHT_SHIFT:
// {
// shift = pressed;
// break;
// }
// case SCANCODE_CAPS_LOCK:
// {
// if (pressed)
// {
// caps_lock = !caps_lock;
// }
// break;
// }
// default:
// {
// keyboard_event_t event = {
// .scan_code = scan_code,
// .pressed = pressed,
// .caps_lock = caps_lock,
// .shift = shift,
// .ascii = scan_code_to_ascii(scan_code),
// };
// for (size_t i = 0; i < handler_index; i++)
// {
// keyboard_handlers[i](&event);
// }
// }
// }
// }
// void register_keypress_handler(const keyboard_handler_t handler)
// {
// // todo(nub31): remove when a memory allocator is implemented and
// // keyboard_handlers is a dynamic list
// if (handler_index >= KEYBOARD_HANDLERS_LENGTH)
// {
// }
// keyboard_handlers[handler_index] = handler;
// handler_index += 1;
// }
// void keyboard_init()
// {
// register_irq_handler(1, handle_keyboard);
// }

View File

@@ -1,19 +0,0 @@
// #pragma once
// #include <stdbool.h>
// #include <stdint.h>
// typedef struct
// {
// uint8_t scan_code;
// bool pressed;
// bool shift;
// bool caps_lock;
// char ascii;
// } keyboard_event_t;
// typedef void (*keyboard_handler_t)(const keyboard_event_t*);
// void keyboard_init();
// void register_keypress_handler(keyboard_handler_t handler);
// char scan_code_to_ascii(uint8_t scan_code);

45
src/arch/x86_64/main.c Normal file
View File

@@ -0,0 +1,45 @@
#include "arch.h"
#include "console.h"
#include "interrupts/idt.h"
#include "interrupts/irq.h"
#include "kernel.h"
#include "mem.h"
#include "panic.h"
#include "util.h"
void x86_64_main(u32 magic, multiboot_info_t* info)
{
console_clear();
if (magic != 0x2BADB002)
{
panic("Multiboot magic does not match\n");
}
if (info == NULL)
{
panic("Multiboot info is NULL\n");
}
idt_init();
mem_init(info);
mem_alloc_2mb(MiB(128) + 1);
remap_pic();
enable_interrupts();
kernel_main();
}
void console_putchar(char c)
{
console_put_char(c, VGA_DEFAULT_COLOR);
}
arch_api_t arch_api = {
.putchar = console_putchar,
.halt = halt,
.disable_interrupts = disable_interrupts,
.enable_interrupts = enable_interrupts,
.panic = panic,
};

255
src/arch/x86_64/mem.c Normal file
View File

@@ -0,0 +1,255 @@
#include "mem.h"
#include "x86_64/panic.h"
typedef struct
{
u64 base_address;
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];
static size_t num_regions = 0;
// Fixed at 2mb for now
#define PAGE_SIZE MiB(2)
// Defines the theoretical max memory the kernel can allocate, not the actual memory of the system
#define MAX_MEMORY GiB(64)
#define BITMAP_PAGE_COUNT (MAX_MEMORY / 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;
#define PML4_INDEX(addr) (((addr) >> 39) & 0x1FF)
#define PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF)
#define PD_INDEX(addr) (((addr) >> 21) & 0x1FF)
#define PTE_MASK 0x000FFFFFFFFFF000ULL
#define PTE_PRESENT (1ULL << 0)
#define PTE_WRITABLE (1ULL << 1)
#define PTE_USER (1ULL << 2)
#define PTE_PS (1ULL << 7)
extern u64 pml4[];
void mem_init(multiboot_info_t* info)
{
if (!(info->flags & (1 << 6)))
{
panic("Invalid memory map given by bootloader\n");
}
u64 offset = 0;
while (offset < info->mmap_length)
{
multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)(info->mmap_addr + offset);
if (mmmt->type == MULTIBOOT_MEMORY_AVAILABLE)
{
if (num_regions < USABLE_REGION_SIZE)
{
usable_regions[num_regions] = (memory_region_t){
.base_address = mmmt->addr,
.length = mmmt->len,
};
num_regions++;
}
else
{
printf("System has more memory than the usable memory map can hold\n");
break;
}
}
offset += mmmt->size + sizeof(mmmt->size);
}
memset(page_bitmap, 0xFF, BITMAP_SIZE);
for (size_t i = 0; i < num_regions; i++)
{
memory_region_t region = usable_regions[i];
u64 start_page = region.base_address / PAGE_SIZE;
u64 num_pages = region.length / PAGE_SIZE;
for (u64 page = start_page; page < start_page + num_pages; page++)
{
if (page < BITMAP_SIZE * 8)
{
page_bitmap[page / 8] &= ~(1 << (page % 8));
free_pages++;
total_pages++;
}
else
{
printf("System has more ram than the bitmap allows!\n");
break;
}
}
}
// 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++)
{
if (page < BITMAP_PAGE_COUNT)
{
if (!(page_bitmap[page / 8] & (1 << (page % 8))))
{
page_bitmap[page / 8] |= (1 << (page % 8));
free_pages--;
}
}
else
{
panic("Bitmap is not large enough to hold the bootloader reserved memory");
}
}
}
u64 mem_alloc_2mb_physical_page()
{
for (size_t i = 0; i < BITMAP_SIZE; i++)
{
if (page_bitmap[i] != 0xFF)
{
for (int bit = 0; bit < 8; bit++)
{
if (!(page_bitmap[i] & (1 << bit)))
{
page_bitmap[i] |= (1 << bit);
free_pages--;
return ((i * 8 + bit) * PAGE_SIZE);
}
}
}
}
return 0;
}
void mem_free_2mb_physical_page(u64 address)
{
u64 page = address / PAGE_SIZE;
if (page < BITMAP_SIZE * 8)
{
if (page_bitmap[page / 8] & (1 << (page % 8)))
{
page_bitmap[page / 8] &= ~(1 << (page % 8));
free_pages++;
}
}
}
static u64 create_pte(u64 physical_address)
{
if (physical_address & MiB(2) - 1)
{
printf("Physical address not 2MB aligned (0x%x)\n", physical_address);
panic("Failed to create PTE");
}
return (physical_address & PTE_MASK) | PTE_PRESENT | PTE_WRITABLE | PTE_PS;
}
void mem_map_2mb_page(u64 virtual_address, u64 physical_address)
{
u64 pml4_idx = PML4_INDEX(virtual_address);
u64 pdpt_idx = PDPT_INDEX(virtual_address);
u64 pd_idx = PD_INDEX(virtual_address);
u64 pdpt = pml4[pml4_idx];
if (!(pdpt & PTE_PRESENT))
{
// 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");
}
u64* pdpt_phys = (u64*)(pdpt & PTE_MASK);
u64 pd = pdpt_phys[pdpt_idx];
if (!(pd & PTE_PRESENT))
{
// 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");
}
u64* pd_phys = (u64*)(pd & PTE_MASK);
u64 entry = pd_phys[pd_idx];
if (entry & PTE_PRESENT)
{
printf("Virtual address 0x%x is already mapped\n", virtual_address);
panic("Failed to map virtual to physical page");
}
pd_phys[pd_idx] = create_pte(physical_address);
}
u64 mem_unmap_2mb_page(u64 virtual_address)
{
u64 pml4_idx = PML4_INDEX(virtual_address);
u64 pdpt_idx = PDPT_INDEX(virtual_address);
u64 pd_idx = PD_INDEX(virtual_address);
u64 pdpt_entry = pml4[pml4_idx];
if (!(pdpt_entry & PTE_PRESENT))
{
printf("PDPT not present at PML4 index %llu\n", pml4_idx);
panic("Failed to unmap virtual address");
}
u64* pdpt_phys = (u64*)(pdpt_entry & PTE_MASK);
u64 pd_entry = pdpt_phys[pdpt_idx];
if (!(pd_entry & PTE_PRESENT))
{
printf("PD not present at PDPT index %llu\n", pdpt_idx);
panic("Failed to unmap virtual address");
}
u64* pd_phys = (u64*)(pd_entry & PTE_MASK);
if (!(pd_phys[pd_idx] & PTE_PRESENT))
{
printf("Virtual address 0x%llx is not mapped\n", virtual_address);
panic("Failed to unmap virtual address");
}
u64 phys = pd_phys[pd_idx] & PTE_MASK;
pd_phys[pd_idx] = 0;
__asm__ volatile("invlpg (%0)" : : "r"(virtual_address) : "memory");
return phys;
}
void* mem_alloc_2mb(u64 virtual_address)
{
u64 phys = mem_alloc_2mb_physical_page();
if (!phys)
{
panic("Out of physical memory");
}
mem_map_2mb_page(virtual_address, phys);
return (void*)virtual_address;
}
void mem_free_2mb(u64 virtual_address)
{
u64 phys = mem_unmap_2mb_page(virtual_address);
mem_free_2mb_physical_page(phys);
}

20
src/arch/x86_64/mem.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "std.h"
#include "x86_64/multiboot.h"
#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)
void mem_init(multiboot_info_t* info);
u64 mem_alloc_2mb_physical_page();
void mem_free_2mb_physical_page(u64 address);
void mem_map_2mb_page(u64 virtual_address, u64 physical_address);
u64 mem_unmap_2mb_page(u64 virtual_address);
void* mem_alloc_2mb(u64 virtual_address);
void mem_free_2mb(u64 virtual_address);

View File

@@ -1,52 +0,0 @@
#include "mmap.h"
#include "../arch.h"
#include <stddef.h>
#include <stdio.h>
#define USABLE_REGION_SIZE 32
memory_map_t memory_map;
static memory_region_t usable_regions[USABLE_REGION_SIZE];
void map_memory(multiboot_info_t* info)
{
if (!(info->flags & (1 << 6)))
{
printf("Invalid memory map given by bootloader\n");
panic();
}
size_t num_regions = 0;
uint64_t offset = 0;
while (offset < info->mmap_length)
{
multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)(info->mmap_addr + offset);
if (mmmt->type == MULTIBOOT_MEMORY_AVAILABLE)
{
if (num_regions < USABLE_REGION_SIZE)
{
usable_regions[num_regions] = (memory_region_t){
.base_address = mmmt->addr,
.length = mmmt->len,
};
num_regions++;
}
else
{
printf("System has more memory than the memory map can hold\n");
break;
}
}
offset += mmmt->size + sizeof(mmmt->size);
}
memory_map = (memory_map_t){
.num_regions = num_regions,
.regions = usable_regions,
};
}

View File

@@ -1,6 +0,0 @@
#pragma once
#include "../arch.h"
#include "multiboot.h"
void map_memory(multiboot_info_t* mbd);

8
src/arch/x86_64/panic.c Normal file
View File

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

3
src/arch/x86_64/panic.h Normal file
View File

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

View File

@@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include "std.h"
enum
{
@@ -68,14 +68,14 @@ enum
CPUID_FEAT_EDX_PBE = 1 << 31
};
static inline void outb(uint16_t port, uint8_t val)
static inline void outb(u16 port, u8 val)
{
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t inb(uint16_t port)
static inline u8 inb(u16 port)
{
uint8_t ret;
u8 ret;
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
@@ -85,22 +85,22 @@ static inline void io_wait()
outb(0x80, 0);
}
static inline void cpuid(uint32_t code, uint32_t* a, uint32_t* d)
static inline void cpuid(u32 code, u32* a, u32* d)
{
__asm__ volatile("cpuid" : "=a"(*a), "=d"(*d) : "a"(code) : "ecx", "ebx");
}
static inline uint64_t rdmsr(uint32_t msr)
static inline u64 rdmsr(u32 msr)
{
uint32_t lo, hi;
u32 lo, hi;
__asm__ volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return ((uint64_t)hi << 32) | lo;
return ((u64)hi << 32) | lo;
}
static inline void wrmsr(uint32_t msr, uint64_t value)
static inline void wrmsr(u32 msr, u64 value)
{
uint32_t lo = (uint32_t)value;
uint32_t hi = (uint32_t)(value >> 32);
u32 lo = (u32)value;
u32 hi = (u32)(value >> 32);
__asm__ volatile("wrmsr" : : "c"(msr), "a"(lo), "d"(hi));
}
@@ -110,4 +110,14 @@ static inline void halt()
{
__asm__ volatile("hlt");
}
}
static inline void enable_interrupts()
{
__asm__ volatile("sti");
}
static inline void disable_interrupts()
{
__asm__ volatile("cli");
}

View File

@@ -1,9 +0,0 @@
#include "kernel.h"
#include "pmm.h"
#include <stdio.h>
void main()
{
pmm_init();
printf("Welcome to nub OS :)\n");
}

View File

@@ -1,3 +0,0 @@
#pragma once
void main();

7
src/kernel/kernel.c Normal file
View File

@@ -0,0 +1,7 @@
#include "kernel.h"
#include "std.h"
void kernel_main()
{
printf("Welcome to nub OS :)\n");
}

3
src/kernel/kernel.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void kernel_main();

View File

@@ -1,87 +0,0 @@
#include "pmm.h"
#include "arch/arch.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#define BITMAP_SIZE 32768 // Supports up to 1GB of RAM
#define USABLE_REGION_SIZE 32
static uint8_t page_bitmap[BITMAP_SIZE];
static uint64_t total_pages = 0;
static uint64_t free_pages = 0;
void pmm_init()
{
memset(page_bitmap, 0xFF, BITMAP_SIZE);
for (size_t i = 0; i < memory_map.num_regions; i++)
{
memory_region_t region = memory_map.regions[i];
uint64_t start_page = region.base_address / PAGE_SIZE;
uint64_t num_pages = region.length / PAGE_SIZE;
for (uint64_t page = start_page; page < start_page + num_pages; page++)
{
if (page < BITMAP_SIZE * 8)
{
page_bitmap[page / 8] &= ~(1 << (page % 8));
free_pages++;
total_pages++;
}
else
{
printf("System has more ram than the bitmap allows!\n");
break;
}
}
}
// Reserve first 64MB which is reserved by boot code
for (uint64_t page = 0; page < (64 * 1024 * 1024) / PAGE_SIZE; page++)
{
if (page < BITMAP_SIZE * 8)
{
if (!(page_bitmap[page / 8] & (1 << (page % 8))))
{
page_bitmap[page / 8] |= (1 << (page % 8));
free_pages--;
}
}
}
}
uint64_t pmm_alloc_page()
{
for (size_t i = 0; i < BITMAP_SIZE; i++)
{
if (page_bitmap[i] != 0xFF)
{
for (int bit = 0; bit < 8; bit++)
{
if (!(page_bitmap[i] & (1 << bit)))
{
page_bitmap[i] |= (1 << bit);
free_pages--;
return ((i * 8 + bit) * PAGE_SIZE);
}
}
}
}
return 0;
}
void pmm_free_page(uint64_t addr)
{
uint64_t page = addr / PAGE_SIZE;
if (page < BITMAP_SIZE * 8)
{
if (page_bitmap[page / 8] & (1 << (page % 8)))
{
page_bitmap[page / 8] &= ~(1 << (page % 8));
free_pages++;
}
}
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include <stdint.h>
#define PAGE_SIZE 4096
void pmm_init();
uint64_t pmm_alloc_page();
void pmm_free_page(uint64_t addr);

6
src/std.h Normal file
View File

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

63
src/stdlib/def.h Normal file
View File

@@ -0,0 +1,63 @@
#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

View File

@@ -1,9 +1,4 @@
#include "../arch/arch.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "arch.h"
void printf(const char* fmt, ...)
{
@@ -20,54 +15,54 @@ void printf(const char* fmt, ...)
if (fmt[i] == '%')
{
put_char('%');
arch_api.putchar('%');
}
else if (fmt[i] == 's')
{
const char* str = va_arg(args, const char*);
for (size_t j = 0; str[j] != '\0'; j++)
{
put_char(str[j]);
arch_api.putchar(str[j]);
}
}
else if (fmt[i] == 'c')
{
char character = (char)va_arg(args, int64_t);
put_char(character);
char character = (char)va_arg(args, u64);
arch_api.putchar(character);
}
else if (fmt[i] == 'd')
{
int64_t val = va_arg(args, int64_t);
u64 val = va_arg(args, u64);
char buf[21];
itoa64(val, buf);
for (size_t j = 0; buf[j] != '\0'; j++)
{
put_char(buf[j]);
arch_api.putchar(buf[j]);
}
}
else if (fmt[i] == 'u')
{
uint64_t val = va_arg(args, uint64_t);
u64 val = va_arg(args, u64);
char buf[21];
uitoa64(val, buf);
for (size_t j = 0; buf[j] != '\0'; j++)
{
put_char(buf[j]);
arch_api.putchar(buf[j]);
}
}
else if (fmt[i] == 'x')
{
uint64_t val = va_arg(args, uint64_t);
u64 val = va_arg(args, u64);
char buf[17];
uitoa64_hex(val, buf);
for (size_t j = 0; buf[j] != '\0'; j++)
{
put_char(buf[j]);
arch_api.putchar(buf[j]);
}
}
else
{
put_char(fmt[i]);
arch_api.putchar(fmt[i]);
}
}
else if (fmt[i] == '%')
@@ -76,7 +71,7 @@ void printf(const char* fmt, ...)
}
else
{
put_char(fmt[i]);
arch_api.putchar(fmt[i]);
}
}

17
src/stdlib/mem.c Normal file
View File

@@ -0,0 +1,17 @@
#include "mem.h"
void memset(void* destination, u8 value, size_t length)
{
for (size_t i = 0; i < length; i++)
{
((u8*)destination)[i] = value;
}
}
void memcpy(void* destination, void* source, size_t length)
{
for (size_t i = 0; i < length; i++)
{
((u8*)destination)[i] = ((u8*)source)[i];
}
}

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

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

View File

@@ -1,8 +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)

View File

@@ -1,7 +0,0 @@
#pragma once
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1

View File

@@ -1,12 +0,0 @@
#pragma once
#ifndef NULL
#define NULL ((void*)0)
#endif
typedef unsigned long size_t;
typedef long ptrdiff_t;
typedef long intptr_t;
typedef unsigned long uintptr_t;
#define offsetof(type, member) __builtin_offsetof(type, member)

View File

@@ -1,50 +0,0 @@
#pragma once
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
typedef uint8_t u8;
typedef int8_t i8;
typedef uint16_t u16;
typedef int16_t i16;
typedef uint32_t u32;
typedef int32_t i32;
typedef uint64_t u64;
typedef int64_t 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

View File

@@ -1,12 +1,4 @@
#include <string.h>
void memset(void* destination, uint8_t value, size_t length)
{
for (size_t i = 0; i < length; i++)
{
((uint8_t*)destination)[i] = value;
}
}
#include "string.h"
int strcmp(const char* a, const char* b)
{
@@ -33,7 +25,7 @@ void reverse(char* str, size_t length)
}
}
void itoa64(int64_t value, char* buffer)
void itoa64(i64 value, char* buffer)
{
char temp[21];
int i = 0, j = 0;
@@ -83,7 +75,7 @@ void itoa64(int64_t value, char* buffer)
buffer[j] = '\0';
}
void uitoa64(uint64_t value, char* buffer)
void uitoa64(u64 value, char* buffer)
{
char temp[21];
int i = 0, j = 0;
@@ -108,7 +100,7 @@ void uitoa64(uint64_t value, char* buffer)
buffer[j] = '\0';
}
void uitoa64_hex(uint64_t value, char* buffer)
void uitoa64_hex(u64 value, char* buffer)
{
const char* digits = "0123456789abcdef";
char temp[17];

View File

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