Eric W. Biederman | 70765aa | 2005-06-25 14:58:07 -0700 | [diff] [blame] | 1 | /* |
| 2 | * relocate_kernel.S - put the kernel image in place to boot |
| 3 | * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> |
| 4 | * |
| 5 | * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz |
| 6 | * |
| 7 | * This source code is licensed under the GNU General Public License, |
| 8 | * Version 2. See the file COPYING for more details. |
| 9 | */ |
| 10 | |
| 11 | #include <asm/reg.h> |
| 12 | #include <asm/ppc_asm.h> |
| 13 | #include <asm/processor.h> |
| 14 | |
| 15 | #include <asm/kexec.h> |
| 16 | |
| 17 | #define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */ |
| 18 | |
| 19 | /* |
| 20 | * Must be relocatable PIC code callable as a C function. |
| 21 | */ |
| 22 | .globl relocate_new_kernel |
| 23 | relocate_new_kernel: |
| 24 | /* r3 = page_list */ |
| 25 | /* r4 = reboot_code_buffer */ |
| 26 | /* r5 = start_address */ |
| 27 | |
| 28 | li r0, 0 |
| 29 | |
| 30 | /* |
| 31 | * Set Machine Status Register to a known status, |
| 32 | * switch the MMU off and jump to 1: in a single step. |
| 33 | */ |
| 34 | |
| 35 | mr r8, r0 |
| 36 | ori r8, r8, MSR_RI|MSR_ME |
| 37 | mtspr SRR1, r8 |
| 38 | addi r8, r4, 1f - relocate_new_kernel |
| 39 | mtspr SRR0, r8 |
| 40 | sync |
| 41 | rfi |
| 42 | |
| 43 | 1: |
| 44 | /* from this point address translation is turned off */ |
| 45 | /* and interrupts are disabled */ |
| 46 | |
| 47 | /* set a new stack at the bottom of our page... */ |
| 48 | /* (not really needed now) */ |
| 49 | addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ |
| 50 | stw r0, 0(r1) |
| 51 | |
| 52 | /* Do the copies */ |
| 53 | li r6, 0 /* checksum */ |
| 54 | mr r0, r3 |
| 55 | b 1f |
| 56 | |
| 57 | 0: /* top, read another word for the indirection page */ |
| 58 | lwzu r0, 4(r3) |
| 59 | |
| 60 | 1: |
| 61 | /* is it a destination page? (r8) */ |
| 62 | rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ |
| 63 | beq 2f |
| 64 | |
| 65 | rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ |
| 66 | b 0b |
| 67 | |
| 68 | 2: /* is it an indirection page? (r3) */ |
| 69 | rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ |
| 70 | beq 2f |
| 71 | |
| 72 | rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ |
| 73 | subi r3, r3, 4 |
| 74 | b 0b |
| 75 | |
| 76 | 2: /* are we done? */ |
| 77 | rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ |
| 78 | beq 2f |
| 79 | b 3f |
| 80 | |
| 81 | 2: /* is it a source page? (r9) */ |
| 82 | rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ |
| 83 | beq 0b |
| 84 | |
| 85 | rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ |
| 86 | |
| 87 | li r7, PAGE_SIZE / 4 |
| 88 | mtctr r7 |
| 89 | subi r9, r9, 4 |
| 90 | subi r8, r8, 4 |
| 91 | 9: |
| 92 | lwzu r0, 4(r9) /* do the copy */ |
| 93 | xor r6, r6, r0 |
| 94 | stwu r0, 4(r8) |
| 95 | dcbst 0, r8 |
| 96 | sync |
| 97 | icbi 0, r8 |
| 98 | bdnz 9b |
| 99 | |
| 100 | addi r9, r9, 4 |
| 101 | addi r8, r8, 4 |
| 102 | b 0b |
| 103 | |
| 104 | 3: |
| 105 | |
| 106 | /* To be certain of avoiding problems with self-modifying code |
| 107 | * execute a serializing instruction here. |
| 108 | */ |
| 109 | isync |
| 110 | sync |
| 111 | |
| 112 | /* jump to the entry point, usually the setup routine */ |
| 113 | mtlr r5 |
| 114 | blrl |
| 115 | |
| 116 | 1: b 1b |
| 117 | |
| 118 | relocate_new_kernel_end: |
| 119 | |
| 120 | .globl relocate_new_kernel_size |
| 121 | relocate_new_kernel_size: |
| 122 | .long relocate_new_kernel_end - relocate_new_kernel |
| 123 | |