aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel/misc.S
diff options
context:
space:
mode:
authorR Sharada <sharada@in.ibm.com>2005-06-25 17:58:10 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 19:24:51 -0400
commitfce0d5740322b98b863f9e609f5a9bd4c06703af (patch)
tree658f5aca95d62c8e35f938a435d9f512c21921df /arch/ppc64/kernel/misc.S
parentf4c82d5132b0592f5d6befc5b652cbd4b08f12ff (diff)
[PATCH] ppc64: kexec support for ppc64
This patch implements the kexec support for ppc64 platforms. A couple of notes: 1) We copy the pages in virtual mode, using the full base kernel and a statically allocated stack. At kexec_prepare time we scan the pages and if any overlap our (0, _end[]) range we return -ETXTBSY. On PowerPC 64 systems running in LPAR (logical partitioning) mode, only a small region of memory, referred to as the RMO, can be accessed in real mode. Since Linux runs with only one zone of memory in the memory allocator, and it can be orders of magnitude more memory than the RMO, looping until we allocate pages in the source region is not feasible. Copying in virtual means we don't have to write a hash table generation and call hypervisor to insert translations, instead we rely on the pinned kernel linear mapping. The kernel already has move to linked location built in, so there is no requirement to load it at 0. If we want to load something other than a kernel, then a stub can be written to copy a linear chunk in real mode. 2) The start entry point gets passed parameters from the kernel. Slaves are started at a fixed address after copying code from the entry point. All CPUs get passed their firmware assigned physical id in r3 (most calling conventions use this register for the first argument). This is used to distinguish each CPU from all other CPUs. Since firmware is not around, there is no other way to obtain this information other than to pass it somewhere. A single CPU, referred to here as the master and the one executing the kexec call, branches to start with the address of start in r4. While this can be calculated, we have to load it through a gpr to branch to this point so defining the register this is contained in is free. A stack of unspecified size is available at r1 (also common calling convention). All remaining running CPUs are sent to start at absolute address 0x60 after copying the first 0x100 bytes from start to address 0. This convention was chosen because it matches what the kernel has been doing itself. (only gpr3 is defined). Note: This is not quite the convention of the kexec bootblock v2 in the kernel. A stub has been written to convert between them, and we may adjust the kernel in the future to allow this directly without any stub. 3) Destination pages can be placed anywhere, even where they would not be accessible in real mode. This will allow us to place ram disks above the RMO if we choose. Signed-off-by: Milton Miller <miltonm@bga.com> Signed-off-by: R Sharada <sharada@in.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc64/kernel/misc.S')
-rw-r--r--arch/ppc64/kernel/misc.S175
1 files changed, 173 insertions, 2 deletions
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index e3c73b3425dc..f3dea0c5a88c 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -680,6 +680,177 @@ _GLOBAL(kernel_thread)
680 ld r30,-16(r1) 680 ld r30,-16(r1)
681 blr 681 blr
682 682
683/* kexec_wait(phys_cpu)
684 *
685 * wait for the flag to change, indicating this kernel is going away but
686 * the slave code for the next one is at addresses 0 to 100.
687 *
688 * This is used by all slaves.
689 *
690 * Physical (hardware) cpu id should be in r3.
691 */
692_GLOBAL(kexec_wait)
693 bl 1f
6941: mflr r5
695 addi r5,r5,kexec_flag-1b
696
69799: HMT_LOW
698#ifdef CONFIG_KEXEC /* use no memory without kexec */
699 lwz r4,0(r5)
700 cmpwi 0,r4,0
701 bnea 0x60
702#endif
703 b 99b
704
705/* this can be in text because we won't change it until we are
706 * running in real anyways
707 */
708kexec_flag:
709 .long 0
710
711
712#ifdef CONFIG_KEXEC
713
714/* kexec_smp_wait(void)
715 *
716 * call with interrupts off
717 * note: this is a terminal routine, it does not save lr
718 *
719 * get phys id from paca
720 * set paca id to -1 to say we got here
721 * switch to real mode
722 * join other cpus in kexec_wait(phys_id)
723 */
724_GLOBAL(kexec_smp_wait)
725 lhz r3,PACAHWCPUID(r13)
726 li r4,-1
727 sth r4,PACAHWCPUID(r13) /* let others know we left */
728 bl real_mode
729 b .kexec_wait
730
731/*
732 * switch to real mode (turn mmu off)
733 * we use the early kernel trick that the hardware ignores bits
734 * 0 and 1 (big endian) of the effective address in real mode
735 *
736 * don't overwrite r3 here, it is live for kexec_wait above.
737 */
738real_mode: /* assume normal blr return */
7391: li r9,MSR_RI
740 li r10,MSR_DR|MSR_IR
741 mflr r11 /* return address to SRR0 */
742 mfmsr r12
743 andc r9,r12,r9
744 andc r10,r12,r10
745
746 mtmsrd r9,1
747 mtspr SPRN_SRR1,r10
748 mtspr SPRN_SRR0,r11
749 rfid
750
751
752/*
753 * kexec_sequence(newstack, start, image, control, clear_all())
754 *
755 * does the grungy work with stack switching and real mode switches
756 * also does simple calls to other code
757 */
758
759_GLOBAL(kexec_sequence)
760 mflr r0
761 std r0,16(r1)
762
763 /* switch stacks to newstack -- &kexec_stack.stack */
764 stdu r1,THREAD_SIZE-112(r3)
765 mr r1,r3
766
767 li r0,0
768 std r0,16(r1)
769
770 /* save regs for local vars on new stack.
771 * yes, we won't go back, but ...
772 */
773 std r31,-8(r1)
774 std r30,-16(r1)
775 std r29,-24(r1)
776 std r28,-32(r1)
777 std r27,-40(r1)
778 std r26,-48(r1)
779 std r25,-56(r1)
780
781 stdu r1,-112-64(r1)
782
783 /* save args into preserved regs */
784 mr r31,r3 /* newstack (both) */
785 mr r30,r4 /* start (real) */
786 mr r29,r5 /* image (virt) */
787 mr r28,r6 /* control, unused */
788 mr r27,r7 /* clear_all() fn desc */
789 mr r26,r8 /* spare */
790 lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */
791
792 /* disable interrupts, we are overwriting kernel data next */
793 mfmsr r3
794 rlwinm r3,r3,0,17,15
795 mtmsrd r3,1
796
797 /* copy dest pages, flush whole dest image */
798 mr r3,r29
799 bl .kexec_copy_flush /* (image) */
800
801 /* turn off mmu */
802 bl real_mode
803
804 /* clear out hardware hash page table and tlb */
805 ld r5,0(r27) /* deref function descriptor */
806 mtctr r5
807 bctrl /* ppc_md.hash_clear_all(void); */
808
809/*
810 * kexec image calling is:
811 * the first 0x100 bytes of the entry point are copied to 0
812 *
813 * all slaves branch to slave = 0x60 (absolute)
814 * slave(phys_cpu_id);
815 *
816 * master goes to start = entry point
817 * start(phys_cpu_id, start, 0);
818 *
819 *
820 * a wrapper is needed to call existing kernels, here is an approximate
821 * description of one method:
822 *
823 * v2: (2.6.10)
824 * start will be near the boot_block (maybe 0x100 bytes before it?)
825 * it will have a 0x60, which will b to boot_block, where it will wait
826 * and 0 will store phys into struct boot-block and load r3 from there,
827 * copy kernel 0-0x100 and tell slaves to back down to 0x60 again
828 *
829 * v1: (2.6.9)
830 * boot block will have all cpus scanning device tree to see if they
831 * are the boot cpu ?????
832 * other device tree differences (prop sizes, va vs pa, etc)...
833 */
834
835 /* copy 0x100 bytes starting at start to 0 */
836 li r3,0
837 mr r4,r30
838 li r5,0x100
839 li r6,0
840 bl .copy_and_flush /* (dest, src, copy limit, start offset) */
8411: /* assume normal blr return */
842
843 /* release other cpus to the new kernel secondary start at 0x60 */
844 mflr r5
845 li r6,1
846 stw r6,kexec_flag-1b(5)
847 mr r3,r25 # my phys cpu
848 mr r4,r30 # start, aka phys mem offset
849 mtlr 4
850 li r5,0
851 blr /* image->start(physid, image->start, 0); */
852#endif /* CONFIG_KEXEC */
853
683/* Why isn't this a) automatic, b) written in 'C'? */ 854/* Why isn't this a) automatic, b) written in 'C'? */
684 .balign 8 855 .balign 8
685_GLOBAL(sys_call_table32) 856_GLOBAL(sys_call_table32)
@@ -951,7 +1122,7 @@ _GLOBAL(sys_call_table32)
951 .llong .compat_sys_mq_timedreceive /* 265 */ 1122 .llong .compat_sys_mq_timedreceive /* 265 */
952 .llong .compat_sys_mq_notify 1123 .llong .compat_sys_mq_notify
953 .llong .compat_sys_mq_getsetattr 1124 .llong .compat_sys_mq_getsetattr
954 .llong .sys_ni_syscall /* 268 reserved for sys_kexec_load */ 1125 .llong .compat_sys_kexec_load
955 .llong .sys32_add_key 1126 .llong .sys32_add_key
956 .llong .sys32_request_key 1127 .llong .sys32_request_key
957 .llong .compat_sys_keyctl 1128 .llong .compat_sys_keyctl
@@ -1227,7 +1398,7 @@ _GLOBAL(sys_call_table)
1227 .llong .sys_mq_timedreceive /* 265 */ 1398 .llong .sys_mq_timedreceive /* 265 */
1228 .llong .sys_mq_notify 1399 .llong .sys_mq_notify
1229 .llong .sys_mq_getsetattr 1400 .llong .sys_mq_getsetattr
1230 .llong .sys_ni_syscall /* 268 reserved for sys_kexec_load */ 1401 .llong .sys_kexec_load
1231 .llong .sys_add_key 1402 .llong .sys_add_key
1232 .llong .sys_request_key /* 270 */ 1403 .llong .sys_request_key /* 270 */
1233 .llong .sys_keyctl 1404 .llong .sys_keyctl