X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/28c176b668c841a3b7fb093faccf0efa39257603..HEAD:/lunaix-os/arch/x86/hal/apic.c diff --git a/lunaix-os/arch/x86/hal/apic.c b/lunaix-os/arch/x86/hal/apic.c index 4e2501f..8e9a013 100644 --- a/lunaix-os/arch/x86/hal/apic.c +++ b/lunaix-os/arch/x86/hal/apic.c @@ -9,26 +9,87 @@ * */ -#include "sys/x86_isa.h" -#include +#include "asm/x86.h" +#include "asm/x86_cpu.h" +#include "asm/soc/apic.h" -#include "sys/apic.h" -#include +#include #include #include #include +#include + +#include +#include #include "pic.h" LOG_MODULE("APIC") +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 +#define IOAPIC_IOREDTBL_BASE 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 + +#define IOAPIC_DELMOD_FIXED 0b000 +#define IOAPIC_DELMOD_LPRIO 0b001 +#define IOAPIC_DELMOD_NMI 0b100 + +#define IOAPIC_MASKED (1 << 16) +#define IOAPIC_TRIG_LEVEL (1 << 15) +#define IOAPIC_INTPOL_L (1 << 13) +#define IOAPIC_DESTMOD_LOGIC (1 << 11) + +#define IOAPIC_BASE_VADDR 0x2000 + +#define IOAPIC_REG_SEL *((volatile u32_t*)(_ioapic_base + IOAPIC_IOREGSEL)) +#define IOAPIC_REG_WIN *((volatile u32_t*)(_ioapic_base + IOAPIC_IOWIN)) + + +#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector) + +// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think +// it is too early for that +// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14) +#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE) +#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector) + + +static volatile ptr_t _ioapic_base; static volatile ptr_t _apic_base; void -apic_setup_lvts(); +apic_write_reg(unsigned int reg, unsigned int val) +{ + *(unsigned int*)(_apic_base + reg) = val; +} void +apic_ack_interrupt(irq_t irq) +{ + *(unsigned int*)(_apic_base + APIC_EOI) = 0; +} + +unsigned int +apic_read_reg(unsigned int reg) +{ + return *(unsigned int*)(_apic_base + (reg)); +} + + +static void +apic_setup_lvts() +{ + apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV)); + apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1); + apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV)); +} + +static void apic_init() { // ensure that external interrupt is disabled @@ -43,7 +104,7 @@ apic_init() // As we are going to use APIC, disable the old 8259 PIC pic_disable(); - _apic_base = (ptr_t)ioremap(__APIC_BASE_PADDR, 4096); + _apic_base = ioremap(__APIC_BASE_PADDR, 4096); // Hardware enable the APIC // By setting bit 11 of IA32_APIC_BASE register @@ -85,40 +146,109 @@ apic_init() apic_write_reg(APIC_SPIVR, spiv); } -#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector) +static void +ioapic_init() +{ + acpi_context* acpi_ctx = acpi_get_context(); -// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think -// it is too early for that -// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14) -#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE) -#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector) + _ioapic_base = + ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096); +} -void -apic_setup_lvts() +static void +ioapic_write(u8_t sel, u32_t val) { - apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV)); - apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1); - apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV)); + IOAPIC_REG_SEL = sel; + IOAPIC_REG_WIN = val; } -void -apic_on_eoi(struct x86_intc* intc_ctx, cpu_t cpu, int iv) +static u32_t +ioapic_read(u8_t sel) { - // for all external interrupts except the spurious interrupt - // this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5 - if (iv >= IV_EX_BEGIN && iv != APIC_SPIV_IV) { - *(unsigned int*)(_apic_base + APIC_EOI) = 0; + IOAPIC_REG_SEL = sel; + return IOAPIC_REG_WIN; +} + +static void +__ioapic_install_line(struct irq_domain *domain, irq_t irq) +{ + struct irq_line_wire *line; + u8_t reg_sel; + u32_t ioapic_fg; + + line = irq->line; + reg_sel = IOAPIC_IOREDTBL_BASE + line->domain_mapped * 2; + ioapic_fg = IOAPIC_DELMOD_FIXED; + + // Write low 32 bits + ioapic_write(reg_sel, (irq->vector | ioapic_fg) & 0x1FFFF); + + // Write high 32 bits + ioapic_write(reg_sel + 1, 0); +} + +static int +__ioapic_translate_irq(struct irq_domain *domain, irq_t irq, void *irq_extra) +{ + struct irq_line_wire *line; + + if (irq->type == IRQ_LINE) { + line = irq->line; + line->domain_mapped = acpi_gsimap(line->domain_local); } + + return 0; } -unsigned int -apic_read_reg(unsigned int reg) +static int +__ioapic_install_irq(struct irq_domain *domain, irq_t irq) { - return *(unsigned int*)(_apic_base + (reg)); + if (irq->vector == IRQ_VECTOR_UNSET) { + irq->vector = btrie_map(&domain->irq_map, IV_EX_BEGIN, IV_EX_END, irq); + } + else { + irq_record(domain, irq); + } + + if (irq->type == IRQ_MESSAGE) { + irq->msi->wr_addr = __APIC_BASE_PADDR; + } + else { + __ioapic_install_line(domain, irq); + } + + return 0; } -void -apic_write_reg(unsigned int reg, unsigned int val) + +static struct irq_domain_ops apic_domain_ops = { + .map_irq = __ioapic_translate_irq, + .install_irq = __ioapic_install_irq +}; + +static int +apic_device_create(struct device_def* def, morph_t* morph) { - *(unsigned int*)(_apic_base + reg) = val; -} \ No newline at end of file + int err; + struct device* dev; + struct irq_domain* domain; + + apic_init(); + ioapic_init(); + + dev = device_allocsys(NULL, NULL); + domain = irq_create_domain(dev, &apic_domain_ops); + + irq_set_default_domain(domain); + register_device(dev, &def->class, "apic"); + irq_attach_domain(NULL, domain); + + return 0; +} + +static struct device_def apic_devdef = { + def_device_class(INTEL, CFG, INTC), + def_device_name("x86 APIC"), + def_on_create(apic_device_create) +}; +EXPORT_DEVICE(x86_apic, &apic_devdef, load_sysconf); \ No newline at end of file