diff options
Diffstat (limited to 'sys/amd64/ia32/ia32_sysvec.c')
-rw-r--r-- | sys/amd64/ia32/ia32_sysvec.c | 225 |
1 files changed, 73 insertions, 152 deletions
diff --git a/sys/amd64/ia32/ia32_sysvec.c b/sys/amd64/ia32/ia32_sysvec.c index 18f4ee2fc78c..684677a7cf88 100644 --- a/sys/amd64/ia32/ia32_sysvec.c +++ b/sys/amd64/ia32/ia32_sysvec.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2002 Doug Rabson + * Copyright (c) 2003 Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,6 +27,8 @@ * $FreeBSD$ */ +#include "opt_compat.h" + #define __ELF_WORD_SIZE 32 #include <sys/param.h> @@ -60,12 +63,16 @@ #include <vm/vm_object.h> #include <vm/vm_extern.h> -#include <ia64/ia32/ia32_util.h> -#include <i386/include/psl.h> -#include <i386/include/segments.h> -#include <i386/include/specialreg.h> +#include <amd64/ia32/ia32_util.h> +#include <amd64/ia32/ia32_proto.h> +#include <amd64/ia32/ia32_signal.h> +#include <machine/psl.h> +#include <machine/segments.h> +#include <machine/specialreg.h> #include <machine/frame.h> #include <machine/md_var.h> +#include <machine/pcb.h> +#include <machine/cpufunc.h> static register_t *ia32_copyout_strings(struct image_params *imgp); static void ia32_setregs(struct thread *td, u_long entry, u_long stack, @@ -73,21 +80,6 @@ static void ia32_setregs(struct thread *td, u_long entry, u_long stack, extern struct sysent ia32_sysent[]; -static char ia32_sigcode[] = { - 0xff, 0x54, 0x24, 0x10, /* call *SIGF_HANDLER(%esp) */ - 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC(%esp),%eax */ - 0x50, /* pushl %eax */ - 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x02, /* testl $PSL_VM,UC_EFLAGS(%eax) */ - 0x75, 0x03, /* jne 9f */ - 0x8e, 0x68, 0x14, /* movl UC_GS(%eax),%gs */ - 0xb8, 0x57, 0x01, 0x00, 0x00, /* 9: movl $SYS_sigreturn,%eax */ - 0x50, /* pushl %eax */ - 0xcd, 0x80, /* int $0x80 */ - 0xeb, 0xfe, /* 0: jmp 0b */ - 0, 0, 0, 0 -}; -static int ia32_szsigcode = sizeof(ia32_sigcode) & ~3; - struct sysentvec ia32_freebsd_sysvec = { SYS_MAXSYSCALL, ia32_sysent, @@ -98,24 +90,26 @@ struct sysentvec ia32_freebsd_sysvec = { NULL, NULL, elf32_freebsd_fixup, - sendsig, + ia32_sendsig, ia32_sigcode, - &ia32_szsigcode, + &sz_ia32_sigcode, NULL, - "FreeBSD ELF", + "FreeBSD ELF32", elf32_coredump, NULL, MINSIGSTKSZ, - 4096, + PAGE_SIZE, 0, - IA32_USRSTACK, - IA32_USRSTACK, - IA32_PS_STRINGS, + USRSTACK, + USRSTACK, + PS_STRINGS, VM_PROT_ALL, ia32_copyout_strings, ia32_setregs }; + + static Elf32_Brandinfo ia32_brand_info = { ELFOSABI_FREEBSD, EM_386, @@ -129,6 +123,8 @@ SYSINIT(ia32, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf32_insert_brand_entry, &ia32_brand_info); +extern int _ucode32sel, _udatasel; + static register_t * ia32_copyout_strings(struct image_params *imgp) { @@ -143,7 +139,7 @@ ia32_copyout_strings(struct image_params *imgp) * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. */ - arginfo = (struct ia32_ps_strings *)IA32_PS_STRINGS; + arginfo = (struct ia32_ps_strings *)PS_STRINGS; szsigcode = *(imgp->proc->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - roundup((ARG_MAX - imgp->stringspace), sizeof(char *)); @@ -190,7 +186,6 @@ ia32_copyout_strings(struct image_params *imgp) stringp = imgp->stringbase; argc = imgp->argc; envc = imgp->envc; - /* * Copy out strings - arguments and environment. */ @@ -234,135 +229,61 @@ ia32_copyout_strings(struct image_params *imgp) return ((register_t *)stack_base); } -static void -ia32_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) +/* + * Clear registers on exec + */ +void +ia32_setregs(td, entry, stack, ps_strings) + struct thread *td; + u_long entry; + u_long stack; + u_long ps_strings; { - struct trapframe *frame = td->td_frame; - vm_offset_t gdt, ldt; - u_int64_t codesel, datasel, ldtsel; - u_int64_t codeseg, dataseg, gdtseg, ldtseg; - struct segment_descriptor desc; - struct vmspace *vmspace = td->td_proc->p_vmspace; + struct trapframe *regs = td->td_frame; + struct pcb *pcb = td->td_pcb; + u_int64_t pc; + register_t s; + + wrmsr(MSR_FSBASE, 0); + wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ + pcb->pcb_fsbase = 0; + pcb->pcb_gsbase = 0; + pcb->pcb_kgsbase = rdmsr(MSR_GSBASE); + load_ds(_udatasel); + load_es(_udatasel); + load_fs(_udatasel); + s = intr_disable(); + pc = rdmsr(MSR_GSBASE); + load_gs(_udatasel); /* Clobbers kernel %GS.base */ + wrmsr(MSR_GSBASE, pc); + intr_restore(s); + pcb->pcb_ds = _udatasel; + pcb->pcb_es = _udatasel; + pcb->pcb_fs = _udatasel; + pcb->pcb_gs = _udatasel; + + bzero((char *)regs, sizeof(struct trapframe)); + regs->tf_rip = entry; + regs->tf_rsp = stack; + regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); + regs->tf_ss = _udatasel; + regs->tf_cs = _ucode32sel; + regs->tf_rbx = ps_strings; /* - * Make sure that we restore the entire trapframe after an - * execve. + * Arrange to trap the next npx or `fwait' instruction (see npx.c + * for why fwait must be trapped at least if there is an npx or an + * emulator). This is mainly to handle the case where npx0 is not + * configured, since the npx routines normally set up the trap + * otherwise. It should be done only at boot time, but doing it + * here allows modifying `npx_exists' for testing the emulator on + * systems with an npx. */ - frame->tf_flags &= ~FRAME_SYSCALL; - - bzero(frame->tf_r, sizeof(frame->tf_r)); - bzero(frame->tf_f, sizeof(frame->tf_f)); - - frame->tf_cr_iip = entry; - frame->tf_cr_ipsr = (IA64_PSR_IC - | IA64_PSR_I - | IA64_PSR_IT - | IA64_PSR_DT - | IA64_PSR_RT - | IA64_PSR_DFH - | IA64_PSR_IS - | IA64_PSR_BN - | IA64_PSR_CPL_USER); - frame->tf_r[FRAME_R12] = stack; - - codesel = LSEL(LUCODE_SEL, SEL_UPL); - datasel = LSEL(LUDATA_SEL, SEL_UPL); - ldtsel = GSEL(GLDT_SEL, SEL_UPL); - -#if 1 - frame->tf_r[FRAME_R16] = (datasel << 48) | (datasel << 32) - | (datasel << 16) | datasel; - frame->tf_r[FRAME_R17] = (ldtsel << 32) | (datasel << 16) | codesel; -#else - frame->tf_r[FRAME_R16] = datasel; - frame->tf_r[FRAME_R17] = codesel; - frame->tf_r[FRAME_R18] = datasel; - frame->tf_r[FRAME_R19] = datasel; - frame->tf_r[FRAME_R20] = datasel; - frame->tf_r[FRAME_R21] = datasel; - frame->tf_r[FRAME_R22] = ldtsel; -#endif + load_cr0(rcr0() | CR0_MP | CR0_TS); - /* - * Build the GDT and LDT. - */ - gdt = IA32_USRSTACK; - vm_map_find(&vmspace->vm_map, 0, 0, - &gdt, PAGE_SIZE, 0, - VM_PROT_ALL, VM_PROT_ALL, 0); - ldt = gdt + 4096; - - desc.sd_lolimit = 8*NLDT-1; - desc.sd_lobase = ldt & 0xffffff; - desc.sd_type = SDT_SYSLDT; - desc.sd_dpl = SEL_UPL; - desc.sd_p = 1; - desc.sd_hilimit = 0; - desc.sd_def32 = 0; - desc.sd_gran = 0; - desc.sd_hibase = ldt >> 24; - copyout(&desc, (caddr_t) gdt + 8*GLDT_SEL, sizeof(desc)); - - desc.sd_lolimit = ((IA32_USRSTACK >> 12) - 1) & 0xffff; - desc.sd_lobase = 0; - desc.sd_type = SDT_MEMERA; - desc.sd_dpl = SEL_UPL; - desc.sd_p = 1; - desc.sd_hilimit = ((IA32_USRSTACK >> 12) - 1) >> 16; - desc.sd_def32 = 1; - desc.sd_gran = 1; - desc.sd_hibase = 0; - copyout(&desc, (caddr_t) ldt + 8*LUCODE_SEL, sizeof(desc)); - desc.sd_type = SDT_MEMRWA; - copyout(&desc, (caddr_t) ldt + 8*LUDATA_SEL, sizeof(desc)); - - codeseg = 0 /* base */ - + (((IA32_USRSTACK >> 12) - 1) << 32) /* limit */ - + ((long)SDT_MEMERA << 52) - + ((long)SEL_UPL << 57) - + (1L << 59) /* present */ - + (1L << 62) /* 32 bits */ - + (1L << 63); /* page granularity */ - dataseg = 0 /* base */ - + (((IA32_USRSTACK >> 12) - 1) << 32) /* limit */ - + ((long)SDT_MEMRWA << 52) - + ((long)SEL_UPL << 57) - + (1L << 59) /* present */ - + (1L << 62) /* 32 bits */ - + (1L << 63); /* page granularity */ - ia64_set_csd(codeseg); - ia64_set_ssd(dataseg); - frame->tf_r[FRAME_R24] = dataseg; /* ESD */ - frame->tf_r[FRAME_R27] = dataseg; /* DSD */ - frame->tf_r[FRAME_R28] = dataseg; /* FSD */ - frame->tf_r[FRAME_R29] = dataseg; /* GSD */ - - gdtseg = gdt /* base */ - + ((8L*NGDT - 1) << 32) /* limit */ - + ((long)SDT_SYSNULL << 52) - + ((long)SEL_UPL << 57) - + (1L << 59) /* present */ - + (0L << 62) /* 16 bits */ - + (0L << 63); /* byte granularity */ - ldtseg = ldt /* base */ - + ((8L*NLDT - 1) << 32) /* limit */ - + ((long)SDT_SYSLDT << 52) - + ((long)SEL_UPL << 57) - + (1L << 59) /* present */ - + (0L << 62) /* 16 bits */ - + (0L << 63); /* byte granularity */ - frame->tf_r[FRAME_R30] = ldtseg; /* LDTD */ - frame->tf_r[FRAME_R31] = gdtseg; /* GDTD */ - - ia64_set_eflag(PSL_USER); - - /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */ - frame->tf_r[FRAME_R11] = IA32_PS_STRINGS; + fpstate_drop(td); - /* - * XXX - Linux emulator - * Make sure sure edx is 0x0 on entry. Linux binaries depend - * on it. - */ + /* Return via doreti so that we can change to a different %cs */ + pcb->pcb_flags |= PCB_FULLCTX; td->td_retval[1] = 0; } |