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> 296cb7bfebSDavid 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 * identify_cpu and calls setup_cpu 4679994a338SPaul Mackerras * In: r3 = base of the cpu_specs array 4689994a338SPaul Mackerras * r4 = address of cur_cpu_spec 4699994a338SPaul Mackerras * r5 = relocation offset 4709994a338SPaul Mackerras */ 4719994a338SPaul Mackerras_GLOBAL(identify_cpu) 4729994a338SPaul Mackerras mfpvr r7 4739994a338SPaul Mackerras1: 4749994a338SPaul Mackerras lwz r8,CPU_SPEC_PVR_MASK(r3) 4759994a338SPaul Mackerras and r8,r8,r7 4769994a338SPaul Mackerras lwz r9,CPU_SPEC_PVR_VALUE(r3) 4779994a338SPaul Mackerras cmplw 0,r9,r8 4789994a338SPaul Mackerras beq 1f 4799994a338SPaul Mackerras addi r3,r3,CPU_SPEC_ENTRY_SIZE 4809994a338SPaul Mackerras b 1b 4819994a338SPaul Mackerras1: 4829994a338SPaul Mackerras sub r0,r3,r5 4839994a338SPaul Mackerras std r0,0(r4) 4849994a338SPaul Mackerras ld r4,CPU_SPEC_SETUP(r3) 4859994a338SPaul Mackerras add r4,r4,r5 4869994a338SPaul Mackerras ld r4,0(r4) 4879994a338SPaul Mackerras add r4,r4,r5 4889994a338SPaul Mackerras mtctr r4 4899994a338SPaul Mackerras /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ 4909994a338SPaul Mackerras mr r4,r3 4919994a338SPaul Mackerras mr r3,r5 4929994a338SPaul Mackerras bctr 4939994a338SPaul Mackerras 4949994a338SPaul Mackerras/* 4959994a338SPaul Mackerras * do_cpu_ftr_fixups - goes through the list of CPU feature fixups 4969994a338SPaul Mackerras * and writes nop's over sections of code that don't apply for this cpu. 4979994a338SPaul Mackerras * r3 = data offset (not changed) 4989994a338SPaul Mackerras */ 4999994a338SPaul Mackerras_GLOBAL(do_cpu_ftr_fixups) 5009994a338SPaul Mackerras /* Get CPU 0 features */ 5019994a338SPaul Mackerras LOADADDR(r6,cur_cpu_spec) 5029994a338SPaul Mackerras sub r6,r6,r3 5039994a338SPaul Mackerras ld r4,0(r6) 5049994a338SPaul Mackerras sub r4,r4,r3 5059994a338SPaul Mackerras ld r4,CPU_SPEC_FEATURES(r4) 5069994a338SPaul Mackerras /* Get the fixup table */ 5079994a338SPaul Mackerras LOADADDR(r6,__start___ftr_fixup) 5089994a338SPaul Mackerras sub r6,r6,r3 5099994a338SPaul Mackerras LOADADDR(r7,__stop___ftr_fixup) 5109994a338SPaul Mackerras sub r7,r7,r3 5119994a338SPaul Mackerras /* Do the fixup */ 5129994a338SPaul Mackerras1: cmpld r6,r7 5139994a338SPaul Mackerras bgelr 5149994a338SPaul Mackerras addi r6,r6,32 5159994a338SPaul Mackerras ld r8,-32(r6) /* mask */ 5169994a338SPaul Mackerras and r8,r8,r4 5179994a338SPaul Mackerras ld r9,-24(r6) /* value */ 5189994a338SPaul Mackerras cmpld r8,r9 5199994a338SPaul Mackerras beq 1b 5209994a338SPaul Mackerras ld r8,-16(r6) /* section begin */ 5219994a338SPaul Mackerras ld r9,-8(r6) /* section end */ 5229994a338SPaul Mackerras subf. r9,r8,r9 5239994a338SPaul Mackerras beq 1b 5249994a338SPaul Mackerras /* write nops over the section of code */ 5259994a338SPaul Mackerras /* todo: if large section, add a branch at the start of it */ 5269994a338SPaul Mackerras srwi r9,r9,2 5279994a338SPaul Mackerras mtctr r9 5289994a338SPaul Mackerras sub r8,r8,r3 5299994a338SPaul Mackerras lis r0,0x60000000@h /* nop */ 5309994a338SPaul Mackerras3: stw r0,0(r8) 5319994a338SPaul Mackerras andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l 5329994a338SPaul Mackerras beq 2f 5339994a338SPaul Mackerras dcbst 0,r8 /* suboptimal, but simpler */ 5349994a338SPaul Mackerras sync 5359994a338SPaul Mackerras icbi 0,r8 5369994a338SPaul Mackerras2: addi r8,r8,4 5379994a338SPaul Mackerras bdnz 3b 5389994a338SPaul Mackerras sync /* additional sync needed on g4 */ 5399994a338SPaul Mackerras isync 5409994a338SPaul Mackerras b 1b 5419994a338SPaul Mackerras 5429994a338SPaul Mackerras#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) 5439994a338SPaul Mackerras/* 5449994a338SPaul Mackerras * Do an IO access in real mode 5459994a338SPaul Mackerras */ 5469994a338SPaul Mackerras_GLOBAL(real_readb) 5479994a338SPaul Mackerras mfmsr r7 5489994a338SPaul Mackerras ori r0,r7,MSR_DR 5499994a338SPaul Mackerras xori r0,r0,MSR_DR 5509994a338SPaul Mackerras sync 5519994a338SPaul Mackerras mtmsrd r0 5529994a338SPaul Mackerras sync 5539994a338SPaul Mackerras isync 5549994a338SPaul Mackerras mfspr r6,SPRN_HID4 5559994a338SPaul Mackerras rldicl r5,r6,32,0 5569994a338SPaul Mackerras ori r5,r5,0x100 5579994a338SPaul Mackerras rldicl r5,r5,32,0 5589994a338SPaul Mackerras sync 5599994a338SPaul Mackerras mtspr SPRN_HID4,r5 5609994a338SPaul Mackerras isync 5619994a338SPaul Mackerras slbia 5629994a338SPaul Mackerras isync 5639994a338SPaul Mackerras lbz r3,0(r3) 5649994a338SPaul Mackerras sync 5659994a338SPaul Mackerras mtspr SPRN_HID4,r6 5669994a338SPaul Mackerras isync 5679994a338SPaul Mackerras slbia 5689994a338SPaul Mackerras isync 5699994a338SPaul Mackerras mtmsrd r7 5709994a338SPaul Mackerras sync 5719994a338SPaul Mackerras isync 5729994a338SPaul Mackerras blr 5739994a338SPaul Mackerras 5749994a338SPaul Mackerras /* 5759994a338SPaul Mackerras * Do an IO access in real mode 5769994a338SPaul Mackerras */ 5779994a338SPaul Mackerras_GLOBAL(real_writeb) 5789994a338SPaul Mackerras mfmsr r7 5799994a338SPaul Mackerras ori r0,r7,MSR_DR 5809994a338SPaul Mackerras xori r0,r0,MSR_DR 5819994a338SPaul Mackerras sync 5829994a338SPaul Mackerras mtmsrd r0 5839994a338SPaul Mackerras sync 5849994a338SPaul Mackerras isync 5859994a338SPaul Mackerras mfspr r6,SPRN_HID4 5869994a338SPaul Mackerras rldicl r5,r6,32,0 5879994a338SPaul Mackerras ori r5,r5,0x100 5889994a338SPaul Mackerras rldicl r5,r5,32,0 5899994a338SPaul Mackerras sync 5909994a338SPaul Mackerras mtspr SPRN_HID4,r5 5919994a338SPaul Mackerras isync 5929994a338SPaul Mackerras slbia 5939994a338SPaul Mackerras isync 5949994a338SPaul Mackerras stb r3,0(r4) 5959994a338SPaul Mackerras sync 5969994a338SPaul Mackerras mtspr SPRN_HID4,r6 5979994a338SPaul Mackerras isync 5989994a338SPaul Mackerras slbia 5999994a338SPaul Mackerras isync 6009994a338SPaul Mackerras mtmsrd r7 6019994a338SPaul Mackerras sync 6029994a338SPaul Mackerras isync 6039994a338SPaul Mackerras blr 6049994a338SPaul Mackerras#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ 6059994a338SPaul Mackerras 6069994a338SPaul Mackerras/* 607*4350147aSBenjamin Herrenschmidt * SCOM access functions for 970 (FX only for now) 608*4350147aSBenjamin Herrenschmidt * 609*4350147aSBenjamin Herrenschmidt * unsigned long scom970_read(unsigned int address); 610*4350147aSBenjamin Herrenschmidt * void scom970_write(unsigned int address, unsigned long value); 611*4350147aSBenjamin Herrenschmidt * 612*4350147aSBenjamin Herrenschmidt * The address passed in is the 24 bits register address. This code 613*4350147aSBenjamin Herrenschmidt * is 970 specific and will not check the status bits, so you should 614*4350147aSBenjamin Herrenschmidt * know what you are doing. 615*4350147aSBenjamin Herrenschmidt */ 616*4350147aSBenjamin Herrenschmidt_GLOBAL(scom970_read) 617*4350147aSBenjamin Herrenschmidt /* interrupts off */ 618*4350147aSBenjamin Herrenschmidt mfmsr r4 619*4350147aSBenjamin Herrenschmidt ori r0,r4,MSR_EE 620*4350147aSBenjamin Herrenschmidt xori r0,r0,MSR_EE 621*4350147aSBenjamin Herrenschmidt mtmsrd r0,1 622*4350147aSBenjamin Herrenschmidt 623*4350147aSBenjamin Herrenschmidt /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits 624*4350147aSBenjamin Herrenschmidt * (including parity). On current CPUs they must be 0'd, 625*4350147aSBenjamin Herrenschmidt * and finally or in RW bit 626*4350147aSBenjamin Herrenschmidt */ 627*4350147aSBenjamin Herrenschmidt rlwinm r3,r3,8,0,15 628*4350147aSBenjamin Herrenschmidt ori r3,r3,0x8000 629*4350147aSBenjamin Herrenschmidt 630*4350147aSBenjamin Herrenschmidt /* do the actual scom read */ 631*4350147aSBenjamin Herrenschmidt sync 632*4350147aSBenjamin Herrenschmidt mtspr SPRN_SCOMC,r3 633*4350147aSBenjamin Herrenschmidt isync 634*4350147aSBenjamin Herrenschmidt mfspr r3,SPRN_SCOMD 635*4350147aSBenjamin Herrenschmidt isync 636*4350147aSBenjamin Herrenschmidt mfspr r0,SPRN_SCOMC 637*4350147aSBenjamin Herrenschmidt isync 638*4350147aSBenjamin Herrenschmidt 639*4350147aSBenjamin Herrenschmidt /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah 640*4350147aSBenjamin Herrenschmidt * that's the best we can do). Not implemented yet as we don't use 641*4350147aSBenjamin Herrenschmidt * the scom on any of the bogus CPUs yet, but may have to be done 642*4350147aSBenjamin Herrenschmidt * ultimately 643*4350147aSBenjamin Herrenschmidt */ 644*4350147aSBenjamin Herrenschmidt 645*4350147aSBenjamin Herrenschmidt /* restore interrupts */ 646*4350147aSBenjamin Herrenschmidt mtmsrd r4,1 647*4350147aSBenjamin Herrenschmidt blr 648*4350147aSBenjamin Herrenschmidt 649*4350147aSBenjamin Herrenschmidt 650*4350147aSBenjamin Herrenschmidt_GLOBAL(scom970_write) 651*4350147aSBenjamin Herrenschmidt /* interrupts off */ 652*4350147aSBenjamin Herrenschmidt mfmsr r5 653*4350147aSBenjamin Herrenschmidt ori r0,r5,MSR_EE 654*4350147aSBenjamin Herrenschmidt xori r0,r0,MSR_EE 655*4350147aSBenjamin Herrenschmidt mtmsrd r0,1 656*4350147aSBenjamin Herrenschmidt 657*4350147aSBenjamin Herrenschmidt /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits 658*4350147aSBenjamin Herrenschmidt * (including parity). On current CPUs they must be 0'd. 659*4350147aSBenjamin Herrenschmidt */ 660*4350147aSBenjamin Herrenschmidt 661*4350147aSBenjamin Herrenschmidt rlwinm r3,r3,8,0,15 662*4350147aSBenjamin Herrenschmidt 663*4350147aSBenjamin Herrenschmidt sync 664*4350147aSBenjamin Herrenschmidt mtspr SPRN_SCOMD,r4 /* write data */ 665*4350147aSBenjamin Herrenschmidt isync 666*4350147aSBenjamin Herrenschmidt mtspr SPRN_SCOMC,r3 /* write command */ 667*4350147aSBenjamin Herrenschmidt isync 668*4350147aSBenjamin Herrenschmidt mfspr 3,SPRN_SCOMC 669*4350147aSBenjamin Herrenschmidt isync 670*4350147aSBenjamin Herrenschmidt 671*4350147aSBenjamin Herrenschmidt /* restore interrupts */ 672*4350147aSBenjamin Herrenschmidt mtmsrd r5,1 673*4350147aSBenjamin Herrenschmidt blr 674*4350147aSBenjamin Herrenschmidt 675*4350147aSBenjamin Herrenschmidt 676*4350147aSBenjamin Herrenschmidt/* 6779994a338SPaul Mackerras * Create a kernel thread 6789994a338SPaul Mackerras * kernel_thread(fn, arg, flags) 6799994a338SPaul Mackerras */ 6809994a338SPaul Mackerras_GLOBAL(kernel_thread) 6819994a338SPaul Mackerras std r29,-24(r1) 6829994a338SPaul Mackerras std r30,-16(r1) 6839994a338SPaul Mackerras stdu r1,-STACK_FRAME_OVERHEAD(r1) 6849994a338SPaul Mackerras mr r29,r3 6859994a338SPaul Mackerras mr r30,r4 6869994a338SPaul Mackerras ori r3,r5,CLONE_VM /* flags */ 6879994a338SPaul Mackerras oris r3,r3,(CLONE_UNTRACED>>16) 6889994a338SPaul Mackerras li r4,0 /* new sp (unused) */ 6899994a338SPaul Mackerras li r0,__NR_clone 6909994a338SPaul Mackerras sc 6919994a338SPaul Mackerras cmpdi 0,r3,0 /* parent or child? */ 6929994a338SPaul Mackerras bne 1f /* return if parent */ 6939994a338SPaul Mackerras li r0,0 6949994a338SPaul Mackerras stdu r0,-STACK_FRAME_OVERHEAD(r1) 6959994a338SPaul Mackerras ld r2,8(r29) 6969994a338SPaul Mackerras ld r29,0(r29) 6979994a338SPaul Mackerras mtlr r29 /* fn addr in lr */ 6989994a338SPaul Mackerras mr r3,r30 /* load arg and call fn */ 6999994a338SPaul Mackerras blrl 7009994a338SPaul Mackerras li r0,__NR_exit /* exit after child exits */ 7019994a338SPaul Mackerras li r3,0 7029994a338SPaul Mackerras sc 7039994a338SPaul Mackerras1: addi r1,r1,STACK_FRAME_OVERHEAD 7049994a338SPaul Mackerras ld r29,-24(r1) 7059994a338SPaul Mackerras ld r30,-16(r1) 7069994a338SPaul Mackerras blr 7079994a338SPaul Mackerras 7089994a338SPaul Mackerras/* 7099994a338SPaul Mackerras * disable_kernel_fp() 7109994a338SPaul Mackerras * Disable the FPU. 7119994a338SPaul Mackerras */ 7129994a338SPaul Mackerras_GLOBAL(disable_kernel_fp) 7139994a338SPaul Mackerras mfmsr r3 7149994a338SPaul Mackerras rldicl r0,r3,(63-MSR_FP_LG),1 7159994a338SPaul Mackerras rldicl r3,r0,(MSR_FP_LG+1),0 7169994a338SPaul Mackerras mtmsrd r3 /* disable use of fpu now */ 7179994a338SPaul Mackerras isync 7189994a338SPaul Mackerras blr 7199994a338SPaul Mackerras 7209994a338SPaul Mackerras#ifdef CONFIG_ALTIVEC 7219994a338SPaul Mackerras 7229994a338SPaul Mackerras#if 0 /* this has no callers for now */ 7239994a338SPaul Mackerras/* 7249994a338SPaul Mackerras * disable_kernel_altivec() 7259994a338SPaul Mackerras * Disable the VMX. 7269994a338SPaul Mackerras */ 7279994a338SPaul Mackerras_GLOBAL(disable_kernel_altivec) 7289994a338SPaul Mackerras mfmsr r3 7299994a338SPaul Mackerras rldicl r0,r3,(63-MSR_VEC_LG),1 7309994a338SPaul Mackerras rldicl r3,r0,(MSR_VEC_LG+1),0 7319994a338SPaul Mackerras mtmsrd r3 /* disable use of VMX now */ 7329994a338SPaul Mackerras isync 7339994a338SPaul Mackerras blr 7349994a338SPaul Mackerras#endif /* 0 */ 7359994a338SPaul Mackerras 7369994a338SPaul Mackerras/* 7379994a338SPaul Mackerras * giveup_altivec(tsk) 7389994a338SPaul Mackerras * Disable VMX for the task given as the argument, 7399994a338SPaul Mackerras * and save the vector registers in its thread_struct. 7409994a338SPaul Mackerras * Enables the VMX for use in the kernel on return. 7419994a338SPaul Mackerras */ 7429994a338SPaul Mackerras_GLOBAL(giveup_altivec) 7439994a338SPaul Mackerras mfmsr r5 7449994a338SPaul Mackerras oris r5,r5,MSR_VEC@h 7459994a338SPaul Mackerras mtmsrd r5 /* enable use of VMX now */ 7469994a338SPaul Mackerras isync 7479994a338SPaul Mackerras cmpdi 0,r3,0 7489994a338SPaul Mackerras beqlr- /* if no previous owner, done */ 7499994a338SPaul Mackerras addi r3,r3,THREAD /* want THREAD of task */ 7509994a338SPaul Mackerras ld r5,PT_REGS(r3) 7519994a338SPaul Mackerras cmpdi 0,r5,0 7529994a338SPaul Mackerras SAVE_32VRS(0,r4,r3) 7539994a338SPaul Mackerras mfvscr vr0 7549994a338SPaul Mackerras li r4,THREAD_VSCR 7559994a338SPaul Mackerras stvx vr0,r4,r3 7569994a338SPaul Mackerras beq 1f 7579994a338SPaul Mackerras ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 7589994a338SPaul Mackerras lis r3,MSR_VEC@h 7599994a338SPaul Mackerras andc r4,r4,r3 /* disable FP for previous task */ 7609994a338SPaul Mackerras std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 7619994a338SPaul Mackerras1: 7629994a338SPaul Mackerras#ifndef CONFIG_SMP 7639994a338SPaul Mackerras li r5,0 7649994a338SPaul Mackerras ld r4,last_task_used_altivec@got(r2) 7659994a338SPaul Mackerras std r5,0(r4) 7669994a338SPaul Mackerras#endif /* CONFIG_SMP */ 7679994a338SPaul Mackerras blr 7689994a338SPaul Mackerras 7699994a338SPaul Mackerras#endif /* CONFIG_ALTIVEC */ 7709994a338SPaul Mackerras 7719994a338SPaul Mackerras_GLOBAL(__setup_cpu_power3) 7729994a338SPaul Mackerras blr 7739994a338SPaul Mackerras 7749994a338SPaul Mackerras_GLOBAL(execve) 7759994a338SPaul Mackerras li r0,__NR_execve 7769994a338SPaul Mackerras sc 7779994a338SPaul Mackerras bnslr 7789994a338SPaul Mackerras neg r3,r3 7799994a338SPaul Mackerras blr 7809994a338SPaul Mackerras 7819994a338SPaul Mackerras/* kexec_wait(phys_cpu) 7829994a338SPaul Mackerras * 7839994a338SPaul Mackerras * wait for the flag to change, indicating this kernel is going away but 7849994a338SPaul Mackerras * the slave code for the next one is at addresses 0 to 100. 7859994a338SPaul Mackerras * 7869994a338SPaul Mackerras * This is used by all slaves. 7879994a338SPaul Mackerras * 7889994a338SPaul Mackerras * Physical (hardware) cpu id should be in r3. 7899994a338SPaul Mackerras */ 7909994a338SPaul Mackerras_GLOBAL(kexec_wait) 7919994a338SPaul Mackerras bl 1f 7929994a338SPaul Mackerras1: mflr r5 7939994a338SPaul Mackerras addi r5,r5,kexec_flag-1b 7949994a338SPaul Mackerras 7959994a338SPaul Mackerras99: HMT_LOW 7969994a338SPaul Mackerras#ifdef CONFIG_KEXEC /* use no memory without kexec */ 7979994a338SPaul Mackerras lwz r4,0(r5) 7989994a338SPaul Mackerras cmpwi 0,r4,0 7999994a338SPaul Mackerras bnea 0x60 8009994a338SPaul Mackerras#endif 8019994a338SPaul Mackerras b 99b 8029994a338SPaul Mackerras 8039994a338SPaul Mackerras/* this can be in text because we won't change it until we are 8049994a338SPaul Mackerras * running in real anyways 8059994a338SPaul Mackerras */ 8069994a338SPaul Mackerraskexec_flag: 8079994a338SPaul Mackerras .long 0 8089994a338SPaul Mackerras 8099994a338SPaul Mackerras 8109994a338SPaul Mackerras#ifdef CONFIG_KEXEC 8119994a338SPaul Mackerras 8129994a338SPaul Mackerras/* kexec_smp_wait(void) 8139994a338SPaul Mackerras * 8149994a338SPaul Mackerras * call with interrupts off 8159994a338SPaul Mackerras * note: this is a terminal routine, it does not save lr 8169994a338SPaul Mackerras * 8179994a338SPaul Mackerras * get phys id from paca 8189994a338SPaul Mackerras * set paca id to -1 to say we got here 8199994a338SPaul Mackerras * switch to real mode 8209994a338SPaul Mackerras * join other cpus in kexec_wait(phys_id) 8219994a338SPaul Mackerras */ 8229994a338SPaul Mackerras_GLOBAL(kexec_smp_wait) 8239994a338SPaul Mackerras lhz r3,PACAHWCPUID(r13) 8249994a338SPaul Mackerras li r4,-1 8259994a338SPaul Mackerras sth r4,PACAHWCPUID(r13) /* let others know we left */ 8269994a338SPaul Mackerras bl real_mode 8279994a338SPaul Mackerras b .kexec_wait 8289994a338SPaul Mackerras 8299994a338SPaul Mackerras/* 8309994a338SPaul Mackerras * switch to real mode (turn mmu off) 8319994a338SPaul Mackerras * we use the early kernel trick that the hardware ignores bits 8329994a338SPaul Mackerras * 0 and 1 (big endian) of the effective address in real mode 8339994a338SPaul Mackerras * 8349994a338SPaul Mackerras * don't overwrite r3 here, it is live for kexec_wait above. 8359994a338SPaul Mackerras */ 8369994a338SPaul Mackerrasreal_mode: /* assume normal blr return */ 8379994a338SPaul Mackerras1: li r9,MSR_RI 8389994a338SPaul Mackerras li r10,MSR_DR|MSR_IR 8399994a338SPaul Mackerras mflr r11 /* return address to SRR0 */ 8409994a338SPaul Mackerras mfmsr r12 8419994a338SPaul Mackerras andc r9,r12,r9 8429994a338SPaul Mackerras andc r10,r12,r10 8439994a338SPaul Mackerras 8449994a338SPaul Mackerras mtmsrd r9,1 8459994a338SPaul Mackerras mtspr SPRN_SRR1,r10 8469994a338SPaul Mackerras mtspr SPRN_SRR0,r11 8479994a338SPaul Mackerras rfid 8489994a338SPaul Mackerras 8499994a338SPaul Mackerras 8509994a338SPaul Mackerras/* 8519994a338SPaul Mackerras * kexec_sequence(newstack, start, image, control, clear_all()) 8529994a338SPaul Mackerras * 8539994a338SPaul Mackerras * does the grungy work with stack switching and real mode switches 8549994a338SPaul Mackerras * also does simple calls to other code 8559994a338SPaul Mackerras */ 8569994a338SPaul Mackerras 8579994a338SPaul Mackerras_GLOBAL(kexec_sequence) 8589994a338SPaul Mackerras mflr r0 8599994a338SPaul Mackerras std r0,16(r1) 8609994a338SPaul Mackerras 8619994a338SPaul Mackerras /* switch stacks to newstack -- &kexec_stack.stack */ 8629994a338SPaul Mackerras stdu r1,THREAD_SIZE-112(r3) 8639994a338SPaul Mackerras mr r1,r3 8649994a338SPaul Mackerras 8659994a338SPaul Mackerras li r0,0 8669994a338SPaul Mackerras std r0,16(r1) 8679994a338SPaul Mackerras 8689994a338SPaul Mackerras /* save regs for local vars on new stack. 8699994a338SPaul Mackerras * yes, we won't go back, but ... 8709994a338SPaul Mackerras */ 8719994a338SPaul Mackerras std r31,-8(r1) 8729994a338SPaul Mackerras std r30,-16(r1) 8739994a338SPaul Mackerras std r29,-24(r1) 8749994a338SPaul Mackerras std r28,-32(r1) 8759994a338SPaul Mackerras std r27,-40(r1) 8769994a338SPaul Mackerras std r26,-48(r1) 8779994a338SPaul Mackerras std r25,-56(r1) 8789994a338SPaul Mackerras 8799994a338SPaul Mackerras stdu r1,-112-64(r1) 8809994a338SPaul Mackerras 8819994a338SPaul Mackerras /* save args into preserved regs */ 8829994a338SPaul Mackerras mr r31,r3 /* newstack (both) */ 8839994a338SPaul Mackerras mr r30,r4 /* start (real) */ 8849994a338SPaul Mackerras mr r29,r5 /* image (virt) */ 8859994a338SPaul Mackerras mr r28,r6 /* control, unused */ 8869994a338SPaul Mackerras mr r27,r7 /* clear_all() fn desc */ 8879994a338SPaul Mackerras mr r26,r8 /* spare */ 8889994a338SPaul Mackerras lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ 8899994a338SPaul Mackerras 8909994a338SPaul Mackerras /* disable interrupts, we are overwriting kernel data next */ 8919994a338SPaul Mackerras mfmsr r3 8929994a338SPaul Mackerras rlwinm r3,r3,0,17,15 8939994a338SPaul Mackerras mtmsrd r3,1 8949994a338SPaul Mackerras 8959994a338SPaul Mackerras /* copy dest pages, flush whole dest image */ 8969994a338SPaul Mackerras mr r3,r29 8979994a338SPaul Mackerras bl .kexec_copy_flush /* (image) */ 8989994a338SPaul Mackerras 8999994a338SPaul Mackerras /* turn off mmu */ 9009994a338SPaul Mackerras bl real_mode 9019994a338SPaul Mackerras 9029994a338SPaul Mackerras /* clear out hardware hash page table and tlb */ 9039994a338SPaul Mackerras ld r5,0(r27) /* deref function descriptor */ 9049994a338SPaul Mackerras mtctr r5 9059994a338SPaul Mackerras bctrl /* ppc_md.hash_clear_all(void); */ 9069994a338SPaul Mackerras 9079994a338SPaul Mackerras/* 9089994a338SPaul Mackerras * kexec image calling is: 9099994a338SPaul Mackerras * the first 0x100 bytes of the entry point are copied to 0 9109994a338SPaul Mackerras * 9119994a338SPaul Mackerras * all slaves branch to slave = 0x60 (absolute) 9129994a338SPaul Mackerras * slave(phys_cpu_id); 9139994a338SPaul Mackerras * 9149994a338SPaul Mackerras * master goes to start = entry point 9159994a338SPaul Mackerras * start(phys_cpu_id, start, 0); 9169994a338SPaul Mackerras * 9179994a338SPaul Mackerras * 9189994a338SPaul Mackerras * a wrapper is needed to call existing kernels, here is an approximate 9199994a338SPaul Mackerras * description of one method: 9209994a338SPaul Mackerras * 9219994a338SPaul Mackerras * v2: (2.6.10) 9229994a338SPaul Mackerras * start will be near the boot_block (maybe 0x100 bytes before it?) 9239994a338SPaul Mackerras * it will have a 0x60, which will b to boot_block, where it will wait 9249994a338SPaul Mackerras * and 0 will store phys into struct boot-block and load r3 from there, 9259994a338SPaul Mackerras * copy kernel 0-0x100 and tell slaves to back down to 0x60 again 9269994a338SPaul Mackerras * 9279994a338SPaul Mackerras * v1: (2.6.9) 9289994a338SPaul Mackerras * boot block will have all cpus scanning device tree to see if they 9299994a338SPaul Mackerras * are the boot cpu ????? 9309994a338SPaul Mackerras * other device tree differences (prop sizes, va vs pa, etc)... 9319994a338SPaul Mackerras */ 9329994a338SPaul Mackerras 9339994a338SPaul Mackerras /* copy 0x100 bytes starting at start to 0 */ 9349994a338SPaul Mackerras li r3,0 9359994a338SPaul Mackerras mr r4,r30 9369994a338SPaul Mackerras li r5,0x100 9379994a338SPaul Mackerras li r6,0 9389994a338SPaul Mackerras bl .copy_and_flush /* (dest, src, copy limit, start offset) */ 9399994a338SPaul Mackerras1: /* assume normal blr return */ 9409994a338SPaul Mackerras 9419994a338SPaul Mackerras /* release other cpus to the new kernel secondary start at 0x60 */ 9429994a338SPaul Mackerras mflr r5 9439994a338SPaul Mackerras li r6,1 9449994a338SPaul Mackerras stw r6,kexec_flag-1b(5) 9459994a338SPaul Mackerras mr r3,r25 # my phys cpu 9469994a338SPaul Mackerras mr r4,r30 # start, aka phys mem offset 9479994a338SPaul Mackerras mtlr 4 9489994a338SPaul Mackerras li r5,0 9499994a338SPaul Mackerras blr /* image->start(physid, image->start, 0); */ 9509994a338SPaul Mackerras#endif /* CONFIG_KEXEC */ 951