#pypp 0 // Iris: micro-kernel for a capability-based operating system. // panic.ccp: Stop running and try to notify the user of the problem. // 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" #ifdef USE_SERIAL void kdebug (unsigned ch): while !(UART0_LSR & UARTLSR_TDRQ): UART0_TDR = ch #else void kdebug (unsigned ch): if !dbg_cap.valid () || dbg_code.l: return kCapability::Context c c.data[0] = ch ++dbg_code.l dbg_cap->invoke (&c) --dbg_code.l #endif void kdebug (char const *str): while *str: kdebug (*str++) void kdebug_num (unsigned num, unsigned digits): char const *encode = "0123456789abcdef" for unsigned i = 0; i < digits; ++i: kdebug (encode[(num >> (4 * ((digits - 1) - i))) & 0xf]) return #if 1 || defined (NDEBUG) static void print_addr (char const *t, unsigned addr, bool last = false): kdebug (t) kdebug_num (addr) #if 1 unsigned de = addr >> 21 unsigned te = (addr >> 12) & ((1 << 9) - 1) if de < 0x400 && old_current && old_current->address_space->arch.directory && old_current->address_space->arch.directory[de]: kdebug ("; EntryLo = ") kdebug_num (old_current->address_space->arch.directory[de]->entrylo[te]) else: kdebug ("; no directory or page table") if old_current && de < 0x400: cp0_set (CP0_ENTRY_HI, (addr & (PAGE_MASK << 1)) | old_current->address_space->arch.asid) __asm__ volatile ("tlbp") unsigned idx, hi cp0_get (CP0_INDEX, idx) kdebug ("; tlb index: ") if idx & (1 << 31): kdebug ("none\n") else: __asm__ volatile ("tlbr") kdebug_num (idx, 2) kdebug ("; EntryLo = ") unsigned lo cp0_get (CP0_ENTRY_LO0, lo) kdebug_num (lo) kdebug (":") cp0_get (CP0_ENTRY_LO1, lo) kdebug_num (lo) kdebug ("\n") else: kdebug ('\n') if addr >= 0x80000000 && addr < 0xc0000000: for int i = -4; i < 4; ++i: kdebug (" ") kdebug_num (((unsigned *)addr)[i]) kdebug ("\n") #else kdebug (last ? '\n' : ';') #endif static void panic_message (unsigned n, const char *line, char const *name, char const *message): unsigned vaddr, epc cp0_get (CP0_BAD_V_ADDR, vaddr) cp0_get (CP0_EPC, epc) #if 1 unsigned addr print_addr ("BadVAddr: ", vaddr) if old_current: print_addr ("PC: ", old_current->pc) print_addr ("epc: ", epc, true) #endif kdebug ("Panic: caller = ") if old_current: kdebug_num (old_current->id, 2) kdebug (":") kdebug_num ((unsigned)old_current) if old_current: kdebug ('@') kdebug_num (old_current->pc) kdebug ("; ") kdebug (name) kdebug (':') kdebug (line) kdebug (": ") kdebug (message) kdebug ('/') kdebug_num (n) kdebug ("; debug: ") kdebug_num (dbg_code.h) kdebug (':') kdebug_num (dbg_code.l) kdebug ('\n') kdebug ("debug buffer:") unsigned b = dbg_buffer_head for unsigned i = 0; i < 16; ++i: kdebug ('\n') for unsigned j = 0; j < 2; ++j: kdebug (' ') kdebug_num (dbg_buffer[b]) ++b if b == 32: b = 0 kdebug ('\n') void panic_impl (unsigned n, const char *line, char const *name, char const *message): // Stop all threads. while first_scheduled: first_scheduled->unrun () for kReceiver *r = first_alarm; r; r = r->next_alarm: if r->owner: r->owner->unrun () for unsigned i = 0; i < 32; ++i: if arch_interrupt_receiver[i] && arch_interrupt_receiver[i]->owner: arch_interrupt_receiver[i]->owner->unrun () #ifndef NDEBUG panic_message (n, line, name, message) // If a log capability is registered, run its owner. #ifndef USE_SERIAL if dbg_cap.valid () && dbg_cap->target->owner: dbg_cap->target->owner->run () // Use the (now running) log thread to display the message. // If no log capability is registered, the machine just hangs. #else arch_reboot () #endif #endif #ifndef NDEBUG void dbg_send (unsigned num, unsigned bits): kdebug ("Warning: ") kdebug_num (num) kdebug ('/') kdebug_num (bits) kdebug ('\n') #endif #else void delay (unsigned ms): for unsigned t = 0; t < 8000 * ms; ++t: GPIO_GPDIR (0) = GPIO_GPDIR (0) void set_leds (bool a, bool b): gpio_as_output (GPIO_NUM_PORT, GPIO_NUM) gpio_as_output (GPIO_CAPS_PORT, GPIO_CAPS) if a: GPIO_GPDR (GPIO_NUM_PORT) &= ~(1 << GPIO_NUM) else: GPIO_GPDR (GPIO_NUM_PORT) |= 1 << GPIO_NUM if b: GPIO_GPDR (GPIO_CAPS_PORT) &= ~(1 << GPIO_CAPS) else: GPIO_GPDR (GPIO_CAPS_PORT) |= 1 << GPIO_CAPS void dbg_send (unsigned n, unsigned bits): for unsigned i = 0; i < bits; ++i: bool v = n & (1 << (bits - 1)) set_leds (v, !v) delay (350) set_leds (false, false) delay (150) n <<= 1 set_leds (true, true) delay (50) set_leds (false, false) delay (50) void panic_impl (unsigned n, const char *line, char const *name, char const *message): unsigned epc cp0_get (CP0_EPC, epc) dbg_send (epc, 32) while true: dbg_send (n, 32) #endif