Add support for I/O APIC with testing kb mapping
This commit is contained in:
@@ -94,4 +94,8 @@
|
||||
movq $AMD64_LAPIC_REG_EOI_ABS, %rax
|
||||
movl $0, (%rax)
|
||||
.endm
|
||||
#else
|
||||
// Externs for C code
|
||||
extern void amd64_irq0();
|
||||
extern void amd64_irq1();
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
#define IOAPIC_REG_ID 0x00
|
||||
#define IOAPIC_REG_VER 0x01
|
||||
#define IOAPIC_REG_REDIR 0x10
|
||||
|
||||
#define IOAPIC_REDIR_DEL_NOPRI (0x0 << 8)
|
||||
#define IOAPIC_REDIR_DEL_LOPRI (0x1 << 8)
|
||||
#define IOAPIC_REDIR_DEL_SMI (0x2 << 8)
|
||||
#define IOAPIC_REDIR_DEL_NMI (0x4 << 8)
|
||||
#define IOAPIC_REDIR_DEL_INIT (0x5 << 8)
|
||||
#define IOAPIC_REDIR_DEL_EXTI (0x7 << 8)
|
||||
|
||||
#define IOAPIC_REDIR_DST_LOG (1 << 11)
|
||||
|
||||
#define IOAPIC_REDIR_POL_LOW (1 << 13)
|
||||
|
||||
#define IOAPIC_REDIR_TRG_LEVEL (1 << 15)
|
||||
|
||||
#define IOAPIC_REDIR_MSK (1 << 16)
|
||||
|
||||
#define IOAPIC_REDIR_DST_SET(x) (((x) & 0xFF) << 24)
|
||||
#define IOAPIC_REDIR_DST_GET(x) (((uint32_t) x) >> 24)
|
||||
|
||||
// Base address of the two-register structure
|
||||
// 0 means "Not available"
|
||||
// [Virtual]
|
||||
extern uintptr_t amd64_ioapic_base;
|
||||
|
||||
uint32_t amd64_ioapic_read(uint8_t reg);
|
||||
void amd64_ioapic_write(uint8_t reg, uint32_t v);
|
||||
|
||||
// Set from reading the MADT
|
||||
void amd64_ioapic_set(uintptr_t addr);
|
||||
void amd64_ioapic_int_src_override(uint8_t bus, uint8_t src, uint32_t no, uint16_t flags);
|
||||
+3
-1
@@ -18,7 +18,9 @@ OBJS+=$(O)/sys/amd64/hw/rs232.o \
|
||||
$(O)/sys/amd64/hw/irq0.o \
|
||||
$(O)/sys/amd64/hw/ap_code_blob.o \
|
||||
$(O)/sys/amd64/hw/con.o \
|
||||
$(O)/sys/amd64/hw/timer.o
|
||||
$(O)/sys/amd64/hw/timer.o \
|
||||
$(O)/sys/amd64/hw/ioapic.o \
|
||||
$(O)/sys/amd64/hw/irqs_s.o
|
||||
|
||||
### From config
|
||||
ifdef AMD64_TRACE_IRQ
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "sys/amd64/hw/apic.h"
|
||||
#include "sys/amd64/hw/ioapic.h"
|
||||
#include "sys/amd64/hw/timer.h"
|
||||
#include "sys/amd64/hw/gdt.h"
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
@@ -50,6 +51,15 @@ struct acpi_ioapic_entry {
|
||||
uint32_t gsi_base;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_int_src_override_entry {
|
||||
struct acpi_apic_field_type hdr;
|
||||
|
||||
uint8_t bus_src;
|
||||
uint8_t irq_src;
|
||||
uint32_t gsi;
|
||||
uint16_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
/////
|
||||
|
||||
// LAPIC ID of the BSP CPU
|
||||
@@ -195,6 +205,18 @@ void amd64_apic_init(struct acpi_madt *madt) {
|
||||
// Get other LAPICs from MADT
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < madt->hdr.length - sizeof(struct acpi_madt)) {
|
||||
struct acpi_apic_field_type *ent_hdr = (struct acpi_apic_field_type *) &madt->entry[offset];
|
||||
if (ent_hdr->type == 1) {
|
||||
// Found I/O APIC
|
||||
struct acpi_ioapic_entry *ent = (struct acpi_ioapic_entry *) ent_hdr;
|
||||
amd64_ioapic_set(ent->ioapic_addr + 0xFFFFFF0000000000);
|
||||
}
|
||||
|
||||
offset += ent_hdr->length;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
while (offset < madt->hdr.length - sizeof(struct acpi_madt)) {
|
||||
struct acpi_apic_field_type *ent_hdr = (struct acpi_apic_field_type *) &madt->entry[offset];
|
||||
|
||||
@@ -207,7 +229,11 @@ void amd64_apic_init(struct acpi_madt *madt) {
|
||||
// Initiate wakeup sequence
|
||||
amd64_core_wakeup(ent->apic_id);
|
||||
}
|
||||
} else if (ent_hdr->type == 2) {
|
||||
struct acpi_int_src_override_entry *ent = (struct acpi_int_src_override_entry *) ent_hdr;
|
||||
amd64_ioapic_int_src_override(ent->bus_src, ent->irq_src, ent->gsi, ent->flags);
|
||||
}
|
||||
|
||||
offset += ent_hdr->length;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
#include "asm/asm_irq.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/types.h"
|
||||
|
||||
@@ -15,7 +16,6 @@
|
||||
#define IDT_FLG_P (1 << 7)
|
||||
|
||||
extern uintptr_t amd64_exception_vectors[32];
|
||||
extern void amd64_irq0(void);
|
||||
|
||||
static struct amd64_idt_entry {
|
||||
uint16_t base_lo;
|
||||
@@ -48,6 +48,7 @@ void amd64_idt_init(void) {
|
||||
amd64_idt_set(i, amd64_exception_vectors[i], 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
}
|
||||
amd64_idt_set(32, (uintptr_t) amd64_irq0, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
amd64_idt_set(33, (uintptr_t) amd64_irq1, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
|
||||
asm volatile ("lidt amd64_idtr(%rip)");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#include "sys/amd64/hw/ioapic.h"
|
||||
#include "sys/debug.h"
|
||||
|
||||
uintptr_t amd64_ioapic_base = 0;
|
||||
|
||||
// Legacy PIC -> I/O APIC routing table
|
||||
static uint32_t ioapic_leg_rt[16] = { 0xFFFFFFFF };
|
||||
|
||||
uint32_t amd64_ioapic_read(uint8_t reg) {
|
||||
if (!amd64_ioapic_base) {
|
||||
// TODO: panic
|
||||
kdebug("Reading non-existent I/O APIC\n");
|
||||
while (1);
|
||||
}
|
||||
uint32_t volatile *ioapic = (uint32_t volatile *) amd64_ioapic_base;
|
||||
ioapic[0] = (reg & 0xFF);
|
||||
return ioapic[4];
|
||||
}
|
||||
|
||||
void amd64_ioapic_write(uint8_t reg, uint32_t v) {
|
||||
if (!amd64_ioapic_base) {
|
||||
// TODO: panic
|
||||
kdebug("Writing non-existent I/O APIC\n");
|
||||
while (1);
|
||||
}
|
||||
uint32_t volatile *ioapic = (uint32_t volatile *) amd64_ioapic_base;
|
||||
ioapic[0] = reg & 0xFF;
|
||||
ioapic[4] = v;
|
||||
}
|
||||
|
||||
void amd64_ioapic_int_src_override(uint8_t bus_src, uint8_t irq_src, uint32_t no, uint16_t flags) {
|
||||
kdebug("IRQ Override: %02x:%02x -> %d\n", bus_src, irq_src, no);
|
||||
if (bus_src == 0 && irq_src < 16) {
|
||||
// Totally a legacy IRQ
|
||||
ioapic_leg_rt[irq_src] = no;
|
||||
}
|
||||
|
||||
// Setup flags properly
|
||||
uint32_t low = amd64_ioapic_read(0x10 + no * 2);
|
||||
|
||||
if (flags & (1 << 1)) {
|
||||
// Low-active IRQ
|
||||
low |= IOAPIC_REDIR_POL_LOW;
|
||||
} else {
|
||||
low &= ~IOAPIC_REDIR_POL_LOW;
|
||||
}
|
||||
|
||||
if (flags & (1 << 3)) {
|
||||
low |= IOAPIC_REDIR_TRG_LEVEL;
|
||||
} else {
|
||||
low &= ~IOAPIC_REDIR_TRG_LEVEL;
|
||||
}
|
||||
|
||||
amd64_ioapic_write(0x10 + no * 2, low);
|
||||
}
|
||||
|
||||
void amd64_ioapic_set(uintptr_t addr) {
|
||||
if (amd64_ioapic_base != 0) {
|
||||
// TODO: panic
|
||||
kdebug("I/O APIC base already set\n");
|
||||
while (1);
|
||||
}
|
||||
amd64_ioapic_base = addr;
|
||||
|
||||
kdebug("I/O APIC @ %p\n", addr);
|
||||
|
||||
// Dump the entries of I/O APIC
|
||||
|
||||
for (uint8_t i = 0x10; i < 0x3F; i += 2) {
|
||||
uint32_t low = amd64_ioapic_read(i + 0);
|
||||
uint32_t high = amd64_ioapic_read(i + 1);
|
||||
|
||||
static const char *del_type[] = {
|
||||
"Normal",
|
||||
"Low priority",
|
||||
"SMI",
|
||||
"???",
|
||||
"NMI",
|
||||
"INIT",
|
||||
"???",
|
||||
"EXTI"
|
||||
};
|
||||
|
||||
kdebug("[%d] %s, %s, DST 0x%02x:0x%02x\n",
|
||||
i,
|
||||
(low & IOAPIC_REDIR_MSK) ? "Masked" : "",
|
||||
del_type[(low >> 8) & 0x7],
|
||||
IOAPIC_REDIR_DST_GET(high),
|
||||
low & 0xF);
|
||||
}
|
||||
|
||||
// Test: set IRQ1 -> LAPIC 0:1 and unmask it
|
||||
uint32_t low = amd64_ioapic_read(0x10 + 1 * 2);
|
||||
uint32_t high = amd64_ioapic_read(0x11 + 1 * 2);
|
||||
|
||||
low &= ~0x7;
|
||||
low &= ~IOAPIC_REDIR_MSK;
|
||||
|
||||
low |= 0x1 + 0x20;
|
||||
high = IOAPIC_REDIR_DST_SET(0);
|
||||
|
||||
amd64_ioapic_write(0x10 + 1 * 2, low);
|
||||
amd64_ioapic_write(0x11 + 1 * 2, high);
|
||||
}
|
||||
@@ -22,23 +22,3 @@ amd64_irq0:
|
||||
|
||||
irq_pop_ctx
|
||||
iretq
|
||||
|
||||
#if defined(AMD64_STACK_CTX_CANARY)
|
||||
amd64_kstack_canary_invalid:
|
||||
// This means we somehow managed to fuck up
|
||||
// Context's kernel stack and were going to
|
||||
// pop nonsense and iret would be fatal.
|
||||
|
||||
// TODO: guess it would be just better to panic
|
||||
// than to halt one CPU
|
||||
xorq %rdi, %rdi
|
||||
leaq _msg0(%rip), %rsi
|
||||
call debugs
|
||||
1:
|
||||
cli
|
||||
hlt
|
||||
jmp 1b
|
||||
|
||||
_msg0:
|
||||
.string "Stack fuckup detected: halting\n"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Temporary file where I play with
|
||||
// Generic IRQ handlers
|
||||
#include "asm/asm_irq.h"
|
||||
|
||||
.section .text
|
||||
|
||||
// This is keyboard
|
||||
// Can be either entered from a legacy PIT IRQ
|
||||
// Or is mapped in I/O APIC
|
||||
.global amd64_irq1
|
||||
amd64_irq1:
|
||||
cli
|
||||
|
||||
irq_push_ctx
|
||||
movq %rsp, %rbp
|
||||
|
||||
irq_trace 1
|
||||
|
||||
// Read from keyboard buffer
|
||||
inb $0x60, %al
|
||||
|
||||
irq_eoi_lapic 1
|
||||
|
||||
irq_pop_ctx
|
||||
|
||||
iretq
|
||||
|
||||
.global amd64_kstack_canary_invalid
|
||||
#if defined(AMD64_STACK_CTX_CANARY)
|
||||
amd64_kstack_canary_invalid:
|
||||
// This means we somehow managed to fuck up
|
||||
// Context's kernel stack and were going to
|
||||
// pop nonsense and iret would be fatal.
|
||||
|
||||
// TODO: guess it would be just better to panic
|
||||
// than to halt one CPU
|
||||
xorq %rdi, %rdi
|
||||
leaq _msg0(%rip), %rsi
|
||||
call debugs
|
||||
1:
|
||||
cli
|
||||
hlt
|
||||
jmp 1b
|
||||
|
||||
_msg0:
|
||||
.string "Stack fuckup detected: halting\n"
|
||||
#endif
|
||||
Reference in New Issue
Block a user