aarch64: start work on interrupt dispatch
This commit is contained in:
parent
8c7e6209f4
commit
a72352d163
@ -152,25 +152,31 @@ void timer_start(void) {
|
||||
/* mask irqs */
|
||||
asm volatile ("msr DAIFSet, #0b1111");
|
||||
|
||||
/* Enable one of the timers. */
|
||||
/* Enable the local timer */
|
||||
set_tick();
|
||||
|
||||
asm volatile (
|
||||
"mov x0, 1\n"
|
||||
"msr CNTV_CTL_EL0, x0\n"
|
||||
:::"x0");
|
||||
|
||||
/* enable */
|
||||
/* This is global, we only need to do this once... */
|
||||
gic_regs[0] = 1;
|
||||
|
||||
/* This is specific to this CPU */
|
||||
gicc_regs[0] = 1;
|
||||
gicc_regs[1] = 0x1ff;
|
||||
|
||||
/* priority mask */
|
||||
gicc_regs[1] = 0xff;
|
||||
/* Timer interrupts are private peripherals, so each CPU gets one */
|
||||
gic_regs[64] = 0xFFFFffff; //(1 << TIMER_IRQ);
|
||||
gic_regs[160] = 0xFFFFffff; //(1 << TIMER_IRQ);
|
||||
|
||||
/* enable interrupts */
|
||||
gic_regs[64] = (1 << TIMER_IRQ);
|
||||
/* These are shared? */
|
||||
gic_regs[65] = 0xFFFFFFFF;
|
||||
|
||||
/* clear this one */
|
||||
gic_regs[160] = (1 << TIMER_IRQ);
|
||||
for (int i = 520; i <= 521; ++i) {
|
||||
gic_regs[i] |= 0x07070707;
|
||||
}
|
||||
}
|
||||
|
||||
static volatile uint64_t time_slice_basis = 0; /**< When the last clock update happened */
|
||||
@ -307,36 +313,82 @@ void aarch64_sync_enter(struct regs * r) {
|
||||
}
|
||||
|
||||
/* Unexpected fault, eg. page fault. */
|
||||
printf("In process %d (%s)\n", this_core->current_process->id, this_core->current_process->name);
|
||||
printf("ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n", esr, far, elr, spsr);
|
||||
dprintf("In process %d (%s)\n", this_core->current_process->id, this_core->current_process->name);
|
||||
dprintf("ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n", esr, far, elr, spsr);
|
||||
aarch64_regs(r);
|
||||
uint64_t tpidr_el0;
|
||||
asm volatile ("mrs %0, TPIDR_EL0" : "=r"(tpidr_el0));
|
||||
printf(" TPIDR_EL0=%#zx\n", tpidr_el0);
|
||||
dprintf(" TPIDR_EL0=%#zx\n", tpidr_el0);
|
||||
|
||||
send_signal(this_core->current_process->id, SIGSEGV, 1);
|
||||
}
|
||||
|
||||
void aarch64_irq_enter(struct regs * r) {
|
||||
uint32_t pending = gic_regs[160];
|
||||
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];
|
||||
uint32_t irq = iar & 0x3FF;
|
||||
//uint32_t cpu = (iar >> 10) & 0x7;
|
||||
|
||||
switch (irq) {
|
||||
case TIMER_IRQ:
|
||||
update_clock();
|
||||
set_tick();
|
||||
EOI(iar);
|
||||
if (from_wfi) {
|
||||
switch_next();
|
||||
} else {
|
||||
switch_task(1);
|
||||
}
|
||||
return;
|
||||
|
||||
case 32:
|
||||
case 33:
|
||||
case 34:
|
||||
case 35:
|
||||
case 36:
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
{
|
||||
struct irq_callback * cb = &irq_callbacks[irq-32];
|
||||
if (cb->owner) {
|
||||
cb->callback(cb->owner, irq-32, cb->data);
|
||||
}
|
||||
EOI(iar);
|
||||
return;
|
||||
}
|
||||
|
||||
case 1022:
|
||||
case 1023:
|
||||
return;
|
||||
|
||||
default:
|
||||
dprintf("gic: Unhandled interrupt: %d\n", irq);
|
||||
EOI(iar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void aarch64_irq_enter(struct regs * r) {
|
||||
if (this_core->current_process) {
|
||||
this_core->current_process->time_switch = arch_perf_timer();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO port the interrupt management system from x86.
|
||||
*/
|
||||
if (pending & (1 << TIMER_IRQ)) {
|
||||
/* Timer interrupt fired in EL0. Update the global clock and reschedule */
|
||||
update_clock();
|
||||
set_tick();
|
||||
gic_regs[160] &= (1 << TIMER_IRQ);
|
||||
switch_task(1);
|
||||
} else if (pending) {
|
||||
printf("Unexpected interrupt = %#x\n", pending);
|
||||
arch_fatal();
|
||||
}
|
||||
aarch64_interrupt_dispatch(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -349,14 +401,14 @@ void aarch64_fault_enter(struct regs * r) {
|
||||
asm volatile ("mrs %0, ELR_EL1" : "=r"(elr));
|
||||
asm volatile ("mrs %0, SPSR_EL1" : "=r"(spsr));
|
||||
|
||||
printf("EL1-EL1 fault handler, core %d\n", this_core->cpu_id);
|
||||
printf("In process %d (%s)\n", this_core->current_process->id, this_core->current_process->name);
|
||||
printf("ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n", esr, far, elr, spsr);
|
||||
dprintf("EL1-EL1 fault handler, core %d\n", this_core->cpu_id);
|
||||
dprintf("In process %d (%s)\n", this_core->current_process->id, this_core->current_process->name);
|
||||
dprintf("ESR: %#zx FAR: %#zx ELR: %#zx SPSR: %#zx\n", esr, far, elr, spsr);
|
||||
aarch64_regs(r);
|
||||
|
||||
uint64_t tpidr_el0;
|
||||
asm volatile ("mrs %0, TPIDR_EL0" : "=r"(tpidr_el0));
|
||||
printf(" TPIDR_EL0=%#zx\n", tpidr_el0);
|
||||
dprintf(" TPIDR_EL0=%#zx\n", tpidr_el0);
|
||||
|
||||
extern void aarch64_safe_dump_traceback(uintptr_t elr, struct regs * r);
|
||||
aarch64_safe_dump_traceback(elr, r);
|
||||
@ -387,21 +439,7 @@ void arch_pause(void) {
|
||||
* the interrupt function won't be called, so we'll need to change
|
||||
* it once we start getting actual hardware interrupts. */
|
||||
asm volatile ("wfi");
|
||||
|
||||
/* Update the clock and reset the timer */
|
||||
update_clock();
|
||||
set_tick();
|
||||
|
||||
/* This shouldn't happen now, but this symbol needs to be present
|
||||
* somewhere or we'll fail to link. Keeping it as the asm stub
|
||||
* for future use... */
|
||||
asm volatile (
|
||||
".globl _ret_from_preempt_source\n"
|
||||
"_ret_from_preempt_source:"
|
||||
);
|
||||
|
||||
/* Force reschedule */
|
||||
switch_next();
|
||||
aarch64_interrupt_dispatch(1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,17 @@
|
||||
#include <kernel/mouse.h>
|
||||
#include <kernel/time.h>
|
||||
|
||||
#include <kernel/arch/aarch64/dtb.h>
|
||||
|
||||
static uint32_t swizzle(uint32_t from) {
|
||||
uint8_t a = from >> 24;
|
||||
uint8_t b = from >> 16;
|
||||
uint8_t c = from >> 8;
|
||||
uint8_t d = from;
|
||||
return (d << 24) | (c << 16) | (b << 8) | (a);
|
||||
}
|
||||
|
||||
|
||||
static fs_node_t * mouse_pipe;
|
||||
static fs_node_t * vmmouse_pipe;
|
||||
static fs_node_t * keyboard_pipe;
|
||||
@ -99,18 +110,112 @@ 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) {
|
||||
uint8_t cause = *(volatile uint8_t *)data;
|
||||
if (cause == 1) {
|
||||
make_process_ready(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard_responder(process_t * this, int irq, void * data) {
|
||||
uint8_t cause = *(volatile uint8_t *)data;
|
||||
if (cause == 1) {
|
||||
make_process_ready(this);
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void virtio_tablet_thread(void * data) {
|
||||
while (this_core->cpu_id != 0) switch_task(1);
|
||||
|
||||
uint32_t device = (uintptr_t)data;
|
||||
uintptr_t t = 0x12000000;
|
||||
pci_write_field(device, PCI_BAR4, 4, t|8);
|
||||
pci_write_field(device, PCI_COMMAND, 2, 4|2|1);
|
||||
|
||||
uint8_t caps = pci_read_field(device, 0x34, 1) & 0xFC;
|
||||
dprintf("virtio: capabilities at 0x%02x\n", caps);
|
||||
|
||||
if (caps) {
|
||||
uint8_t next = caps;
|
||||
do {
|
||||
uint8_t cap_id = pci_read_field(device, next, 1);
|
||||
dprintf("@%d cap %d\n", next, cap_id);
|
||||
if (cap_id == 9) {
|
||||
/* vendor cap */
|
||||
uint8_t len = pci_read_field(device, next+2, 1);
|
||||
uint8_t type = pci_read_field(device, next+3, 1);
|
||||
uint8_t bar = pci_read_field(device, next+4, 1);
|
||||
uint32_t off = pci_read_field(device, next+8, 4);
|
||||
|
||||
dprintf("len=%d type=%d bar=%d off=%#x\n",
|
||||
len, type, bar, off);
|
||||
|
||||
}
|
||||
next = pci_read_field(device, next+1, 1);
|
||||
} while (next);
|
||||
}
|
||||
|
||||
struct virtio_device_cfg * cfg = (void*)((char*)mmu_map_mmio_region(t + 0x2000, 0x1000));
|
||||
cfg->select = 1; /* ask for name */
|
||||
cfg->subsel = 0;
|
||||
asm volatile ("isb" ::: "memory");
|
||||
dprintf("virtio: found '%s'\n", cfg->data.str);
|
||||
|
||||
volatile char * irq_region = (char*)mmu_map_mmio_region(t + 0x1000, 0x1000);
|
||||
int irq;
|
||||
map_interrupt("virtio-tablet", device, &irq, tablet_responder, irq_region);
|
||||
dprintf("virtio-tablet: irq is %d\n", irq);
|
||||
|
||||
/* figure out range values */
|
||||
cfg->select = 0x12;
|
||||
cfg->subsel = 0; /* X */
|
||||
@ -184,9 +289,6 @@ static void virtio_tablet_thread(void * data) {
|
||||
while (1) {
|
||||
/* Inform the device we have room */
|
||||
while (queue->used.index == index) {
|
||||
unsigned long s, ss;
|
||||
relative_time(0, 100, &s, &ss);
|
||||
sleep_until((process_t *)this_core->current_process, s, ss);
|
||||
switch_task(0);
|
||||
}
|
||||
|
||||
@ -265,8 +367,9 @@ static const uint8_t ext_key_map[256] = {
|
||||
|
||||
static void virtio_keyboard_thread(void * data) {
|
||||
while (this_core->cpu_id != 0) switch_task(1);
|
||||
|
||||
uint32_t device = (uintptr_t)data;
|
||||
uintptr_t t = 0x12000000;
|
||||
uintptr_t t = 0x12100000;
|
||||
pci_write_field(device, PCI_BAR4, 4, t|8);
|
||||
pci_write_field(device, PCI_COMMAND, 2, 4|2|1);
|
||||
struct virtio_device_cfg * cfg = (void*)((char*)mmu_map_mmio_region(t + 0x2000, 0x1000));
|
||||
@ -275,6 +378,11 @@ static void virtio_keyboard_thread(void * data) {
|
||||
asm volatile ("isb" ::: "memory");
|
||||
dprintf("virtio: found '%s'\n", cfg->data.str);
|
||||
|
||||
volatile char * irq_region = (char*)mmu_map_mmio_region(t + 0x1000, 0x1000);
|
||||
int irq;
|
||||
map_interrupt("virtio-keyboard", device, &irq, keyboard_responder, irq_region);
|
||||
dprintf("virtio-keyboard: irq is %d\n", irq);
|
||||
|
||||
cfg->select = 0;
|
||||
cfg->subsel = 0;
|
||||
asm volatile ("isb" ::: "memory");
|
||||
@ -327,9 +435,6 @@ static void virtio_keyboard_thread(void * data) {
|
||||
while (1) {
|
||||
/* Inform the device we have room */
|
||||
while (queue->used.index == index) {
|
||||
unsigned long s, ss;
|
||||
relative_time(0, 100, &s, &ss);
|
||||
sleep_until((process_t *)this_core->current_process, s, ss);
|
||||
switch_task(0);
|
||||
}
|
||||
|
||||
@ -394,11 +499,11 @@ void virtio_input(void) {
|
||||
vmmouse_pipe->flags = FS_CHARDEVICE;
|
||||
vfs_mount("/dev/vmmouse", vmmouse_pipe);
|
||||
|
||||
pci_scan(virtio_input_maybe, -1, NULL);
|
||||
|
||||
keyboard_pipe = make_pipe(128);
|
||||
keyboard_pipe->flags = FS_CHARDEVICE;
|
||||
vfs_mount("/dev/kbd", keyboard_pipe);
|
||||
|
||||
pci_scan(virtio_input_maybe, -1, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user