/* * Entry point and assembler functions for ppc64 tests. * * Copyright (C) 2016, Red Hat Inc, Andrew Jones * * This work is licensed under the terms of the GNU LGPL, version 2. */ #define __ASSEMBLY__ #include #include #include #include #include "spapr.h" #define P_HANDLER 0x2ff8 .section .init /* * start is the entry point. r3 points to the DTB */ .globl start start: FIXUP_ENDIAN /* Switch to 64-bit mode */ mfmsr r1 li r2,1 sldi r2,r2,MSR_SF_BIT or r1,r1,r2 mtmsrd r1 /* * We were loaded at QEMU's kernel load address, but we're not * allowed to link there due to how QEMU deals with linker VMAs, * so we just linked at zero. This means the first thing to do is * to find our stack and toc, and then do a relocate. powernv and * pseries load addresses are not the same, so find the address * dynamically: */ bl 0f 0: mflr r31 subi r31, r31, 0b - start /* QEMU's kernel load address */ ld r1, (p_stack - start)(r31) ld r2, (p_toc - start)(r31) add r1, r1, r31 add r2, r2, r31 /* Zero backpointers in initial stack frame so backtrace() stops */ li r0,0 std r0,0(r1) std r0,16(r1) /* save DTB pointer */ std r3, 56(r1) /* * Call relocate. relocate is C code, but careful to not use * any global references, as they may use absolute addresses, * which are, obviously, not yet relocated. */ mr r3, r31 ld r4, (p_dyn - start)(r31) add r4, r4, r31 bl relocate /* compute address of call_handler */ LOAD_REG_ADDR(r4, call_handler) std r4, P_HANDLER(0) /* relocate vector table to base address 0x0 (MSR_IP = 0) */ /* source: r4, dest end: r5, destination: r6 */ LOAD_REG_ADDR(r4, __start_interrupts) LOAD_REG_ADDR(r5, __end_interrupts) sub r5,r5,r4 li r6,0x100 sub r4,r4,r6 add r5,r5,r6 addi r6,r6,-8 2: li r0,8 mtctr r0 /* copy a cache line size */ 3: addi r6,r6,8 ldx r0,r6,r4 stdx r0,0,r6 bdnz 3b dcbst 0,r6 /* flush icache */ sync icbi 0,r6 cmpld 0,r6,r5 blt 2b sync isync /* powernv machine does not check broken_sc1 */ mfmsr r3 li r4,1 sldi r4,r4,MSR_HV_BIT and. r3,r3,r4 bne 1f /* patch sc1 if needed */ bl hcall_have_broken_sc1 cmpwi r3, 0 beq 1f LOAD_REG_ADDR(r3, hcall) LOAD_REG_IMMEDIATE(r4, SC1_REPLACEMENT) stw r4, 0(r3) /* complete setup */ 1: ld r3, 56(r1) bl setup /* run the test */ LOAD_REG_ADDR(r3, __argc) LOAD_REG_ADDR(r4, __argv) LOAD_REG_ADDR(r5, __environ) lwz r3, 0(r3) bl main bl exit b halt /* * start_secondary is the secondary entry point. r3 contains the cpu id */ .globl start_secondary start_secondary: FIXUP_ENDIAN /* Switch to 64-bit mode */ mfmsr r1 li r2,1 sldi r2,r2,MSR_SF_BIT or r1,r1,r2 mtmsrd r1 bl 0f 0: mflr r31 subi r31, r31, 0b - start /* QEMU's kernel load address */ ld r2, (p_toc - start)(r31) LOAD_REG_ADDR(r9, cpus) li r8,0 li r7,0 1: add r6,r9,r7 ld r6,CPU_SERVER_NO(r6) cmpd r6,r3 beq 2f addi r7,r7,SIZEOF_STRUCT_CPU addi r8,r8,1 cmpdi r8,MAX_CPUS bne 1b b . 2: add r3,r9,r7 ld r1,CPU_STACK(r3) /* Zero backpointers in initial stack frame so backtrace() stops */ li r0,0 std r0,0(r1) std r0,16(r1) bl main_secondary bl exit b halt .align 3 p_stack: .llong stackptr p_toc: .llong tocptr p_dyn: .llong dynamic_start .text start_text: .align 3 p_toc_text: .llong tocptr .align 3 .globl hcall hcall: sc 1 blr .globl halt halt: 1: b 1b .globl enter_rtas enter_rtas: LOAD_REG_ADDR(r11, rtas_entry) ld r10, 0(r11) cmpdi r10,0 bne external_rtas /* Use H_RTAS directly */ mr r4,r3 lis r3,KVMPPC_H_RTAS@h ori r3,r3,KVMPPC_H_RTAS@l b hcall external_rtas: /* Use external RTAS blob */ mflr r0 std r0, 16(r1) LOAD_REG_ADDR(r11, rtas_return_loc) mtlr r11 mfmsr r11 LOAD_REG_IMMEDIATE(r9, RTAS_MSR_MASK) and r11, r11, r9 mtsrr0 r10 mtsrr1 r11 rfid b . rtas_return_loc: FIXUP_ENDIAN ld r0, 16(r1) mtlr r0 blr call_handler: /* save context */ /* GPRs */ .irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 SAVE_GPR(\i, r1) .endr mfsprg1 r0 std r0,GPR1(r1) std r0,0(r1) /* Backchain from interrupt stack to regular stack */ /* lr, xer, ccr */ mflr r0 std r0,_LINK(r1) mfxer r0 std r0,_XER(r1) mfcr r0 std r0,_CCR(r1) /* restore TOC pointer */ bl 0f 0: mflr r31 subi r31, r31, 0b - start_text ld r2, (p_toc_text - start_text)(r31) /* call generic handler */ addi r3,r1,STACK_FRAME_OVERHEAD bl do_handle_exception .global do_handle_exception_return do_handle_exception_return: /* restore context */ ld r0,_CTR(r1) mtctr r0 ld r0,_LINK(r1) mtlr r0 ld r0,_XER(r1) mtxer r0 ld r0,_CCR(r1) mtcr r0 ld r0, _NIP(r1) mtsrr0 r0 ld r0, _MSR(r1) mtsrr1 r0 .irp i, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 REST_GPR(\i, r1) .endr /* restore r1, as we don't need it anymore */ REST_GPR(1,r1) rfid b . .section .text.ex /* [H]VECTOR must not be more than 8 instructions to fit in 0x20 vectors */ .macro VECTOR vec . = \vec mtsprg1 r1 /* save r1 */ mfsprg0 r1 /* get struct cpu address */ ld r1,CPU_EXCEPTION_STACK(r1) /* get exception stack address */ subi r1,r1, INT_FRAME_SIZE /* save r0 and ctr to call generic handler */ SAVE_GPR(0,r1) li r0,\vec std r0,_TRAP(r1) b handler_trampoline .endm .macro HVECTOR vec . = \vec mtsprg1 r1 /* save r1 */ mfsprg0 r1 /* get struct cpu address */ ld r1,CPU_EXCEPTION_STACK(r1) /* get exception stack address */ subi r1,r1, INT_FRAME_SIZE /* save r0 and ctr to call generic handler */ SAVE_GPR(0,r1) li r0,\vec std r0,_TRAP(r1) b handler_htrampoline .endm . = 0x100 .globl __start_interrupts __start_interrupts: VECTOR(0x100) VECTOR(0x200) VECTOR(0x300) VECTOR(0x380) VECTOR(0x400) VECTOR(0x480) VECTOR(0x500) VECTOR(0x600) VECTOR(0x700) VECTOR(0x800) VECTOR(0x900) HVECTOR(0x980) VECTOR(0xa00) VECTOR(0xc00) VECTOR(0xd00) HVECTOR(0xe00) HVECTOR(0xe20) HVECTOR(0xe40) HVECTOR(0xe60) HVECTOR(0xe80) HVECTOR(0xea0) VECTOR(0xf00) VECTOR(0xf20) VECTOR(0xf40) VECTOR(0xf60) HVECTOR(0xf80) handler_trampoline: mfctr r0 std r0,_CTR(r1) ld r0, P_HANDLER(0) mtctr r0 /* nip and msr */ mfsrr0 r0 std r0, _NIP(r1) mfsrr1 r0 std r0, _MSR(r1) bctr handler_htrampoline: mfctr r0 std r0,_CTR(r1) ld r0, P_HANDLER(0) mtctr r0 /* nip and msr */ mfspr r0, SPR_HSRR0 std r0, _NIP(r1) mfspr r0, SPR_HSRR1 std r0, _MSR(r1) bctr .align 7 .globl __end_interrupts __end_interrupts: .org P_HANDLER .llong 0