| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <linux/sys.h> |
| #include <asm/unistd.h> |
| #include <asm/errno.h> |
| #include <asm/processor.h> |
| #include <asm/page.h> |
| #include <asm/cache.h> |
| #include <asm/ppc_asm.h> |
| #include <asm/asm-offsets.h> |
| #include <asm/cputable.h> |
| #include <asm/thread_info.h> |
| #include <asm/kexec.h> |
| #include <asm/ptrace.h> |
| #include <asm/mmu.h> |
| #include <asm/export.h> |
| #include <asm/feature-fixups.h> |
| |
| <------>.text |
| |
| _GLOBAL(call_do_softirq) |
| <------>mflr r0 |
| <------>std r0,16(r1) |
| <------>stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3) |
| <------>mr r1,r3 |
| <------>bl __do_softirq |
| <------>ld r1,0(r1) |
| <------>ld r0,16(r1) |
| <------>mtlr r0 |
| <------>blr |
| |
| _GLOBAL(call_do_irq) |
| <------>mflr r0 |
| <------>std r0,16(r1) |
| <------>stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) |
| <------>mr r1,r4 |
| <------>bl __do_irq |
| <------>ld r1,0(r1) |
| <------>ld r0,16(r1) |
| <------>mtlr r0 |
| <------>blr |
| |
| _GLOBAL(__bswapdi2) |
| EXPORT_SYMBOL(__bswapdi2) |
| <------>srdi r8,r3,32 |
| <------>rlwinm r7,r3,8,0xffffffff |
| <------>rlwimi r7,r3,24,0,7 |
| <------>rlwinm r9,r8,8,0xffffffff |
| <------>rlwimi r7,r3,24,16,23 |
| <------>rlwimi r9,r8,24,0,7 |
| <------>rlwimi r9,r8,24,16,23 |
| <------>sldi r7,r7,32 |
| <------>or r3,r7,r9 |
| <------>blr |
| |
| |
| #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX |
| _GLOBAL(rmci_on) |
| <------>sync |
| <------>isync |
| <------>li r3,0x100 |
| <------>rldicl r3,r3,32,0 |
| <------>mfspr r5,SPRN_HID4 |
| <------>or r5,r5,r3 |
| <------>sync |
| <------>mtspr SPRN_HID4,r5 |
| <------>isync |
| <------>slbia |
| <------>isync |
| <------>sync |
| <------>blr |
| |
| _GLOBAL(rmci_off) |
| <------>sync |
| <------>isync |
| <------>li r3,0x100 |
| <------>rldicl r3,r3,32,0 |
| <------>mfspr r5,SPRN_HID4 |
| <------>andc r5,r5,r3 |
| <------>sync |
| <------>mtspr SPRN_HID4,r5 |
| <------>isync |
| <------>slbia |
| <------>isync |
| <------>sync |
| <------>blr |
| #endif |
| |
| #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) |
| |
| |
| |
| |
| _GLOBAL(real_readb) |
| <------>mfmsr r7 |
| <------>ori r0,r7,MSR_DR |
| <------>xori r0,r0,MSR_DR |
| <------>sync |
| <------>mtmsrd r0 |
| <------>sync |
| <------>isync |
| <------>mfspr r6,SPRN_HID4 |
| <------>rldicl r5,r6,32,0 |
| <------>ori r5,r5,0x100 |
| <------>rldicl r5,r5,32,0 |
| <------>sync |
| <------>mtspr SPRN_HID4,r5 |
| <------>isync |
| <------>slbia |
| <------>isync |
| <------>lbz r3,0(r3) |
| <------>sync |
| <------>mtspr SPRN_HID4,r6 |
| <------>isync |
| <------>slbia |
| <------>isync |
| <------>mtmsrd r7 |
| <------>sync |
| <------>isync |
| <------>blr |
| |
| <------> |
| |
| |
| _GLOBAL(real_writeb) |
| <------>mfmsr r7 |
| <------>ori r0,r7,MSR_DR |
| <------>xori r0,r0,MSR_DR |
| <------>sync |
| <------>mtmsrd r0 |
| <------>sync |
| <------>isync |
| <------>mfspr r6,SPRN_HID4 |
| <------>rldicl r5,r6,32,0 |
| <------>ori r5,r5,0x100 |
| <------>rldicl r5,r5,32,0 |
| <------>sync |
| <------>mtspr SPRN_HID4,r5 |
| <------>isync |
| <------>slbia |
| <------>isync |
| <------>stb r3,0(r4) |
| <------>sync |
| <------>mtspr SPRN_HID4,r6 |
| <------>isync |
| <------>slbia |
| <------>isync |
| <------>mtmsrd r7 |
| <------>sync |
| <------>isync |
| <------>blr |
| #endif |
| |
| #ifdef CONFIG_PPC_PASEMI |
| |
| _GLOBAL(real_205_readb) |
| <------>mfmsr r7 |
| <------>ori r0,r7,MSR_DR |
| <------>xori r0,r0,MSR_DR |
| <------>sync |
| <------>mtmsrd r0 |
| <------>sync |
| <------>isync |
| <------>LBZCIX(R3,R0,R3) |
| <------>isync |
| <------>mtmsrd r7 |
| <------>sync |
| <------>isync |
| <------>blr |
| |
| _GLOBAL(real_205_writeb) |
| <------>mfmsr r7 |
| <------>ori r0,r7,MSR_DR |
| <------>xori r0,r0,MSR_DR |
| <------>sync |
| <------>mtmsrd r0 |
| <------>sync |
| <------>isync |
| <------>STBCIX(R3,R0,R4) |
| <------>isync |
| <------>mtmsrd r7 |
| <------>sync |
| <------>isync |
| <------>blr |
| |
| #endif |
| |
| |
| #if defined(CONFIG_CPU_FREQ_PMAC64) || defined(CONFIG_CPU_FREQ_MAPLE) |
| |
| * SCOM access functions for 970 (FX only for now) |
| * |
| * unsigned long scom970_read(unsigned int address); |
| * void scom970_write(unsigned int address, unsigned long value); |
| * |
| * The address passed in is the 24 bits register address. This code |
| * is 970 specific and will not check the status bits, so you should |
| * know what you are doing. |
| */ |
| _GLOBAL(scom970_read) |
| <------> |
| <------>mfmsr r4 |
| <------>ori r0,r4,MSR_EE |
| <------>xori r0,r0,MSR_EE |
| <------>mtmsrd r0,1 |
| |
| <------> |
| <------> * (including parity). On current CPUs they must be 0'd, |
| <------> * and finally or in RW bit |
| <------> */ |
| <------>rlwinm r3,r3,8,0,15 |
| <------>ori r3,r3,0x8000 |
| |
| <------> |
| <------>sync |
| <------>mtspr SPRN_SCOMC,r3 |
| <------>isync |
| <------>mfspr r3,SPRN_SCOMD |
| <------>isync |
| <------>mfspr r0,SPRN_SCOMC |
| <------>isync |
| |
| <------> |
| <------> * that's the best we can do). Not implemented yet as we don't use |
| <------> * the scom on any of the bogus CPUs yet, but may have to be done |
| <------> * ultimately |
| <------> */ |
| |
| <------> |
| <------>mtmsrd r4,1 |
| <------>blr |
| |
| |
| _GLOBAL(scom970_write) |
| <------> |
| <------>mfmsr r5 |
| <------>ori r0,r5,MSR_EE |
| <------>xori r0,r0,MSR_EE |
| <------>mtmsrd r0,1 |
| |
| <------> |
| <------> * (including parity). On current CPUs they must be 0'd. |
| <------> */ |
| |
| <------>rlwinm r3,r3,8,0,15 |
| |
| <------>sync |
| <------>mtspr SPRN_SCOMD,r4 |
| <------>isync |
| <------>mtspr SPRN_SCOMC,r3 |
| <------>isync |
| <------>mfspr 3,SPRN_SCOMC |
| <------>isync |
| |
| <------> |
| <------>mtmsrd r5,1 |
| <------>blr |
| #endif |
| |
| |
| * |
| * wait for the flag to change, indicating this kernel is going away but |
| * the slave code for the next one is at addresses 0 to 100. |
| * |
| * This is used by all slaves, even those that did not find a matching |
| * paca in the secondary startup code. |
| * |
| * Physical (hardware) cpu id should be in r3. |
| */ |
| _GLOBAL(kexec_wait) |
| <------>bl 1f |
| 1: mflr r5 |
| <------>addi r5,r5,kexec_flag-1b |
| |
| 99: HMT_LOW |
| #ifdef CONFIG_KEXEC_CORE |
| <------>lwz r4,0(r5) |
| <------>cmpwi 0,r4,0 |
| <------>beq 99b |
| #ifdef CONFIG_PPC_BOOK3S_64 |
| <------>li r10,0x60 |
| <------>mfmsr r11 |
| <------>clrrdi r11,r11,1 |
| <------>mtsrr0 r10 |
| <------>mtsrr1 r11 |
| <------>rfid |
| #else |
| <------> |
| <------>li r4,0 |
| <------>ba 0x60 |
| #endif |
| #endif |
| |
| |
| * running in real anyways |
| */ |
| kexec_flag: |
| <------>.long 0 |
| |
| |
| #ifdef CONFIG_KEXEC_CORE |
| #ifdef CONFIG_PPC_BOOK3E |
| |
| * BOOK3E has no real MMU mode, so we have to setup the initial TLB |
| * for a core to identity map v:0 to p:0. This current implementation |
| * assumes that 1G is enough for kexec. |
| */ |
| kexec_create_tlb: |
| <------> |
| <------> * Invalidate all non-IPROT TLB entries to avoid any TLB conflict. |
| <------> * IPROT TLB entries should be >= PAGE_OFFSET and thus not conflict. |
| <------> */ |
| <------>PPC_TLBILX_ALL(0,R0) |
| <------>sync |
| <------>isync |
| |
| <------>mfspr r10,SPRN_TLB1CFG |
| <------>andi. r10,r10,TLBnCFG_N_ENTRY |
| <------>subi r10,r10,1 |
| <------>lis r9,MAS0_TLBSEL(1)@h |
| <------>rlwimi r9,r10,16,4,15 |
| |
| |
| <------>mtspr SPRN_MAS0,r9 |
| |
| <------>lis r9,(MAS1_VALID|MAS1_IPROT)@h |
| <------>ori r9,r9,(MAS1_TSIZE(BOOK3E_PAGESZ_1GB))@l |
| <------>mtspr SPRN_MAS1,r9 |
| |
| <------>LOAD_REG_IMMEDIATE(r9, 0x0 | MAS2_M_IF_NEEDED) |
| <------>mtspr SPRN_MAS2,r9 |
| |
| <------>LOAD_REG_IMMEDIATE(r9, 0x0 | MAS3_SR | MAS3_SW | MAS3_SX) |
| <------>mtspr SPRN_MAS3,r9 |
| <------>li r9,0 |
| <------>mtspr SPRN_MAS7,r9 |
| |
| <------>tlbwe |
| <------>isync |
| <------>blr |
| #endif |
| |
| |
| * |
| * call with interrupts off |
| * note: this is a terminal routine, it does not save lr |
| * |
| * get phys id from paca |
| * switch to real mode |
| * mark the paca as no longer used |
| * join other cpus in kexec_wait(phys_id) |
| */ |
| _GLOBAL(kexec_smp_wait) |
| <------>lhz r3,PACAHWCPUID(r13) |
| <------>bl real_mode |
| |
| <------>li r4,KEXEC_STATE_REAL_MODE |
| <------>stb r4,PACAKEXECSTATE(r13) |
| |
| <------>b kexec_wait |
| |
| |
| * switch to real mode (turn mmu off) |
| * we use the early kernel trick that the hardware ignores bits |
| * 0 and 1 (big endian) of the effective address in real mode |
| * |
| * don't overwrite r3 here, it is live for kexec_wait above. |
| */ |
| real_mode: |
| #ifdef CONFIG_PPC_BOOK3E |
| <------> |
| <------>b kexec_create_tlb |
| #else |
| 1: li r9,MSR_RI |
| <------>li r10,MSR_DR|MSR_IR |
| <------>mflr r11 |
| <------>mfmsr r12 |
| <------>andc r9,r12,r9 |
| <------>andc r10,r12,r10 |
| |
| <------>mtmsrd r9,1 |
| <------>mtspr SPRN_SRR1,r10 |
| <------>mtspr SPRN_SRR0,r11 |
| <------>rfid |
| #endif |
| |
| |
| * kexec_sequence(newstack, start, image, control, clear_all(), |
| <------> copy_with_mmu_off) |
| * |
| * does the grungy work with stack switching and real mode switches |
| * also does simple calls to other code |
| */ |
| |
| _GLOBAL(kexec_sequence) |
| <------>mflr r0 |
| <------>std r0,16(r1) |
| |
| <------> |
| <------>stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3) |
| <------>mr r1,r3 |
| |
| <------>li r0,0 |
| <------>std r0,16(r1) |
| |
| <------> |
| <------> * yes, we won't go back, but ... |
| <------> */ |
| <------>std r31,-8(r1) |
| <------>std r30,-16(r1) |
| <------>std r29,-24(r1) |
| <------>std r28,-32(r1) |
| <------>std r27,-40(r1) |
| <------>std r26,-48(r1) |
| <------>std r25,-56(r1) |
| |
| <------>stdu r1,-STACK_FRAME_OVERHEAD-64(r1) |
| |
| <------> |
| <------>mr r31,r3 |
| <------>mr r30,r4 |
| <------>mr r29,r5 |
| <------>mr r28,r6 |
| <------>mr r27,r7 |
| <------>mr r26,r8 |
| <------>lhz r25,PACAHWCPUID(r13) |
| |
| <------> |
| #ifdef CONFIG_PPC_BOOK3E |
| <------>wrteei 0 |
| #else |
| <------>mfmsr r3 |
| <------>rlwinm r3,r3,0,17,15 |
| <------>mtmsrd r3,1 |
| #endif |
| |
| <------> |
| <------> * under a hypervisor |
| <------> */ |
| <------>cmpdi r26,0 |
| <------>beq 1f |
| <------>bl real_mode |
| 1: |
| <------> |
| <------>mr r3,r29 |
| <------>bl kexec_copy_flush |
| |
| <------> |
| <------>cmpdi r26,0 |
| <------>bne 1f |
| <------>bl real_mode |
| |
| <------> |
| 1: li r3,0 |
| <------>mr r4,r30 |
| <------>li r5,0x100 |
| <------>li r6,0 |
| <------>bl copy_and_flush |
| 1: |
| |
| <------> |
| <------>mflr r5 |
| <------>li r6,1 |
| <------>stw r6,kexec_flag-1b(5) |
| |
| <------>cmpdi r27,0 |
| <------>beq 1f |
| |
| <------> |
| #ifdef PPC64_ELF_ABI_v1 |
| <------>ld r12,0(r27) |
| #else |
| <------>mr r12,r27 |
| #endif |
| <------>mtctr r12 |
| <------>bctrl |
| |
| |
| * kexec image calling is: |
| * the first 0x100 bytes of the entry point are copied to 0 |
| * |
| * all slaves branch to slave = 0x60 (absolute) |
| * slave(phys_cpu_id); |
| * |
| * master goes to start = entry point |
| * start(phys_cpu_id, start, 0); |
| * |
| * |
| * a wrapper is needed to call existing kernels, here is an approximate |
| * description of one method: |
| * |
| * v2: (2.6.10) |
| * start will be near the boot_block (maybe 0x100 bytes before it?) |
| * it will have a 0x60, which will b to boot_block, where it will wait |
| * and 0 will store phys into struct boot-block and load r3 from there, |
| * copy kernel 0-0x100 and tell slaves to back down to 0x60 again |
| * |
| * v1: (2.6.9) |
| * boot block will have all cpus scanning device tree to see if they |
| * are the boot cpu ????? |
| * other device tree differences (prop sizes, va vs pa, etc)... |
| */ |
| 1: mr r3,r25 # my phys cpu |
| <------>mr r4,r30 # start, aka phys mem offset |
| <------>mtlr 4 |
| <------>li r5,0 |
| <------>blr |
| #endif |
| |
| |