aarch64: interrupt mapping improvements, chained interrupt handlers
This commit is contained in:
parent
b95f27dc60
commit
f6d0206059
15
base/usr/include/kernel/arch/aarch64/gic.h
Normal file
15
base/usr/include/kernel/arch/aarch64/gic.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/process.h>
|
||||
|
||||
struct irq_callback {
|
||||
int (*callback)(process_t * this, int irq, void *data);
|
||||
process_t * owner;
|
||||
void * data;
|
||||
struct irq_callback * next;
|
||||
};
|
||||
|
||||
extern struct irq_callback * irq_callbacks[];
|
||||
|
||||
void gic_assign_interrupt(int irq, int (*callback)(process_t*,int,void*), void * data);
|
||||
void gic_map_pci_interrupt(const char * name, uint32_t device, int * int_out, int (*callback)(process_t*,int,void*), void * isr_addr);
|
87
kernel/arch/aarch64/gic.c
Normal file
87
kernel/arch/aarch64/gic.c
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file kernel/arch/aarch64/virtio.c
|
||||
* @brief Rudimentary, hacky implementations of virtio input devices.
|
||||
*
|
||||
* @copyright
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2021-2022 K. Lange
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <kernel/printf.h>
|
||||
#include <kernel/string.h>
|
||||
#include <kernel/pci.h>
|
||||
#include <kernel/process.h>
|
||||
#include <kernel/spinlock.h>
|
||||
|
||||
#include <kernel/arch/aarch64/dtb.h>
|
||||
#include <kernel/arch/aarch64/gic.h>
|
||||
|
||||
struct irq_callback * irq_callbacks[256] = {0};
|
||||
|
||||
static spin_lock_t irq_acquire;
|
||||
|
||||
void gic_assign_interrupt(int irq, int (*callback)(process_t*,int,void*), void * data) {
|
||||
spin_lock(irq_acquire);
|
||||
dprintf("gic: assign irq %d\n", irq);
|
||||
struct irq_callback * cb = calloc(sizeof(struct irq_callback),1);
|
||||
|
||||
cb->callback = callback;
|
||||
cb->owner = (process_t*)this_core->current_process;
|
||||
cb->data = data;
|
||||
cb->next = NULL;
|
||||
|
||||
if (irq_callbacks[irq]) {
|
||||
dprintf("gic: irq %d has an assignment, finding end of chain\n", irq);
|
||||
struct irq_callback * parent = irq_callbacks[irq];
|
||||
while (parent->next) {
|
||||
parent = parent->next;
|
||||
}
|
||||
parent->next = cb;
|
||||
} else {
|
||||
dprintf("gic: irq %d is new\n", irq);
|
||||
irq_callbacks[irq] = cb;
|
||||
}
|
||||
|
||||
spin_unlock(irq_acquire);
|
||||
}
|
||||
|
||||
void gic_map_pci_interrupt(const char * name, uint32_t device, int * int_out, int (*callback)(process_t*,int,void*), void * isr_addr) {
|
||||
uint32_t phys_hi = (pci_extract_bus(device) << 16) | (pci_extract_slot(device) << 11);
|
||||
uint32_t pin = pci_read_field(device, PCI_INTERRUPT_PIN, 1);
|
||||
dprintf("%s: device %#x, slot = %d (0x%04x), irq pin = %d\n", name, device, pci_extract_slot(device),
|
||||
phys_hi, pin);
|
||||
|
||||
uint32_t * pcie_dtb = dtb_find_node_prefix("pcie@");
|
||||
if (!pcie_dtb) {
|
||||
dprintf("%s: can't find dtb entry\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t * intMask = dtb_node_find_property(pcie_dtb, "interrupt-map-mask");
|
||||
if (!intMask) {
|
||||
dprintf("%s: can't find property 'interrupt-map-mask'\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t * intMap = dtb_node_find_property(pcie_dtb, "interrupt-map");
|
||||
|
||||
if (!intMap) {
|
||||
dprintf("%s: can't find property 'interrupt-map'\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)swizzle(intMap[0])/4; i += 10) {
|
||||
if (swizzle(intMap[i+2]) == (swizzle(intMask[2]) & phys_hi)) {
|
||||
if (swizzle(intMap[i+5]) == (swizzle(intMask[5]) & pin)) {
|
||||
dprintf("%s: %#x %#x %#x %#x\n", name,
|
||||
swizzle(intMap[i+2]), swizzle(intMap[i+3]), swizzle(intMap[i+4]), swizzle(intMap[i+5]));
|
||||
dprintf("%s: Matching device and pin, Interrupt maps to %d\n", name, swizzle(intMap[i+10]));
|
||||
*int_out = swizzle(intMap[i+10]);
|
||||
gic_assign_interrupt(*int_out, callback, isr_addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <kernel/arch/aarch64/regs.h>
|
||||
#include <kernel/arch/aarch64/dtb.h>
|
||||
#include <kernel/arch/aarch64/gic.h>
|
||||
|
||||
extern void fbterm_initialize(void);
|
||||
extern void mmu_init(size_t memsize, size_t phys, uintptr_t firstFreePage, uintptr_t endOfInitrd);
|
||||
@ -324,14 +325,6 @@ void aarch64_sync_enter(struct regs * r) {
|
||||
|
||||
char _ret_from_preempt_source[1];
|
||||
|
||||
struct irq_callback {
|
||||
void (*callback)(process_t * this, int irq, void *data);
|
||||
process_t * owner;
|
||||
void * data;
|
||||
};
|
||||
|
||||
extern struct irq_callback irq_callbacks[];
|
||||
|
||||
#define EOI(x) do { gicc_regs[4] = (x); } while (0)
|
||||
static void aarch64_interrupt_dispatch(int from_wfi) {
|
||||
uint32_t iar = gicc_regs[3];
|
||||
@ -362,9 +355,14 @@ static void aarch64_interrupt_dispatch(int from_wfi) {
|
||||
case 41:
|
||||
case 42:
|
||||
{
|
||||
struct irq_callback * cb = &irq_callbacks[irq-32];
|
||||
if (cb->owner) {
|
||||
cb->callback(cb->owner, irq-32, cb->data);
|
||||
struct irq_callback * cb = irq_callbacks[irq-32];
|
||||
if (cb) {
|
||||
while (cb) {
|
||||
int res = cb->callback(cb->owner, irq-32, cb->data);
|
||||
if (res) break;
|
||||
cb = cb->next;
|
||||
}
|
||||
/* Maybe warn? We have a lot of spurious irqs, though */
|
||||
} else {
|
||||
dprintf("irq: unhandled irq %d\n", irq);
|
||||
}
|
||||
|
@ -15,23 +15,19 @@
|
||||
#include <kernel/mmu.h>
|
||||
|
||||
#include <kernel/arch/aarch64/dtb.h>
|
||||
#include <kernel/arch/aarch64/gic.h>
|
||||
|
||||
/* TODO interrupt handler installers */
|
||||
struct irq_callback {
|
||||
void (*callback)(process_t * this, int irq, void *data);
|
||||
process_t * owner;
|
||||
void * data;
|
||||
};
|
||||
|
||||
extern struct irq_callback irq_callbacks[];
|
||||
|
||||
static void pl011_irq(process_t * this, int irq, void * data) {
|
||||
static int pl011_irq(process_t * this, int irq, void * data) {
|
||||
volatile uint32_t * uart_mapped = (volatile uint32_t *)data;
|
||||
uint32_t mis = uart_mapped[16];
|
||||
if (mis & (1 << 4)) {
|
||||
make_process_ready(this);
|
||||
if (mis) {
|
||||
if (mis & (1 << 4)) {
|
||||
make_process_ready(this);
|
||||
}
|
||||
uart_mapped[17] = mis;
|
||||
return 1;
|
||||
}
|
||||
uart_mapped[17] = mis;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pl011_fill_name(pty_t * pty, char * name) {
|
||||
@ -54,9 +50,7 @@ static void pl011_thread(void * arg) {
|
||||
vfs_mount("/dev/ttyS0", pty->slave);
|
||||
|
||||
/* Set up interrupt callback */
|
||||
irq_callbacks[1].callback = pl011_irq;
|
||||
irq_callbacks[1].owner = (process_t*)this_core->current_process;
|
||||
irq_callbacks[1].data = (void *)uart_mapped;
|
||||
gic_assign_interrupt(1, pl011_irq, (void*)uart_mapped);
|
||||
|
||||
/* Enable interrupts */
|
||||
uart_mapped[12] = 0;
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <kernel/mouse.h>
|
||||
#include <kernel/time.h>
|
||||
|
||||
#include <kernel/arch/aarch64/dtb.h>
|
||||
#include <kernel/arch/aarch64/gic.h>
|
||||
|
||||
static fs_node_t * mouse_pipe;
|
||||
static fs_node_t * vmmouse_pipe;
|
||||
@ -101,68 +101,22 @@ struct virtio_input_event {
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
struct irq_callback {
|
||||
void (*callback)(process_t * this, int irq, void *data);
|
||||
process_t * owner;
|
||||
void * data;
|
||||
};
|
||||
|
||||
struct irq_callback irq_callbacks[256];
|
||||
|
||||
static void tablet_responder(process_t * this, int irq, void * data) {
|
||||
static int tablet_responder(process_t * this, int irq, void * data) {
|
||||
uint8_t cause = *(volatile uint8_t *)data;
|
||||
if (cause == 1) {
|
||||
make_process_ready(this);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keyboard_responder(process_t * this, int irq, void * data) {
|
||||
static int keyboard_responder(process_t * this, int irq, void * data) {
|
||||
uint8_t cause = *(volatile uint8_t *)data;
|
||||
if (cause == 1) {
|
||||
make_process_ready(this);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void map_interrupt(const char * name, uint32_t device, int * int_out, void (*callback)(process_t*,int,void*), void * isr_addr) {
|
||||
uint32_t phys_hi = (pci_extract_bus(device) << 16) | (pci_extract_slot(device) << 11);
|
||||
uint32_t pin = pci_read_field(device, PCI_INTERRUPT_PIN, 1);
|
||||
dprintf("%s: device %#x, slot = %d (0x%04x), irq pin = %d\n", name, device, pci_extract_slot(device),
|
||||
phys_hi, pin);
|
||||
|
||||
uint32_t * pcie_dtb = dtb_find_node_prefix("pcie@");
|
||||
if (!pcie_dtb) {
|
||||
dprintf("%s: can't find dtb entry\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t * intMask = dtb_node_find_property(pcie_dtb, "interrupt-map-mask");
|
||||
if (!intMask) {
|
||||
dprintf("%s: can't find property 'interrupt-map-mask'\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t * intMap = dtb_node_find_property(pcie_dtb, "interrupt-map");
|
||||
|
||||
if (!intMap) {
|
||||
dprintf("%s: can't find property 'interrupt-map'\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < swizzle(intMap[0])/4; i += 10) {
|
||||
if (swizzle(intMap[i+2]) == (swizzle(intMask[2]) & phys_hi)) {
|
||||
if (swizzle(intMap[i+5]) == (swizzle(intMask[5]) & pin)) {
|
||||
dprintf("%s: %#x %#x %#x %#x\n", name,
|
||||
swizzle(intMap[i+2]), swizzle(intMap[i+3]), swizzle(intMap[i+4]), swizzle(intMap[i+5]));
|
||||
dprintf("%s: Matching device and pin, Interrupt maps to %d\n", name, swizzle(intMap[i+10]));
|
||||
*int_out = swizzle(intMap[i+10]);
|
||||
irq_callbacks[*int_out].callback = callback;
|
||||
irq_callbacks[*int_out].owner = this_core->current_process;
|
||||
irq_callbacks[*int_out].data = isr_addr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_tablet_thread(void * data) {
|
||||
@ -204,7 +158,7 @@ static void virtio_tablet_thread(void * data) {
|
||||
|
||||
volatile char * irq_region = (char*)mmu_map_mmio_region(t + 0x1000, 0x1000);
|
||||
int irq;
|
||||
map_interrupt("virtio-tablet", device, &irq, tablet_responder, irq_region);
|
||||
gic_map_pci_interrupt("virtio-tablet", device, &irq, tablet_responder, irq_region);
|
||||
dprintf("virtio-tablet: irq is %d\n", irq);
|
||||
|
||||
/* figure out range values */
|
||||
@ -371,7 +325,7 @@ static void virtio_keyboard_thread(void * data) {
|
||||
|
||||
volatile char * irq_region = (char*)mmu_map_mmio_region(t + 0x1000, 0x1000);
|
||||
int irq;
|
||||
map_interrupt("virtio-keyboard", device, &irq, keyboard_responder, irq_region);
|
||||
gic_map_pci_interrupt("virtio-keyboard", device, &irq, keyboard_responder, irq_region);
|
||||
dprintf("virtio-keyboard: irq is %d\n", irq);
|
||||
|
||||
cfg->select = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user