Add support for I/O APIC with testing kb mapping

This commit is contained in:
Mark
2019-10-10 16:40:19 +03:00
parent e0039376f3
commit 75d48ffdbc
8 changed files with 222 additions and 22 deletions
+4
View File
@@ -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
+36
View File
@@ -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
View File
@@ -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
+26
View File
@@ -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
View File
@@ -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)");
}
+104
View File
@@ -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);
}
-20
View File
@@ -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
+47
View File
@@ -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