Updated kernel to now have its stack past 0xc0000000. Implemented context switching.
This commit is contained in:
parent
2dd799b406
commit
ed67adc9c9
@ -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);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
[BITS 32]
|
||||
|
||||
_start:
|
||||
mov esp, 0xc1005ffc
|
||||
jmp main
|
||||
|
||||
extern main
|
@ -3,6 +3,7 @@
|
||||
namespace Global {
|
||||
Allocator* allocator = 0;
|
||||
Kernel* kernel = 0;
|
||||
Process* currentProc = 0;
|
||||
}
|
||||
|
||||
void* operator new (uint32_t size) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user