On Sat, Dec 25, 2010 at 12:02:58PM -0800, Philip Guenther wrote: > Here's a revised diff to correct the handling on amd64 and i386 of the > MXCSR register in frames that could be altered by users, so that a user > can't trick the kernel into faulting by trying to load an invalid MXCSR > value during the return to userspace. > > Originally worked out by joshe@; this corrects the timing of the call to > fpuinit() for the primary CPU on amd64 so that the saved mask value is > initialized correctly. It also uniformly uses > __attribute__((aligned(16))) do get a buffer of the correct alignment. > > I've been using this on amd64 for a while and have confirmed that a test > program which previous crashed the box now continues just fine. I'm away > from my i386 test box so we could use confirmation from someone running an > i386 that shows FXSR in the cpu0 flags list. > > ok? > > > Philip Guenther > > Index: sys/arch/amd64/amd64/cpu.c > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/amd64/cpu.c,v > retrieving revision 1.40 > diff -u -p -r1.40 cpu.c > --- sys/arch/amd64/amd64/cpu.c 27 Nov 2010 13:03:04 -0000 1.40 > +++ sys/arch/amd64/amd64/cpu.c 25 Dec 2010 19:38:48 -0000 > @@ -365,6 +365,8 @@ cpu_attach(struct device *parent, struct > void > cpu_init(struct cpu_info *ci) > { > + fpuinit(ci); > + > /* configure the CPU if needed */ > if (ci->cpu_setup != NULL) > (*ci->cpu_setup)(ci); > @@ -509,7 +511,6 @@ cpu_hatch(void *v) > cpu_init_idt(); > lapic_set_lvt(); > gdt_init_cpu(ci); > - fpuinit(ci); > > lldt(0); > > Index: sys/arch/amd64/amd64/fpu.c > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/amd64/fpu.c,v > retrieving revision 1.21 > diff -u -p -r1.21 fpu.c > --- sys/arch/amd64/amd64/fpu.c 29 Sep 2010 15:11:31 -0000 1.21 > +++ sys/arch/amd64/amd64/fpu.c 25 Dec 2010 19:38:48 -0000 > @@ -95,6 +95,8 @@ > void fpudna(struct cpu_info *); > static int x86fpflags_to_siginfo(u_int32_t); > > +uint32_t fpu_mxcsr_mask; > + > /* > * Init the FPU. > */ > @@ -103,6 +105,16 @@ fpuinit(struct cpu_info *ci) > { > lcr0(rcr0() & ~(CR0_EM|CR0_TS)); > fninit(); > + if (CPU_IS_PRIMARY(ci)) { > + struct fxsave64 fx __attribute__((aligned(16))); > + > + bzero(&fx, sizeof(fx)); > + fxsave(&fx); > + if (fx.fx_mxcsr_mask) > + fpu_mxcsr_mask = fx.fx_mxcsr_mask; > + else > + fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__; > + } > lcr0(rcr0() | (CR0_TS)); > } > > Index: sys/arch/amd64/amd64/machdep.c > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v > retrieving revision 1.129 > diff -u -p -r1.129 machdep.c > --- sys/arch/amd64/amd64/machdep.c 22 Nov 2010 21:07:16 -0000 1.129 > +++ sys/arch/amd64/amd64/machdep.c 25 Dec 2010 19:38:49 -0000 > @@ -658,9 +658,11 @@ sys_sigreturn(struct proc *p, void *v, r > fpusave_proc(p, 0); > > if (ksc.sc_fpstate) { > - if ((error = copyin(ksc.sc_fpstate, > - &p->p_addr->u_pcb.pcb_savefpu.fp_fxsave, sizeof (struct > fxsave64)))) > + struct fxsave64 *fx = &p->p_addr->u_pcb.pcb_savefpu.fp_fxsave; > + > + if ((error = copyin(ksc.sc_fpstate, fx, sizeof(*fx)))) > return (error); > + fx->fx_mxcsr &= fpu_mxcsr_mask; > p->p_md.md_flags |= MDP_USEDFPU; > } > > Index: sys/arch/amd64/amd64/process_machdep.c > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/amd64/process_machdep.c,v > retrieving revision 1.9 > diff -u -p -r1.9 process_machdep.c > --- sys/arch/amd64/amd64/process_machdep.c 29 Sep 2010 15:11:31 -0000 > 1.9 > +++ sys/arch/amd64/amd64/process_machdep.c 25 Dec 2010 19:38:50 -0000 > @@ -137,7 +137,7 @@ process_read_fpregs(struct proc *p, stru > frame->fx_fsw = 0x0000; > frame->fx_ftw = 0xff; > frame->fx_mxcsr = __INITIAL_MXCSR__; > - frame->fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; > + frame->fx_mxcsr_mask = fpu_mxcsr_mask; > p->p_md.md_flags |= MDP_USEDFPU; > } > > @@ -198,6 +198,7 @@ process_write_fpregs(struct proc *p, str > } > > memcpy(frame, ®s->fxstate, sizeof(*regs)); > + frame->fx_mxcsr &= fpu_mxcsr_mask; > return (0); > } > > Index: sys/arch/amd64/include/fpu.h > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/include/fpu.h,v > retrieving revision 1.7 > diff -u -p -r1.7 fpu.h > --- sys/arch/amd64/include/fpu.h 20 Nov 2010 20:11:17 -0000 1.7 > +++ sys/arch/amd64/include/fpu.h 25 Dec 2010 19:38:50 -0000 > @@ -49,6 +49,8 @@ struct savefpu { > struct trapframe; > struct cpu_info; > > +extern uint32_t fpu_mxcsr_mask; > + > void fpuinit(struct cpu_info *); > void fpudrop(void); > void fpudiscard(struct proc *); > Index: sys/arch/i386/i386/machdep.c > =================================================================== > RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v > retrieving revision 1.485 > diff -u -p -r1.485 machdep.c > --- sys/arch/i386/i386/machdep.c 2 Oct 2010 23:31:34 -0000 1.485 > +++ sys/arch/i386/i386/machdep.c 25 Dec 2010 19:38:52 -0000 > @@ -2362,9 +2362,11 @@ sys_sigreturn(struct proc *p, void *v, r > npxsave_proc(p, 0); > > if (context.sc_fpstate) { > - if ((error = copyin(context.sc_fpstate, > - &p->p_addr->u_pcb.pcb_savefpu, sizeof (union savefpu)))) > + union savefpu *sfp = &p->p_addr->u_pcb.pcb_savefpu; > + if ((error = copyin(context.sc_fpstate, sfp, sizeof(*sfp)))) > return (error); > + if (i386_use_fxsave) > + sfp->sv_xmm.sv_env.en_mxcsr &= fpu_mxcsr_mask; > p->p_md.md_flags |= MDP_USEDFPU; > } > > Index: sys/arch/i386/i386/process_machdep.c > =================================================================== > RCS file: /cvs/src/sys/arch/i386/i386/process_machdep.c,v > retrieving revision 1.25 > diff -u -p -r1.25 process_machdep.c > --- sys/arch/i386/i386/process_machdep.c 29 Sep 2010 15:11:31 -0000 > 1.25 > +++ sys/arch/i386/i386/process_machdep.c 25 Dec 2010 19:38:52 -0000 > @@ -137,6 +137,7 @@ process_fninit_xmm(struct savexmm *sxmm) > memset(sxmm, 0, sizeof(*sxmm)); > sxmm->sv_env.en_cw = __OpenBSD_NPXCW__; > sxmm->sv_env.en_mxcsr = __INITIAL_MXCSR__; > + sxmm->sv_env.en_mxcsr_mask = fpu_mxcsr_mask; > sxmm->sv_env.en_sw = 0x0000; > sxmm->sv_env.en_tw = 0x00; > } > @@ -308,6 +309,7 @@ process_write_fpregs(struct proc *p, str > /* XXX Yuck. */ > memcpy(&s87, regs, sizeof(*regs)); > process_s87_to_xmm(&s87, &frame->sv_xmm); > + frame->sv_xmm.sv_env.en_mxcsr &= fpu_mxcsr_mask; > } else > memcpy(&frame->sv_87, regs, sizeof(*regs)); > > Index: sys/arch/i386/include/npx.h > =================================================================== > RCS file: /cvs/src/sys/arch/i386/include/npx.h,v > retrieving revision 1.15 > diff -u -p -r1.15 npx.h > --- sys/arch/i386/include/npx.h 29 Sep 2010 15:11:31 -0000 1.15 > +++ sys/arch/i386/include/npx.h 25 Dec 2010 19:38:52 -0000 > @@ -96,7 +96,7 @@ struct envxmm { > uint16_t en_fos; /* FPU Data pointer selector */ > uint16_t en_rsvd2; > uint32_t en_mxcsr; /* MXCSR Register State */ > - uint32_t en_rsvd3; > + uint32_t en_mxcsr_mask; /* Mask for valid MXCSR bits (may be 0) */ > }; > > /* FPU regsters in the extended save format. */ > @@ -142,6 +142,7 @@ struct emcsts { > * Set Reference, pg. 3-369. > */ > #define __INITIAL_MXCSR__ 0x1f80 > +#define __INITIAL_MXCSR_MASK__ 0xffbf > > /* > * The standard control word from finit is 0x37F, giving: > @@ -157,6 +158,8 @@ void process_s87_to_xmm(const struct > > struct cpu_info; > struct trapframe; > + > +extern unsigned int fpu_mxcsr_mask; > > void npxinit(struct cpu_info *); > void npxtrap(struct trapframe *); > Index: sys/arch/i386/isa/npx.c > =================================================================== > RCS file: /cvs/src/sys/arch/i386/isa/npx.c,v > retrieving revision 1.53 > diff -u -p -r1.53 npx.c > --- sys/arch/i386/isa/npx.c 29 Sep 2010 15:11:31 -0000 1.53 > +++ sys/arch/i386/isa/npx.c 25 Dec 2010 19:38:52 -0000 > @@ -54,6 +54,7 @@ > > #include <machine/cpu.h> > #include <machine/intr.h> > +#include <machine/lock.h> > #include <machine/npx.h> > #include <machine/pio.h> > #include <machine/cpufunc.h> > @@ -97,6 +98,11 @@ > #define clts() __asm("clts") > #define stts() lcr0(rcr0() | CR0_TS) > > +/* > + * The mxcsr_mask for this host, taken from fxsave() on the primary CPU > + */ > +unsigned int fpu_mxcsr_mask; > + > int npxintr(void *); > static int npxprobe1(struct isa_attach_args *); > static int x86fpflags_to_siginfo(u_int32_t); > @@ -350,6 +356,16 @@ npxinit(struct cpu_info *ci) > i386_fpu_fdivbug = 1; > printf("%s: WARNING: Pentium FDIV bug detected!\n", > ci->ci_dev.dv_xname); > + } > + if (CPU_IS_PRIMARY(ci) && i386_use_fxsave) { > + struct savexmm xm __attribute__((aligned(16))); > + > + bzero(&xm, sizeof(xm)); > + fxsave(&xm); > + if (xm.sv_env.en_mxcsr_mask) > + fpu_mxcsr_mask = xm.sv_env.en_mxcsr_mask; > + else > + fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__; > } > lcr0(rcr0() | (CR0_TS)); > } >
Appears to work (i.e. boot) on both my amd64 and i386 boxes. The latter has FXSR in the cpu0 flags. Just in case I am hallucinating, the i386 dmesg is below. .... Ken OpenBSD 4.8-current (GENERIC.MP) #0: Sun Dec 26 08:56:56 EST 2010 r...@acer.westerback.ca:/usr/src/sys/arch/i386/compile/GENERIC.MP cpu0: Pentium(R) Dual-Core CPU E5400 @ 2.70GHz ("GenuineIntel" 686-class) 2.71 GHz cpu0: FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,SBF,SSE3,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,XSAVE real mem = 2683523072 (2559MB) avail mem = 2629521408 (2507MB) mainbus0 at root bios0 at mainbus0: AT/286+ BIOS, date 10/14/09, SMBIOS rev. 2.6 @ 0x9f400 (38 entries) bios0: vendor American Megatrends Inc. version "P01-A4" date 10/14/2009 bios0: Acer Aspire X1800 acpi0 at bios0: rev 0 acpi0: sleep states S0 S3 S4 S5 acpi0: tables DSDT FACP APIC MCFG SLIC WDRT OEMB HPET NVHD AWMI SSDT acpi0: wakeup devices PS2K(S4) PS2M(S4) NSMB(S4) USB0(S3) USB2(S3) NMAC(S5) P0P1(S4) HDAC(S4) BR10(S4) BR11(S4) BR12(S4) PWRB(S4) acpitimer0 at acpi0: 3579545 Hz, 32 bits acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat cpu0 at mainbus0: apid 0 (boot processor) cpu0: apic clock running at 200MHz cpu1 at mainbus0: apid 1 (application processor) cpu1: Pentium(R) Dual-Core CPU E5400 @ 2.70GHz ("GenuineIntel" 686-class) 2.71 GHz cpu1: FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,SBF,SSE3,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,XSAVE ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 11, 24 pins acpihpet0 at acpi0: 25000000 Hz acpiprt0 at acpi0: bus 0 (PCI0) acpiprt1 at acpi0: bus 1 (P0P1) acpiprt2 at acpi0: bus 2 (BR10) acpiprt3 at acpi0: bus 3 (BR11) acpiprt4 at acpi0: bus 4 (BR12) acpicpu0 at acpi0: PSS acpicpu1 at acpi0: PSS acpitz0 at acpi0: critical temperature 125 degC acpibtn0 at acpi0: PWRB bios0: ROM list: 0xc0000/0xde00 cpu0: Enhanced SpeedStep 2701 MHz: speeds: 2700, 2003, 1603, 1203 MHz pci0 at mainbus0 bus 0: configuration mode 1 (bios) pchb0 at pci0 dev 0 function 0 "NVIDIA MCP73 Host" rev 0xa2 "NVIDIA MCP73 Memory" rev 0xa2 at pci0 dev 0 function 1 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 0 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 1 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 2 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 3 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 4 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 5 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 1 function 6 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 2 function 0 not configured pcib0 at pci0 dev 3 function 0 "NVIDIA MCP73 ISA" rev 0xa2 nviic0 at pci0 dev 3 function 1 "NVIDIA MCP73 SMBus" rev 0xa1 iic0 at nviic0 spdmem0 at iic0 addr 0x50: 2GB DDR2 SDRAM non-parity PC2-6400CL5 spdmem1 at iic0 addr 0x51: 2GB DDR2 SDRAM non-parity PC2-6400CL5 iic1 at nviic0 "eeprom" at iic1 addr 0x55 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 3 function 2 not configured "NVIDIA MCP73 Memory" rev 0xa1 at pci0 dev 3 function 4 not configured ohci0 at pci0 dev 4 function 0 "NVIDIA MCP73 USB" rev 0xa1: apic 2 int 7 (irq 7), version 1.0, legacy support ehci0 at pci0 dev 4 function 1 "NVIDIA MCP73 USB" rev 0xa1: apic 2 int 10 (irq 10) usb0 at ehci0: USB revision 2.0 uhub0 at usb0 "NVIDIA EHCI root hub" rev 2.00/1.00 addr 1 pciide0 at pci0 dev 8 function 0 "NVIDIA MCP73 IDE" rev 0xa1: DMA, channel 0 configured to compatibility, channel 1 configured to compatibility pciide0: channel 0 disabled (no drives) pciide0: channel 1 ignored (disabled) azalia0 at pci0 dev 9 function 0 "NVIDIA MCP73 HD Audio" rev 0xa1: apic 2 int 11 (irq 11) azalia0: codecs: Realtek ALC888, NVIDIA/0x8001, using Realtek ALC888 audio0 at azalia0 ppb0 at pci0 dev 10 function 0 "NVIDIA MCP73 PCIE" rev 0xa1 pci1 at ppb0 bus 1 ppb1 at pci0 dev 11 function 0 "NVIDIA MCP73 PCIE" rev 0xa1 pci2 at ppb1 bus 2 ppb2 at pci0 dev 12 function 0 "NVIDIA MCP73 PCIE" rev 0xa1 pci3 at ppb2 bus 3 ppb3 at pci0 dev 13 function 0 "NVIDIA MCP73 PCIE" rev 0xa1 pci4 at ppb3 bus 4 vendor "VIA", unknown product 0x3403 (class serial bus subclass Firewire, rev 0x00) at pci4 dev 0 function 0 not configured ahci0 at pci0 dev 14 function 0 "NVIDIA MCP73 AHCI" rev 0xa2: apic 2 int 5 (irq 5), AHCI 1.1 scsibus0 at ahci0: 32 targets sd0 at scsibus0 targ 0 lun 0: <ATA, Hitachi HDT72103, ST2O> SCSI3 0/direct fixed sd0: 305245MB, 512 bytes/sec, 625142448 sec total cd0 at scsibus0 targ 1 lun 0: <ATAPI, DVD A DH16AASH, SA15> ATAPI 5/cdrom removable nfe0 at pci0 dev 15 function 0 "NVIDIA MCP73 LAN" rev 0xa2: apic 2 int 7 (irq 7), address 00:25:11:8e:a6:7c rgephy0 at nfe0 phy 3: RTL8169S/8110S PHY, rev. 2 vga1 at pci0 dev 16 function 0 "NVIDIA GeForce 7100" rev 0xa2 wsdisplay0 at vga1 mux 1: console (80x25, vt100 emulation) wsdisplay0: screen 1-5 added (80x25, vt100 emulation) isa0 at pcib0 isadma0 at isa0 com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo pckbc0 at isa0 port 0x60/5 pckbd0 at pckbc0 (kbd slot) pckbc0: using irq 1 for kbd slot wskbd0 at pckbd0: console keyboard, using wsdisplay0 pcppi0 at isa0 port 0x61 spkr0 at pcppi0 it0 at isa0 port 0x2e/2: IT8718F rev 4, EC port 0xa10 npx0 at isa0 port 0xf0/16: reported by CPUID; using exception 16 usb1 at ohci0: USB revision 1.0 uhub1 at usb1 "NVIDIA OHCI root hub" rev 1.00/1.00 addr 1 mtrr: Pentium Pro MTRR support umass0 at uhub0 port 6 configuration 1 interface 0 "Generic Mass Storage Device" rev 2.00/1.00 addr 2 umass0: using SCSI over Bulk-Only scsibus1 at umass0: 2 targets, initiator 0 sd1 at scsibus1 targ 1 lun 0: <Generic-, Compact Flash, 1.01> SCSI0 0/direct removable sd1: drive offline sd2 at scsibus1 targ 1 lun 1: <Multiple, Flash Reader, 1.05> SCSI0 0/direct removable sd2: drive offline uhidev0 at uhub0 port 6 configuration 1 interface 1 "Generic Mass Storage Device" rev 2.00/1.00 addr 2 uhidev0: iclass 3/0, 4 report ids uhid0 at uhidev0 reportid 4: input=7, output=0, feature=0 vscsi0 at root scsibus2 at vscsi0: 256 targets softraid0 at root root on sd0a swap on sd0b dump on sd0b