1/* 2 * s390x startup code 3 * 4 * Copyright (c) 2017 Red Hat Inc 5 * 6 * Authors: 7 * Thomas Huth <thuth@redhat.com> 8 * David Hildenbrand <david@redhat.com> 9 * 10 * This code is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU Library General Public License version 2. 12 */ 13#include <asm/asm-offsets.h> 14#include <asm/sigp.h> 15 16.section .init 17 18/* 19 * Short init between 0x10000 and 0x10480 and then jump to 0x11000. 20 * 0x10480 - 0x11000 are written to by bootloader. 21 * 22 * For KVM and TCG kernel boot we are in 64 bit z/Arch mode. 23 * When booting from disk the initial short psw is in 31 bit mode. 24 * When running under LPAR or z/VM, we might start in 31 bit and esam mode. 25 */ 26 .globl start 27start: 28 /* Switch to z/Architecture mode and 64-bit */ 29 slr %r0, %r0 # Set cpuid to zero 30 lhi %r1, 2 # mode 2 = esame 31 sigp %r1, %r0, SIGP_SET_ARCHITECTURE 32 /* XOR all registers with themselves to clear them fully. */ 33 .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 34 xgr \i,\i 35 .endr 36 sam64 # Set addressing mode to 64 bit 37 /* setup stack */ 38 larl %r15, stackptr 39 /* setup initial PSW mask + control registers*/ 40 larl %r1, initial_psw 41 lpswe 0(%r1) 42clear_bss_start: 43 larl %r2, __bss_start 44 larl %r3, __bss_end 45 slgr %r3, %r2 # Get sizeof bss 46 aghi %r3,-1 47 srlg %r4,%r3,8 # Calc number of 256 byte chunks 48 ltgr %r4,%r4 49 lgr %r1,%r2 50 jz clear_bss_remainder # If none, clear remaining bytes 51clear_bss_loop: 52 xc 0(256,%r1), 0(%r1) # Clear 256 byte chunks via xor 53 la %r1, 256(%r1) 54 brctg %r4, clear_bss_loop 55clear_bss_remainder: 56 larl %r2, memsetxc 57 ex %r3, 0(%r2) 58 /* setup pgm interrupt handler */ 59 larl %r1, pgm_int_psw 60 mvc GEN_LC_PGM_NEW_PSW(16), 0(%r1) 61 /* setup ext interrupt handler */ 62 larl %r1, ext_int_psw 63 mvc GEN_LC_EXT_NEW_PSW(16), 0(%r1) 64 /* setup mcck interrupt handler */ 65 larl %r1, mcck_int_psw 66 mvc GEN_LC_MCCK_NEW_PSW(16), 0(%r1) 67 /* setup io interrupt handler */ 68 larl %r1, io_int_psw 69 mvc GEN_LC_IO_NEW_PSW(16), 0(%r1) 70 /* setup svc interrupt handler */ 71 larl %r1, svc_int_psw 72 mvc GEN_LC_SVC_NEW_PSW(16), 0(%r1) 73 /* setup cr0, enabling e.g. AFP-register control */ 74 larl %r1, initial_cr0 75 lctlg %c0, %c0, 0(%r1) 76 /* call setup() */ 77 brasl %r14, setup 78 /* forward test parameter */ 79 larl %r2, __argc 80 llgf %r2, 0(%r2) 81 larl %r3, __argv 82 /* call to main() */ 83 brasl %r14, main 84 /* forward exit code */ 85 lgr %r3, %r2 86 /* call exit() */ 87 j exit 88 89memsetxc: 90 xc 0(1,%r1),0(%r1) 91 92 .macro SAVE_REGS 93 /* save grs 0-15 */ 94 stmg %r0, %r15, GEN_LC_SW_INT_GRS 95 /* save crs 0-15 */ 96 stctg %c0, %c15, GEN_LC_SW_INT_CRS 97 /* load a cr0 that has the AFP control bit which enables all FPRs */ 98 larl %r1, initial_cr0 99 lctlg %c0, %c0, 0(%r1) 100 /* save fprs 0-15 + fpc */ 101 la %r1, GEN_LC_SW_INT_FPRS 102 .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 103 std \i, \i * 8(%r1) 104 .endr 105 stfpc GEN_LC_SW_INT_FPC 106 .endm 107 108 .macro RESTORE_REGS 109 /* restore fprs 0-15 + fpc */ 110 la %r1, GEN_LC_SW_INT_FPRS 111 .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 112 ld \i, \i * 8(%r1) 113 .endr 114 lfpc GEN_LC_SW_INT_FPC 115 /* restore crs 0-15 */ 116 lctlg %c0, %c15, GEN_LC_SW_INT_CRS 117 /* restore grs 0-15 */ 118 lmg %r0, %r15, GEN_LC_SW_INT_GRS 119 .endm 120 121/* Save registers on the stack (r15), so we can have stacked interrupts. */ 122 .macro SAVE_REGS_STACK 123 /* Allocate a stack frame for 15 general registers */ 124 slgfi %r15, 15 * 8 125 /* Store registers r0 to r14 on the stack */ 126 stmg %r0, %r14, 0(%r15) 127 /* Allocate a stack frame for 16 floating point registers */ 128 /* The size of a FP register is the size of an double word */ 129 slgfi %r15, 16 * 8 130 /* Save fp register on stack: offset to SP is multiple of reg number */ 131 .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 132 std \i, \i * 8(%r15) 133 .endr 134 /* Save fpc, but keep stack aligned on 64bits */ 135 slgfi %r15, 8 136 efpc %r0 137 stg %r0, 0(%r15) 138 .endm 139 140/* Restore the register in reverse order */ 141 .macro RESTORE_REGS_STACK 142 /* Restore fpc */ 143 lfpc 0(%r15) 144 algfi %r15, 8 145 /* Restore fp register from stack: SP still where it was left */ 146 /* and offset to SP is a multiple of reg number */ 147 .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 148 ld \i, \i * 8(%r15) 149 .endr 150 /* Now that we're done, rewind the stack pointer by 16 double word */ 151 algfi %r15, 16 * 8 152 /* Load the registers from stack */ 153 lmg %r0, %r14, 0(%r15) 154 /* Rewind the stack by 15 double word */ 155 algfi %r15, 15 * 8 156 .endm 157 158.section .text 159/* 160 * load_reset calling convention: 161 * %r2 subcode (0 or 1) 162 */ 163.globl diag308_load_reset 164diag308_load_reset: 165 SAVE_REGS 166 /* Backup current PSW mask, as we have to restore it on success */ 167 epsw %r0, %r1 168 st %r0, GEN_LC_SW_INT_PSW 169 st %r1, GEN_LC_SW_INT_PSW + 4 170 /* Load reset psw mask (short psw, 64 bit) */ 171 lg %r0, reset_psw 172 /* Load the success label address */ 173 larl %r1, 0f 174 /* Or it to the mask */ 175 ogr %r0, %r1 176 /* Store it at the reset PSW location (real 0x0) */ 177 stg %r0, 0 178 /* Do the reset */ 179 diag %r0,%r2,0x308 180 /* Failure path */ 181 xgr %r2, %r2 182 br %r14 183 /* Success path */ 184 /* load a cr0 that has the AFP control bit which enables all FPRs */ 1850: larl %r1, initial_cr0 186 lctlg %c0, %c0, 0(%r1) 187 RESTORE_REGS 188 lhi %r2, 1 189 larl %r0, 1f 190 stg %r0, GEN_LC_SW_INT_PSW + 8 191 lpswe GEN_LC_SW_INT_PSW 1921: br %r14 193 194.globl smp_cpu_setup_state 195smp_cpu_setup_state: 196 xgr %r1, %r1 197 lmg %r0, %r15, GEN_LC_SW_INT_GRS 198 lctlg %c0, %c0, GEN_LC_SW_INT_CRS 199 /* We should only go once through cpu setup and not for every restart */ 200 stg %r14, GEN_LC_RESTART_NEW_PSW + 8 201 larl %r14, 0f 202 lpswe GEN_LC_SW_INT_PSW 203 /* If the function returns, just loop here */ 2040: j 0 205 206pgm_int: 207 SAVE_REGS 208 brasl %r14, handle_pgm_int 209 RESTORE_REGS 210 lpswe GEN_LC_PGM_OLD_PSW 211 212ext_int: 213 SAVE_REGS 214 brasl %r14, handle_ext_int 215 RESTORE_REGS 216 lpswe GEN_LC_EXT_OLD_PSW 217 218mcck_int: 219 SAVE_REGS 220 brasl %r14, handle_mcck_int 221 RESTORE_REGS 222 lpswe GEN_LC_MCCK_OLD_PSW 223 224io_int: 225 SAVE_REGS_STACK 226 brasl %r14, handle_io_int 227 RESTORE_REGS_STACK 228 lpswe GEN_LC_IO_OLD_PSW 229 230svc_int: 231 SAVE_REGS 232 brasl %r14, handle_svc_int 233 RESTORE_REGS 234 lpswe GEN_LC_SVC_OLD_PSW 235 236 .align 8 237reset_psw: 238 .quad 0x0008000180000000 239initial_psw: 240 .quad 0x0000000180000000, clear_bss_start 241pgm_int_psw: 242 .quad 0x0000000180000000, pgm_int 243ext_int_psw: 244 .quad 0x0000000180000000, ext_int 245mcck_int_psw: 246 .quad 0x0000000180000000, mcck_int 247io_int_psw: 248 .quad 0x0000000180000000, io_int 249svc_int_psw: 250 .quad 0x0000000180000000, svc_int 251initial_cr0: 252 /* enable AFP-register control, so FP regs (+BFP instr) can be used */ 253 .quad 0x0000000000040000 254