Updated kernel to now have its stack past 0xc0000000. Implemented context switching.

This commit is contained in:
Xnoe 2021-11-26 20:20:15 +00:00
parent 2dd799b406
commit ed67adc9c9
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
13 changed files with 206 additions and 31 deletions

View File

@ -167,7 +167,7 @@ void main() {
mark_unavailble(0xc0502000, 0x1000, vm_bitmap);
mark_unavailble(0xc0600000, 0x20000, vm_bitmap);
mark_unavailble(0xc0620000, 0x20000, vm_bitmap);
mark_unavailble(0x8a000, 0x6000, vm_bitmap);
mark_unavailble(0xc1000000, 0x6000, vm_bitmap);
// Map the bitmap
map_many_4k_phys_to_virt(0x100000, 0xc0600000, kernel_page_directory, kernel_page_tables, 32);
@ -175,7 +175,9 @@ void main() {
map_many_4k_phys_to_virt(0x522000, 0xc0620000, kernel_page_directory, kernel_page_tables, 32);
map_4k_phys_to_virt(0x8000, 0x8000, kernel_page_directory, kernel_page_tables);
// Map the stack
map_many_4k_phys_to_virt(0x8a000, 0x8a000, kernel_page_directory, kernel_page_tables, 6);
map_many_4k_phys_to_virt(0x8a000, 0xc1000000, kernel_page_directory, kernel_page_tables, 6);
load_file("KERNEL BIN", kernel_location);

View File

@ -1,6 +1,7 @@
[BITS 32]
_start:
mov esp, 0xc1005ffc
jmp main
extern main

View File

@ -3,6 +3,7 @@
namespace Global {
Allocator* allocator = 0;
Kernel* kernel = 0;
Process* currentProc = 0;
}
void* operator new (uint32_t size) {

View File

@ -5,10 +5,12 @@
class Kernel;
class Allocator;
class Process;
namespace Global {
extern Allocator* allocator;
extern Kernel* kernel;
extern Process* currentProc;
}
void* operator new (uint32_t size);

View File

@ -22,14 +22,89 @@ __attribute__((interrupt)) void interrupt_20(interrupt_frame* frame) {
__attribute__((interrupt)) void page_fault(interrupt_frame* frame, uint32_t err_code) {
uint32_t problem_address;
asm("mov %%cr2, %0" : "=a" (problem_address) :);
printf("Page Fault at %x\n", problem_address);
asm("hlt");
printf("(EIP %x): Page Fault at %x\n", frame->eip, problem_address);
while (1) asm("hlt");
}
__attribute__((interrupt)) void ignore_interrupt(interrupt_frame* frame) {
outb(0x20, 0x20);
}
__attribute__((interrupt)) void gpf(interrupt_frame* frame, uint32_t err_code) {
printf("General Protection Fault %d\n", err_code);
while (1) asm("hlt");
}
__attribute__((interrupt)) void context_switch(interrupt_frame* frame) {
asm ("cli"); // Disable interrupts whilst handling the context switch.
asm ("pusha"); // Push registers to the stack
Process* currentProc = Global::currentProc;
Process* nextProc = 0;
if (currentProc) {
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes;
// This cursed bit of code first determines if the processes list is longer than 1 and if it is
// - Determines if it has 2 or more elements
// - If it has two, swap the first and last, update prev and next of each to be null or the other item
// - If it has more than two, swap the first and last, then swap their next and prevs, and set the
// other value to null
if (processes->start->next != 0) {
if (processes->end->prev == processes->start) {
xnoe::linkedlistelem<Process*>* tmp = processes->start;
processes->start = processes->end;
processes->end = tmp;
processes->start->prev = 0;
processes->end->next = 0;
processes->end->prev = processes->start;
processes->start->next = processes->end;
} else {
xnoe::linkedlistelem<Process*>* tmp = processes->start;
processes->start = processes->end;
processes->end = tmp;
processes->start->next = processes->end->next;
processes->end->prev = processes->start->prev;
processes->start->prev = 0;
processes->end->next = 0;
processes->start->next->prev = processes->start;
processes->end->prev->next = processes->end;
}
// Get the next process.
nextProc = processes->start->elem;
}
Global::currentProc = nextProc;
uint32_t cESP;
asm volatile ("mov %%esp, %0" : "=a" (cESP) :);
currentProc->esp = cESP; // Store the current ESP of the current process process.
// Select the next processes page directory
asm volatile ("mov %0, %%cr3" : : "r" (nextProc->PD->phys_addr));
// Restore ESP of the new process.
asm volatile ("mov %0, %%esp" : : "m" (Global::kernel->processes.start->elem->esp));
// Restore registers
asm ("popa");
// Clear the garbage that was on the stack from previous switch_context call.
asm ("add $44, %esp");
// Pop EBP
asm ("pop %ebp");
// Re-enable interrupts.
asm ("sti");
// Manually perform iret.
asm ("iret");
}
}
void init_idt() {
idt_desc desc = {.size = 256 * sizeof(GateEntry) - 1, .offset = (uint32_t)idt};
asm volatile("lidt %0" : : "m" (desc));
@ -37,7 +112,9 @@ void init_idt() {
set_entry(i, 0x08, &ignore_interrupt, 0x8E);
set_entry(0x20, 0x08, &interrupt_20, 0x8E);
set_entry(0xD, 0x08, &gpf, 0x8E);
set_entry(0xE, 0x08, &page_fault, 0x8E);
set_entry(0x80, 0x08, &context_switch, 0x8E);
outb(0x20, 0x11);
outb(0xA0, 0x11);

View File

@ -3,13 +3,14 @@
#include "types.h"
#include "screenstuff.h"
#include "global.h"
#include "kernel.h"
struct interrupt_frame {
uint16_t ip;
uint32_t eip;
uint16_t cs;
uint16_t flags;
uint16_t sp;
uint16_t ss;
uint16_t _ignored0;
uint32_t eflags;
};
extern void load_idt();
void set_entry(uint8_t interrupt_number, uint16_t code_segment, void* handler, uint8_t type);

View File

@ -6,6 +6,10 @@ Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint
this->currentPID = 1;
Global::allocator = this;
Global::kernel = this;
Global::currentProc = 0;
this->processes.append(this);
}
void Kernel::init_kernel() {
@ -13,8 +17,11 @@ void Kernel::init_kernel() {
}
Process* Kernel::createProcess() {
Process* p = new Process(currentPID);
Process* p = new Process(currentPID, this->PD, 0xc0000000);
this->pid_map->set(currentPID, p);
currentPID++;
this->processes.append(p);
return p;
}

View File

@ -6,12 +6,12 @@
#include "global.h"
class Kernel : public Process {
private:
public:
uint32_t currentPID;
public:
xnoe::hashtable<uint32_t, Process*>* pid_map; // Map of PIDs -> Process*s
uint32_t current_PID;
xnoe::linkedlist<Process*> processes;
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);

View File

@ -47,10 +47,15 @@ int main() {
term->printf("KERNEL OK!\n");
kernel.createProcess();
Process* p = kernel.createProcess();
term->deactivate();
term2->activate();
//term->deactivate();
//term2->activate();
Global::currentProc = &kernel;
asm ("int $0x80");
term->printf("\n\nIf you are reading this, the XnoeOS kernel successfully switched contexts to another process, and then switched contexts back to the kernel. Therefore we can conclude that context switching works.");
while (1);

View File

@ -88,8 +88,10 @@ PageTable::PageTable(uint32_t phys, uint32_t virt) {
}
PageTable::PageTable(){
virt_addr = new PTE[1024];
phys_addr = Global::allocator->virtual_to_physical(virt_addr);
virt_addr = new PTE[2048];
while ((uint32_t)this->virt_addr & 0xfff || (uint32_t)this->virt_addr % 0x4)
this->virt_addr++;
phys_addr = (Global::allocator->virtual_to_physical(virt_addr)) >> 12;
page_table = (PTE*)virt_addr;
}
@ -143,8 +145,11 @@ PageDirectory::PageDirectory(PDE* page_directory, uint32_t phys_addr, uint32_t o
PageDirectory::PageDirectory() {
this->page_tables = (PageTable*)this->__page_tables;
this->page_directory = new PDE[1024];
this->page_directory = new PDE[2048];
while ((uint32_t)this->page_directory & 0xfff || (uint32_t)this->page_directory % 0x4)
this->page_directory++;
memset((uint8_t*)this->page_tables, sizeof(PageTable) * 1024, 0);
memset((uint8_t*)this->page_directory, sizeof(PDE) * 1024, 0);
this->phys_addr = Global::allocator->virtual_to_physical(this->page_directory);
}
@ -180,11 +185,11 @@ void PageDirectory::unmap(uint32_t virt) {
uint32_t PageDirectory::virtual_to_physical(uint32_t virt) {
split_addr* split = (split_addr*)&virt;
return page_tables[split->pd_index].get_physical_address(split->pt_index);
return page_tables[split->pd_index].get_physical_address(split->pt_index) + split->page_offset;
}
void PageDirectory::select() {
asm volatile("mov %0, %%eax; mov %%eax, %%cr3" : : "m" (phys_addr));
asm volatile("mov %0, %%cr3" : : "r" (phys_addr));
}
PageMap* Allocator::phys;
@ -205,7 +210,6 @@ Allocator::Allocator(PageDirectory* page_directory, PageMap* virt, uint32_t virt
}
void* Allocator::allocate(uint32_t size) {
asm("mov $0x0, 0x8a000");
uint32_t count = (size + (4096 - size % 4096)) / 4096;
uint32_t virt_addr = virt->find_next_available_from(this->virt_alloc_base, count);
@ -214,7 +218,6 @@ void* Allocator::allocate(uint32_t size) {
for (int i=0; i<count; i++) {
uint32_t phys_addr = this->phys->find_next_available_from(0);
this->phys->mark_unavailable(phys_addr);
asm("mov $0xdead, 0x8a000");
this->PD->map(phys_addr, virt_addr + 4096 * i);
}

View File

@ -51,13 +51,14 @@ struct PageTable {
class PageDirectory {
private:
PDE* page_directory;
uint8_t __page_tables[sizeof(PageTable) * 1024];
PageTable* page_tables;
public:
uint32_t phys_addr;
public:
PDE* page_directory;
PageDirectory(PDE* page_directories, uint32_t phys_addr, uint32_t offset);
PageDirectory();
@ -74,10 +75,10 @@ protected:
static PageMap* phys;
PageMap* virt;
PageDirectory* PD;
uint32_t virt_alloc_base;
public:
PageDirectory* PD;
Allocator(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
Allocator(PageDirectory* page_directory, PageMap* virt, uint32_t virt_alloc_base);
virtual void* allocate(uint32_t size);

View File

@ -26,11 +26,80 @@ Process::Process(uint32_t PID)
: Allocator(new PageDirectory, new PageMap, 0) {
this->PID = PID;
this->page_remaining = 0;
this->last_page_pointer = virt_alloc_base;
this->stack = new uint8_t[0x8000];
this->last_page_pointer = 0;
this->stack = this->allocate(0x8000);
}
Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase)
: Allocator(new PageDirectory, new PageMap, 0) {
this->PID = PID;
this->page_remaining = 0;
this->last_page_pointer = 0;
for (int index = inheritBase >> 22; index < 1024; index++)
this->PD->page_directory[index] = inherit->page_directory[index];
this->stack = this->allocate(0x8000);
uint32_t pCR3;
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
this->PD->select();
// We also need to initialise ESP and the stack
uint32_t* stack32 = ((uint32_t)this->stack + 0x8000);
printf("stack32: %x\n", stack32);
stack32--;
*stack32 = 0x0; // EFLAGS
stack32--;
*stack32 = 8; // CS 0x08
stack32--;
*stack32 = 0x14; // Execution will begin from 0x14
stack32--;
*stack32 = ((uint32_t)this->stack + 0x8000); // EBP
stack32 -= 11;
stack32--;
*stack32 = 0; // EAX
stack32--;
*stack32 = 0; // ECX
stack32--;
*stack32 = 0; // EDX
stack32--;
*stack32 = 0; // EBX
stack32--;
*stack32 = 0; // ESP
stack32--;
*stack32 = (uint32_t)this->stack + 0x7ffc; // EBP
stack32--;
*stack32 = 0; // ESI
stack32--;
*stack32 = 0; // EDI
this->esp = stack32;
printf("this->esp: %x\n", stack32);
/*((uint8_t*)this->stack)[0] = 0xe9;
((uint8_t*)this->stack)[1] = 0xfb;
((uint8_t*)this->stack)[2] = 0xff;
((uint8_t*)this->stack)[3] = 0xff;
((uint8_t*)this->stack)[4] = 0xff;*/
((uint8_t*)this->stack)[0] = 0xcd;
((uint8_t*)this->stack)[1] = 0x80;
asm ("mov %0, %%cr3" : : "r" (pCR3));
}
void* Process::allocate(uint32_t size) {
bool switched_PD = false;
uint32_t pCR3;
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
if (Global::currentProc != this) {
switched_PD = true;
this->PD->select();
}
void* ptr;
// Determine if there's enough space to just allocate what's been requested
if (size < this->page_remaining) {
@ -46,7 +115,7 @@ void* Process::allocate(uint32_t size) {
uint32_t pages = size / 4096;
uint32_t remainder = 4096 - (size % 4096);
ptr = Allocator::allocate(size);
ptr = this->Allocator::allocate(size);
// Update local values
this->last_page_pointer = ptr + pages * 4096;
@ -61,6 +130,9 @@ void* Process::allocate(uint32_t size) {
ptr += elem_size;
}
asm ("mov %0, %%cr3" : : "r" (pCR3));
return ptr;
}
@ -68,7 +140,7 @@ void Process::deallocate(uint32_t virt_addr) {
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> alloc_tracker = this->get_alloc_tracker(virt_addr);
if (alloc_tracker.is_ok()) {
AllocTracker* ac = &alloc_tracker.get()->elem;
ac->alloc_count -= 1;
ac->alloc_count--;
if (ac->alloc_count == 0) {
void* base = ac->page_base;
uint32_t count = ac->page_size;

View File

@ -32,8 +32,11 @@ private:
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
public:
uint32_t esp;
Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
Process(uint32_t PID);
Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase);
void* allocate(uint32_t size) override;
void deallocate(uint32_t virt_addr) override;