Use APIC for interrupts rather than PIC.
Still rely on the PIT for now rather than the local APIC timer.
This commit is contained in:
parent
7c9d1075eb
commit
add533071b
|
@ -3,7 +3,9 @@ add_executable(zion
|
|||
capability/capability.cpp
|
||||
common/gdt.cpp
|
||||
common/load_gdt.s
|
||||
common/msr.cpp
|
||||
debug/debug.cpp
|
||||
interrupt/apic.cpp
|
||||
interrupt/interrupt.cpp
|
||||
interrupt/interrupt_enter.s
|
||||
interrupt/timer.cpp
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include "common/msr.h"
|
||||
|
||||
uint64_t GetMSR(uint32_t msr) {
|
||||
uint32_t lo, hi;
|
||||
asm("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
|
||||
return (static_cast<uint64_t>(hi) << 32) | lo;
|
||||
}
|
||||
|
||||
void SetMSR(uint32_t msr, uint64_t val) {
|
||||
uint32_t lo = static_cast<uint32_t>(val);
|
||||
uint32_t hi = val >> 32;
|
||||
asm("wrmsr" ::"a"(lo), "d"(hi), "c"(msr));
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t GetMSR(uint32_t msr);
|
||||
void SetMSR(uint32_t msr, uint64_t val);
|
|
@ -0,0 +1,128 @@
|
|||
#include "interrupt/apic.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/boot_info.h"
|
||||
#include "common/msr.h"
|
||||
#include "common/port.h"
|
||||
#include "debug/debug.h"
|
||||
|
||||
#define APIC_DEBUG 0
|
||||
|
||||
namespace {
|
||||
|
||||
#define IA32_APIC_BASE_MSR 0x1B
|
||||
#define IA32_APIC_BASE_MSR_BSP 0x100 // Processor is a BSP
|
||||
#define IA32_APIC_BASE_MSR_ENABLE 0x800
|
||||
|
||||
const uint64_t kEoiOffset = 0xB0;
|
||||
|
||||
constexpr uint64_t kLApicBase = 0xFEE0'0000;
|
||||
constexpr uint64_t kIoApicAddr = 0xFEC0'0000;
|
||||
constexpr uint64_t kIoApicData = 0xFEC0'0010;
|
||||
|
||||
uint32_t volatile* GetPhys(uint64_t base, uint64_t offset = 0) {
|
||||
return reinterpret_cast<uint32_t*>(boot::GetHigherHalfDirectMap() + base +
|
||||
offset);
|
||||
}
|
||||
|
||||
uint32_t GetLocalReg(uint64_t offset) {
|
||||
uint32_t volatile* reg = GetPhys(kLApicBase, offset);
|
||||
return *reg;
|
||||
}
|
||||
|
||||
void WriteLocalReg(uint64_t offset, uint32_t value) {
|
||||
*GetPhys(kLApicBase, offset) = value;
|
||||
}
|
||||
|
||||
uint32_t GetIoReg(uint8_t reg) {
|
||||
*GetPhys(kIoApicAddr) = reg;
|
||||
return *GetPhys(kIoApicData);
|
||||
}
|
||||
|
||||
uint64_t GetIoEntry(uint8_t reg) {
|
||||
*GetPhys(kIoApicAddr) = reg;
|
||||
uint64_t entry = *GetPhys(kIoApicData);
|
||||
*GetPhys(kIoApicAddr) = reg + 1;
|
||||
entry |= ((uint64_t)*GetPhys(kIoApicData)) << 32;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void SetIoEntry(uint8_t reg, uint64_t value) {
|
||||
*GetPhys(kIoApicAddr) = reg;
|
||||
*GetPhys(kIoApicData) = value & 0xFFFFFFFF;
|
||||
*GetPhys(kIoApicAddr) = reg + 1;
|
||||
*GetPhys(kIoApicData) = value >> 32;
|
||||
}
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_DATA 0xA1
|
||||
|
||||
void MaskPic() {
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
outb(PIC2_DATA, 0xFF);
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
// Potential spurious interrupts at 0x87
|
||||
outb(PIC1_DATA, 0x80); // PIC1 offset (high and dry).
|
||||
outb(PIC2_DATA, 0x80); // PIC2 offset (high and dry).
|
||||
outb(PIC1_DATA, 0x4);
|
||||
outb(PIC2_DATA, 0x2);
|
||||
outb(PIC1_DATA, 0x1);
|
||||
outb(PIC2_DATA, 0x1);
|
||||
|
||||
// Mask all.
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
outb(PIC2_DATA, 0xFF);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void InspectApic() {
|
||||
#if APIC_DEBUG
|
||||
dbgln("APIC:");
|
||||
dbgln("ID: %x", GetLocalReg(0x20));
|
||||
dbgln("VER: %x", GetLocalReg(0x30));
|
||||
dbgln("TPR: %x", GetLocalReg(0x80));
|
||||
dbgln("APR: %x", GetLocalReg(0x90));
|
||||
dbgln("PPR: %x", GetLocalReg(0xA0));
|
||||
dbgln("RRD: %x", GetLocalReg(0xC0));
|
||||
dbgln("LDR: %x", GetLocalReg(0xD0));
|
||||
dbgln("DFR: %x", GetLocalReg(0xE0));
|
||||
dbgln("SIV: %x", GetLocalReg(0xF0));
|
||||
for (uint64_t i = 0; i < 8; i++) {
|
||||
dbgln("ISR(%u): %x", i, GetLocalReg(0x100 + (0x10 * i)));
|
||||
}
|
||||
for (uint64_t i = 0; i < 8; i++) {
|
||||
dbgln("TMR(%u): %x", i, GetLocalReg(0x180 + (0x10 * i)));
|
||||
}
|
||||
for (uint64_t i = 0; i < 8; i++) {
|
||||
dbgln("IRR(%u): %x", i, GetLocalReg(0x200 + (0x10 * i)));
|
||||
}
|
||||
dbgln("ESR: %x", GetLocalReg(0x280));
|
||||
|
||||
dbgln("IO ID: %x", GetIoReg(0x0));
|
||||
dbgln("IO VER: %x", GetIoReg(0x1));
|
||||
dbgln("IO ARB: %x", GetIoReg(0x2));
|
||||
for (uint8_t i = 0x10; i < 0x3F; i += 2) {
|
||||
dbgln("IO (%u): %x", i, GetIoEntry(i));
|
||||
}
|
||||
dbgln("APIC MSR: %x", GetMSR(0x1B));
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnableApic() {
|
||||
MaskPic();
|
||||
// Map Timer.
|
||||
SetIoEntry(0x14, 0x20);
|
||||
// Skip Keyboard for now.
|
||||
// SetIoEntry(0x12, 0x21);
|
||||
InspectApic();
|
||||
}
|
||||
|
||||
void SignalEOI() {
|
||||
// Value doesn't matter.
|
||||
WriteLocalReg(kEoiOffset, 0x1);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
void InspectApic();
|
||||
|
||||
void EnableApic();
|
||||
|
||||
void SignalEOI();
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "common/port.h"
|
||||
#include "debug/debug.h"
|
||||
#include "interrupt/apic.h"
|
||||
#include "memory/kernel_heap.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
|
||||
|
@ -124,10 +125,6 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) {
|
|||
panic("PF");
|
||||
}
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC_EOI 0x20
|
||||
|
||||
uint64_t cnt = 0;
|
||||
extern "C" void isr_timer();
|
||||
extern "C" void interrupt_timer(InterruptFrame*) {
|
||||
|
@ -138,20 +135,10 @@ extern "C" void interrupt_timer(InterruptFrame*) {
|
|||
}
|
||||
dbgln("timer: %us", cnt * 50 / 1000);
|
||||
}
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
SignalEOI();
|
||||
gScheduler->Preempt();
|
||||
}
|
||||
|
||||
void EnablePic() {
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC1_DATA, 0x20); // PIC1 offset.
|
||||
outb(PIC1_DATA, 0x4);
|
||||
outb(PIC1_DATA, 0x1);
|
||||
|
||||
// Mask all except the timer.
|
||||
outb(PIC1_DATA, 0xE);
|
||||
}
|
||||
|
||||
void InitIdt() {
|
||||
gIdt[0] = CreateDescriptor(isr_divide_by_zero);
|
||||
gIdt[13] = CreateDescriptor(isr_protection_fault);
|
||||
|
@ -163,5 +150,5 @@ void InitIdt() {
|
|||
};
|
||||
asm volatile("lidt %0" ::"m"(idtp));
|
||||
|
||||
EnablePic();
|
||||
EnableApic();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/msr.h"
|
||||
#include "debug/debug.h"
|
||||
#include "include/zcall.h"
|
||||
#include "include/zerrors.h"
|
||||
|
@ -15,24 +16,8 @@
|
|||
#define STAR 0xC0000081
|
||||
#define LSTAR 0xC0000082
|
||||
|
||||
namespace {
|
||||
|
||||
uint64_t GetMSR(uint32_t msr) {
|
||||
uint32_t lo, hi;
|
||||
asm("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
|
||||
return (static_cast<uint64_t>(hi) << 32) | lo;
|
||||
}
|
||||
|
||||
void SetMSR(uint32_t msr, uint64_t val) {
|
||||
uint32_t lo = static_cast<uint32_t>(val);
|
||||
uint32_t hi = val >> 32;
|
||||
asm("wrmsr" ::"a"(lo), "d"(hi), "c"(msr));
|
||||
}
|
||||
|
||||
extern "C" void syscall_enter();
|
||||
|
||||
} // namespace
|
||||
|
||||
// Used by syscall_enter.s
|
||||
extern "C" uint64_t GetKernelRsp() {
|
||||
return gScheduler->CurrentThread().Rsp0Start();
|
||||
|
|
Loading…
Reference in New Issue