Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2be29982 authored by Jeremy Fitzhardinge's avatar Jeremy Fitzhardinge Committed by Ingo Molnar
Browse files

x86/paravirt: add sysret/sysexit pvops for returning to 32-bit compatibility userspace



In a 64-bit system, we need separate sysret/sysexit operations to
return to a 32-bit userspace.

Signed-off-by: default avatarJeremy Fitzhardinge <jeremy.fitzhardinge@citirx.com>
Cc: xen-devel <xen-devel@lists.xensource.com>
Cc: Stephen Tweedie <sct@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent c7245da6
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -61,6 +61,19 @@
	CFI_UNDEFINED	r15
	.endm

#ifdef CONFIG_PARAVIRT
ENTRY(native_usergs_sysret32)
	swapgs
	sysretl
ENDPROC(native_usergs_sysret32)

ENTRY(native_irq_enable_sysexit)
	swapgs
	sti
	sysexit
ENDPROC(native_irq_enable_sysexit)
#endif

/*
 * 32bit SYSENTER instruction entry.
 *
@@ -151,10 +164,7 @@ sysenter_do_call:
	CFI_ADJUST_CFA_OFFSET -8
	CFI_REGISTER rsp,rcx
	TRACE_IRQS_ON
	swapgs
	sti		/* sti only takes effect after the next instruction */
	/* sysexit */
	.byte	0xf, 0x35
	ENABLE_INTERRUPTS_SYSEXIT32

sysenter_tracesys:
	CFI_RESTORE_STATE
@@ -254,8 +264,7 @@ cstar_do_call:
	TRACE_IRQS_ON
	movl RSP-ARGOFFSET(%rsp),%esp
	CFI_RESTORE rsp
	swapgs
	sysretl
	USERGS_SYSRET32
	
cstar_tracesys:	
	CFI_RESTORE_STATE
+3 −1
Original line number Diff line number Diff line
@@ -62,7 +62,9 @@ int main(void)
	OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
	OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
	OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
	OFFSET(PV_CPU_usergs_sysret, pv_cpu_ops, usergs_sysret);
	OFFSET(PV_CPU_usergs_sysret32, pv_cpu_ops, usergs_sysret32);
	OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);
	OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
	OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs);
	OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
#endif
+2 −2
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@
#endif	

#ifdef CONFIG_PARAVIRT
ENTRY(native_usergs_sysret)
ENTRY(native_usergs_sysret64)
	swapgs
	sysretq
#endif /* CONFIG_PARAVIRT */
@@ -275,7 +275,7 @@ sysret_check:
	RESTORE_ARGS 0,-ARG_SKIP,1
	/*CFI_REGISTER	rflags,r11*/
	movq	%gs:pda_oldrsp, %rsp
	USERGS_SYSRET
	USERGS_SYSRET64

	CFI_RESTORE_STATE
	/* Handle reschedules */
+7 −5
Original line number Diff line number Diff line
@@ -141,7 +141,8 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
		ret = paravirt_patch_nop();
	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
		 type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret))
		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
		/* If operation requires a jmp, then jmp */
		ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
	else
@@ -193,7 +194,8 @@ static void native_flush_tlb_single(unsigned long addr)
/* These are in entry.S */
extern void native_iret(void);
extern void native_irq_enable_sysexit(void);
extern void native_usergs_sysret(void);
extern void native_usergs_sysret32(void);
extern void native_usergs_sysret64(void);

static int __init print_banner(void)
{
@@ -329,10 +331,10 @@ struct pv_cpu_ops pv_cpu_ops = {
	.write_idt_entry = native_write_idt_entry,
	.load_sp0 = native_load_sp0,

#ifdef CONFIG_X86_32
	.irq_enable_sysexit = native_irq_enable_sysexit,
#else
	.usergs_sysret = native_usergs_sysret,
#ifdef CONFIG_X86_64
	.usergs_sysret32 = native_usergs_sysret32,
	.usergs_sysret64 = native_usergs_sysret64,
#endif
	.iret = native_iret,
	.swapgs = native_swapgs,
+6 −3
Original line number Diff line number Diff line
@@ -14,8 +14,9 @@ DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
DEF_NATIVE(pv_cpu_ops, clts, "clts");
DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");

/* the three commands give us more control to how to return from a syscall */
DEF_NATIVE(pv_cpu_ops, usergs_sysret, "swapgs; sysretq;");
DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "swapgs; sti; sysexit");
DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");

unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
@@ -35,7 +36,9 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
		PATCH_SITE(pv_irq_ops, irq_enable);
		PATCH_SITE(pv_irq_ops, irq_disable);
		PATCH_SITE(pv_cpu_ops, iret);
		PATCH_SITE(pv_cpu_ops, usergs_sysret);
		PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
		PATCH_SITE(pv_cpu_ops, usergs_sysret32);
		PATCH_SITE(pv_cpu_ops, usergs_sysret64);
		PATCH_SITE(pv_cpu_ops, swapgs);
		PATCH_SITE(pv_mmu_ops, read_cr2);
		PATCH_SITE(pv_mmu_ops, read_cr3);
Loading