diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2017-09-18 20:22:42 +0000 | 
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2017-09-18 20:22:42 +0000 | 
| commit | 5efe338f3da0dc100bf37325794a1f2bc422641b (patch) | |
| tree | 04cb3f7b016c3a00235092441fc17910e49790bc | |
| parent | ffa317051b8374cd99b74bdcfa544eb0be764fae (diff) | |
Notes
| -rw-r--r-- | sys/i386/i386/apic_vector.s | 14 | ||||
| -rw-r--r-- | sys/i386/i386/db_trace.c | 3 | ||||
| -rw-r--r-- | sys/i386/i386/exception.s | 72 | ||||
| -rw-r--r-- | sys/i386/i386/locore.s | 41 | ||||
| -rw-r--r-- | sys/i386/i386/machdep.c | 70 | ||||
| -rw-r--r-- | sys/i386/i386/trap.c | 19 | ||||
| -rw-r--r-- | sys/i386/include/md_var.h | 1 | ||||
| -rw-r--r-- | sys/i386/isa/npx.c | 2 | ||||
| -rw-r--r-- | sys/kern/imgact_aout.c | 17 | 
9 files changed, 134 insertions, 105 deletions
diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s index 992fc9278d16d..5a4bc6135ee2a 100644 --- a/sys/i386/i386/apic_vector.s +++ b/sys/i386/i386/apic_vector.s @@ -189,8 +189,7 @@ IDTVEC(xen_intr_upcall)  	SUPERALIGN_TEXT  invltlb_ret:  	call	as_lapic_eoi -	POP_FRAME -	iret +	jmp	doreti  	SUPERALIGN_TEXT  IDTVEC(invltlb) @@ -274,9 +273,7 @@ IDTVEC(cpustop)  	call	as_lapic_eoi  	call	cpustop_handler - -	POP_FRAME -	iret +	jmp	doreti  /*   * Executed by a CPU when it receives an IPI_SUSPEND from another CPU. @@ -290,9 +287,7 @@ IDTVEC(cpususpend)  	call	as_lapic_eoi  	call	cpususpend_handler - -	POP_FRAME -	jmp	doreti_iret +	jmp	doreti  /*   * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU. @@ -314,7 +309,6 @@ IDTVEC(rendezvous)  	call	smp_rendezvous_action  	call	as_lapic_eoi -	POP_FRAME -	iret +	jmp	doreti  #endif /* SMP */ diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c index b4f52d6ec3c62..ce0a7c94682bc 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -326,8 +326,7 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)  		else if (strncmp(name, "Xatpic_intr", 11) == 0 ||  		    strncmp(name, "Xapic_isr", 9) == 0)  			frame_type = INTERRUPT; -		else if (strcmp(name, "Xlcall_syscall") == 0 || -		    strcmp(name, "Xint0x80_syscall") == 0) +		else if (strcmp(name, "Xint0x80_syscall") == 0)  			frame_type = SYSCALL;  		else if (strcmp(name, "dblfault_handler") == 0)  			frame_type = DOUBLE_FAULT; diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s index b905fb1fd635c..cc2f05ad9ac30 100644 --- a/sys/i386/i386/exception.s +++ b/sys/i386/i386/exception.s @@ -98,15 +98,16 @@ MCOUNT_LABEL(user)  MCOUNT_LABEL(btrap)  #define	TRAP(a)		pushl $(a) ; jmp alltraps +#define	TRAP_NOEN(a)	pushl $(a) ; jmp alltraps_noen  IDTVEC(div)  	pushl $0; TRAP(T_DIVIDE)  IDTVEC(dbg) -	pushl $0; TRAP(T_TRCTRAP) +	pushl $0; TRAP_NOEN(T_TRCTRAP)  IDTVEC(nmi) -	pushl $0; TRAP(T_NMI) +	pushl $0; TRAP_NOEN(T_NMI)  IDTVEC(bpt) -	pushl $0; TRAP(T_BPTFLT) +	pushl $0; TRAP_NOEN(T_BPTFLT)  IDTVEC(dtrace_ret)  	pushl $0; TRAP(T_DTRACE_RET)  IDTVEC(ofl) @@ -130,7 +131,7 @@ IDTVEC(stk)  IDTVEC(prot)  	TRAP(T_PROTFLT)  IDTVEC(page) -	TRAP(T_PAGEFLT) +	TRAP_NOEN(T_PAGEFLT)  IDTVEC(mchk)  	pushl $0; TRAP(T_MCHK)  IDTVEC(rsvd) @@ -142,6 +143,21 @@ IDTVEC(align)  IDTVEC(xmm)  	pushl $0; TRAP(T_XMMFLT) +	SUPERALIGN_TEXT +	.globl	alltraps_noen +alltraps_noen: +	pushal +	pushl	$0 +	movw	%ds,(%esp) +	pushl	$0 +	movw	%es,(%esp) +	pushl	$0 +	movw	%fs,(%esp) +	SET_KERNEL_SREGS +	cld +	FAKE_MCOUNT(TF_EIP(%esp)) +	jmp	calltrap +	  	/*  	 * All traps except ones for syscalls jump to alltraps.  If  	 * interrupts were enabled when the trap occurred, then interrupts @@ -164,6 +180,7 @@ alltraps:  	movw	%fs,(%esp)  alltraps_with_regs_pushed:  	SET_KERNEL_SREGS +	sti  	cld  	FAKE_MCOUNT(TF_EIP(%esp))  calltrap: @@ -225,40 +242,6 @@ norm_ill:  #endif  /* - * Call gate entry for syscalls (lcall 7,0). - * This is used by FreeBSD 1.x a.out executables and "old" NetBSD executables. - * - * The intersegment call has been set up to specify one dummy parameter. - * This leaves a place to put eflags so that the call frame can be - * converted to a trap frame. Note that the eflags is (semi-)bogusly - * pushed into (what will be) tf_err and then copied later into the - * final spot. It has to be done this way because esp can't be just - * temporarily altered for the pushfl - an interrupt might come in - * and clobber the saved cs/eip. - */ -	SUPERALIGN_TEXT -IDTVEC(lcall_syscall) -	pushfl				/* save eflags */ -	popl	8(%esp)			/* shuffle into tf_eflags */ -	pushl	$7			/* sizeof "lcall 7,0" */ -	pushl	$0			/* tf_trapno */ -	pushal -	pushl	$0 -	movw	%ds,(%esp) -	pushl	$0 -	movw	%es,(%esp) -	pushl	$0 -	movw	%fs,(%esp) -	SET_KERNEL_SREGS -	cld -	FAKE_MCOUNT(TF_EIP(%esp)) -	pushl	%esp -	call	syscall -	add	$4, %esp -	MEXITCOUNT -	jmp	doreti - -/*   * Trap gate entry for syscalls (int 0x80).   * This is used by FreeBSD ELF executables, "new" NetBSD executables, and all   * Linux executables. @@ -279,6 +262,7 @@ IDTVEC(int0x80_syscall)  	pushl	$0  	movw	%fs,(%esp)  	SET_KERNEL_SREGS +	sti  	cld  	FAKE_MCOUNT(TF_EIP(%esp))  	pushl	%esp @@ -362,7 +346,7 @@ doreti_next:  #ifdef HWPMC_HOOKS  	je	doreti_nmi  #else -	je	doreti_exit +	je	doreti_notvm86  #endif  	/*  	 * PSL_VM must be checked first since segment registers only @@ -378,7 +362,7 @@ doreti_next:  doreti_notvm86:  	testb	$SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */ -	jz	doreti_exit		/* can't handle ASTs now if not */ +	jz	doreti_nosegs		/* can't handle ASTs now if not */  doreti_ast:  	/* @@ -415,6 +399,12 @@ doreti_popl_es:  	.globl	doreti_popl_ds  doreti_popl_ds:  	popl	%ds +	jmp	doreti_iret_popal + +doreti_nosegs: +	MEXITCOUNT +	addl	$12,%esp +doreti_iret_popal:  	popal  	addl	$8,%esp  	.globl	doreti_iret @@ -457,7 +447,7 @@ doreti_nmi:  	 * needs a user call chain capture.  	 */  	testb	$SEL_RPL_MASK,TF_CS(%esp) -	jz	doreti_exit +	jz	doreti_nosegs  	movl	PCPU(CURTHREAD),%eax	/* curthread present? */  	orl	%eax,%eax  	jz	doreti_exit diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s index 44c3c86a3557a..351d131886674 100644 --- a/sys/i386/i386/locore.s +++ b/sys/i386/i386/locore.s @@ -335,6 +335,44 @@ osigcode:  	pushl	%eax			/* junk to fake return addr. */  	int	$0x80			/* enter kernel with args */  0:	jmp	0b + +/* + * The lcall $7,$0 handler cannot use the call gate that does an + * inter-privilege transition. The reason is that the call gate + * does not disable interrupts, and, before the kernel segment registers + * are loaded, we would have a window where the ring 0 code is + * executed with the wrong segments. + * + * Instead, set LDT descriptor 0 as code segment, which reflects + * the lcall $7,$0 back to ring 3 trampoline.  The trampoline sets up + * the frame for int $0x80. + */ +	ALIGN_TEXT +lcall_tramp: +	cmpl	$SYS_vfork,%eax +	je	1f +	pushl	%ebp +	movl	%esp,%ebp +	pushl	0x24(%ebp) /* arg 6 */ +	pushl	0x20(%ebp) +	pushl	0x1c(%ebp) +	pushl	0x18(%ebp) +	pushl	0x14(%ebp) +	pushl	0x10(%ebp) /* arg 1 */ +	subl	$4,%esp   /* gap */ +	int	$0x80 +	leavel +	lretl +1: +	/* +	 * vfork handling is special and relies on the libc stub saving +	 * the return ip in %ecx.  Also, we assume that the call was done +	 * with ucode32 selector in %cs. +	 */ +	int	$0x80 +	movl	$0x33,4(%esp)	/* GUCODE32_SEL | SEL_UPL */ +	movl	%ecx,(%esp) +	lretl  #endif /* COMPAT_43 */  	ALIGN_TEXT @@ -353,6 +391,9 @@ szfreebsd4_sigcode:  	.globl	szosigcode  szosigcode:  	.long	esigcode-osigcode +	.globl	szlcallcode +szlcallcode: +	.long	esigcode-lcall_tramp  #endif  	.text diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 9103929219283..4f592cbc2f0a9 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -1513,7 +1513,7 @@ extern inthand_t  #ifdef XENHVM  	IDTVEC(xen_intr_upcall),  #endif -	IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); +	IDTVEC(int0x80_syscall);  #ifdef DDB  /* @@ -2157,7 +2157,9 @@ i386_kdb_init(void)  register_t  init386(int first)  { -	struct gate_descriptor *gdp; +#ifdef COMPAT_43 +	struct segment_descriptor *gdp; +#endif  	int gsel_tss, metadata_missing, x, pa;  	struct pcpu *pc;  	struct xstate_hdr *xhdr; @@ -2246,9 +2248,9 @@ init386(int first)  	/* exceptions */  	for (x = 0; x < NIDT; x++) -		setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, +		setidt(x, &IDTVEC(rsvd), SDT_SYS386IGT, SEL_KPL,  		    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_DE, &IDTVEC(div),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_DE, &IDTVEC(div),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL));  	setidt(IDT_DB, &IDTVEC(dbg),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); @@ -2256,39 +2258,39 @@ init386(int first)  	    GSEL(GCODE_SEL, SEL_KPL));   	setidt(IDT_BP, &IDTVEC(bpt),  SDT_SYS386IGT, SEL_UPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_OF, &IDTVEC(ofl),  SDT_SYS386TGT, SEL_UPL, +	setidt(IDT_OF, &IDTVEC(ofl),  SDT_SYS386IGT, SEL_UPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_BR, &IDTVEC(bnd),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_BR, &IDTVEC(bnd),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_UD, &IDTVEC(ill),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_UD, &IDTVEC(ill),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_NM, &IDTVEC(dna),  SDT_SYS386TGT, SEL_KPL +	setidt(IDT_NM, &IDTVEC(dna),  SDT_SYS386IGT, SEL_KPL  	    , GSEL(GCODE_SEL, SEL_KPL));  	setidt(IDT_DF, 0,  SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL)); -	setidt(IDT_FPUGP, &IDTVEC(fpusegm),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_FPUGP, &IDTVEC(fpusegm),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_TS, &IDTVEC(tss),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_TS, &IDTVEC(tss),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_NP, &IDTVEC(missing),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_NP, &IDTVEC(missing),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_SS, &IDTVEC(stk),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_SS, &IDTVEC(stk),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_GP, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_GP, &IDTVEC(prot),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL));  	setidt(IDT_PF, &IDTVEC(page),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_MF, &IDTVEC(fpu),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_MF, &IDTVEC(fpu),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_AC, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_AC, &IDTVEC(align), SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_MC, &IDTVEC(mchk),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_MC, &IDTVEC(mchk),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_XF, &IDTVEC(xmm), SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_XF, &IDTVEC(xmm), SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); - 	setidt(IDT_SYSCALL, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, + 	setidt(IDT_SYSCALL, &IDTVEC(int0x80_syscall), SDT_SYS386IGT, SEL_UPL,  	    GSEL(GCODE_SEL, SEL_KPL));  #ifdef KDTRACE_HOOKS -	setidt(IDT_DTRACE_RET, &IDTVEC(dtrace_ret), SDT_SYS386TGT, SEL_UPL, +	setidt(IDT_DTRACE_RET, &IDTVEC(dtrace_ret), SDT_SYS386IGT, SEL_UPL,  	    GSEL(GCODE_SEL, SEL_KPL));  #endif  #ifdef XENHVM @@ -2329,9 +2331,9 @@ init386(int first)  	clock_init();  	finishidentcpu();	/* Final stage of CPU initialization */ -	setidt(IDT_UD, &IDTVEC(ill),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_UD, &IDTVEC(ill),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL)); -	setidt(IDT_GP, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_GP, &IDTVEC(prot),  SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL));  	initializecpu();	/* Initialize CPU registers */  	initializecpucache(); @@ -2436,17 +2438,21 @@ init386(int first)  	gdt[GPROC0_SEL].sd.sd_type = SDT_SYS386TSS;	/* clear busy bit */  	ltr(gsel_tss); -	/* make a call gate to reenter kernel with */ -	gdp = &ldt[LSYS5CALLS_SEL].gd; - -	x = (int) &IDTVEC(lcall_syscall); -	gdp->gd_looffset = x; -	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); -	gdp->gd_stkcpy = 1; -	gdp->gd_type = SDT_SYS386CGT; -	gdp->gd_dpl = SEL_UPL; -	gdp->gd_p = 1; -	gdp->gd_hioffset = x >> 16; +#ifdef COMPAT_43 +	/* +	 * Make a code descriptor to emulate lcall $7,$0 with int +	 * $0x80.  sd_hibase and sd_lobase are set after the sigtramp +	 * base in the shared table is known. +	 */ +	gdp = &ldt[LSYS5CALLS_SEL].sd; +	gdp->sd_type = SDT_MEMERA; +	gdp->sd_dpl = SEL_UPL; +	gdp->sd_p = 1; +	gdp->sd_def32 = 1; +	gdp->sd_gran = 1; +	gdp->sd_lolimit = 0xffff; +	gdp->sd_hilimit = 0xf; +#endif  	/* transfer to user mode */ diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 2acdb6cfc4f8e..787929d991676 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -114,8 +114,6 @@ static int trap_pfault(struct trapframe *, int, vm_offset_t);  static void trap_fatal(struct trapframe *, vm_offset_t);  void dblfault_handler(void); -extern inthand_t IDTVEC(lcall_syscall); -  #define MAX_TRAP_MSG		32  static char *trap_msg[] = {  	"",					/*  0 unused */ @@ -629,23 +627,6 @@ user_trctrap_out:  		case T_TRCTRAP:	 /* trace trap */  kernel_trctrap: -			if (frame->tf_eip == (int)IDTVEC(lcall_syscall)) { -				/* -				 * We've just entered system mode via the -				 * syscall lcall.  Continue single stepping -				 * silently until the syscall handler has -				 * saved the flags. -				 */ -				return; -			} -			if (frame->tf_eip == (int)IDTVEC(lcall_syscall) + 1) { -				/* -				 * The syscall handler has now saved the -				 * flags.  Stop single stepping it. -				 */ -				frame->tf_eflags &= ~PSL_T; -				return; -			}  			/*  			 * Ignore debug register trace traps due to  			 * accesses in the user's address space, which diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h index 2ca8c856fdf60..cdcd0406a34af 100644 --- a/sys/i386/include/md_var.h +++ b/sys/i386/include/md_var.h @@ -43,6 +43,7 @@ extern	int	szfreebsd4_sigcode;  #endif  #ifdef COMPAT_43  extern	int	szosigcode; +extern	int	szlcallcode;  #endif  extern	uint32_t *vm_page_dump; diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index 8b27ee7edcabc..5baa576ffee6f 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -237,7 +237,7 @@ npx_probe(void)  	}  	save_idt_npxtrap = idt[IDT_MF]; -	setidt(IDT_MF, probetrap, SDT_SYS386TGT, SEL_KPL, +	setidt(IDT_MF, probetrap, SDT_SYS386IGT, SEL_KPL,  	    GSEL(GCODE_SEL, SEL_KPL));  	/* diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index cbde46b5acdcf..840eb476549a6 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -27,6 +27,8 @@  #include <sys/cdefs.h>  __FBSDID("$FreeBSD$"); +#include "opt_compat.h" +  #include <sys/param.h>  #include <sys/exec.h>  #include <sys/imgact.h> @@ -337,3 +339,18 @@ exec_aout_imgact(struct image_params *imgp)   */  static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };  EXEC_SET(aout, aout_execsw); + +#if defined(__i386__) && defined(COMPAT_43) +static void +exec_init_lcall(void *arg __unused) +{ +	struct segment_descriptor *gdp; +	u_int lcall_addr; + +	gdp = &ldt[LSYS5CALLS_SEL].sd; +	lcall_addr = aout_sysvec.sv_psstrings - szlcallcode; +	gdp->sd_hibase = lcall_addr >> 24; +	gdp->sd_lobase = lcall_addr; +} +SYSINIT(aout, SI_SUB_EXEC + 1, SI_ORDER_ANY, exec_init_lcall, NULL); +#endif  | 
