/* * * * Second stage boot-loader and exception vectors for Open Hack'Ware. * * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License V2 * as published by the Free Software Foundation * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define ASSEMBLY_CODE #include "bios.h" .section .text .align 2 .globl _start _start: /* Entry point */ li r0, 0 ; _turn_off_mmu: /* Be sure MMU is off and we are in 32 bits mode (for PPC64) */ lis r11, _hw_init@h ; ori r11, r11, _hw_init@l ; mtspr 26, r11 ; mtspr 27, r0 ; rfi ; _hw_init: /* May need more hw init here */ _load_bios: /* Load the full BIOS into RAM */ lis r12, bios_base@h ; ori r12, r12, bios_base@l ; lmw r29, 0(r12) ; /* Set up the C stack */ addis r1, r29, 0x0040 ; clrrwi r1, r1, 19 ; stw r1, -16(r1) ; stwu r0, -4(r1) ; stwu r0, -4(r1) ; stwu r0, -4(r1) ; stwu r0, -4(r1) ; /* Skip frame pointer */ stwu r0, -8(r1) ; stwu r0, -4(r1) ; stwu r0, -4(r1) ; /* Start copying */ mtctr r30 ; subi r12, r3, 4 ; subi r13, r29, 4 ; _bios_copy_loop: lwzu r14, 4(r12) ; stwu r14, 4(r13) ; bdnz _bios_copy_loop ; /* Synchronize the whole execution context */ /* Also enable FPU */ ori r0, r0, (1 << 13) ; mtspr 26, r29 ; mtspr 27, r0 ; rfi ; /* If we ever return, stop */ bl bug ; .org 0x0080 .section .text .align 2 bug: /* Dump the exception and its context */ mflr r3 ; mfspr r4, SRR0 ; mfspr r5, SRR1 ; mfspr r6, DAR ; mfspr r7, DSISR ; /* Turn MMU off */ lis r0, _bug_no_mmu@h ; ori r0, r0, _bug_no_mmu@l ; mtspr 26, r0 ; li r0, 0 ; mtspr 27, r0 ; rfi ; _bug_no_mmu: bl dump_exception ; _forever: /* Loop forever */ b _forever ; skip_exception: /* Skip external interrupts and decrementer exception */ /* BEWARE: be sure not to modify any register */ stw r11, save_area@l(0) ; mfspr r11, 27 ; clrlwi r11, r11, 16 ; mtspr 27, r11 ; lwz r11, save_area@l(0) ; rfi ; #define EXCP_BUG(entry) \ .org 0x##entry ; \ .section .text ; \ .align 2 ; \ excp_##entry: ; \ bl bug #define EXCP_SKIP(entry) \ .org 0x##entry ; \ .section .text ; \ .align 2 ; \ excp_##entry##: ; \ b skip_exception /* Exception vectors */ /* Reset exception */ .org 0x0100 excp_0100: ba 0xfffffffc /* Machine check exception */ EXCP_BUG(0200) ; /* DSI exception */ EXCP_BUG(0300) ; /* ISI exception */ EXCP_BUG(0400) ; /* External interrupt: skip it */ EXCP_SKIP(0500) ; /* Alignment exception */ EXCP_BUG(0600) ; /* Program exception */ EXCP_BUG(0700) ; /* No floating point exception */ EXCP_BUG(0800) ; /* Decrementer exception: skip it */ EXCP_SKIP(0900) ; /* Reserved A exception */ EXCP_BUG(0A00) ; /* Reserved B exception */ EXCP_BUG(0B00) ; /* System call exception */ EXCP_BUG(0C00) ; /* Trace exception */ EXCP_BUG(0D00) ; /* Floating point assist exception */ EXCP_BUG(0E00) ; /* Performance monitor exception */ EXCP_BUG(0F00) ; /* Instruction TLB miss exception */ EXCP_BUG(1000) ; /* Data TLB miss for store exception */ EXCP_BUG(1100) ; /* Data TLB miss for load exception */ EXCP_BUG(1200) ; /* Instruction address breakpoint exception */ EXCP_BUG(1300) ; /* System management interrupt exception */ EXCP_BUG(1400) ; /* Thermal management exception */ EXCP_BUG(1500) ; /* Unknown exceptions */ EXCP_BUG(1600) ; EXCP_BUG(1700) ; EXCP_BUG(1800) ; EXCP_BUG(1900) ; EXCP_BUG(1A00) ; EXCP_BUG(1B00) ; EXCP_BUG(1C00) ; EXCP_BUG(1D00) ; EXCP_BUG(1E00) ; EXCP_BUG(1F00) ; /* End of exception vectors list */ .org 0x2000 .section .text .align 2 helpers_start: outb: /* void outb (uint32_t port, uint32_t data); * Writes a single character on an IO port. * Used for serial console. */ stb r4, 0(r3) ; eieio ; blr ; outstr: /* void outstr (uint32_t port, const unsigned char *str); * Writes a string on an IO port. */ mflr r20 ; subi r11, r4, 1 ; _outstr_next: lbzu r4, 1(r11) ; cmpi 0, r4, 0 ; beq _outstr_done ; bl outb ; b _outstr_next ; _outstr_done: mtlr r20 ; blr ; outdigit: /* void outdigit (uint32_t port, uint32_t digit); * Dumps a single digit on serial port. */ mflr r20 ; addi r4, r4, '0' ; bl outb ; mtlr r20 ; blr ; outhex: /* void outhex (uint32_t port, uint32_t value); * Dumps a 32 bits hex number on serial port */ mflr r21 li r11, 8 ; mtctr r11 ; mr r11, r4 ; _outhex_next: rlwinm r11, r11, 4, 0, 31 ; clrlwi r4, r11, 28 ; cmpi 0, r4, 9 ; bgt _outhex_xdigit ; bl outdigit ; bdnz _outhex_next ; b _outhex_done ; _outhex_xdigit: addi r4, r4, 'a' - 10 ; bl outb ; bdnz _outhex_next ; _outhex_done: mtlr r21 ; blr ; /* void dump_exception (uint32_t lr, uint32_t srr0, uint32_t srr1, * uint32_t dar, uint32_t dsisr); * Dump a message when catching an exception */ dump_exception: /* Save call parameters */ mflr r19 ; mr r22, r3 ; mr r23, r4 ; mr r24, r5 ; mr r25, r6 ; mr r26, r7 ; lis r11, registers_area@h ; ori r11, r11, registers_area@l ; lmw r27, 0(r11) ; /* Now, serial IO port is in r27, * message table start is in r28, * first exception message offset is in r29, * and last known exception number is in r30 */ /* Print error prompt message */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; /* Find message corresponding to the caught exception */ srwi r12, r22, 8 ; cmp 0, r12, r30 ; ble _dump_excp_msg ; subi r12, r30, 1 ; _dump_excp_msg: rlwinm r12, r12, 2, 0, 31 ; /* Dump execption message */ mr r3, r27 ; lwzx r4, r12, r29 ; bl outstr ; /* Complete exception message */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; /* Dump nip */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; mr r3, r27 ; mr r4, r23 ; bl outhex ; /* dump msr */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; mr r3, r27 ; mr r4, r24 ; bl outhex ; /* dump dar */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; mr r3, r27 ; mr r4, r25 ; bl outhex ; /* dump dsisr */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; mr r3, r27 ; mr r4, r26 ; bl outhex ; /* All done, dump last message and return */ mr r3, r27 ; lwzu r4, 4(r28) ; bl outstr ; mtlr r19 ; blr ; .section .rodata .align 2 _BUG_message_0: .string "ERROR: BUG caught...\n" _BUG_message_1: .string " exception" _BUG_message_2: .string "\nnip=0x" _BUG_message_3: .string " msr=0x" _BUG_message_4: .string " dar=0x" _BUG_message_5: .string " dsisr=0x" _BUG_message_6: .string "\nStopping execution\n" _excp_message_0x00: .string "BIOS execution" _excp_message_0x01: .string "Reset" _excp_message_0x02: .string "Machine check" _excp_message_0x03: .string "Data memory access" _excp_message_0x04: .string "Instruction fetch" _excp_message_0x05: .string "External" _excp_message_0x06: .string "Alignment" _excp_message_0x07: .string "Program" _excp_message_0x08: .string "No floating point" _excp_message_0x09: .string "Decrementer" _excp_message_0x0a: .string "Reserved A" _excp_message_0x0b: .string "Reserved B" _excp_message_0x0c: .string "System call" _excp_message_0x0d: .string "Trace" _excp_message_0x0e: .string "Floating point assist" _excp_message_0x0f: .string "Performance monitor" _excp_message_0x10: .string "Instruction TLB miss" _excp_message_0x11: .string "Data TLB miss for store" _excp_message_0x12: .string "Data TLB miss for load" _excp_message_0x13: .string "Instruction address breakpoint" _excp_message_0x14: .string "System management" _excp_message_0x15: .string "Thermal management" _excp_message_0x16: .string "Unknown" _messages_table: .long _BUG_message_0 .long _BUG_message_1 .long _BUG_message_2 .long _BUG_message_3 .long _BUG_message_4 .long _BUG_message_5 .long _BUG_message_6 _excp_messages_table: .long _excp_message_0x00 .long _excp_message_0x01 .long _excp_message_0x02 .long _excp_message_0x03 .long _excp_message_0x04 .long _excp_message_0x05 .long _excp_message_0x06 .long _excp_message_0x07 .long _excp_message_0x08 .long _excp_message_0x09 .long _excp_message_0x0a .long _excp_message_0x0b .long _excp_message_0x0c .long _excp_message_0x0d .long _excp_message_0x0e .long _excp_message_0x0f .long _excp_message_0x10 .long _excp_message_0x11 .long _excp_message_0x12 .long _excp_message_0x13 .long _excp_message_0x14 .long _excp_message_0x15 .long _excp_message_0x16 _last_excp_message: bios_base: .long BIOS_BASE bios_size: .long BIOS_SIZE / 4 _dummy_0: .long 0x00000000 registers_area: /* To be loaded in register when an exception is caught */ _serial_IO: /* r27 */ .long 0x800003F8 _messages_start: /* r28 */ .long _messages_table - 4 _excp_messages: /* r29 */ .long _excp_messages_table _max_excp: /* r30 */ .long (_last_excp_message - _excp_messages_table) / 4 _dummy_1: /* r31: dummy */ .long 0x00000000 .section .data .align 2 save_area: /* Area for r11 save when an exception is skipped */ .long 0x00000000