mirror of
https://github.com/usatiuk/ficus.git
synced 2025-10-29 00:27:52 +01:00
A little IDT cleanup
This commit is contained in:
42
.idea/codeStyles/Project.xml
generated
42
.idea/codeStyles/Project.xml
generated
@@ -6,6 +6,48 @@
|
||||
<fileSet type="globPattern" pattern="stl/*" />
|
||||
</list>
|
||||
</option>
|
||||
<Objective-C-extensions>
|
||||
<rules>
|
||||
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="PUBLIC" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="CONST" prefix="k" style="PASCAL_CASE" suffix="" />
|
||||
</rules>
|
||||
</Objective-C-extensions>
|
||||
<Objective-C-extensions>
|
||||
<rules>
|
||||
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="PUBLIC" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="CONST" prefix="k" style="PASCAL_CASE" suffix="" />
|
||||
</rules>
|
||||
</Objective-C-extensions>
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
</clangFormatSettings>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,7 @@ SerialTty::SerialTty() : Tty() {
|
||||
task->start();
|
||||
|
||||
attach_interrupt(4, &SerialTty::isr, this);
|
||||
IRQ_clear_mask(4);
|
||||
Arch::IDT::IRQ_clear_mask(4);
|
||||
}
|
||||
void SerialTty::isr(void *tty) {
|
||||
((SerialTty *) tty)->this_isr();
|
||||
|
||||
@@ -40,7 +40,7 @@ extern "C" __attribute__((unused)) void _start(void) {
|
||||
barrier();
|
||||
Arch::GDT::gdt_setup();
|
||||
barrier();
|
||||
idt_init();
|
||||
Arch::IDT::idt_init();
|
||||
barrier();
|
||||
init_serial();
|
||||
barrier();
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Arch::GDT {
|
||||
unsigned int base_high : 8;
|
||||
|
||||
//
|
||||
uint64_t selector() volatile;
|
||||
[[nodiscard]] uint64_t selector() const volatile;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct gdt_tss_entry_bits {
|
||||
@@ -81,7 +81,7 @@ namespace Arch::GDT {
|
||||
} __attribute__((packed)) gdtr;
|
||||
}
|
||||
|
||||
inline uint64_t gdt_entry_bits::selector() volatile {
|
||||
inline uint64_t gdt_entry_bits::selector() const volatile {
|
||||
return (((uint64_t) this) - ((uint64_t) &gdt_null));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,15 @@
|
||||
#ifndef OS1_GLOBALS_H
|
||||
#define OS1_GLOBALS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define KERN_STACK_SIZE (1024 * 1024)
|
||||
extern uint64_t KERN_stack[KERN_STACK_SIZE] __attribute__((aligned(16)));
|
||||
|
||||
class AddressSpace;
|
||||
|
||||
extern AddressSpace *BOOT_AddressSpace;
|
||||
extern AddressSpace *KERN_AddressSpace;
|
||||
|
||||
|
||||
#define TASK_POINTER 0x10000
|
||||
|
||||
#endif //OS1_GLOBALS_H
|
||||
|
||||
@@ -5,7 +5,18 @@
|
||||
|
||||
#include "task.hpp"
|
||||
|
||||
extern "C" __attribute__((noreturn)) void exception_handler(void) {
|
||||
extern "C" __attribute__((noreturn)) void exception_handler_err(uint64_t code) {
|
||||
//FIXME:
|
||||
if (Scheduler::cur_task()->_mode == Task::TaskMode::TASKMODE_USER) {
|
||||
writestr_no_yield("Task ded");
|
||||
Scheduler::cur_task()->_state = Task::TaskState::TS_BLOCKED;
|
||||
_yield_self_kern();
|
||||
} else {
|
||||
writestr_no_yield("Kernel ded");
|
||||
_hcf();
|
||||
}
|
||||
}
|
||||
extern "C" __attribute__((noreturn)) void exception_handler_no_err(void) {
|
||||
//FIXME:
|
||||
if (Scheduler::cur_task()->_mode == Task::TaskMode::TASKMODE_USER) {
|
||||
writestr_no_yield("Task ded");
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
|
||||
%include "task.inc.asm"
|
||||
|
||||
extern exception_handler_err
|
||||
extern exception_handler_no_err
|
||||
|
||||
section .text
|
||||
%macro isr_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
pop rdi ; Keep the stacktrace
|
||||
call exception_handler
|
||||
call exception_handler_err
|
||||
iretq
|
||||
%endmacro
|
||||
|
||||
%macro isr_no_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
call exception_handler
|
||||
call exception_handler_no_err
|
||||
iretq
|
||||
%endmacro
|
||||
|
||||
extern exception_handler
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
|
||||
@@ -5,229 +5,237 @@
|
||||
#include "io.hpp"
|
||||
#include "misc.hpp"
|
||||
#include "task.hpp"
|
||||
#include "task_arch.hpp"
|
||||
#include "timer.hpp"
|
||||
|
||||
__attribute__((aligned(0x10))) static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
|
||||
static idtr_t idtr;
|
||||
namespace Arch::IDT {
|
||||
|
||||
extern "C" void pic1_irq_0();
|
||||
extern "C" void pic1_irq_1();
|
||||
extern "C" void pic1_irq_2();
|
||||
extern "C" void pic1_irq_3();
|
||||
extern "C" void pic1_irq_4();
|
||||
extern "C" void pic1_irq_5();
|
||||
extern "C" void pic1_irq_6();
|
||||
extern "C" void pic1_irq_7();
|
||||
__attribute__((aligned(0x10))) static IdtEntry idt[256]; // Create an array of IDT entries; aligned for performance
|
||||
|
||||
extern "C" void pic2_irq_0();
|
||||
extern "C" void pic2_irq_1();
|
||||
extern "C" void pic2_irq_2();
|
||||
extern "C" void pic2_irq_3();
|
||||
extern "C" void pic2_irq_4();
|
||||
extern "C" void pic2_irq_5();
|
||||
extern "C" void pic2_irq_6();
|
||||
extern "C" void pic2_irq_7();
|
||||
//
|
||||
static Idtr idtr;
|
||||
|
||||
extern "C" void pic1_irq_0();
|
||||
extern "C" void pic1_irq_1();
|
||||
extern "C" void pic1_irq_2();
|
||||
extern "C" void pic1_irq_3();
|
||||
extern "C" void pic1_irq_4();
|
||||
extern "C" void pic1_irq_5();
|
||||
extern "C" void pic1_irq_6();
|
||||
extern "C" void pic1_irq_7();
|
||||
|
||||
extern "C" void pic2_irq_0();
|
||||
extern "C" void pic2_irq_1();
|
||||
extern "C" void pic2_irq_2();
|
||||
extern "C" void pic2_irq_3();
|
||||
extern "C" void pic2_irq_4();
|
||||
extern "C" void pic2_irq_5();
|
||||
extern "C" void pic2_irq_6();
|
||||
extern "C" void pic2_irq_7();
|
||||
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void (*isr)(), uint8_t flags) {
|
||||
idt_entry_t *descriptor = &idt[vector];
|
||||
void idt_set_descriptor(uint8_t vector, void (*isr)(), uint8_t flags) {
|
||||
IdtEntry *descriptor = &idt[vector];
|
||||
|
||||
descriptor->isr_low = (uint64_t) isr & 0xFFFF;
|
||||
descriptor->kernel_cs = Arch::GDT::gdt_code.selector();
|
||||
descriptor->ist = 0;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->isr_mid = ((uint64_t) isr >> 16) & 0xFFFF;
|
||||
descriptor->isr_high = ((uint64_t) isr >> 32) & 0xFFFFFFFF;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
void idt_init() {
|
||||
idtr.base = (uintptr_t) &idt[0];
|
||||
idtr.limit = (uint16_t) ((uint64_t) &idt[255] - (uint64_t) &idt[0]);
|
||||
|
||||
for (uint8_t vector = 0; vector < 32; vector++) {
|
||||
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
||||
descriptor->isr_low = (uint64_t) isr & 0xFFFF;
|
||||
descriptor->kernel_cs = Arch::GDT::gdt_code.selector();
|
||||
descriptor->ist = 0;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->isr_mid = ((uint64_t) isr >> 16) & 0xFFFF;
|
||||
descriptor->isr_high = ((uint64_t) isr >> 32) & 0xFFFFFFFF;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
idt_set_descriptor(PIC1_OFFSET + 0, pic1_irq_0, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 1, pic1_irq_1, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 2, pic1_irq_2, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 3, pic1_irq_3, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 4, pic1_irq_4, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 5, pic1_irq_5, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 6, pic1_irq_6, 0x8e);
|
||||
idt_set_descriptor(PIC1_OFFSET + 7, pic1_irq_7, 0x8e);
|
||||
void idt_init() {
|
||||
idtr.base = (uintptr_t) &idt[0];
|
||||
idtr.limit = (uint16_t) ((uint64_t) &idt[255] - (uint64_t) &idt[0]);
|
||||
|
||||
idt_set_descriptor(PIC2_OFFSET + 0, pic2_irq_0, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 1, pic2_irq_1, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 2, pic2_irq_2, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 3, pic2_irq_3, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 4, pic2_irq_4, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 5, pic2_irq_5, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 6, pic2_irq_6, 0x8e);
|
||||
idt_set_descriptor(PIC2_OFFSET + 7, pic2_irq_7, 0x8e);
|
||||
for (uint8_t vector = 0; vector < 32; vector++) {
|
||||
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
||||
}
|
||||
|
||||
barrier();
|
||||
__asm__ volatile("lidt %0"
|
||||
:
|
||||
: "m"(idtr)); // load the new IDT
|
||||
__asm__ volatile("sti"); // set the interrupt flag
|
||||
barrier();
|
||||
idt_set_descriptor(kPIC1_OFFSET + 0, pic1_irq_0, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 1, pic1_irq_1, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 2, pic1_irq_2, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 3, pic1_irq_3, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 4, pic1_irq_4, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 5, pic1_irq_5, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 6, pic1_irq_6, 0x8e);
|
||||
idt_set_descriptor(kPIC1_OFFSET + 7, pic1_irq_7, 0x8e);
|
||||
|
||||
PIC_init();
|
||||
}
|
||||
idt_set_descriptor(kPIC2_OFFSET + 0, pic2_irq_0, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 1, pic2_irq_1, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 2, pic2_irq_2, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 3, pic2_irq_3, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 4, pic2_irq_4, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 5, pic2_irq_5, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 6, pic2_irq_6, 0x8e);
|
||||
idt_set_descriptor(kPIC2_OFFSET + 7, pic2_irq_7, 0x8e);
|
||||
|
||||
void PIC_sendEOI(unsigned char irq) {
|
||||
if (irq >= 8)
|
||||
outb(PIC2_COMMAND, PIC_EOI);
|
||||
barrier();
|
||||
__asm__ volatile("lidt %0"
|
||||
:
|
||||
: "m"(idtr)); // load the new IDT
|
||||
__asm__ volatile("sti"); // set the interrupt flag
|
||||
barrier();
|
||||
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
void PIC_init() {
|
||||
unsigned char a1, a2;
|
||||
|
||||
a1 = inb(PIC1_DATA); // save masks
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode)
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, PIC1_OFFSET); // ICW2: Master PIC vector offset
|
||||
io_wait();
|
||||
outb(PIC2_DATA, PIC2_OFFSET); // ICW2: Slave PIC vector offset
|
||||
io_wait();
|
||||
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, ICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode)
|
||||
io_wait();
|
||||
outb(PIC2_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, a1); // restore saved masks.
|
||||
outb(PIC2_DATA, a2);
|
||||
}
|
||||
void IRQ_set_mask(unsigned char IRQline) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (IRQline < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
IRQline -= 8;
|
||||
PIC_init();
|
||||
}
|
||||
value = inb(port) | (1 << IRQline);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void IRQ_clear_mask(unsigned char IRQline) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
void PIC_sendEOI(unsigned char irq) {
|
||||
if (irq >= 8)
|
||||
outb(kPIC2_COMMAND, kPIC_EOI);
|
||||
|
||||
if (IRQline < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
IRQline -= 8;
|
||||
outb(kPIC1_COMMAND, kPIC_EOI);
|
||||
}
|
||||
|
||||
void PIC_init() {
|
||||
unsigned char a1, a2;
|
||||
|
||||
a1 = inb(kPIC1_DATA); // save masks
|
||||
a2 = inb(kPIC2_DATA);
|
||||
|
||||
outb(kPIC1_COMMAND, kICW1_INIT | kICW1_ICW4); // starts the initialization sequence (in cascade mode)
|
||||
io_wait();
|
||||
outb(kPIC2_COMMAND, kICW1_INIT | kICW1_ICW4);
|
||||
io_wait();
|
||||
outb(kPIC1_DATA, kPIC1_OFFSET); // ICW2: Master PIC vector offset
|
||||
io_wait();
|
||||
outb(kPIC2_DATA, kPIC2_OFFSET); // ICW2: Slave PIC vector offset
|
||||
io_wait();
|
||||
outb(kPIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
||||
io_wait();
|
||||
outb(kPIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
|
||||
io_wait();
|
||||
|
||||
outb(kPIC1_DATA, kICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode)
|
||||
io_wait();
|
||||
outb(kPIC2_DATA, kICW4_8086);
|
||||
io_wait();
|
||||
|
||||
outb(kPIC1_DATA, a1); // restore saved masks.
|
||||
outb(kPIC2_DATA, a2);
|
||||
}
|
||||
void IRQ_set_mask(unsigned char IRQline) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (IRQline < 8) {
|
||||
port = kPIC1_DATA;
|
||||
} else {
|
||||
port = kPIC2_DATA;
|
||||
IRQline -= 8;
|
||||
}
|
||||
value = inb(port) | (1 << IRQline);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void IRQ_clear_mask(unsigned char IRQline) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (IRQline < 8) {
|
||||
port = kPIC1_DATA;
|
||||
} else {
|
||||
port = kPIC2_DATA;
|
||||
IRQline -= 8;
|
||||
}
|
||||
value = inb(port) & ~(1 << IRQline);
|
||||
outb(port, value);
|
||||
}
|
||||
value = inb(port) & ~(1 << IRQline);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
|
||||
/* Helper func */
|
||||
static uint16_t __pic_get_irq_reg(int ocw3) {
|
||||
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||
/* Helper func */
|
||||
static uint16_t __pic_get_irq_reg(int ocw3) {
|
||||
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||
* represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
||||
outb(PIC1_COMMAND, ocw3);
|
||||
outb(PIC2_COMMAND, ocw3);
|
||||
return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs irq request register */
|
||||
uint16_t pic_get_irr(void) {
|
||||
return __pic_get_irq_reg(PIC_READ_IRR);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs in-service register */
|
||||
uint16_t pic_get_isr(void) {
|
||||
return __pic_get_irq_reg(PIC_READ_ISR);
|
||||
}
|
||||
|
||||
static int_handler_t handlers[256];
|
||||
static void *handlers_args[256];
|
||||
|
||||
extern "C" void pic1_irq_real_0(TaskFrame *frame) {
|
||||
timer_tick();
|
||||
Scheduler::switch_task(frame);
|
||||
PIC_sendEOI(0);
|
||||
}
|
||||
extern "C" void pic1_irq_real_1() {
|
||||
PIC_sendEOI(1);
|
||||
}
|
||||
extern "C" void pic1_irq_real_2() {
|
||||
_hcf();
|
||||
PIC_sendEOI(2);
|
||||
}
|
||||
extern "C" void pic1_irq_real_3() {
|
||||
PIC_sendEOI(3);
|
||||
}
|
||||
extern "C" void pic1_irq_real_4() {
|
||||
if (handlers[4] != nullptr) {
|
||||
handlers[4](handlers_args[4]);
|
||||
}
|
||||
PIC_sendEOI(4);
|
||||
}
|
||||
extern "C" void pic1_irq_real_5() {
|
||||
PIC_sendEOI(5);
|
||||
}
|
||||
extern "C" void pic1_irq_real_6() {
|
||||
PIC_sendEOI(6);
|
||||
}
|
||||
extern "C" void pic1_irq_real_7() {
|
||||
int irr = pic_get_irr();
|
||||
if (!(irr & 0x80)) return;
|
||||
PIC_sendEOI(7);
|
||||
}
|
||||
|
||||
extern "C" void pic2_irq_real_0() {
|
||||
PIC_sendEOI(8);
|
||||
}
|
||||
extern "C" void pic2_irq_real_1() {
|
||||
PIC_sendEOI(9);
|
||||
}
|
||||
extern "C" void pic2_irq_real_2() {
|
||||
PIC_sendEOI(10);
|
||||
}
|
||||
extern "C" void pic2_irq_real_3() {
|
||||
PIC_sendEOI(11);
|
||||
}
|
||||
extern "C" void pic2_irq_real_4() {
|
||||
PIC_sendEOI(12);
|
||||
}
|
||||
extern "C" void pic2_irq_real_5() {
|
||||
PIC_sendEOI(13);
|
||||
}
|
||||
extern "C" void pic2_irq_real_6() {
|
||||
PIC_sendEOI(14);
|
||||
}
|
||||
extern "C" void pic2_irq_real_7() {
|
||||
// Probaby wrong
|
||||
int irr = pic_get_irr();
|
||||
if (!(irr & (0x80 << 8))) {
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
return;
|
||||
outb(kPIC1_COMMAND, ocw3);
|
||||
outb(kPIC2_COMMAND, ocw3);
|
||||
return (inb(kPIC2_COMMAND) << 8) | inb(kPIC1_COMMAND);
|
||||
}
|
||||
|
||||
PIC_sendEOI(15);
|
||||
}
|
||||
/* Returns the combined value of the cascaded PICs irq request register */
|
||||
uint16_t pic_get_irr(void) {
|
||||
return __pic_get_irq_reg(kPIC_READ_IRR);
|
||||
}
|
||||
|
||||
/* Returns the combined value of the cascaded PICs in-service register */
|
||||
uint16_t pic_get_isr(void) {
|
||||
return __pic_get_irq_reg(kPIC_READ_ISR);
|
||||
}
|
||||
|
||||
static int_handler_t handlers[256];
|
||||
static void *handlers_args[256];
|
||||
|
||||
// TODO: guarantee alignment in the asm part
|
||||
extern "C" __attribute__((force_align_arg_pointer)) void pic1_irq_real_0(TaskFrame *frame) {
|
||||
timer_tick();
|
||||
Scheduler::switch_task(frame);
|
||||
PIC_sendEOI(0);
|
||||
}
|
||||
extern "C" void pic1_irq_real_1() {
|
||||
PIC_sendEOI(1);
|
||||
}
|
||||
extern "C" void pic1_irq_real_2() {
|
||||
_hcf();
|
||||
PIC_sendEOI(2);
|
||||
}
|
||||
extern "C" void pic1_irq_real_3() {
|
||||
PIC_sendEOI(3);
|
||||
}
|
||||
extern "C" __attribute__((force_align_arg_pointer)) void pic1_irq_real_4() {
|
||||
if (handlers[4] != nullptr) {
|
||||
handlers[4](handlers_args[4]);
|
||||
}
|
||||
PIC_sendEOI(4);
|
||||
}
|
||||
extern "C" void pic1_irq_real_5() {
|
||||
PIC_sendEOI(5);
|
||||
}
|
||||
extern "C" void pic1_irq_real_6() {
|
||||
PIC_sendEOI(6);
|
||||
}
|
||||
extern "C" void pic1_irq_real_7() {
|
||||
int irr = pic_get_irr();
|
||||
if (!(irr & 0x80)) return;
|
||||
PIC_sendEOI(7);
|
||||
}
|
||||
|
||||
extern "C" void pic2_irq_real_0() {
|
||||
PIC_sendEOI(8);
|
||||
}
|
||||
extern "C" void pic2_irq_real_1() {
|
||||
PIC_sendEOI(9);
|
||||
}
|
||||
extern "C" void pic2_irq_real_2() {
|
||||
PIC_sendEOI(10);
|
||||
}
|
||||
extern "C" void pic2_irq_real_3() {
|
||||
PIC_sendEOI(11);
|
||||
}
|
||||
extern "C" void pic2_irq_real_4() {
|
||||
PIC_sendEOI(12);
|
||||
}
|
||||
extern "C" void pic2_irq_real_5() {
|
||||
PIC_sendEOI(13);
|
||||
}
|
||||
extern "C" void pic2_irq_real_6() {
|
||||
PIC_sendEOI(14);
|
||||
}
|
||||
extern "C" void pic2_irq_real_7() {
|
||||
// Probaby wrong
|
||||
int irr = pic_get_irr();
|
||||
if (!(irr & (0x80 << 8))) {
|
||||
outb(kPIC1_COMMAND, kPIC_EOI);
|
||||
return;
|
||||
}
|
||||
|
||||
PIC_sendEOI(15);
|
||||
}
|
||||
|
||||
} // namespace Arch::IDT
|
||||
|
||||
void attach_interrupt(unsigned num, int_handler_t handler, void *firstarg) {
|
||||
handlers[num] = handler;
|
||||
handlers_args[num] = firstarg;
|
||||
}
|
||||
Arch::IDT::handlers[num] = handler;
|
||||
Arch::IDT::handlers_args[num] = firstarg;
|
||||
}
|
||||
|
||||
@@ -1,96 +1,68 @@
|
||||
#ifndef OS1_IDT_H
|
||||
#define OS1_IDT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#define PIC1 0x20 /* IO base address for master PIC */
|
||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
||||
#define PIC1_COMMAND PIC1
|
||||
#define PIC1_DATA (PIC1 + 1)
|
||||
#define PIC2_COMMAND PIC2
|
||||
#define PIC2_DATA (PIC2 + 1)
|
||||
#define PIC_EOI 0x20 /* End-of-interrupt command code */
|
||||
namespace Arch::IDT {
|
||||
static constexpr int kPIC1 = 0x20; /* IO base address for master PIC */
|
||||
static constexpr int kPIC2 = 0xA0; /* IO base address for slave PIC */
|
||||
static constexpr int kPIC1_COMMAND = kPIC1;
|
||||
static constexpr int kPIC1_DATA = (kPIC1 + 1);
|
||||
static constexpr int kPIC2_COMMAND = kPIC2;
|
||||
static constexpr int kPIC2_DATA = (kPIC2 + 1);
|
||||
static constexpr int kPIC_EOI = 0x20; /* End-of-interrupt command code */
|
||||
|
||||
#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
||||
static constexpr int kICW1_ICW4 = 0x01; /* Indicates that ICW4 will be present */
|
||||
static constexpr int kICW1_SINGLE = 0x02; /* Single (cascade) mode */
|
||||
static constexpr int kICW1_INTERVAL4 = 0x04; /* Call address interval 4 (8) */
|
||||
static constexpr int kICW1_LEVEL = 0x08; /* Level triggered (edge) mode */
|
||||
static constexpr int kICW1_INIT = 0x10; /* Initialization - required! */
|
||||
|
||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||
static constexpr int kICW4_8086 = 0x01; /* 8086/88 (MCS-80/85) mode */
|
||||
static constexpr int kICW4_AUTO = 0x02; /* Auto (normal) EOI */
|
||||
static constexpr int kICW4_BUF_SLAVE = 0x08; /* Buffered mode/slave */
|
||||
static constexpr int kICW4_BUF_MASTER = 0x0C; /* Buffered mode/master */
|
||||
static constexpr int kICW4_SFNM = 0x10; /* Special fully nested (not) */
|
||||
|
||||
#define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */
|
||||
#define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */
|
||||
static constexpr int kPIC_READ_IRR = 0x0a; /* OCW3 irq ready next CMD read */
|
||||
static constexpr int kPIC_READ_ISR = 0x0b; /* OCW3 irq service next CMD read */
|
||||
|
||||
#define PIC1_OFFSET 0x20
|
||||
#define PIC2_OFFSET 0x28
|
||||
static constexpr int kPIC1_OFFSET = 0x20;
|
||||
static constexpr int kPIC2_OFFSET = 0x28;
|
||||
|
||||
void PIC_sendEOI(unsigned char irq);
|
||||
void PIC_init();
|
||||
void IRQ_set_mask(unsigned char IRQline);
|
||||
void IRQ_clear_mask(unsigned char IRQline);
|
||||
uint16_t pic_get_irr(void);
|
||||
uint16_t pic_get_isr(void);
|
||||
void PIC_sendEOI(unsigned char irq);
|
||||
void PIC_init();
|
||||
void IRQ_set_mask(unsigned char IRQline);
|
||||
void IRQ_clear_mask(unsigned char IRQline);
|
||||
uint16_t pic_get_irr(void);
|
||||
uint16_t pic_get_isr(void);
|
||||
|
||||
typedef struct {
|
||||
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
||||
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||
uint8_t ist; // The IST in the TSS that the CPU will load into RSP; set to zero for now
|
||||
uint8_t attributes; // Type and attributes; see the IDT page
|
||||
uint16_t isr_mid; // The higher 16 bits of the lower 32 bits of the ISR's address
|
||||
uint32_t isr_high; // The higher 32 bits of the ISR's address
|
||||
uint32_t reserved; // Set to zero
|
||||
} __attribute__((packed)) idt_entry_t;
|
||||
struct IdtEntry {
|
||||
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
||||
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||
uint8_t ist; // The IST in the TSS that the CPU will load into RSP; set to zero for now
|
||||
uint8_t attributes; // Type and attributes; see the IDT page
|
||||
uint16_t isr_mid; // The higher 16 bits of the lower 32 bits of the ISR's address
|
||||
uint32_t isr_high; // The higher 32 bits of the ISR's address
|
||||
uint32_t reserved; // Set to zero
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} __attribute__((packed)) idtr_t;
|
||||
struct Idtr {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define IDT_GUARD 0xdeadbe3fdeadb3efULL
|
||||
|
||||
// Assuming the compiler understands that this is pushed on the stack in the correct order
|
||||
struct TaskFrame {
|
||||
uint64_t guard;
|
||||
uint64_t guard2; // To keep stack aligned after pushaq
|
||||
extern "C" void exception_handler_err(uint64_t code);
|
||||
extern "C" void exception_handler_no_err(void);
|
||||
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
void idt_set_descriptor(uint8_t vector, void (*isr)(), uint8_t flags);
|
||||
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rbp;
|
||||
uint64_t rbx;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rax;
|
||||
void idt_init();
|
||||
|
||||
uint64_t ip;
|
||||
uint64_t cs;
|
||||
uint64_t flags;
|
||||
uint64_t sp;
|
||||
uint64_t ss;
|
||||
}
|
||||
__attribute__((packed));
|
||||
|
||||
extern "C" void exception_handler(void);
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void (*isr)(), uint8_t flags);
|
||||
|
||||
void idt_init(void);
|
||||
|
||||
extern void (*isr_stub_table[])();
|
||||
extern "C" void (*isr_stub_table[])();
|
||||
} // namespace Arch::IDT
|
||||
|
||||
using int_handler_t = void (*)(void *);
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ struct FourPages {
|
||||
enum PageStatus second : 2;
|
||||
enum PageStatus third : 2;
|
||||
enum PageStatus fourth : 2;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(FourPages) == 1);
|
||||
|
||||
void parse_limine_memmap(struct limine_memmap_entry *entries, unsigned int num, uint64_t what_is_considered_free);
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
char temp_fxsave[512] __attribute__((aligned(16)));
|
||||
|
||||
void sanity_check_frame(TaskFrame *cur_frame) {
|
||||
void sanity_check_frame(Arch::TaskFrame *cur_frame) {
|
||||
// TODO: This makes sense to check when entering, but not when switching
|
||||
// assert((((uintptr_t) cur_frame) & 0xFULL) == 0);
|
||||
assert2((void *) cur_frame->ip != NULL, "Sanity check");
|
||||
assert2((void *) cur_frame->sp != NULL, "Sanity check");
|
||||
assert2(cur_frame->guard == IDT_GUARD, "IDT Guard wrong!");
|
||||
assert2(cur_frame->guard == Arch::kIDT_GUARD, "IDT Guard wrong!");
|
||||
assert(cur_frame->ss != 0);
|
||||
assert(cur_frame->cs != 0);
|
||||
assert(cur_frame->sp != 0);
|
||||
@@ -111,7 +111,7 @@ Task::Task(Task::TaskMode mode, void (*entrypoint)(), const char *name) {
|
||||
for (int i = 0; i < 512; i++) _fxsave->_fxsave[i] = 0;
|
||||
|
||||
_frame.flags = flags();
|
||||
_frame.guard = IDT_GUARD;
|
||||
_frame.guard = Arch::kIDT_GUARD;
|
||||
if (mode == TaskMode::TASKMODE_USER) {
|
||||
_ownAddressSpace = UniquePtr(new AddressSpace());
|
||||
_vma = UniquePtr<VMA>(new VMA(_ownAddressSpace.get()));
|
||||
@@ -276,7 +276,7 @@ void Scheduler::init_tasks() {
|
||||
atomic_store(&initialized, true);
|
||||
}
|
||||
|
||||
extern "C" void Scheduler::switch_task(TaskFrame *cur_frame) {
|
||||
extern "C" void Scheduler::switch_task(Arch::TaskFrame *cur_frame) {
|
||||
assert2(!are_interrupts_enabled(), "Switching tasks with enabled interrupts!");
|
||||
if (!atomic_load(&initialized)) return;
|
||||
sanity_check_frame(cur_frame);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "SkipList.hpp"
|
||||
#include "String.hpp"
|
||||
#include "idt.hpp"
|
||||
#include "task_arch.hpp"
|
||||
|
||||
#define TASK_SS 16384
|
||||
|
||||
@@ -58,7 +59,7 @@ public:
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
uint64_t _entry_ksp_val;
|
||||
TaskFrame _frame;
|
||||
Arch::TaskFrame _frame;
|
||||
TaskPID _pid;
|
||||
std::atomic<uint64_t> _used_time;
|
||||
|
||||
@@ -102,7 +103,7 @@ namespace Scheduler {
|
||||
void unblock(List<Task *>::Node *what);
|
||||
void unblock_nolock(List<Task *>::Node *what);
|
||||
|
||||
extern "C" void switch_task(TaskFrame *cur_frame);
|
||||
extern "C" void switch_task(Arch::TaskFrame *cur_frame);
|
||||
|
||||
// TODO: that's quite inefficient!
|
||||
SkipList<uint64_t, std::pair<String, Task::TaskPID>> getTaskTimePerPid();
|
||||
|
||||
44
src/arch/x86/task_arch.hpp
Normal file
44
src/arch/x86/task_arch.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 01.04.2024.
|
||||
//
|
||||
|
||||
#ifndef FICUS_TASK_ARCH_HPP
|
||||
#define FICUS_TASK_ARCH_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Arch {
|
||||
static constexpr uint64_t kIDT_GUARD = 0xdeadbe3fdeadb3efULL;
|
||||
|
||||
// Assuming the compiler understands that this is pushed on the stack in the correct order
|
||||
struct TaskFrame {
|
||||
uint64_t guard;
|
||||
uint64_t guard2; // To keep stack aligned after pushaq
|
||||
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rbp;
|
||||
uint64_t rbx;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rax;
|
||||
|
||||
uint64_t ip;
|
||||
uint64_t cs;
|
||||
uint64_t flags;
|
||||
uint64_t sp;
|
||||
uint64_t ss;
|
||||
} __attribute__((packed));
|
||||
|
||||
} // namespace Arch
|
||||
|
||||
#endif //FICUS_TASK_ARCH_HPP
|
||||
@@ -46,7 +46,7 @@ static_assert(MICROS_PER_TICK >= 1);
|
||||
void init_timer() {
|
||||
outb(0x43, 0b00110100);
|
||||
set_pit_count(RELOAD_VAL);
|
||||
IRQ_clear_mask(0);
|
||||
Arch::IDT::IRQ_clear_mask(0);
|
||||
}
|
||||
|
||||
void timer_tick() {
|
||||
|
||||
Reference in New Issue
Block a user