1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 00:44:31 +03:00
iris/mips/interrupts.ccp

334 lines
9.5 KiB
COBOL

#pypp 0
// vim: set filetype=cpp : //
// Iris: micro-kernel for a capability-based operating system.
// mips/interrupts.ccp: Functions called by mips/entry.S.
// 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/>.
#define ARCH
#include "kernel.hh"
void arch_flush_cache ():
__asm__ volatile ("\t.set noreorder\n"
"\tlui $k0, 0x8000\n"
"\tori $k1, $k0, 0x4000 - 0x20\n"
"1:\tcache 0, 0($k0)\n"
"\tcache 1, 0($k0)\n"
"\tbne $k0, $k1, 1b\n"
"\taddiu $k0, $k0, 0x20\n"
"\t.set reorder\n")
static kThread *handle_exit ():
dbg_check ()
--dbg_code.h
// Set must_wait to false, so random threads are not set to waiting when the kernel invokes something (such as a dbg_cap).
must_wait = false
if !current || (current == &idle):
schedule ()
if !current:
current = &idle
if (current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) != Iris::Thread::RUNNING:
panic (current->flags, "non-scheduled thread running")
if old_current == current:
return current
arch_flush_cache ()
if current != &idle:
if (kMemory *)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
++random
if random >= 64:
random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
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 & Iris::Thread::PRIV:
cp0_set (CP0_STATUS, 0x1000ff13)
else:
cp0_set (CP0_STATUS, 0x0000ff13)
dbg_push ((unsigned)current)
dbg_push (current->pc)
return current
/// 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.
kThread *tlb_refill ():
++dbg_code.h
old_current = current
if !directory:
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_NO_PAGE_DIRECTORY, addr)
return handle_exit ()
unsigned EntryHi
cp0_get (CP0_ENTRY_HI, EntryHi)
Table *t = directory[EntryHi >> 21]
if !t:
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_NO_PAGE_TABLE, addr)
else:
// - 2 instead of - 1 means reset bit 0
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
cp0_set (CP0_ENTRY_LO0, t->entrylo[idx])
cp0_set (CP0_ENTRY_LO1, t->entrylo[idx + 1])
__asm__ volatile ("tlbwr")
if dbg_code.l:
kdebug ("tlb refill ")
__asm__ volatile ("tlbp")
unsigned index
cp0_get (CP0_INDEX, index)
kdebug_num (index, 2)
kdebug ("|")
kdebug_num (t->entrylo[idx])
kdebug (":")
kdebug_num (t->entrylo[idx + 1])
kdebug (" for ")
kdebug_num (EntryHi)
kdebug ("\n")
return handle_exit ()
/// An interrupt which is not an exception has occurred.
kThread *interrupt ():
++dbg_code.h
old_current = current
unsigned ipr = INTC_IPR
//if ipr & ~((1 << TIMER_INTERRUPT) | (1 << 0x18)):
// kdebug ("interrupt: ")
// kdebug_num (ipr)
// kdebug ("&")
// kdebug_num (~INTC_IMR)
for unsigned i = 0; i < 32; ++i:
if ipr & (1 << i):
// Handle timer interrupts specially: don't disable them.
if i == TIMER_INTERRUPT:
continue
//if i != 0x18:
// kdebug (" ")
// kdebug_num (i, 2)
// Disable the interrupt while handling it.
intc_mask_irq (i)
intc_ack_irq (i)
// Send message to interrupt handler.
if arch_interrupt_receiver[i]:
kCapability::Context c
c.data[0] = i
c.data[1] = 0
arch_interrupt_receiver[i]->send_message (0, &c)
arch_interrupt_receiver[i] = NULL
//if ipr & ~((1 << TIMER_INTERRUPT) | (1 << 0x18)):
// kdebug ("\n")
if ipr & (1 << TIMER_INTERRUPT):
#if defined (TRENDTAC)
ost_clear_uf (0)
#elif defined (NANONOTE)
tcu_clear_full_match_flag (0)
#else
#error unknown board
#endif
intc_ack_irq (TIMER_INTERRUPT)
timer_interrupt ()
return handle_exit ()
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 + 2))
__asm__ volatile ("tlbwi")
static void arch_invoke ():
kCapRef target = old_current->find_capability (old_current->arch.v[0], &must_wait)
do_schedule = false
kCapability::Context msg
if must_wait:
old_current->recv_reply = old_current->arch.t[2]
old_current->recv_arg = old_current->arch.t[3]
//kdebug_num (old_current->recv_reply)
//kdebug ("/")
//kdebug_num (old_current->recv_arg)
//kdebug ("\n")
if !target.valid ():
if must_wait:
old_current->wait ()
else:
dpanic (target.index, "invalid target called")
return
msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
msg.data[0] = Iris::Num (old_current->arch.a[0], old_current->arch.a[1])
msg.data[1] = Iris::Num (old_current->arch.a[2], old_current->arch.a[3])
target->invoke (&msg)
if do_schedule && !must_wait:
// If the call was to schedule without wait, it isn't done yet.
schedule ()
else if old_current != current && old_current && (old_current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) == Iris::Thread::RUNNING:
// If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
current = old_current
/// A general exception has occurred.
kThread *exception ():
++dbg_code.h
old_current = current
unsigned cause
cp0_get (CP0_CAUSE, cause)
switch (cause >> 2) & 0x1f:
case 0:
// Interrupt. This shouldn't happen, since CAUSE[IV] == 1.
panic (0, "Interrupt on exception vector.")
break
case 1:
// TLB modification.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_WRITE_DENIED, addr)
break
case 2:
// TLB load or instruction fetch.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_UNMAPPED_READ, addr)
break
case 3:
// TLB store.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_UNMAPPED_WRITE, addr)
break
case 4:
// Address error load or instruction fetch.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_INVALID_ADDRESS_READ, addr)
break
case 5:
// Address error store.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Iris::ERR_INVALID_ADDRESS_WRITE, addr)
break
case 6:
// Bus error instruction fetch.
panic (0, "Bus error instruction fetch.")
break
case 7:
// Bus error load or store.
panic (0, "Bus error load or store.")
break
case 8:
// Syscall.
current->pc += 4
arch_invoke ()
//check (0x88392883, "check error")
break
case 9:
// Breakpoint.
#if 0 || defined (NDEBUG)
//current->raise (Iris::ERR_BREAKPOINT, 0)
#ifndef NDEBUG
current->pc += 4
#endif
#else
unsigned opcode = *(unsigned *)current->pc
if opcode == 0x0007000d:
panic (0, "Division by zero (detected by compiler)")
current->pc += 4
if current->arch.a[0]:
if dbg_cap.valid ():
dpanic (0, "Break instruction while log capability was already set")
break
bool dummy
dbg_cap = current->find_capability (current->arch.a[1], &dummy)
if !dbg_cap.valid ():
dpanic (0, "no log capability provided")
break
kdebug ("log capability registered.\n")
break
kdebug (current->arch.a[1])
#endif
break
case 10:
// Reserved instruction.
current->raise (Iris::ERR_RESERVED_INSTRUCTION, 0)
break
case 11:
// Coprocessor unusable.
current->raise (Iris::ERR_COPROCESSOR_UNUSABLE, 0)
break
case 12:
// Arithmetic overflow.
current->raise (Iris::ERR_OVERFLOW, 0)
break
case 13:
// Trap.
current->raise (Iris::ERR_TRAP, 0)
break
case 15:
// Floating point exception.
panic (0xe1223344, "Floating point exception.")
break
case 23:
// Reference to WatchHi/WatchLo address.
cp0_set0 (CP0_WATCH_LO)
current->raise (Iris::ERR_WATCHPOINT, 0)
break
case 24:
// Machine check.
panic (0xf3223344, "Machine check.")
break
case 30:
// Cache error (EJTAG only).
panic (0xf4223344, "Cache error (EJTAG only).")
break
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")
break
default:
panic (0xf6223344, "Impossible exception code")
break
return handle_exit ()
/// There's a cache error. Big trouble. Probably not worth trying to recover.
kThread *cache_error ():
++dbg_code.h
panic (0x33333333, "cache error")
old_current = current
return handle_exit ()