aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/ia64/hyperprivop.S
diff options
context:
space:
mode:
Diffstat (limited to 'xen/arch/ia64/hyperprivop.S')
-rw-r--r--xen/arch/ia64/hyperprivop.S418
1 files changed, 414 insertions, 4 deletions
diff --git a/xen/arch/ia64/hyperprivop.S b/xen/arch/ia64/hyperprivop.S
index 4c8ebb09fc..6903c66782 100644
--- a/xen/arch/ia64/hyperprivop.S
+++ b/xen/arch/ia64/hyperprivop.S
@@ -14,6 +14,25 @@
#include <asm/system.h>
#include <public/arch-ia64.h>
+#define FAST_HYPERPRIVOP_CNT
+#define FAST_REFLECT_CNT
+
+// Should be included from common header file (also in process.c)
+// NO PSR_CLR IS DIFFERENT! (CPL)
+#define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT)
+#define IA64_PSR_CPL0 (__IA64_UL(1) << IA64_PSR_CPL0_BIT)
+// note IA64_PSR_PK removed from following, why is this necessary?
+#define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \
+ IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \
+ IA64_PSR_IT | IA64_PSR_BN)
+
+#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \
+ IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \
+ IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \
+ IA64_PSR_MC | IA64_PSR_IS | \
+ IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \
+ IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA)
+
// Note: not hand-scheduled for now
// Registers at entry
// r16 == cr.isr
@@ -22,7 +41,13 @@
// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits)
// r31 == pr
GLOBAL_ENTRY(fast_hyperprivop)
- //cover;;
+#if 1
+ // HYPERPRIVOP_SSM_I?
+ // assumes domain interrupts pending, so just do it
+ cmp.eq p7,p6=XEN_HYPER_SSM_I,r17
+(p7) br.sptk.many hyper_ssm_i;;
+#endif
+#if 1
// if domain interrupts pending, give up for now and do it the slow way
adds r20=XSI_PEND_OFS-XSI_PSR_IC_OFS,r18 ;;
ld8 r20=[r20] ;;
@@ -32,11 +57,291 @@ GLOBAL_ENTRY(fast_hyperprivop)
// HYPERPRIVOP_RFI?
cmp.eq p7,p6=XEN_HYPER_RFI,r17
(p7) br.sptk.many hyper_rfi;;
- // if not rfi, give up for now and do it the slow way
+
+// hard to test, because only called from rbs_switch
+ // HYPERPRIVOP_COVER?
+ cmp.eq p7,p6=XEN_HYPER_COVER,r17
+(p7) br.sptk.many hyper_cover;;
+#endif
+
+#if 1
+ // HYPERPRIVOP_SSM_DT?
+ cmp.eq p7,p6=XEN_HYPER_SSM_DT,r17
+(p7) br.sptk.many hyper_ssm_dt;;
+#endif
+
+#if 1
+ // HYPERPRIVOP_RSM_DT?
+ cmp.eq p7,p6=XEN_HYPER_RSM_DT,r17
+(p7) br.sptk.many hyper_rsm_dt;;
+#endif
+
+ // if not one of the above, give up for now and do it the slow way
+ br.sptk.many dispatch_break_fault ;;
+
+
+// give up for now if: ipsr.be==1, ipsr.pp==1
+// from reflect_interruption, don't need to:
+// - printf first extint (debug only)
+// - check for interrupt collection enabled (routine will force on)
+// - set ifa (not valid for extint)
+// - set iha (not valid for extint)
+// - set itir (not valid for extint)
+// DO need to
+// - increment the HYPER_SSM_I fast_hyperprivop counter
+// - set shared_mem iip to instruction after HYPER_SSM_I
+// - set cr.iip to guest iva+0x3000
+// - set shared_mem ipsr to [vcpu_get_ipsr_int_state]
+// be = pp = bn = 0; dt = it = rt = 1; cpl = 3 or 0;
+// i = shared_mem interrupt_delivery_enabled
+// ic = shared_mem interrupt_collection_enabled
+// ri = instruction after HYPER_SSM_I
+// all other bits unchanged from real cr.ipsr
+// - set cr.ipsr (DELIVER_PSR_SET/CLEAR, don't forget cpl!)
+// - set shared_mem isr: isr.ei to instr following HYPER_SSM_I
+// and isr.ri to cr.isr.ri (all other bits zero)
+// - cover and set shared_mem precover_ifs to cr.ifs
+// ^^^ MISSED THIS FOR fast_break??
+// - set shared_mem ifs and incomplete_regframe to 0
+// - set shared_mem interrupt_delivery_enabled to 0
+// - set shared_mem interrupt_collection_enabled to 0
+// - set r31 to SHAREDINFO_ADDR
+// - virtual bank switch 0
+// maybe implement later
+// - verify that there really IS a deliverable interrupt pending
+// - set shared_mem iva
+// needs to be done but not implemented (in reflect_interruption)
+// - set shared_mem iipa
+// don't know for sure
+// - set shared_mem unat
+// r16 == cr.isr
+// r17 == cr.iim
+// r18 == XSI_PSR_IC
+// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits)
+// r31 == pr
+ENTRY(hyper_ssm_i)
+ // give up for now if: ipsr.be==1, ipsr.pp==1
+ mov r30=cr.ipsr;;
+ mov r29=cr.iip;;
+ extr.u r21=r30,IA64_PSR_BE_BIT,1 ;;
+ cmp.ne p7,p0=r21,r0
+(p7) br.sptk.many dispatch_break_fault ;;
+ extr.u r21=r30,IA64_PSR_PP_BIT,1 ;;
+ cmp.ne p7,p0=r21,r0
+(p7) br.sptk.many dispatch_break_fault ;;
+#ifdef FAST_HYPERPRIVOP_CNT
+ movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SSM_I);;
+ ld8 r21=[r20];;
+ adds r21=1,r21;;
+ st8 [r20]=r21;;
+#endif
+ // set shared_mem iip to instruction after HYPER_SSM_I
+ extr.u r20=r30,41,2 ;;
+ cmp.eq p6,p7=2,r20 ;;
+(p6) mov r20=0
+(p6) adds r29=16,r29
+(p7) adds r20=1,r20 ;;
+ dep r30=r20,r30,41,2;; // adjust cr.ipsr.ri but don't save yet
+ adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r29 ;;
+ // set shared_mem isr
+ extr.u r16=r16,38,1;; // grab cr.isr.ir bit
+ dep r16=r16,r0,38,1 ;; // insert into cr.isr (rest of bits zero)
+ dep r16=r20,r16,41,2 ;; // deposit cr.isr.ri
+ adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r16 ;;
+ // set cr.ipsr
+ mov r29=r30 ;;
+ movl r28=DELIVER_PSR_SET;;
+ movl r27=~DELIVER_PSR_CLR;;
+ or r29=r29,r28;;
+ and r29=r29,r27;;
+ mov cr.ipsr=r29;;
+ // set shared_mem ipsr (from ipsr in r30 with ipsr.ri already set)
+ extr.u r29=r30,IA64_PSR_CPL0_BIT,2;;
+ cmp.eq p6,p7=3,r29;;
+(p6) dep r30=-1,r30,IA64_PSR_CPL0_BIT,2
+(p7) dep r30=0,r30,IA64_PSR_CPL0_BIT,2
+ ;;
+ // FOR SSM_I ONLY, also turn on psr.i and psr.ic
+ movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT|IA64_PSR_I|IA64_PSR_IC);;
+ movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN);;
+ or r30=r30,r28;;
+ and r30=r30,r27;;
+ adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r30 ;;
+ // set shared_mem interrupt_delivery_enabled to 0
+ // set shared_mem interrupt_collection_enabled to 0
+ st8 [r18]=r0;;
+ // cover and set shared_mem precover_ifs to cr.ifs
+ // set shared_mem ifs and incomplete_regframe to 0
+ cover ;;
+ mov r20=cr.ifs;;
+ adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st4 [r21]=r0 ;;
+ adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r0 ;;
+ adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r20 ;;
+ // leave cr.ifs alone for later rfi
+ // set iip to go to domain IVA break instruction vector
+ mov r22=IA64_KR(CURRENT);;
+ adds r22=IA64_VCPU_IVA_OFFSET,r22;;
+ ld8 r23=[r22];;
+ movl r24=0x3000;;
+ add r24=r24,r23;;
+ mov cr.iip=r24;;
+ // OK, now all set to go except for switch to virtual bank0
+ mov r30=r2; mov r29=r3;;
+ adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18;
+ adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;;
+ bsw.1;;
+ st8 [r2]=r16,16; st8 [r3]=r17,16 ;;
+ st8 [r2]=r18,16; st8 [r3]=r19,16 ;;
+ st8 [r2]=r20,16; st8 [r3]=r21,16 ;;
+ st8 [r2]=r22,16; st8 [r3]=r23,16 ;;
+ st8 [r2]=r24,16; st8 [r3]=r25,16 ;;
+ st8 [r2]=r26,16; st8 [r3]=r27,16 ;;
+ st8 [r2]=r28,16; st8 [r3]=r29,16 ;;
+ st8 [r2]=r30,16; st8 [r3]=r31,16 ;;
+ movl r31=XSI_IPSR;;
+ bsw.0 ;;
+ mov r2=r30; mov r3=r29;;
+ adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st4 [r20]=r0 ;;
+ mov pr=r31,-1 ;;
+ rfi
+ ;;
+
+// reflect domain breaks directly to domain
+// FIXME: DOES NOT WORK YET
+// r16 == cr.isr
+// r17 == cr.iim
+// r18 == XSI_PSR_IC
+// r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits)
+// r31 == pr
+GLOBAL_ENTRY(fast_break_reflect)
+#define FAST_BREAK
+#ifndef FAST_BREAK
br.sptk.many dispatch_break_fault ;;
+#endif
+ mov r30=cr.ipsr;;
+ mov r29=cr.iip;;
+ extr.u r21=r30,IA64_PSR_BE_BIT,1 ;;
+ cmp.ne p7,p0=r21,r0 ;;
+(p7) br.sptk.many dispatch_break_fault ;;
+ extr.u r21=r30,IA64_PSR_PP_BIT,1 ;;
+ cmp.ne p7,p0=r21,r0 ;;
+(p7) br.sptk.many dispatch_break_fault ;;
+#if 1 /* special handling in case running on simulator */
+ movl r20=first_break;;
+ ld4 r23=[r20];;
+ movl r21=0x80001;
+ movl r22=0x80002;;
+ cmp.ne p7,p0=r23,r0;;
+(p7) br.sptk.many dispatch_break_fault ;;
+ cmp.eq p7,p0=r21,r17;
+(p7) br.sptk.many dispatch_break_fault ;;
+ cmp.eq p7,p0=r22,r17;
+(p7) br.sptk.many dispatch_break_fault ;;
+#endif
+#ifdef FAST_REFLECT_CNT
+ movl r20=fast_reflect_count+((0x2c00>>8)*8);;
+ ld8 r21=[r20];;
+ adds r21=1,r21;;
+ st8 [r20]=r21;;
+#endif
+ // save iim in shared_info
+ adds r21=XSI_IIM_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r17;;
+ // save iip in shared_info (DON'T POINT TO NEXT INSTRUCTION!)
+ adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r29;;
+ // set shared_mem isr
+ adds r21=XSI_ISR_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r16 ;;
+ // set cr.ipsr
+ mov r29=r30 ;;
+ movl r28=DELIVER_PSR_SET;;
+ movl r27=~(DELIVER_PSR_CLR|IA64_PSR_CPL0);;
+ or r29=r29,r28;;
+ and r29=r29,r27;;
+ mov cr.ipsr=r29;;
+ // set shared_mem ipsr (from ipsr in r30 with ipsr.ri already set)
+ extr.u r29=r30,IA64_PSR_CPL0_BIT,2;;
+ cmp.eq p6,p7=3,r29;;
+(p6) dep r30=-1,r30,IA64_PSR_CPL0_BIT,2
+(p7) dep r30=0,r30,IA64_PSR_CPL0_BIT,2
+ ;;
+ movl r28=(IA64_PSR_DT|IA64_PSR_IT|IA64_PSR_RT);;
+ movl r27=~(IA64_PSR_BE|IA64_PSR_PP|IA64_PSR_BN);;
+ or r30=r30,r28;;
+ and r30=r30,r27;;
+ // also set shared_mem ipsr.i and ipsr.ic appropriately
+ ld8 r20=[r18];;
+ extr.u r22=r20,32,32
+ cmp4.eq p6,p7=r20,r0;;
+(p6) dep r30=0,r30,IA64_PSR_IC_BIT,1
+(p7) dep r30=-1,r30,IA64_PSR_IC_BIT,1 ;;
+ cmp4.eq p6,p7=r22,r0;;
+(p6) dep r30=0,r30,IA64_PSR_I_BIT,1
+(p7) dep r30=-1,r30,IA64_PSR_I_BIT,1 ;;
+ adds r21=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r30 ;;
+ // set shared_mem interrupt_delivery_enabled to 0
+ // set shared_mem interrupt_collection_enabled to 0
+ st8 [r18]=r0;;
+ // cover and set shared_mem precover_ifs to cr.ifs
+ // set shared_mem ifs and incomplete_regframe to 0
+ cover ;;
+ mov r20=cr.ifs;;
+ adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st4 [r21]=r0 ;;
+ adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r0 ;;
+ adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st8 [r21]=r20 ;;
+ // vpsr.i = vpsr.ic = 0 on delivery of interruption
+ st8 [r18]=r0;;
+ // FIXME: need to save iipa and isr to be arch-compliant
+ // set iip to go to domain IVA break instruction vector
+ mov r22=IA64_KR(CURRENT);;
+ adds r22=IA64_VCPU_IVA_OFFSET,r22;;
+ ld8 r23=[r22];;
+ movl r24=0x2c00;;
+ add r24=r24,r23;;
+ mov cr.iip=r24;;
+ // OK, now all set to go except for switch to virtual bank0
+ mov r30=r2; mov r29=r3;;
+ adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18;
+ adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;;
+ bsw.1;;
+ st8 [r2]=r16,16; st8 [r3]=r17,16 ;;
+ st8 [r2]=r18,16; st8 [r3]=r19,16 ;;
+ st8 [r2]=r20,16; st8 [r3]=r21,16 ;;
+ st8 [r2]=r22,16; st8 [r3]=r23,16 ;;
+ st8 [r2]=r24,16; st8 [r3]=r25,16 ;;
+ st8 [r2]=r26,16; st8 [r3]=r27,16 ;;
+ st8 [r2]=r28,16; st8 [r3]=r29,16 ;;
+ st8 [r2]=r30,16; st8 [r3]=r31,16 ;;
+ movl r31=XSI_IPSR;;
+ bsw.0 ;;
+ mov r2=r30; mov r3=r29;;
+ adds r20=XSI_BANKNUM_OFS-XSI_PSR_IC_OFS,r18 ;;
+ st4 [r20]=r0 ;;
+ mov pr=r31,-1 ;;
+ rfi
+ ;;
+
// ensure that, if giving up, registers at entry to fast_hyperprivop unchanged
ENTRY(hyper_rfi)
+#ifdef FAST_HYPERPRIVOP_CNT
+ movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_RFI);;
+ ld8 r21=[r20];;
+ adds r21=1,r21;;
+ st8 [r20]=r21;;
+#endif
adds r20=XSI_IPSR_OFS-XSI_PSR_IC_OFS,r18 ;;
ld8 r21=[r20];; // r21 = vcr.ipsr
extr.u r22=r21,IA64_PSR_BE_BIT,1 ;;
@@ -78,8 +383,6 @@ ENTRY(hyper_rfi)
ld8 r20=[r20];;
dep r20=0,r20,38,25;; // ensure ifs has no reserved bits set
mov cr.ifs=r20 ;;
-// TODO: increment a counter so we can count how many rfi's go the fast way
-// but where? counter must be pinned
// ipsr.cpl == (vcr.ipsr.cpl == 0) 2 : 3;
dep r21=-1,r21,IA64_PSR_CPL1_BIT,1 ;;
// vpsr.i = vcr.ipsr.i; vpsr.ic = vcr.ipsr.ic
@@ -101,3 +404,110 @@ ENTRY(hyper_rfi)
;;
rfi
;;
+
+ENTRY(hyper_cover)
+#ifdef FAST_HYPERPRIVOP_CNT
+ movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_COVER);;
+ ld8 r21=[r20];;
+ adds r21=1,r21;;
+ st8 [r20]=r21;;
+#endif
+ mov r24=cr.ipsr
+ mov r25=cr.iip;;
+ // skip test for vpsr.ic.. it's a prerequisite for hyperprivops
+ cover ;;
+ adds r20=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;;
+ mov r30=cr.ifs;;
+ adds r22=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18
+ ld4 r21=[r20] ;;
+ cmp.eq p6,p7=r21,r0 ;;
+(p6) st8 [r22]=r30;;
+(p7) st4 [r20]=r0;;
+ mov cr.ifs=r0;;
+ // adjust return address to skip over break instruction
+ extr.u r26=r24,41,2 ;;
+ cmp.eq p6,p7=2,r26 ;;
+(p6) mov r26=0
+(p6) adds r25=16,r25
+(p7) adds r26=1,r26
+ ;;
+ dep r24=r26,r24,41,2
+ ;;
+ mov cr.ipsr=r24
+ mov cr.iip=r25
+ mov pr=r31,-1 ;;
+ rfi
+ ;;
+
+#if 1
+// return from metaphysical mode (meta=1) to virtual mode (meta=0)
+ENTRY(hyper_ssm_dt)
+#ifdef FAST_HYPERPRIVOP_CNT
+ movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_SSM_DT);;
+ ld8 r21=[r20];;
+ adds r21=1,r21;;
+ st8 [r20]=r21;;
+#endif
+ mov r24=cr.ipsr
+ mov r25=cr.iip;;
+ adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ ld4 r21=[r20];;
+ cmp.eq p7,p0=r21,r0 // meta==0?
+(p7) br.spnt.many 1f ;; // already in virtual mode
+ mov r22=IA64_KR(CURRENT);;
+ adds r22=IA64_VCPU_META_SAVED_RR0_OFFSET,r22;;
+ ld4 r23=[r22];;
+ mov rr[r0]=r23;;
+ srlz.i;;
+ st4 [r20]=r0 ;;
+ // adjust return address to skip over break instruction
+1: extr.u r26=r24,41,2 ;;
+ cmp.eq p6,p7=2,r26 ;;
+(p6) mov r26=0
+(p6) adds r25=16,r25
+(p7) adds r26=1,r26
+ ;;
+ dep r24=r26,r24,41,2
+ ;;
+ mov cr.ipsr=r24
+ mov cr.iip=r25
+ mov pr=r31,-1 ;;
+ rfi
+ ;;
+
+// go to metaphysical mode (meta=1) from virtual mode (meta=0)
+ENTRY(hyper_rsm_dt)
+#ifdef FAST_HYPERPRIVOP_CNT
+ movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_RSM_DT);;
+ ld8 r21=[r20];;
+ adds r21=1,r21;;
+ st8 [r20]=r21;;
+#endif
+ mov r24=cr.ipsr
+ mov r25=cr.iip;;
+ adds r20=XSI_METAPHYS_OFS-XSI_PSR_IC_OFS,r18 ;;
+ ld4 r21=[r20];;
+ cmp.ne p7,p0=r21,r0 // meta==0?
+(p7) br.spnt.many 1f ;; // already in metaphysical mode
+ mov r22=IA64_KR(CURRENT);;
+ adds r22=IA64_VCPU_META_RR0_OFFSET,r22;;
+ ld4 r23=[r22];;
+ mov rr[r0]=r23;;
+ srlz.i;;
+ adds r21=1,r0 ;;
+ st4 [r20]=r21 ;;
+ // adjust return address to skip over break instruction
+1: extr.u r26=r24,41,2 ;;
+ cmp.eq p6,p7=2,r26 ;;
+(p6) mov r26=0
+(p6) adds r25=16,r25
+(p7) adds r26=1,r26
+ ;;
+ dep r24=r26,r24,41,2
+ ;;
+ mov cr.ipsr=r24
+ mov cr.iip=r25
+ mov pr=r31,-1 ;;
+ rfi
+ ;;
+#endif