/*1*2* This file is subject to the terms and conditions of the GNU General Public3* License. See the file "COPYING" in the main directory of this archive4* for more details.5*6* Copyright (C) 2000 Hewlett Packard (Paul Bame [email protected])7*8*/910#include <asm/pdc.h>11#include <asm/psw.h>12#include <asm/assembly.h>13#include <asm/asm-offsets.h>1415#include <linux/linkage.h>161718.section .bss1920.export pdc_result21.export pdc_result222.align 823pdc_result:24.block ASM_PDC_RESULT_SIZE25pdc_result2:26.block ASM_PDC_RESULT_SIZE2728.export real_stack29.export real32_stack30.export real64_stack31.align 6432real_stack:33real32_stack:34real64_stack:35.block 81923637#ifdef CONFIG_64BIT38# define REG_SZ 839#else40# define REG_SZ 441#endif4243#define N_SAVED_REGS 94445save_cr_space:46.block REG_SZ * N_SAVED_REGS47save_cr_end:484950/************************ 32-bit real-mode calls ***********************/51/* This can be called in both narrow and wide kernels */5253.text5455/* unsigned long real32_call_asm(unsigned int *sp,56* unsigned int *arg0p,57* unsigned int iodc_fn)58* sp is value of stack pointer to adopt before calling PDC (virt)59* arg0p points to where saved arg values may be found60* iodc_fn is the IODC function to call61*/6263ENTRY(real32_call_asm)64STREG %rp, -RP_OFFSET(%sp) /* save RP */65#ifdef CONFIG_64BIT66callee_save67ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */68STREG %r27, -1*REG_SZ(%sp)69STREG %r29, -2*REG_SZ(%sp)70#endif71STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */72copy %arg0, %sp /* adopt the real-mode SP */7374/* save iodc_fn */75copy %arg2, %r317677/* load up the arg registers from the saved arg area */78/* 32-bit calling convention passes first 4 args in registers */79ldw 0(%arg1), %arg0 /* note overwriting arg0 */80ldw -8(%arg1), %arg281ldw -12(%arg1), %arg382ldw -4(%arg1), %arg1 /* obviously must do this one last! */8384tophys_r1 %sp8586b,l rfi_virt2real,%r287nop8889b,l save_control_regs,%r2 /* modifies r1, r2, r28 */90nop9192#ifdef CONFIG_64BIT93rsm PSW_SM_W, %r0 /* go narrow */94#endif9596load32 PA(ric_ret), %r297bv 0(%r31)98nop99ric_ret:100#ifdef CONFIG_64BIT101ssm PSW_SM_W, %r0 /* go wide */102#endif103/* restore CRs before going virtual in case we page fault */104b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */105nop106107b,l rfi_real2virt,%r2108nop109110tovirt_r1 %sp111LDREG -REG_SZ(%sp), %sp /* restore SP */112#ifdef CONFIG_64BIT113LDREG -1*REG_SZ(%sp), %r27114LDREG -2*REG_SZ(%sp), %r29115ldo -2*REG_SZ(%sp), %sp116callee_rest117#endif118LDREG -RP_OFFSET(%sp), %rp /* restore RP */119bv 0(%rp)120nop121ENDPROC(real32_call_asm)122123124# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where)125# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r126127.text128save_control_regs:129load32 PA(save_cr_space), %r28130PUSH_CR(%cr24, %r28)131PUSH_CR(%cr25, %r28)132PUSH_CR(%cr26, %r28)133PUSH_CR(%cr27, %r28)134PUSH_CR(%cr28, %r28)135PUSH_CR(%cr29, %r28)136PUSH_CR(%cr30, %r28)137PUSH_CR(%cr31, %r28)138PUSH_CR(%cr15, %r28)139bv 0(%r2)140nop141142restore_control_regs:143load32 PA(save_cr_end), %r26144POP_CR(%cr15, %r26)145POP_CR(%cr31, %r26)146POP_CR(%cr30, %r26)147POP_CR(%cr29, %r26)148POP_CR(%cr28, %r26)149POP_CR(%cr27, %r26)150POP_CR(%cr26, %r26)151POP_CR(%cr25, %r26)152POP_CR(%cr24, %r26)153bv 0(%r2)154nop155156/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for157* more general-purpose use by the several places which need RFIs158*/159.text160.align 128161rfi_virt2real:162/* switch to real mode... */163rsm PSW_SM_I,%r0164load32 PA(rfi_v2r_1), %r1165nop166nop167nop168nop169nop170171rsm PSW_SM_Q,%r0 /* disable Q & I bits to load iia queue */172mtctl %r0, %cr17 /* Clear IIASQ tail */173mtctl %r0, %cr17 /* Clear IIASQ head */174mtctl %r1, %cr18 /* IIAOQ head */175ldo 4(%r1), %r1176mtctl %r1, %cr18 /* IIAOQ tail */177load32 REAL_MODE_PSW, %r1178mtctl %r1, %cr22179rfi180181nop182nop183nop184nop185nop186nop187nop188nop189rfi_v2r_1:190tophys_r1 %r2191bv 0(%r2)192nop193194.text195.align 128196rfi_real2virt:197rsm PSW_SM_I,%r0198load32 (rfi_r2v_1), %r1199nop200nop201nop202nop203nop204205rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */206mtctl %r0, %cr17 /* Clear IIASQ tail */207mtctl %r0, %cr17 /* Clear IIASQ head */208mtctl %r1, %cr18 /* IIAOQ head */209ldo 4(%r1), %r1210mtctl %r1, %cr18 /* IIAOQ tail */211load32 KERNEL_PSW, %r1212mtctl %r1, %cr22213rfi214215nop216nop217nop218nop219nop220nop221nop222nop223rfi_r2v_1:224tovirt_r1 %r2225bv 0(%r2)226nop227228#ifdef CONFIG_64BIT229230/************************ 64-bit real-mode calls ***********************/231/* This is only usable in wide kernels right now and will probably stay so */232.text233/* unsigned long real64_call_asm(unsigned long *sp,234* unsigned long *arg0p,235* unsigned long fn)236* sp is value of stack pointer to adopt before calling PDC (virt)237* arg0p points to where saved arg values may be found238* iodc_fn is the IODC function to call239*/240ENTRY(real64_call_asm)241std %rp, -0x10(%sp) /* save RP */242std %sp, -8(%arg0) /* save SP on real-mode stack */243copy %arg0, %sp /* adopt the real-mode SP */244245/* save fn */246copy %arg2, %r31247248/* set up the new ap */249ldo 64(%arg1), %r29250251/* load up the arg registers from the saved arg area */252/* 32-bit calling convention passes first 4 args in registers */253ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */254ldd 2*REG_SZ(%arg1), %arg2255ldd 3*REG_SZ(%arg1), %arg3256ldd 4*REG_SZ(%arg1), %r22257ldd 5*REG_SZ(%arg1), %r21258ldd 6*REG_SZ(%arg1), %r20259ldd 7*REG_SZ(%arg1), %r19260ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */261262tophys_r1 %sp263264b,l rfi_virt2real,%r2265nop266267b,l save_control_regs,%r2 /* modifies r1, r2, r28 */268nop269270load32 PA(r64_ret), %r2271bv 0(%r31)272nop273r64_ret:274/* restore CRs before going virtual in case we page fault */275b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */276nop277278b,l rfi_real2virt,%r2279nop280281tovirt_r1 %sp282ldd -8(%sp), %sp /* restore SP */283ldd -0x10(%sp), %rp /* restore RP */284bv 0(%rp)285nop286ENDPROC(real64_call_asm)287288#endif289290.text291/* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html292** GCC 3.3 and later has a new function in libgcc.a for293** comparing function pointers.294*/295ENTRY(__canonicalize_funcptr_for_compare)296#ifdef CONFIG_64BIT297bve (%r2)298#else299bv %r0(%r2)300#endif301copy %r26,%r28302ENDPROC(__canonicalize_funcptr_for_compare)303304305306