#pypp 0 // Iris: micro-kernel for a capability-based operating system. // mips/interrupts.ccp: Functions called by mips/entry.S. // Copyright 2009 Bas Wijnen // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #define ARCH #include "../kernel.hh" /// A TLB miss has occurred. This is the slow version. It is only used /// when k0 or k1 is not 0, or when an error occurs. /// Otherwise, the ultra-fast code in entry.S is used. Thread *tlb_refill (): //panic (0x88776655, "TLB refill") if !directory: panic (0x44449999, "No directory") unsigned EntryHi cp0_get (CP0_ENTRY_HI, EntryHi) unsigned *t = directory[EntryHi >> 21] if !t: unsigned a cp0_get (CP0_EPC, a) dbg_send (a) cp0_get (CP0_BAD_V_ADDR, a) dbg_send (a) panic (0x99992222, "No page table") // - 2 instead of - 1 means reset bit 0 unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2) cp0_set (CP0_ENTRY_LO0, t[idx]) cp0_set (CP0_ENTRY_LO1, t[idx + 1]) __asm__ volatile ("tlbwr") return current /// An interrupt which is not an exception has occurred. Thread *interrupt (): //panic (0x88877722, "Interrupt") //dbg_send (INTC_IPR) unsigned ipr = INTC_IPR for unsigned i = 0; i < 32; ++i: if ipr & (1 << i): // Handle timer interrupts specially: don't disable them. if i == IRQ_OST0: continue // Disable the interrupt while handling it. intc_mask_irq (i) intc_ack_irq (i) // Send message to interrupt handler. if arch_interrupt_receiver[i]: Capability::Context c for unsigned j = 0; j < 4; ++j: c.data[j] = 0 c.cap[j] = NULL c.copy[j] = false arch_interrupt_receiver[i]->send_message (i, &c) if ipr & (1 << IRQ_OST0): ost_clear_uf (0) intc_ack_irq (IRQ_OST0) timer_interrupt () return current void flush_tlb (unsigned asid): for unsigned tlb = 1; tlb < 32; ++tlb: cp0_set (CP0_INDEX, tlb) __asm__ volatile ("tlbr") unsigned hi cp0_get (CP0_ENTRY_HI, hi) if (hi & 0x1f) == asid: // Set asid to 0, which is only used by the idle task. cp0_set (CP0_ENTRY_HI, 0x2000 * tlb) __asm__ volatile ("tlbwi") static void arch_invoke (): Capability *target bool wait Thread *caller = current target = caller->address_space->find_capability (caller->arch.v0, &wait) if !target: // TODO: there must be no action here. This is just because the rest doesn't work yet. dbg_send (3, 2) //dbg_send (caller->arch.v0) schedule () // Calling an invalid capability always fails. caller->arch.v0 = 0 else: if wait: caller->wait () Capability::Context c c.cap[0] = caller->address_space->find_capability (caller->arch.a0, &c.copy[0]) c.cap[1] = caller->address_space->find_capability (caller->arch.a1, &c.copy[1]) c.cap[2] = caller->address_space->find_capability (caller->arch.a2, &c.copy[2]) c.cap[3] = caller->address_space->find_capability (caller->arch.a3, &c.copy[3]) c.data[0] = caller->arch.t0 c.data[1] = caller->arch.t1 c.data[2] = caller->arch.t2 c.data[3] = caller->arch.t3 caller->arch.v0 = target->invoke (&c) ? 1 : 0 if caller != current && caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING: current = caller else if !current: schedule () if !current: current = &idle if caller != current: if (Memory *)asids[current->address_space->arch.asid] != current->address_space: if asids[0]: current->address_space->arch.asid = asids[0] asids[0] = asids[asids[0]] else: static unsigned random = 1 current->address_space->arch.asid = random // Overwrite used asid, so flush those values from tlb. flush_tlb (random) ++random if random >= 64: random = 1 asids[current->address_space->arch.asid] = (unsigned)current->address_space cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid) directory = current->address_space->arch.directory unsigned status cp0_get (CP0_STATUS, status) status &= 0x0fffffff if current->flags & THREAD_FLAG_PRIV: status |= 0x10000000 cp0_set (CP0_STATUS, status | 0x13) /// A general exception has occurred. Thread *exception (): unsigned cause cp0_get (CP0_CAUSE, cause) switch (cause >> 2) & 0x1f: case 0: // Interrupt. This shouldn't happen, since CAUSE[IV] == 1. panic (0x11223344, "Interrupt on exception vector.") case 1: // TLB modification. panic (0x21223344, "TLB modification.") case 2: // TLB load or instruction fetch. unsigned a cp0_get (CP0_EPC, a) dbg_send (a) panic (0x31223344, "TLB load or instruction fetch.") case 3: // TLB store. panic (0x41223344, "TLB store.") case 4: // Address error load or instruction fetch. panic (0x51223344, "Address error load or instruction fetch.") case 5: // Address error store. unsigned a cp0_get (CP0_EPC, a) dbg_send (a, 16) panic (0x61223344, "Address error store.") case 6: // Bus error instruction fetch. panic (0x71223344, "Bus error instruction fetch.") case 7: // Bus error load or store. panic (0x81223344, "Bus error load or store.") case 8: // Syscall. current->pc += 4 arch_invoke () break case 9: // Breakpoint. panic (0x91223344, "Breakpoint.") case 10: // Reserved instruction. panic (0xa1223344, "Reserved instruction.") case 11: // Coprocessor unusable. panic (0xb1223344, "Coprocessor unusable.") case 12: // Arithmetic overflow. panic (0xc1223344, "Arithmetic overflow.") case 13: // Trap. panic (0xe1223344, "Trap.") case 15: // Floating point exception. panic (0xf1223344, "Floating point exception.") case 23: // Reference to WatchHi/WatchLo address. panic (0xf2223344, "Reference to WatchHi/WatchLo address.") case 24: // Machine check. panic (0xf3223344, "Machine check.") case 30: // Cache error (EJTAG only). panic (0xf4223344, "Cache error (EJTAG only).") case 14: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 25: case 26: case 27: case 28: case 29: case 31: // Reserved. panic (0xf5223344, "Reserved exception code") default: panic (0xf6223344, "Impossible exception code") return current /// There's a cache error. Big trouble. Probably not worth trying to recover. Thread *cache_error (): panic (0x33333333, "cache error") return current