1*9994a338SPaul Mackerras/* 2*9994a338SPaul Mackerras * arch/powerpc/kernel/misc64.S 3*9994a338SPaul Mackerras * 4*9994a338SPaul Mackerras * This file contains miscellaneous low-level functions. 5*9994a338SPaul Mackerras * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 6*9994a338SPaul Mackerras * 7*9994a338SPaul Mackerras * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) 8*9994a338SPaul Mackerras * and Paul Mackerras. 9*9994a338SPaul Mackerras * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) 10*9994a338SPaul Mackerras * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) 11*9994a338SPaul Mackerras * 12*9994a338SPaul Mackerras * This program is free software; you can redistribute it and/or 13*9994a338SPaul Mackerras * modify it under the terms of the GNU General Public License 14*9994a338SPaul Mackerras * as published by the Free Software Foundation; either version 15*9994a338SPaul Mackerras * 2 of the License, or (at your option) any later version. 16*9994a338SPaul Mackerras * 17*9994a338SPaul Mackerras */ 18*9994a338SPaul Mackerras 19*9994a338SPaul Mackerras#include <linux/config.h> 20*9994a338SPaul Mackerras#include <linux/sys.h> 21*9994a338SPaul Mackerras#include <asm/unistd.h> 22*9994a338SPaul Mackerras#include <asm/errno.h> 23*9994a338SPaul Mackerras#include <asm/processor.h> 24*9994a338SPaul Mackerras#include <asm/page.h> 25*9994a338SPaul Mackerras#include <asm/cache.h> 26*9994a338SPaul Mackerras#include <asm/ppc_asm.h> 27*9994a338SPaul Mackerras#include <asm/asm-offsets.h> 28*9994a338SPaul Mackerras#include <asm/cputable.h> 29*9994a338SPaul Mackerras 30*9994a338SPaul Mackerras .text 31*9994a338SPaul Mackerras 32*9994a338SPaul Mackerras/* 33*9994a338SPaul Mackerras * Returns (address we are running at) - (address we were linked at) 34*9994a338SPaul Mackerras * for use before the text and data are mapped to KERNELBASE. 35*9994a338SPaul Mackerras */ 36*9994a338SPaul Mackerras 37*9994a338SPaul Mackerras_GLOBAL(reloc_offset) 38*9994a338SPaul Mackerras mflr r0 39*9994a338SPaul Mackerras bl 1f 40*9994a338SPaul Mackerras1: mflr r3 41*9994a338SPaul Mackerras LOADADDR(r4,1b) 42*9994a338SPaul Mackerras subf r3,r4,r3 43*9994a338SPaul Mackerras mtlr r0 44*9994a338SPaul Mackerras blr 45*9994a338SPaul Mackerras 46*9994a338SPaul Mackerras/* 47*9994a338SPaul Mackerras * add_reloc_offset(x) returns x + reloc_offset(). 48*9994a338SPaul Mackerras */ 49*9994a338SPaul Mackerras_GLOBAL(add_reloc_offset) 50*9994a338SPaul Mackerras mflr r0 51*9994a338SPaul Mackerras bl 1f 52*9994a338SPaul Mackerras1: mflr r5 53*9994a338SPaul Mackerras LOADADDR(r4,1b) 54*9994a338SPaul Mackerras subf r5,r4,r5 55*9994a338SPaul Mackerras add r3,r3,r5 56*9994a338SPaul Mackerras mtlr r0 57*9994a338SPaul Mackerras blr 58*9994a338SPaul Mackerras 59*9994a338SPaul Mackerras_GLOBAL(get_msr) 60*9994a338SPaul Mackerras mfmsr r3 61*9994a338SPaul Mackerras blr 62*9994a338SPaul Mackerras 63*9994a338SPaul Mackerras_GLOBAL(get_dar) 64*9994a338SPaul Mackerras mfdar r3 65*9994a338SPaul Mackerras blr 66*9994a338SPaul Mackerras 67*9994a338SPaul Mackerras_GLOBAL(get_srr0) 68*9994a338SPaul Mackerras mfsrr0 r3 69*9994a338SPaul Mackerras blr 70*9994a338SPaul Mackerras 71*9994a338SPaul Mackerras_GLOBAL(get_srr1) 72*9994a338SPaul Mackerras mfsrr1 r3 73*9994a338SPaul Mackerras blr 74*9994a338SPaul Mackerras 75*9994a338SPaul Mackerras_GLOBAL(get_sp) 76*9994a338SPaul Mackerras mr r3,r1 77*9994a338SPaul Mackerras blr 78*9994a338SPaul Mackerras 79*9994a338SPaul Mackerras#ifdef CONFIG_IRQSTACKS 80*9994a338SPaul Mackerras_GLOBAL(call_do_softirq) 81*9994a338SPaul Mackerras mflr r0 82*9994a338SPaul Mackerras std r0,16(r1) 83*9994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r3) 84*9994a338SPaul Mackerras mr r1,r3 85*9994a338SPaul Mackerras bl .__do_softirq 86*9994a338SPaul Mackerras ld r1,0(r1) 87*9994a338SPaul Mackerras ld r0,16(r1) 88*9994a338SPaul Mackerras mtlr r0 89*9994a338SPaul Mackerras blr 90*9994a338SPaul Mackerras 91*9994a338SPaul Mackerras_GLOBAL(call_handle_IRQ_event) 92*9994a338SPaul Mackerras mflr r0 93*9994a338SPaul Mackerras std r0,16(r1) 94*9994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r6) 95*9994a338SPaul Mackerras mr r1,r6 96*9994a338SPaul Mackerras bl .handle_IRQ_event 97*9994a338SPaul Mackerras ld r1,0(r1) 98*9994a338SPaul Mackerras ld r0,16(r1) 99*9994a338SPaul Mackerras mtlr r0 100*9994a338SPaul Mackerras blr 101*9994a338SPaul Mackerras#endif /* CONFIG_IRQSTACKS */ 102*9994a338SPaul Mackerras 103*9994a338SPaul Mackerras /* 104*9994a338SPaul Mackerras * To be called by C code which needs to do some operations with MMU 105*9994a338SPaul Mackerras * disabled. Note that interrupts have to be disabled by the caller 106*9994a338SPaul Mackerras * prior to calling us. The code called _MUST_ be in the RMO of course 107*9994a338SPaul Mackerras * and part of the linear mapping as we don't attempt to translate the 108*9994a338SPaul Mackerras * stack pointer at all. The function is called with the stack switched 109*9994a338SPaul Mackerras * to this CPU emergency stack 110*9994a338SPaul Mackerras * 111*9994a338SPaul Mackerras * prototype is void *call_with_mmu_off(void *func, void *data); 112*9994a338SPaul Mackerras * 113*9994a338SPaul Mackerras * the called function is expected to be of the form 114*9994a338SPaul Mackerras * 115*9994a338SPaul Mackerras * void *called(void *data); 116*9994a338SPaul Mackerras */ 117*9994a338SPaul Mackerras_GLOBAL(call_with_mmu_off) 118*9994a338SPaul Mackerras mflr r0 /* get link, save it on stackframe */ 119*9994a338SPaul Mackerras std r0,16(r1) 120*9994a338SPaul Mackerras mr r1,r5 /* save old stack ptr */ 121*9994a338SPaul Mackerras ld r1,PACAEMERGSP(r13) /* get emerg. stack */ 122*9994a338SPaul Mackerras subi r1,r1,STACK_FRAME_OVERHEAD 123*9994a338SPaul Mackerras std r0,16(r1) /* save link on emerg. stack */ 124*9994a338SPaul Mackerras std r5,0(r1) /* save old stack ptr in backchain */ 125*9994a338SPaul Mackerras ld r3,0(r3) /* get to real function ptr (assume same TOC) */ 126*9994a338SPaul Mackerras bl 2f /* we need LR to return, continue at label 2 */ 127*9994a338SPaul Mackerras 128*9994a338SPaul Mackerras ld r0,16(r1) /* we return here from the call, get LR and */ 129*9994a338SPaul Mackerras ld r1,0(r1) /* .. old stack ptr */ 130*9994a338SPaul Mackerras mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ 131*9994a338SPaul Mackerras mfmsr r4 132*9994a338SPaul Mackerras ori r4,r4,MSR_IR|MSR_DR 133*9994a338SPaul Mackerras mtspr SPRN_SRR1,r4 134*9994a338SPaul Mackerras rfid 135*9994a338SPaul Mackerras 136*9994a338SPaul Mackerras2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ 137*9994a338SPaul Mackerras mr r3,r4 /* get parameter */ 138*9994a338SPaul Mackerras mfmsr r0 139*9994a338SPaul Mackerras ori r0,r0,MSR_IR|MSR_DR 140*9994a338SPaul Mackerras xori r0,r0,MSR_IR|MSR_DR 141*9994a338SPaul Mackerras mtspr SPRN_SRR1,r0 142*9994a338SPaul Mackerras rfid 143*9994a338SPaul Mackerras 144*9994a338SPaul Mackerras 145*9994a338SPaul Mackerras .section ".toc","aw" 146*9994a338SPaul MackerrasPPC64_CACHES: 147*9994a338SPaul Mackerras .tc ppc64_caches[TC],ppc64_caches 148*9994a338SPaul Mackerras .section ".text" 149*9994a338SPaul Mackerras 150*9994a338SPaul Mackerras/* 151*9994a338SPaul Mackerras * Write any modified data cache blocks out to memory 152*9994a338SPaul Mackerras * and invalidate the corresponding instruction cache blocks. 153*9994a338SPaul Mackerras * 154*9994a338SPaul Mackerras * flush_icache_range(unsigned long start, unsigned long stop) 155*9994a338SPaul Mackerras * 156*9994a338SPaul Mackerras * flush all bytes from start through stop-1 inclusive 157*9994a338SPaul Mackerras */ 158*9994a338SPaul Mackerras 159*9994a338SPaul Mackerras_KPROBE(__flush_icache_range) 160*9994a338SPaul Mackerras 161*9994a338SPaul Mackerras/* 162*9994a338SPaul Mackerras * Flush the data cache to memory 163*9994a338SPaul Mackerras * 164*9994a338SPaul Mackerras * Different systems have different cache line sizes 165*9994a338SPaul Mackerras * and in some cases i-cache and d-cache line sizes differ from 166*9994a338SPaul Mackerras * each other. 167*9994a338SPaul Mackerras */ 168*9994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 169*9994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */ 170*9994a338SPaul Mackerras addi r5,r7,-1 171*9994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 172*9994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 173*9994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 174*9994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ 175*9994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 176*9994a338SPaul Mackerras beqlr /* nothing to do? */ 177*9994a338SPaul Mackerras mtctr r8 178*9994a338SPaul Mackerras1: dcbst 0,r6 179*9994a338SPaul Mackerras add r6,r6,r7 180*9994a338SPaul Mackerras bdnz 1b 181*9994a338SPaul Mackerras sync 182*9994a338SPaul Mackerras 183*9994a338SPaul Mackerras/* Now invalidate the instruction cache */ 184*9994a338SPaul Mackerras 185*9994a338SPaul Mackerras lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ 186*9994a338SPaul Mackerras addi r5,r7,-1 187*9994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 188*9994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 189*9994a338SPaul Mackerras add r8,r8,r5 190*9994a338SPaul Mackerras lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ 191*9994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 192*9994a338SPaul Mackerras beqlr /* nothing to do? */ 193*9994a338SPaul Mackerras mtctr r8 194*9994a338SPaul Mackerras2: icbi 0,r6 195*9994a338SPaul Mackerras add r6,r6,r7 196*9994a338SPaul Mackerras bdnz 2b 197*9994a338SPaul Mackerras isync 198*9994a338SPaul Mackerras blr 199*9994a338SPaul Mackerras .previous .text 200*9994a338SPaul Mackerras/* 201*9994a338SPaul Mackerras * Like above, but only do the D-cache. 202*9994a338SPaul Mackerras * 203*9994a338SPaul Mackerras * flush_dcache_range(unsigned long start, unsigned long stop) 204*9994a338SPaul Mackerras * 205*9994a338SPaul Mackerras * flush all bytes from start to stop-1 inclusive 206*9994a338SPaul Mackerras */ 207*9994a338SPaul Mackerras_GLOBAL(flush_dcache_range) 208*9994a338SPaul Mackerras 209*9994a338SPaul Mackerras/* 210*9994a338SPaul Mackerras * Flush the data cache to memory 211*9994a338SPaul Mackerras * 212*9994a338SPaul Mackerras * Different systems have different cache line sizes 213*9994a338SPaul Mackerras */ 214*9994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 215*9994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ 216*9994a338SPaul Mackerras addi r5,r7,-1 217*9994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 218*9994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 219*9994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 220*9994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ 221*9994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 222*9994a338SPaul Mackerras beqlr /* nothing to do? */ 223*9994a338SPaul Mackerras mtctr r8 224*9994a338SPaul Mackerras0: dcbst 0,r6 225*9994a338SPaul Mackerras add r6,r6,r7 226*9994a338SPaul Mackerras bdnz 0b 227*9994a338SPaul Mackerras sync 228*9994a338SPaul Mackerras blr 229*9994a338SPaul Mackerras 230*9994a338SPaul Mackerras/* 231*9994a338SPaul Mackerras * Like above, but works on non-mapped physical addresses. 232*9994a338SPaul Mackerras * Use only for non-LPAR setups ! It also assumes real mode 233*9994a338SPaul Mackerras * is cacheable. Used for flushing out the DART before using 234*9994a338SPaul Mackerras * it as uncacheable memory 235*9994a338SPaul Mackerras * 236*9994a338SPaul Mackerras * flush_dcache_phys_range(unsigned long start, unsigned long stop) 237*9994a338SPaul Mackerras * 238*9994a338SPaul Mackerras * flush all bytes from start to stop-1 inclusive 239*9994a338SPaul Mackerras */ 240*9994a338SPaul Mackerras_GLOBAL(flush_dcache_phys_range) 241*9994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 242*9994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ 243*9994a338SPaul Mackerras addi r5,r7,-1 244*9994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 245*9994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 246*9994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 247*9994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ 248*9994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 249*9994a338SPaul Mackerras beqlr /* nothing to do? */ 250*9994a338SPaul Mackerras mfmsr r5 /* Disable MMU Data Relocation */ 251*9994a338SPaul Mackerras ori r0,r5,MSR_DR 252*9994a338SPaul Mackerras xori r0,r0,MSR_DR 253*9994a338SPaul Mackerras sync 254*9994a338SPaul Mackerras mtmsr r0 255*9994a338SPaul Mackerras sync 256*9994a338SPaul Mackerras isync 257*9994a338SPaul Mackerras mtctr r8 258*9994a338SPaul Mackerras0: dcbst 0,r6 259*9994a338SPaul Mackerras add r6,r6,r7 260*9994a338SPaul Mackerras bdnz 0b 261*9994a338SPaul Mackerras sync 262*9994a338SPaul Mackerras isync 263*9994a338SPaul Mackerras mtmsr r5 /* Re-enable MMU Data Relocation */ 264*9994a338SPaul Mackerras sync 265*9994a338SPaul Mackerras isync 266*9994a338SPaul Mackerras blr 267*9994a338SPaul Mackerras 268*9994a338SPaul Mackerras_GLOBAL(flush_inval_dcache_range) 269*9994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 270*9994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ 271*9994a338SPaul Mackerras addi r5,r7,-1 272*9994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 273*9994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 274*9994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 275*9994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */ 276*9994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 277*9994a338SPaul Mackerras beqlr /* nothing to do? */ 278*9994a338SPaul Mackerras sync 279*9994a338SPaul Mackerras isync 280*9994a338SPaul Mackerras mtctr r8 281*9994a338SPaul Mackerras0: dcbf 0,r6 282*9994a338SPaul Mackerras add r6,r6,r7 283*9994a338SPaul Mackerras bdnz 0b 284*9994a338SPaul Mackerras sync 285*9994a338SPaul Mackerras isync 286*9994a338SPaul Mackerras blr 287*9994a338SPaul Mackerras 288*9994a338SPaul Mackerras 289*9994a338SPaul Mackerras/* 290*9994a338SPaul Mackerras * Flush a particular page from the data cache to RAM. 291*9994a338SPaul Mackerras * Note: this is necessary because the instruction cache does *not* 292*9994a338SPaul Mackerras * snoop from the data cache. 293*9994a338SPaul Mackerras * 294*9994a338SPaul Mackerras * void __flush_dcache_icache(void *page) 295*9994a338SPaul Mackerras */ 296*9994a338SPaul Mackerras_GLOBAL(__flush_dcache_icache) 297*9994a338SPaul Mackerras/* 298*9994a338SPaul Mackerras * Flush the data cache to memory 299*9994a338SPaul Mackerras * 300*9994a338SPaul Mackerras * Different systems have different cache line sizes 301*9994a338SPaul Mackerras */ 302*9994a338SPaul Mackerras 303*9994a338SPaul Mackerras/* Flush the dcache */ 304*9994a338SPaul Mackerras ld r7,PPC64_CACHES@toc(r2) 305*9994a338SPaul Mackerras clrrdi r3,r3,PAGE_SHIFT /* Page align */ 306*9994a338SPaul Mackerras lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ 307*9994a338SPaul Mackerras lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ 308*9994a338SPaul Mackerras mr r6,r3 309*9994a338SPaul Mackerras mtctr r4 310*9994a338SPaul Mackerras0: dcbst 0,r6 311*9994a338SPaul Mackerras add r6,r6,r5 312*9994a338SPaul Mackerras bdnz 0b 313*9994a338SPaul Mackerras sync 314*9994a338SPaul Mackerras 315*9994a338SPaul Mackerras/* Now invalidate the icache */ 316*9994a338SPaul Mackerras 317*9994a338SPaul Mackerras lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ 318*9994a338SPaul Mackerras lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ 319*9994a338SPaul Mackerras mtctr r4 320*9994a338SPaul Mackerras1: icbi 0,r3 321*9994a338SPaul Mackerras add r3,r3,r5 322*9994a338SPaul Mackerras bdnz 1b 323*9994a338SPaul Mackerras isync 324*9994a338SPaul Mackerras blr 325*9994a338SPaul Mackerras 326*9994a338SPaul Mackerras/* 327*9994a338SPaul Mackerras * I/O string operations 328*9994a338SPaul Mackerras * 329*9994a338SPaul Mackerras * insb(port, buf, len) 330*9994a338SPaul Mackerras * outsb(port, buf, len) 331*9994a338SPaul Mackerras * insw(port, buf, len) 332*9994a338SPaul Mackerras * outsw(port, buf, len) 333*9994a338SPaul Mackerras * insl(port, buf, len) 334*9994a338SPaul Mackerras * outsl(port, buf, len) 335*9994a338SPaul Mackerras * insw_ns(port, buf, len) 336*9994a338SPaul Mackerras * outsw_ns(port, buf, len) 337*9994a338SPaul Mackerras * insl_ns(port, buf, len) 338*9994a338SPaul Mackerras * outsl_ns(port, buf, len) 339*9994a338SPaul Mackerras * 340*9994a338SPaul Mackerras * The *_ns versions don't do byte-swapping. 341*9994a338SPaul Mackerras */ 342*9994a338SPaul Mackerras_GLOBAL(_insb) 343*9994a338SPaul Mackerras cmpwi 0,r5,0 344*9994a338SPaul Mackerras mtctr r5 345*9994a338SPaul Mackerras subi r4,r4,1 346*9994a338SPaul Mackerras blelr- 347*9994a338SPaul Mackerras00: lbz r5,0(r3) 348*9994a338SPaul Mackerras eieio 349*9994a338SPaul Mackerras stbu r5,1(r4) 350*9994a338SPaul Mackerras bdnz 00b 351*9994a338SPaul Mackerras twi 0,r5,0 352*9994a338SPaul Mackerras isync 353*9994a338SPaul Mackerras blr 354*9994a338SPaul Mackerras 355*9994a338SPaul Mackerras_GLOBAL(_outsb) 356*9994a338SPaul Mackerras cmpwi 0,r5,0 357*9994a338SPaul Mackerras mtctr r5 358*9994a338SPaul Mackerras subi r4,r4,1 359*9994a338SPaul Mackerras blelr- 360*9994a338SPaul Mackerras00: lbzu r5,1(r4) 361*9994a338SPaul Mackerras stb r5,0(r3) 362*9994a338SPaul Mackerras bdnz 00b 363*9994a338SPaul Mackerras sync 364*9994a338SPaul Mackerras blr 365*9994a338SPaul Mackerras 366*9994a338SPaul Mackerras_GLOBAL(_insw) 367*9994a338SPaul Mackerras cmpwi 0,r5,0 368*9994a338SPaul Mackerras mtctr r5 369*9994a338SPaul Mackerras subi r4,r4,2 370*9994a338SPaul Mackerras blelr- 371*9994a338SPaul Mackerras00: lhbrx r5,0,r3 372*9994a338SPaul Mackerras eieio 373*9994a338SPaul Mackerras sthu r5,2(r4) 374*9994a338SPaul Mackerras bdnz 00b 375*9994a338SPaul Mackerras twi 0,r5,0 376*9994a338SPaul Mackerras isync 377*9994a338SPaul Mackerras blr 378*9994a338SPaul Mackerras 379*9994a338SPaul Mackerras_GLOBAL(_outsw) 380*9994a338SPaul Mackerras cmpwi 0,r5,0 381*9994a338SPaul Mackerras mtctr r5 382*9994a338SPaul Mackerras subi r4,r4,2 383*9994a338SPaul Mackerras blelr- 384*9994a338SPaul Mackerras00: lhzu r5,2(r4) 385*9994a338SPaul Mackerras sthbrx r5,0,r3 386*9994a338SPaul Mackerras bdnz 00b 387*9994a338SPaul Mackerras sync 388*9994a338SPaul Mackerras blr 389*9994a338SPaul Mackerras 390*9994a338SPaul Mackerras_GLOBAL(_insl) 391*9994a338SPaul Mackerras cmpwi 0,r5,0 392*9994a338SPaul Mackerras mtctr r5 393*9994a338SPaul Mackerras subi r4,r4,4 394*9994a338SPaul Mackerras blelr- 395*9994a338SPaul Mackerras00: lwbrx r5,0,r3 396*9994a338SPaul Mackerras eieio 397*9994a338SPaul Mackerras stwu r5,4(r4) 398*9994a338SPaul Mackerras bdnz 00b 399*9994a338SPaul Mackerras twi 0,r5,0 400*9994a338SPaul Mackerras isync 401*9994a338SPaul Mackerras blr 402*9994a338SPaul Mackerras 403*9994a338SPaul Mackerras_GLOBAL(_outsl) 404*9994a338SPaul Mackerras cmpwi 0,r5,0 405*9994a338SPaul Mackerras mtctr r5 406*9994a338SPaul Mackerras subi r4,r4,4 407*9994a338SPaul Mackerras blelr- 408*9994a338SPaul Mackerras00: lwzu r5,4(r4) 409*9994a338SPaul Mackerras stwbrx r5,0,r3 410*9994a338SPaul Mackerras bdnz 00b 411*9994a338SPaul Mackerras sync 412*9994a338SPaul Mackerras blr 413*9994a338SPaul Mackerras 414*9994a338SPaul Mackerras/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */ 415*9994a338SPaul Mackerras_GLOBAL(_insw_ns) 416*9994a338SPaul Mackerras cmpwi 0,r5,0 417*9994a338SPaul Mackerras mtctr r5 418*9994a338SPaul Mackerras subi r4,r4,2 419*9994a338SPaul Mackerras blelr- 420*9994a338SPaul Mackerras00: lhz r5,0(r3) 421*9994a338SPaul Mackerras eieio 422*9994a338SPaul Mackerras sthu r5,2(r4) 423*9994a338SPaul Mackerras bdnz 00b 424*9994a338SPaul Mackerras twi 0,r5,0 425*9994a338SPaul Mackerras isync 426*9994a338SPaul Mackerras blr 427*9994a338SPaul Mackerras 428*9994a338SPaul Mackerras/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */ 429*9994a338SPaul Mackerras_GLOBAL(_outsw_ns) 430*9994a338SPaul Mackerras cmpwi 0,r5,0 431*9994a338SPaul Mackerras mtctr r5 432*9994a338SPaul Mackerras subi r4,r4,2 433*9994a338SPaul Mackerras blelr- 434*9994a338SPaul Mackerras00: lhzu r5,2(r4) 435*9994a338SPaul Mackerras sth r5,0(r3) 436*9994a338SPaul Mackerras bdnz 00b 437*9994a338SPaul Mackerras sync 438*9994a338SPaul Mackerras blr 439*9994a338SPaul Mackerras 440*9994a338SPaul Mackerras_GLOBAL(_insl_ns) 441*9994a338SPaul Mackerras cmpwi 0,r5,0 442*9994a338SPaul Mackerras mtctr r5 443*9994a338SPaul Mackerras subi r4,r4,4 444*9994a338SPaul Mackerras blelr- 445*9994a338SPaul Mackerras00: lwz r5,0(r3) 446*9994a338SPaul Mackerras eieio 447*9994a338SPaul Mackerras stwu r5,4(r4) 448*9994a338SPaul Mackerras bdnz 00b 449*9994a338SPaul Mackerras twi 0,r5,0 450*9994a338SPaul Mackerras isync 451*9994a338SPaul Mackerras blr 452*9994a338SPaul Mackerras 453*9994a338SPaul Mackerras_GLOBAL(_outsl_ns) 454*9994a338SPaul Mackerras cmpwi 0,r5,0 455*9994a338SPaul Mackerras mtctr r5 456*9994a338SPaul Mackerras subi r4,r4,4 457*9994a338SPaul Mackerras blelr- 458*9994a338SPaul Mackerras00: lwzu r5,4(r4) 459*9994a338SPaul Mackerras stw r5,0(r3) 460*9994a338SPaul Mackerras bdnz 00b 461*9994a338SPaul Mackerras sync 462*9994a338SPaul Mackerras blr 463*9994a338SPaul Mackerras 464*9994a338SPaul Mackerras 465*9994a338SPaul Mackerras_GLOBAL(cvt_fd) 466*9994a338SPaul Mackerras lfd 0,0(r5) /* load up fpscr value */ 467*9994a338SPaul Mackerras mtfsf 0xff,0 468*9994a338SPaul Mackerras lfs 0,0(r3) 469*9994a338SPaul Mackerras stfd 0,0(r4) 470*9994a338SPaul Mackerras mffs 0 /* save new fpscr value */ 471*9994a338SPaul Mackerras stfd 0,0(r5) 472*9994a338SPaul Mackerras blr 473*9994a338SPaul Mackerras 474*9994a338SPaul Mackerras_GLOBAL(cvt_df) 475*9994a338SPaul Mackerras lfd 0,0(r5) /* load up fpscr value */ 476*9994a338SPaul Mackerras mtfsf 0xff,0 477*9994a338SPaul Mackerras lfd 0,0(r3) 478*9994a338SPaul Mackerras stfs 0,0(r4) 479*9994a338SPaul Mackerras mffs 0 /* save new fpscr value */ 480*9994a338SPaul Mackerras stfd 0,0(r5) 481*9994a338SPaul Mackerras blr 482*9994a338SPaul Mackerras 483*9994a338SPaul Mackerras/* 484*9994a338SPaul Mackerras * identify_cpu and calls setup_cpu 485*9994a338SPaul Mackerras * In: r3 = base of the cpu_specs array 486*9994a338SPaul Mackerras * r4 = address of cur_cpu_spec 487*9994a338SPaul Mackerras * r5 = relocation offset 488*9994a338SPaul Mackerras */ 489*9994a338SPaul Mackerras_GLOBAL(identify_cpu) 490*9994a338SPaul Mackerras mfpvr r7 491*9994a338SPaul Mackerras1: 492*9994a338SPaul Mackerras lwz r8,CPU_SPEC_PVR_MASK(r3) 493*9994a338SPaul Mackerras and r8,r8,r7 494*9994a338SPaul Mackerras lwz r9,CPU_SPEC_PVR_VALUE(r3) 495*9994a338SPaul Mackerras cmplw 0,r9,r8 496*9994a338SPaul Mackerras beq 1f 497*9994a338SPaul Mackerras addi r3,r3,CPU_SPEC_ENTRY_SIZE 498*9994a338SPaul Mackerras b 1b 499*9994a338SPaul Mackerras1: 500*9994a338SPaul Mackerras sub r0,r3,r5 501*9994a338SPaul Mackerras std r0,0(r4) 502*9994a338SPaul Mackerras ld r4,CPU_SPEC_SETUP(r3) 503*9994a338SPaul Mackerras add r4,r4,r5 504*9994a338SPaul Mackerras ld r4,0(r4) 505*9994a338SPaul Mackerras add r4,r4,r5 506*9994a338SPaul Mackerras mtctr r4 507*9994a338SPaul Mackerras /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ 508*9994a338SPaul Mackerras mr r4,r3 509*9994a338SPaul Mackerras mr r3,r5 510*9994a338SPaul Mackerras bctr 511*9994a338SPaul Mackerras 512*9994a338SPaul Mackerras/* 513*9994a338SPaul Mackerras * do_cpu_ftr_fixups - goes through the list of CPU feature fixups 514*9994a338SPaul Mackerras * and writes nop's over sections of code that don't apply for this cpu. 515*9994a338SPaul Mackerras * r3 = data offset (not changed) 516*9994a338SPaul Mackerras */ 517*9994a338SPaul Mackerras_GLOBAL(do_cpu_ftr_fixups) 518*9994a338SPaul Mackerras /* Get CPU 0 features */ 519*9994a338SPaul Mackerras LOADADDR(r6,cur_cpu_spec) 520*9994a338SPaul Mackerras sub r6,r6,r3 521*9994a338SPaul Mackerras ld r4,0(r6) 522*9994a338SPaul Mackerras sub r4,r4,r3 523*9994a338SPaul Mackerras ld r4,CPU_SPEC_FEATURES(r4) 524*9994a338SPaul Mackerras /* Get the fixup table */ 525*9994a338SPaul Mackerras LOADADDR(r6,__start___ftr_fixup) 526*9994a338SPaul Mackerras sub r6,r6,r3 527*9994a338SPaul Mackerras LOADADDR(r7,__stop___ftr_fixup) 528*9994a338SPaul Mackerras sub r7,r7,r3 529*9994a338SPaul Mackerras /* Do the fixup */ 530*9994a338SPaul Mackerras1: cmpld r6,r7 531*9994a338SPaul Mackerras bgelr 532*9994a338SPaul Mackerras addi r6,r6,32 533*9994a338SPaul Mackerras ld r8,-32(r6) /* mask */ 534*9994a338SPaul Mackerras and r8,r8,r4 535*9994a338SPaul Mackerras ld r9,-24(r6) /* value */ 536*9994a338SPaul Mackerras cmpld r8,r9 537*9994a338SPaul Mackerras beq 1b 538*9994a338SPaul Mackerras ld r8,-16(r6) /* section begin */ 539*9994a338SPaul Mackerras ld r9,-8(r6) /* section end */ 540*9994a338SPaul Mackerras subf. r9,r8,r9 541*9994a338SPaul Mackerras beq 1b 542*9994a338SPaul Mackerras /* write nops over the section of code */ 543*9994a338SPaul Mackerras /* todo: if large section, add a branch at the start of it */ 544*9994a338SPaul Mackerras srwi r9,r9,2 545*9994a338SPaul Mackerras mtctr r9 546*9994a338SPaul Mackerras sub r8,r8,r3 547*9994a338SPaul Mackerras lis r0,0x60000000@h /* nop */ 548*9994a338SPaul Mackerras3: stw r0,0(r8) 549*9994a338SPaul Mackerras andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l 550*9994a338SPaul Mackerras beq 2f 551*9994a338SPaul Mackerras dcbst 0,r8 /* suboptimal, but simpler */ 552*9994a338SPaul Mackerras sync 553*9994a338SPaul Mackerras icbi 0,r8 554*9994a338SPaul Mackerras2: addi r8,r8,4 555*9994a338SPaul Mackerras bdnz 3b 556*9994a338SPaul Mackerras sync /* additional sync needed on g4 */ 557*9994a338SPaul Mackerras isync 558*9994a338SPaul Mackerras b 1b 559*9994a338SPaul Mackerras 560*9994a338SPaul Mackerras#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) 561*9994a338SPaul Mackerras/* 562*9994a338SPaul Mackerras * Do an IO access in real mode 563*9994a338SPaul Mackerras */ 564*9994a338SPaul Mackerras_GLOBAL(real_readb) 565*9994a338SPaul Mackerras mfmsr r7 566*9994a338SPaul Mackerras ori r0,r7,MSR_DR 567*9994a338SPaul Mackerras xori r0,r0,MSR_DR 568*9994a338SPaul Mackerras sync 569*9994a338SPaul Mackerras mtmsrd r0 570*9994a338SPaul Mackerras sync 571*9994a338SPaul Mackerras isync 572*9994a338SPaul Mackerras mfspr r6,SPRN_HID4 573*9994a338SPaul Mackerras rldicl r5,r6,32,0 574*9994a338SPaul Mackerras ori r5,r5,0x100 575*9994a338SPaul Mackerras rldicl r5,r5,32,0 576*9994a338SPaul Mackerras sync 577*9994a338SPaul Mackerras mtspr SPRN_HID4,r5 578*9994a338SPaul Mackerras isync 579*9994a338SPaul Mackerras slbia 580*9994a338SPaul Mackerras isync 581*9994a338SPaul Mackerras lbz r3,0(r3) 582*9994a338SPaul Mackerras sync 583*9994a338SPaul Mackerras mtspr SPRN_HID4,r6 584*9994a338SPaul Mackerras isync 585*9994a338SPaul Mackerras slbia 586*9994a338SPaul Mackerras isync 587*9994a338SPaul Mackerras mtmsrd r7 588*9994a338SPaul Mackerras sync 589*9994a338SPaul Mackerras isync 590*9994a338SPaul Mackerras blr 591*9994a338SPaul Mackerras 592*9994a338SPaul Mackerras /* 593*9994a338SPaul Mackerras * Do an IO access in real mode 594*9994a338SPaul Mackerras */ 595*9994a338SPaul Mackerras_GLOBAL(real_writeb) 596*9994a338SPaul Mackerras mfmsr r7 597*9994a338SPaul Mackerras ori r0,r7,MSR_DR 598*9994a338SPaul Mackerras xori r0,r0,MSR_DR 599*9994a338SPaul Mackerras sync 600*9994a338SPaul Mackerras mtmsrd r0 601*9994a338SPaul Mackerras sync 602*9994a338SPaul Mackerras isync 603*9994a338SPaul Mackerras mfspr r6,SPRN_HID4 604*9994a338SPaul Mackerras rldicl r5,r6,32,0 605*9994a338SPaul Mackerras ori r5,r5,0x100 606*9994a338SPaul Mackerras rldicl r5,r5,32,0 607*9994a338SPaul Mackerras sync 608*9994a338SPaul Mackerras mtspr SPRN_HID4,r5 609*9994a338SPaul Mackerras isync 610*9994a338SPaul Mackerras slbia 611*9994a338SPaul Mackerras isync 612*9994a338SPaul Mackerras stb r3,0(r4) 613*9994a338SPaul Mackerras sync 614*9994a338SPaul Mackerras mtspr SPRN_HID4,r6 615*9994a338SPaul Mackerras isync 616*9994a338SPaul Mackerras slbia 617*9994a338SPaul Mackerras isync 618*9994a338SPaul Mackerras mtmsrd r7 619*9994a338SPaul Mackerras sync 620*9994a338SPaul Mackerras isync 621*9994a338SPaul Mackerras blr 622*9994a338SPaul Mackerras#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ 623*9994a338SPaul Mackerras 624*9994a338SPaul Mackerras/* 625*9994a338SPaul Mackerras * Create a kernel thread 626*9994a338SPaul Mackerras * kernel_thread(fn, arg, flags) 627*9994a338SPaul Mackerras */ 628*9994a338SPaul Mackerras_GLOBAL(kernel_thread) 629*9994a338SPaul Mackerras std r29,-24(r1) 630*9994a338SPaul Mackerras std r30,-16(r1) 631*9994a338SPaul Mackerras stdu r1,-STACK_FRAME_OVERHEAD(r1) 632*9994a338SPaul Mackerras mr r29,r3 633*9994a338SPaul Mackerras mr r30,r4 634*9994a338SPaul Mackerras ori r3,r5,CLONE_VM /* flags */ 635*9994a338SPaul Mackerras oris r3,r3,(CLONE_UNTRACED>>16) 636*9994a338SPaul Mackerras li r4,0 /* new sp (unused) */ 637*9994a338SPaul Mackerras li r0,__NR_clone 638*9994a338SPaul Mackerras sc 639*9994a338SPaul Mackerras cmpdi 0,r3,0 /* parent or child? */ 640*9994a338SPaul Mackerras bne 1f /* return if parent */ 641*9994a338SPaul Mackerras li r0,0 642*9994a338SPaul Mackerras stdu r0,-STACK_FRAME_OVERHEAD(r1) 643*9994a338SPaul Mackerras ld r2,8(r29) 644*9994a338SPaul Mackerras ld r29,0(r29) 645*9994a338SPaul Mackerras mtlr r29 /* fn addr in lr */ 646*9994a338SPaul Mackerras mr r3,r30 /* load arg and call fn */ 647*9994a338SPaul Mackerras blrl 648*9994a338SPaul Mackerras li r0,__NR_exit /* exit after child exits */ 649*9994a338SPaul Mackerras li r3,0 650*9994a338SPaul Mackerras sc 651*9994a338SPaul Mackerras1: addi r1,r1,STACK_FRAME_OVERHEAD 652*9994a338SPaul Mackerras ld r29,-24(r1) 653*9994a338SPaul Mackerras ld r30,-16(r1) 654*9994a338SPaul Mackerras blr 655*9994a338SPaul Mackerras 656*9994a338SPaul Mackerras/* 657*9994a338SPaul Mackerras * disable_kernel_fp() 658*9994a338SPaul Mackerras * Disable the FPU. 659*9994a338SPaul Mackerras */ 660*9994a338SPaul Mackerras_GLOBAL(disable_kernel_fp) 661*9994a338SPaul Mackerras mfmsr r3 662*9994a338SPaul Mackerras rldicl r0,r3,(63-MSR_FP_LG),1 663*9994a338SPaul Mackerras rldicl r3,r0,(MSR_FP_LG+1),0 664*9994a338SPaul Mackerras mtmsrd r3 /* disable use of fpu now */ 665*9994a338SPaul Mackerras isync 666*9994a338SPaul Mackerras blr 667*9994a338SPaul Mackerras 668*9994a338SPaul Mackerras#ifdef CONFIG_ALTIVEC 669*9994a338SPaul Mackerras 670*9994a338SPaul Mackerras#if 0 /* this has no callers for now */ 671*9994a338SPaul Mackerras/* 672*9994a338SPaul Mackerras * disable_kernel_altivec() 673*9994a338SPaul Mackerras * Disable the VMX. 674*9994a338SPaul Mackerras */ 675*9994a338SPaul Mackerras_GLOBAL(disable_kernel_altivec) 676*9994a338SPaul Mackerras mfmsr r3 677*9994a338SPaul Mackerras rldicl r0,r3,(63-MSR_VEC_LG),1 678*9994a338SPaul Mackerras rldicl r3,r0,(MSR_VEC_LG+1),0 679*9994a338SPaul Mackerras mtmsrd r3 /* disable use of VMX now */ 680*9994a338SPaul Mackerras isync 681*9994a338SPaul Mackerras blr 682*9994a338SPaul Mackerras#endif /* 0 */ 683*9994a338SPaul Mackerras 684*9994a338SPaul Mackerras/* 685*9994a338SPaul Mackerras * giveup_altivec(tsk) 686*9994a338SPaul Mackerras * Disable VMX for the task given as the argument, 687*9994a338SPaul Mackerras * and save the vector registers in its thread_struct. 688*9994a338SPaul Mackerras * Enables the VMX for use in the kernel on return. 689*9994a338SPaul Mackerras */ 690*9994a338SPaul Mackerras_GLOBAL(giveup_altivec) 691*9994a338SPaul Mackerras mfmsr r5 692*9994a338SPaul Mackerras oris r5,r5,MSR_VEC@h 693*9994a338SPaul Mackerras mtmsrd r5 /* enable use of VMX now */ 694*9994a338SPaul Mackerras isync 695*9994a338SPaul Mackerras cmpdi 0,r3,0 696*9994a338SPaul Mackerras beqlr- /* if no previous owner, done */ 697*9994a338SPaul Mackerras addi r3,r3,THREAD /* want THREAD of task */ 698*9994a338SPaul Mackerras ld r5,PT_REGS(r3) 699*9994a338SPaul Mackerras cmpdi 0,r5,0 700*9994a338SPaul Mackerras SAVE_32VRS(0,r4,r3) 701*9994a338SPaul Mackerras mfvscr vr0 702*9994a338SPaul Mackerras li r4,THREAD_VSCR 703*9994a338SPaul Mackerras stvx vr0,r4,r3 704*9994a338SPaul Mackerras beq 1f 705*9994a338SPaul Mackerras ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 706*9994a338SPaul Mackerras lis r3,MSR_VEC@h 707*9994a338SPaul Mackerras andc r4,r4,r3 /* disable FP for previous task */ 708*9994a338SPaul Mackerras std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 709*9994a338SPaul Mackerras1: 710*9994a338SPaul Mackerras#ifndef CONFIG_SMP 711*9994a338SPaul Mackerras li r5,0 712*9994a338SPaul Mackerras ld r4,last_task_used_altivec@got(r2) 713*9994a338SPaul Mackerras std r5,0(r4) 714*9994a338SPaul Mackerras#endif /* CONFIG_SMP */ 715*9994a338SPaul Mackerras blr 716*9994a338SPaul Mackerras 717*9994a338SPaul Mackerras#endif /* CONFIG_ALTIVEC */ 718*9994a338SPaul Mackerras 719*9994a338SPaul Mackerras_GLOBAL(__setup_cpu_power3) 720*9994a338SPaul Mackerras blr 721*9994a338SPaul Mackerras 722*9994a338SPaul Mackerras_GLOBAL(execve) 723*9994a338SPaul Mackerras li r0,__NR_execve 724*9994a338SPaul Mackerras sc 725*9994a338SPaul Mackerras bnslr 726*9994a338SPaul Mackerras neg r3,r3 727*9994a338SPaul Mackerras blr 728*9994a338SPaul Mackerras 729*9994a338SPaul Mackerras/* kexec_wait(phys_cpu) 730*9994a338SPaul Mackerras * 731*9994a338SPaul Mackerras * wait for the flag to change, indicating this kernel is going away but 732*9994a338SPaul Mackerras * the slave code for the next one is at addresses 0 to 100. 733*9994a338SPaul Mackerras * 734*9994a338SPaul Mackerras * This is used by all slaves. 735*9994a338SPaul Mackerras * 736*9994a338SPaul Mackerras * Physical (hardware) cpu id should be in r3. 737*9994a338SPaul Mackerras */ 738*9994a338SPaul Mackerras_GLOBAL(kexec_wait) 739*9994a338SPaul Mackerras bl 1f 740*9994a338SPaul Mackerras1: mflr r5 741*9994a338SPaul Mackerras addi r5,r5,kexec_flag-1b 742*9994a338SPaul Mackerras 743*9994a338SPaul Mackerras99: HMT_LOW 744*9994a338SPaul Mackerras#ifdef CONFIG_KEXEC /* use no memory without kexec */ 745*9994a338SPaul Mackerras lwz r4,0(r5) 746*9994a338SPaul Mackerras cmpwi 0,r4,0 747*9994a338SPaul Mackerras bnea 0x60 748*9994a338SPaul Mackerras#endif 749*9994a338SPaul Mackerras b 99b 750*9994a338SPaul Mackerras 751*9994a338SPaul Mackerras/* this can be in text because we won't change it until we are 752*9994a338SPaul Mackerras * running in real anyways 753*9994a338SPaul Mackerras */ 754*9994a338SPaul Mackerraskexec_flag: 755*9994a338SPaul Mackerras .long 0 756*9994a338SPaul Mackerras 757*9994a338SPaul Mackerras 758*9994a338SPaul Mackerras#ifdef CONFIG_KEXEC 759*9994a338SPaul Mackerras 760*9994a338SPaul Mackerras/* kexec_smp_wait(void) 761*9994a338SPaul Mackerras * 762*9994a338SPaul Mackerras * call with interrupts off 763*9994a338SPaul Mackerras * note: this is a terminal routine, it does not save lr 764*9994a338SPaul Mackerras * 765*9994a338SPaul Mackerras * get phys id from paca 766*9994a338SPaul Mackerras * set paca id to -1 to say we got here 767*9994a338SPaul Mackerras * switch to real mode 768*9994a338SPaul Mackerras * join other cpus in kexec_wait(phys_id) 769*9994a338SPaul Mackerras */ 770*9994a338SPaul Mackerras_GLOBAL(kexec_smp_wait) 771*9994a338SPaul Mackerras lhz r3,PACAHWCPUID(r13) 772*9994a338SPaul Mackerras li r4,-1 773*9994a338SPaul Mackerras sth r4,PACAHWCPUID(r13) /* let others know we left */ 774*9994a338SPaul Mackerras bl real_mode 775*9994a338SPaul Mackerras b .kexec_wait 776*9994a338SPaul Mackerras 777*9994a338SPaul Mackerras/* 778*9994a338SPaul Mackerras * switch to real mode (turn mmu off) 779*9994a338SPaul Mackerras * we use the early kernel trick that the hardware ignores bits 780*9994a338SPaul Mackerras * 0 and 1 (big endian) of the effective address in real mode 781*9994a338SPaul Mackerras * 782*9994a338SPaul Mackerras * don't overwrite r3 here, it is live for kexec_wait above. 783*9994a338SPaul Mackerras */ 784*9994a338SPaul Mackerrasreal_mode: /* assume normal blr return */ 785*9994a338SPaul Mackerras1: li r9,MSR_RI 786*9994a338SPaul Mackerras li r10,MSR_DR|MSR_IR 787*9994a338SPaul Mackerras mflr r11 /* return address to SRR0 */ 788*9994a338SPaul Mackerras mfmsr r12 789*9994a338SPaul Mackerras andc r9,r12,r9 790*9994a338SPaul Mackerras andc r10,r12,r10 791*9994a338SPaul Mackerras 792*9994a338SPaul Mackerras mtmsrd r9,1 793*9994a338SPaul Mackerras mtspr SPRN_SRR1,r10 794*9994a338SPaul Mackerras mtspr SPRN_SRR0,r11 795*9994a338SPaul Mackerras rfid 796*9994a338SPaul Mackerras 797*9994a338SPaul Mackerras 798*9994a338SPaul Mackerras/* 799*9994a338SPaul Mackerras * kexec_sequence(newstack, start, image, control, clear_all()) 800*9994a338SPaul Mackerras * 801*9994a338SPaul Mackerras * does the grungy work with stack switching and real mode switches 802*9994a338SPaul Mackerras * also does simple calls to other code 803*9994a338SPaul Mackerras */ 804*9994a338SPaul Mackerras 805*9994a338SPaul Mackerras_GLOBAL(kexec_sequence) 806*9994a338SPaul Mackerras mflr r0 807*9994a338SPaul Mackerras std r0,16(r1) 808*9994a338SPaul Mackerras 809*9994a338SPaul Mackerras /* switch stacks to newstack -- &kexec_stack.stack */ 810*9994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r3) 811*9994a338SPaul Mackerras mr r1,r3 812*9994a338SPaul Mackerras 813*9994a338SPaul Mackerras li r0,0 814*9994a338SPaul Mackerras std r0,16(r1) 815*9994a338SPaul Mackerras 816*9994a338SPaul Mackerras /* save regs for local vars on new stack. 817*9994a338SPaul Mackerras * yes, we won't go back, but ... 818*9994a338SPaul Mackerras */ 819*9994a338SPaul Mackerras std r31,-8(r1) 820*9994a338SPaul Mackerras std r30,-16(r1) 821*9994a338SPaul Mackerras std r29,-24(r1) 822*9994a338SPaul Mackerras std r28,-32(r1) 823*9994a338SPaul Mackerras std r27,-40(r1) 824*9994a338SPaul Mackerras std r26,-48(r1) 825*9994a338SPaul Mackerras std r25,-56(r1) 826*9994a338SPaul Mackerras 827*9994a338SPaul Mackerras stdu r1,-112-64(r1) 828*9994a338SPaul Mackerras 829*9994a338SPaul Mackerras /* save args into preserved regs */ 830*9994a338SPaul Mackerras mr r31,r3 /* newstack (both) */ 831*9994a338SPaul Mackerras mr r30,r4 /* start (real) */ 832*9994a338SPaul Mackerras mr r29,r5 /* image (virt) */ 833*9994a338SPaul Mackerras mr r28,r6 /* control, unused */ 834*9994a338SPaul Mackerras mr r27,r7 /* clear_all() fn desc */ 835*9994a338SPaul Mackerras mr r26,r8 /* spare */ 836*9994a338SPaul Mackerras lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ 837*9994a338SPaul Mackerras 838*9994a338SPaul Mackerras /* disable interrupts, we are overwriting kernel data next */ 839*9994a338SPaul Mackerras mfmsr r3 840*9994a338SPaul Mackerras rlwinm r3,r3,0,17,15 841*9994a338SPaul Mackerras mtmsrd r3,1 842*9994a338SPaul Mackerras 843*9994a338SPaul Mackerras /* copy dest pages, flush whole dest image */ 844*9994a338SPaul Mackerras mr r3,r29 845*9994a338SPaul Mackerras bl .kexec_copy_flush /* (image) */ 846*9994a338SPaul Mackerras 847*9994a338SPaul Mackerras /* turn off mmu */ 848*9994a338SPaul Mackerras bl real_mode 849*9994a338SPaul Mackerras 850*9994a338SPaul Mackerras /* clear out hardware hash page table and tlb */ 851*9994a338SPaul Mackerras ld r5,0(r27) /* deref function descriptor */ 852*9994a338SPaul Mackerras mtctr r5 853*9994a338SPaul Mackerras bctrl /* ppc_md.hash_clear_all(void); */ 854*9994a338SPaul Mackerras 855*9994a338SPaul Mackerras/* 856*9994a338SPaul Mackerras * kexec image calling is: 857*9994a338SPaul Mackerras * the first 0x100 bytes of the entry point are copied to 0 858*9994a338SPaul Mackerras * 859*9994a338SPaul Mackerras * all slaves branch to slave = 0x60 (absolute) 860*9994a338SPaul Mackerras * slave(phys_cpu_id); 861*9994a338SPaul Mackerras * 862*9994a338SPaul Mackerras * master goes to start = entry point 863*9994a338SPaul Mackerras * start(phys_cpu_id, start, 0); 864*9994a338SPaul Mackerras * 865*9994a338SPaul Mackerras * 866*9994a338SPaul Mackerras * a wrapper is needed to call existing kernels, here is an approximate 867*9994a338SPaul Mackerras * description of one method: 868*9994a338SPaul Mackerras * 869*9994a338SPaul Mackerras * v2: (2.6.10) 870*9994a338SPaul Mackerras * start will be near the boot_block (maybe 0x100 bytes before it?) 871*9994a338SPaul Mackerras * it will have a 0x60, which will b to boot_block, where it will wait 872*9994a338SPaul Mackerras * and 0 will store phys into struct boot-block and load r3 from there, 873*9994a338SPaul Mackerras * copy kernel 0-0x100 and tell slaves to back down to 0x60 again 874*9994a338SPaul Mackerras * 875*9994a338SPaul Mackerras * v1: (2.6.9) 876*9994a338SPaul Mackerras * boot block will have all cpus scanning device tree to see if they 877*9994a338SPaul Mackerras * are the boot cpu ????? 878*9994a338SPaul Mackerras * other device tree differences (prop sizes, va vs pa, etc)... 879*9994a338SPaul Mackerras */ 880*9994a338SPaul Mackerras 881*9994a338SPaul Mackerras /* copy 0x100 bytes starting at start to 0 */ 882*9994a338SPaul Mackerras li r3,0 883*9994a338SPaul Mackerras mr r4,r30 884*9994a338SPaul Mackerras li r5,0x100 885*9994a338SPaul Mackerras li r6,0 886*9994a338SPaul Mackerras bl .copy_and_flush /* (dest, src, copy limit, start offset) */ 887*9994a338SPaul Mackerras1: /* assume normal blr return */ 888*9994a338SPaul Mackerras 889*9994a338SPaul Mackerras /* release other cpus to the new kernel secondary start at 0x60 */ 890*9994a338SPaul Mackerras mflr r5 891*9994a338SPaul Mackerras li r6,1 892*9994a338SPaul Mackerras stw r6,kexec_flag-1b(5) 893*9994a338SPaul Mackerras mr r3,r25 # my phys cpu 894*9994a338SPaul Mackerras mr r4,r30 # start, aka phys mem offset 895*9994a338SPaul Mackerras mtlr 4 896*9994a338SPaul Mackerras li r5,0 897*9994a338SPaul Mackerras blr /* image->start(physid, image->start, 0); */ 898*9994a338SPaul Mackerras#endif /* CONFIG_KEXEC */ 899