Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions kernel/include/kernel/handlers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

#ifndef HANDLERS_H
#define HANDLERS_H

#include <kernel/idt.h>

void handle_gpf (registers_t* registers);

void __init_handlers__ ();

#endif
1 change: 1 addition & 0 deletions kernel/include/kernel/idt.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ typedef void (*irq_handler_t) (registers_t*);

void __init_idt__ (void);
void idt_register_handler (int vector, irq_handler_t handler);
void idt_set_flags (int vector, uint8_t gate_type, uint8_t dpl, uint8_t ist);

#endif
4 changes: 2 additions & 2 deletions kernel/include/kernel/memmgt.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ vaddr_t get_vaddr_t_from_ptr (void* ptr);
void* get_vaddr_hhdm (uint64_t phys_address);
void* vaddr_t_to_ptr (vaddr_t* virtual_addr);

void* alloc_vpages (size_t req_count);
void* alloc_vpage (void);
void* alloc_vpages (size_t req_count, bool user);
void* alloc_vpage (bool user);
void free_vpages (void* ptr, size_t count);
void free_vpage (void* ptr);

Expand Down
10 changes: 10 additions & 0 deletions kernel/include/kernel/syscall.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#ifndef SYSCALL_H
#define SYSCALL_H

#include <kernel/idt.h>

void syscall_handler (registers_t* registers);
void __init_syscalls__ (void);

#endif
46 changes: 45 additions & 1 deletion kernel/src/kernel/entry.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#include <kernel/console.h>
#include <kernel/gdt.h>
#include <kernel/graphics.h>
#include <kernel/handlers.h>
#include <kernel/hardfonts/classic.h>
#include <kernel/hw/pic.h>
#include <kernel/idt.h>
#include <kernel/limine.h>
#include <kernel/memmgt.h>
#include <kernel/serial.h>
#include <kernel/stack.h>
#include <kernel/syscall.h>
#include <liballoc/liballoc.h>
#include <memory.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
Expand All @@ -31,6 +34,33 @@ static void hcf (void) {
}
}

__attribute__ ((noreturn)) void jump_to_usermode (uintptr_t entry_point, uintptr_t user_stack) {
__asm__ volatile (
"cli \n\t" // 1. Disable interrupts while swapping states
"mov $0x3B, %%ax \n\t" // 2. Load User Data Segment descriptor (0x38 | 3 = 0x3B)
"mov %%ax, %%ds \n\t"
"mov %%ax, %%es \n\t"
"mov %%ax, %%fs \n\t"
"mov %%ax, %%gs \n\t" // (Note: if you use swapgs later, handling GS changes)

// 3. Push the structure for iretq
"pushq $0x3B \n\t" // Push SS (User Data Segment)
"pushq %0 \n\t" // Push RSP (User Stack Pointer)
"pushq $0x202 \n\t" // Push RFLAGS (0x202 = Interrupts Enabled)
"pushq $0x43 \n\t" // Push CS (User Code Segment, 0x40 | 3 = 0x43)
"pushq %1 \n\t" // Push RIP (Entry Point)

"iretq \n\t" // 4. Fire iretq to pop registers and drop to Ring 3
:
: "r"(user_stack), "r"(entry_point) // Inputs from C
: "memory", "rax" // Clobbers
);

// This loop should never be reached, but satisfies compiling with noreturn
while (1)
;
}

/*!
Entry point of kernel. Everything is set up here.
*/
Expand All @@ -48,7 +78,7 @@ void _start (void) {
asm ("cli");

gdt_init ();
// tss_init();
tss_init ();

__init_pic__ ();
__init_idt__ ();
Expand All @@ -73,6 +103,8 @@ void _start (void) {
}

__init_memmgt__ (hhdm_base, memmap_req.response);
__init_syscalls__ ();
__init_handlers__ ();

set_color (0x44eeaa);

Expand Down Expand Up @@ -103,6 +135,18 @@ void _start (void) {

printf ("CR3: %lx", cr3);

printf ("\nJumping to user land!\n");

/*
* TODO: bunch of stuff
* - [ ] set up user mode code to actually compile
* - [ ] set up limine loading it as a module
* - [ ] set up a vfs
* - [ ] set up elf-loading
* - [ ] set up cpio reading and ramfs driver
* only THEN actually jump to user code
*/

// We're done, just hang...
printf ("\n\nAll execution completed.");
hcf ();
Expand Down
10 changes: 10 additions & 0 deletions kernel/src/kernel/handlers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <kernel/handlers.h>
#include <kernel/serial.h>

void handle_gpf (registers_t* registers) {
write_serial_str ("\nOopsy! Looks like someone tried to execute a disallowed instruction!");
for (;;)
;
}

void __init_handlers__ (void) { idt_register_handler (0xD, handle_gpf); }
8 changes: 8 additions & 0 deletions kernel/src/kernel/idt.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ void idt_register_handler (int vector, irq_handler_t handler) {
interrupt_handlers[vector] = handler;
}

void idt_set_flags (int vector, uint8_t gate_type, uint8_t dpl, uint8_t ist) {
idt_entry_t* descriptor = &idt[vector];

descriptor->gate_type = gate_type;
descriptor->dpl = dpl;
descriptor->ist = ist;
}

void __init_idt__ (void) {
idtr.size = (uint16_t)(sizeof (idt_entry_t) * 256) - 1;
idtr.offset = (uint64_t)&idt[0];
Expand Down
14 changes: 9 additions & 5 deletions kernel/src/kernel/memmgt.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ static bool is_vaddr_t_lt (vaddr_t* a, vaddr_t* b) {
* @param last last virtual address in range
* @param base_addr base address of physical memory of corresponding size
*/
static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base_addr) {
static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base_addr, bool user) {
uint64_t phys_base_track = (uint64_t)base_addr;
pml4t_entry_t* pml4t_entry = &pml4_base_ptr[first.pml4_index];

Expand All @@ -293,6 +293,7 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base
pdpt_entry->pd_base_address = (uint64_t)new_table / PAGE_SIZE;
memset (get_vaddr_from_frame ((uint64_t)new_table / PAGE_SIZE), 0, PAGE_SIZE);
}
pdpt_entry->user_supervisor = user;

pd_entry_t* pd_base = (pd_entry_t*)get_vaddr_from_frame (pdpt_entry->pd_base_address);
pd_entry_t* pd_entry = &pd_base[current.pd_index];
Expand All @@ -304,13 +305,15 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base
pd_entry->pt_base_address = (uint64_t)new_table / PAGE_SIZE;
memset (get_vaddr_from_frame ((uint64_t)new_table / PAGE_SIZE), 0, PAGE_SIZE);
}
pd_entry->us = user;

pt_entry_t* pt_base = (pt_entry_t*)get_vaddr_from_frame (pd_entry->pt_base_address);
pt_entry_t* pt_entry = &pt_base[current.pt_index];

pt_entry->present = 1;
pt_entry->rw = 1;
pt_entry->frame_base_address = phys_base_track / PAGE_SIZE;
pt_entry->us = user;
phys_base_track += PAGE_SIZE;

if (!is_vaddr_t_lt (&current, &last))
Expand All @@ -333,7 +336,7 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base
* @param count number of consecutive pages to allocate
* @return base virtual address of allocated pages
*/
void* alloc_vpages (size_t req_count) {
void* alloc_vpages (size_t req_count, bool user) {
// all memory allocations are currently under one pml4 entry. this is 512 gb of memory, which
// should be plenty for literally any use case of COS.
pml4t_entry_t* pml4t_entry = &pml4_base_ptr[1];
Expand Down Expand Up @@ -414,7 +417,7 @@ void* alloc_vpages (size_t req_count) {
((start_page_idx + req_count - 1) >> 9) & 0x1FF,
(start_page_idx + req_count - 1) & 0x1FF, 0};

alloc_all_vpages_in_range (first_vaddr, last_vaddr, base_physical);
alloc_all_vpages_in_range (first_vaddr, last_vaddr, base_physical, user);
return vaddr_t_to_ptr (&first_vaddr);
}

Expand All @@ -425,7 +428,7 @@ void* alloc_vpages (size_t req_count) {
* Allocate one virtual page
* @return base virtual address of allocated page
*/
void* alloc_vpage (void) { return alloc_vpages (1); }
void* alloc_vpage (bool user) { return alloc_vpages (1, user); }

/*!
* Check if page structure is empty
Expand Down Expand Up @@ -564,6 +567,7 @@ void __init_memmgt__ (uint64_t p_hhdm_offset, struct limine_memmap_response* mem

pml4_base_ptr[1].present = 1;
pml4_base_ptr[1].read_write = 1;
pml4_base_ptr[1].user_supervisor = 1;
pml4_base_ptr[1].pdpt_base_address = ((uint64_t)pdpt_frame) / PAGE_SIZE;
}

Expand Down Expand Up @@ -675,7 +679,7 @@ int liballoc_unlock () {
return 0;
}

void* liballoc_alloc (size_t count) { return alloc_vpages (count); }
void* liballoc_alloc (size_t count) { return alloc_vpages (count, false); }

int liballoc_free (void* ptr, size_t count) {
if (is_locked)
Expand Down
9 changes: 9 additions & 0 deletions kernel/src/kernel/syscall.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <kernel/serial.h>
#include <kernel/syscall.h>

void syscall_handler (registers_t* registers) { uint8_t syscall_number = registers->rax; }

void __init_syscalls__ (void) {
idt_register_handler (0x80, syscall_handler);
idt_set_flags (0x80, 0x0E, 3, 0);
}
Loading