Move to own ISR solution rather than using GCC ISRs. Lots of changes to accomodate that.

This commit is contained in:
Xnoe 2021-12-17 14:00:52 +00:00
parent aba8a0a8c9
commit 2825c1ff5e
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
19 changed files with 272 additions and 124 deletions

3
.gitignore vendored
View File

@ -4,4 +4,5 @@
*.sector
*.o
img.d/
build/
build/
isr.S

View File

@ -5,6 +5,7 @@ int main() {
uint32_t PID = getPID();
char intbuffer[32];
uint32_t index = int_to_decimal(PID, intbuffer);
uint32_t x = *(uint32_t*)0xdeadbeef;
while (1) {
counter++;
if (counter == 312500) {

View File

@ -1,14 +1,14 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
OUTPUT(build/program/hello.bin)
OUTPUT(build/hello/hello.bin)
SECTIONS {
. = 0x8020;
.text : {
build/program_code_entry.o(.text)
build/program/hello.o(.text)
build/hello/hello.o(.text)
build/common/common.o(.text)
}
}

25
src/kernel/gen_isr_asm.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env zsh
test -f isr.S && rm isr.S
cp isr.S.base isr.S
for i ({0..255}); do
cat >> isr.S << EOF
isr$i:
push ebp
mov ebp, esp
push $i
jmp catchall
EOF
done
x=""
for i ({0..255}); do
if [ $i = 255 ]; then
x="$x isr$i"
else
x="$x isr$i,"
fi
done
echo "isrs dd $x" >> isr.S

View File

@ -5,6 +5,7 @@ namespace Global {
Kernel* kernel = 0;
Process* currentProc = 0;
tss_struct* tss = 0;
bool currentProcValid = true;
}
void* operator new (uint32_t size) {

View File

@ -13,6 +13,7 @@ namespace Global {
extern Kernel* kernel;
extern Process* currentProc;
extern tss_struct* tss;
extern bool currentProcValid;
}
void* operator new (uint32_t size);

View File

@ -2,7 +2,11 @@
GateEntry idt[256];
void set_entry(uint8_t interrupt_number, uint16_t code_segment, void* handler, uint8_t type, uint8_t privilege) {
void(*gates[256])(frame_struct*);
extern void(*isrs[256])(void);
void set_entry(uint8_t interrupt_number, uint16_t code_segment, void(*handler)(), uint8_t type, uint8_t privilege) {
uint32_t handler_addr = (uint32_t)handler;
uint16_t* handler_halves = (uint16_t*)&handler_addr;
idt[interrupt_number] = (GateEntry) {
@ -17,28 +21,41 @@ void set_entry(uint8_t interrupt_number, uint16_t code_segment, void* handler, u
};
}
__attribute__((interrupt)) void interrupt_20(interrupt_frame* frame) {
// printf("Interrupt 20 received!!\n");
outb(0x20, 0x20);
}
__attribute__((interrupt)) void page_fault(interrupt_frame* frame, uint32_t err_code) {
void page_fault(frame_struct* frame, uint32_t err_code) {
uint32_t problem_address;
asm("mov %%cr2, %0" : "=a" (problem_address) :);
printf("(EIP %x): Page Fault at %x\n", frame->eip, problem_address);
while (1) asm("hlt");
Global::kernel->terminal->printf("(EIP %x): Page Fault at %x\n", frame->eip, problem_address);
if (frame->cs & 3 == 0) {
Global::kernel->terminal->printf("[FATAL] Kernel Page Fault!!!\n");
while (1) asm("hlt");
} else {
// Print an error message.
Global::kernel->terminal->printf("PID %d Terminated due to page fault!\n", Global::currentProc->PID);
// We are currently in the kernel stack for the current process so we need to load the main kernel stack in to esp.
//Global::kernel->loadPrimaryStack();
asm volatile ("mov %0, %%esp" ::"m"(Global::kernel->stack));
// We can now safely delete the current process
Global::kernel->destroyProcess(Global::currentProc);
// We want to load the kernel's page directory too.
//Global::kernel->PD->select();
//Global::currentProcValid = false;
asm ("int $0x20"); // Call context switch.
while (1) asm("hlt");
}
}
__attribute__((interrupt)) void ignore_interrupt(interrupt_frame* frame) {
outb(0x20, 0x20);
}
void ignore_interrupt(frame_struct* frame) {}
__attribute__((interrupt)) void gpf(interrupt_frame* frame, uint32_t err_code) {
void gpf(frame_struct* frame, uint32_t err_code) {
printf("General Protection Fault %x\n", err_code);
while (1) asm("hlt");
}
__attribute__((interrupt)) void context_switch(interrupt_frame* frame) {
void context_switch(frame_struct* frame) {
// When any interrupt occurs (including context_switch), SS:ESP is set to
// the values of SS0:ESP0 in Global::tss
//
@ -53,80 +70,86 @@ __attribute__((interrupt)) void context_switch(interrupt_frame* frame) {
// to iret
asm ("cli"); // Disable interrupts whilst handling the context switch.
asm ("pusha"); // Push registers to the stack
//asm ("pushf"); // Push flags to the stack
Process* currentProc = Global::currentProc;
// Restore eax
asm ("mov %0, %%eax"::"r"(frame->eax));
Process* currentProc = 0;
Process* nextProc = 0;
// Write current esp to currentProc->kernelStackPtr
asm ("mov %%esp, %0" : "=a" (currentProc->kernelStackPtr):);
if (Global::currentProcValid) {
currentProc = Global::currentProc;
// Write current esp to currentProc->kernelStackPtr
asm ("mov %%esp, %0" : "=a" (currentProc->kernelStackPtr):);
}
if (currentProc) {
if (currentProc || !Global::currentProcValid) {
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, add the start to the end then set start to the second element
if (processes->start->next != 0) {
if (processes->end->prev == processes->start) {
xnoe::linkedlistelem<Process*>* tmp = processes->start;
processes->start = processes->end;
processes->end = tmp;
if (processes->start) {
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 {
processes->end->next = processes->start;
processes->start = processes->start->next;
processes->start->prev = 0;
xnoe::linkedlistelem<Process*>* tmp = processes->end;
processes->end = processes->end->next;
processes->end->next = 0;
processes->end->prev = tmp;
processes->start->prev = 0;
processes->end->next = 0;
processes->end->prev = processes->start;
processes->start->next = processes->end;
} else {
processes->end->next = processes->start;
processes->start = processes->start->next;
processes->start->prev = 0;
xnoe::linkedlistelem<Process*>* tmp = processes->end;
processes->end = processes->end->next;
processes->end->next = 0;
processes->end->prev = tmp;
}
}
}
// Get the next process.
nextProc = processes->start->elem;
if (processes->start)
nextProc = processes->start->elem;
if (nextProc == 0) {
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
while (1) asm ("hlt");
}
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.
outb(0x20, 0x20);
// Select the next processes page directory
asm volatile ("mov %0, %%cr3" : : "r" (nextProc->PD->phys_addr));
// Restore kernelStackPtr of the new process.
asm volatile ("mov %0, %%esp" : : "m" (Global::kernel->processes.start->elem->kernelStackPtr));
// At this point interrupts are disabled till iret so we can safely set
// Global::tss->esp0
// to the new Process's kernelStackPtrDefault
// Global::tss->esp0 to the new Process's kernelStackPtrDefault
Global::tss->esp0 = Global::kernel->processes.start->elem->kernelStackPtrDefault;
//asm ("popf"); // Pop flags
asm ("popa"); // Restore registers
asm ("mov -0xc(%ebp), %eax"); // Restore the initial eax
// Clear the garbage that was on the stack from previous switch_context call.
asm ("mov %ebp, %esp");
asm ("pop %ebp"); // Pop EBP
// Set the current proc to valid
Global::currentProcValid = true;
asm ("iret"); // Manually perform iret.
uint32_t* espVal;
asm ("mov %%esp, %0":"=a"(espVal):);
if (*espVal == 0) {
asm("add $4, %esp");
asm("ret");
}
}
}
extern uint8_t current_scancode;
extern char decoded;
__attribute__((interrupt)) void syscall(interrupt_frame* frame) {
void syscall(frame_struct* frame) {
// Syscall ABI:
// 0: print: Print null terminated string (in esi: char*)
// 1: getch: Get current keyboard character ASCII (out eax: char)
@ -138,17 +161,11 @@ __attribute__((interrupt)) void syscall(interrupt_frame* frame) {
// 7: fork: create process from filename (in esi: char* filename)
// 8: getPID: returns the current process's PID (out eax: uint32_t)
uint32_t* ebp;
asm("mov %%ebp, %0" : "=a" (ebp) :);
uint32_t eax = *(ebp-4);
uint32_t rval = eax;
uint32_t rval = frame->eax;
uint32_t syscall_number;
uint32_t esi;
uint32_t edi;
asm("mov %%esi, %0" : "=a" (esi) :);
asm("mov %%edi, %0" : "=a" (edi) :);
switch (eax) {
uint32_t esi = frame->esi;
uint32_t edi = frame->edi;
switch (frame->eax) {
case 0:
Global::kernel->terminal->printf("%s", (char*)esi);
break;
@ -181,22 +198,25 @@ __attribute__((interrupt)) void syscall(interrupt_frame* frame) {
break;
}
asm volatile ("mov %0, %%eax" : : "m" (rval));
asm ("mov %ebp, %esp");
asm ("pop %ebp");
asm ("iret");
frame->eax = rval;
}
void init_idt() {
idt_desc desc = {.size = 256 * sizeof(GateEntry) - 1, .offset = (uint32_t)idt};
asm volatile("lidt %0" : : "m" (desc));
for (int i=0; i<256; i++)
set_entry(i, 0x08, &ignore_interrupt, 0x8E);
set_entry(i, 0x08, isrs[i], 0xE);
for (int i=0; i<256; i++)
gates[i] = &ignore_interrupt;
set_entry(0x20, 0x08, &context_switch, 0xE);
set_entry(0xD, 0x08, &gpf, 0xE);
set_entry(0xE, 0x08, &page_fault, 0xE);
set_entry(0x7f, 0x08, &syscall, 0xE, 3);
gates[0x20] = &context_switch;
gates[0xd] = &gpf;
gates[0xe] = &page_fault;
gates[0x7f] = &syscall;
idt[0x7f].privilege = 3;
outb(0x20, 0x11);
outb(0xA0, 0x11);

View File

@ -7,14 +7,28 @@
#include "kernel.h"
#include "gdt.h"
struct interrupt_frame {
uint32_t eip;
uint16_t cs;
uint16_t _ignored0;
uint32_t eflags;
struct __attribute__((packed)) frame_struct {
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t oesp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t eip;
uint16_t cs;
uint16_t _ignored0;
uint32_t eflags;
uint16_t ss;
uint16_t _ignored1;
uint32_t esp;
};
extern void(*gates[256])(frame_struct*);
extern void load_idt();
void set_entry(uint8_t interrupt_number, uint16_t code_segment, void* handler, uint8_t type, uint8_t privilege = 0);
void set_entry(uint8_t interrupt_number, uint16_t code_segment, void(*handler)(), uint8_t type, uint8_t privilege = 0);
void init_idt();
void enable_idt();
@ -27,11 +41,11 @@ struct __attribute__((packed)) GateEntry{
uint8_t privilege : 2;
uint8_t present : 1;
uint16_t offset_high;
} ;
};
struct __attribute__((packed)) idt_desc {
uint16_t size;
uint32_t offset;
} ;
};
#endif

View File

@ -1,19 +1,21 @@
#include "io.h"
void outb(uint16_t portnumber, uint8_t data) {
asm volatile("outb %0, %1" : : "a" (data), "Nd" (portnumber));
}
uint8_t inb(uint16_t portnumber) {
uint8_t result;
asm volatile("inb %1, %0" : "=a" (result) : "Nd" (portnumber));
return result;
}
extern "C" {
void outb(uint16_t portnumber, uint8_t data) {
asm volatile("outb %0, %1" : : "a" (data), "Nd" (portnumber));
}
uint8_t inb(uint16_t portnumber) {
uint8_t result;
asm volatile("inb %1, %0" : "=a" (result) : "Nd" (portnumber));
return result;
}
void outw(uint16_t portnumber, uint16_t data) {
asm volatile("outw %0, %1" : : "a" (data), "Nd" (portnumber));
}
uint16_t inw(uint16_t portnumber) {
uint16_t result;
asm volatile("inw %1, %0" : "=a" (result) : "Nd" (portnumber));
return result;
void outw(uint16_t portnumber, uint16_t data) {
asm volatile("outw %0, %1" : : "a" (data), "Nd" (portnumber));
}
uint16_t inw(uint16_t portnumber) {
uint16_t result;
asm volatile("inw %1, %0" : "=a" (result) : "Nd" (portnumber));
return result;
}
}

View File

@ -3,10 +3,12 @@
#include "types.h"
void outb(uint16_t portnumber, uint8_t data);
uint8_t inb(uint16_t portnumber);
extern "C" {
void outb(uint16_t portnumber, uint8_t data);
uint8_t inb(uint16_t portnumber);
void outw(uint16_t portnumber, uint16_t data);
uint16_t inw(uint16_t portnumber);
void outw(uint16_t portnumber, uint16_t data);
uint16_t inw(uint16_t portnumber);
}
#endif

52
src/kernel/isr.S.base Normal file
View File

@ -0,0 +1,52 @@
[BITS 32]
global isrs
global catchall_return
catchall: ; At this point the gate number has been pushed to the stack
pushad ; Pushed 32 bytes
mov eax, [esp+32]
mov ebx, gates
mov eax, [ebx+4*eax]
push esp
call eax
catchall_return:
add esp, 4
push 0x20
push 0x20
call outb
add esp, 8
popad
mov esp, ebp
pop ebp
iret
extern gates ; (void(*)(frame_struct))*
extern outb
; struct frame_struct __attribute__((packed)) {
; popad
; uint32_t edi;
; uint32_t esi;
; uint32_t ebp;
; uint32_t esp;
; uint32_t ebx;
; uint32_t edx;
; uint32_t ecx;
; uint32_t eax;
;
; interrupt
; uint32_t eip;
; uint32_t cs;
; uint32_t eflags;
; uint32_t esp;
; uint32_t ss;
;
; if it's an error
; uint32_t err_code;
; }

View File

@ -1,6 +1,6 @@
#include "kernel.h"
Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base)
Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack)
: Process(0, 0x8a000, page_directory, phys, virt, virt_alloc_base)
{
this->currentPID = 1;
@ -9,6 +9,8 @@ Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint
Global::currentProc = 0;
this->stack = stack;
//this->processes.append(this);
}
@ -30,5 +32,8 @@ void Kernel::destroyProcess(Process* p) {
this->processes.remove(p);
this->pid_map->remove(p->PID, p);
delete p;
while (1);
}
}
//void Kernel::loadPrimaryStack() {
// asm volatile("mov %0, %%esp"::"m"(this->stack - 64));
//}

View File

@ -9,18 +9,20 @@
class Kernel : public Process {
public:
uint32_t currentPID;
uint32_t stack;
Terminal* terminal;
xnoe::hashtable<uint32_t, Process*>* pid_map; // Map of PIDs -> Process*s
xnoe::linkedlist<Process*> processes;
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack);
void init_kernel();
Process* createProcess(char* filename);
void destroyProcess(Process* p);
//void loadPrimaryStack();
};
#endif

View File

@ -36,7 +36,7 @@ char decoded = 0;
bool caps_on = false;
bool shift_on = false;
__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame* frame) {
void keyboard_interrupt(frame_struct* frame) {
current_scancode = inb(0x60);
outb(0x20, 0x21);
if ((current_scancode&0x7f) == 0x2a)
@ -54,7 +54,8 @@ __attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame* frame
}
void init_keyboard() {
set_entry(0x21, 0x08, &keyboard_interrupt, 0x8E);
//set_entry(0x21, 0x08, &keyboard_interrupt, 0x8E);
gates[0x21] = &keyboard_interrupt;
while (inb(0x64) & 1) {
inb(0x60);

View File

@ -27,7 +27,7 @@ int main() {
PageMap phys_pm(0xc0600000);
PageMap virt_pm(0xc0620000);
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000);
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, 0xc1006000);
kernel.init_kernel();
init_atapio();
@ -47,6 +47,7 @@ int main() {
Global::currentProc = &kernel;
Process* p1 = kernel.createProcess("WORLD BIN");
kernel.createProcess("HELLO BIN");
init_keyboard();

View File

@ -1,5 +1,7 @@
#include "process.h"
extern void(*catchall_return)();
AllocTracker::AllocTracker(void* base, uint32_t size, uint32_t count) : page_base(base), page_size(size), alloc_count(count) {}
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> Process::get_alloc_tracker(uint32_t address) {
@ -68,8 +70,6 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, cha
uint32_t rEBP = stack32;
stack32 -= 21;
stack32--;
*stack32 = 0; // EAX
stack32--;
@ -87,6 +87,13 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, cha
stack32--;
*stack32 = 0; // EDI
stack32--;
stack32--;
*stack32 = &catchall_return; // cachall_return
stack32--;
this->kernelStackPtr = stack32;
load_file(filename, program_data);

View File

@ -58,6 +58,20 @@ void Terminal::printf(const char* string, ...) {
this->cur_y++;
}
if (current == '\b') {
if (this->cur_x > 0) {
this->cur_x--;
} else {
this->cur_y--;
this->cur_x = this->width-1;
}
int mem_pos = this->cur_y * this->width + this->cur_x;
this->putchar(mem_pos, ' ');
continue;
}
if (this->cur_x == this->width) {
this->cur_x = 0;
this->cur_y++;

View File

@ -2,7 +2,7 @@
#include <stdbool.h>
char key_to_char[128] = {
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 0,
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', 0,
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0,
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\',
'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0,
@ -12,7 +12,7 @@ char key_to_char[128] = {
};
char key_to_char_caps[128] = {
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 0,
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', 0,
0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', 0, '\\',
'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0,
@ -22,7 +22,7 @@ char key_to_char_caps[128] = {
};
char key_to_char_shift[128] = {
0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 0,
0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0,
0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0, '|',
'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0,
@ -54,12 +54,6 @@ void readline(int max, char* buffer) {
if (scancode == 0x3a)
caps_on ^= 1;
/*if (scancode == 0x0e && index > 0) {
set_curpos_raw(get_curpos()-1);
non_moving_put(' ');
buffer[--index] = 0;
}*/
if (shift_on)
decoded = key_to_char_shift[scancode&0x7f];
else if (caps_on)
@ -67,7 +61,12 @@ void readline(int max, char* buffer) {
else
decoded = key_to_char[scancode&0x7f];
if (decoded && scancode < 0x80) {
if (scancode == 0x0e) {
if (index > 0) {
buffer[--index] = 0;
print("\b");
}
} else if (decoded && scancode < 0x80) {
buffer[index++] = decoded;
char_print[0] = decoded;
print(char_print);

View File

@ -1,14 +1,14 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
OUTPUT(build/program/world.bin)
OUTPUT(build/world/world.bin)
SECTIONS {
. = 0x8020;
.text : {
build/program_code_entry.o(.text)
build/program/world.o(.text)
build/world/world.o(.text)
build/common/common.o(.text)
}
}