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
[email protected]:/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