Skip to content

Commit 4df8d22

Browse files
Isaku Yamahataaegl
authored andcommitted
[IA64] pvops: paravirtualize entry.S
paravirtualize ia64_swtich_to, ia64_leave_syscall and ia64_leave_kernel. They include sensitive or performance critical privileged instructions so that they need paravirtualization. To paravirtualize them by single source and multi compile they are converted into indirect jump. And define each pv instances. Cc: Keith Owens <[email protected]> Cc: "Dong, Eddie" <[email protected]> Signed-off-by: Isaku Yamahata <[email protected]> Signed-off-by: Tony Luck <[email protected]>
1 parent 498c517 commit 4df8d22

File tree

6 files changed

+183
-44
lines changed

6 files changed

+183
-44
lines changed

arch/ia64/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ obj-$(CONFIG_PCI_MSI) += msi_ia64.o
3636
mca_recovery-y += mca_drv.o mca_drv_asm.o
3737
obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
3838

39-
obj-$(CONFIG_PARAVIRT) += paravirt.o
39+
obj-$(CONFIG_PARAVIRT) += paravirt.o paravirtentry.o
4040

4141
obj-$(CONFIG_IA64_ESI) += esi.o
4242
ifneq ($(CONFIG_IA64_ESI),)

arch/ia64/kernel/entry.S

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
* Patrick O'Rourke <[email protected]>
2323
* 11/07/2000
2424
*/
25+
/*
26+
* Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
27+
* VA Linux Systems Japan K.K.
28+
* pv_ops.
29+
*/
2530
/*
2631
* Global (preserved) predicate usage on syscall entry/exit path:
2732
*
@@ -45,6 +50,7 @@
4550

4651
#include "minstate.h"
4752

53+
#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
4854
/*
4955
* execve() is special because in case of success, we need to
5056
* setup a null register window frame.
@@ -173,14 +179,15 @@ GLOBAL_ENTRY(sys_clone)
173179
mov rp=loc0
174180
br.ret.sptk.many rp
175181
END(sys_clone)
182+
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
176183

177184
/*
178185
* prev_task <- ia64_switch_to(struct task_struct *next)
179186
* With Ingo's new scheduler, interrupts are disabled when this routine gets
180187
* called. The code starting at .map relies on this. The rest of the code
181188
* doesn't care about the interrupt masking status.
182189
*/
183-
GLOBAL_ENTRY(ia64_switch_to)
190+
GLOBAL_ENTRY(__paravirt_switch_to)
184191
.prologue
185192
alloc r16=ar.pfs,1,0,0,0
186193
DO_SAVE_SWITCH_STACK
@@ -204,7 +211,7 @@ GLOBAL_ENTRY(ia64_switch_to)
204211
;;
205212
.done:
206213
ld8 sp=[r21] // load kernel stack pointer of new task
207-
mov IA64_KR(CURRENT)=in0 // update "current" application register
214+
MOV_TO_KR(CURRENT, in0, r8, r9) // update "current" application register
208215
mov r8=r13 // return pointer to previously running task
209216
mov r13=in0 // set "current" pointer
210217
;;
@@ -216,26 +223,25 @@ GLOBAL_ENTRY(ia64_switch_to)
216223
br.ret.sptk.many rp // boogie on out in new context
217224

218225
.map:
219-
rsm psr.ic // interrupts (psr.i) are already disabled here
226+
RSM_PSR_IC(r25) // interrupts (psr.i) are already disabled here
220227
movl r25=PAGE_KERNEL
221228
;;
222229
srlz.d
223230
or r23=r25,r20 // construct PA | page properties
224231
mov r25=IA64_GRANULE_SHIFT<<2
225232
;;
226-
mov cr.itir=r25
227-
mov cr.ifa=in0 // VA of next task...
233+
MOV_TO_ITIR(p0, r25, r8)
234+
MOV_TO_IFA(in0, r8) // VA of next task...
228235
;;
229236
mov r25=IA64_TR_CURRENT_STACK
230-
mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped...
237+
MOV_TO_KR(CURRENT_STACK, r26, r8, r9) // remember last page we mapped...
231238
;;
232239
itr.d dtr[r25]=r23 // wire in new mapping...
233-
ssm psr.ic // reenable the psr.ic bit
234-
;;
235-
srlz.d
240+
SSM_PSR_IC_AND_SRLZ_D(r8, r9) // reenable the psr.ic bit
236241
br.cond.sptk .done
237-
END(ia64_switch_to)
242+
END(__paravirt_switch_to)
238243

244+
#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
239245
/*
240246
* Note that interrupts are enabled during save_switch_stack and load_switch_stack. This
241247
* means that we may get an interrupt with "sp" pointing to the new kernel stack while
@@ -375,7 +381,7 @@ END(save_switch_stack)
375381
* - b7 holds address to return to
376382
* - must not touch r8-r11
377383
*/
378-
ENTRY(load_switch_stack)
384+
GLOBAL_ENTRY(load_switch_stack)
379385
.prologue
380386
.altrp b7
381387

@@ -571,7 +577,7 @@ GLOBAL_ENTRY(ia64_trace_syscall)
571577
.ret3:
572578
(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
573579
(pUStk) rsm psr.i // disable interrupts
574-
br.cond.sptk .work_pending_syscall_end
580+
br.cond.sptk ia64_work_pending_syscall_end
575581

576582
strace_error:
577583
ld8 r3=[r2] // load pt_regs.r8
@@ -636,8 +642,17 @@ GLOBAL_ENTRY(ia64_ret_from_syscall)
636642
adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8
637643
mov r10=r0 // clear error indication in r10
638644
(p7) br.cond.spnt handle_syscall_error // handle potential syscall failure
645+
#ifdef CONFIG_PARAVIRT
646+
;;
647+
br.cond.sptk.few ia64_leave_syscall
648+
;;
649+
#endif /* CONFIG_PARAVIRT */
639650
END(ia64_ret_from_syscall)
651+
#ifndef CONFIG_PARAVIRT
640652
// fall through
653+
#endif
654+
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
655+
641656
/*
642657
* ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't
643658
* need to switch to bank 0 and doesn't restore the scratch registers.
@@ -682,7 +697,7 @@ END(ia64_ret_from_syscall)
682697
* ar.csd: cleared
683698
* ar.ssd: cleared
684699
*/
685-
ENTRY(ia64_leave_syscall)
700+
GLOBAL_ENTRY(__paravirt_leave_syscall)
686701
PT_REGS_UNWIND_INFO(0)
687702
/*
688703
* work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -692,11 +707,11 @@ ENTRY(ia64_leave_syscall)
692707
* extra work. We always check for extra work when returning to user-level.
693708
* With CONFIG_PREEMPT, we also check for extra work when the preempt_count
694709
* is 0. After extra work processing has been completed, execution
695-
* resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check
710+
* resumes at ia64_work_processed_syscall with p6 set to 1 if the extra-work-check
696711
* needs to be redone.
697712
*/
698713
#ifdef CONFIG_PREEMPT
699-
rsm psr.i // disable interrupts
714+
RSM_PSR_I(p0, r2, r18) // disable interrupts
700715
cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall
701716
(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
702717
;;
@@ -706,11 +721,12 @@ ENTRY(ia64_leave_syscall)
706721
;;
707722
cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0)
708723
#else /* !CONFIG_PREEMPT */
709-
(pUStk) rsm psr.i
724+
RSM_PSR_I(pUStk, r2, r18)
710725
cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall
711726
(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
712727
#endif
713-
.work_processed_syscall:
728+
.global __paravirt_work_processed_syscall;
729+
__paravirt_work_processed_syscall:
714730
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
715731
adds r2=PT(LOADRS)+16,r12
716732
(pUStk) mov.m r22=ar.itc // fetch time at leave
@@ -744,7 +760,7 @@ ENTRY(ia64_leave_syscall)
744760
(pNonSys) break 0 // bug check: we shouldn't be here if pNonSys is TRUE!
745761
;;
746762
invala // M0|1 invalidate ALAT
747-
rsm psr.i | psr.ic // M2 turn off interrupts and interruption collection
763+
RSM_PSR_I_IC(r28, r29, r30) // M2 turn off interrupts and interruption collection
748764
cmp.eq p9,p0=r0,r0 // A set p9 to indicate that we should restore cr.ifs
749765

750766
ld8 r29=[r2],16 // M0|1 load cr.ipsr
@@ -765,7 +781,7 @@ ENTRY(ia64_leave_syscall)
765781
;;
766782
#endif
767783
ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs
768-
(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
784+
MOV_FROM_PSR(pKStk, r22, r21) // M2 read PSR now that interrupts are disabled
769785
nop 0
770786
;;
771787
ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // M0|1 load b0
@@ -798,7 +814,7 @@ ENTRY(ia64_leave_syscall)
798814

799815
srlz.d // M0 ensure interruption collection is off (for cover)
800816
shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition
801-
cover // B add current frame into dirty partition & set cr.ifs
817+
COVER // B add current frame into dirty partition & set cr.ifs
802818
;;
803819
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
804820
mov r19=ar.bsp // M2 get new backing store pointer
@@ -823,8 +839,9 @@ ENTRY(ia64_leave_syscall)
823839
mov.m ar.ssd=r0 // M2 clear ar.ssd
824840
mov f11=f0 // F clear f11
825841
br.cond.sptk.many rbs_switch // B
826-
END(ia64_leave_syscall)
842+
END(__paravirt_leave_syscall)
827843

844+
#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
828845
#ifdef CONFIG_IA32_SUPPORT
829846
GLOBAL_ENTRY(ia64_ret_from_ia32_execve)
830847
PT_REGS_UNWIND_INFO(0)
@@ -835,10 +852,20 @@ GLOBAL_ENTRY(ia64_ret_from_ia32_execve)
835852
st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit
836853
.mem.offset 8,0
837854
st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit
855+
#ifdef CONFIG_PARAVIRT
856+
;;
857+
// don't fall through, ia64_leave_kernel may be #define'd
858+
br.cond.sptk.few ia64_leave_kernel
859+
;;
860+
#endif /* CONFIG_PARAVIRT */
838861
END(ia64_ret_from_ia32_execve)
862+
#ifndef CONFIG_PARAVIRT
839863
// fall through
864+
#endif
840865
#endif /* CONFIG_IA32_SUPPORT */
841-
GLOBAL_ENTRY(ia64_leave_kernel)
866+
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
867+
868+
GLOBAL_ENTRY(__paravirt_leave_kernel)
842869
PT_REGS_UNWIND_INFO(0)
843870
/*
844871
* work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -852,7 +879,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
852879
* needs to be redone.
853880
*/
854881
#ifdef CONFIG_PREEMPT
855-
rsm psr.i // disable interrupts
882+
RSM_PSR_I(p0, r17, r31) // disable interrupts
856883
cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel
857884
(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
858885
;;
@@ -862,7 +889,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
862889
;;
863890
cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0)
864891
#else
865-
(pUStk) rsm psr.i
892+
RSM_PSR_I(pUStk, r17, r31)
866893
cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel
867894
(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
868895
#endif
@@ -910,7 +937,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
910937
mov ar.csd=r30
911938
mov ar.ssd=r31
912939
;;
913-
rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection
940+
RSM_PSR_I_IC(r23, r22, r25) // initiate turning off of interrupt and interruption collection
914941
invala // invalidate ALAT
915942
;;
916943
ld8.fill r22=[r2],24
@@ -942,20 +969,20 @@ GLOBAL_ENTRY(ia64_leave_kernel)
942969
mov ar.ccv=r15
943970
;;
944971
ldf.fill f11=[r2]
945-
bsw.0 // switch back to bank 0 (no stop bit required beforehand...)
972+
BSW_0(r2, r3, r15) // switch back to bank 0 (no stop bit required beforehand...)
946973
;;
947974
(pUStk) mov r18=IA64_KR(CURRENT)// M2 (12 cycle read latency)
948975
adds r16=PT(CR_IPSR)+16,r12
949976
adds r17=PT(CR_IIP)+16,r12
950977

951978
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
952979
.pred.rel.mutex pUStk,pKStk
953-
(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
980+
MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled
954981
(pUStk) mov.m r22=ar.itc // M fetch time at leave
955982
nop.i 0
956983
;;
957984
#else
958-
(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
985+
MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled
959986
nop.i 0
960987
nop.i 0
961988
;;
@@ -1027,7 +1054,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
10271054
* NOTE: alloc, loadrs, and cover can't be predicated.
10281055
*/
10291056
(pNonSys) br.cond.dpnt dont_preserve_current_frame
1030-
cover // add current frame into dirty partition and set cr.ifs
1057+
COVER // add current frame into dirty partition and set cr.ifs
10311058
;;
10321059
mov r19=ar.bsp // get new backing store pointer
10331060
rbs_switch:
@@ -1130,16 +1157,16 @@ skip_rbs_switch:
11301157
(pKStk) dep r29=r22,r29,21,1 // I0 update ipsr.pp with psr.pp
11311158
(pLvSys)mov r16=r0 // A clear r16 for leave_syscall, no-op otherwise
11321159
;;
1133-
mov cr.ipsr=r29 // M2
1160+
MOV_TO_IPSR(p0, r29, r25) // M2
11341161
mov ar.pfs=r26 // I0
11351162
(pLvSys)mov r17=r0 // A clear r17 for leave_syscall, no-op otherwise
11361163

1137-
(p9) mov cr.ifs=r30 // M2
1164+
MOV_TO_IFS(p9, r30, r25)// M2
11381165
mov b0=r21 // I0
11391166
(pLvSys)mov r18=r0 // A clear r18 for leave_syscall, no-op otherwise
11401167

11411168
mov ar.fpsr=r20 // M2
1142-
mov cr.iip=r28 // M2
1169+
MOV_TO_IIP(r28, r25) // M2
11431170
nop 0
11441171
;;
11451172
(pUStk) mov ar.rnat=r24 // M2 must happen with RSE in lazy mode
@@ -1148,7 +1175,7 @@ skip_rbs_switch:
11481175

11491176
mov ar.rsc=r27 // M2
11501177
mov pr=r31,-1 // I0
1151-
rfi // B
1178+
RFI // B
11521179

11531180
/*
11541181
* On entry:
@@ -1174,35 +1201,36 @@ skip_rbs_switch:
11741201
;;
11751202
(pKStk) st4 [r20]=r21
11761203
#endif
1177-
ssm psr.i // enable interrupts
1204+
SSM_PSR_I(p0, p6, r2) // enable interrupts
11781205
br.call.spnt.many rp=schedule
11791206
.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 (re-check)
1180-
rsm psr.i // disable interrupts
1207+
RSM_PSR_I(p0, r2, r20) // disable interrupts
11811208
;;
11821209
#ifdef CONFIG_PREEMPT
11831210
(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
11841211
;;
11851212
(pKStk) st4 [r20]=r0 // preempt_count() <- 0
11861213
#endif
1187-
(pLvSys)br.cond.sptk.few .work_pending_syscall_end
1214+
(pLvSys)br.cond.sptk.few __paravirt_pending_syscall_end
11881215
br.cond.sptk.many .work_processed_kernel
11891216

11901217
.notify:
11911218
(pUStk) br.call.spnt.many rp=notify_resume_user
11921219
.ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 (don't re-check)
1193-
(pLvSys)br.cond.sptk.few .work_pending_syscall_end
1220+
(pLvSys)br.cond.sptk.few __paravirt_pending_syscall_end
11941221
br.cond.sptk.many .work_processed_kernel
11951222

1196-
.work_pending_syscall_end:
1223+
.global __paravirt_pending_syscall_end;
1224+
__paravirt_pending_syscall_end:
11971225
adds r2=PT(R8)+16,r12
11981226
adds r3=PT(R10)+16,r12
11991227
;;
12001228
ld8 r8=[r2]
12011229
ld8 r10=[r3]
1202-
br.cond.sptk.many .work_processed_syscall
1203-
1204-
END(ia64_leave_kernel)
1230+
br.cond.sptk.many __paravirt_work_processed_syscall_target
1231+
END(__paravirt_leave_kernel)
12051232

1233+
#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
12061234
ENTRY(handle_syscall_error)
12071235
/*
12081236
* Some system calls (e.g., ptrace, mmap) can return arbitrary values which could
@@ -1244,7 +1272,7 @@ END(ia64_invoke_schedule_tail)
12441272
* We declare 8 input registers so the system call args get preserved,
12451273
* in case we need to restart a system call.
12461274
*/
1247-
ENTRY(notify_resume_user)
1275+
GLOBAL_ENTRY(notify_resume_user)
12481276
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
12491277
alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
12501278
mov r9=ar.unat
@@ -1306,7 +1334,7 @@ ENTRY(sys_rt_sigreturn)
13061334
adds sp=16,sp
13071335
;;
13081336
ld8 r9=[sp] // load new ar.unat
1309-
mov.sptk b7=r8,ia64_leave_kernel
1337+
mov.sptk b7=r8,ia64_native_leave_kernel
13101338
;;
13111339
mov ar.unat=r9
13121340
br.many b7
@@ -1665,3 +1693,4 @@ sys_call_table:
16651693
data8 sys_timerfd_gettime
16661694

16671695
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
1696+
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */

0 commit comments

Comments
 (0)