/*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>1617.export real_stack18.export real64_stack19__PAGE_ALIGNED_BSS20real_stack:21real64_stack:22.block 81922324#define N_SAVED_REGS 925.section .bss26save_cr_space:27.block REG_SZ * N_SAVED_REGS28save_cr_end:293031/************************ 32-bit real-mode calls ***********************/32/* This can be called in both narrow and wide kernels */3334.text3536/* unsigned long real32_call_asm(unsigned int *sp,37* unsigned int *arg0p,38* unsigned int iodc_fn)39* sp is value of stack pointer to adopt before calling PDC (virt)40* arg0p points to where saved arg values may be found41* iodc_fn is the IODC function to call42*/4344ENTRY_CFI(real32_call_asm)45STREG %rp, -RP_OFFSET(%sp) /* save RP */46#ifdef CONFIG_64BIT47callee_save48ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */49STREG %r27, -1*REG_SZ(%sp)50STREG %r29, -2*REG_SZ(%sp)51#endif52STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */53copy %arg0, %sp /* adopt the real-mode SP */5455/* save iodc_fn */56copy %arg2, %r315758/* load up the arg registers from the saved arg area */59/* 32-bit calling convention passes first 4 args in registers */60ldw 0(%arg1), %arg0 /* note overwriting arg0 */61ldw -8(%arg1), %arg262ldw -12(%arg1), %arg363ldw -4(%arg1), %arg1 /* obviously must do this one last! */6465tophys_r1 %sp6667b,l rfi_virt2real,%r268nop6970b,l save_control_regs,%r2 /* modifies r1, r2, r28 */71nop7273#ifdef CONFIG_64BIT74rsm PSW_SM_W, %r0 /* go narrow */75#endif7677load32 PA(ric_ret), %r278bv 0(%r31)79nop80ric_ret:81#ifdef CONFIG_64BIT82ssm PSW_SM_W, %r0 /* go wide */83#endif84/* restore CRs before going virtual in case we page fault */85b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */86nop8788b,l rfi_real2virt,%r289nop9091tovirt_r1 %sp92LDREG -REG_SZ(%sp), %sp /* restore SP */93#ifdef CONFIG_64BIT94LDREG -1*REG_SZ(%sp), %r2795LDREG -2*REG_SZ(%sp), %r2996ldo -2*REG_SZ(%sp), %sp97callee_rest98#endif99LDREG -RP_OFFSET(%sp), %rp /* restore RP */100bv 0(%rp)101nop102ENDPROC_CFI(real32_call_asm)103104105# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where)106# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r107108.text109ENTRY_CFI(save_control_regs)110load32 PA(save_cr_space), %r28111PUSH_CR(%cr24, %r28)112PUSH_CR(%cr25, %r28)113PUSH_CR(%cr26, %r28)114PUSH_CR(%cr27, %r28)115PUSH_CR(%cr28, %r28)116PUSH_CR(%cr29, %r28)117PUSH_CR(%cr30, %r28)118PUSH_CR(%cr31, %r28)119PUSH_CR(%cr15, %r28)120bv 0(%r2)121nop122ENDPROC_CFI(save_control_regs)123124ENTRY_CFI(restore_control_regs)125load32 PA(save_cr_end), %r26126POP_CR(%cr15, %r26)127POP_CR(%cr31, %r26)128POP_CR(%cr30, %r26)129POP_CR(%cr29, %r26)130POP_CR(%cr28, %r26)131POP_CR(%cr27, %r26)132POP_CR(%cr26, %r26)133POP_CR(%cr25, %r26)134POP_CR(%cr24, %r26)135bv 0(%r2)136nop137ENDPROC_CFI(restore_control_regs)138139/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for140* more general-purpose use by the several places which need RFIs141*/142.text143.align 128144ENTRY_CFI(rfi_virt2real)145#if !defined(BOOTLOADER)146/* switch to real mode... */147rsm PSW_SM_I,%r0148load32 PA(rfi_v2r_1), %r1149nop150nop151nop152nop153nop154155rsm PSW_SM_Q,%r0 /* disable Q & I bits to load iia queue */156mtctl %r0, %cr17 /* Clear IIASQ tail */157mtctl %r0, %cr17 /* Clear IIASQ head */158mtctl %r1, %cr18 /* IIAOQ head */159ldo 4(%r1), %r1160mtctl %r1, %cr18 /* IIAOQ tail */161load32 REAL_MODE_PSW, %r1162mtctl %r1, %cr22163rfi164165nop166nop167nop168nop169nop170nop171nop172nop173rfi_v2r_1:174tophys_r1 %r2175#endif /* defined(BOOTLOADER) */176bv 0(%r2)177nop178ENDPROC_CFI(rfi_virt2real)179180.text181.align 128182ENTRY_CFI(rfi_real2virt)183#if !defined(BOOTLOADER)184rsm PSW_SM_I,%r0185load32 (rfi_r2v_1), %r1186nop187nop188nop189nop190nop191192rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */193mtctl %r0, %cr17 /* Clear IIASQ tail */194mtctl %r0, %cr17 /* Clear IIASQ head */195mtctl %r1, %cr18 /* IIAOQ head */196ldo 4(%r1), %r1197mtctl %r1, %cr18 /* IIAOQ tail */198load32 KERNEL_PSW, %r1199mtctl %r1, %cr22200rfi201202nop203nop204nop205nop206nop207nop208nop209nop210rfi_r2v_1:211tovirt_r1 %r2212#endif /* defined(BOOTLOADER) */213bv 0(%r2)214nop215ENDPROC_CFI(rfi_real2virt)216217#ifdef CONFIG_64BIT218219/************************ 64-bit real-mode calls ***********************/220/* This is only usable in wide kernels right now and will probably stay so */221.text222/* unsigned long real64_call_asm(unsigned long *sp,223* unsigned long *arg0p,224* unsigned long fn)225* sp is value of stack pointer to adopt before calling PDC (virt)226* arg0p points to where saved arg values may be found227* iodc_fn is the IODC function to call228*/229ENTRY_CFI(real64_call_asm)230std %rp, -0x10(%sp) /* save RP */231std %sp, -8(%arg0) /* save SP on real-mode stack */232copy %arg0, %sp /* adopt the real-mode SP */233234/* save fn */235copy %arg2, %r31236237/* load up the arg registers from the saved arg area */238/* 32-bit calling convention passes first 4 args in registers */239ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */240ldd 2*REG_SZ(%arg1), %arg2241ldd 3*REG_SZ(%arg1), %arg3242ldd 4*REG_SZ(%arg1), %r22243ldd 5*REG_SZ(%arg1), %r21244ldd 6*REG_SZ(%arg1), %r20245ldd 7*REG_SZ(%arg1), %r19246ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */247248/* set up real-mode stack and real-mode ap */249tophys_r1 %sp250ldo -16(%sp), %r29 /* Reference param save area */251252b,l rfi_virt2real,%r2253nop254255b,l save_control_regs,%r2 /* modifies r1, r2, r28 */256nop257258load32 PA(r64_ret), %r2259bv 0(%r31)260nop261r64_ret:262/* restore CRs before going virtual in case we page fault */263b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */264nop265266b,l rfi_real2virt,%r2267nop268269tovirt_r1 %sp270ldd -8(%sp), %sp /* restore SP */271ldd -0x10(%sp), %rp /* restore RP */272bv 0(%rp)273nop274ENDPROC_CFI(real64_call_asm)275276#endif277278.text279/* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html280** GCC 3.3 and later has a new function in libgcc.a for281** comparing function pointers.282*/283ENTRY_CFI(__canonicalize_funcptr_for_compare)284#ifdef CONFIG_64BIT285bve (%r2)286#else287bv %r0(%r2)288#endif289copy %r26,%r28290ENDPROC_CFI(__canonicalize_funcptr_for_compare)291292293294