Root/mips/interrupts.ccp

1#pypp 0
2// vim: set filetype=cpp : //
3// Iris: micro-kernel for a capability-based operating system.
4// mips/interrupts.ccp: Functions called by mips/entry.S.
5// Copyright 2009 Bas Wijnen <wijnen@debian.org>
6//
7// This program is free software: you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20#define ARCH
21#include "kernel.hh"
22
23void arch_flush_cache ():
24    __asm__ volatile ("\t.set noreorder\n"
25        "\tlui $k0, 0x8000\n"
26        "\tori $k1, $k0, 0x4000 - 0x20\n"
27        "1:\tcache 0, 0($k0)\n"
28        "\tcache 1, 0($k0)\n"
29        "\tbne $k0, $k1, 1b\n"
30        "\taddiu $k0, $k0, 0x20\n"
31        "\t.set reorder\n")
32
33static kThread *handle_exit ():
34    dbg_check ()
35    --dbg_code.h
36    // Set must_wait to false, so random threads are not set to waiting when the kernel invokes something (such as a dbg_cap).
37    must_wait = false
38    if !current || (current == &idle):
39        schedule ()
40        if !current:
41            current = &idle
42    if (current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) != Iris::Thread::RUNNING:
43        panic (current->flags, "non-scheduled thread running")
44    if old_current == current:
45        return current
46    arch_flush_cache ()
47    if current != &idle:
48        if (kMemory *)asids[current->address_space->arch.asid] != current->address_space:
49            if asids[0]:
50                current->address_space->arch.asid = asids[0]
51                asids[0] = asids[asids[0]]
52            else:
53                static unsigned random
54                ++random
55                if random >= 64:
56                    random = 1
57                current->address_space->arch.asid = random
58                // Overwrite used asid, so flush those values from tlb.
59                flush_tlb (random)
60            asids[current->address_space->arch.asid] = (unsigned)current->address_space
61    cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
62    directory = current->address_space->arch.directory
63    if current->flags & Iris::Thread::PRIV:
64        cp0_set (CP0_STATUS, 0x1000ff13)
65    else:
66        cp0_set (CP0_STATUS, 0x0000ff13)
67    dbg_push ((unsigned)current)
68    dbg_push (current->pc)
69    return current
70
71/// A TLB miss has occurred. This is the slow version. It is only used
72/// when k0 or k1 is not 0, or when an error occurs.
73/// Otherwise, the ultra-fast code in entry.S is used.
74kThread *tlb_refill ():
75    ++dbg_code.h
76    old_current = current
77    if !directory:
78        unsigned addr
79        cp0_get (CP0_BAD_V_ADDR, addr)
80        current->raise (Iris::ERR_NO_PAGE_DIRECTORY, addr)
81        return handle_exit ()
82    unsigned EntryHi
83    cp0_get (CP0_ENTRY_HI, EntryHi)
84    Table *t = directory[EntryHi >> 21]
85    if !t:
86        unsigned addr
87        cp0_get (CP0_BAD_V_ADDR, addr)
88        current->raise (Iris::ERR_NO_PAGE_TABLE, addr)
89    else:
90        // - 2 instead of - 1 means reset bit 0
91        unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
92        cp0_set (CP0_ENTRY_LO0, t->entrylo[idx])
93        cp0_set (CP0_ENTRY_LO1, t->entrylo[idx + 1])
94        __asm__ volatile ("tlbwr")
95        if dbg_code.l:
96            kdebug ("tlb refill ")
97            __asm__ volatile ("tlbp")
98            unsigned index
99            cp0_get (CP0_INDEX, index)
100            kdebug_num (index, 2)
101            kdebug ("|")
102            kdebug_num (t->entrylo[idx])
103            kdebug (":")
104            kdebug_num (t->entrylo[idx + 1])
105            kdebug (" for ")
106            kdebug_num (EntryHi)
107            kdebug ("\n")
108    return handle_exit ()
109
110/// An interrupt which is not an exception has occurred.
111kThread *interrupt ():
112    ++dbg_code.h
113    old_current = current
114    unsigned ipr = INTC_IPR
115    //if ipr & ~((1 << TIMER_INTERRUPT) | (1 << 0x18)):
116    // kdebug ("interrupt: ")
117    // kdebug_num (ipr)
118    // kdebug ("&")
119    // kdebug_num (~INTC_IMR)
120    for unsigned i = 0; i < 32; ++i:
121        if ipr & (1 << i):
122            // Handle timer interrupts specially: don't disable them.
123            if i == TIMER_INTERRUPT:
124                continue
125            //if i != 0x18:
126            // kdebug (" ")
127            // kdebug_num (i, 2)
128            // Disable the interrupt while handling it.
129            intc_mask_irq (i)
130            intc_ack_irq (i)
131            // Send message to interrupt handler.
132            if arch_interrupt_receiver[i]:
133                kCapability::Context c
134                c.data[0] = i
135                c.data[1] = 0
136                arch_interrupt_receiver[i]->send_message (0, &c)
137                arch_interrupt_receiver[i] = NULL
138    //if ipr & ~((1 << TIMER_INTERRUPT) | (1 << 0x18)):
139    // kdebug ("\n")
140    if ipr & (1 << TIMER_INTERRUPT):
141        #if defined (TRENDTAC)
142        ost_clear_uf (0)
143        #elif defined (NANONOTE)
144        tcu_clear_full_match_flag (0)
145        #else
146        #error unknown board
147        #endif
148        intc_ack_irq (TIMER_INTERRUPT)
149        timer_interrupt ()
150    return handle_exit ()
151
152void flush_tlb (unsigned asid):
153    for unsigned tlb = 1; tlb < 32; ++tlb:
154        cp0_set (CP0_INDEX, tlb)
155        __asm__ volatile ("tlbr")
156        unsigned hi
157        cp0_get (CP0_ENTRY_HI, hi)
158        if (hi & 0x1f) == asid:
159            // Set asid to 0, which is only used by the idle task.
160            cp0_set (CP0_ENTRY_HI, 0x2000 * (tlb + 2))
161            __asm__ volatile ("tlbwi")
162
163static void arch_invoke ():
164    kCapRef target = old_current->find_capability (old_current->arch.v[0], &must_wait)
165    do_schedule = false
166    kCapability::Context msg
167    if must_wait:
168        old_current->recv_reply = old_current->arch.t[2]
169        old_current->recv_arg = old_current->arch.t[3]
170        //kdebug_num (old_current->recv_reply)
171        //kdebug ("/")
172        //kdebug_num (old_current->recv_arg)
173        //kdebug ("\n")
174    if !target.valid ():
175        if must_wait:
176            old_current->wait ()
177        else:
178            dpanic (target.index, "invalid target called")
179        return
180    msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
181    msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
182    msg.data[0] = Iris::Num (old_current->arch.a[0], old_current->arch.a[1])
183    msg.data[1] = Iris::Num (old_current->arch.a[2], old_current->arch.a[3])
184    target->invoke (&msg)
185    if do_schedule && !must_wait:
186        // If the call was to schedule without wait, it isn't done yet.
187        schedule ()
188    else if old_current != current && old_current && (old_current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) == Iris::Thread::RUNNING:
189        // If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
190        current = old_current
191
192/// A general exception has occurred.
193kThread *exception ():
194    ++dbg_code.h
195    old_current = current
196    unsigned cause
197    cp0_get (CP0_CAUSE, cause)
198    switch (cause >> 2) & 0x1f:
199        case 0:
200            // Interrupt. This shouldn't happen, since CAUSE[IV] == 1.
201            panic (0, "Interrupt on exception vector.")
202            break
203        case 1:
204            // TLB modification.
205            unsigned addr
206            cp0_get (CP0_BAD_V_ADDR, addr)
207            current->raise (Iris::ERR_WRITE_DENIED, addr)
208            break
209        case 2:
210            // TLB load or instruction fetch.
211            unsigned addr
212            cp0_get (CP0_BAD_V_ADDR, addr)
213            current->raise (Iris::ERR_UNMAPPED_READ, addr)
214            break
215        case 3:
216            // TLB store.
217            unsigned addr
218            cp0_get (CP0_BAD_V_ADDR, addr)
219            current->raise (Iris::ERR_UNMAPPED_WRITE, addr)
220            break
221        case 4:
222            // Address error load or instruction fetch.
223            unsigned addr
224            cp0_get (CP0_BAD_V_ADDR, addr)
225            current->raise (Iris::ERR_INVALID_ADDRESS_READ, addr)
226            break
227        case 5:
228            // Address error store.
229            unsigned addr
230            cp0_get (CP0_BAD_V_ADDR, addr)
231            current->raise (Iris::ERR_INVALID_ADDRESS_WRITE, addr)
232            break
233        case 6:
234            // Bus error instruction fetch.
235            panic (0, "Bus error instruction fetch.")
236            break
237        case 7:
238            // Bus error load or store.
239            panic (0, "Bus error load or store.")
240            break
241        case 8:
242            // Syscall.
243            current->pc += 4
244            arch_invoke ()
245            //check (0x88392883, "check error")
246            break
247        case 9:
248            // Breakpoint.
249            #if 0 || defined (NDEBUG)
250            //current->raise (Iris::ERR_BREAKPOINT, 0)
251            #ifndef NDEBUG
252            current->pc += 4
253            #endif
254            #else
255            unsigned opcode = *(unsigned *)current->pc
256            if opcode == 0x0007000d:
257                panic (0, "Division by zero (detected by compiler)")
258            current->pc += 4
259            if current->arch.a[0]:
260                if dbg_cap.valid ():
261                    dpanic (0, "Break instruction while log capability was already set")
262                    break
263                bool dummy
264                dbg_cap = current->find_capability (current->arch.a[1], &dummy)
265                if !dbg_cap.valid ():
266                    dpanic (0, "no log capability provided")
267                    break
268                kdebug ("log capability registered.\n")
269                break
270            kdebug (current->arch.a[1])
271            #endif
272            break
273        case 10:
274            // Reserved instruction.
275            current->raise (Iris::ERR_RESERVED_INSTRUCTION, 0)
276            break
277        case 11:
278            // Coprocessor unusable.
279            current->raise (Iris::ERR_COPROCESSOR_UNUSABLE, 0)
280            break
281        case 12:
282            // Arithmetic overflow.
283            current->raise (Iris::ERR_OVERFLOW, 0)
284            break
285        case 13:
286            // Trap.
287            current->raise (Iris::ERR_TRAP, 0)
288            break
289        case 15:
290            // Floating point exception.
291            panic (0xe1223344, "Floating point exception.")
292            break
293        case 23:
294            // Reference to WatchHi/WatchLo address.
295            cp0_set0 (CP0_WATCH_LO)
296            current->raise (Iris::ERR_WATCHPOINT, 0)
297            break
298        case 24:
299            // Machine check.
300            panic (0xf3223344, "Machine check.")
301            break
302        case 30:
303            // Cache error (EJTAG only).
304            panic (0xf4223344, "Cache error (EJTAG only).")
305            break
306        case 14:
307        case 16:
308        case 17:
309        case 18:
310        case 19:
311        case 20:
312        case 21:
313        case 22:
314        case 25:
315        case 26:
316        case 27:
317        case 28:
318        case 29:
319        case 31:
320            // Reserved.
321            panic (0xf5223344, "Reserved exception code")
322            break
323        default:
324            panic (0xf6223344, "Impossible exception code")
325            break
326    return handle_exit ()
327
328/// There's a cache error. Big trouble. Probably not worth trying to recover.
329kThread *cache_error ():
330    ++dbg_code.h
331    panic (0x33333333, "cache error")
332    old_current = current
333    return handle_exit ()
334

Archive Download this file

Branches:
master



interactive