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