feature: apic is now enabled and the double fault interrupt at boot no longer occurs
This commit is contained in:
parent
9479515685
commit
d6b35a2786
16
headers/apic.h
Normal file
16
headers/apic.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// MSR
|
||||
bool cpu_has_msr();
|
||||
void cpu_set_msr(uint32_t msr, uint32_t lo, uint32_t hi);
|
||||
void cpu_get_msr(uint32_t msr, uint32_t *lo, uint32_t *hi);
|
||||
|
||||
// 8259 PIC
|
||||
void pic_disable(void);
|
||||
void pic_remap(int offset_master, int offset_slave);
|
||||
|
||||
// APIC
|
||||
void enable_apic(void);
|
66
headers/cpuid.h
Normal file
66
headers/cpuid.h
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
enum {
|
||||
CPUID_FEAT_ECX_SSE3 = 1 << 0,
|
||||
CPUID_FEAT_ECX_PCLMUL = 1 << 1,
|
||||
CPUID_FEAT_ECX_DTES64 = 1 << 2,
|
||||
CPUID_FEAT_ECX_MONITOR = 1 << 3,
|
||||
CPUID_FEAT_ECX_DS_CPL = 1 << 4,
|
||||
CPUID_FEAT_ECX_VMX = 1 << 5,
|
||||
CPUID_FEAT_ECX_SMX = 1 << 6,
|
||||
CPUID_FEAT_ECX_EST = 1 << 7,
|
||||
CPUID_FEAT_ECX_TM2 = 1 << 8,
|
||||
CPUID_FEAT_ECX_SSSE3 = 1 << 9,
|
||||
CPUID_FEAT_ECX_CID = 1 << 10,
|
||||
CPUID_FEAT_ECX_SDBG = 1 << 11,
|
||||
CPUID_FEAT_ECX_FMA = 1 << 12,
|
||||
CPUID_FEAT_ECX_CX16 = 1 << 13,
|
||||
CPUID_FEAT_ECX_XTPR = 1 << 14,
|
||||
CPUID_FEAT_ECX_PDCM = 1 << 15,
|
||||
CPUID_FEAT_ECX_PCID = 1 << 17,
|
||||
CPUID_FEAT_ECX_DCA = 1 << 18,
|
||||
CPUID_FEAT_ECX_SSE4_1 = 1 << 19,
|
||||
CPUID_FEAT_ECX_SSE4_2 = 1 << 20,
|
||||
CPUID_FEAT_ECX_X2APIC = 1 << 21,
|
||||
CPUID_FEAT_ECX_MOVBE = 1 << 22,
|
||||
CPUID_FEAT_ECX_POPCNT = 1 << 23,
|
||||
CPUID_FEAT_ECX_TSC = 1 << 24,
|
||||
CPUID_FEAT_ECX_AES = 1 << 25,
|
||||
CPUID_FEAT_ECX_XSAVE = 1 << 26,
|
||||
CPUID_FEAT_ECX_OSXSAVE = 1 << 27,
|
||||
CPUID_FEAT_ECX_AVX = 1 << 28,
|
||||
CPUID_FEAT_ECX_F16C = 1 << 29,
|
||||
CPUID_FEAT_ECX_RDRAND = 1 << 30,
|
||||
CPUID_FEAT_ECX_HYPERVISOR = 1 << 31,
|
||||
|
||||
CPUID_FEAT_EDX_FPU = 1 << 0,
|
||||
CPUID_FEAT_EDX_VME = 1 << 1,
|
||||
CPUID_FEAT_EDX_DE = 1 << 2,
|
||||
CPUID_FEAT_EDX_PSE = 1 << 3,
|
||||
CPUID_FEAT_EDX_TSC = 1 << 4,
|
||||
CPUID_FEAT_EDX_MSR = 1 << 5,
|
||||
CPUID_FEAT_EDX_PAE = 1 << 6,
|
||||
CPUID_FEAT_EDX_MCE = 1 << 7,
|
||||
CPUID_FEAT_EDX_CX8 = 1 << 8,
|
||||
CPUID_FEAT_EDX_APIC = 1 << 9,
|
||||
CPUID_FEAT_EDX_SEP = 1 << 11,
|
||||
CPUID_FEAT_EDX_MTRR = 1 << 12,
|
||||
CPUID_FEAT_EDX_PGE = 1 << 13,
|
||||
CPUID_FEAT_EDX_MCA = 1 << 14,
|
||||
CPUID_FEAT_EDX_CMOV = 1 << 15,
|
||||
CPUID_FEAT_EDX_PAT = 1 << 16,
|
||||
CPUID_FEAT_EDX_PSE36 = 1 << 17,
|
||||
CPUID_FEAT_EDX_PSN = 1 << 18,
|
||||
CPUID_FEAT_EDX_CLFLUSH = 1 << 19,
|
||||
CPUID_FEAT_EDX_DS = 1 << 21,
|
||||
CPUID_FEAT_EDX_ACPI = 1 << 22,
|
||||
CPUID_FEAT_EDX_MMX = 1 << 23,
|
||||
CPUID_FEAT_EDX_FXSR = 1 << 24,
|
||||
CPUID_FEAT_EDX_SSE = 1 << 25,
|
||||
CPUID_FEAT_EDX_SSE2 = 1 << 26,
|
||||
CPUID_FEAT_EDX_SS = 1 << 27,
|
||||
CPUID_FEAT_EDX_HTT = 1 << 28,
|
||||
CPUID_FEAT_EDX_TM = 1 << 29,
|
||||
CPUID_FEAT_EDX_IA64 = 1 << 30,
|
||||
CPUID_FEAT_EDX_PBE = 1 << 31
|
||||
};
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t val)
|
||||
@ -25,3 +26,18 @@ static inline uint16_t inw(uint16_t port)
|
||||
__asm__ volatile("inb %w1, %b0" : "=a"(ret) : "Nd"(port) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void io_wait(void)
|
||||
{
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
static inline void write_reg(size_t addr, uint32_t val)
|
||||
{
|
||||
*(volatile uint32_t *)addr = val;
|
||||
}
|
||||
|
||||
static inline uint32_t read_reg(size_t addr)
|
||||
{
|
||||
return *(volatile uint32_t *)addr;
|
||||
}
|
||||
|
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);
|
||||
}
|
@ -27,7 +27,7 @@ void kernel_main(void)
|
||||
{
|
||||
terminal_initialize();
|
||||
init_gdt();
|
||||
init_memory();
|
||||
init_idt();
|
||||
init_memory();
|
||||
shell_init();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user