1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-05 15:49:21 +02:00
iris/mips/interrupts.ccp

281 lines
8.4 KiB
Plaintext
Raw Normal View History

2009-05-11 01:28:12 +03:00
#pypp 0
2009-06-01 15:26:42 +03:00
// Iris: micro-kernel for a capability-based operating system.
2009-06-24 01:47:13 +03:00
// mips/interrupts.ccp: Functions called by mips/entry.S.
2009-06-01 15:26:42 +03:00
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// 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 <http://www.gnu.org/licenses/>.
2009-05-22 23:48:49 +03:00
#define ARCH
2009-06-01 15:26:42 +03:00
#include "../kernel.hh"
2009-05-11 01:28:12 +03:00
2009-07-21 13:17:52 +03:00
typedef unsigned cacheline[8]
void arch_flush_cache ():
for cacheline *line = (cacheline *)0x80000000; line < (cacheline *)0x80008000; ++line:
__asm__ volatile ("lw $k0, %0; cache 0, 0($k0); cache 1, 0($k0)" :: "m"(line))
2009-07-05 11:52:44 +03:00
static void handle_exit (Thread *old_current):
2009-07-20 01:23:45 +03:00
if !current || (current == &idle):
2009-07-05 11:52:44 +03:00
schedule ()
if !current:
current = &idle
2009-07-23 13:06:32 +03:00
if (current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) != THREAD_FLAG_RUNNING:
dbg_send ((unsigned)current >> PAGE_BITS, 3)
panic (0x99338844, "non-scheduled thread running")
2009-07-05 11:52:44 +03:00
if old_current == current:
return
2009-07-23 13:06:32 +03:00
dbg_send ((unsigned)current >> PAGE_BITS, 3)
2009-07-21 13:17:52 +03:00
arch_flush_cache ()
2009-07-05 11:52:44 +03:00
if current != &idle:
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
if current->flags & THREAD_FLAG_PRIV:
cp0_set (CP0_STATUS, 0x1000ff13)
else:
cp0_set (CP0_STATUS, 0x0000ff13)
/// 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.
2009-05-23 21:55:31 +03:00
Thread *tlb_refill ():
//panic (0x88776655, "TLB refill")
2009-07-05 11:52:44 +03:00
Thread *old_current = current
if !directory:
panic (0x44449999, "No directory")
2009-05-23 21:55:31 +03:00
unsigned EntryHi
cp0_get (CP0_ENTRY_HI, EntryHi)
unsigned *t = directory[EntryHi >> 21]
if !t:
2009-06-08 14:46:13 +03:00
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])
2009-05-22 23:48:49 +03:00
__asm__ volatile ("tlbwr")
2009-07-05 11:52:44 +03:00
handle_exit (old_current)
2009-05-11 01:28:12 +03:00
return current
/// An interrupt which is not an exception has occurred.
2009-05-23 21:55:31 +03:00
Thread *interrupt ():
2009-07-04 17:21:28 +03:00
//panic (0x88877722, "Interrupt")
2009-07-05 11:52:44 +03:00
Thread *old_current = current
2009-06-26 00:09:42 +03:00
unsigned ipr = INTC_IPR
2009-07-04 17:21:28 +03:00
for unsigned i = 0; i < 32; ++i:
2009-06-26 00:09:42 +03:00
if ipr & (1 << i):
2009-07-04 17:21:28 +03:00
// Handle timer interrupts specially: don't disable them.
if i == IRQ_OST0:
continue
2009-05-27 19:33:05 +03:00
// Disable the interrupt while handling it.
2009-06-26 00:09:42 +03:00
intc_mask_irq (i)
2009-07-04 17:21:28 +03:00
intc_ack_irq (i)
2009-05-27 19:33:05 +03:00
// Send message to interrupt handler.
if arch_interrupt_receiver[i]:
2009-06-08 14:46:13 +03:00
Capability::Context c
for unsigned j = 0; j < 4; ++j:
c.data[j] = 0
c.cap[j] = NULL
c.copy[j] = false
2009-07-20 01:23:45 +03:00
dbg_code = (unsigned)arch_interrupt_receiver[i]->owner
2009-06-08 14:46:13 +03:00
arch_interrupt_receiver[i]->send_message (i, &c)
2009-07-23 13:06:32 +03:00
arch_interrupt_receiver[i] = NULL
2009-07-04 17:21:28 +03:00
if ipr & (1 << IRQ_OST0):
2009-06-26 00:09:42 +03:00
ost_clear_uf (0)
2009-07-04 17:21:28 +03:00
intc_ack_irq (IRQ_OST0)
2009-06-26 00:09:42 +03:00
timer_interrupt ()
2009-07-05 11:52:44 +03:00
handle_exit (old_current)
2009-05-11 01:28:12 +03:00
return current
2009-06-26 00:09:42 +03:00
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)
2009-07-20 01:23:45 +03:00
do_schedule = false
if wait:
2009-07-23 13:06:32 +03:00
unschedule ()
2009-07-20 01:23:45 +03:00
caller->wait ()
2009-06-26 00:09:42 +03:00
if !target:
2009-07-23 13:06:32 +03:00
dbg_send (0, 0)
2009-07-05 11:52:44 +03:00
// There must be no action here.
2009-06-26 00:09:42 +03:00
else:
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
2009-07-20 01:23:45 +03:00
target->invoke (&c)
2009-07-23 13:06:32 +03:00
if do_schedule:
// If the call was to schedule without wait, it isn't done yet.
if !wait:
schedule ()
else:
// If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
if caller != current && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
current = caller
2009-06-26 00:09:42 +03:00
2009-05-11 01:28:12 +03:00
/// A general exception has occurred.
2009-05-23 21:55:31 +03:00
Thread *exception ():
2009-07-05 11:52:44 +03:00
Thread *old_current = current
2009-05-20 23:07:56 +03:00
unsigned cause
2009-05-23 21:55:31 +03:00
cp0_get (CP0_CAUSE, cause)
2009-05-20 23:07:56 +03:00
switch (cause >> 2) & 0x1f:
case 0:
2009-05-25 01:31:35 +03:00
// Interrupt. This shouldn't happen, since CAUSE[IV] == 1.
2009-07-21 13:17:52 +03:00
panic (0x01223344, "Interrupt on exception vector.")
2009-05-20 23:07:56 +03:00
case 1:
// TLB modification.
2009-07-21 13:17:52 +03:00
panic (0x11223344, "TLB modification.")
2009-05-20 23:07:56 +03:00
case 2:
// TLB load or instruction fetch.
2009-06-08 14:46:13 +03:00
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a)
2009-07-21 13:17:52 +03:00
panic (0x21223344, "TLB load or instruction fetch.")
2009-05-20 23:07:56 +03:00
case 3:
// TLB store.
2009-07-20 01:23:45 +03:00
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a)
2009-07-21 13:17:52 +03:00
cp0_get (CP0_BAD_V_ADDR, a)
dbg_send (a)
panic (0x31223344, "TLB store.")
2009-05-20 23:07:56 +03:00
case 4:
// Address error load or instruction fetch.
2009-07-20 01:23:45 +03:00
unsigned a
cp0_get (CP0_EPC, a)
dbg_send (a)
2009-07-21 13:17:52 +03:00
cp0_get (CP0_BAD_V_ADDR, a)
dbg_send (a)
panic (0x41223344, "Address error load or instruction fetch.")
2009-05-20 23:07:56 +03:00
case 5:
// Address error store.
2009-07-21 13:17:52 +03:00
dbg_send (current->arch.v1, 4)
2009-06-08 14:46:13 +03:00
unsigned a
2009-07-21 13:17:52 +03:00
cp0_get (CP0_EPC, a)
dbg_send (*(unsigned *)(a & ~3), 32)
dbg_send (a, 32)
2009-07-20 01:23:45 +03:00
cp0_get (CP0_BAD_V_ADDR, a)
dbg_send (a, 32)
2009-07-21 13:17:52 +03:00
panic (0x51223344, "Address error store.")
2009-05-20 23:07:56 +03:00
case 6:
// Bus error instruction fetch.
2009-07-21 13:17:52 +03:00
panic (0x61223344, "Bus error instruction fetch.")
2009-05-20 23:07:56 +03:00
case 7:
// Bus error load or store.
2009-07-21 13:17:52 +03:00
panic (0x71223344, "Bus error load or store.")
2009-05-20 23:07:56 +03:00
case 8:
// Syscall.
2009-06-08 14:46:13 +03:00
current->pc += 4
2009-05-23 21:55:31 +03:00
arch_invoke ()
2009-05-27 15:38:52 +03:00
break
2009-05-20 23:07:56 +03:00
case 9:
// Breakpoint.
2009-07-20 01:23:45 +03:00
//panic (0x91223344, "Breakpoint.")
current->pc += 4
2009-07-23 13:06:32 +03:00
if current->arch.a0:
if dbg_cap:
panic (0x34259380, "Break instruction while log capability was already set")
bool dummy
dbg_cap = current->address_space->find_capability (current->arch.a1, &dummy)
if !dbg_cap:
panic (0x06111129, "no log capability provided")
break
if dbg_cap:
dbg_log_char (current->arch.a1)
break
2009-07-20 01:23:45 +03:00
break
2009-05-20 23:07:56 +03:00
case 10:
// Reserved instruction.
2009-05-22 23:48:49 +03:00
panic (0xa1223344, "Reserved instruction.")
2009-05-20 23:07:56 +03:00
case 11:
// Coprocessor unusable.
2009-05-22 23:48:49 +03:00
panic (0xb1223344, "Coprocessor unusable.")
2009-05-20 23:07:56 +03:00
case 12:
// Arithmetic overflow.
2009-05-22 23:48:49 +03:00
panic (0xc1223344, "Arithmetic overflow.")
2009-05-20 23:07:56 +03:00
case 13:
// Trap.
2009-07-21 13:17:52 +03:00
panic (0xd1223344, "Trap.")
2009-05-20 23:07:56 +03:00
case 15:
// Floating point exception.
2009-07-21 13:17:52 +03:00
panic (0xe1223344, "Floating point exception.")
2009-05-20 23:07:56 +03:00
case 23:
// Reference to WatchHi/WatchLo address.
2009-07-21 13:17:52 +03:00
panic (0xf1223344, "Reference to WatchHi/WatchLo address.")
2009-05-20 23:07:56 +03:00
case 24:
// Machine check.
2009-05-22 23:48:49 +03:00
panic (0xf3223344, "Machine check.")
2009-05-20 23:07:56 +03:00
case 30:
// Cache error (EJTAG only).
2009-05-22 23:48:49 +03:00
panic (0xf4223344, "Cache error (EJTAG only).")
2009-05-20 23:07:56 +03:00
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.
2009-05-23 21:55:31 +03:00
panic (0xf5223344, "Reserved exception code")
default:
panic (0xf6223344, "Impossible exception code")
2009-07-05 11:52:44 +03:00
handle_exit (old_current)
2009-05-11 01:28:12 +03:00
return current
/// There's a cache error. Big trouble. Probably not worth trying to recover.
2009-05-23 21:55:31 +03:00
Thread *cache_error ():
2009-05-11 01:28:12 +03:00
panic (0x33333333, "cache error")
2009-07-05 11:52:44 +03:00
Thread *old_current = current
handle_exit (old_current)
2009-05-11 01:28:12 +03:00
return current