1/* 2 * Copyright IBM Corp. 2005 3 * 4 * Author(s): Rolf Adelsberger, 5 * Heiko Carstens <heiko.carstens@de.ibm.com> 6 * 7 */ 8 9#include <linux/linkage.h> 10#include <asm/sigp.h> 11 12/* 13 * moves the new kernel to its destination... 14 * %r2 = pointer to first kimage_entry_t 15 * %r3 = start address - where to jump to after the job is done... 16 * 17 * %r5 will be used as temp. storage 18 * %r6 holds the destination address 19 * %r7 = PAGE_SIZE 20 * %r8 holds the source address 21 * %r9 = PAGE_SIZE 22 * %r10 is a page mask 23 */ 24 25 .text 26ENTRY(relocate_kernel) 27 basr %r13,0 # base address 28 .base: 29 stnsm sys_msk-.base(%r13),0xfb # disable DAT 30 stctl %c0,%c15,ctlregs-.base(%r13) 31 stm %r0,%r15,gprregs-.base(%r13) 32 la %r1,load_psw-.base(%r13) 33 mvc 0(8,%r0),0(%r1) 34 la %r0,.back-.base(%r13) 35 st %r0,4(%r0) 36 oi 4(%r0),0x80 37 mvc 0x68(8,%r0),0(%r1) 38 la %r0,.back_pgm-.base(%r13) 39 st %r0,0x6c(%r0) 40 oi 0x6c(%r0),0x80 41 lhi %r0,0 42 diag %r0,%r0,0x308 43 .back: 44 basr %r13,0 45 .back_base: 46 oi have_diag308-.back_base(%r13),0x01 47 lctl %c0,%c15,ctlregs-.back_base(%r13) 48 lm %r0,%r15,gprregs-.back_base(%r13) 49 j .start_reloc 50 .back_pgm: 51 lm %r0,%r15,gprregs-.base(%r13) 52 .start_reloc: 53 lhi %r10,-1 # preparing the mask 54 sll %r10,12 # shift it such that it becomes 0xf000 55 .top: 56 lhi %r7,4096 # load PAGE_SIZE in r7 57 lhi %r9,4096 # load PAGE_SIZE in r9 58 l %r5,0(%r2) # read another word for indirection page 59 ahi %r2,4 # increment pointer 60 tml %r5,0x1 # is it a destination page? 61 je .indir_check # NO, goto "indir_check" 62 lr %r6,%r5 # r6 = r5 63 nr %r6,%r10 # mask it out and... 64 j .top # ...next iteration 65 .indir_check: 66 tml %r5,0x2 # is it a indirection page? 67 je .done_test # NO, goto "done_test" 68 nr %r5,%r10 # YES, mask out, 69 lr %r2,%r5 # move it into the right register, 70 j .top # and read next... 71 .done_test: 72 tml %r5,0x4 # is it the done indicator? 73 je .source_test # NO! Well, then it should be the source indicator... 74 j .done # ok, lets finish it here... 75 .source_test: 76 tml %r5,0x8 # it should be a source indicator... 77 je .top # NO, ignore it... 78 lr %r8,%r5 # r8 = r5 79 nr %r8,%r10 # masking 80 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 81 jo 0b 82 j .top 83 .done: 84 sr %r0,%r0 # clear register r0 85 la %r4,load_psw-.base(%r13) # load psw-address into the register 86 o %r3,4(%r4) # or load address into psw 87 st %r3,4(%r4) 88 mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 89 tm have_diag308-.base(%r13),0x01 90 jno .no_diag308 91 diag %r0,%r0,0x308 92 .no_diag308: 93 sr %r1,%r1 # clear %r1 94 sr %r2,%r2 # clear %r2 95 sigp %r1,%r2,SIGP_SET_ARCHITECTURE # set cpuid to zero 96 lpsw 0 # hopefully start new kernel... 97 98 .align 8 99 load_psw: 100 .long 0x00080000,0x80000000 101 sys_msk: 102 .quad 0 103 ctlregs: 104 .rept 16 105 .long 0 106 .endr 107 gprregs: 108 .rept 16 109 .long 0 110 .endr 111 have_diag308: 112 .byte 0 113 .align 8 114 relocate_kernel_end: 115 .align 8 116 .globl relocate_kernel_len 117 relocate_kernel_len: 118 .quad relocate_kernel_end - relocate_kernel 119