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 11#include <asm/pdc.h> 12#include <asm/psw.h> 13#include <asm/assembly.h> 14#include <asm/asm-offsets.h> 15 16#include <linux/linkage.h> 17 18 19 .section .bss 20 21 .export pdc_result 22 .export pdc_result2 23 .align 8 24pdc_result: 25 .block ASM_PDC_RESULT_SIZE 26pdc_result2: 27 .block ASM_PDC_RESULT_SIZE 28 29 .export real_stack 30 .export real32_stack 31 .export real64_stack 32 .align 64 33real_stack: 34real32_stack: 35real64_stack: 36 .block 8192 37 38#ifdef CONFIG_64BIT 39# define REG_SZ 8 40#else 41# define REG_SZ 4 42#endif 43 44#define N_SAVED_REGS 9 45 46save_cr_space: 47 .block REG_SZ * N_SAVED_REGS 48save_cr_end: 49 50 51/************************ 32-bit real-mode calls ***********************/ 52/* This can be called in both narrow and wide kernels */ 53 54 .text 55 56 /* unsigned long real32_call_asm(unsigned int *sp, 57 * unsigned int *arg0p, 58 * unsigned int iodc_fn) 59 * sp is value of stack pointer to adopt before calling PDC (virt) 60 * arg0p points to where saved arg values may be found 61 * iodc_fn is the IODC function to call 62 */ 63 64ENTRY_CFI(real32_call_asm) 65 STREG %rp, -RP_OFFSET(%sp) /* save RP */ 66#ifdef CONFIG_64BIT 67 callee_save 68 ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */ 69 STREG %r27, -1*REG_SZ(%sp) 70 STREG %r29, -2*REG_SZ(%sp) 71#endif 72 STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */ 73 copy %arg0, %sp /* adopt the real-mode SP */ 74 75 /* save iodc_fn */ 76 copy %arg2, %r31 77 78 /* load up the arg registers from the saved arg area */ 79 /* 32-bit calling convention passes first 4 args in registers */ 80 ldw 0(%arg1), %arg0 /* note overwriting arg0 */ 81 ldw -8(%arg1), %arg2 82 ldw -12(%arg1), %arg3 83 ldw -4(%arg1), %arg1 /* obviously must do this one last! */ 84 85 tophys_r1 %sp 86 87 b,l rfi_virt2real,%r2 88 nop 89 90 b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ 91 nop 92 93#ifdef CONFIG_64BIT 94 rsm PSW_SM_W, %r0 /* go narrow */ 95#endif 96 97 load32 PA(ric_ret), %r2 98 bv 0(%r31) 99 nop 100ric_ret: 101#ifdef CONFIG_64BIT 102 ssm PSW_SM_W, %r0 /* go wide */ 103#endif 104 /* restore CRs before going virtual in case we page fault */ 105 b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ 106 nop 107 108 b,l rfi_real2virt,%r2 109 nop 110 111 tovirt_r1 %sp 112 LDREG -REG_SZ(%sp), %sp /* restore SP */ 113#ifdef CONFIG_64BIT 114 LDREG -1*REG_SZ(%sp), %r27 115 LDREG -2*REG_SZ(%sp), %r29 116 ldo -2*REG_SZ(%sp), %sp 117 callee_rest 118#endif 119 LDREG -RP_OFFSET(%sp), %rp /* restore RP */ 120 bv 0(%rp) 121 nop 122ENDPROC_CFI(real32_call_asm) 123 124 125# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) 126# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r 127 128 .text 129ENTRY_CFI(save_control_regs) 130 load32 PA(save_cr_space), %r28 131 PUSH_CR(%cr24, %r28) 132 PUSH_CR(%cr25, %r28) 133 PUSH_CR(%cr26, %r28) 134 PUSH_CR(%cr27, %r28) 135 PUSH_CR(%cr28, %r28) 136 PUSH_CR(%cr29, %r28) 137 PUSH_CR(%cr30, %r28) 138 PUSH_CR(%cr31, %r28) 139 PUSH_CR(%cr15, %r28) 140 bv 0(%r2) 141 nop 142ENDPROC_CFI(save_control_regs) 143 144ENTRY_CFI(restore_control_regs) 145 load32 PA(save_cr_end), %r26 146 POP_CR(%cr15, %r26) 147 POP_CR(%cr31, %r26) 148 POP_CR(%cr30, %r26) 149 POP_CR(%cr29, %r26) 150 POP_CR(%cr28, %r26) 151 POP_CR(%cr27, %r26) 152 POP_CR(%cr26, %r26) 153 POP_CR(%cr25, %r26) 154 POP_CR(%cr24, %r26) 155 bv 0(%r2) 156 nop 157ENDPROC_CFI(restore_control_regs) 158 159/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for 160 * more general-purpose use by the several places which need RFIs 161 */ 162 .text 163 .align 128 164ENTRY_CFI(rfi_virt2real) 165#if !defined(BOOTLOADER) 166 /* switch to real mode... */ 167 rsm PSW_SM_I,%r0 168 load32 PA(rfi_v2r_1), %r1 169 nop 170 nop 171 nop 172 nop 173 nop 174 175 rsm PSW_SM_Q,%r0 /* disable Q & I bits to load iia queue */ 176 mtctl %r0, %cr17 /* Clear IIASQ tail */ 177 mtctl %r0, %cr17 /* Clear IIASQ head */ 178 mtctl %r1, %cr18 /* IIAOQ head */ 179 ldo 4(%r1), %r1 180 mtctl %r1, %cr18 /* IIAOQ tail */ 181 load32 REAL_MODE_PSW, %r1 182 mtctl %r1, %cr22 183 rfi 184 185 nop 186 nop 187 nop 188 nop 189 nop 190 nop 191 nop 192 nop 193rfi_v2r_1: 194 tophys_r1 %r2 195#endif /* defined(BOOTLOADER) */ 196 bv 0(%r2) 197 nop 198ENDPROC_CFI(rfi_virt2real) 199 200 .text 201 .align 128 202ENTRY_CFI(rfi_real2virt) 203#if !defined(BOOTLOADER) 204 rsm PSW_SM_I,%r0 205 load32 (rfi_r2v_1), %r1 206 nop 207 nop 208 nop 209 nop 210 nop 211 212 rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */ 213 mtctl %r0, %cr17 /* Clear IIASQ tail */ 214 mtctl %r0, %cr17 /* Clear IIASQ head */ 215 mtctl %r1, %cr18 /* IIAOQ head */ 216 ldo 4(%r1), %r1 217 mtctl %r1, %cr18 /* IIAOQ tail */ 218 load32 KERNEL_PSW, %r1 219 mtctl %r1, %cr22 220 rfi 221 222 nop 223 nop 224 nop 225 nop 226 nop 227 nop 228 nop 229 nop 230rfi_r2v_1: 231 tovirt_r1 %r2 232#endif /* defined(BOOTLOADER) */ 233 bv 0(%r2) 234 nop 235ENDPROC_CFI(rfi_real2virt) 236 237#ifdef CONFIG_64BIT 238 239/************************ 64-bit real-mode calls ***********************/ 240/* This is only usable in wide kernels right now and will probably stay so */ 241 .text 242 /* unsigned long real64_call_asm(unsigned long *sp, 243 * unsigned long *arg0p, 244 * unsigned long fn) 245 * sp is value of stack pointer to adopt before calling PDC (virt) 246 * arg0p points to where saved arg values may be found 247 * iodc_fn is the IODC function to call 248 */ 249ENTRY_CFI(real64_call_asm) 250 std %rp, -0x10(%sp) /* save RP */ 251 std %sp, -8(%arg0) /* save SP on real-mode stack */ 252 copy %arg0, %sp /* adopt the real-mode SP */ 253 254 /* save fn */ 255 copy %arg2, %r31 256 257 /* set up the new ap */ 258 ldo 64(%arg1), %r29 259 260 /* load up the arg registers from the saved arg area */ 261 /* 32-bit calling convention passes first 4 args in registers */ 262 ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */ 263 ldd 2*REG_SZ(%arg1), %arg2 264 ldd 3*REG_SZ(%arg1), %arg3 265 ldd 4*REG_SZ(%arg1), %r22 266 ldd 5*REG_SZ(%arg1), %r21 267 ldd 6*REG_SZ(%arg1), %r20 268 ldd 7*REG_SZ(%arg1), %r19 269 ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */ 270 271 tophys_r1 %sp 272 273 b,l rfi_virt2real,%r2 274 nop 275 276 b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ 277 nop 278 279 load32 PA(r64_ret), %r2 280 bv 0(%r31) 281 nop 282r64_ret: 283 /* restore CRs before going virtual in case we page fault */ 284 b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ 285 nop 286 287 b,l rfi_real2virt,%r2 288 nop 289 290 tovirt_r1 %sp 291 ldd -8(%sp), %sp /* restore SP */ 292 ldd -0x10(%sp), %rp /* restore RP */ 293 bv 0(%rp) 294 nop 295ENDPROC_CFI(real64_call_asm) 296 297#endif 298 299 .text 300 /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html 301 ** GCC 3.3 and later has a new function in libgcc.a for 302 ** comparing function pointers. 303 */ 304ENTRY_CFI(__canonicalize_funcptr_for_compare) 305#ifdef CONFIG_64BIT 306 bve (%r2) 307#else 308 bv %r0(%r2) 309#endif 310 copy %r26,%r28 311ENDPROC_CFI(__canonicalize_funcptr_for_compare) 312 313