Add initial IDT and GDT setup.

WIP interrupt handling. Interrupts do not yet return.
This commit is contained in:
Justin C. Miller
2018-04-15 09:14:53 -07:00
parent 447991e82b
commit 2388a92085
8 changed files with 551 additions and 0 deletions

View File

@@ -17,6 +17,8 @@ section .text
align 16
global _start:function (_start.end - _start)
_start:
cli
extern kernel_main
call kernel_main
@@ -26,3 +28,13 @@ _start:
hlt
jmp .hang
.end:
global interrupts_enable
interrupts_enable:
sti
ret
global interrupts_disable
interrupts_disable:
cli
ret

View File

@@ -0,0 +1,68 @@
#include <stddef.h>
#include <stdint.h>
#include "device_manager.h"
#include "console.h"
#include "util.h"
static const char expected_signature[] = "RSD PTR ";
struct Acpi10RSDPDescriptor
{
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
} __attribute__ ((packed));
struct Acpi20RSDPDescriptor
{
char signature[8];
uint8_t checksum10;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
uint32_t length;
uint64_t xsdt_address;
uint8_t checksum20;
uint8_t reserved[3];
} __attribute__ ((packed));
template <typename T>
uint8_t acpi_checksum(const T *p, size_t off = 0)
{
uint8_t sum = 0;
const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
for (int i = off; i < sizeof(T); ++i) sum += c[i];
return sum;
}
device_manager::device_manager(const void *root_table)
{
console *cons = console::get();
kassert(root_table != 0, "ACPI root table pointer is null.");
const Acpi10RSDPDescriptor *acpi1 =
reinterpret_cast<const Acpi10RSDPDescriptor *>(root_table);
for (int i = 0; i < sizeof(acpi1->signature); ++i)
kassert(acpi1->signature[i] == expected_signature[i],
"ACPI RSDP table signature mismatch");
uint8_t sum = acpi_checksum(acpi1, 0);
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
const Acpi20RSDPDescriptor *acpi2 =
reinterpret_cast<const Acpi20RSDPDescriptor *>(acpi1);
sum = acpi_checksum(acpi2, sizeof(Acpi10RSDPDescriptor));
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
cons->puts("ACPI 2.0 tables loading...\n");
}

View File

@@ -0,0 +1,10 @@
#pragma once
class device_manager
{
public:
device_manager(const void *root_table);
device_manager() = delete;
device_manager(const device_manager &) = delete;
};

View File

@@ -0,0 +1,32 @@
ISR( 0, isr0);
ISR( 1, isr1);
ISR( 2, isr2);
ISR( 3, isr3);
ISR( 4, isr4);
ISR( 5, isr5);
ISR( 6, isr6);
ISR( 7, isr7);
ISR( 8, isr8);
ISR( 9, isr9);
ISR(10, isr10);
ISR(11, isr11);
ISR(12, isr12);
ISR(13, isr13);
ISR(14, isr14);
ISR(15, isr15);
ISR(16, isr16);
ISR(17, isr17);
ISR(18, isr18);
ISR(19, isr19);
ISR(20, isr20);
ISR(21, isr21);
ISR(22, isr22);
ISR(23, isr23);
ISR(24, isr24);
ISR(25, isr25);
ISR(26, isr26);
ISR(27, isr27);
ISR(28, isr28);
ISR(29, isr29);
ISR(30, isr30);
ISR(31, isr31);

View File

@@ -0,0 +1,297 @@
#include <stddef.h>
#include <stdint.h>
#include "console.h"
#include "interrupts.h"
enum class gdt_flags : uint8_t
{
ac = 0x01,
rw = 0x02,
dc = 0x04,
ex = 0x08,
r1 = 0x20,
r2 = 0x40,
r3 = 0x60,
pr = 0x80,
res_1 = 0x10
};
inline gdt_flags
operator | (gdt_flags lhs, gdt_flags rhs)
{
return static_cast<gdt_flags>(
static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
}
struct gdt_descriptor
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_mid;
uint8_t flags;
uint8_t granularity;
uint8_t base_high;
} __attribute__ ((packed));
struct idt_descriptor
{
uint16_t base_low;
uint16_t selector;
uint8_t ist;
uint8_t flags;
uint16_t base_mid;
uint32_t base_high;
uint32_t reserved; // must be zero
} __attribute__ ((packed));
struct table_ptr
{
uint16_t limit;
uint64_t base;
} __attribute__ ((packed));
gdt_descriptor g_gdt_table[10];
idt_descriptor g_idt_table[256];
table_ptr g_gdtr;
table_ptr g_idtr;
struct registers;
extern "C" {
void idt_write();
void idt_load();
void gdt_write();
void gdt_load();
void isr_handler(registers);
#define ISR(i, name) extern void name ()
#include "interrupt_isrs.inc"
#undef ISR
}
void idt_dump(const table_ptr &table);
void gdt_dump(const table_ptr &table);
void
set_gdt_entry(uint8_t i, uint32_t base, uint32_t limit, bool is64, gdt_flags flags)
{
g_gdt_table[i].limit_low = limit & 0xffff;
g_gdt_table[i].base_low = base & 0xffff;
g_gdt_table[i].base_mid = (base >> 16) & 0xff;
g_gdt_table[i].base_high = (base >> 24) & 0xff;
g_gdt_table[i].granularity =
((limit >> 16) & 0xf) | (is64 ? 0xa0 : 0xc0);
g_gdt_table[i].flags = static_cast<uint8_t>(flags | gdt_flags::res_1 | gdt_flags::pr);
}
void
set_idt_entry(uint8_t i, uint64_t addr, uint16_t selector, uint8_t flags)
{
g_idt_table[i].base_low = addr & 0xffff;
g_idt_table[i].base_mid = (addr >> 16) & 0xffff;
g_idt_table[i].base_high = (addr >> 32) & 0xffffffff;
g_idt_table[i].selector = selector;
g_idt_table[i].flags = flags;
g_idt_table[i].ist = 0;
g_idt_table[i].reserved = 0;
}
void
interrupts_init()
{
uint8_t *p;
gdt_load();
gdt_dump(g_gdtr);
p = reinterpret_cast<uint8_t *>(&g_gdt_table);
for (int i = 0; i < sizeof(g_gdt_table); ++i) p[i] = 0;
g_gdtr.limit = sizeof(g_gdt_table) - 1;
g_gdtr.base = reinterpret_cast<uint64_t>(&g_gdt_table);
set_gdt_entry(1, 0, 0xfffff, false, gdt_flags::rw);
set_gdt_entry(2, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex | gdt_flags::dc);
set_gdt_entry(3, 0, 0xfffff, false, gdt_flags::rw);
set_gdt_entry(4, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex);
set_gdt_entry(6, 0, 0xfffff, false, gdt_flags::rw);
set_gdt_entry(7, 0, 0xfffff, true, gdt_flags::rw | gdt_flags::ex);
gdt_write();
gdt_load();
gdt_dump(g_gdtr);
p = reinterpret_cast<uint8_t *>(&g_idt_table);
for (int i = 0; i < sizeof(g_idt_table); ++i) p[i] = 0;
g_idtr.limit = sizeof(g_idt_table) - 1;
g_idtr.base = reinterpret_cast<uint64_t>(&g_idt_table);
#define ISR(i, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
#include "interrupt_isrs.inc"
#undef ISR
idt_write();
}
struct registers
{
uint64_t ds;
uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax;
uint64_t interrupt, errorcode;
uint64_t rip, cs, eflags, user_esp, ss;
};
void
isr_handler(registers regs)
{
console::get()->puts("received interrupt: ");
console::get()->put_dec(regs.interrupt);
console::get()->puts("\n");
while(1);
}
void
gdt_dump(const table_ptr &table)
{
console *cons = console::get();
cons->puts("Loaded GDT at: ");
cons->put_hex(table.base);
cons->puts(" size: ");
cons->put_dec(table.limit + 1);
cons->puts(" bytes\n");
int count = (table.limit + 1) / sizeof(gdt_descriptor);
const gdt_descriptor *gdt =
reinterpret_cast<const gdt_descriptor *>(table.base);
for (int i = 0; i < count; ++i) {
uint32_t base =
(gdt[i].base_high << 24) |
(gdt[i].base_mid << 16) |
gdt[i].base_low;
uint32_t limit =
static_cast<uint32_t>(gdt[i].granularity & 0x0f) << 16 |
gdt[i].limit_low;
cons->puts(" Entry ");
cons->put_dec(i);
cons->puts(": Base ");
cons->put_hex(base);
cons->puts(" Limit ");
cons->put_hex(limit);
cons->puts(" Privs ");
cons->put_dec((gdt[i].flags >> 5) & 0x03);
cons->puts(" Flags ");
if (gdt[i].flags & 0x80) {
cons->puts("P ");
if (gdt[i].flags & 0x08)
cons->puts("EX ");
else
cons->puts(" ");
if (gdt[i].flags & 0x04)
cons->puts("DC ");
else
cons->puts(" ");
if (gdt[i].flags & 0x02)
cons->puts("RW ");
else
cons->puts(" ");
if (gdt[i].granularity & 0x80)
cons->puts("KB ");
else
cons->puts(" B ");
if ((gdt[i].granularity & 0x60) == 0x20)
cons->puts("64");
else if ((gdt[i].granularity & 0x60) == 0x40)
cons->puts("32");
else
cons->puts("16");
}
cons->puts("\n");
}
}
void
idt_dump(const table_ptr &table)
{
console *cons = console::get();
cons->puts("Loaded IDT at: ");
cons->put_hex(table.base);
cons->puts(" size: ");
cons->put_dec(table.limit + 1);
cons->puts(" bytes\n");
int count = (table.limit + 1) / sizeof(idt_descriptor);
const idt_descriptor *idt =
reinterpret_cast<const idt_descriptor *>(table.base);
if (count > 32) count = 32;
for (int i = 0; i < count; ++i) {
uint64_t base =
(static_cast<uint64_t>(idt[i].base_high) << 32) |
(static_cast<uint64_t>(idt[i].base_mid) << 16) |
idt[i].base_low;
cons->puts(" Entry ");
cons->put_dec(i);
cons->puts(": Base ");
cons->put_hex(base);
cons->puts(" Sel(");
cons->put_dec(idt[i].selector & 0x3);
cons->puts(",");
cons->put_dec((idt[i].selector & 0x4) >> 2);
cons->puts(",");
cons->put_dec(idt[i].selector >> 3);
cons->puts(") ");
cons->puts("IST ");
cons->put_dec(idt[i].ist);
switch (idt[i].flags & 0xf) {
case 0x5: cons->puts(" 32tsk "); break;
case 0x6: cons->puts(" 16int "); break;
case 0x7: cons->puts(" 16trp "); break;
case 0xe: cons->puts(" 32int "); break;
case 0xf: cons->puts(" 32trp "); break;
default:
cons->puts(" ?");
cons->put_hex(idt[i].flags & 0xf);
cons->puts(" ");
break;
}
cons->puts("DPL ");
cons->put_dec((idt[i].flags >> 5) & 0x3);
if (idt[i].flags & 0x80)
cons->puts(" P");
cons->puts("\n");
}
}

View File

@@ -0,0 +1,8 @@
#pragma once
extern "C" {
void interrupts_enable();
void interrupts_disable();
}
void interrupts_init();

View File

@@ -0,0 +1,112 @@
extern g_idtr
extern g_gdtr
global idt_write
idt_write:
lidt [g_idtr]
ret
global idt_load
idt_load:
sidt [g_idtr]
ret
global gdt_write
gdt_write:
lgdt [g_gdtr]
ret
global gdt_load
gdt_load:
sgdt [g_gdtr]
ret
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli
push byte 0
push byte %1
jmp isr_handler_prelude
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli
push byte %1
jmp isr_handler_prelude
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
extern isr_handler
global isr_handler_prelude
isr_handler_prelude:
push rax
push rcx
push rdx
push rbx
push rbp
push rsi
push rdi
mov ax, ds ; Save the data segment register
push rax
mov ax, 0x10 ; load the kernel data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler
pop rax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
pop rax
add rsp, 8 ; because the ISRs added err/num
sti
iretq

View File

@@ -3,6 +3,7 @@
#include "console.h"
#include "font.h"
#include "interrupts.h"
#include "kernel_data.h"
#include "screen.h"
@@ -27,6 +28,8 @@ load_console(const popcorn_data *header)
header->log_length};
}
extern "C" { void isr31(); }
void
kernel_main(popcorn_data *header)
{
@@ -37,5 +40,14 @@ kernel_main(popcorn_data *header)
cons.set_color(0x08, 0x00);
cons.puts(GIT_VERSION " booting...\n");
interrupts_init();
interrupts_enable();
cons.puts("Interrupts initialized.\n");
// isr31();
__asm__ __volatile__("int $31");
cons.puts("boogity!");
do_the_set_registers(header);
}