diff --git a/libgloss/ChangeLog b/libgloss/ChangeLog index eb74e93c2..9bd02c785 100644 --- a/libgloss/ChangeLog +++ b/libgloss/ChangeLog @@ -1,3 +1,9 @@ +2015-08-07 Stefan Wallentowitz + + * or1k/crt0.S: Add exception nesting + * or1k/exceptions-asm.S: ditto + * or1k/util.c: ditto + 2015-08-07 Stefan Wallentowitz * or1k/sbrk.c: Make heap end globally visible diff --git a/libgloss/or1k/crt0.S b/libgloss/or1k/crt0.S index ecaf9172f..74ddaacf7 100644 --- a/libgloss/or1k/crt0.S +++ b/libgloss/or1k/crt0.S @@ -66,14 +66,18 @@ // function #define EXCEPTION_STACK_FRAME 136 +#define REDZONE 128 + .extern _or1k_stack_top /* points to the next address after the stack */ .extern _or1k_stack_bottom /* points to the last address in the stack */ .extern _or1k_exception_stack_top .extern _or1k_exception_stack_bottom + .extern _or1k_exception_level /* Nesting level of exceptions */ .section .data .global _or1k_stack_size /* reserved stack size */ .global _or1k_exception_stack_size + .global _or1k_exception_level _or1k_stack_size: .word STACK_SIZE _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE @@ -95,13 +99,35 @@ _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE #define GPR_BUF_OFFSET(x) (x << 2) #ifndef __OR1K_MULTICORE__ -#define CALL_EXCEPTION_HANDLER \ - /* store current stack pointer to address 4 */ \ +#define CALL_EXCEPTION_HANDLER(id) \ + /* Store current stack pointer to address 4 */ \ l.sw 0x4(r0),r1; \ + /* Load address of exception nesting level */ \ + l.movhi r1,hi(_or1k_exception_level); \ + l.ori r1,r1,lo(_or1k_exception_level); \ + /* Load the current nesting level */ \ + l.lwz r1,0(r1); \ + /* Set flag if this is the outer (first) exception */ \ + l.sfeq r1,r0; \ + /* Branch to the code for nested exceptions */ \ + OR1K_DELAYED_NOP( \ + OR1K_INST(l.bnf .Lnested_##id) \ + ); \ /* Load top of the exception stack */ \ l.movhi r1,hi(_or1k_exception_stack_top); \ l.ori r1,r1,lo(_or1k_exception_stack_top); \ - l.lwz r1,0(r1); \ + OR1K_DELAYED( \ + /* Load value from array to stack pointer */ \ + OR1K_INST(l.lwz r1,0(r1)), \ + /* and jump over the nested code */ \ + OR1K_INST(l.j .Lnesting_done_##id) \ + ); \ +.Lnested_##id: \ + /* Load back the stack pointer */ \ + l.lwz r1,0x4(r0)); \ + /* Add redzone, nesting needs this */ \ + l.addi r1,r1,-REDZONE; \ +.Lnesting_done_##id: \ /* Reserve red zone and context space */ \ l.addi r1,r1,-EXCEPTION_STACK_FRAME; \ /* Store GPR3 in context */ \ @@ -112,6 +138,15 @@ _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE l.sw GPR_BUF_OFFSET(1)(r1),r3; \ /* Store GPR4 in the context */ \ l.sw GPR_BUF_OFFSET(4)(r1),r4; \ + /* Load address of the exception level */ \ + l.movhi r3,hi(_or1k_exception_level); \ + l.ori r3,r3,lo(_or1k_exception_level); \ + /* Load current value */ \ + l.lwz r4,0(r3); \ + /* Increment level */ \ + l.addi r4,r4,1; \ + /* Store back */ \ + l.sw 0(r3),r4; \ /* Copy the current program counter as first */ \ /* argument for the exception handler. This */ \ /* is then used to determine the exception. */ \ @@ -124,11 +159,36 @@ _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE OR1K_INST(l.j _or1k_exception_handler) \ ) #else -#define CALL_EXCEPTION_HANDLER \ - /* store current stack pointer to shadow reg */ \ +#define CALL_EXCEPTION_HANDLER(id) \ + /* Store current stack pointer to shadow reg */ \ l.mtspr r0,r1,SHADOW_REG(1); \ - /* store current GPR3 as we need it */ \ + /* Store current GPR3 for temporary use */ \ l.mtspr r0,r3,SHADOW_REG(2); \ + /* Store current GPR2 for the level pointer */ \ + l.mtspr r0,r4,SHADOW_REG(3); \ + /* Load nesting level of exceptions */ \ + l.movhi r4,hi(_or1k_exception_level); \ + l.ori r4,r4,lo(_or1k_exception_level); \ + /* Load array pointer */ \ + l.lwz r4,0(r4); \ + /* Get core id */ \ + l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR; \ + /* Generate offset */ \ + l.slli r3,r3,2; \ + /* Generate core nesting level address */ \ + l.add r4,r4,r3; \ + /* Load nesting level */ \ + l.lwz r3,0(r4); \ + /* Increment nesting level */ \ + l.addi r3,r3,1; \ + /* Write back nesting level */ \ + l.sw 0(r4),r3; \ + /* Set flag if this is the outer (first) exception */ \ + l.sfeqi r3,1; \ + /* Branch to the code for nested exceptions */ \ + OR1K_DELAYED_NOP( \ + OR1K_INST(l.bnf .Lnested_##id) \ + ); \ /* Load pointer to exception stack array */ \ l.movhi r1,hi(_or1k_exception_stack_core); \ l.ori r1,r1,lo(_or1k_exception_stack_core); \ @@ -137,10 +197,19 @@ _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR; \ /* Calculate offset in array */ \ l.slli r3,r3,2; \ - /* Load value from array to stack pointer */ \ l.add r1,r1,r3; \ - l.lwz r1,0(r1); \ - /* Reserve red zone and context space */ \ + OR1K_DELAYED( \ + /* Load value from array to stack pointer */ \ + OR1K_INST(l.lwz r1,0(r1)), \ + /* and jump over nested exception pointer */ \ + OR1K_INST(l.j .Lnesting_done_##id) \ + ); \ +.Lnested_##id: \ + /* The stack pointer is still active */ \ + /* Add redzone, nesting needs this */ \ + l.addi r1,r1,-REDZONE; \ +.Lnesting_done_##id: \ + /* Reserve context space */ \ l.addi r1,r1,-EXCEPTION_STACK_FRAME; \ /* Load back software's stack pointer */ \ l.mfspr r3,r0,SHADOW_REG(1); \ @@ -150,6 +219,8 @@ _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE l.mfspr r3,r0,SHADOW_REG(2); \ /* Store this in the context */ \ l.sw GPR_BUF_OFFSET(3)(r1),r3; \ + /* Load back GPR4 */ \ + l.mfspr r4,r0,SHADOW_REG(3); \ /* Store GPR4 in the context */ \ l.sw GPR_BUF_OFFSET(4)(r1),r4; \ /* Copy the current program counter as first */ \ @@ -223,107 +294,107 @@ _or1k_reset: OR1K_DELAYED_NOP(OR1K_INST(l.jr r4)) .org 0x200 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(2) /* 0x300: Data Page Fault exception */ .org 0x300 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(3) /* 0x400: Insn Page Fault exception */ .org 0x400 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(4) /* 0x500: Timer exception */ .org 0x500 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(5) /* 0x600: Aligment exception */ .org 0x600 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(6) /* 0x700: Illegal insn exception */ .org 0x700 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(7) /* 0x800: External interrupt exception */ .org 0x800 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(8) /* 0x900: DTLB miss exception */ .org 0x900 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(9) /* 0xa00: ITLB miss exception */ .org 0xa00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(10) /* 0xb00: Range exception */ .org 0xb00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(11) /* 0xc00: Syscall exception */ .org 0xc00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(12) /* 0xd00: Floating point exception */ .org 0xd00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(13) /* 0xe00: Trap exception */ .org 0xe00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(14) /* 0xf00: Reserved exceptions */ .org 0xf00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(15) .org 0x1000 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(16) .org 0x1100 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(17) .org 0x1200 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(18) .org 0x1300 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(19) .org 0x1400 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(20) .org 0x1500 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(21) .org 0x1600 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(22) .org 0x1700 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(23) .org 0x1800 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(24) .org 0x1900 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(25) .org 0x1a00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(26) .org 0x1b00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(27) .org 0x1c00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(28) .org 0x1d00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(29) .org 0x1e00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(30) .org 0x1f00 - CALL_EXCEPTION_HANDLER + CALL_EXCEPTION_HANDLER(31) /* Pad to the end */ .org 0x1ffc diff --git a/libgloss/or1k/exceptions-asm.S b/libgloss/or1k/exceptions-asm.S index 91a2d8972..4dd4d106a 100644 --- a/libgloss/or1k/exceptions-asm.S +++ b/libgloss/or1k/exceptions-asm.S @@ -27,6 +27,7 @@ #define EXCEPTION_STACK_SIZE 136 .extern _or1k_exception_handler_table + .extern _or1k_exception_level /* -------------------------------------------------------------------------- */ /*!Function to call appropriate exception handler @@ -159,6 +160,24 @@ _or1k_exception_handler: #endif l.sw 0(r21),r20 + /* Decrement the exception nesting level */ + // Load the exception level entry + l.movhi r2,hi(_or1k_exception_level) + l.ori r2,r2,lo(_or1k_exception_level) +#ifdef __OR1K_MULTICORE__ + // In multicore this is the pointer to an array + // Load pointer value + l.lwz r2,0(r2) + // Add word offset of this core's nesting level + l.add r2,r2,r22 +#endif + // Load the nesting level entry + l.lwz r3,0(r2) + // Decrement nesting level + l.addi r3,r3,-1 + // Store back the nesting level + l.sw 0(r2),r3 + /* Restore state */ l.lwz r2,0x80(r1) l.mtspr r0,r2,OR1K_SPR_SYS_EPCR_BASE diff --git a/libgloss/or1k/util.c b/libgloss/or1k/util.c index 74071719e..5e853f359 100644 --- a/libgloss/or1k/util.c +++ b/libgloss/or1k/util.c @@ -23,8 +23,13 @@ #include "or1k-internals.h" #ifdef __OR1K_MULTICORE__ +// Define pointers to arrays uint32_t* *_or1k_stack_core; uint32_t* *_or1k_exception_stack_core; +uint32_t* *_or1k_exception_level; +#else +// Define scalar +uint32_t _or1k_exception_level; #endif uint32_t* _or1k_stack_top; @@ -68,6 +73,15 @@ void _or1k_init() { #else _or1k_exception_handler_table[6] = _or1k_interrupt_handler; #endif + +#ifdef __OR1K_MULTICORE__ + _or1k_exception_level = _sbrk_r(0, 4 * or1k_numcores()); + for (c = 0; c < or1k_numcores(); c++) { + _or1k_exception_level[c] = 0; + } +#else + _or1k_exception_level = 0; +#endif } uint32_t or1k_critical_begin() {