1/* 2 * 3 * This file is subject to the terms and conditions of the GNU General Public 4 * License. See the file "COPYING" in the main directory of this archive 5 * for more details. 6 * 7 * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) 8 * 9 */ 10#include <asm/assembly.h> 11#include <asm/psw.h> 12 13 .section .bss 14 .export real_stack 15 .align 64 16real_stack: 17 .block 8192 18 19#ifdef __LP64__ 20# define REG_SZ 8 21#else 22# define REG_SZ 4 23#endif 24 25#define N_SAVED_REGS 9 26 27save_cr_space: 28 .block REG_SZ * N_SAVED_REGS 29 30 31/************************ 32-bit real-mode calls ***********************/ 32/* This can be called in both narrow and wide kernels */ 33 34 .text 35 36 .export real32_call_asm 37 38 /* unsigned long real32_call_asm(unsigned int *sp, 39 * unsigned int *arg0p, 40 * unsigned int iodc_fn) 41 * sp is value of stack pointer to adopt before calling PDC (virt) 42 * arg0p points to where saved arg values may be found 43 * iodc_fn is the IODC function to call 44 */ 45 46real32_call_asm: 47 STREG %rp, -RP_OFFSET(%sp) /* save RP */ 48#ifdef __LP64__ 49 callee_save 50 ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */ 51 STREG %r27, -1*REG_SZ(%sp) 52 STREG %r29, -2*REG_SZ(%sp) 53#endif 54 STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */ 55 copy %arg0, %sp /* adopt the real-mode SP */ 56 57 /* save iodc_fn */ 58 copy %arg2, %r31 59 60 /* load up the arg registers from the saved arg area */ 61 /* 32-bit calling convention passes first 4 args in registers */ 62 ldw 0(%arg1), %arg0 /* note overwriting arg0 */ 63 ldw -8(%arg1), %arg2 64 ldw -12(%arg1), %arg3 65 ldw -4(%arg1), %arg1 /* obviously must do this one last! */ 66 67 tophys_r1 %sp 68 69 b,l rfi_virt2real,%r2 70 nop 71 72 b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ 73 nop 74 75#ifdef __LP64__ 76 rsm PSW_SM_W, %r0 /* go narrow */ 77#endif 78 79 ldil L%PA(ric_ret), %r2 80 ldo R%PA(ric_ret)(%r2), %r2 81 bv 0(%r31) 82 nop 83ric_ret: 84#ifdef __LP64__ 85 ssm PSW_SM_W, %r0 /* go wide */ 86#endif 87 /* restore CRs before going virtual in case we page fault */ 88 b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ 89 nop 90 91 b,l rfi_real2virt,%r2 92 nop 93 94 tovirt_r1 %sp 95 LDREG -REG_SZ(%sp), %sp /* restore SP */ 96#ifdef __LP64__ 97 LDREG -1*REG_SZ(%sp), %r27 98 LDREG -2*REG_SZ(%sp), %r29 99 ldo -2*REG_SZ(%sp), %sp 100 callee_rest 101#endif 102 LDREG -RP_OFFSET(%sp), %rp /* restore RP */ 103 bv 0(%rp) 104 nop 105 106 107# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) 108# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r 109 110 .text 111save_control_regs: 112 load32 PA(save_cr_space), %r28 113 PUSH_CR(%cr24, %r28) 114 PUSH_CR(%cr25, %r28) 115 PUSH_CR(%cr26, %r28) 116 PUSH_CR(%cr27, %r28) 117 PUSH_CR(%cr28, %r28) 118 PUSH_CR(%cr29, %r28) 119 PUSH_CR(%cr30, %r28) 120 PUSH_CR(%cr31, %r28) 121 PUSH_CR(%cr15, %r28) 122 bv 0(%r2) 123 nop 124 125restore_control_regs: 126 load32 PA(save_cr_space + (N_SAVED_REGS * REG_SZ)), %r26 127 POP_CR(%cr15, %r26) 128 POP_CR(%cr31, %r26) 129 POP_CR(%cr30, %r26) 130 POP_CR(%cr29, %r26) 131 POP_CR(%cr28, %r26) 132 POP_CR(%cr27, %r26) 133 POP_CR(%cr26, %r26) 134 POP_CR(%cr25, %r26) 135 POP_CR(%cr24, %r26) 136 bv 0(%r2) 137 nop 138 139/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for 140 * more general-purpose use by the several places which need RFIs 141 */ 142 .align 128 143 .text 144rfi_virt2real: 145 /* switch to real mode... */ 146 ssm 0,0 /* See "relied upon translation" */ 147 nop /* comment in interruption.S */ 148 nop 149 nop 150 nop 151 nop 152 nop 153 nop 154 nop 155 156 rsm (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q & I bits to load iia queue */ 157 mtctl 0, %cr17 /* space 0 */ 158 mtctl 0, %cr17 159 load32 PA(rfi_v2r_1), %r1 160 mtctl %r1, %cr18 161 ldo 4(%r1), %r1 162 mtctl %r1, %cr18 163 load32 REAL_MODE_PSW, %r1 164 mtctl %r1, %cr22 165 rfi 166 167 nop 168 nop 169 nop 170 nop 171 nop 172 nop 173 nop 174 nop 175rfi_v2r_1: 176 tophys_r1 %r2 177 bv 0(%r2) 178 nop 179 180 .text 181 .align 128 182rfi_real2virt: 183 ssm 0,0 /* See "relied upon translation" */ 184 nop /* comment in interruption.S */ 185 nop 186 nop 187 nop 188 nop 189 nop 190 nop 191 nop 192 193 rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */ 194 mtctl 0, %cr17 /* space 0 */ 195 mtctl 0, %cr17 196 load32 (rfi_r2v_1), %r1 197 mtctl %r1, %cr18 198 ldo 4(%r1), %r1 199 mtctl %r1, %cr18 200 load32 KERNEL_PSW, %r1 201 mtctl %r1, %cr22 202 rfi 203 204 nop 205 nop 206 nop 207 nop 208 nop 209 nop 210 nop 211 nop 212rfi_r2v_1: 213 tovirt_r1 %r2 214 bv 0(%r2) 215 nop 216 217#ifdef __LP64__ 218 219/************************ 64-bit real-mode calls ***********************/ 220/* This is only usable in wide kernels right now and will probably stay so */ 221 .text 222 .export real64_call_asm 223 /* unsigned long real64_call_asm(unsigned long *sp, 224 * unsigned long *arg0p, 225 * unsigned long fn) 226 * sp is value of stack pointer to adopt before calling PDC (virt) 227 * arg0p points to where saved arg values may be found 228 * iodc_fn is the IODC function to call 229 */ 230real64_call_asm: 231 std %rp, -0x10(%sp) /* save RP */ 232 std %sp, -8(%arg0) /* save SP on real-mode stack */ 233 copy %arg0, %sp /* adopt the real-mode SP */ 234 235 /* save fn */ 236 copy %arg2, %r31 237 238 /* set up the new ap */ 239 ldo 64(%arg1), %r29 240 241 /* load up the arg registers from the saved arg area */ 242 /* 32-bit calling convention passes first 4 args in registers */ 243 ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */ 244 ldd 2*REG_SZ(%arg1), %arg2 245 ldd 3*REG_SZ(%arg1), %arg3 246 ldd 4*REG_SZ(%arg1), %r22 247 ldd 5*REG_SZ(%arg1), %r21 248 ldd 6*REG_SZ(%arg1), %r20 249 ldd 7*REG_SZ(%arg1), %r19 250 ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */ 251 252 tophys_r1 %sp 253 254 b,l rfi_virt2real,%r2 255 nop 256 257 b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ 258 nop 259 260 load32 PA(r64_ret), %r2 261 bv 0(%r31) 262 nop 263r64_ret: 264 /* restore CRs before going virtual in case we page fault */ 265 b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ 266 nop 267 268 b,l rfi_real2virt,%r2 269 nop 270 271 tovirt_r1 %sp 272 ldd -8(%sp), %sp /* restore SP */ 273 ldd -0x10(%sp), %rp /* restore RP */ 274 bv 0(%rp) 275 nop 276 277#endif 278 .export pc_in_user_space 279 .text 280 /* Doesn't belong here but I couldn't find a nicer spot. */ 281 /* Should never get called, only used by profile stuff in time.c */ 282pc_in_user_space: 283 bv,n 0(%rp) 284 nop 285 286