Compare commits
16 Commits
a3822dd350
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd3dbc3ab1 | ||
|
|
ff12b6abf2 | ||
|
|
a018dfd471 | ||
|
|
8cc90d6f2f | ||
|
|
4f55956fee | ||
|
|
45a9023bab | ||
|
|
130e271461 | ||
|
|
46bc977104 | ||
|
|
5f071104bc | ||
|
|
62680a05bc | ||
|
|
ac0299d718 | ||
|
|
b15c037b16 | ||
|
|
02f0ba9aad | ||
|
|
0ccb483047 | ||
|
|
ad0ec03b0f | ||
|
|
7b115e5b66 |
19
.clangd
19
.clangd
@@ -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
28
.vscode/c_cpp_properties.json
vendored
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
34
.vscode/settings.json
vendored
34
.vscode/settings.json
vendored
@@ -3,6 +3,38 @@
|
|||||||
"bitset": "c",
|
"bitset": "c",
|
||||||
"algorithm": "c",
|
"algorithm": "c",
|
||||||
"format": "c",
|
"format": "c",
|
||||||
"multiboot.h": "c"
|
"multiboot.h": "c",
|
||||||
|
"irq.h": "c",
|
||||||
|
"idt.h": "c",
|
||||||
|
"util.h": "c",
|
||||||
|
"deque": "c",
|
||||||
|
"forward_list": "c",
|
||||||
|
"list": "c",
|
||||||
|
"string": "c",
|
||||||
|
"unordered_map": "c",
|
||||||
|
"unordered_set": "c",
|
||||||
|
"vector": "c",
|
||||||
|
"any": "c",
|
||||||
|
"system_error": "c",
|
||||||
|
"std.h": "c",
|
||||||
|
"panic.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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,25 +3,24 @@ ENTRY(_start)
|
|||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 2M;
|
. = 2M;
|
||||||
kernel_start = .;
|
|
||||||
|
|
||||||
.text BLOCK(4K) : ALIGN(4K)
|
.text :
|
||||||
{
|
{
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
*(.text)
|
*(.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
.rodata BLOCK(4K) : ALIGN(4K)
|
.rodata :
|
||||||
{
|
{
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
}
|
}
|
||||||
|
|
||||||
.data BLOCK(4K) : ALIGN(4K)
|
.data :
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
.bss BLOCK(4K) : ALIGN(4K)
|
.bss :
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
|||||||
12
makefile
12
makefile
@@ -2,9 +2,15 @@ CC = x86_64-elf-gcc
|
|||||||
LD = x86_64-elf-ld
|
LD = x86_64-elf-ld
|
||||||
AS = nasm
|
AS = nasm
|
||||||
|
|
||||||
CFLAGS = -m64 -ffreestanding -nostdinc -nostdlib -fno-builtin -Wall -Wextra -Wshadow -std=c11 -I src -I src/kernel -I src/arch -g
|
# Modify these settings here for defines and debug info
|
||||||
LDFLAGS = -g
|
CFLAGS = -g -D DEBUG
|
||||||
ASFLAGS = -f elf64 -g -F dwarf
|
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_C := $(shell find src -name '*.c')
|
||||||
SRC_ASM := $(shell find src -name '*.asm')
|
SRC_ASM := $(shell find src -name '*.asm')
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#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
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
extern arch_api_t arch_api;
|
|
||||||
93
src/arch/x86_64/arch.c
Normal file
93
src/arch/x86_64/arch.c
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#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()
|
||||||
|
{
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arch_disable_interrupts()
|
||||||
|
{
|
||||||
|
disable_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arch_enable_interrupts()
|
||||||
|
{
|
||||||
|
enable_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arch_panic()
|
||||||
|
{
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arch_console_putchar(char c)
|
||||||
|
{
|
||||||
|
console_putchar(c, VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arch_console_clear()
|
||||||
|
{
|
||||||
|
console_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
.putchar = arch_console_putchar,
|
||||||
|
.clear = arch_console_clear,
|
||||||
|
};
|
||||||
|
|
||||||
|
arch_api_t arch_api = {
|
||||||
|
.halt = arch_halt,
|
||||||
|
.disable_interrupts = arch_disable_interrupts,
|
||||||
|
.enable_interrupts = arch_enable_interrupts,
|
||||||
|
.panic = arch_panic,
|
||||||
|
.console = arch_console_api,
|
||||||
|
.mem = arch_mem_api,
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
global _start
|
global _start
|
||||||
global pml4
|
global pml4
|
||||||
extern x86_64_main
|
extern x86_64_main
|
||||||
|
extern kernel_end
|
||||||
|
|
||||||
%define FLAGS 0b10
|
%define FLAGS 0b10
|
||||||
%define MAGIC 0x1BADB002
|
%define MAGIC 0x1BADB002
|
||||||
@@ -43,6 +44,8 @@ section .data
|
|||||||
dd 0
|
dd 0
|
||||||
multiboot_magic:
|
multiboot_magic:
|
||||||
dd 0
|
dd 0
|
||||||
|
kernel_page_count:
|
||||||
|
dd 0
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
bits 32
|
bits 32
|
||||||
@@ -98,10 +101,18 @@ section .text
|
|||||||
mov eax, pd
|
mov eax, pd
|
||||||
or eax, 0x03
|
or eax, 0x03
|
||||||
mov [pdpt], eax
|
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 edi, pd
|
||||||
mov eax, 0x83
|
mov eax, 0x83
|
||||||
mov ecx, 32
|
|
||||||
.setup_pd:
|
.setup_pd:
|
||||||
mov [edi], eax
|
mov [edi], eax
|
||||||
add eax, 0x200000
|
add eax, 0x200000
|
||||||
@@ -150,6 +161,7 @@ section .text
|
|||||||
; Finally, we call in to c
|
; Finally, we call in to c
|
||||||
mov edi, [multiboot_magic]
|
mov edi, [multiboot_magic]
|
||||||
mov esi, [multiboot_info]
|
mov esi, [multiboot_info]
|
||||||
|
mov edx, [kernel_page_count]
|
||||||
call x86_64_main
|
call x86_64_main
|
||||||
.hang:
|
.hang:
|
||||||
hlt
|
hlt
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static vga_char_t* vga_buffer = (vga_char_t*)0xb8000;
|
|||||||
static u8 cursor_row = 0;
|
static u8 cursor_row = 0;
|
||||||
static u8 cursor_col = 0;
|
static u8 cursor_col = 0;
|
||||||
|
|
||||||
void console_put_char(char c, u8 color)
|
void console_putchar(char c, u8 color)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "std.h"
|
#include <def.h>
|
||||||
|
|
||||||
#define VGA_BLACK 0
|
#define VGA_BLACK 0
|
||||||
#define VGA_BLUE 1
|
#define VGA_BLUE 1
|
||||||
@@ -21,5 +21,5 @@
|
|||||||
|
|
||||||
#define VGA_DEFAULT_COLOR VGA_LIGHT_GRAY | VGA_BLACK << 4
|
#define VGA_DEFAULT_COLOR VGA_LIGHT_GRAY | VGA_BLACK << 4
|
||||||
|
|
||||||
void console_put_char(char character, u8 color);
|
void console_putchar(char character, u8 color);
|
||||||
void console_clear();
|
void console_clear();
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "../panic.h"
|
#include "../panic.h"
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
static const char* exception_messages[32] = {
|
static const char* exception_messages[32] = {
|
||||||
"divide by zero",
|
"divide by zero",
|
||||||
@@ -39,5 +40,5 @@ static const char* exception_messages[32] = {
|
|||||||
void handle_exception(const isr_frame_t* frame)
|
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);
|
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();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
#define PIC1_COMMAND 0x20
|
#define PIC1_COMMAND 0x20
|
||||||
#define PIC1_DATA 0x21
|
#define PIC1_DATA 0x21
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "isr.h"
|
#include "isr.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
|
#include <def.h>
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
void handle_isr(const isr_frame_t* frame)
|
void handle_isr(const isr_frame_t* frame)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "std.h"
|
#include <def.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,45 +1,35 @@
|
|||||||
#include "arch.h"
|
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "interrupts/idt.h"
|
#include "interrupts/idt.h"
|
||||||
#include "interrupts/irq.h"
|
#include "interrupts/irq.h"
|
||||||
#include "kernel.h"
|
#include "mem/pmm.h"
|
||||||
#include "mem.h"
|
#include "mem/vmm.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "util.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();
|
console_clear();
|
||||||
|
|
||||||
if (magic != 0x2BADB002)
|
if (magic != 0x2BADB002)
|
||||||
{
|
{
|
||||||
panic("Multiboot magic does not match\n");
|
printf("Multiboot magic does not match\n");
|
||||||
|
panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
{
|
{
|
||||||
panic("Multiboot info is NULL\n");
|
printf("Multiboot info is NULL\n");
|
||||||
|
panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
idt_init();
|
idt_init();
|
||||||
mem_init(info);
|
|
||||||
|
|
||||||
mem_alloc_2mb(MiB(128) + 1);
|
|
||||||
|
|
||||||
remap_pic();
|
remap_pic();
|
||||||
enable_interrupts();
|
|
||||||
|
pmm_init(kernel_page_count, info);
|
||||||
|
vmm_init(kernel_page_count);
|
||||||
|
|
||||||
kernel_main();
|
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,
|
|
||||||
};
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#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);
|
|
||||||
127
src/arch/x86_64/mem/pmm.c
Normal file
127
src/arch/x86_64/mem/pmm.c
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#include "pmm.h"
|
||||||
|
#include "../panic.h"
|
||||||
|
#include <mem.h>
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u64 base_address;
|
||||||
|
size_t length;
|
||||||
|
} memory_region_t;
|
||||||
|
|
||||||
|
#define USABLE_REGION_SIZE 32
|
||||||
|
|
||||||
|
static memory_region_t usable_regions[USABLE_REGION_SIZE];
|
||||||
|
static size_t num_regions = 0;
|
||||||
|
|
||||||
|
#define BITMAP_PAGE_COUNT (MAX_MEMORY / PAGE_SIZE)
|
||||||
|
#define BITMAP_SIZE (BITMAP_PAGE_COUNT / 8)
|
||||||
|
|
||||||
|
static u8 page_bitmap[BITMAP_SIZE];
|
||||||
|
|
||||||
|
void pmm_init(u32 kernel_page_count, multiboot_info_t* info)
|
||||||
|
{
|
||||||
|
if (!(info->flags & (1 << 6)))
|
||||||
|
{
|
||||||
|
printf("Invalid memory map given by bootloader\n");
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
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_PAGE_COUNT)
|
||||||
|
{
|
||||||
|
page_bitmap[page / 8] &= ~(1 << (page % 8));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("System has more ram than the bitmap allows!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
printf("Bitmap is not large enough to hold the memory reserved by the kernel");
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
page_bitmap[page / 8] |= (1 << (page % 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 pmm_alloc()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
return ((i * 8 + bit) * PAGE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pmm_free(u64 physical_address)
|
||||||
|
{
|
||||||
|
u64 page = physical_address / PAGE_SIZE;
|
||||||
|
if (page < BITMAP_SIZE * 8)
|
||||||
|
{
|
||||||
|
if (page_bitmap[page / 8] & (1 << (page % 8)))
|
||||||
|
{
|
||||||
|
page_bitmap[page / 8] &= ~(1 << (page % 8));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Physical address %x is already free", physical_address);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/arch/x86_64/mem/pmm.h
Normal file
20
src/arch/x86_64/mem/pmm.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
// Defines the theoretical max memory the kernel can allocate, not the actual memory of the system
|
||||||
|
// The value must be a multible of 8
|
||||||
|
#define MAX_MEMORY GiB(64)
|
||||||
|
|
||||||
|
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
|
||||||
|
// A return value 0 indicates out of memory
|
||||||
|
u64 pmm_alloc();
|
||||||
|
|
||||||
|
// Low level function to free a 2mb physical page
|
||||||
|
void pmm_free(u64 physical_address);
|
||||||
185
src/arch/x86_64/mem/vmm.c
Normal file
185
src/arch/x86_64/mem/vmm.c
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#include "vmm.h"
|
||||||
|
#include "../panic.h"
|
||||||
|
#include "pmm.h"
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
|
#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 BITMAP_PAGE_COUNT (ADDRES_SPACE_SIZE / PAGE_SIZE)
|
||||||
|
#define BITMAP_SIZE (BITMAP_PAGE_COUNT / 8)
|
||||||
|
|
||||||
|
static u8 page_bitmap[BITMAP_SIZE];
|
||||||
|
|
||||||
|
extern u64 pml4[];
|
||||||
|
|
||||||
|
void vmm_init(u32 kernel_page_count)
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
size_t total_pages = BITMAP_PAGE_COUNT;
|
||||||
|
|
||||||
|
for (size_t start_page = 0; start_page <= total_pages - page_count; start_page++)
|
||||||
|
{
|
||||||
|
bool found_block = true;
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_free_address(u64 virtual_address, size_t page_count)
|
||||||
|
{
|
||||||
|
u64 start_page = virtual_address / PAGE_SIZE;
|
||||||
|
if (start_page + page_count > BITMAP_PAGE_COUNT)
|
||||||
|
{
|
||||||
|
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)))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (physical_address & (PAGE_SIZE - 1))
|
||||||
|
{
|
||||||
|
printf("Physical address not page aligned (0x%x)\n", physical_address);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (physical_address & PTE_MASK) | flags | PTE_PS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_map(u64 physical_address, u64 virtual_address, u32 flags)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64* pdpt_physical_address = (u64*)(pdpt & PTE_MASK);
|
||||||
|
u64 pd = pdpt_physical_address[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();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64* pd_physical_address = (u64*)(pd & PTE_MASK);
|
||||||
|
u64 entry = pd_physical_address[pd_idx];
|
||||||
|
|
||||||
|
if (entry & PTE_PRESENT)
|
||||||
|
{
|
||||||
|
printf("Virtual address 0x%x is already mapped\n", virtual_address);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
pd_physical_address[pd_idx] = create_2mb_pte(physical_address, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 vmm_unmap(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();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64* pdpt_physical_address = (u64*)(pdpt_entry & PTE_MASK);
|
||||||
|
u64 pd_entry = pdpt_physical_address[pdpt_idx];
|
||||||
|
if (!(pd_entry & PTE_PRESENT))
|
||||||
|
{
|
||||||
|
printf("PD not present at PDPT index %llu\n", pdpt_idx);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 physical_address = pd_physical_address[pd_idx] & PTE_MASK;
|
||||||
|
pd_physical_address[pd_idx] = 0;
|
||||||
|
|
||||||
|
__asm__ volatile("invlpg (%0)" : : "r"(virtual_address) : "memory");
|
||||||
|
|
||||||
|
return physical_address;
|
||||||
|
}
|
||||||
27
src/arch/x86_64/mem/vmm.h
Normal file
27
src/arch/x86_64/mem/vmm.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#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`
|
||||||
|
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);
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
void panic(const char* msg)
|
void panic()
|
||||||
{
|
{
|
||||||
printf(msg);
|
disable_interrupts();
|
||||||
halt();
|
halt();
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void panic(const char* msg);
|
void panic();
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "std.h"
|
#include <def.h>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|||||||
49
src/kernel/alloc.c
Normal file
49
src/kernel/alloc.c
Normal 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
6
src/kernel/alloc.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
|
void* malloc(size_t size);
|
||||||
|
void free(void* ptr);
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "std.h"
|
#include <arch.h>
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
void kernel_main()
|
void kernel_main()
|
||||||
{
|
{
|
||||||
|
arch_api.enable_interrupts();
|
||||||
|
|
||||||
printf("Welcome to nub OS :)\n");
|
printf("Welcome to nub OS :)\n");
|
||||||
|
printf("Kernel has exited\n");
|
||||||
|
arch_api.halt();
|
||||||
}
|
}
|
||||||
40
src/lib/arch.h
Normal file
40
src/lib/arch.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <def.h>
|
||||||
|
|
||||||
|
typedef void (*arch_console_putchar_t)(char c);
|
||||||
|
typedef void (*arch_console_clear_t)();
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const arch_console_putchar_t putchar;
|
||||||
|
const arch_console_clear_t clear;
|
||||||
|
} arch_console_api_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)();
|
||||||
|
typedef void (*arch_enable_interrupts_t)();
|
||||||
|
typedef void (*arch_disable_interrupts_t)();
|
||||||
|
typedef void (*arch_halt_t)();
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const arch_panic_t panic;
|
||||||
|
const arch_enable_interrupts_t enable_interrupts;
|
||||||
|
const arch_disable_interrupts_t disable_interrupts;
|
||||||
|
const arch_halt_t halt;
|
||||||
|
const arch_console_api_t console;
|
||||||
|
const arch_mem_api_t mem;
|
||||||
|
} arch_api_t;
|
||||||
|
|
||||||
|
extern arch_api_t arch_api;
|
||||||
17
src/lib/assert.h
Normal file
17
src/lib/assert.h
Normal 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
67
src/lib/def.h
Normal 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
6
src/lib/mem.h
Normal 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);
|
||||||
@@ -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, ...)
|
void printf(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
@@ -15,20 +35,20 @@ void printf(const char* fmt, ...)
|
|||||||
|
|
||||||
if (fmt[i] == '%')
|
if (fmt[i] == '%')
|
||||||
{
|
{
|
||||||
arch_api.putchar('%');
|
arch_api.console.putchar('%');
|
||||||
}
|
}
|
||||||
else if (fmt[i] == 's')
|
else if (fmt[i] == 's')
|
||||||
{
|
{
|
||||||
const char* str = va_arg(args, const char*);
|
const char* str = va_arg(args, const char*);
|
||||||
for (size_t j = 0; str[j] != '\0'; j++)
|
for (size_t j = 0; str[j] != '\0'; j++)
|
||||||
{
|
{
|
||||||
arch_api.putchar(str[j]);
|
arch_api.console.putchar(str[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fmt[i] == 'c')
|
else if (fmt[i] == 'c')
|
||||||
{
|
{
|
||||||
char character = (char)va_arg(args, u64);
|
char character = (char)va_arg(args, u64);
|
||||||
arch_api.putchar(character);
|
arch_api.console.putchar(character);
|
||||||
}
|
}
|
||||||
else if (fmt[i] == 'd')
|
else if (fmt[i] == 'd')
|
||||||
{
|
{
|
||||||
@@ -37,7 +57,7 @@ void printf(const char* fmt, ...)
|
|||||||
itoa64(val, buf);
|
itoa64(val, buf);
|
||||||
for (size_t j = 0; buf[j] != '\0'; j++)
|
for (size_t j = 0; buf[j] != '\0'; j++)
|
||||||
{
|
{
|
||||||
arch_api.putchar(buf[j]);
|
arch_api.console.putchar(buf[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fmt[i] == 'u')
|
else if (fmt[i] == 'u')
|
||||||
@@ -47,7 +67,7 @@ void printf(const char* fmt, ...)
|
|||||||
uitoa64(val, buf);
|
uitoa64(val, buf);
|
||||||
for (size_t j = 0; buf[j] != '\0'; j++)
|
for (size_t j = 0; buf[j] != '\0'; j++)
|
||||||
{
|
{
|
||||||
arch_api.putchar(buf[j]);
|
arch_api.console.putchar(buf[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fmt[i] == 'x')
|
else if (fmt[i] == 'x')
|
||||||
@@ -57,12 +77,12 @@ void printf(const char* fmt, ...)
|
|||||||
uitoa64_hex(val, buf);
|
uitoa64_hex(val, buf);
|
||||||
for (size_t j = 0; buf[j] != '\0'; j++)
|
for (size_t j = 0; buf[j] != '\0'; j++)
|
||||||
{
|
{
|
||||||
arch_api.putchar(buf[j]);
|
arch_api.console.putchar(buf[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arch_api.putchar(fmt[i]);
|
arch_api.console.putchar(fmt[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fmt[i] == '%')
|
else if (fmt[i] == '%')
|
||||||
@@ -71,7 +91,7 @@ void printf(const char* fmt, ...)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arch_api.putchar(fmt[i]);
|
arch_api.console.putchar(fmt[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
4
src/lib/printf.h
Normal file
4
src/lib/printf.h
Normal 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, ...);
|
||||||
@@ -25,6 +25,10 @@ void reverse(char* str, size_t length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ```c
|
||||||
|
// char buffer[21];
|
||||||
|
// itoa64(-1234, buffer);
|
||||||
|
// ```
|
||||||
void itoa64(i64 value, char* buffer)
|
void itoa64(i64 value, char* buffer)
|
||||||
{
|
{
|
||||||
char temp[21];
|
char temp[21];
|
||||||
@@ -34,7 +38,7 @@ void itoa64(i64 value, char* buffer)
|
|||||||
if (value < 0)
|
if (value < 0)
|
||||||
{
|
{
|
||||||
negative = 1;
|
negative = 1;
|
||||||
if (value == INT64_MIN)
|
if (value == I64_MIN)
|
||||||
{
|
{
|
||||||
const char* min_str = "9223372036854775808";
|
const char* min_str = "9223372036854775808";
|
||||||
for (i = 0; min_str[i] != '\0'; i++)
|
for (i = 0; min_str[i] != '\0'; i++)
|
||||||
@@ -54,7 +58,7 @@ void itoa64(i64 value, char* buffer)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(negative && value == INT64_MIN))
|
if (!(negative && value == I64_MIN))
|
||||||
{
|
{
|
||||||
while (value > 0)
|
while (value > 0)
|
||||||
{
|
{
|
||||||
@@ -75,6 +79,10 @@ void itoa64(i64 value, char* buffer)
|
|||||||
buffer[j] = '\0';
|
buffer[j] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ```c
|
||||||
|
// char buffer[21];
|
||||||
|
// uitoa64(1234, buffer);
|
||||||
|
// ```
|
||||||
void uitoa64(u64 value, char* buffer)
|
void uitoa64(u64 value, char* buffer)
|
||||||
{
|
{
|
||||||
char temp[21];
|
char temp[21];
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "std.h"
|
#include <def.h>
|
||||||
|
|
||||||
int strcmp(const char* a, const char* b);
|
int strcmp(const char* a, const char* b);
|
||||||
void reverse(char* str, size_t length);
|
void reverse(char* str, size_t length);
|
||||||
|
|
||||||
void uitoa64(u64 value, char* buffer);
|
|
||||||
void itoa64(i64 value, char* buffer);
|
void itoa64(i64 value, char* buffer);
|
||||||
|
void uitoa64(u64 value, char* buffer);
|
||||||
void uitoa64_hex(u64 value, char* buffer);
|
void uitoa64_hex(u64 value, char* buffer);
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "stdlib/def.h"
|
|
||||||
#include "stdlib/io.h"
|
|
||||||
#include "stdlib/mem.h"
|
|
||||||
#include "stdlib/string.h"
|
|
||||||
@@ -1,63 +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
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void printf(const char* fmt, ...);
|
|
||||||
@@ -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);
|
|
||||||
Reference in New Issue
Block a user