Author: blueswirl Date: 2009-02-28 19:38:55 +0100 (Sat, 28 Feb 2009) New Revision: 462
Modified: openbios-devel/arch/ppc/qemu/init.c openbios-devel/arch/ppc/qemu/start.S openbios-devel/include/ppc/processor.h Log: Make OpenBIOS interrupt handlers 64bit aware v2
While booting a 64bit kernel, there is a small timeframe where OF and the kernel communicate with each other. Within that timeframe, DSI/ISI interrupts may occur, because some memory is not mapped yet.
Right now in case that happens, we jump into the DSI/ISI interrupt handler which clobbers the high 32 bits of the kernel's registers. In order to circumvent that, let's save/restore all 64 bits of all kernel registers when we get a DSI/ISI interrupt.
This patch enables a PPC64 Linux kernel to boot up to the point where it tries to set up the SLB entries (slbmte), which is not yet implemented in qemu.
v2 implements handling for the HIOR register, bringing interrupt handlers to RAM.
Signed-off-by: Alexander Graf alex@csgraf.de
Modified: openbios-devel/arch/ppc/qemu/init.c =================================================================== --- openbios-devel/arch/ppc/qemu/init.c 2009-02-27 22:13:34 UTC (rev 461) +++ openbios-devel/arch/ppc/qemu/init.c 2009-02-28 18:38:55 UTC (rev 462) @@ -32,6 +32,7 @@ #include "libc/vsprintf.h" #define NO_QEMU_PROTOS #include "openbios/fw_cfg.h" +#include "ppc/processor.h"
#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
@@ -238,7 +239,27 @@ fword("finish-device"); }
+/* In order to get 64 bit aware handlers that rescue all our + GPRs from getting truncated to 32 bits, we need to patch the + existing handlers so they jump to our 64 bit aware ones. */ static void +ppc64_patch_handlers(void) +{ + uint32_t *dsi = (uint32_t *)0x300UL; + uint32_t *isi = (uint32_t *)0x400UL; + + // Patch the first DSI handler instruction to: ba 0x2000 + *dsi = 0x48002002; + + // Patch the first ISI handler instruction to: ba 0x2200 + *isi = 0x48002202; + + // Invalidate the cache lines + asm ( "icbi 0, %0" : : "r"(dsi) ); + asm ( "icbi 0, %0" : : "r"(isi) ); +} + +static void cpu_970_init(const struct cpudef *cpu) { cpu_generic_init(cpu); @@ -249,6 +270,15 @@ fword("property");
fword("finish-device"); + + /* The 970 is a PPC64 CPU, so we need to activate + * 64bit aware interrupt handlers */ + + ppc64_patch_handlers(); + + /* The 970 also implements the HIOR which we need to set to 0 */ + + mtspr(S_HIOR, 0); }
static const struct cpudef ppc_defs[] = {
Modified: openbios-devel/arch/ppc/qemu/start.S =================================================================== --- openbios-devel/arch/ppc/qemu/start.S 2009-02-27 22:13:34 UTC (rev 461) +++ openbios-devel/arch/ppc/qemu/start.S 2009-02-28 18:38:55 UTC (rev 462) @@ -24,39 +24,155 @@ #define ILLEGAL_VECTOR( v ) .org __vectors + v ; bl trap_error ; #define VECTOR( v, dummystr ) .org __vectors + v ; vector__##v
-#define EXCEPTION_PREAMBLE \ - mtsprg1 r1 ; /* scratch */ \ - mfsprg0 r1 ; /* exception stack in sprg0 */ \ - addi r1,r1,-80 ; /* push exception frame */ \ +/* We're trying to use the same code for the ppc32 and ppc64 handlers here. + * On ppc32 we only save/restore the registers, C considers volatile. + * + * On ppc64 on the other hand, we have to save/restore all registers, because + * all OF code is 32 bits, which only saves/restores the low 32 bits of the + * registers it clobbers. + */ + +#define EXCEPTION_PREAMBLE_TEMPLATE \ + mtsprg1 r1 ; /* scratch */ \ + mfsprg0 r1 ; /* exception stack in sprg0 */ \ +.ifc ULONG_SIZE, 8 ; \ + addi r1,r1,-(40 * ULONG_SIZE) ; /* push exception frame */ \ +.else ; \ + addi r1,r1,-(20 * ULONG_SIZE) ; /* push exception frame */ \ +.endif ; \ \ - stw r0,0(r1) ; /* save r0 */ \ + stl r0,(0 * ULONG_SIZE)(r1) ; /* save r0 */ \ mfsprg1 r0 ; \ - stw r0,4(r1) ; /* save r1 */ \ - stw r2,8(r1) ; /* save r2 */ \ - stw r3,12(r1) ; /* save r3 */ \ - stw r4,16(r1) ; \ - stw r5,20(r1) ; \ - stw r6,24(r1) ; \ - stw r7,28(r1) ; \ - stw r8,32(r1) ; \ - stw r9,36(r1) ; \ - stw r10,40(r1) ; \ - stw r11,44(r1) ; \ - stw r12,48(r1) ; \ + stl r0,(1 * ULONG_SIZE)(r1) ; /* save r1 */ \ + stl r2,(2 * ULONG_SIZE)(r1) ; /* save r2 */ \ + stl r3,(3 * ULONG_SIZE)(r1) ; /* save r3 */ \ + stl r4,(4 * ULONG_SIZE)(r1) ; \ + stl r5,(5 * ULONG_SIZE)(r1) ; \ + stl r6,(6 * ULONG_SIZE)(r1) ; \ + stl r7,(7 * ULONG_SIZE)(r1) ; \ + stl r8,(8 * ULONG_SIZE)(r1) ; \ + stl r9,(9 * ULONG_SIZE)(r1) ; \ + stl r10,(10 * ULONG_SIZE)(r1) ; \ + stl r11,(11 * ULONG_SIZE)(r1) ; \ + stl r12,(12 * ULONG_SIZE)(r1) ; \ +.ifc ULONG_SIZE, 8 ; \ + stl r13,(17 * ULONG_SIZE)(r1) ; \ + stl r14,(18 * ULONG_SIZE)(r1) ; \ + stl r15,(19 * ULONG_SIZE)(r1) ; \ + stl r16,(20 * ULONG_SIZE)(r1) ; \ + stl r17,(21 * ULONG_SIZE)(r1) ; \ + stl r18,(22 * ULONG_SIZE)(r1) ; \ + stl r19,(23 * ULONG_SIZE)(r1) ; \ + stl r20,(24 * ULONG_SIZE)(r1) ; \ + stl r21,(25 * ULONG_SIZE)(r1) ; \ + stl r22,(26 * ULONG_SIZE)(r1) ; \ + stl r23,(27 * ULONG_SIZE)(r1) ; \ + stl r24,(28 * ULONG_SIZE)(r1) ; \ + stl r25,(29 * ULONG_SIZE)(r1) ; \ + stl r26,(30 * ULONG_SIZE)(r1) ; \ + stl r27,(31 * ULONG_SIZE)(r1) ; \ + stl r28,(32 * ULONG_SIZE)(r1) ; \ + stl r29,(33 * ULONG_SIZE)(r1) ; \ + stl r30,(34 * ULONG_SIZE)(r1) ; \ + stl r31,(35 * ULONG_SIZE)(r1) ; \ +.endif ; \ \ mflr r0 ; \ - stw r0,52(r1) ; \ + stl r0,(13 * ULONG_SIZE)(r1) ; \ mfcr r0 ; \ - stw r0,56(r1) ; \ + stl r0,(14 * ULONG_SIZE)(r1) ; \ mfctr r0 ; \ - stw r0,60(r1) ; \ + stl r0,(15 * ULONG_SIZE)(r1) ; \ mfxer r0 ; \ - stw r0,64(r1) ; \ + stl r0,(16 * ULONG_SIZE)(r1) ; \ \ /* 76(r1) unused */ \ - addi r1,r1,-16 ; /* call conventions uses 0(r1) and 4(r1)... */ + addi r1,r1,-16 ; /* C ABI uses 0(r1) and 4(r1)... */
+#define EXCEPTION_EPILOGUE_TEMPLATE \ + addi r1,r1,16 ; /* pop ABI frame */ \ +\ + ll r0,(13 * ULONG_SIZE)(r1) ; \ + mtlr r0 ; \ + ll r0,(14 * ULONG_SIZE)(r1) ; \ + mtcr r0 ; \ + ll r0,(15 * ULONG_SIZE)(r1) ; \ + mtctr r0 ; \ + ll r0,(16 * ULONG_SIZE)(r1) ; \ + mtxer r0 ; \ +\ + ll r0,(0 * ULONG_SIZE)(r1) ; \ + ll r2,(2 * ULONG_SIZE)(r1) ; \ + ll r3,(3 * ULONG_SIZE)(r1) ; \ + ll r4,(4 * ULONG_SIZE)(r1) ; \ + ll r5,(5 * ULONG_SIZE)(r1) ; \ + ll r6,(6 * ULONG_SIZE)(r1) ; \ + ll r7,(7 * ULONG_SIZE)(r1) ; \ + ll r8,(8 * ULONG_SIZE)(r1) ; \ + ll r9,(9 * ULONG_SIZE)(r1) ; \ + ll r10,(10 * ULONG_SIZE)(r1) ; \ + ll r11,(11 * ULONG_SIZE)(r1) ; \ + ll r12,(12 * ULONG_SIZE)(r1) ; \ +.ifc ULONG_SIZE, 8 ; \ + ll r13,(17 * ULONG_SIZE)(r1) ; \ + ll r14,(18 * ULONG_SIZE)(r1) ; \ + ll r15,(19 * ULONG_SIZE)(r1) ; \ + ll r16,(20 * ULONG_SIZE)(r1) ; \ + ll r17,(21 * ULONG_SIZE)(r1) ; \ + ll r18,(22 * ULONG_SIZE)(r1) ; \ + ll r19,(23 * ULONG_SIZE)(r1) ; \ + ll r20,(24 * ULONG_SIZE)(r1) ; \ + ll r21,(25 * ULONG_SIZE)(r1) ; \ + ll r22,(26 * ULONG_SIZE)(r1) ; \ + ll r23,(27 * ULONG_SIZE)(r1) ; \ + ll r24,(28 * ULONG_SIZE)(r1) ; \ + ll r25,(29 * ULONG_SIZE)(r1) ; \ + ll r26,(30 * ULONG_SIZE)(r1) ; \ + ll r27,(31 * ULONG_SIZE)(r1) ; \ + ll r28,(32 * ULONG_SIZE)(r1) ; \ + ll r29,(33 * ULONG_SIZE)(r1) ; \ + ll r30,(34 * ULONG_SIZE)(r1) ; \ + ll r31,(35 * ULONG_SIZE)(r1) ; \ +.endif ; \ + ll r1,(1 * ULONG_SIZE)(r1) ; /* restore stack at last */ \ + rfi
+// PPC32 + +#define ULONG_SIZE 4 +#define stl stw +#define ll lwz + +.macro EXCEPTION_PREAMBLE + EXCEPTION_PREAMBLE_TEMPLATE +.endm + +.macro EXCEPTION_EPILOGUE + EXCEPTION_EPILOGUE_TEMPLATE +.endm + +#undef ULONG_SIZE +#undef stl +#undef ll + +// PPC64 + +#define ULONG_SIZE 8 +#define stl std +#define ll ld + +.macro EXCEPTION_PREAMBLE_64 + EXCEPTION_PREAMBLE_TEMPLATE +.endm + +.macro EXCEPTION_EPILOGUE_64 + EXCEPTION_EPILOGUE_TEMPLATE +.endm + +#undef ULONG_SIZE +#undef stl +#undef ll + /************************************************************************/ /* vectors */ /************************************************************************/ @@ -68,32 +184,8 @@ b 1b
exception_return: - addi r1,r1,16 // pop ABI frame + EXCEPTION_EPILOGUE
- lwz r0,52(r1) - mtlr r0 - lwz r0,56(r1) - mtcr r0 - lwz r0,60(r1) - mtctr r0 - lwz r0,64(r1) - mtxer r0 - - lwz r0,0(r1) // restore r0 - lwz r2,8(r1) // restore r2 - lwz r3,12(r1) // restore r3 - lwz r4,16(r1) - lwz r5,20(r1) - lwz r6,24(r1) - lwz r7,28(r1) - lwz r8,32(r1) - lwz r9,36(r1) - lwz r10,40(r1) - lwz r11,44(r1) - lwz r12,48(r1) - lwz r1,4(r1) // restore r1 - rfi - .globl __divide_error __divide_error: trap_error: @@ -150,6 +242,22 @@ ILLEGAL_VECTOR( 0x1600 ) ILLEGAL_VECTOR( 0x1700 )
+VECTOR( 0x2000, "DSI_64" ): + EXCEPTION_PREAMBLE_64 + lis r3,HA(dsi_exception) + addi r3,r3,LO(dsi_exception) + mtctr r3 + bctrl + EXCEPTION_EPILOGUE_64 + +VECTOR( 0x2200, "ISI_64" ): + EXCEPTION_PREAMBLE_64 + lis r3,HA(isi_exception) + addi r3,r3,LO(isi_exception) + mtctr r3 + bctrl + EXCEPTION_EPILOGUE_64 + GLOBL(__vectors_end):
/************************************************************************/
Modified: openbios-devel/include/ppc/processor.h =================================================================== --- openbios-devel/include/ppc/processor.h 2009-02-27 22:13:34 UTC (rev 461) +++ openbios-devel/include/ppc/processor.h 2009-02-28 18:38:55 UTC (rev 462) @@ -92,6 +92,7 @@ #define S_TBWL 284 /* Time base Upper/Lower (Writing) */ #define S_TBWU 285 #define S_PVR 287 /* Processor Version Register */ +#define S_HIOR 311 /* Hardware Interrupt Offset Register */ #define S_IBAT0U 528 #define S_IBAT0L 529 #define S_IBAT1U 530 @@ -400,4 +401,10 @@
#define SPRNUM_FLIP( v ) ( (((v)>>5) & 0x1f) | (((v)<<5) & 0x3e0) )
+/* C helpers */ + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) +#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) + #endif /* _H_PROCESSOR */