lkml.org 
[lkml]   [2011]   [Jul]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 01/19] OpenRISC: Boot code
    Date

    Architecture code and early setup routines for booting Linux.

    Signed-off-by: Jonas Bonn <jonas@southpole.se>
    Reviewed-by: Arnd Bergmann <arnd@arndb.de>
    ---
    arch/openrisc/kernel/entry.S | 1128 ++++++++++++++++++++++++++
    arch/openrisc/kernel/head.S | 1607 ++++++++++++++++++++++++++++++++++++++
    arch/openrisc/kernel/init_task.c | 41 +
    arch/openrisc/kernel/setup.c | 381 +++++++++
    4 files changed, 3157 insertions(+), 0 deletions(-)
    create mode 100644 arch/openrisc/kernel/entry.S
    create mode 100644 arch/openrisc/kernel/head.S
    create mode 100644 arch/openrisc/kernel/init_task.c
    create mode 100644 arch/openrisc/kernel/setup.c

    diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S
    new file mode 100644
    index 0000000..d5f9c35
    --- /dev/null
    +++ b/arch/openrisc/kernel/entry.S
    @@ -0,0 +1,1128 @@
    +/*
    + * OpenRISC entry.S
    + *
    + * Linux architectural port borrowing liberally from similar works of
    + * others. All original copyrights apply as per the original source
    + * declaration.
    + *
    + * Modifications for the OpenRISC architecture:
    + * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
    + * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com>
    + * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
    + *
    + * 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
    + * 2 of the License, or (at your option) any later version.
    + */
    +
    +#include <linux/linkage.h>
    +
    +#include <asm/processor.h>
    +#include <asm/unistd.h>
    +#include <asm/thread_info.h>
    +#include <asm/errno.h>
    +#include <asm/spr_defs.h>
    +#include <asm/page.h>
    +#include <asm/mmu.h>
    +#include <asm/pgtable.h>
    +#include <asm/asm-offsets.h>
    +
    +#define DISABLE_INTERRUPTS(t1,t2) \
    + l.mfspr t2,r0,SPR_SR ;\
    + l.movhi t1,hi(~(SPR_SR_IEE|SPR_SR_TEE)) ;\
    + l.ori t1,t1,lo(~(SPR_SR_IEE|SPR_SR_TEE)) ;\
    + l.and t2,t2,t1 ;\
    + l.mtspr r0,t2,SPR_SR
    +
    +#define ENABLE_INTERRUPTS(t1) \
    + l.mfspr t1,r0,SPR_SR ;\
    + l.ori t1,t1,lo(SPR_SR_IEE|SPR_SR_TEE) ;\
    + l.mtspr r0,t1,SPR_SR
    +
    +/* =========================================================[ macros ]=== */
    +
    +/*
    + * We need to disable interrupts at beginning of RESTORE_ALL
    + * since interrupt might come in after we've loaded EPC return address
    + * and overwrite EPC with address somewhere in RESTORE_ALL
    + * which is of course wrong!
    + */
    +
    +#define RESTORE_ALL \
    + DISABLE_INTERRUPTS(r3,r4) ;\
    + l.lwz r3,PT_PC(r1) ;\
    + l.mtspr r0,r3,SPR_EPCR_BASE ;\
    + l.lwz r3,PT_SR(r1) ;\
    + l.mtspr r0,r3,SPR_ESR_BASE ;\
    + l.lwz r2,PT_GPR2(r1) ;\
    + l.lwz r3,PT_GPR3(r1) ;\
    + l.lwz r4,PT_GPR4(r1) ;\
    + l.lwz r5,PT_GPR5(r1) ;\
    + l.lwz r6,PT_GPR6(r1) ;\
    + l.lwz r7,PT_GPR7(r1) ;\
    + l.lwz r8,PT_GPR8(r1) ;\
    + l.lwz r9,PT_GPR9(r1) ;\
    + l.lwz r10,PT_GPR10(r1) ;\
    + l.lwz r11,PT_GPR11(r1) ;\
    + l.lwz r12,PT_GPR12(r1) ;\
    + l.lwz r13,PT_GPR13(r1) ;\
    + l.lwz r14,PT_GPR14(r1) ;\
    + l.lwz r15,PT_GPR15(r1) ;\
    + l.lwz r16,PT_GPR16(r1) ;\
    + l.lwz r17,PT_GPR17(r1) ;\
    + l.lwz r18,PT_GPR18(r1) ;\
    + l.lwz r19,PT_GPR19(r1) ;\
    + l.lwz r20,PT_GPR20(r1) ;\
    + l.lwz r21,PT_GPR21(r1) ;\
    + l.lwz r22,PT_GPR22(r1) ;\
    + l.lwz r23,PT_GPR23(r1) ;\
    + l.lwz r24,PT_GPR24(r1) ;\
    + l.lwz r25,PT_GPR25(r1) ;\
    + l.lwz r26,PT_GPR26(r1) ;\
    + l.lwz r27,PT_GPR27(r1) ;\
    + l.lwz r28,PT_GPR28(r1) ;\
    + l.lwz r29,PT_GPR29(r1) ;\
    + l.lwz r30,PT_GPR30(r1) ;\
    + l.lwz r31,PT_GPR31(r1) ;\
    + l.lwz r1,PT_SP(r1) ;\
    + l.rfe
    +
    +
    +#define EXCEPTION_ENTRY(handler) \
    + .global handler ;\
    +handler: ;\
    + /* r1, EPCR, ESR a already saved */ ;\
    + l.sw PT_GPR2(r1),r2 ;\
    + l.sw PT_GPR3(r1),r3 ;\
    + l.sw PT_ORIG_GPR11(r1),r11 ;\
    + /* r4 already save */ ;\
    + l.sw PT_GPR5(r1),r5 ;\
    + l.sw PT_GPR6(r1),r6 ;\
    + l.sw PT_GPR7(r1),r7 ;\
    + l.sw PT_GPR8(r1),r8 ;\
    + l.sw PT_GPR9(r1),r9 ;\
    + /* r10 already saved */ ;\
    + l.sw PT_GPR11(r1),r11 ;\
    + /* r12 already saved */ ;\
    + l.sw PT_GPR13(r1),r13 ;\
    + l.sw PT_GPR14(r1),r14 ;\
    + l.sw PT_GPR15(r1),r15 ;\
    + l.sw PT_GPR16(r1),r16 ;\
    + l.sw PT_GPR17(r1),r17 ;\
    + l.sw PT_GPR18(r1),r18 ;\
    + l.sw PT_GPR19(r1),r19 ;\
    + l.sw PT_GPR20(r1),r20 ;\
    + l.sw PT_GPR21(r1),r21 ;\
    + l.sw PT_GPR22(r1),r22 ;\
    + l.sw PT_GPR23(r1),r23 ;\
    + l.sw PT_GPR24(r1),r24 ;\
    + l.sw PT_GPR25(r1),r25 ;\
    + l.sw PT_GPR26(r1),r26 ;\
    + l.sw PT_GPR27(r1),r27 ;\
    + l.sw PT_GPR28(r1),r28 ;\
    + l.sw PT_GPR29(r1),r29 ;\
    + /* r30 already save */ ;\
    +/* l.sw PT_GPR30(r1),r30*/ ;\
    + l.sw PT_GPR31(r1),r31 ;\
    + l.sw PT_SYSCALLNO(r1),r0
    +
    +#define UNHANDLED_EXCEPTION(handler,vector) \
    + .global handler ;\
    +handler: ;\
    + /* r1, EPCR, ESR already saved */ ;\
    + l.sw PT_GPR2(r1),r2 ;\
    + l.sw PT_GPR3(r1),r3 ;\
    + l.sw PT_ORIG_GPR11(r1),r11 ;\
    + l.sw PT_GPR5(r1),r5 ;\
    + l.sw PT_GPR6(r1),r6 ;\
    + l.sw PT_GPR7(r1),r7 ;\
    + l.sw PT_GPR8(r1),r8 ;\
    + l.sw PT_GPR9(r1),r9 ;\
    + /* r10 already saved */ ;\
    + l.sw PT_GPR11(r1),r11 ;\
    + /* r12 already saved */ ;\
    + l.sw PT_GPR13(r1),r13 ;\
    + l.sw PT_GPR14(r1),r14 ;\
    + l.sw PT_GPR15(r1),r15 ;\
    + l.sw PT_GPR16(r1),r16 ;\
    + l.sw PT_GPR17(r1),r17 ;\
    + l.sw PT_GPR18(r1),r18 ;\
    + l.sw PT_GPR19(r1),r19 ;\
    + l.sw PT_GPR20(r1),r20 ;\
    + l.sw PT_GPR21(r1),r21 ;\
    + l.sw PT_GPR22(r1),r22 ;\
    + l.sw PT_GPR23(r1),r23 ;\
    + l.sw PT_GPR24(r1),r24 ;\
    + l.sw PT_GPR25(r1),r25 ;\
    + l.sw PT_GPR26(r1),r26 ;\
    + l.sw PT_GPR27(r1),r27 ;\
    + l.sw PT_GPR28(r1),r28 ;\
    + l.sw PT_GPR29(r1),r29 ;\
    + /* r31 already saved */ ;\
    + l.sw PT_GPR30(r1),r30 ;\
    +/* l.sw PT_GPR31(r1),r31 */ ;\
    + l.sw PT_SYSCALLNO(r1),r0 ;\
    + l.addi r3,r1,0 ;\
    + /* r4 is exception EA */ ;\
    + l.addi r5,r0,vector ;\
    + l.jal unhandled_exception ;\
    + l.nop ;\
    + l.j _ret_from_exception ;\
    + l.nop
    +
    +/*
    + * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR
    + * contain the same values as when exception we're handling
    + * occured. in fact they never do. if you need them use
    + * values saved on stack (for SPR_EPC, SPR_ESR) or content
    + * of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE()
    + * in 'arch/or32/kernel/head.S'
    + */
    +
    +/* =====================================================[ exceptions] === */
    +
    +/* ---[ 0x100: RESET exception ]----------------------------------------- */
    +
    +EXCEPTION_ENTRY(_tng_kernel_start)
    + l.jal _start
    + l.andi r0,r0,0
    +
    +/* ---[ 0x200: BUS exception ]------------------------------------------- */
    +
    +EXCEPTION_ENTRY(_bus_fault_handler)
    + /* r4: EA of fault (set by EXCEPTION_HANDLE) */
    + l.jal do_bus_fault
    + l.addi r3,r1,0 /* pt_regs */
    +
    + l.j _ret_from_exception
    + l.nop
    +
    +/* ---[ 0x300: Data Page Fault exception ]------------------------------- */
    +
    +EXCEPTION_ENTRY(_data_page_fault_handler)
    + /* set up parameters for do_page_fault */
    + l.addi r3,r1,0 // pt_regs
    + /* r4 set be EXCEPTION_HANDLE */ // effective address of fault
    + l.ori r5,r0,0x300 // exception vector
    +
    + /*
    + * __PHX__: TODO
    + *
    + * all this can be written much simpler. look at
    + * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part
    + */
    +#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX
    + l.lwz r6,PT_PC(r3) // address of an offending insn
    + l.lwz r6,0(r6) // instruction that caused pf
    +
    + l.srli r6,r6,26 // check opcode for jump insn
    + l.sfeqi r6,0 // l.j
    + l.bf 8f
    + l.sfeqi r6,1 // l.jal
    + l.bf 8f
    + l.sfeqi r6,3 // l.bnf
    + l.bf 8f
    + l.sfeqi r6,4 // l.bf
    + l.bf 8f
    + l.sfeqi r6,0x11 // l.jr
    + l.bf 8f
    + l.sfeqi r6,0x12 // l.jalr
    + l.bf 8f
    +
    + l.nop
    +
    + l.j 9f
    + l.nop
    +8:
    +
    + l.lwz r6,PT_PC(r3) // address of an offending insn
    + l.addi r6,r6,4
    + l.lwz r6,0(r6) // instruction that caused pf
    + l.srli r6,r6,26 // get opcode
    +9:
    +
    +#else
    +
    + l.mfspr r6,r0,SPR_SR // SR
    +// l.lwz r6,PT_SR(r3) // ESR
    + l.andi r6,r6,SPR_SR_DSX // check for delay slot exception
    + l.sfeqi r6,0x1 // exception happened in delay slot
    + l.bnf 7f
    + l.lwz r6,PT_PC(r3) // address of an offending insn
    +
    + l.addi r6,r6,4 // offending insn is in delay slot
    +7:
    + l.lwz r6,0(r6) // instruction that caused pf
    + l.srli r6,r6,26 // check opcode for write access
    +#endif
    +
    + l.sfgeui r6,0x34 // check opcode for write access
    + l.bnf 1f
    + l.sfleui r6,0x37
    + l.bnf 1f
    + l.ori r6,r0,0x1 // write access
    + l.j 2f
    + l.nop
    +1: l.ori r6,r0,0x0 // !write access
    +2:
    +
    + /* call fault.c handler in or32/mm/fault.c */
    + l.jal do_page_fault
    + l.nop
    + l.j _ret_from_exception
    + l.nop
    +
    +/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */
    +
    +EXCEPTION_ENTRY(_insn_page_fault_handler)
    + /* set up parameters for do_page_fault */
    + l.addi r3,r1,0 // pt_regs
    + /* r4 set be EXCEPTION_HANDLE */ // effective address of fault
    + l.ori r5,r0,0x400 // exception vector
    + l.ori r6,r0,0x0 // !write access
    +
    + /* call fault.c handler in or32/mm/fault.c */
    + l.jal do_page_fault
    + l.nop
    + l.j _ret_from_exception
    + l.nop
    +
    +
    +/* ---[ 0x500: Timer exception ]----------------------------------------- */
    +
    +EXCEPTION_ENTRY(_timer_handler)
    + l.jal timer_interrupt
    + l.addi r3,r1,0 /* pt_regs */
    +
    + l.j _ret_from_intr
    + l.nop
    +
    +/* ---[ 0x600: Aligment exception ]-------------------------------------- */
    +
    +EXCEPTION_ENTRY(_alignment_handler)
    + /* r4: EA of fault (set by EXCEPTION_HANDLE) */
    + l.jal do_unaligned_access
    + l.addi r3,r1,0 /* pt_regs */
    +
    + l.j _ret_from_exception
    + l.nop
    +
    +#if 0
    +EXCEPTION_ENTRY(_aligment_handler)
    +// l.mfspr r2,r0,SPR_EEAR_BASE /* Load the efective addres */
    + l.addi r2,r4,0
    +// l.mfspr r5,r0,SPR_EPCR_BASE /* Load the insn address */
    + l.lwz r5,PT_PC(r1)
    +
    + l.lwz r3,0(r5) /* Load insn */
    + l.srli r4,r3,26 /* Shift left to get the insn opcode */
    +
    + l.sfeqi r4,0x00 /* Check if the load/store insn is in delay slot */
    + l.bf jmp
    + l.sfeqi r4,0x01
    + l.bf jmp
    + l.sfeqi r4,0x03
    + l.bf jmp
    + l.sfeqi r4,0x04
    + l.bf jmp
    + l.sfeqi r4,0x11
    + l.bf jr
    + l.sfeqi r4,0x12
    + l.bf jr
    + l.nop
    + l.j 1f
    + l.addi r5,r5,4 /* Increment PC to get return insn address */
    +
    +jmp:
    + l.slli r4,r3,6 /* Get the signed extended jump length */
    + l.srai r4,r4,4
    +
    + l.lwz r3,4(r5) /* Load the real load/store insn */
    +
    + l.add r5,r5,r4 /* Calculate jump target address */
    +
    + l.j 1f
    + l.srli r4,r3,26 /* Shift left to get the insn opcode */
    +
    +jr:
    + l.slli r4,r3,9 /* Shift to get the reg nb */
    + l.andi r4,r4,0x7c
    +
    + l.lwz r3,4(r5) /* Load the real load/store insn */
    +
    + l.add r4,r4,r1 /* Load the jump register value from the stack */
    + l.lwz r5,0(r4)
    +
    + l.srli r4,r3,26 /* Shift left to get the insn opcode */
    +
    +
    +1:
    +// l.mtspr r0,r5,SPR_EPCR_BASE
    + l.sw PT_PC(r1),r5
    +
    + l.sfeqi r4,0x26
    + l.bf lhs
    + l.sfeqi r4,0x25
    + l.bf lhz
    + l.sfeqi r4,0x22
    + l.bf lws
    + l.sfeqi r4,0x21
    + l.bf lwz
    + l.sfeqi r4,0x37
    + l.bf sh
    + l.sfeqi r4,0x35
    + l.bf sw
    + l.nop
    +
    +1: l.j 1b /* I don't know what to do */
    + l.nop
    +
    +lhs: l.lbs r5,0(r2)
    + l.slli r5,r5,8
    + l.lbz r6,1(r2)
    + l.or r5,r5,r6
    + l.srli r4,r3,19
    + l.andi r4,r4,0x7c
    + l.add r4,r4,r1
    + l.j align_end
    + l.sw 0(r4),r5
    +
    +lhz: l.lbz r5,0(r2)
    + l.slli r5,r5,8
    + l.lbz r6,1(r2)
    + l.or r5,r5,r6
    + l.srli r4,r3,19
    + l.andi r4,r4,0x7c
    + l.add r4,r4,r1
    + l.j align_end
    + l.sw 0(r4),r5
    +
    +lws: l.lbs r5,0(r2)
    + l.slli r5,r5,24
    + l.lbz r6,1(r2)
    + l.slli r6,r6,16
    + l.or r5,r5,r6
    + l.lbz r6,2(r2)
    + l.slli r6,r6,8
    + l.or r5,r5,r6
    + l.lbz r6,3(r2)
    + l.or r5,r5,r6
    + l.srli r4,r3,19
    + l.andi r4,r4,0x7c
    + l.add r4,r4,r1
    + l.j align_end
    + l.sw 0(r4),r5
    +
    +lwz: l.lbz r5,0(r2)
    + l.slli r5,r5,24
    + l.lbz r6,1(r2)
    + l.slli r6,r6,16
    + l.or r5,r5,r6
    + l.lbz r6,2(r2)
    + l.slli r6,r6,8
    + l.or r5,r5,r6
    + l.lbz r6,3(r2)
    + l.or r5,r5,r6
    + l.srli r4,r3,19
    + l.andi r4,r4,0x7c
    + l.add r4,r4,r1
    + l.j align_end
    + l.sw 0(r4),r5
    +
    +sh:
    + l.srli r4,r3,9
    + l.andi r4,r4,0x7c
    + l.add r4,r4,r1
    + l.lwz r5,0(r4)
    + l.sb 1(r2),r5
    + l.srli r5,r5,8
    + l.j align_end
    + l.sb 0(r2),r5
    +
    +sw:
    + l.srli r4,r3,9
    + l.andi r4,r4,0x7c
    + l.add r4,r4,r1
    + l.lwz r5,0(r4)
    + l.sb 3(r2),r5
    + l.srli r5,r5,8
    + l.sb 2(r2),r5
    + l.srli r5,r5,8
    + l.sb 1(r2),r5
    + l.srli r5,r5,8
    + l.j align_end
    + l.sb 0(r2),r5
    +
    +align_end:
    + l.j _ret_from_intr
    + l.nop
    +#endif
    +
    +/* ---[ 0x700: Illegal insn exception ]---------------------------------- */
    +
    +EXCEPTION_ENTRY(_illegal_instruction_handler)
    + /* r4: EA of fault (set by EXCEPTION_HANDLE) */
    + l.jal do_illegal_instruction
    + l.addi r3,r1,0 /* pt_regs */
    +
    + l.j _ret_from_exception
    + l.nop
    +
    +/* ---[ 0x800: External interrupt exception ]---------------------------- */
    +
    +EXCEPTION_ENTRY(_external_irq_handler)
    +#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK
    + l.lwz r4,PT_SR(r1) // were interrupts enabled ?
    + l.andi r4,r4,SPR_SR_IEE
    + l.sfeqi r4,0
    + l.bnf 1f // ext irq enabled, all ok.
    + l.nop
    +
    + l.addi r1,r1,-0x8
    + l.movhi r3,hi(42f)
    + l.ori r3,r3,lo(42f)
    + l.sw 0x0(r1),r3
    + l.jal printk
    + l.sw 0x4(r1),r4
    + l.addi r1,r1,0x8
    +
    + .section .rodata, "a"
    +42:
    + .string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r"
    + .align 4
    + .previous
    +
    + l.ori r4,r4,SPR_SR_IEE // fix the bug
    +// l.sw PT_SR(r1),r4
    +1:
    +#endif
    + l.addi r3,r1,0
    + l.movhi r8,hi(do_IRQ)
    + l.ori r8,r8,lo(do_IRQ)
    + l.jalr r8
    + l.nop
    + l.j _ret_from_intr
    + l.nop
    +
    +/* ---[ 0x900: DTLB miss exception ]------------------------------------- */
    +
    +
    +/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */
    +
    +
    +/* ---[ 0xb00: Range exception ]----------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0xb00,0xb00)
    +
    +/* ---[ 0xc00: Syscall exception ]--------------------------------------- */
    +
    +/*
    + * Syscalls are a special type of exception in that they are
    + * _explicitly_ invoked by userspace and can therefore be
    + * held to conform to the same ABI as normal functions with
    + * respect to whether registers are preserved across the call
    + * or not.
    + */
    +
    +/* Upon syscall entry we just save the callee-saved registers
    + * and not the call-clobbered ones.
    + */
    +
    +_string_syscall_return:
    + .string "syscall return %ld \n\r\0"
    + .align 4
    +
    +ENTRY(_sys_call_handler)
    + /* syscalls run with interrupts enabled */
    + ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp
    +
    + /* r1, EPCR, ESR a already saved */
    + l.sw PT_GPR2(r1),r2
    + /* r3-r8 must be saved because syscall restart relies
    + * on us being able to restart the syscall args... technically
    + * they should be clobbered, otherwise
    + */
    + l.sw PT_GPR3(r1),r3
    + /* r4 already saved */
    + /* r4 holds the EEAR address of the fault, load the original r4 */
    + l.lwz r4,PT_GPR4(r1)
    + l.sw PT_GPR5(r1),r5
    + l.sw PT_GPR6(r1),r6
    + l.sw PT_GPR7(r1),r7
    + l.sw PT_GPR8(r1),r8
    + l.sw PT_GPR9(r1),r9
    + /* r10 already saved */
    + l.sw PT_GPR11(r1),r11
    + l.sw PT_ORIG_GPR11(r1),r11
    + /* r12,r13 already saved */
    +
    + /* r14-r28 (even) aren't touched by the syscall fast path below
    + * so we don't need to save them. However, the functions that return
    + * to userspace via a call to switch() DO need to save these because
    + * switch() effectively clobbers them... saving these registers for
    + * such functions is handled in their syscall wrappers (see fork, vfork,
    + * and clone, below).
    +
    + /* r30 is the only register we clobber in the fast path */
    + /* r30 already saved */
    +/* l.sw PT_GPR30(r1),r30 */
    + /* This is used by do_signal to determine whether to check for
    + * syscall restart or not */
    + l.sw PT_SYSCALLNO(r1),r11
    +
    +_syscall_check_trace_enter:
    + /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
    + l.lwz r30,TI_FLAGS(r10)
    + l.andi r30,r30,_TIF_SYSCALL_TRACE
    + l.sfne r30,r0
    + l.bf _syscall_trace_enter
    + l.nop
    +
    +_syscall_check:
    + /* Ensure that the syscall number is reasonable */
    + l.sfgeui r11,__NR_syscalls
    + l.bf _syscall_badsys
    + l.nop
    +
    +_syscall_call:
    + l.movhi r29,hi(sys_call_table)
    + l.ori r29,r29,lo(sys_call_table)
    + l.slli r11,r11,2
    + l.add r29,r29,r11
    + l.lwz r29,0(r29)
    +
    + l.jalr r29
    + l.nop
    +
    +_syscall_return:
    + /* All syscalls return here... just pay attention to ret_from_fork
    + * which does it in a round-about way.
    + */
    + l.sw PT_GPR11(r1),r11 // save return value
    +
    +#if 0
    +_syscall_debug:
    + l.movhi r3,hi(_string_syscall_return)
    + l.ori r3,r3,lo(_string_syscall_return)
    + l.ori r27,r0,1
    + l.sw -4(r1),r27
    + l.sw -8(r1),r11
    + l.addi r1,r1,-8
    + l.movhi r27,hi(printk)
    + l.ori r27,r27,lo(printk)
    + l.jalr r27
    + l.nop
    + l.addi r1,r1,8
    +#endif
    +
    +_syscall_check_trace_leave:
    + /* r30 is a callee-saved register so this should still hold the
    + * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above...
    + * _syscall_trace_leave expects syscall result to be in pt_regs->r11.
    + */
    + l.sfne r30,r0
    + l.bf _syscall_trace_leave
    + l.nop
    +
    +/* This is where the exception-return code begins... interrupts need to be
    + * disabled the rest of the way here because we can't afford to miss any
    + * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */
    +
    +_syscall_check_work:
    + /* Here we need to disable interrupts */
    + DISABLE_INTERRUPTS(r27,r29)
    + l.lwz r30,TI_FLAGS(r10)
    + l.andi r30,r30,_TIF_WORK_MASK
    + l.sfne r30,r0
    +
    + l.bnf _syscall_resume_userspace
    + l.nop
    +
    + /* Work pending follows a different return path, so we need to
    + * make sure that all the call-saved registers get into pt_regs
    + * before branching...
    + */
    + l.sw PT_GPR14(r1),r14
    + l.sw PT_GPR16(r1),r16
    + l.sw PT_GPR18(r1),r18
    + l.sw PT_GPR20(r1),r20
    + l.sw PT_GPR22(r1),r22
    + l.sw PT_GPR24(r1),r24
    + l.sw PT_GPR26(r1),r26
    + l.sw PT_GPR28(r1),r28
    +
    + /* _work_pending needs to be called with interrupts disabled */
    + l.j _work_pending
    + l.nop
    +
    +_syscall_resume_userspace:
    +// ENABLE_INTERRUPTS(r29)
    +
    +
    +/* This is the hot path for returning to userspace from a syscall. If there's
    + * work to be done and the branch to _work_pending was taken above, then the
    + * return to userspace will be done via the normal exception return path...
    + * that path restores _all_ registers and will overwrite the "clobbered"
    + * registers with whatever garbage is in pt_regs -- that's OK because those
    + * registers are clobbered anyway and because the extra work is insignificant
    + * in the context of the extra work that _work_pending is doing.
    +
    +/* Once again, syscalls are special and only guarantee to preserve the
    + * same registers as a normal function call */
    +
    +/* The assumption here is that the registers r14-r28 (even) are untouched and
    + * don't need to be restored... be sure that that's really the case!
    + */
    +
    +/* This is still too much... we should only be restoring what we actually
    + * clobbered... we should even be using 'scratch' (odd) regs above so that
    + * we don't need to restore anything, hardly...
    + */
    +
    + l.lwz r2,PT_GPR2(r1)
    +
    + /* Restore args */
    + /* r3-r8 are technically clobbered, but syscall restart needs these
    + * to be restored...
    + */
    + l.lwz r3,PT_GPR3(r1)
    + l.lwz r4,PT_GPR4(r1)
    + l.lwz r5,PT_GPR5(r1)
    + l.lwz r6,PT_GPR6(r1)
    + l.lwz r7,PT_GPR7(r1)
    + l.lwz r8,PT_GPR8(r1)
    +
    + l.lwz r9,PT_GPR9(r1)
    + l.lwz r10,PT_GPR10(r1)
    + l.lwz r11,PT_GPR11(r1)
    +
    + /* r30 is the only register we clobber in the fast path */
    + l.lwz r30,PT_GPR30(r1)
    +
    + /* Here we use r13-r19 (odd) as scratch regs */
    + l.lwz r13,PT_PC(r1)
    + l.lwz r15,PT_SR(r1)
    + l.lwz r1,PT_SP(r1)
    + /* Interrupts need to be disabled for setting EPCR and ESR
    + * so that another interrupt doesn't come in here and clobber
    + * them before we can use them for our l.rfe */
    + DISABLE_INTERRUPTS(r17,r19)
    + l.mtspr r0,r13,SPR_EPCR_BASE
    + l.mtspr r0,r15,SPR_ESR_BASE
    + l.rfe
    +
    +/* End of hot path!
    + * Keep the below tracing and error handling out of the hot path...
    +*/
    +
    +_syscall_trace_enter:
    + /* Here we pass pt_regs to do_syscall_trace_enter. Make sure
    + * that function is really getting all the info it needs as
    + * pt_regs isn't a complete set of userspace regs, just the
    + * ones relevant to the syscall...
    + *
    + * Note use of delay slot for setting argument.
    + */
    + l.jal do_syscall_trace_enter
    + l.addi r3,r1,0
    +
    + /* Restore arguments (not preserved across do_syscall_trace_enter)
    + * so that we can do the syscall for real and return to the syscall
    + * hot path.
    + */
    + l.lwz r11,PT_SYSCALLNO(r1)
    + l.lwz r3,PT_GPR3(r1)
    + l.lwz r4,PT_GPR4(r1)
    + l.lwz r5,PT_GPR5(r1)
    + l.lwz r6,PT_GPR6(r1)
    + l.lwz r7,PT_GPR7(r1)
    +
    + l.j _syscall_check
    + l.lwz r8,PT_GPR8(r1)
    +
    +_syscall_trace_leave:
    + l.jal do_syscall_trace_leave
    + l.addi r3,r1,0
    +
    + l.j _syscall_check_work
    + l.nop
    +
    +_syscall_badsys:
    + /* Here we effectively pretend to have executed an imaginary
    + * syscall that returns -ENOSYS and then return to the regular
    + * syscall hot path.
    + * Note that "return value" is set in the delay slot...
    + */
    + l.j _syscall_return
    + l.addi r11,r0,-ENOSYS
    +
    +/******* END SYSCALL HANDLING *******/
    +
    +/* ---[ 0xd00: Trap exception ]------------------------------------------ */
    +
    +UNHANDLED_EXCEPTION(_vector_0xd00,0xd00)
    +
    +/* ---[ 0xe00: Trap exception ]------------------------------------------ */
    +
    +EXCEPTION_ENTRY(_trap_handler)
    + /* r4: EA of fault (set by EXCEPTION_HANDLE) */
    + l.jal do_trap
    + l.addi r3,r1,0 /* pt_regs */
    +
    + l.j _ret_from_exception
    + l.nop
    +
    +/* ---[ 0xf00: Reserved exception ]-------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0xf00,0xf00)
    +
    +/* ---[ 0x1000: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1000,0x1000)
    +
    +/* ---[ 0x1100: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1100,0x1100)
    +
    +/* ---[ 0x1200: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1200,0x1200)
    +
    +/* ---[ 0x1300: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1300,0x1300)
    +
    +/* ---[ 0x1400: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1400,0x1400)
    +
    +/* ---[ 0x1500: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1500,0x1500)
    +
    +/* ---[ 0x1600: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1600,0x1600)
    +
    +/* ---[ 0x1700: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1700,0x1700)
    +
    +/* ---[ 0x1800: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1800,0x1800)
    +
    +/* ---[ 0x1900: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1900,0x1900)
    +
    +/* ---[ 0x1a00: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00)
    +
    +/* ---[ 0x1b00: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00)
    +
    +/* ---[ 0x1c00: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00)
    +
    +/* ---[ 0x1d00: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00)
    +
    +/* ---[ 0x1e00: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00)
    +
    +/* ---[ 0x1f00: Reserved exception ]------------------------------------- */
    +
    +UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00)
    +
    +/* ========================================================[ return ] === */
    +
    +_work_pending:
    + /*
    + * if (current_thread_info->flags & _TIF_NEED_RESCHED)
    + * schedule();
    + */
    + l.lwz r5,TI_FLAGS(r10)
    + l.andi r3,r5,_TIF_NEED_RESCHED
    + l.sfnei r3,0
    + l.bnf _work_notifysig
    + l.nop
    + l.jal schedule
    + l.nop
    + l.j _resume_userspace
    + l.nop
    +
    +/* Handle pending signals and notify-resume requests.
    + * do_notify_resume must be passed the latest pushed pt_regs, not
    + * necessarily the "userspace" ones. Also, pt_regs->syscallno
    + * must be set so that the syscall restart functionality works.
    + */
    +_work_notifysig:
    + l.jal do_notify_resume
    + l.ori r3,r1,0 /* pt_regs */
    +
    +_resume_userspace:
    + DISABLE_INTERRUPTS(r3,r4)
    + l.lwz r3,TI_FLAGS(r10)
    + l.andi r3,r3,_TIF_WORK_MASK
    + l.sfnei r3,0
    + l.bf _work_pending
    + l.nop
    +
    +_restore_all:
    + RESTORE_ALL
    + /* This returns to userspace code */
    +
    +
    +ENTRY(_ret_from_intr)
    +ENTRY(_ret_from_exception)
    + l.lwz r4,PT_SR(r1)
    + l.andi r3,r4,SPR_SR_SM
    + l.sfeqi r3,0
    + l.bnf _restore_all
    + l.nop
    + l.j _resume_userspace
    + l.nop
    +
    +ENTRY(ret_from_fork)
    + l.jal schedule_tail
    + l.nop
    +
    + /* _syscall_returns expect r11 to contain return value */
    + l.lwz r11,PT_GPR11(r1)
    +
    + /* The syscall fast path return expects call-saved registers
    + * r12-r28 to be untouched, so we restore them here as they
    + * will have been effectively clobbered when arriving here
    + * via the call to switch()
    + */
    + l.lwz r12,PT_GPR12(r1)
    + l.lwz r14,PT_GPR14(r1)
    + l.lwz r16,PT_GPR16(r1)
    + l.lwz r18,PT_GPR18(r1)
    + l.lwz r20,PT_GPR20(r1)
    + l.lwz r22,PT_GPR22(r1)
    + l.lwz r24,PT_GPR24(r1)
    + l.lwz r26,PT_GPR26(r1)
    + l.lwz r28,PT_GPR28(r1)
    +
    + l.j _syscall_return
    + l.nop
    +
    +/* Since syscalls don't save call-clobbered registers, the args to
    + * kernel_thread_helper will need to be passed through callee-saved
    + * registers and copied to the parameter registers when the thread
    + * begins running.
    + *
    + * See arch/openrisc/kernel/process.c:
    + * The args are passed as follows:
    + * arg1 (r3) : passed in r20
    + * arg2 (r4) : passed in r22
    + */
    +
    +ENTRY(_kernel_thread_helper)
    + l.or r3,r20,r0
    + l.or r4,r22,r0
    + l.movhi r31,hi(kernel_thread_helper)
    + l.ori r31,r31,lo(kernel_thread_helper)
    + l.jr r31
    + l.nop
    +
    +
    +/* ========================================================[ switch ] === */
    +
    +/*
    + * This routine switches between two different tasks. The process
    + * state of one is saved on its kernel stack. Then the state
    + * of the other is restored from its kernel stack. The memory
    + * management hardware is updated to the second process's state.
    + * Finally, we can return to the second process, via the 'return'.
    + *
    + * Note: there are two ways to get to the "going out" portion
    + * of this code; either by coming in via the entry (_switch)
    + * or via "fork" which must set up an environment equivalent
    + * to the "_switch" path. If you change this (or in particular, the
    + * SAVE_REGS macro), you'll have to change the fork code also.
    + */
    +
    +
    +/* _switch MUST never lay on page boundry, cause it runs from
    + * effective addresses and beeing interrupted by iTLB miss would kill it.
    + * dTLB miss seams to never accour in the bad place since data accesses
    + * are from task structures which are always page aligned.
    + *
    + * The problem happens in RESTORE_ALL_NO_R11 where we first set the EPCR
    + * register, then load the previous register values and only at the end call
    + * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets
    + * garbled and we end up calling l.rfe with the wrong EPCR. (same probably
    + * holds for ESR)
    + *
    + * To avoid this problems it is sufficient to align _switch to
    + * some nice round number smaller than it's size...
    + */
    +
    +/* ABI rules apply here... we either enter _switch via schedule() or via
    + * an imaginary call to which we shall return at return_from_fork. Either
    + * way, we are a function call and only need to preserve the callee-saved
    + * registers when we return. As such, we don't need to save the registers
    + * on the stack that we won't be returning as they were...
    + */
    +
    + .align 0x400
    +ENTRY(_switch)
    + /* We don't store SR as _switch only gets called in a context where
    + * the SR will be the same going in and coming out... */
    +
    + /* Set up new pt_regs struct for saving task state */
    + l.addi r1,r1,-(INT_FRAME_SIZE)
    +
    + /* No need to store r1/PT_SP as it goes into KSP below */
    + l.sw PT_GPR2(r1),r2
    + l.sw PT_GPR9(r1),r9
    + /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being
    + * and expects r12 to be callee-saved... */
    + l.sw PT_GPR12(r1),r12
    + l.sw PT_GPR14(r1),r14
    + l.sw PT_GPR16(r1),r16
    + l.sw PT_GPR18(r1),r18
    + l.sw PT_GPR20(r1),r20
    + l.sw PT_GPR22(r1),r22
    + l.sw PT_GPR24(r1),r24
    + l.sw PT_GPR26(r1),r26
    + l.sw PT_GPR28(r1),r28
    + l.sw PT_GPR30(r1),r30
    +
    + l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/
    +
    + /* We use thread_info->ksp for storing the address of the above
    + * structure so that we can get back to it later... we don't want
    + * to lose the value of thread_info->ksp, though, so store it as
    + * pt_regs->sp so that we can easily restore it when we are made
    + * live again...
    + */
    +
    + /* Save the old value of thread_info->ksp as pt_regs->sp */
    + l.lwz r29,TI_KSP(r10)
    + l.sw PT_SP(r1),r29
    +
    + /* Swap kernel stack pointers */
    + l.sw TI_KSP(r10),r1 /* Save old stack pointer */
    + l.or r10,r4,r0 /* Set up new current_thread_info */
    + l.lwz r1,TI_KSP(r10) /* Load new stack pointer */
    +
    + /* Restore the old value of thread_info->ksp */
    + l.lwz r29,PT_SP(r1)
    + l.sw TI_KSP(r10),r29
    +
    + /* ...and restore the registers, except r11 because the return value
    + * has already been set above.
    + */
    + l.lwz r2,PT_GPR2(r1)
    + l.lwz r9,PT_GPR9(r1)
    + /* No need to restore r10 */
    + /* ...and do not restore r11 */
    +
    + /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being
    + * and expects r12 to be callee-saved... */
    + l.lwz r12,PT_GPR12(r1)
    + l.lwz r14,PT_GPR14(r1)
    + l.lwz r16,PT_GPR16(r1)
    + l.lwz r18,PT_GPR18(r1)
    + l.lwz r20,PT_GPR20(r1)
    + l.lwz r22,PT_GPR22(r1)
    + l.lwz r24,PT_GPR24(r1)
    + l.lwz r26,PT_GPR26(r1)
    + l.lwz r28,PT_GPR28(r1)
    + l.lwz r30,PT_GPR30(r1)
    +
    + /* Unwind stack to pre-switch state */
    + l.addi r1,r1,(INT_FRAME_SIZE)
    +
    + /* Return via the link-register back to where we 'came from', where that can be
    + * either schedule() or return_from_fork()... */
    + l.jr r9
    + l.nop
    +
    +/* ==================================================================== */
    +
    +/* These all use the delay slot for setting the argument register, so the
    + * jump is always happening after the l.addi instruction.
    + *
    + * These are all just wrappers that don't touch the link-register r9, so the
    + * return from the "real" syscall function will return back to the syscall
    + * code that did the l.jal that brought us here.
    + */
    +
    +/* fork requires that we save all the callee-saved registers because they
    + * are all effectively clobbered by the call to _switch. Here we store
    + * all the registers that aren't touched by the syscall fast path and thus
    + * weren't saved there.
    + */
    +
    +_fork_save_extra_regs_and_call:
    + l.sw PT_GPR14(r1),r14
    + l.sw PT_GPR16(r1),r16
    + l.sw PT_GPR18(r1),r18
    + l.sw PT_GPR20(r1),r20
    + l.sw PT_GPR22(r1),r22
    + l.sw PT_GPR24(r1),r24
    + l.sw PT_GPR26(r1),r26
    + l.jr r29
    + l.sw PT_GPR28(r1),r28
    +
    +ENTRY(sys_clone)
    + l.movhi r29,hi(_sys_clone)
    + l.ori r29,r29,lo(_sys_clone)
    + l.j _fork_save_extra_regs_and_call
    + l.addi r7,r1,0
    +
    +ENTRY(sys_fork)
    + l.movhi r29,hi(_sys_fork)
    + l.ori r29,r29,lo(_sys_fork)
    + l.j _fork_save_extra_regs_and_call
    + l.addi r3,r1,0
    +
    +ENTRY(sys_execve)
    + l.j _sys_execve
    + l.addi r6,r1,0
    +
    +ENTRY(sys_sigaltstack)
    + l.j _sys_sigaltstack
    + l.addi r5,r1,0
    +
    +ENTRY(sys_rt_sigreturn)
    + l.j _sys_rt_sigreturn
    + l.addi r3,r1,0
    +
    +/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000.
    + * The functions takes a variable number of parameters depending on which
    + * particular flavour of atomic you want... parameter 1 is a flag identifying
    + * the atomic in question. Currently, this function implements the
    + * following variants:
    + *
    + * XCHG:
    + * @flag: 1
    + * @ptr1:
    + * @ptr2:
    + * Atomically exchange the values in pointers 1 and 2.
    + *
    + */
    +
    +ENTRY(sys_or1k_atomic)
    + /* FIXME: This ignores r3 and always does an XCHG */
    + DISABLE_INTERRUPTS(r17,r19)
    + l.lwz r30,0(r4)
    + l.lwz r28,0(r5)
    + l.sw 0(r4),r28
    + l.sw 0(r5),r30
    + ENABLE_INTERRUPTS(r17)
    + l.jr r9
    + l.or r11,r0,r0
    +
    +/* ============================================================[ EOF ]=== */
    diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S
    new file mode 100644
    index 0000000..c75018d
    --- /dev/null
    +++ b/arch/openrisc/kernel/head.S
    @@ -0,0 +1,1607 @@
    +/*
    + * OpenRISC head.S
    + *
    + * Linux architectural port borrowing liberally from similar works of
    + * others. All original copyrights apply as per the original source
    + * declaration.
    + *
    + * Modifications for the OpenRISC architecture:
    + * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
    + * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
    + *
    + * 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
    + * 2 of the License, or (at your option) any later version.
    + */
    +
    +#include <linux/linkage.h>
    +#include <linux/threads.h>
    +#include <linux/errno.h>
    +#include <linux/init.h>
    +#include <asm/processor.h>
    +#include <asm/page.h>
    +#include <asm/mmu.h>
    +#include <asm/pgtable.h>
    +#include <asm/cache.h>
    +#include <asm/spr_defs.h>
    +#include <asm/asm-offsets.h>
    +
    +#define tophys(rd,rs) \
    + l.movhi rd,hi(-KERNELBASE) ;\
    + l.add rd,rd,rs
    +
    +#define CLEAR_GPR(gpr) \
    + l.or gpr,r0,r0
    +
    +#define LOAD_SYMBOL_2_GPR(gpr,symbol) \
    + l.movhi gpr,hi(symbol) ;\
    + l.ori gpr,gpr,lo(symbol)
    +
    +
    +#define UART_BASE_ADD 0x90000000
    +
    +#define EXCEPTION_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_SM)
    +#define SYSCALL_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_IEE | SPR_SR_TEE | SPR_SR_SM)
    +
    +/* ============================================[ tmp store locations ]=== */
    +
    +/*
    + * emergency_print temporary stores
    + */
    +#define EMERGENCY_PRINT_STORE_GPR4 l.sw 0x20(r0),r4
    +#define EMERGENCY_PRINT_LOAD_GPR4 l.lwz r4,0x20(r0)
    +
    +#define EMERGENCY_PRINT_STORE_GPR5 l.sw 0x24(r0),r5
    +#define EMERGENCY_PRINT_LOAD_GPR5 l.lwz r5,0x24(r0)
    +
    +#define EMERGENCY_PRINT_STORE_GPR6 l.sw 0x28(r0),r6
    +#define EMERGENCY_PRINT_LOAD_GPR6 l.lwz r6,0x28(r0)
    +
    +#define EMERGENCY_PRINT_STORE_GPR7 l.sw 0x2c(r0),r7
    +#define EMERGENCY_PRINT_LOAD_GPR7 l.lwz r7,0x2c(r0)
    +
    +#define EMERGENCY_PRINT_STORE_GPR8 l.sw 0x30(r0),r8
    +#define EMERGENCY_PRINT_LOAD_GPR8 l.lwz r8,0x30(r0)
    +
    +#define EMERGENCY_PRINT_STORE_GPR9 l.sw 0x34(r0),r9
    +#define EMERGENCY_PRINT_LOAD_GPR9 l.lwz r9,0x34(r0)
    +
    +
    +/*
    + * TLB miss handlers temorary stores
    + */
    +#define EXCEPTION_STORE_GPR9 l.sw 0x10(r0),r9
    +#define EXCEPTION_LOAD_GPR9 l.lwz r9,0x10(r0)
    +
    +#define EXCEPTION_STORE_GPR2 l.sw 0x64(r0),r2
    +#define EXCEPTION_LOAD_GPR2 l.lwz r2,0x64(r0)
    +
    +#define EXCEPTION_STORE_GPR3 l.sw 0x68(r0),r3
    +#define EXCEPTION_LOAD_GPR3 l.lwz r3,0x68(r0)
    +
    +#define EXCEPTION_STORE_GPR4 l.sw 0x6c(r0),r4
    +#define EXCEPTION_LOAD_GPR4 l.lwz r4,0x6c(r0)
    +
    +#define EXCEPTION_STORE_GPR5 l.sw 0x70(r0),r5
    +#define EXCEPTION_LOAD_GPR5 l.lwz r5,0x70(r0)
    +
    +#define EXCEPTION_STORE_GPR6 l.sw 0x74(r0),r6
    +#define EXCEPTION_LOAD_GPR6 l.lwz r6,0x74(r0)
    +
    +
    +/*
    + * EXCEPTION_HANDLE temporary stores
    + */
    +
    +#define EXCEPTION_T_STORE_GPR30 l.sw 0x78(r0),r30
    +#define EXCEPTION_T_LOAD_GPR30(reg) l.lwz reg,0x78(r0)
    +
    +#define EXCEPTION_T_STORE_GPR10 l.sw 0x7c(r0),r10
    +#define EXCEPTION_T_LOAD_GPR10(reg) l.lwz reg,0x7c(r0)
    +
    +#define EXCEPTION_T_STORE_SP l.sw 0x80(r0),r1
    +#define EXCEPTION_T_LOAD_SP(reg) l.lwz reg,0x80(r0)
    +
    +/*
    + * For UNHANLDED_EXCEPTION
    + */
    +
    +#define EXCEPTION_T_STORE_GPR31 l.sw 0x84(r0),r31
    +#define EXCEPTION_T_LOAD_GPR31(reg) l.lwz reg,0x84(r0)
    +
    +/* =========================================================[ macros ]=== */
    +
    +
    +#define GET_CURRENT_PGD(reg,t1) \
    + LOAD_SYMBOL_2_GPR(reg,current_pgd) ;\
    + tophys (t1,reg) ;\
    + l.lwz reg,0(t1)
    +
    +
    +/*
    + * DSCR: this is a common hook for handling exceptions. it will save
    + * the needed registers, set up stack and pointer to current
    + * then jump to the handler while enabling MMU
    + *
    + * PRMS: handler - a function to jump to. it has to save the
    + * remaining registers to kernel stack, call
    + * appropriate arch-independant exception handler
    + * and finaly jump to ret_from_except
    + *
    + * PREQ: unchanged state from the time exception happened
    + *
    + * POST: SAVED the following registers original value
    + * to the new created exception frame pointed to by r1
    + *
    + * r1 - ksp pointing to the new (exception) frame
    + * r4 - EEAR exception EA
    + * r10 - current pointing to current_thread_info struct
    + * r12 - syscall 0, since we didn't come from syscall
    + * r13 - temp it actually contains new SR, not needed anymore
    + * r31 - handler address of the handler we'll jump to
    + *
    + * handler has to save remaining registers to the exception
    + * ksp frame *before* tainting them!
    + *
    + * NOTE: this function is not reentrant per se. reentrancy is guaranteed
    + * by processor disabling all exceptions/interrupts when exception
    + * accours.
    + *
    + * OPTM: no need to make it so wasteful to extract ksp when in user mode
    + */
    +
    +#define EXCEPTION_HANDLE(handler) \
    + EXCEPTION_T_STORE_GPR30 ;\
    + l.mfspr r30,r0,SPR_ESR_BASE ;\
    + l.andi r30,r30,SPR_SR_SM ;\
    + l.sfeqi r30,0 ;\
    + EXCEPTION_T_STORE_GPR10 ;\
    + l.bnf 2f /* kernel_mode */ ;\
    + EXCEPTION_T_STORE_SP /* delay slot */ ;\
    +1: /* user_mode: */ ;\
    + LOAD_SYMBOL_2_GPR(r1,current_thread_info_set) ;\
    + tophys (r30,r1) ;\
    + /* r10: current_thread_info */ ;\
    + l.lwz r10,0(r30) ;\
    + tophys (r30,r10) ;\
    + l.lwz r1,(TI_KSP)(r30) ;\
    + /* fall through */ ;\
    +2: /* kernel_mode: */ ;\
    + /* create new stack frame, save only needed gprs */ ;\
    + /* r1: KSP, r10: current, r4: EEAR, r31: __pa(KSP) */ ;\
    + /* r12: temp, syscall indicator */ ;\
    + l.addi r1,r1,-(INT_FRAME_SIZE) ;\
    + /* r1 is KSP, r30 is __pa(KSP) */ ;\
    + tophys (r30,r1) ;\
    + l.sw PT_GPR12(r30),r12 ;\
    + l.mfspr r12,r0,SPR_EPCR_BASE ;\
    + l.sw PT_PC(r30),r12 ;\
    + l.mfspr r12,r0,SPR_ESR_BASE ;\
    + l.sw PT_SR(r30),r12 ;\
    + /* save r30 */ ;\
    + EXCEPTION_T_LOAD_GPR30(r12) ;\
    + l.sw PT_GPR30(r30),r12 ;\
    + /* save r10 as was prior to exception */ ;\
    + EXCEPTION_T_LOAD_GPR10(r12) ;\
    + l.sw PT_GPR10(r30),r12 ;\
    + /* save PT_SP as was prior to exception */ ;\
    + EXCEPTION_T_LOAD_SP(r12) ;\
    + l.sw PT_SP(r30),r12 ;\
    + /* save exception r4, set r4 = EA */ ;\
    + l.sw PT_GPR4(r30),r4 ;\
    + l.mfspr r4,r0,SPR_EEAR_BASE ;\
    + /* r12 == 1 if we come from syscall */ ;\
    + CLEAR_GPR(r12) ;\
    + /* ----- turn on MMU ----- */ ;\
    + l.ori r30,r0,(EXCEPTION_SR) ;\
    + l.mtspr r0,r30,SPR_ESR_BASE ;\
    + /* r30: EA address of handler */ ;\
    + LOAD_SYMBOL_2_GPR(r30,handler) ;\
    + l.mtspr r0,r30,SPR_EPCR_BASE ;\
    + l.rfe
    +
    +/*
    + * this doesn't work
    + *
    + *
    + * #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION
    + * #define UNHANDLED_EXCEPTION(handler) \
    + * l.ori r3,r0,0x1 ;\
    + * l.mtspr r0,r3,SPR_SR ;\
    + * l.movhi r3,hi(0xf0000100) ;\
    + * l.ori r3,r3,lo(0xf0000100) ;\
    + * l.jr r3 ;\
    + * l.nop 1
    + *
    + * #endif
    + */
    +
    +/* DSCR: this is the same as EXCEPTION_HANDLE(), we are just
    + * a bit more carefull (if we have a PT_SP or current pointer
    + * corruption) and set them up from 'current_set'
    + *
    + */
    +#define UNHANDLED_EXCEPTION(handler) \
    + EXCEPTION_T_STORE_GPR31 ;\
    + EXCEPTION_T_STORE_GPR10 ;\
    + EXCEPTION_T_STORE_SP ;\
    + /* temporary store r3, r9 into r1, r10 */ ;\
    + l.addi r1,r3,0x0 ;\
    + l.addi r10,r9,0x0 ;\
    + /* the string referenced by r3 must be low enough */ ;\
    + l.jal _emergency_print ;\
    + l.ori r3,r0,lo(_string_unhandled_exception) ;\
    + l.mfspr r3,r0,SPR_NPC ;\
    + l.jal _emergency_print_nr ;\
    + l.andi r3,r3,0x1f00 ;\
    + /* the string referenced by r3 must be low enough */ ;\
    + l.jal _emergency_print ;\
    + l.ori r3,r0,lo(_string_epc_prefix) ;\
    + l.jal _emergency_print_nr ;\
    + l.mfspr r3,r0,SPR_EPCR_BASE ;\
    + l.jal _emergency_print ;\
    + l.ori r3,r0,lo(_string_nl) ;\
    + /* end of printing */ ;\
    + l.addi r3,r1,0x0 ;\
    + l.addi r9,r10,0x0 ;\
    + /* extract current, ksp from current_set */ ;\
    + LOAD_SYMBOL_2_GPR(r1,_unhandled_stack_top) ;\
    + LOAD_SYMBOL_2_GPR(r10,init_thread_union) ;\
    + /* create new stack frame, save only needed gprs */ ;\
    + /* r1: KSP, r10: current, r31: __pa(KSP) */ ;\
    + /* r12: temp, syscall indicator, r13 temp */ ;\
    + l.addi r1,r1,-(INT_FRAME_SIZE) ;\
    + /* r1 is KSP, r31 is __pa(KSP) */ ;\
    + tophys (r31,r1) ;\
    + l.sw PT_GPR12(r31),r12 ;\
    + l.mfspr r12,r0,SPR_EPCR_BASE ;\
    + l.sw PT_PC(r31),r12 ;\
    + l.mfspr r12,r0,SPR_ESR_BASE ;\
    + l.sw PT_SR(r31),r12 ;\
    + /* save r31 */ ;\
    + EXCEPTION_T_LOAD_GPR31(r12) ;\
    + l.sw PT_GPR31(r31),r12 ;\
    + /* save r10 as was prior to exception */ ;\
    + EXCEPTION_T_LOAD_GPR10(r12) ;\
    + l.sw PT_GPR10(r31),r12 ;\
    + /* save PT_SP as was prior to exception */ ;\
    + EXCEPTION_T_LOAD_SP(r12) ;\
    + l.sw PT_SP(r31),r12 ;\
    + l.sw PT_GPR13(r31),r13 ;\
    + /* --> */ ;\
    + /* save exception r4, set r4 = EA */ ;\
    + l.sw PT_GPR4(r31),r4 ;\
    + l.mfspr r4,r0,SPR_EEAR_BASE ;\
    + /* r12 == 1 if we come from syscall */ ;\
    + CLEAR_GPR(r12) ;\
    + /* ----- play a MMU trick ----- */ ;\
    + l.ori r31,r0,(EXCEPTION_SR) ;\
    + l.mtspr r0,r31,SPR_ESR_BASE ;\
    + /* r31: EA address of handler */ ;\
    + LOAD_SYMBOL_2_GPR(r31,handler) ;\
    + l.mtspr r0,r31,SPR_EPCR_BASE ;\
    + l.rfe
    +
    +/* =====================================================[ exceptions] === */
    +
    +/* ---[ 0x100: RESET exception ]----------------------------------------- */
    + .org 0x100
    + /* Jump to .init code at _start which lives in the .head section
    + * and will be discarded after boot.
    + */
    + LOAD_SYMBOL_2_GPR(r4, _start)
    + tophys (r3,r4) /* MMU disabled */
    + l.jr r3
    + l.nop
    +
    +/* ---[ 0x200: BUS exception ]------------------------------------------- */
    + .org 0x200
    +_dispatch_bus_fault:
    + EXCEPTION_HANDLE(_bus_fault_handler)
    +
    +/* ---[ 0x300: Data Page Fault exception ]------------------------------- */
    + .org 0x300
    +_dispatch_do_dpage_fault:
    +// totaly disable timer interrupt
    +// l.mtspr r0,r0,SPR_TTMR
    +// DEBUG_TLB_PROBE(0x300)
    +// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x300)
    + EXCEPTION_HANDLE(_data_page_fault_handler)
    +
    +/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */
    + .org 0x400
    +_dispatch_do_ipage_fault:
    +// totaly disable timer interrupt
    +// l.mtspr r0,r0,SPR_TTMR
    +// DEBUG_TLB_PROBE(0x400)
    +// EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x400)
    + EXCEPTION_HANDLE(_insn_page_fault_handler)
    +
    +/* ---[ 0x500: Timer exception ]----------------------------------------- */
    + .org 0x500
    + EXCEPTION_HANDLE(_timer_handler)
    +
    +/* ---[ 0x600: Aligment exception ]-------------------------------------- */
    + .org 0x600
    + EXCEPTION_HANDLE(_alignment_handler)
    +
    +/* ---[ 0x700: Illegal insn exception ]---------------------------------- */
    + .org 0x700
    + EXCEPTION_HANDLE(_illegal_instruction_handler)
    +
    +/* ---[ 0x800: External interrupt exception ]---------------------------- */
    + .org 0x800
    + EXCEPTION_HANDLE(_external_irq_handler)
    +
    +/* ---[ 0x900: DTLB miss exception ]------------------------------------- */
    + .org 0x900
    + l.j boot_dtlb_miss_handler
    + l.nop
    +
    +/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */
    + .org 0xa00
    + l.j boot_itlb_miss_handler
    + l.nop
    +
    +/* ---[ 0xb00: Range exception ]----------------------------------------- */
    + .org 0xb00
    + UNHANDLED_EXCEPTION(_vector_0xb00)
    +
    +/* ---[ 0xc00: Syscall exception ]--------------------------------------- */
    + .org 0xc00
    + EXCEPTION_HANDLE(_sys_call_handler)
    +
    +/* ---[ 0xd00: Trap exception ]------------------------------------------ */
    + .org 0xd00
    + UNHANDLED_EXCEPTION(_vector_0xd00)
    +
    +/* ---[ 0xe00: Trap exception ]------------------------------------------ */
    + .org 0xe00
    +// UNHANDLED_EXCEPTION(_vector_0xe00)
    + EXCEPTION_HANDLE(_trap_handler)
    +
    +/* ---[ 0xf00: Reserved exception ]-------------------------------------- */
    + .org 0xf00
    + UNHANDLED_EXCEPTION(_vector_0xf00)
    +
    +/* ---[ 0x1000: Reserved exception ]------------------------------------- */
    + .org 0x1000
    + UNHANDLED_EXCEPTION(_vector_0x1000)
    +
    +/* ---[ 0x1100: Reserved exception ]------------------------------------- */
    + .org 0x1100
    + UNHANDLED_EXCEPTION(_vector_0x1100)
    +
    +/* ---[ 0x1200: Reserved exception ]------------------------------------- */
    + .org 0x1200
    + UNHANDLED_EXCEPTION(_vector_0x1200)
    +
    +/* ---[ 0x1300: Reserved exception ]------------------------------------- */
    + .org 0x1300
    + UNHANDLED_EXCEPTION(_vector_0x1300)
    +
    +/* ---[ 0x1400: Reserved exception ]------------------------------------- */
    + .org 0x1400
    + UNHANDLED_EXCEPTION(_vector_0x1400)
    +
    +/* ---[ 0x1500: Reserved exception ]------------------------------------- */
    + .org 0x1500
    + UNHANDLED_EXCEPTION(_vector_0x1500)
    +
    +/* ---[ 0x1600: Reserved exception ]------------------------------------- */
    + .org 0x1600
    + UNHANDLED_EXCEPTION(_vector_0x1600)
    +
    +/* ---[ 0x1700: Reserved exception ]------------------------------------- */
    + .org 0x1700
    + UNHANDLED_EXCEPTION(_vector_0x1700)
    +
    +/* ---[ 0x1800: Reserved exception ]------------------------------------- */
    + .org 0x1800
    + UNHANDLED_EXCEPTION(_vector_0x1800)
    +
    +/* ---[ 0x1900: Reserved exception ]------------------------------------- */
    + .org 0x1900
    + UNHANDLED_EXCEPTION(_vector_0x1900)
    +
    +/* ---[ 0x1a00: Reserved exception ]------------------------------------- */
    + .org 0x1a00
    + UNHANDLED_EXCEPTION(_vector_0x1a00)
    +
    +/* ---[ 0x1b00: Reserved exception ]------------------------------------- */
    + .org 0x1b00
    + UNHANDLED_EXCEPTION(_vector_0x1b00)
    +
    +/* ---[ 0x1c00: Reserved exception ]------------------------------------- */
    + .org 0x1c00
    + UNHANDLED_EXCEPTION(_vector_0x1c00)
    +
    +/* ---[ 0x1d00: Reserved exception ]------------------------------------- */
    + .org 0x1d00
    + UNHANDLED_EXCEPTION(_vector_0x1d00)
    +
    +/* ---[ 0x1e00: Reserved exception ]------------------------------------- */
    + .org 0x1e00
    + UNHANDLED_EXCEPTION(_vector_0x1e00)
    +
    +/* ---[ 0x1f00: Reserved exception ]------------------------------------- */
    + .org 0x1f00
    + UNHANDLED_EXCEPTION(_vector_0x1f00)
    +
    + .org 0x2000
    +/* ===================================================[ kernel start ]=== */
    +
    +/* .text*/
    +
    +/* This early stuff belongs in HEAD, but some of the functions below definitely
    + * don't... */
    +
    + __HEAD
    + .global _start
    +_start:
    + /*
    + * ensure a deterministic start
    + */
    +
    + l.ori r3,r0,0x1
    + l.mtspr r0,r3,SPR_SR
    +
    + CLEAR_GPR(r1)
    + CLEAR_GPR(r2)
    + CLEAR_GPR(r3)
    + CLEAR_GPR(r4)
    + CLEAR_GPR(r5)
    + CLEAR_GPR(r6)
    + CLEAR_GPR(r7)
    + CLEAR_GPR(r8)
    + CLEAR_GPR(r9)
    + CLEAR_GPR(r10)
    + CLEAR_GPR(r11)
    + CLEAR_GPR(r12)
    + CLEAR_GPR(r13)
    + CLEAR_GPR(r14)
    + CLEAR_GPR(r15)
    + CLEAR_GPR(r16)
    + CLEAR_GPR(r17)
    + CLEAR_GPR(r18)
    + CLEAR_GPR(r19)
    + CLEAR_GPR(r20)
    + CLEAR_GPR(r21)
    + CLEAR_GPR(r22)
    + CLEAR_GPR(r23)
    + CLEAR_GPR(r24)
    + CLEAR_GPR(r25)
    + CLEAR_GPR(r26)
    + CLEAR_GPR(r27)
    + CLEAR_GPR(r28)
    + CLEAR_GPR(r29)
    + CLEAR_GPR(r30)
    + CLEAR_GPR(r31)
    +
    + /*
    + * set up initial ksp and current
    + */
    + LOAD_SYMBOL_2_GPR(r1,init_thread_union+0x2000) // setup kernel stack
    + LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current
    + tophys (r31,r10)
    + l.sw TI_KSP(r31), r1
    +
    + l.ori r4,r0,0x0
    +
    +
    + /*
    + * .data contains initialized data,
    + * .bss contains uninitialized data - clear it up
    + */
    +clear_bss:
    + LOAD_SYMBOL_2_GPR(r24, __bss_start)
    + LOAD_SYMBOL_2_GPR(r26, _end)
    + tophys(r28,r24)
    + tophys(r30,r26)
    + CLEAR_GPR(r24)
    + CLEAR_GPR(r26)
    +1:
    + l.sw (0)(r28),r0
    + l.sfltu r28,r30
    + l.bf 1b
    + l.addi r28,r28,4
    +
    +enable_ic:
    + l.jal _ic_enable
    + l.nop
    +
    +enable_dc:
    + l.jal _dc_enable
    + l.nop
    +
    +flush_tlb:
    + /*
    + * I N V A L I D A T E T L B e n t r i e s
    + */
    + LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0))
    + LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0))
    + l.addi r7,r0,128 /* Maximum number of sets */
    +1:
    + l.mtspr r5,r0,0x0
    + l.mtspr r6,r0,0x0
    +
    + l.addi r5,r5,1
    + l.addi r6,r6,1
    + l.sfeq r7,r0
    + l.bnf 1b
    + l.addi r7,r7,-1
    +
    +
    +/* The MMU needs to be enabled before or32_early_setup is called */
    +
    +enable_mmu:
    + /*
    + * enable dmmu & immu
    + * SR[5] = 0, SR[6] = 0, 6th and 7th bit of SR set to 0
    + */
    + l.mfspr r30,r0,SPR_SR
    + l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME)
    + l.ori r28,r28,lo(SPR_SR_DME | SPR_SR_IME)
    + l.or r30,r30,r28
    + l.mtspr r0,r30,SPR_SR
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    +
    + // reset the simulation counters
    + l.nop 5
    +
    + LOAD_SYMBOL_2_GPR(r24, or32_early_setup)
    + l.jalr r24
    + l.nop
    +
    +clear_regs:
    + /*
    + * clear all GPRS to increase determinism
    + */
    + CLEAR_GPR(r2)
    + CLEAR_GPR(r3)
    + CLEAR_GPR(r4)
    + CLEAR_GPR(r5)
    + CLEAR_GPR(r6)
    + CLEAR_GPR(r7)
    + CLEAR_GPR(r8)
    + CLEAR_GPR(r9)
    + CLEAR_GPR(r11)
    + CLEAR_GPR(r12)
    + CLEAR_GPR(r13)
    + CLEAR_GPR(r14)
    + CLEAR_GPR(r15)
    + CLEAR_GPR(r16)
    + CLEAR_GPR(r17)
    + CLEAR_GPR(r18)
    + CLEAR_GPR(r19)
    + CLEAR_GPR(r20)
    + CLEAR_GPR(r21)
    + CLEAR_GPR(r22)
    + CLEAR_GPR(r23)
    + CLEAR_GPR(r24)
    + CLEAR_GPR(r25)
    + CLEAR_GPR(r26)
    + CLEAR_GPR(r27)
    + CLEAR_GPR(r28)
    + CLEAR_GPR(r29)
    + CLEAR_GPR(r30)
    + CLEAR_GPR(r31)
    +
    +jump_start_kernel:
    + /*
    + * jump to kernel entry (start_kernel)
    + */
    + LOAD_SYMBOL_2_GPR(r30, start_kernel)
    + l.jr r30
    + l.nop
    +
    +/* ========================================[ cache ]=== */
    +
    + /* aligment here so we don't change memory offsets with
    + * memory controler defined
    + */
    + .align 0x2000
    +
    +_ic_enable:
    + /* Check if IC present and skip enabling otherwise */
    + l.mfspr r24,r0,SPR_UPR
    + l.andi r26,r24,SPR_UPR_ICP
    + l.sfeq r26,r0
    + l.bf 9f
    + l.nop
    +
    + /* Disable IC */
    + l.mfspr r6,r0,SPR_SR
    + l.addi r5,r0,-1
    + l.xori r5,r5,SPR_SR_ICE
    + l.and r5,r6,r5
    + l.mtspr r0,r5,SPR_SR
    +
    + /* Establish cache block size
    + If BS=0, 16;
    + If BS=1, 32;
    + r14 contain block size
    + */
    + l.mfspr r24,r0,SPR_ICCFGR
    + l.andi r26,r24,SPR_ICCFGR_CBS
    + l.srli r28,r26,7
    + l.ori r30,r0,16
    + l.sll r14,r30,r28
    +
    + /* Establish number of cache sets
    + r16 contains number of cache sets
    + r28 contains log(# of cache sets)
    + */
    + l.andi r26,r24,SPR_ICCFGR_NCS
    + l.srli r28,r26,3
    + l.ori r30,r0,1
    + l.sll r16,r30,r28
    +
    + /* Invalidate IC */
    + l.addi r6,r0,0
    + l.sll r5,r14,r28
    +// l.mul r5,r14,r16
    +// l.trap 1
    +// l.addi r5,r0,IC_SIZE
    +1:
    + l.mtspr r0,r6,SPR_ICBIR
    + l.sfne r6,r5
    + l.bf 1b
    + l.add r6,r6,r14
    + // l.addi r6,r6,IC_LINE
    +
    + /* Enable IC */
    + l.mfspr r6,r0,SPR_SR
    + l.ori r6,r6,SPR_SR_ICE
    + l.mtspr r0,r6,SPR_SR
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    + l.nop
    +9:
    + l.jr r9
    + l.nop
    +
    +_dc_enable:
    + /* Check if DC present and skip enabling otherwise */
    + l.mfspr r24,r0,SPR_UPR
    + l.andi r26,r24,SPR_UPR_DCP
    + l.sfeq r26,r0
    + l.bf 9f
    + l.nop
    +
    + /* Disable DC */
    + l.mfspr r6,r0,SPR_SR
    + l.addi r5,r0,-1
    + l.xori r5,r5,SPR_SR_DCE
    + l.and r5,r6,r5
    + l.mtspr r0,r5,SPR_SR
    +
    + /* Establish cache block size
    + If BS=0, 16;
    + If BS=1, 32;
    + r14 contain block size
    + */
    + l.mfspr r24,r0,SPR_DCCFGR
    + l.andi r26,r24,SPR_DCCFGR_CBS
    + l.srli r28,r26,7
    + l.ori r30,r0,16
    + l.sll r14,r30,r28
    +
    + /* Establish number of cache sets
    + r16 contains number of cache sets
    + r28 contains log(# of cache sets)
    + */
    + l.andi r26,r24,SPR_DCCFGR_NCS
    + l.srli r28,r26,3
    + l.ori r30,r0,1
    + l.sll r16,r30,r28
    +
    + /* Invalidate DC */
    + l.addi r6,r0,0
    + l.sll r5,r14,r28
    +1:
    + l.mtspr r0,r6,SPR_DCBIR
    + l.sfne r6,r5
    + l.bf 1b
    + l.add r6,r6,r14
    +
    + /* Enable DC */
    + l.mfspr r6,r0,SPR_SR
    + l.ori r6,r6,SPR_SR_DCE
    + l.mtspr r0,r6,SPR_SR
    +9:
    + l.jr r9
    + l.nop
    +
    +/* ===============================================[ page table masks ]=== */
    +
    +/* bit 4 is used in hardware as write back cache bit. we never use this bit
    + * explicitly, so we can reuse it as _PAGE_FILE bit and mask it out when
    + * writing into hardware pte's
    + */
    +
    +#define DTLB_UP_CONVERT_MASK 0x3fa
    +#define ITLB_UP_CONVERT_MASK 0x3a
    +
    +/* for SMP we'd have (this is a bit subtle, CC must be always set
    + * for SMP, but since we have _PAGE_PRESENT bit always defined
    + * we can just modify the mask)
    + */
    +#define DTLB_SMP_CONVERT_MASK 0x3fb
    +#define ITLB_SMP_CONVERT_MASK 0x3b
    +
    +/* ---[ boot dtlb miss handler ]----------------------------------------- */
    +
    +boot_dtlb_miss_handler:
    +
    +/* mask for DTLB_MR register: - (0) sets V (valid) bit,
    + * - (31-12) sets bits belonging to VPN (31-12)
    + */
    +#define DTLB_MR_MASK 0xfffff001
    +
    +/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit,
    + * - (4) sets A (access) bit,
    + * - (5) sets D (dirty) bit,
    + * - (8) sets SRE (superuser read) bit
    + * - (9) sets SWE (superuser write) bit
    + * - (31-12) sets bits belonging to VPN (31-12)
    + */
    +#define DTLB_TR_MASK 0xfffff332
    +
    +/* These are for masking out the VPN/PPN value from the MR/TR registers...
    + * it's not the same as the PFN */
    +#define VPN_MASK 0xfffff000
    +#define PPN_MASK 0xfffff000
    +
    +
    + EXCEPTION_STORE_GPR6
    +
    +#if 0
    + l.mfspr r6,r0,SPR_ESR_BASE //
    + l.andi r6,r6,SPR_SR_SM // are we in kernel mode ?
    + l.sfeqi r6,0 // r6 == 0x1 --> SM
    + l.bf exit_with_no_dtranslation //
    + l.nop
    +#endif
    +
    + /* this could be optimized by moving storing of
    + * non r6 registers here, and jumping r6 restore
    + * if not in supervisor mode
    + */
    +
    + EXCEPTION_STORE_GPR2
    + EXCEPTION_STORE_GPR3
    + EXCEPTION_STORE_GPR4
    + EXCEPTION_STORE_GPR5
    +
    + l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA
    +
    +immediate_translation:
    + CLEAR_GPR(r6)
    +
    + l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb)
    +
    + l.mfspr r6, r0, SPR_DMMUCFGR
    + l.andi r6, r6, SPR_DMMUCFGR_NTS
    + l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF
    + l.ori r5, r0, 0x1
    + l.sll r5, r5, r6 // r5 = number DMMU sets
    + l.addi r6, r5, -1 // r6 = nsets mask
    + l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK
    +
    + l.or r6,r6,r4 // r6 <- r4
    + l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff
    + l.movhi r5,hi(DTLB_MR_MASK) // r5 <- ffff:0000.x000
    + l.ori r5,r5,lo(DTLB_MR_MASK) // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK
    + l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have DTLBMR entry
    + l.mtspr r2,r5,SPR_DTLBMR_BASE(0) // set DTLBMR
    +
    + /* set up DTLB with no translation for EA <= 0xbfffffff */
    + LOAD_SYMBOL_2_GPR(r6,0xbfffffff)
    + l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xbfffffff >= EA)
    + l.bf 1f // goto out
    + l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1)
    +
    + tophys(r3,r4) // r3 <- PA
    +1:
    + l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff
    + l.movhi r5,hi(DTLB_TR_MASK) // r5 <- ffff:0000.x000
    + l.ori r5,r5,lo(DTLB_TR_MASK) // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK
    + l.and r5,r5,r3 // r5 <- PPN :PPN .x330 - we have DTLBTR entry
    + l.mtspr r2,r5,SPR_DTLBTR_BASE(0) // set DTLBTR
    +
    + EXCEPTION_LOAD_GPR6
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR2
    +
    + l.rfe // SR <- ESR, PC <- EPC
    +
    +exit_with_no_dtranslation:
    + /* EA out of memory or not in supervisor mode */
    + EXCEPTION_LOAD_GPR6
    + EXCEPTION_LOAD_GPR4
    + l.j _dispatch_bus_fault
    +
    +/* ---[ boot itlb miss handler ]----------------------------------------- */
    +
    +boot_itlb_miss_handler:
    +
    +/* mask for ITLB_MR register: - sets V (valid) bit,
    + * - sets bits belonging to VPN (15-12)
    + */
    +#define ITLB_MR_MASK 0xfffff001
    +
    +/* mask for ITLB_TR register: - sets A (access) bit,
    + * - sets SXE (superuser execute) bit
    + * - sets bits belonging to VPN (15-12)
    + */
    +#define ITLB_TR_MASK 0xfffff050
    +
    +/*
    +#define VPN_MASK 0xffffe000
    +#define PPN_MASK 0xffffe000
    +*/
    +
    +
    +
    + EXCEPTION_STORE_GPR2
    + EXCEPTION_STORE_GPR3
    + EXCEPTION_STORE_GPR4
    + EXCEPTION_STORE_GPR5
    + EXCEPTION_STORE_GPR6
    +
    +#if 0
    + l.mfspr r6,r0,SPR_ESR_BASE //
    + l.andi r6,r6,SPR_SR_SM // are we in kernel mode ?
    + l.sfeqi r6,0 // r6 == 0x1 --> SM
    + l.bf exit_with_no_itranslation
    + l.nop
    +#endif
    +
    +
    + l.mfspr r4,r0,SPR_EEAR_BASE // get the offending EA
    +
    +earlyearly:
    + CLEAR_GPR(r6)
    +
    + l.srli r3,r4,0xd // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb)
    +
    + l.mfspr r6, r0, SPR_IMMUCFGR
    + l.andi r6, r6, SPR_IMMUCFGR_NTS
    + l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF
    + l.ori r5, r0, 0x1
    + l.sll r5, r5, r6 // r5 = number IMMU sets from IMMUCFGR
    + l.addi r6, r5, -1 // r6 = nsets mask
    + l.and r2, r3, r6 // r2 <- r3 % NSETS_MASK
    +
    + l.or r6,r6,r4 // r6 <- r4
    + l.ori r6,r6,~(VPN_MASK) // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff
    + l.movhi r5,hi(ITLB_MR_MASK) // r5 <- ffff:0000.x000
    + l.ori r5,r5,lo(ITLB_MR_MASK) // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK
    + l.and r5,r5,r6 // r5 <- VPN :VPN .x001 - we have ITLBMR entry
    + l.mtspr r2,r5,SPR_ITLBMR_BASE(0) // set ITLBMR
    +
    + /*
    + * set up ITLB with no translation for EA <= 0x0fffffff
    + *
    + * we need this for head.S mapping (EA = PA). if we move all functions
    + * which run with mmu enabled into entry.S, we might be able to eliminate this.
    + *
    + */
    + LOAD_SYMBOL_2_GPR(r6,0x0fffffff)
    + l.sfgeu r6,r4 // flag if r6 >= r4 (if 0xb0ffffff >= EA)
    + l.bf 1f // goto out
    + l.and r3,r4,r4 // delay slot :: 24 <- r4 (if flag==1)
    +
    + tophys(r3,r4) // r3 <- PA
    +1:
    + l.ori r3,r3,~(PPN_MASK) // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff
    + l.movhi r5,hi(ITLB_TR_MASK) // r5 <- ffff:0000.x000
    + l.ori r5,r5,lo(ITLB_TR_MASK) // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK
    + l.and r5,r5,r3 // r5 <- PPN :PPN .x050 - we have ITLBTR entry
    + l.mtspr r2,r5,SPR_ITLBTR_BASE(0) // set ITLBTR
    +
    + EXCEPTION_LOAD_GPR6
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR2
    +
    + l.rfe // SR <- ESR, PC <- EPC
    +
    +exit_with_no_itranslation:
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR6
    + l.j _dispatch_bus_fault
    + l.nop
    +
    +/* ====================================================================== */
    +/*
    + * Stuff below here shouldn't go into .head section... maybe this stuff
    + * can be moved to entry.S ???
    + */
    +
    +/* ==============================================[ DTLB miss handler ]=== */
    +
    +/*
    + * Comments:
    + * Exception handlers are entered with MMU off so the following handler
    + * needs to use physical addressing
    + *
    + */
    +
    + .text
    +ENTRY(dtlb_miss_handler)
    + EXCEPTION_STORE_GPR2
    + EXCEPTION_STORE_GPR3
    + EXCEPTION_STORE_GPR4
    + EXCEPTION_STORE_GPR5
    + EXCEPTION_STORE_GPR6
    + /*
    + * get EA of the miss
    + */
    + l.mfspr r2,r0,SPR_EEAR_BASE
    + /*
    + * pmd = (pmd_t *)(current_pgd + pgd_index(daddr));
    + */
    + GET_CURRENT_PGD(r3,r5) // r3 is current_pgd, r5 is temp
    + l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2)
    + l.slli r4,r4,0x2 // to get address << 2
    + l.add r5,r4,r3 // r4 is pgd_index(daddr)
    + /*
    + * if (pmd_none(*pmd))
    + * goto pmd_none:
    + */
    + tophys (r4,r5)
    + l.lwz r3,0x0(r4) // get *pmd value
    + l.sfne r3,r0
    + l.bnf d_pmd_none
    + l.andi r3,r3,~PAGE_MASK //0x1fff // ~PAGE_MASK
    + /*
    + * if (pmd_bad(*pmd))
    + * pmd_clear(pmd)
    + * goto pmd_bad:
    + */
    +// l.sfeq r3,r0 // check *pmd value
    +// l.bf d_pmd_good
    + l.addi r3,r0,0xffffe000 // PAGE_MASK
    +// l.j d_pmd_bad
    +// l.sw 0x0(r4),r0 // clear pmd
    +d_pmd_good:
    + /*
    + * pte = *pte_offset(pmd, daddr);
    + */
    + l.lwz r4,0x0(r4) // get **pmd value
    + l.and r4,r4,r3 // & PAGE_MASK
    + l.srli r5,r2,0xd // >> PAGE_SHIFT, r2 == EEAR
    + l.andi r3,r5,0x7ff // (1UL << PAGE_SHIFT - 2) - 1
    + l.slli r3,r3,0x2 // to get address << 2
    + l.add r3,r3,r4
    + l.lwz r2,0x0(r3) // this is pte at last
    + /*
    + * if (!pte_present(pte))
    + */
    + l.andi r4,r2,0x1
    + l.sfne r4,r0 // is pte present
    + l.bnf d_pte_not_present
    + l.addi r3,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK
    + /*
    + * fill DTLB TR register
    + */
    + l.and r4,r2,r3 // apply the mask
    + // Determine number of DMMU sets
    + l.mfspr r6, r0, SPR_DMMUCFGR
    + l.andi r6, r6, SPR_DMMUCFGR_NTS
    + l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF
    + l.ori r3, r0, 0x1
    + l.sll r3, r3, r6 // r3 = number DMMU sets DMMUCFGR
    + l.addi r6, r3, -1 // r6 = nsets mask
    + l.and r5, r5, r6 // calc offset: & (NUM_TLB_ENTRIES-1)
    + //NUM_TLB_ENTRIES
    + l.mtspr r5,r4,SPR_DTLBTR_BASE(0)
    + /*
    + * fill DTLB MR register
    + */
    + l.mfspr r2,r0,SPR_EEAR_BASE
    + l.addi r3,r0,0xffffe000 // PAGE_MASK
    + l.and r4,r2,r3 // apply PAGE_MASK to EA (__PHX__ do we really need this?)
    + l.ori r4,r4,0x1 // set hardware valid bit: DTBL_MR entry
    + l.mtspr r5,r4,SPR_DTLBMR_BASE(0)
    +
    + EXCEPTION_LOAD_GPR2
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR6
    + l.rfe
    +d_pmd_bad:
    + l.nop 1
    + EXCEPTION_LOAD_GPR2
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR6
    + l.rfe
    +d_pmd_none:
    +d_pte_not_present:
    + EXCEPTION_LOAD_GPR2
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR6
    + l.j _dispatch_do_dpage_fault
    + l.nop
    +
    +/* ==============================================[ ITLB miss handler ]=== */
    +ENTRY(itlb_miss_handler)
    + EXCEPTION_STORE_GPR2
    + EXCEPTION_STORE_GPR3
    + EXCEPTION_STORE_GPR4
    + EXCEPTION_STORE_GPR5
    + EXCEPTION_STORE_GPR6
    + /*
    + * get EA of the miss
    + */
    + l.mfspr r2,r0,SPR_EEAR_BASE
    +
    + /*
    + * pmd = (pmd_t *)(current_pgd + pgd_index(daddr));
    + *
    + */
    + GET_CURRENT_PGD(r3,r5) // r3 is current_pgd, r5 is temp
    + l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2)
    + l.slli r4,r4,0x2 // to get address << 2
    + l.add r5,r4,r3 // r4 is pgd_index(daddr)
    + /*
    + * if (pmd_none(*pmd))
    + * goto pmd_none:
    + */
    + tophys (r4,r5)
    + l.lwz r3,0x0(r4) // get *pmd value
    + l.sfne r3,r0
    + l.bnf i_pmd_none
    + l.andi r3,r3,0x1fff // ~PAGE_MASK
    + /*
    + * if (pmd_bad(*pmd))
    + * pmd_clear(pmd)
    + * goto pmd_bad:
    + */
    +
    +// l.sfeq r3,r0 // check *pmd value
    +// l.bf i_pmd_good
    + l.addi r3,r0,0xffffe000 // PAGE_MASK
    +// l.j i_pmd_bad
    +// l.sw 0x0(r4),r0 // clear pmd
    +
    +i_pmd_good:
    + /*
    + * pte = *pte_offset(pmd, iaddr);
    + *
    + */
    + l.lwz r4,0x0(r4) // get **pmd value
    + l.and r4,r4,r3 // & PAGE_MASK
    + l.srli r5,r2,0xd // >> PAGE_SHIFT, r2 == EEAR
    + l.andi r3,r5,0x7ff // (1UL << PAGE_SHIFT - 2) - 1
    + l.slli r3,r3,0x2 // to get address << 2
    + l.add r3,r3,r4
    + l.lwz r2,0x0(r3) // this is pte at last
    + /*
    + * if (!pte_present(pte))
    + *
    + */
    + l.andi r4,r2,0x1
    + l.sfne r4,r0 // is pte present
    + l.bnf i_pte_not_present
    + l.addi r3,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK
    + /*
    + * fill ITLB TR register
    + */
    + l.and r4,r2,r3 // apply the mask
    + l.andi r3,r2,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE
    +// l.andi r3,r2,0x400 // _PAGE_EXEC
    + l.sfeq r3,r0
    + l.bf itlb_tr_fill //_workaround
    + // Determine number of IMMU sets
    + l.mfspr r6, r0, SPR_IMMUCFGR
    + l.andi r6, r6, SPR_IMMUCFGR_NTS
    + l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF
    + l.ori r3, r0, 0x1
    + l.sll r3, r3, r6 // r3 = number IMMU sets IMMUCFGR
    + l.addi r6, r3, -1 // r6 = nsets mask
    + l.and r5, r5, r6 // calc offset: & (NUM_TLB_ENTRIES-1)
    +
    +/*
    + * __PHX__ :: fixme
    + * we should not just blindly set executable flags,
    + * but it does help with ping. the clean way would be to find out
    + * (and fix it) why stack doesn't have execution permissions
    + */
    +
    +itlb_tr_fill_workaround:
    + l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE)
    +itlb_tr_fill:
    + l.mtspr r5,r4,SPR_ITLBTR_BASE(0)
    + /*
    + * fill DTLB MR register
    + */
    + l.mfspr r2,r0,SPR_EEAR_BASE
    + l.addi r3,r0,0xffffe000 // PAGE_MASK
    + l.and r4,r2,r3 // apply PAGE_MASK to EA (__PHX__ do we really need this?)
    + l.ori r4,r4,0x1 // set hardware valid bit: DTBL_MR entry
    + l.mtspr r5,r4,SPR_ITLBMR_BASE(0)
    +
    + EXCEPTION_LOAD_GPR2
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR6
    + l.rfe
    +
    +i_pmd_bad:
    + l.nop 1
    + EXCEPTION_LOAD_GPR2
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR6
    + l.rfe
    +i_pmd_none:
    +i_pte_not_present:
    + EXCEPTION_LOAD_GPR2
    + EXCEPTION_LOAD_GPR3
    + EXCEPTION_LOAD_GPR4
    + EXCEPTION_LOAD_GPR5
    + EXCEPTION_LOAD_GPR6
    + l.j _dispatch_do_ipage_fault
    + l.nop
    +
    +/* ==============================================[ boot tlb handlers ]=== */
    +
    +
    +/* =================================================[ debugging aids ]=== */
    +
    + .align 64
    +_immu_trampoline:
    + .space 64
    +_immu_trampoline_top:
    +
    +#define TRAMP_SLOT_0 (0x0)
    +#define TRAMP_SLOT_1 (0x4)
    +#define TRAMP_SLOT_2 (0x8)
    +#define TRAMP_SLOT_3 (0xc)
    +#define TRAMP_SLOT_4 (0x10)
    +#define TRAMP_SLOT_5 (0x14)
    +#define TRAMP_FRAME_SIZE (0x18)
    +
    +ENTRY(_immu_trampoline_workaround)
    + // r2 EEA
    + // r6 is physical EEA
    + tophys(r6,r2)
    +
    + LOAD_SYMBOL_2_GPR(r5,_immu_trampoline)
    + tophys (r3,r5) // r3 is trampoline (physical)
    +
    + LOAD_SYMBOL_2_GPR(r4,0x15000000)
    + l.sw TRAMP_SLOT_0(r3),r4
    + l.sw TRAMP_SLOT_1(r3),r4
    + l.sw TRAMP_SLOT_4(r3),r4
    + l.sw TRAMP_SLOT_5(r3),r4
    +
    + // EPC = EEA - 0x4
    + l.lwz r4,0x0(r6) // load op @ EEA + 0x0 (fc address)
    + l.sw TRAMP_SLOT_3(r3),r4 // store it to _immu_trampoline_data
    + l.lwz r4,-0x4(r6) // load op @ EEA - 0x4 (f8 address)
    + l.sw TRAMP_SLOT_2(r3),r4 // store it to _immu_trampoline_data
    +
    + l.srli r5,r4,26 // check opcode for write access
    + l.sfeqi r5,0 // l.j
    + l.bf 0f
    + l.sfeqi r5,0x11 // l.jr
    + l.bf 1f
    + l.sfeqi r5,1 // l.jal
    + l.bf 2f
    + l.sfeqi r5,0x12 // l.jalr
    + l.bf 3f
    + l.sfeqi r5,3 // l.bnf
    + l.bf 4f
    + l.sfeqi r5,4 // l.bf
    + l.bf 5f
    +99:
    + l.nop
    + l.j 99b // should never happen
    + l.nop 1
    +
    + // r2 is EEA
    + // r3 is trampoline address (physical)
    + // r4 is instruction
    + // r6 is physical(EEA)
    + //
    + // r5
    +
    +2: // l.jal
    +
    + /* 19 20 aa aa l.movhi r9,0xaaaa
    + * a9 29 bb bb l.ori r9,0xbbbb
    + *
    + * where 0xaaaabbbb is EEA + 0x4 shifted right 2
    + */
    +
    + l.addi r6,r2,0x4 // this is 0xaaaabbbb
    +
    + // l.movhi r9,0xaaaa
    + l.ori r5,r0,0x1920 // 0x1920 == l.movhi r9
    + l.sh (TRAMP_SLOT_0+0x0)(r3),r5
    + l.srli r5,r6,16
    + l.sh (TRAMP_SLOT_0+0x2)(r3),r5
    +
    + // l.ori r9,0xbbbb
    + l.ori r5,r0,0xa929 // 0xa929 == l.ori r9
    + l.sh (TRAMP_SLOT_1+0x0)(r3),r5
    + l.andi r5,r6,0xffff
    + l.sh (TRAMP_SLOT_1+0x2)(r3),r5
    +
    + /* falthrough, need to set up new jump offset */
    +
    +
    +0: // l.j
    + l.slli r6,r4,6 // original offset shifted left 6 - 2
    +// l.srli r6,r6,6 // original offset shifted right 2
    +
    + l.slli r4,r2,4 // old jump position: EEA shifted left 4
    +// l.srli r4,r4,6 // old jump position: shifted right 2
    +
    + l.addi r5,r3,0xc // new jump position (physical)
    + l.slli r5,r5,4 // new jump position: shifted left 4
    +
    + // calculate new jump offset
    + // new_off = old_off + (old_jump - new_jump)
    +
    + l.sub r5,r4,r5 // old_jump - new_jump
    + l.add r5,r6,r5 // orig_off + (old_jump - new_jump)
    + l.srli r5,r5,6 // new offset shifted right 2
    +
    + // r5 is new jump offset
    + // l.j has opcode 0x0...
    + l.sw TRAMP_SLOT_2(r3),r5 // write it back
    +
    + l.j trampoline_out
    + l.nop
    +
    +/* ----------------------------- */
    +
    +3: // l.jalr
    +
    + /* 19 20 aa aa l.movhi r9,0xaaaa
    + * a9 29 bb bb l.ori r9,0xbbbb
    + *
    + * where 0xaaaabbbb is EEA + 0x4 shifted right 2
    + */
    +
    + l.addi r6,r2,0x4 // this is 0xaaaabbbb
    +
    + // l.movhi r9,0xaaaa
    + l.ori r5,r0,0x1920 // 0x1920 == l.movhi r9
    + l.sh (TRAMP_SLOT_0+0x0)(r3),r5
    + l.srli r5,r6,16
    + l.sh (TRAMP_SLOT_0+0x2)(r3),r5
    +
    + // l.ori r9,0xbbbb
    + l.ori r5,r0,0xa929 // 0xa929 == l.ori r9
    + l.sh (TRAMP_SLOT_1+0x0)(r3),r5
    + l.andi r5,r6,0xffff
    + l.sh (TRAMP_SLOT_1+0x2)(r3),r5
    +
    + l.lhz r5,(TRAMP_SLOT_2+0x0)(r3) // load hi part of jump instruction
    + l.andi r5,r5,0x3ff // clear out opcode part
    + l.ori r5,r5,0x4400 // opcode changed from l.jalr -> l.jr
    + l.sh (TRAMP_SLOT_2+0x0)(r3),r5 // write it back
    +
    + /* falthrough */
    +
    +1: // l.jr
    + l.j trampoline_out
    + l.nop
    +
    +/* ----------------------------- */
    +
    +4: // l.bnf
    +5: // l.bf
    + l.slli r6,r4,6 // original offset shifted left 6 - 2
    +// l.srli r6,r6,6 // original offset shifted right 2
    +
    + l.slli r4,r2,4 // old jump position: EEA shifted left 4
    +// l.srli r4,r4,6 // old jump position: shifted right 2
    +
    + l.addi r5,r3,0xc // new jump position (physical)
    + l.slli r5,r5,4 // new jump position: shifted left 4
    +
    + // calculate new jump offset
    + // new_off = old_off + (old_jump - new_jump)
    +
    + l.add r6,r6,r4 // (orig_off + old_jump)
    + l.sub r6,r6,r5 // (orig_off + old_jump) - new_jump
    + l.srli r6,r6,6 // new offset shifted right 2
    +
    + // r6 is new jump offset
    + l.lwz r4,(TRAMP_SLOT_2+0x0)(r3) // load jump instruction
    + l.srli r4,r4,16
    + l.andi r4,r4,0xfc00 // get opcode part
    + l.slli r4,r4,16
    + l.or r6,r4,r6 // l.b(n)f new offset
    + l.sw TRAMP_SLOT_2(r3),r6 // write it back
    +
    + /* we need to add l.j to EEA + 0x8 */
    + tophys (r4,r2) // may not be needed (due to shifts down_
    + l.addi r4,r4,(0x8 - 0x8) // jump target = r2 + 0x8 (compensate for 0x8)
    + // jump position = r5 + 0x8 (0x8 compensated)
    + l.sub r4,r4,r5 // jump offset = target - new_position + 0x8
    +
    + l.slli r4,r4,4 // the amount of info in imediate of jump
    + l.srli r4,r4,6 // jump instruction with offset
    + l.sw TRAMP_SLOT_4(r3),r4 // write it to 4th slot
    +
    + /* fallthrough */
    +
    +trampoline_out:
    + // set up new EPC to point to our trampoline code
    + LOAD_SYMBOL_2_GPR(r5,_immu_trampoline)
    + l.mtspr r0,r5,SPR_EPCR_BASE
    +
    + // immu_trampoline is (4x) CACHE_LINE aligned
    + // and only 6 instructions long,
    + // so we need to invalidate only 2 lines
    +
    + /* Establish cache block size
    + If BS=0, 16;
    + If BS=1, 32;
    + r14 contain block size
    + */
    + l.mfspr r21,r0,SPR_ICCFGR
    + l.andi r21,r21,SPR_ICCFGR_CBS
    + l.srli r21,r21,7
    + l.ori r23,r0,16
    + l.sll r14,r23,r21
    +
    + l.mtspr r0,r5,SPR_ICBIR
    + l.add r5,r5,r14
    + l.mtspr r0,r5,SPR_ICBIR
    +
    + l.jr r9
    + l.nop
    +
    +
    +/*
    + * DSCR: prints a string referenced by r3.
    + *
    + * PRMS: r3 - address of the first character of null
    + * terminated string to be printed
    + *
    + * PREQ: UART at UART_BASE_ADD has to be initialized
    + *
    + * POST: caller should be aware that r3, r9 are changed
    + */
    +ENTRY(_emergency_print)
    + EMERGENCY_PRINT_STORE_GPR4
    + EMERGENCY_PRINT_STORE_GPR5
    + EMERGENCY_PRINT_STORE_GPR6
    + EMERGENCY_PRINT_STORE_GPR7
    +2:
    + l.lbz r7,0(r3)
    + l.sfeq r7,r0
    + l.bf 9f
    + l.nop
    +
    +// putc:
    + l.movhi r4,hi(UART_BASE_ADD)
    +
    + l.addi r6,r0,0x20
    +1: l.lbz r5,5(r4)
    + l.andi r5,r5,0x20
    + l.sfeq r5,r6
    + l.bnf 1b
    + l.nop
    +
    + l.sb 0(r4),r7
    +
    + l.addi r6,r0,0x60
    +1: l.lbz r5,5(r4)
    + l.andi r5,r5,0x60
    + l.sfeq r5,r6
    + l.bnf 1b
    + l.nop
    +
    + /* next character */
    + l.j 2b
    + l.addi r3,r3,0x1
    +
    +9:
    + EMERGENCY_PRINT_LOAD_GPR7
    + EMERGENCY_PRINT_LOAD_GPR6
    + EMERGENCY_PRINT_LOAD_GPR5
    + EMERGENCY_PRINT_LOAD_GPR4
    + l.jr r9
    + l.nop
    +
    +ENTRY(_emergency_print_nr)
    + EMERGENCY_PRINT_STORE_GPR4
    + EMERGENCY_PRINT_STORE_GPR5
    + EMERGENCY_PRINT_STORE_GPR6
    + EMERGENCY_PRINT_STORE_GPR7
    + EMERGENCY_PRINT_STORE_GPR8
    +
    + l.addi r8,r0,32 // shift register
    +
    +1: /* remove leading zeros */
    + l.addi r8,r8,-0x4
    + l.srl r7,r3,r8
    + l.andi r7,r7,0xf
    +
    + /* don't skip the last zero if number == 0x0 */
    + l.sfeqi r8,0x4
    + l.bf 2f
    + l.nop
    +
    + l.sfeq r7,r0
    + l.bf 1b
    + l.nop
    +
    +2:
    + l.srl r7,r3,r8
    +
    + l.andi r7,r7,0xf
    + l.sflts r8,r0
    + l.bf 9f
    +
    + l.sfgtui r7,0x9
    + l.bnf 8f
    + l.nop
    + l.addi r7,r7,0x27
    +
    +8:
    + l.addi r7,r7,0x30
    +// putc:
    + l.movhi r4,hi(UART_BASE_ADD)
    +
    + l.addi r6,r0,0x20
    +1: l.lbz r5,5(r4)
    + l.andi r5,r5,0x20
    + l.sfeq r5,r6
    + l.bnf 1b
    + l.nop
    +
    + l.sb 0(r4),r7
    +
    + l.addi r6,r0,0x60
    +1: l.lbz r5,5(r4)
    + l.andi r5,r5,0x60
    + l.sfeq r5,r6
    + l.bnf 1b
    + l.nop
    +
    + /* next character */
    + l.j 2b
    + l.addi r8,r8,-0x4
    +
    +9:
    + EMERGENCY_PRINT_LOAD_GPR8
    + EMERGENCY_PRINT_LOAD_GPR7
    + EMERGENCY_PRINT_LOAD_GPR6
    + EMERGENCY_PRINT_LOAD_GPR5
    + EMERGENCY_PRINT_LOAD_GPR4
    + l.jr r9
    + l.nop
    +
    +
    +/*
    + * This should be used for debugging only.
    + * It messes up the Linux early serial output
    + * somehow, so use it sparingly and essentially
    + * only if you need to debug something that goes wrong
    + * before Linux gets the early serial going.
    + *
    + * Furthermore, you'll have to make sure you set the
    + * UART_DEVISOR correctly according to the system
    + * clock rate.
    + *
    + *
    + */
    +
    +
    +
    +#define SYS_CLK 20000000
    +//#define SYS_CLK 1843200
    +#define OR32_CONSOLE_BAUD 115200
    +#define UART_DIVISOR SYS_CLK/(16*OR32_CONSOLE_BAUD)
    +
    +ENTRY(_early_uart_init)
    + l.movhi r3,hi(UART_BASE_ADD)
    +
    + l.addi r4,r0,0x7
    + l.sb 0x2(r3),r4
    +
    + l.addi r4,r0,0x0
    + l.sb 0x1(r3),r4
    +
    + l.addi r4,r0,0x3
    + l.sb 0x3(r3),r4
    +
    + l.lbz r5,3(r3)
    + l.ori r4,r5,0x80
    + l.sb 0x3(r3),r4
    + l.addi r4,r0,((UART_DIVISOR>>8) & 0x000000ff)
    + l.sb UART_DLM(r3),r4
    + l.addi r4,r0,((UART_DIVISOR) & 0x000000ff)
    + l.sb UART_DLL(r3),r4
    + l.sb 0x3(r3),r5
    +
    + l.jr r9
    + l.nop
    +
    +_string_copying_linux:
    + .string "\n\n\n\n\n\rCopying Linux... \0"
    +
    +_string_ok_booting:
    + .string "Ok, booting the kernel.\n\r\0"
    +
    +_string_unhandled_exception:
    + .string "\n\rRunarunaround: Unhandled exception 0x\0"
    +
    +_string_epc_prefix:
    + .string ": EPC=0x\0"
    +
    +_string_nl:
    + .string "\n\r\0"
    +
    + .global _string_esr_irq_bug
    +_string_esr_irq_bug:
    + .string "\n\rESR external interrupt bug, for details look into entry.S\n\r\0"
    +
    +
    +
    +/* ========================================[ page aligned structures ]=== */
    +
    +/*
    + * .data section should be page aligned
    + * (look into arch/or32/kernel/vmlinux.lds)
    + */
    + .section .data,"aw"
    + .align 8192
    + .global empty_zero_page
    +empty_zero_page:
    + .space 8192
    +
    + .global swapper_pg_dir
    +swapper_pg_dir:
    + .space 8192
    +
    + .global _unhandled_stack
    +_unhandled_stack:
    + .space 8192
    +_unhandled_stack_top:
    +
    +/* ============================================================[ EOF ]=== */
    diff --git a/arch/openrisc/kernel/init_task.c b/arch/openrisc/kernel/init_task.c
    new file mode 100644
    index 0000000..45744a38
    --- /dev/null
    +++ b/arch/openrisc/kernel/init_task.c
    @@ -0,0 +1,41 @@
    +/*
    + * OpenRISC init_task.c
    + *
    + * Linux architectural port borrowing liberally from similar works of
    + * others. All original copyrights apply as per the original source
    + * declaration.
    + *
    + * Modifications for the OpenRISC architecture:
    + * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
    + * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
    + *
    + * 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
    + * 2 of the License, or (at your option) any later version.
    + */
    +
    +#include <linux/init_task.h>
    +#include <linux/mqueue.h>
    +
    +static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
    +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
    +
    +/*
    + * Initial thread structure.
    + *
    + * We need to make sure that this is THREAD_SIZE aligned due to the
    + * way process stacks are handled. This is done by having a special
    + * "init_task" linker map entry..
    + */
    +union thread_union init_thread_union __init_task_data = {
    + INIT_THREAD_INFO(init_task)
    +};
    +
    +/*
    + * Initial task structure.
    + *
    + * All other task structs will be allocated on slabs in fork.c
    + */
    +struct task_struct init_task = INIT_TASK(init_task);
    +EXPORT_SYMBOL(init_task);
    diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c
    new file mode 100644
    index 0000000..1422f74
    --- /dev/null
    +++ b/arch/openrisc/kernel/setup.c
    @@ -0,0 +1,381 @@
    +/*
    + * OpenRISC setup.c
    + *
    + * Linux architectural port borrowing liberally from similar works of
    + * others. All original copyrights apply as per the original source
    + * declaration.
    + *
    + * Modifications for the OpenRISC architecture:
    + * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
    + * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
    + *
    + * 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
    + * 2 of the License, or (at your option) any later version.
    + *
    + * This file handles the architecture-dependent parts of initialization
    + */
    +
    +#include <linux/errno.h>
    +#include <linux/sched.h>
    +#include <linux/kernel.h>
    +#include <linux/mm.h>
    +#include <linux/stddef.h>
    +#include <linux/unistd.h>
    +#include <linux/ptrace.h>
    +#include <linux/slab.h>
    +#include <linux/tty.h>
    +#include <linux/ioport.h>
    +#include <linux/delay.h>
    +#include <linux/console.h>
    +#include <linux/init.h>
    +#include <linux/bootmem.h>
    +#include <linux/seq_file.h>
    +#include <linux/serial.h>
    +#include <linux/initrd.h>
    +#include <linux/of_fdt.h>
    +#include <linux/of.h>
    +#include <linux/memblock.h>
    +#include <linux/device.h>
    +#include <linux/of_platform.h>
    +
    +#include <asm/segment.h>
    +#include <asm/system.h>
    +#include <asm/pgtable.h>
    +#include <asm/types.h>
    +#include <asm/setup.h>
    +#include <asm/io.h>
    +#include <asm/cpuinfo.h>
    +#include <asm/delay.h>
    +
    +#include "vmlinux.h"
    +
    +char __initdata cmd_line[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
    +
    +static unsigned long __init setup_memory(void)
    +{
    + unsigned long bootmap_size;
    + unsigned long ram_start_pfn;
    + unsigned long free_ram_start_pfn;
    + unsigned long ram_end_pfn;
    + phys_addr_t memory_start, memory_end;
    + struct memblock_region *region;
    +
    + memory_end = memory_start = 0;
    +
    + /* Find main memory where is the kernel */
    + for_each_memblock(memory, region) {
    + memory_start = region->base;
    + memory_end = region->base + region->size;
    + printk(KERN_INFO "%s: Memory: 0x%x-0x%x\n", __func__,
    + memory_start, memory_end);
    + }
    +
    + if (!memory_end) {
    + panic("No memory!");
    + }
    +
    + ram_start_pfn = PFN_UP(memory_start);
    + /* free_ram_start_pfn is first page after kernel */
    + free_ram_start_pfn = PFN_UP(__pa(&_end));
    + ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM());
    +
    + max_pfn = ram_end_pfn;
    +
    + /*
    + * initialize the boot-time allocator (with low memory only).
    + *
    + * This makes the memory from the end of the kernel to the end of
    + * RAM usable.
    + * init_bootmem sets the global values min_low_pfn, max_low_pfn.
    + */
    + bootmap_size = init_bootmem(free_ram_start_pfn,
    + ram_end_pfn - ram_start_pfn);
    + free_bootmem(PFN_PHYS(free_ram_start_pfn),
    + (ram_end_pfn - free_ram_start_pfn) << PAGE_SHIFT);
    + reserve_bootmem(PFN_PHYS(free_ram_start_pfn), bootmap_size,
    + BOOTMEM_DEFAULT);
    +
    + for_each_memblock(reserved, region) {
    + printk(KERN_INFO "Reserved - 0x%08x-0x%08x\n",
    + (u32) region->base, (u32) region->size);
    + reserve_bootmem(region->base, region->size, BOOTMEM_DEFAULT);
    + }
    +
    + return ram_end_pfn;
    +}
    +
    +struct cpuinfo cpuinfo;
    +
    +static void print_cpuinfo(void)
    +{
    + unsigned long upr = mfspr(SPR_UPR);
    + unsigned long vr = mfspr(SPR_VR);
    + unsigned int version;
    + unsigned int revision;
    +
    + version = (vr & SPR_VR_VER) >> 24;
    + revision = (vr & SPR_VR_REV);
    +
    + printk(KERN_INFO "CPU: OpenRISC-%x (revision %d) @%d MHz\n",
    + version, revision, cpuinfo.clock_frequency / 1000000);
    +
    + if (!(upr & SPR_UPR_UP)) {
    + printk(KERN_INFO
    + "-- no UPR register... unable to detect configuration\n");
    + return;
    + }
    +
    + if (upr & SPR_UPR_DCP)
    + printk(KERN_INFO
    + "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n",
    + cpuinfo.dcache_size, cpuinfo.dcache_block_size, 1);
    + else
    + printk(KERN_INFO "-- dcache disabled\n");
    + if (upr & SPR_UPR_ICP)
    + printk(KERN_INFO
    + "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n",
    + cpuinfo.icache_size, cpuinfo.icache_block_size, 1);
    + else
    + printk(KERN_INFO "-- icache disabled\n");
    +
    + if (upr & SPR_UPR_DMP)
    + printk(KERN_INFO "-- dmmu: %4d entries, %lu way(s)\n",
    + 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
    + 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW));
    + if (upr & SPR_UPR_IMP)
    + printk(KERN_INFO "-- immu: %4d entries, %lu way(s)\n",
    + 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
    + 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW));
    +
    + printk(KERN_INFO "-- additional features:\n");
    + if (upr & SPR_UPR_DUP)
    + printk(KERN_INFO "-- debug unit\n");
    + if (upr & SPR_UPR_PCUP)
    + printk(KERN_INFO "-- performance counters\n");
    + if (upr & SPR_UPR_PMP)
    + printk(KERN_INFO "-- power management\n");
    + if (upr & SPR_UPR_PICP)
    + printk(KERN_INFO "-- PIC\n");
    + if (upr & SPR_UPR_TTP)
    + printk(KERN_INFO "-- timer\n");
    + if (upr & SPR_UPR_CUP)
    + printk(KERN_INFO "-- custom unit(s)\n");
    +}
    +
    +void __init setup_cpuinfo(void)
    +{
    + struct device_node *cpu;
    + unsigned long iccfgr, dccfgr;
    + unsigned long cache_set_size, cache_ways;
    +
    + cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481");
    + if (!cpu)
    + panic("No compatible CPU found in device tree...\n");
    +
    + iccfgr = mfspr(SPR_ICCFGR);
    + cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
    + cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
    + cpuinfo.icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7);
    + cpuinfo.icache_size =
    + cache_set_size * cache_ways * cpuinfo.icache_block_size;
    +
    + dccfgr = mfspr(SPR_DCCFGR);
    + cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
    + cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
    + cpuinfo.dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7);
    + cpuinfo.dcache_size =
    + cache_set_size * cache_ways * cpuinfo.dcache_block_size;
    +
    + if (of_property_read_u32(cpu, "clock-frequency",
    + &cpuinfo.clock_frequency)) {
    + printk(KERN_WARNING
    + "Device tree missing CPU 'clock-frequency' parameter."
    + "Assuming frequency 25MHZ"
    + "This is probably not what you want.");
    + }
    +
    + of_node_put(cpu);
    +
    + print_cpuinfo();
    +}
    +
    +/**
    + * or32_early_setup
    + *
    + * Handles the pointer to the device tree that this kernel is to use
    + * for establishing the available platform devices.
    + *
    + * For now, this is limited to using the built-in device tree. In the future,
    + * it is intended that this function will take a pointer to the device tree
    + * that is potentially built-in, but potentially also passed in by the
    + * bootloader, or discovered by some equally clever means...
    + */
    +
    +void __init or32_early_setup(void)
    +{
    +
    + early_init_devtree(__dtb_start);
    +
    + printk(KERN_INFO "Compiled-in FDT at 0x%p\n", __dtb_start);
    +}
    +
    +static int __init openrisc_device_probe(void)
    +{
    + of_platform_populate(NULL, NULL, NULL, NULL);
    +
    + return 0;
    +}
    +
    +device_initcall(openrisc_device_probe);
    +
    +static inline unsigned long extract_value_bits(unsigned long reg,
    + short bit_nr, short width)
    +{
    + return (reg >> bit_nr) & (0 << width);
    +}
    +
    +static inline unsigned long extract_value(unsigned long reg, unsigned long mask)
    +{
    + while (!(mask & 0x1)) {
    + reg = reg >> 1;
    + mask = mask >> 1;
    + }
    + return mask & reg;
    +}
    +
    +void __init detect_unit_config(unsigned long upr, unsigned long mask,
    + char *text, void (*func) (void))
    +{
    + if (text != NULL)
    + printk("%s", text);
    +
    + if (upr & mask) {
    + if (func != NULL)
    + func();
    + else
    + printk("present\n");
    + } else
    + printk("not present\n");
    +}
    +
    +/*
    + * calibrate_delay
    + *
    + * Lightweight calibrate_delay implementation that calculates loops_per_jiffy
    + * from the clock frequency passed in via the device tree
    + *
    + */
    +
    +void __cpuinit calibrate_delay(void)
    +{
    + const int *val;
    + struct device_node *cpu = NULL;
    + cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481");
    + val = of_get_property(cpu, "clock-frequency", NULL);
    + if (!val)
    + panic("no cpu 'clock-frequency' parameter in device tree");
    + loops_per_jiffy = *val / HZ;
    + pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
    + loops_per_jiffy / (500000 / HZ),
    + (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
    +}
    +
    +void __init setup_arch(char **cmdline_p)
    +{
    + unsigned long max_low_pfn;
    +
    + unflatten_device_tree();
    +
    + setup_cpuinfo();
    +
    + /* process 1's initial memory region is the kernel code/data */
    + init_mm.start_code = (unsigned long)&_stext;
    + init_mm.end_code = (unsigned long)&_etext;
    + init_mm.end_data = (unsigned long)&_edata;
    + init_mm.brk = (unsigned long)&_end;
    +
    +#ifdef CONFIG_BLK_DEV_INITRD
    + initrd_start = (unsigned long)&__initrd_start;
    + initrd_end = (unsigned long)&__initrd_end;
    + if (initrd_start == initrd_end) {
    + initrd_start = 0;
    + initrd_end = 0;
    + }
    + initrd_below_start_ok = 1;
    +#endif
    +
    + /* setup bootmem allocator */
    + max_low_pfn = setup_memory();
    +
    + /* paging_init() sets up the MMU and marks all pages as reserved */
    + paging_init();
    +
    +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
    + if (!conswitchp)
    + conswitchp = &dummy_con;
    +#endif
    +
    + *cmdline_p = cmd_line;
    +
    + printk(KERN_INFO "OpenRISC Linux -- http://openrisc.net\n");
    +}
    +
    +static int show_cpuinfo(struct seq_file *m, void *v)
    +{
    + unsigned long vr;
    + int version, revision;
    +
    + vr = mfspr(SPR_VR);
    + version = (vr & SPR_VR_VER) >> 24;
    + revision = vr & SPR_VR_REV;
    +
    + return seq_printf(m,
    + "cpu\t\t: OpenRISC-%x\n"
    + "revision\t: %d\n"
    + "frequency\t: %ld\n"
    + "dcache size\t: %d bytes\n"
    + "dcache block size\t: %d bytes\n"
    + "icache size\t: %d bytes\n"
    + "icache block size\t: %d bytes\n"
    + "immu\t\t: %d entries, %lu ways\n"
    + "dmmu\t\t: %d entries, %lu ways\n"
    + "bogomips\t: %lu.%02lu\n",
    + version,
    + revision,
    + loops_per_jiffy * HZ,
    + cpuinfo.dcache_size,
    + cpuinfo.dcache_block_size,
    + cpuinfo.icache_size,
    + cpuinfo.icache_block_size,
    + 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
    + 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW),
    + 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
    + 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW),
    + (loops_per_jiffy * HZ) / 500000,
    + ((loops_per_jiffy * HZ) / 5000) % 100);
    +}
    +
    +static void *c_start(struct seq_file *m, loff_t * pos)
    +{
    + /* We only have one CPU... */
    + return *pos < 1 ? (void *)1 : NULL;
    +}
    +
    +static void *c_next(struct seq_file *m, void *v, loff_t * pos)
    +{
    + ++*pos;
    + return NULL;
    +}
    +
    +static void c_stop(struct seq_file *m, void *v)
    +{
    +}
    +
    +const struct seq_operations cpuinfo_op = {
    + .start = c_start,
    + .next = c_next,
    + .stop = c_stop,
    + .show = show_cpuinfo,
    +};
    --
    1.7.4.1


    \
     
     \ /
      Last update: 2011-07-17 17:17    [W:4.248 / U:0.064 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site