feature: apic is now enabled and the double fault interrupt at boot no longer occurs
This commit is contained in:
60
src/interrupt/apic.c
Normal file
60
src/interrupt/apic.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include "apic.h"
|
||||
#include "cpuid.h"
|
||||
#include "sys/io.h"
|
||||
#include <cpuid.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define IA32_APIC_BASE_MSR 0x1B
|
||||
#define IA32_APIC_BASE_MSR_BSP 0x100 // Processor is a BSP
|
||||
#define IA32_APIC_BASE_MSR_ENABLE 0x800
|
||||
|
||||
/** returns a 'true' value if the CPU supports APIC
|
||||
* and if the local APIC hasn't been disabled in MSRs
|
||||
* note that this requires CPUID to be supported.
|
||||
*/
|
||||
bool check_apic()
|
||||
{
|
||||
static unsigned int eax, edx, unused;
|
||||
__get_cpuid(1, &eax, &unused, &unused, &edx);
|
||||
return edx & CPUID_FEAT_EDX_APIC;
|
||||
}
|
||||
|
||||
/* Set the physical address for local APIC registers */
|
||||
static void cpu_set_apic_base(uintptr_t apic)
|
||||
{
|
||||
uint32_t edx = 0;
|
||||
uint32_t eax = (apic & 0xfffff0000) | IA32_APIC_BASE_MSR_ENABLE;
|
||||
|
||||
#ifdef __PHYSICAL_MEMORY_EXTENSION__
|
||||
edx = (apic >> 32) & 0x0f;
|
||||
#endif
|
||||
|
||||
cpu_set_msr(IA32_APIC_BASE_MSR, eax, edx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the physical address of the APIC registers page
|
||||
* make sure you map it to virtual memory ;)
|
||||
*/
|
||||
static uintptr_t cpu_get_apic_base(void)
|
||||
{
|
||||
uint32_t eax, edx;
|
||||
cpu_get_msr(IA32_APIC_BASE_MSR, &eax, &edx);
|
||||
|
||||
#ifdef __PHYSICAL_MEMORY_EXTENSION__
|
||||
return (eax & 0xfffff000) | ((edx & 0x0f) << 32);
|
||||
#else
|
||||
return (eax & 0xfffff000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void enable_apic(void)
|
||||
{
|
||||
/* Hardware enable the Local APIC if it wasn't enabled */
|
||||
cpu_set_apic_base(cpu_get_apic_base());
|
||||
|
||||
/* Set the Spurious Interrupt Vector Register bit 8 to start receiving
|
||||
* interrupts */
|
||||
write_reg(0xF0, read_reg(0xF0) | 0x100);
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
void exception_handler(void)
|
||||
{
|
||||
int8_t index = -1;
|
||||
__asm__ volatile("movb %%al, %0" ::"m"(index));
|
||||
__asm__ volatile("movb %%bl, %0" ::"m"(index));
|
||||
|
||||
kprintf(KERN_CRIT "interrupt: ");
|
||||
switch (index) {
|
||||
|
@ -1,39 +1,22 @@
|
||||
#include "sys/io.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "apic.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
|
||||
#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)
|
||||
|
||||
extern void *isr_stub_table[];
|
||||
|
||||
__attribute__((aligned(0x10))) static struct idt_entry idt_entries[IDT_SIZE];
|
||||
static struct idt_descriptor idtr;
|
||||
/*
|
||||
static void set_idt_entry_value(uint16_t *target, uint32_t offset,
|
||||
uint16_t selector, uint8_t dpl,
|
||||
uint8_t gate_type)
|
||||
{
|
||||
// Encode the offset
|
||||
target[0] = offset & 0xFFFF; // Low 16 bits
|
||||
target[3] = (offset >> 16) & 0xFFFF; // High 16 bits
|
||||
|
||||
// Encode the presence (bit 15)
|
||||
target[1] |= 1 << 15;
|
||||
|
||||
// Encode the CPU Privilege Levels (DPL)
|
||||
target[1] &= ~(0b11 << 13); // Clear previous DPL
|
||||
target[1] |= (dpl & 0b11) << 13; // Set new DPL
|
||||
|
||||
// Clear bit 12 (always 0 for interrupts)
|
||||
target[1] &= ~(1 << 12);
|
||||
|
||||
// Encode Gate Type
|
||||
target[1] &= ~0x0F00; // Clear previous gate type
|
||||
target[1] |= (gate_type & 0x0F) << 8; // Set new gate type
|
||||
|
||||
// Encode selector
|
||||
target[2] = selector;
|
||||
}*/
|
||||
|
||||
void idt_set_descriptor(uint8_t index, void *isr, uint8_t flags)
|
||||
{
|
||||
@ -53,7 +36,9 @@ void init_idt(void)
|
||||
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
idt_set_descriptor(i, isr_stub_table[i], 0x8E);
|
||||
|
||||
__asm__ volatile("lidt %0" : : "m"(idtr));
|
||||
__asm__ volatile("sti");
|
||||
pic_remap(32, 32);
|
||||
pic_disable();
|
||||
enable_apic();
|
||||
}
|
||||
|
22
src/interrupt/msr.c
Normal file
22
src/interrupt/msr.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <cpuid.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
const uint32_t CPUID_FLAG_MSR = 1 << 5;
|
||||
|
||||
bool cpu_has_msr()
|
||||
{
|
||||
static unsigned int eax, edx, unused;
|
||||
__get_cpuid(1, &eax, &unused, &unused, &edx);
|
||||
return edx & CPUID_FLAG_MSR;
|
||||
}
|
||||
|
||||
void cpu_get_msr(uint32_t msr, uint32_t *lo, uint32_t *hi)
|
||||
{
|
||||
asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
|
||||
}
|
||||
|
||||
void cpu_set_msr(uint32_t msr, uint32_t lo, uint32_t hi)
|
||||
{
|
||||
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
|
||||
}
|
61
src/interrupt/pic.c
Normal file
61
src/interrupt/pic.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "sys/io.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#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 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! */
|
||||
|
||||
#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) */
|
||||
|
||||
void pic_remap(int offset_master, int offset_slave)
|
||||
{
|
||||
uint8_t 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, offset_master); // ICW2: Master PIC vector offset
|
||||
io_wait();
|
||||
outb(PIC2_DATA, offset_slave); // 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 pic_disable(void)
|
||||
{
|
||||
outb(PIC1_DATA, 0xff);
|
||||
outb(PIC2_DATA, 0xff);
|
||||
}
|
Reference in New Issue
Block a user