19994a338SPaul Mackerras/* 29994a338SPaul Mackerras * arch/powerpc/kernel/misc64.S 39994a338SPaul Mackerras * 49994a338SPaul Mackerras * This file contains miscellaneous low-level functions. 59994a338SPaul Mackerras * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 69994a338SPaul Mackerras * 79994a338SPaul Mackerras * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) 89994a338SPaul Mackerras * and Paul Mackerras. 99994a338SPaul Mackerras * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) 109994a338SPaul Mackerras * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) 119994a338SPaul Mackerras * 129994a338SPaul Mackerras * This program is free software; you can redistribute it and/or 139994a338SPaul Mackerras * modify it under the terms of the GNU General Public License 149994a338SPaul Mackerras * as published by the Free Software Foundation; either version 159994a338SPaul Mackerras * 2 of the License, or (at your option) any later version. 169994a338SPaul Mackerras * 179994a338SPaul Mackerras */ 189994a338SPaul Mackerras 199994a338SPaul Mackerras#include <linux/config.h> 209994a338SPaul Mackerras#include <linux/sys.h> 219994a338SPaul Mackerras#include <asm/unistd.h> 229994a338SPaul Mackerras#include <asm/errno.h> 239994a338SPaul Mackerras#include <asm/processor.h> 249994a338SPaul Mackerras#include <asm/page.h> 259994a338SPaul Mackerras#include <asm/cache.h> 269994a338SPaul Mackerras#include <asm/ppc_asm.h> 279994a338SPaul Mackerras#include <asm/asm-offsets.h> 289994a338SPaul Mackerras#include <asm/cputable.h> 29*6cb7bfebSDavid Gibson#include <asm/thread_info.h> 309994a338SPaul Mackerras 319994a338SPaul Mackerras .text 329994a338SPaul Mackerras 339994a338SPaul Mackerras/* 349994a338SPaul Mackerras * Returns (address we are running at) - (address we were linked at) 359994a338SPaul Mackerras * for use before the text and data are mapped to KERNELBASE. 369994a338SPaul Mackerras */ 379994a338SPaul Mackerras 389994a338SPaul Mackerras_GLOBAL(reloc_offset) 399994a338SPaul Mackerras mflr r0 409994a338SPaul Mackerras bl 1f 419994a338SPaul Mackerras1: mflr r3 429994a338SPaul Mackerras LOADADDR(r4,1b) 439994a338SPaul Mackerras subf r3,r4,r3 449994a338SPaul Mackerras mtlr r0 459994a338SPaul Mackerras blr 469994a338SPaul Mackerras 479994a338SPaul Mackerras/* 489994a338SPaul Mackerras * add_reloc_offset(x) returns x + reloc_offset(). 499994a338SPaul Mackerras */ 509994a338SPaul Mackerras_GLOBAL(add_reloc_offset) 519994a338SPaul Mackerras mflr r0 529994a338SPaul Mackerras bl 1f 539994a338SPaul Mackerras1: mflr r5 549994a338SPaul Mackerras LOADADDR(r4,1b) 559994a338SPaul Mackerras subf r5,r4,r5 569994a338SPaul Mackerras add r3,r3,r5 579994a338SPaul Mackerras mtlr r0 589994a338SPaul Mackerras blr 599994a338SPaul Mackerras 609994a338SPaul Mackerras_GLOBAL(get_msr) 619994a338SPaul Mackerras mfmsr r3 629994a338SPaul Mackerras blr 639994a338SPaul Mackerras 649994a338SPaul Mackerras_GLOBAL(get_dar) 659994a338SPaul Mackerras mfdar r3 669994a338SPaul Mackerras blr 679994a338SPaul Mackerras 689994a338SPaul Mackerras_GLOBAL(get_srr0) 699994a338SPaul Mackerras mfsrr0 r3 709994a338SPaul Mackerras blr 719994a338SPaul Mackerras 729994a338SPaul Mackerras_GLOBAL(get_srr1) 739994a338SPaul Mackerras mfsrr1 r3 749994a338SPaul Mackerras blr 759994a338SPaul Mackerras 769994a338SPaul Mackerras_GLOBAL(get_sp) 779994a338SPaul Mackerras mr r3,r1 789994a338SPaul Mackerras blr 799994a338SPaul Mackerras 809994a338SPaul Mackerras#ifdef CONFIG_IRQSTACKS 819994a338SPaul Mackerras_GLOBAL(call_do_softirq) 829994a338SPaul Mackerras mflr r0 839994a338SPaul Mackerras std r0,16(r1) 849994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r3) 859994a338SPaul Mackerras mr r1,r3 869994a338SPaul Mackerras bl .__do_softirq 879994a338SPaul Mackerras ld r1,0(r1) 889994a338SPaul Mackerras ld r0,16(r1) 899994a338SPaul Mackerras mtlr r0 909994a338SPaul Mackerras blr 919994a338SPaul Mackerras 929994a338SPaul Mackerras_GLOBAL(call_handle_IRQ_event) 939994a338SPaul Mackerras mflr r0 949994a338SPaul Mackerras std r0,16(r1) 959994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r6) 969994a338SPaul Mackerras mr r1,r6 979994a338SPaul Mackerras bl .handle_IRQ_event 989994a338SPaul Mackerras ld r1,0(r1) 999994a338SPaul Mackerras ld r0,16(r1) 1009994a338SPaul Mackerras mtlr r0 1019994a338SPaul Mackerras blr 1029994a338SPaul Mackerras#endif /* CONFIG_IRQSTACKS */ 1039994a338SPaul Mackerras 1049994a338SPaul Mackerras /* 1059994a338SPaul Mackerras * To be called by C code which needs to do some operations with MMU 1069994a338SPaul Mackerras * disabled. Note that interrupts have to be disabled by the caller 1079994a338SPaul Mackerras * prior to calling us. The code called _MUST_ be in the RMO of course 1089994a338SPaul Mackerras * and part of the linear mapping as we don't attempt to translate the 1099994a338SPaul Mackerras * stack pointer at all. The function is called with the stack switched 1109994a338SPaul Mackerras * to this CPU emergency stack 1119994a338SPaul Mackerras * 1129994a338SPaul Mackerras * prototype is void *call_with_mmu_off(void *func, void *data); 1139994a338SPaul Mackerras * 1149994a338SPaul Mackerras * the called function is expected to be of the form 1159994a338SPaul Mackerras * 1169994a338SPaul Mackerras * void *called(void *data); 1179994a338SPaul Mackerras */ 1189994a338SPaul Mackerras_GLOBAL(call_with_mmu_off) 1199994a338SPaul Mackerras mflr r0 /* get link, save it on stackframe */ 1209994a338SPaul Mackerras std r0,16(r1) 1219994a338SPaul Mackerras mr r1,r5 /* save old stack ptr */ 1229994a338SPaul Mackerras ld r1,PACAEMERGSP(r13) /* get emerg. stack */ 1239994a338SPaul Mackerras subi r1,r1,STACK_FRAME_OVERHEAD 1249994a338SPaul Mackerras std r0,16(r1) /* save link on emerg. stack */ 1259994a338SPaul Mackerras std r5,0(r1) /* save old stack ptr in backchain */ 1269994a338SPaul Mackerras ld r3,0(r3) /* get to real function ptr (assume same TOC) */ 1279994a338SPaul Mackerras bl 2f /* we need LR to return, continue at label 2 */ 1289994a338SPaul Mackerras 1299994a338SPaul Mackerras ld r0,16(r1) /* we return here from the call, get LR and */ 1309994a338SPaul Mackerras ld r1,0(r1) /* .. old stack ptr */ 1319994a338SPaul Mackerras mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ 1329994a338SPaul Mackerras mfmsr r4 1339994a338SPaul Mackerras ori r4,r4,MSR_IR|MSR_DR 1349994a338SPaul Mackerras mtspr SPRN_SRR1,r4 1359994a338SPaul Mackerras rfid 1369994a338SPaul Mackerras 1379994a338SPaul Mackerras2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ 1389994a338SPaul Mackerras mr r3,r4 /* get parameter */ 1399994a338SPaul Mackerras mfmsr r0 1409994a338SPaul Mackerras ori r0,r0,MSR_IR|MSR_DR 1419994a338SPaul Mackerras xori r0,r0,MSR_IR|MSR_DR 1429994a338SPaul Mackerras mtspr SPRN_SRR1,r0 1439994a338SPaul Mackerras rfid 1449994a338SPaul Mackerras 1459994a338SPaul Mackerras 1469994a338SPaul Mackerras .section ".toc","aw" 1479994a338SPaul MackerrasPPC64_CACHES: 1489994a338SPaul Mackerras .tc ppc64_caches[TC],ppc64_caches 1499994a338SPaul Mackerras .section ".text" 1509994a338SPaul Mackerras 1519994a338SPaul Mackerras/* 1529994a338SPaul Mackerras * Write any modified data cache blocks out to memory 1539994a338SPaul Mackerras * and invalidate the corresponding instruction cache blocks. 1549994a338SPaul Mackerras * 1559994a338SPaul Mackerras * flush_icache_range(unsigned long start, unsigned long stop) 1569994a338SPaul Mackerras * 1579994a338SPaul Mackerras * flush all bytes from start through stop-1 inclusive 1589994a338SPaul Mackerras */ 1599994a338SPaul Mackerras 1609994a338SPaul Mackerras_KPROBE(__flush_icache_range) 1619994a338SPaul Mackerras 1629994a338SPaul Mackerras/* 1639994a338SPaul Mackerras * Flush the data cache to memory 1649994a338SPaul Mackerras * 1659994a338SPaul Mackerras * Different systems have different cache line sizes 1669994a338SPaul Mackerras * and in some cases i-cache and d-cache line sizes differ from 1679994a338SPaul Mackerras * each other. 1689994a338SPaul Mackerras */ 1699994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 1709994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */ 1719994a338SPaul Mackerras addi r5,r7,-1 1729994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 1739994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 1749994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 1759994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ 1769994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 1779994a338SPaul Mackerras beqlr /* nothing to do? */ 1789994a338SPaul Mackerras mtctr r8 1799994a338SPaul Mackerras1: dcbst 0,r6 1809994a338SPaul Mackerras add r6,r6,r7 1819994a338SPaul Mackerras bdnz 1b 1829994a338SPaul Mackerras sync 1839994a338SPaul Mackerras 1849994a338SPaul Mackerras/* Now invalidate the instruction cache */ 1859994a338SPaul Mackerras 1869994a338SPaul Mackerras lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ 1879994a338SPaul Mackerras addi r5,r7,-1 1889994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 1899994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 1909994a338SPaul Mackerras add r8,r8,r5 1919994a338SPaul Mackerras lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ 1929994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 1939994a338SPaul Mackerras beqlr /* nothing to do? */ 1949994a338SPaul Mackerras mtctr r8 1959994a338SPaul Mackerras2: icbi 0,r6 1969994a338SPaul Mackerras add r6,r6,r7 1979994a338SPaul Mackerras bdnz 2b 1989994a338SPaul Mackerras isync 1999994a338SPaul Mackerras blr 2009994a338SPaul Mackerras .previous .text 2019994a338SPaul Mackerras/* 2029994a338SPaul Mackerras * Like above, but only do the D-cache. 2039994a338SPaul Mackerras * 2049994a338SPaul Mackerras * flush_dcache_range(unsigned long start, unsigned long stop) 2059994a338SPaul Mackerras * 2069994a338SPaul Mackerras * flush all bytes from start to stop-1 inclusive 2079994a338SPaul Mackerras */ 2089994a338SPaul Mackerras_GLOBAL(flush_dcache_range) 2099994a338SPaul Mackerras 2109994a338SPaul Mackerras/* 2119994a338SPaul Mackerras * Flush the data cache to memory 2129994a338SPaul Mackerras * 2139994a338SPaul Mackerras * Different systems have different cache line sizes 2149994a338SPaul Mackerras */ 2159994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 2169994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ 2179994a338SPaul Mackerras addi r5,r7,-1 2189994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 2199994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 2209994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 2219994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ 2229994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 2239994a338SPaul Mackerras beqlr /* nothing to do? */ 2249994a338SPaul Mackerras mtctr r8 2259994a338SPaul Mackerras0: dcbst 0,r6 2269994a338SPaul Mackerras add r6,r6,r7 2279994a338SPaul Mackerras bdnz 0b 2289994a338SPaul Mackerras sync 2299994a338SPaul Mackerras blr 2309994a338SPaul Mackerras 2319994a338SPaul Mackerras/* 2329994a338SPaul Mackerras * Like above, but works on non-mapped physical addresses. 2339994a338SPaul Mackerras * Use only for non-LPAR setups ! It also assumes real mode 2349994a338SPaul Mackerras * is cacheable. Used for flushing out the DART before using 2359994a338SPaul Mackerras * it as uncacheable memory 2369994a338SPaul Mackerras * 2379994a338SPaul Mackerras * flush_dcache_phys_range(unsigned long start, unsigned long stop) 2389994a338SPaul Mackerras * 2399994a338SPaul Mackerras * flush all bytes from start to stop-1 inclusive 2409994a338SPaul Mackerras */ 2419994a338SPaul Mackerras_GLOBAL(flush_dcache_phys_range) 2429994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 2439994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ 2449994a338SPaul Mackerras addi r5,r7,-1 2459994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 2469994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 2479994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 2489994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ 2499994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 2509994a338SPaul Mackerras beqlr /* nothing to do? */ 2519994a338SPaul Mackerras mfmsr r5 /* Disable MMU Data Relocation */ 2529994a338SPaul Mackerras ori r0,r5,MSR_DR 2539994a338SPaul Mackerras xori r0,r0,MSR_DR 2549994a338SPaul Mackerras sync 2559994a338SPaul Mackerras mtmsr r0 2569994a338SPaul Mackerras sync 2579994a338SPaul Mackerras isync 2589994a338SPaul Mackerras mtctr r8 2599994a338SPaul Mackerras0: dcbst 0,r6 2609994a338SPaul Mackerras add r6,r6,r7 2619994a338SPaul Mackerras bdnz 0b 2629994a338SPaul Mackerras sync 2639994a338SPaul Mackerras isync 2649994a338SPaul Mackerras mtmsr r5 /* Re-enable MMU Data Relocation */ 2659994a338SPaul Mackerras sync 2669994a338SPaul Mackerras isync 2679994a338SPaul Mackerras blr 2689994a338SPaul Mackerras 2699994a338SPaul Mackerras_GLOBAL(flush_inval_dcache_range) 2709994a338SPaul Mackerras ld r10,PPC64_CACHES@toc(r2) 2719994a338SPaul Mackerras lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ 2729994a338SPaul Mackerras addi r5,r7,-1 2739994a338SPaul Mackerras andc r6,r3,r5 /* round low to line bdy */ 2749994a338SPaul Mackerras subf r8,r6,r4 /* compute length */ 2759994a338SPaul Mackerras add r8,r8,r5 /* ensure we get enough */ 2769994a338SPaul Mackerras lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */ 2779994a338SPaul Mackerras srw. r8,r8,r9 /* compute line count */ 2789994a338SPaul Mackerras beqlr /* nothing to do? */ 2799994a338SPaul Mackerras sync 2809994a338SPaul Mackerras isync 2819994a338SPaul Mackerras mtctr r8 2829994a338SPaul Mackerras0: dcbf 0,r6 2839994a338SPaul Mackerras add r6,r6,r7 2849994a338SPaul Mackerras bdnz 0b 2859994a338SPaul Mackerras sync 2869994a338SPaul Mackerras isync 2879994a338SPaul Mackerras blr 2889994a338SPaul Mackerras 2899994a338SPaul Mackerras 2909994a338SPaul Mackerras/* 2919994a338SPaul Mackerras * Flush a particular page from the data cache to RAM. 2929994a338SPaul Mackerras * Note: this is necessary because the instruction cache does *not* 2939994a338SPaul Mackerras * snoop from the data cache. 2949994a338SPaul Mackerras * 2959994a338SPaul Mackerras * void __flush_dcache_icache(void *page) 2969994a338SPaul Mackerras */ 2979994a338SPaul Mackerras_GLOBAL(__flush_dcache_icache) 2989994a338SPaul Mackerras/* 2999994a338SPaul Mackerras * Flush the data cache to memory 3009994a338SPaul Mackerras * 3019994a338SPaul Mackerras * Different systems have different cache line sizes 3029994a338SPaul Mackerras */ 3039994a338SPaul Mackerras 3049994a338SPaul Mackerras/* Flush the dcache */ 3059994a338SPaul Mackerras ld r7,PPC64_CACHES@toc(r2) 3069994a338SPaul Mackerras clrrdi r3,r3,PAGE_SHIFT /* Page align */ 3079994a338SPaul Mackerras lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ 3089994a338SPaul Mackerras lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ 3099994a338SPaul Mackerras mr r6,r3 3109994a338SPaul Mackerras mtctr r4 3119994a338SPaul Mackerras0: dcbst 0,r6 3129994a338SPaul Mackerras add r6,r6,r5 3139994a338SPaul Mackerras bdnz 0b 3149994a338SPaul Mackerras sync 3159994a338SPaul Mackerras 3169994a338SPaul Mackerras/* Now invalidate the icache */ 3179994a338SPaul Mackerras 3189994a338SPaul Mackerras lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ 3199994a338SPaul Mackerras lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ 3209994a338SPaul Mackerras mtctr r4 3219994a338SPaul Mackerras1: icbi 0,r3 3229994a338SPaul Mackerras add r3,r3,r5 3239994a338SPaul Mackerras bdnz 1b 3249994a338SPaul Mackerras isync 3259994a338SPaul Mackerras blr 3269994a338SPaul Mackerras 3279994a338SPaul Mackerras/* 3289994a338SPaul Mackerras * I/O string operations 3299994a338SPaul Mackerras * 3309994a338SPaul Mackerras * insb(port, buf, len) 3319994a338SPaul Mackerras * outsb(port, buf, len) 3329994a338SPaul Mackerras * insw(port, buf, len) 3339994a338SPaul Mackerras * outsw(port, buf, len) 3349994a338SPaul Mackerras * insl(port, buf, len) 3359994a338SPaul Mackerras * outsl(port, buf, len) 3369994a338SPaul Mackerras * insw_ns(port, buf, len) 3379994a338SPaul Mackerras * outsw_ns(port, buf, len) 3389994a338SPaul Mackerras * insl_ns(port, buf, len) 3399994a338SPaul Mackerras * outsl_ns(port, buf, len) 3409994a338SPaul Mackerras * 3419994a338SPaul Mackerras * The *_ns versions don't do byte-swapping. 3429994a338SPaul Mackerras */ 3439994a338SPaul Mackerras_GLOBAL(_insb) 3449994a338SPaul Mackerras cmpwi 0,r5,0 3459994a338SPaul Mackerras mtctr r5 3469994a338SPaul Mackerras subi r4,r4,1 3479994a338SPaul Mackerras blelr- 3489994a338SPaul Mackerras00: lbz r5,0(r3) 3499994a338SPaul Mackerras eieio 3509994a338SPaul Mackerras stbu r5,1(r4) 3519994a338SPaul Mackerras bdnz 00b 3529994a338SPaul Mackerras twi 0,r5,0 3539994a338SPaul Mackerras isync 3549994a338SPaul Mackerras blr 3559994a338SPaul Mackerras 3569994a338SPaul Mackerras_GLOBAL(_outsb) 3579994a338SPaul Mackerras cmpwi 0,r5,0 3589994a338SPaul Mackerras mtctr r5 3599994a338SPaul Mackerras subi r4,r4,1 3609994a338SPaul Mackerras blelr- 3619994a338SPaul Mackerras00: lbzu r5,1(r4) 3629994a338SPaul Mackerras stb r5,0(r3) 3639994a338SPaul Mackerras bdnz 00b 3649994a338SPaul Mackerras sync 3659994a338SPaul Mackerras blr 3669994a338SPaul Mackerras 3679994a338SPaul Mackerras_GLOBAL(_insw) 3689994a338SPaul Mackerras cmpwi 0,r5,0 3699994a338SPaul Mackerras mtctr r5 3709994a338SPaul Mackerras subi r4,r4,2 3719994a338SPaul Mackerras blelr- 3729994a338SPaul Mackerras00: lhbrx r5,0,r3 3739994a338SPaul Mackerras eieio 3749994a338SPaul Mackerras sthu r5,2(r4) 3759994a338SPaul Mackerras bdnz 00b 3769994a338SPaul Mackerras twi 0,r5,0 3779994a338SPaul Mackerras isync 3789994a338SPaul Mackerras blr 3799994a338SPaul Mackerras 3809994a338SPaul Mackerras_GLOBAL(_outsw) 3819994a338SPaul Mackerras cmpwi 0,r5,0 3829994a338SPaul Mackerras mtctr r5 3839994a338SPaul Mackerras subi r4,r4,2 3849994a338SPaul Mackerras blelr- 3859994a338SPaul Mackerras00: lhzu r5,2(r4) 3869994a338SPaul Mackerras sthbrx r5,0,r3 3879994a338SPaul Mackerras bdnz 00b 3889994a338SPaul Mackerras sync 3899994a338SPaul Mackerras blr 3909994a338SPaul Mackerras 3919994a338SPaul Mackerras_GLOBAL(_insl) 3929994a338SPaul Mackerras cmpwi 0,r5,0 3939994a338SPaul Mackerras mtctr r5 3949994a338SPaul Mackerras subi r4,r4,4 3959994a338SPaul Mackerras blelr- 3969994a338SPaul Mackerras00: lwbrx r5,0,r3 3979994a338SPaul Mackerras eieio 3989994a338SPaul Mackerras stwu r5,4(r4) 3999994a338SPaul Mackerras bdnz 00b 4009994a338SPaul Mackerras twi 0,r5,0 4019994a338SPaul Mackerras isync 4029994a338SPaul Mackerras blr 4039994a338SPaul Mackerras 4049994a338SPaul Mackerras_GLOBAL(_outsl) 4059994a338SPaul Mackerras cmpwi 0,r5,0 4069994a338SPaul Mackerras mtctr r5 4079994a338SPaul Mackerras subi r4,r4,4 4089994a338SPaul Mackerras blelr- 4099994a338SPaul Mackerras00: lwzu r5,4(r4) 4109994a338SPaul Mackerras stwbrx r5,0,r3 4119994a338SPaul Mackerras bdnz 00b 4129994a338SPaul Mackerras sync 4139994a338SPaul Mackerras blr 4149994a338SPaul Mackerras 4159994a338SPaul Mackerras/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */ 4169994a338SPaul Mackerras_GLOBAL(_insw_ns) 4179994a338SPaul Mackerras cmpwi 0,r5,0 4189994a338SPaul Mackerras mtctr r5 4199994a338SPaul Mackerras subi r4,r4,2 4209994a338SPaul Mackerras blelr- 4219994a338SPaul Mackerras00: lhz r5,0(r3) 4229994a338SPaul Mackerras eieio 4239994a338SPaul Mackerras sthu r5,2(r4) 4249994a338SPaul Mackerras bdnz 00b 4259994a338SPaul Mackerras twi 0,r5,0 4269994a338SPaul Mackerras isync 4279994a338SPaul Mackerras blr 4289994a338SPaul Mackerras 4299994a338SPaul Mackerras/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */ 4309994a338SPaul Mackerras_GLOBAL(_outsw_ns) 4319994a338SPaul Mackerras cmpwi 0,r5,0 4329994a338SPaul Mackerras mtctr r5 4339994a338SPaul Mackerras subi r4,r4,2 4349994a338SPaul Mackerras blelr- 4359994a338SPaul Mackerras00: lhzu r5,2(r4) 4369994a338SPaul Mackerras sth r5,0(r3) 4379994a338SPaul Mackerras bdnz 00b 4389994a338SPaul Mackerras sync 4399994a338SPaul Mackerras blr 4409994a338SPaul Mackerras 4419994a338SPaul Mackerras_GLOBAL(_insl_ns) 4429994a338SPaul Mackerras cmpwi 0,r5,0 4439994a338SPaul Mackerras mtctr r5 4449994a338SPaul Mackerras subi r4,r4,4 4459994a338SPaul Mackerras blelr- 4469994a338SPaul Mackerras00: lwz r5,0(r3) 4479994a338SPaul Mackerras eieio 4489994a338SPaul Mackerras stwu r5,4(r4) 4499994a338SPaul Mackerras bdnz 00b 4509994a338SPaul Mackerras twi 0,r5,0 4519994a338SPaul Mackerras isync 4529994a338SPaul Mackerras blr 4539994a338SPaul Mackerras 4549994a338SPaul Mackerras_GLOBAL(_outsl_ns) 4559994a338SPaul Mackerras cmpwi 0,r5,0 4569994a338SPaul Mackerras mtctr r5 4579994a338SPaul Mackerras subi r4,r4,4 4589994a338SPaul Mackerras blelr- 4599994a338SPaul Mackerras00: lwzu r5,4(r4) 4609994a338SPaul Mackerras stw r5,0(r3) 4619994a338SPaul Mackerras bdnz 00b 4629994a338SPaul Mackerras sync 4639994a338SPaul Mackerras blr 4649994a338SPaul Mackerras 4659994a338SPaul Mackerras 4669994a338SPaul Mackerras_GLOBAL(cvt_fd) 4679994a338SPaul Mackerras lfd 0,0(r5) /* load up fpscr value */ 4689994a338SPaul Mackerras mtfsf 0xff,0 4699994a338SPaul Mackerras lfs 0,0(r3) 4709994a338SPaul Mackerras stfd 0,0(r4) 4719994a338SPaul Mackerras mffs 0 /* save new fpscr value */ 4729994a338SPaul Mackerras stfd 0,0(r5) 4739994a338SPaul Mackerras blr 4749994a338SPaul Mackerras 4759994a338SPaul Mackerras_GLOBAL(cvt_df) 4769994a338SPaul Mackerras lfd 0,0(r5) /* load up fpscr value */ 4779994a338SPaul Mackerras mtfsf 0xff,0 4789994a338SPaul Mackerras lfd 0,0(r3) 4799994a338SPaul Mackerras stfs 0,0(r4) 4809994a338SPaul Mackerras mffs 0 /* save new fpscr value */ 4819994a338SPaul Mackerras stfd 0,0(r5) 4829994a338SPaul Mackerras blr 4839994a338SPaul Mackerras 4849994a338SPaul Mackerras/* 4859994a338SPaul Mackerras * identify_cpu and calls setup_cpu 4869994a338SPaul Mackerras * In: r3 = base of the cpu_specs array 4879994a338SPaul Mackerras * r4 = address of cur_cpu_spec 4889994a338SPaul Mackerras * r5 = relocation offset 4899994a338SPaul Mackerras */ 4909994a338SPaul Mackerras_GLOBAL(identify_cpu) 4919994a338SPaul Mackerras mfpvr r7 4929994a338SPaul Mackerras1: 4939994a338SPaul Mackerras lwz r8,CPU_SPEC_PVR_MASK(r3) 4949994a338SPaul Mackerras and r8,r8,r7 4959994a338SPaul Mackerras lwz r9,CPU_SPEC_PVR_VALUE(r3) 4969994a338SPaul Mackerras cmplw 0,r9,r8 4979994a338SPaul Mackerras beq 1f 4989994a338SPaul Mackerras addi r3,r3,CPU_SPEC_ENTRY_SIZE 4999994a338SPaul Mackerras b 1b 5009994a338SPaul Mackerras1: 5019994a338SPaul Mackerras sub r0,r3,r5 5029994a338SPaul Mackerras std r0,0(r4) 5039994a338SPaul Mackerras ld r4,CPU_SPEC_SETUP(r3) 5049994a338SPaul Mackerras add r4,r4,r5 5059994a338SPaul Mackerras ld r4,0(r4) 5069994a338SPaul Mackerras add r4,r4,r5 5079994a338SPaul Mackerras mtctr r4 5089994a338SPaul Mackerras /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ 5099994a338SPaul Mackerras mr r4,r3 5109994a338SPaul Mackerras mr r3,r5 5119994a338SPaul Mackerras bctr 5129994a338SPaul Mackerras 5139994a338SPaul Mackerras/* 5149994a338SPaul Mackerras * do_cpu_ftr_fixups - goes through the list of CPU feature fixups 5159994a338SPaul Mackerras * and writes nop's over sections of code that don't apply for this cpu. 5169994a338SPaul Mackerras * r3 = data offset (not changed) 5179994a338SPaul Mackerras */ 5189994a338SPaul Mackerras_GLOBAL(do_cpu_ftr_fixups) 5199994a338SPaul Mackerras /* Get CPU 0 features */ 5209994a338SPaul Mackerras LOADADDR(r6,cur_cpu_spec) 5219994a338SPaul Mackerras sub r6,r6,r3 5229994a338SPaul Mackerras ld r4,0(r6) 5239994a338SPaul Mackerras sub r4,r4,r3 5249994a338SPaul Mackerras ld r4,CPU_SPEC_FEATURES(r4) 5259994a338SPaul Mackerras /* Get the fixup table */ 5269994a338SPaul Mackerras LOADADDR(r6,__start___ftr_fixup) 5279994a338SPaul Mackerras sub r6,r6,r3 5289994a338SPaul Mackerras LOADADDR(r7,__stop___ftr_fixup) 5299994a338SPaul Mackerras sub r7,r7,r3 5309994a338SPaul Mackerras /* Do the fixup */ 5319994a338SPaul Mackerras1: cmpld r6,r7 5329994a338SPaul Mackerras bgelr 5339994a338SPaul Mackerras addi r6,r6,32 5349994a338SPaul Mackerras ld r8,-32(r6) /* mask */ 5359994a338SPaul Mackerras and r8,r8,r4 5369994a338SPaul Mackerras ld r9,-24(r6) /* value */ 5379994a338SPaul Mackerras cmpld r8,r9 5389994a338SPaul Mackerras beq 1b 5399994a338SPaul Mackerras ld r8,-16(r6) /* section begin */ 5409994a338SPaul Mackerras ld r9,-8(r6) /* section end */ 5419994a338SPaul Mackerras subf. r9,r8,r9 5429994a338SPaul Mackerras beq 1b 5439994a338SPaul Mackerras /* write nops over the section of code */ 5449994a338SPaul Mackerras /* todo: if large section, add a branch at the start of it */ 5459994a338SPaul Mackerras srwi r9,r9,2 5469994a338SPaul Mackerras mtctr r9 5479994a338SPaul Mackerras sub r8,r8,r3 5489994a338SPaul Mackerras lis r0,0x60000000@h /* nop */ 5499994a338SPaul Mackerras3: stw r0,0(r8) 5509994a338SPaul Mackerras andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l 5519994a338SPaul Mackerras beq 2f 5529994a338SPaul Mackerras dcbst 0,r8 /* suboptimal, but simpler */ 5539994a338SPaul Mackerras sync 5549994a338SPaul Mackerras icbi 0,r8 5559994a338SPaul Mackerras2: addi r8,r8,4 5569994a338SPaul Mackerras bdnz 3b 5579994a338SPaul Mackerras sync /* additional sync needed on g4 */ 5589994a338SPaul Mackerras isync 5599994a338SPaul Mackerras b 1b 5609994a338SPaul Mackerras 5619994a338SPaul Mackerras#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) 5629994a338SPaul Mackerras/* 5639994a338SPaul Mackerras * Do an IO access in real mode 5649994a338SPaul Mackerras */ 5659994a338SPaul Mackerras_GLOBAL(real_readb) 5669994a338SPaul Mackerras mfmsr r7 5679994a338SPaul Mackerras ori r0,r7,MSR_DR 5689994a338SPaul Mackerras xori r0,r0,MSR_DR 5699994a338SPaul Mackerras sync 5709994a338SPaul Mackerras mtmsrd r0 5719994a338SPaul Mackerras sync 5729994a338SPaul Mackerras isync 5739994a338SPaul Mackerras mfspr r6,SPRN_HID4 5749994a338SPaul Mackerras rldicl r5,r6,32,0 5759994a338SPaul Mackerras ori r5,r5,0x100 5769994a338SPaul Mackerras rldicl r5,r5,32,0 5779994a338SPaul Mackerras sync 5789994a338SPaul Mackerras mtspr SPRN_HID4,r5 5799994a338SPaul Mackerras isync 5809994a338SPaul Mackerras slbia 5819994a338SPaul Mackerras isync 5829994a338SPaul Mackerras lbz r3,0(r3) 5839994a338SPaul Mackerras sync 5849994a338SPaul Mackerras mtspr SPRN_HID4,r6 5859994a338SPaul Mackerras isync 5869994a338SPaul Mackerras slbia 5879994a338SPaul Mackerras isync 5889994a338SPaul Mackerras mtmsrd r7 5899994a338SPaul Mackerras sync 5909994a338SPaul Mackerras isync 5919994a338SPaul Mackerras blr 5929994a338SPaul Mackerras 5939994a338SPaul Mackerras /* 5949994a338SPaul Mackerras * Do an IO access in real mode 5959994a338SPaul Mackerras */ 5969994a338SPaul Mackerras_GLOBAL(real_writeb) 5979994a338SPaul Mackerras mfmsr r7 5989994a338SPaul Mackerras ori r0,r7,MSR_DR 5999994a338SPaul Mackerras xori r0,r0,MSR_DR 6009994a338SPaul Mackerras sync 6019994a338SPaul Mackerras mtmsrd r0 6029994a338SPaul Mackerras sync 6039994a338SPaul Mackerras isync 6049994a338SPaul Mackerras mfspr r6,SPRN_HID4 6059994a338SPaul Mackerras rldicl r5,r6,32,0 6069994a338SPaul Mackerras ori r5,r5,0x100 6079994a338SPaul Mackerras rldicl r5,r5,32,0 6089994a338SPaul Mackerras sync 6099994a338SPaul Mackerras mtspr SPRN_HID4,r5 6109994a338SPaul Mackerras isync 6119994a338SPaul Mackerras slbia 6129994a338SPaul Mackerras isync 6139994a338SPaul Mackerras stb r3,0(r4) 6149994a338SPaul Mackerras sync 6159994a338SPaul Mackerras mtspr SPRN_HID4,r6 6169994a338SPaul Mackerras isync 6179994a338SPaul Mackerras slbia 6189994a338SPaul Mackerras isync 6199994a338SPaul Mackerras mtmsrd r7 6209994a338SPaul Mackerras sync 6219994a338SPaul Mackerras isync 6229994a338SPaul Mackerras blr 6239994a338SPaul Mackerras#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ 6249994a338SPaul Mackerras 6259994a338SPaul Mackerras/* 6269994a338SPaul Mackerras * Create a kernel thread 6279994a338SPaul Mackerras * kernel_thread(fn, arg, flags) 6289994a338SPaul Mackerras */ 6299994a338SPaul Mackerras_GLOBAL(kernel_thread) 6309994a338SPaul Mackerras std r29,-24(r1) 6319994a338SPaul Mackerras std r30,-16(r1) 6329994a338SPaul Mackerras stdu r1,-STACK_FRAME_OVERHEAD(r1) 6339994a338SPaul Mackerras mr r29,r3 6349994a338SPaul Mackerras mr r30,r4 6359994a338SPaul Mackerras ori r3,r5,CLONE_VM /* flags */ 6369994a338SPaul Mackerras oris r3,r3,(CLONE_UNTRACED>>16) 6379994a338SPaul Mackerras li r4,0 /* new sp (unused) */ 6389994a338SPaul Mackerras li r0,__NR_clone 6399994a338SPaul Mackerras sc 6409994a338SPaul Mackerras cmpdi 0,r3,0 /* parent or child? */ 6419994a338SPaul Mackerras bne 1f /* return if parent */ 6429994a338SPaul Mackerras li r0,0 6439994a338SPaul Mackerras stdu r0,-STACK_FRAME_OVERHEAD(r1) 6449994a338SPaul Mackerras ld r2,8(r29) 6459994a338SPaul Mackerras ld r29,0(r29) 6469994a338SPaul Mackerras mtlr r29 /* fn addr in lr */ 6479994a338SPaul Mackerras mr r3,r30 /* load arg and call fn */ 6489994a338SPaul Mackerras blrl 6499994a338SPaul Mackerras li r0,__NR_exit /* exit after child exits */ 6509994a338SPaul Mackerras li r3,0 6519994a338SPaul Mackerras sc 6529994a338SPaul Mackerras1: addi r1,r1,STACK_FRAME_OVERHEAD 6539994a338SPaul Mackerras ld r29,-24(r1) 6549994a338SPaul Mackerras ld r30,-16(r1) 6559994a338SPaul Mackerras blr 6569994a338SPaul Mackerras 6579994a338SPaul Mackerras/* 6589994a338SPaul Mackerras * disable_kernel_fp() 6599994a338SPaul Mackerras * Disable the FPU. 6609994a338SPaul Mackerras */ 6619994a338SPaul Mackerras_GLOBAL(disable_kernel_fp) 6629994a338SPaul Mackerras mfmsr r3 6639994a338SPaul Mackerras rldicl r0,r3,(63-MSR_FP_LG),1 6649994a338SPaul Mackerras rldicl r3,r0,(MSR_FP_LG+1),0 6659994a338SPaul Mackerras mtmsrd r3 /* disable use of fpu now */ 6669994a338SPaul Mackerras isync 6679994a338SPaul Mackerras blr 6689994a338SPaul Mackerras 6699994a338SPaul Mackerras#ifdef CONFIG_ALTIVEC 6709994a338SPaul Mackerras 6719994a338SPaul Mackerras#if 0 /* this has no callers for now */ 6729994a338SPaul Mackerras/* 6739994a338SPaul Mackerras * disable_kernel_altivec() 6749994a338SPaul Mackerras * Disable the VMX. 6759994a338SPaul Mackerras */ 6769994a338SPaul Mackerras_GLOBAL(disable_kernel_altivec) 6779994a338SPaul Mackerras mfmsr r3 6789994a338SPaul Mackerras rldicl r0,r3,(63-MSR_VEC_LG),1 6799994a338SPaul Mackerras rldicl r3,r0,(MSR_VEC_LG+1),0 6809994a338SPaul Mackerras mtmsrd r3 /* disable use of VMX now */ 6819994a338SPaul Mackerras isync 6829994a338SPaul Mackerras blr 6839994a338SPaul Mackerras#endif /* 0 */ 6849994a338SPaul Mackerras 6859994a338SPaul Mackerras/* 6869994a338SPaul Mackerras * giveup_altivec(tsk) 6879994a338SPaul Mackerras * Disable VMX for the task given as the argument, 6889994a338SPaul Mackerras * and save the vector registers in its thread_struct. 6899994a338SPaul Mackerras * Enables the VMX for use in the kernel on return. 6909994a338SPaul Mackerras */ 6919994a338SPaul Mackerras_GLOBAL(giveup_altivec) 6929994a338SPaul Mackerras mfmsr r5 6939994a338SPaul Mackerras oris r5,r5,MSR_VEC@h 6949994a338SPaul Mackerras mtmsrd r5 /* enable use of VMX now */ 6959994a338SPaul Mackerras isync 6969994a338SPaul Mackerras cmpdi 0,r3,0 6979994a338SPaul Mackerras beqlr- /* if no previous owner, done */ 6989994a338SPaul Mackerras addi r3,r3,THREAD /* want THREAD of task */ 6999994a338SPaul Mackerras ld r5,PT_REGS(r3) 7009994a338SPaul Mackerras cmpdi 0,r5,0 7019994a338SPaul Mackerras SAVE_32VRS(0,r4,r3) 7029994a338SPaul Mackerras mfvscr vr0 7039994a338SPaul Mackerras li r4,THREAD_VSCR 7049994a338SPaul Mackerras stvx vr0,r4,r3 7059994a338SPaul Mackerras beq 1f 7069994a338SPaul Mackerras ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 7079994a338SPaul Mackerras lis r3,MSR_VEC@h 7089994a338SPaul Mackerras andc r4,r4,r3 /* disable FP for previous task */ 7099994a338SPaul Mackerras std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 7109994a338SPaul Mackerras1: 7119994a338SPaul Mackerras#ifndef CONFIG_SMP 7129994a338SPaul Mackerras li r5,0 7139994a338SPaul Mackerras ld r4,last_task_used_altivec@got(r2) 7149994a338SPaul Mackerras std r5,0(r4) 7159994a338SPaul Mackerras#endif /* CONFIG_SMP */ 7169994a338SPaul Mackerras blr 7179994a338SPaul Mackerras 7189994a338SPaul Mackerras#endif /* CONFIG_ALTIVEC */ 7199994a338SPaul Mackerras 7209994a338SPaul Mackerras_GLOBAL(__setup_cpu_power3) 7219994a338SPaul Mackerras blr 7229994a338SPaul Mackerras 7239994a338SPaul Mackerras_GLOBAL(execve) 7249994a338SPaul Mackerras li r0,__NR_execve 7259994a338SPaul Mackerras sc 7269994a338SPaul Mackerras bnslr 7279994a338SPaul Mackerras neg r3,r3 7289994a338SPaul Mackerras blr 7299994a338SPaul Mackerras 7309994a338SPaul Mackerras/* kexec_wait(phys_cpu) 7319994a338SPaul Mackerras * 7329994a338SPaul Mackerras * wait for the flag to change, indicating this kernel is going away but 7339994a338SPaul Mackerras * the slave code for the next one is at addresses 0 to 100. 7349994a338SPaul Mackerras * 7359994a338SPaul Mackerras * This is used by all slaves. 7369994a338SPaul Mackerras * 7379994a338SPaul Mackerras * Physical (hardware) cpu id should be in r3. 7389994a338SPaul Mackerras */ 7399994a338SPaul Mackerras_GLOBAL(kexec_wait) 7409994a338SPaul Mackerras bl 1f 7419994a338SPaul Mackerras1: mflr r5 7429994a338SPaul Mackerras addi r5,r5,kexec_flag-1b 7439994a338SPaul Mackerras 7449994a338SPaul Mackerras99: HMT_LOW 7459994a338SPaul Mackerras#ifdef CONFIG_KEXEC /* use no memory without kexec */ 7469994a338SPaul Mackerras lwz r4,0(r5) 7479994a338SPaul Mackerras cmpwi 0,r4,0 7489994a338SPaul Mackerras bnea 0x60 7499994a338SPaul Mackerras#endif 7509994a338SPaul Mackerras b 99b 7519994a338SPaul Mackerras 7529994a338SPaul Mackerras/* this can be in text because we won't change it until we are 7539994a338SPaul Mackerras * running in real anyways 7549994a338SPaul Mackerras */ 7559994a338SPaul Mackerraskexec_flag: 7569994a338SPaul Mackerras .long 0 7579994a338SPaul Mackerras 7589994a338SPaul Mackerras 7599994a338SPaul Mackerras#ifdef CONFIG_KEXEC 7609994a338SPaul Mackerras 7619994a338SPaul Mackerras/* kexec_smp_wait(void) 7629994a338SPaul Mackerras * 7639994a338SPaul Mackerras * call with interrupts off 7649994a338SPaul Mackerras * note: this is a terminal routine, it does not save lr 7659994a338SPaul Mackerras * 7669994a338SPaul Mackerras * get phys id from paca 7679994a338SPaul Mackerras * set paca id to -1 to say we got here 7689994a338SPaul Mackerras * switch to real mode 7699994a338SPaul Mackerras * join other cpus in kexec_wait(phys_id) 7709994a338SPaul Mackerras */ 7719994a338SPaul Mackerras_GLOBAL(kexec_smp_wait) 7729994a338SPaul Mackerras lhz r3,PACAHWCPUID(r13) 7739994a338SPaul Mackerras li r4,-1 7749994a338SPaul Mackerras sth r4,PACAHWCPUID(r13) /* let others know we left */ 7759994a338SPaul Mackerras bl real_mode 7769994a338SPaul Mackerras b .kexec_wait 7779994a338SPaul Mackerras 7789994a338SPaul Mackerras/* 7799994a338SPaul Mackerras * switch to real mode (turn mmu off) 7809994a338SPaul Mackerras * we use the early kernel trick that the hardware ignores bits 7819994a338SPaul Mackerras * 0 and 1 (big endian) of the effective address in real mode 7829994a338SPaul Mackerras * 7839994a338SPaul Mackerras * don't overwrite r3 here, it is live for kexec_wait above. 7849994a338SPaul Mackerras */ 7859994a338SPaul Mackerrasreal_mode: /* assume normal blr return */ 7869994a338SPaul Mackerras1: li r9,MSR_RI 7879994a338SPaul Mackerras li r10,MSR_DR|MSR_IR 7889994a338SPaul Mackerras mflr r11 /* return address to SRR0 */ 7899994a338SPaul Mackerras mfmsr r12 7909994a338SPaul Mackerras andc r9,r12,r9 7919994a338SPaul Mackerras andc r10,r12,r10 7929994a338SPaul Mackerras 7939994a338SPaul Mackerras mtmsrd r9,1 7949994a338SPaul Mackerras mtspr SPRN_SRR1,r10 7959994a338SPaul Mackerras mtspr SPRN_SRR0,r11 7969994a338SPaul Mackerras rfid 7979994a338SPaul Mackerras 7989994a338SPaul Mackerras 7999994a338SPaul Mackerras/* 8009994a338SPaul Mackerras * kexec_sequence(newstack, start, image, control, clear_all()) 8019994a338SPaul Mackerras * 8029994a338SPaul Mackerras * does the grungy work with stack switching and real mode switches 8039994a338SPaul Mackerras * also does simple calls to other code 8049994a338SPaul Mackerras */ 8059994a338SPaul Mackerras 8069994a338SPaul Mackerras_GLOBAL(kexec_sequence) 8079994a338SPaul Mackerras mflr r0 8089994a338SPaul Mackerras std r0,16(r1) 8099994a338SPaul Mackerras 8109994a338SPaul Mackerras /* switch stacks to newstack -- &kexec_stack.stack */ 8119994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r3) 8129994a338SPaul Mackerras mr r1,r3 8139994a338SPaul Mackerras 8149994a338SPaul Mackerras li r0,0 8159994a338SPaul Mackerras std r0,16(r1) 8169994a338SPaul Mackerras 8179994a338SPaul Mackerras /* save regs for local vars on new stack. 8189994a338SPaul Mackerras * yes, we won't go back, but ... 8199994a338SPaul Mackerras */ 8209994a338SPaul Mackerras std r31,-8(r1) 8219994a338SPaul Mackerras std r30,-16(r1) 8229994a338SPaul Mackerras std r29,-24(r1) 8239994a338SPaul Mackerras std r28,-32(r1) 8249994a338SPaul Mackerras std r27,-40(r1) 8259994a338SPaul Mackerras std r26,-48(r1) 8269994a338SPaul Mackerras std r25,-56(r1) 8279994a338SPaul Mackerras 8289994a338SPaul Mackerras stdu r1,-112-64(r1) 8299994a338SPaul Mackerras 8309994a338SPaul Mackerras /* save args into preserved regs */ 8319994a338SPaul Mackerras mr r31,r3 /* newstack (both) */ 8329994a338SPaul Mackerras mr r30,r4 /* start (real) */ 8339994a338SPaul Mackerras mr r29,r5 /* image (virt) */ 8349994a338SPaul Mackerras mr r28,r6 /* control, unused */ 8359994a338SPaul Mackerras mr r27,r7 /* clear_all() fn desc */ 8369994a338SPaul Mackerras mr r26,r8 /* spare */ 8379994a338SPaul Mackerras lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ 8389994a338SPaul Mackerras 8399994a338SPaul Mackerras /* disable interrupts, we are overwriting kernel data next */ 8409994a338SPaul Mackerras mfmsr r3 8419994a338SPaul Mackerras rlwinm r3,r3,0,17,15 8429994a338SPaul Mackerras mtmsrd r3,1 8439994a338SPaul Mackerras 8449994a338SPaul Mackerras /* copy dest pages, flush whole dest image */ 8459994a338SPaul Mackerras mr r3,r29 8469994a338SPaul Mackerras bl .kexec_copy_flush /* (image) */ 8479994a338SPaul Mackerras 8489994a338SPaul Mackerras /* turn off mmu */ 8499994a338SPaul Mackerras bl real_mode 8509994a338SPaul Mackerras 8519994a338SPaul Mackerras /* clear out hardware hash page table and tlb */ 8529994a338SPaul Mackerras ld r5,0(r27) /* deref function descriptor */ 8539994a338SPaul Mackerras mtctr r5 8549994a338SPaul Mackerras bctrl /* ppc_md.hash_clear_all(void); */ 8559994a338SPaul Mackerras 8569994a338SPaul Mackerras/* 8579994a338SPaul Mackerras * kexec image calling is: 8589994a338SPaul Mackerras * the first 0x100 bytes of the entry point are copied to 0 8599994a338SPaul Mackerras * 8609994a338SPaul Mackerras * all slaves branch to slave = 0x60 (absolute) 8619994a338SPaul Mackerras * slave(phys_cpu_id); 8629994a338SPaul Mackerras * 8639994a338SPaul Mackerras * master goes to start = entry point 8649994a338SPaul Mackerras * start(phys_cpu_id, start, 0); 8659994a338SPaul Mackerras * 8669994a338SPaul Mackerras * 8679994a338SPaul Mackerras * a wrapper is needed to call existing kernels, here is an approximate 8689994a338SPaul Mackerras * description of one method: 8699994a338SPaul Mackerras * 8709994a338SPaul Mackerras * v2: (2.6.10) 8719994a338SPaul Mackerras * start will be near the boot_block (maybe 0x100 bytes before it?) 8729994a338SPaul Mackerras * it will have a 0x60, which will b to boot_block, where it will wait 8739994a338SPaul Mackerras * and 0 will store phys into struct boot-block and load r3 from there, 8749994a338SPaul Mackerras * copy kernel 0-0x100 and tell slaves to back down to 0x60 again 8759994a338SPaul Mackerras * 8769994a338SPaul Mackerras * v1: (2.6.9) 8779994a338SPaul Mackerras * boot block will have all cpus scanning device tree to see if they 8789994a338SPaul Mackerras * are the boot cpu ????? 8799994a338SPaul Mackerras * other device tree differences (prop sizes, va vs pa, etc)... 8809994a338SPaul Mackerras */ 8819994a338SPaul Mackerras 8829994a338SPaul Mackerras /* copy 0x100 bytes starting at start to 0 */ 8839994a338SPaul Mackerras li r3,0 8849994a338SPaul Mackerras mr r4,r30 8859994a338SPaul Mackerras li r5,0x100 8869994a338SPaul Mackerras li r6,0 8879994a338SPaul Mackerras bl .copy_and_flush /* (dest, src, copy limit, start offset) */ 8889994a338SPaul Mackerras1: /* assume normal blr return */ 8899994a338SPaul Mackerras 8909994a338SPaul Mackerras /* release other cpus to the new kernel secondary start at 0x60 */ 8919994a338SPaul Mackerras mflr r5 8929994a338SPaul Mackerras li r6,1 8939994a338SPaul Mackerras stw r6,kexec_flag-1b(5) 8949994a338SPaul Mackerras mr r3,r25 # my phys cpu 8959994a338SPaul Mackerras mr r4,r30 # start, aka phys mem offset 8969994a338SPaul Mackerras mtlr 4 8979994a338SPaul Mackerras li r5,0 8989994a338SPaul Mackerras blr /* image->start(physid, image->start, 0); */ 8999994a338SPaul Mackerras#endif /* CONFIG_KEXEC */ 900