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