Add today's advisory and notices.

Approved by:	so
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Gordon Tetlow 2018-06-21 05:37:37 +00:00
parent 5f4afae871
commit 94c673d390
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=51892
8 changed files with 804 additions and 0 deletions

View file

@ -0,0 +1,144 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
=============================================================================
FreeBSD-EN-18:07.pmap Errata Notice
The FreeBSD Project
Topic: Incorrect TLB shootdown for Xen based guests
Category: core
Module: kernel
Announced: 2018-06-21
Credits: Colin Percival
Affects: FreeBSD 11.1
Corrected: 2018-05-22 14:36:46 UTC (stable/11, 11.2-BETA2)
2018-06-21 05:18:08 UTC (releng/11.1, 11.1-RELEASE-p11)
For general information regarding FreeBSD Errata Notices and Security
Advisories, including descriptions of the fields above, security
branches, and the following sections, please visit
<URL:https://security.FreeBSD.org/>.
I. Background
CPUs rely on a Translation Lookaside Buffer (TLB) to cache virtual memory
paging information. When a page is unmapped from the virtual address space
of a process on a multiprocessor system, an Inter-Processor Interrupt (IPI)
may be sent to instruct other CPUs to invalidate ("shoot down") their TLB
entries for the addresses in question.
For virtualization-related performance reasons, FreeBSD has IPI code for the
Xen platform which is separate from the generic x86 IPI code.
II. Problem Description
In the course of changes to the FreeBSD virtual memory system to address
FreeBSD-SA-18:03.speculative_execution, changes were made to the IPIs used
for shooting down TLB entries. Unfortunately, the IPI handlers for Xen were
left non-PTI, even when PTI was enabled, which result in TLB shootdowns for
the user mode portion of the address space not being consistently performed
correctly.
III. Impact
Processes on Xen based guests may "see" pages of memory which were previously
mapped but have since been unmapped, resulted in data being corrupted and/or
processes crashing due to internal data structures becoming inconsistent.
IV. Workaround
Only Xen based guests are affected by this issue. All other platforms are
not susceptible.
For Xen based guests, disabling PTI will workaround the issue. Add the
following line to /boot/loader.conf:
vm.pmap.pti=0
Please be aware, by disabling PTI, the system will be vulnerable to
FreeBSD-SA-18:03.speculative_execution.
V. Solution
Perform one of the following:
1) Upgrade your system to a supported FreeBSD stable or release / security
branch (releng) dated after the correction date.
Afterward, reboot the system.
2) To update your system via a binary patch:
Systems running a RELEASE version of FreeBSD on the i386 or amd64
platforms can be updated via the freebsd-update(8) utility:
# freebsd-update fetch
# freebsd-update install
Afterward, reboot the system.
3) To update your system via a source code patch:
The following patches have been verified to apply to the applicable
FreeBSD release branches.
a) Download the relevant patch from the location below, and verify the
detached PGP signature using your PGP utility.
[FreeBSD 11.1]
# fetch https://security.FreeBSD.org/patches/EN-18:07/pmap.patch
# fetch https://security.FreeBSD.org/patches/EN-18:07/pmap.patch.asc
# gpg --verify pmap.patch.asc
b) Apply the patch. Execute the following commands as root:
# cd /usr/src
# patch < /path/to/patch
c) Recompile your kernel as described in
<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
system.
VI. Correction details
The following list contains the correction revision numbers for each
affected branch.
Branch/path Revision
- -------------------------------------------------------------------------
stable/11/ r334047
releng/11.1/ r335466
- -------------------------------------------------------------------------
To see which files were modified by a particular revision, run the
following command, replacing NNNNNN with the revision number, on a
machine with Subversion installed:
# svn diff -cNNNNNN --summarize svn://svn.freebsd.org/base
Or visit the following URL, replacing NNNNNN with the revision number:
<URL:https://svnweb.freebsd.org/base?view=revision&revision=NNNNNN>
VII. References
The latest revision of this notice is available at
<URL:https://security.FreeBSD.org/advisories/FreeBSD-EN-18:07.pmap.asc>
-----BEGIN PGP SIGNATURE-----
iQKTBAEBCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN3hfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cIOow/+P+zdQ8dmZcEIy7HjYdpTAbPIGNnSdvuXV5O5XGamOziTJOuEEDBxeNiE
QE9VM8a94Ybl0CJZhfBVPhqrDpYuXOqKvnfHlcXWjppDliUPWohF6kTj4ugqGKrl
T2VckEvjltgJQ1/XqnkE7n1LuezLcqF/RbW3xOeRkAhf3X+IXd/E3uCuw/n4yknl
O5EvLmjq3bGlN7OfHOM4E+PHvYOxxfbjYH5S+1Z9g0/apR6HOUi9WU0hV5YEB9Cz
hUCsnx15Nla97jD9P1xy0tr3FkPpvZRJGj2BelNaQoFNrZB7oWB9xwOmwSqxye/b
zvp+/WUuGlo1KWU8RldzVPP6A7piuL6oAvYqW8/wcpwd9HqNGXblWz1XodpE3x1F
TKHTGcP/e/wgU6810SolylwJKxhGVZaQK3UH1iVKPRRTw+HUR1OVDY+q7XAyFD7c
QbKRyWQIYr2X98LhiT8TMVssharFg7AcviRSDEdCYt+A6S9jiDWMe+C3hGndSSET
Cf/0q6PQ89GQKw3lQOgwvtWlMaKPwfg3W8lxkusK5o935aXWhbRee3Hzkld7eUl0
8/uGBCgDnSk7hPIHLDcddIKI+QT0IpHKCPlBRRoTJUhpXo/g5bVkbUnMKBZ7zf3O
mBvci+KPc2yqp///fw1eMhgRTOOOOnXAHUMsb/FH1b+yIcikudo=
=fw9I
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,147 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
=============================================================================
FreeBSD-SA-18:07.lazyfpu Security Advisory
The FreeBSD Project
Topic: Lazy FPU State Restore Information Disclosure
Category: core
Module: kernel
Announced: 2018-06-21
Credits: Julian Stecklina from Amazon Germany
Thomas Prescher from Cyberus Technology GmbH
Zdenek Sojka from SYSGO AG
Colin Percival
Affects: All supported version of FreeBSD.
Corrected: 2018-06-14 18:50:49 UTC (stable/11, 11.2-PRERELEASE)
2018-06-15 13:21:37 UTC (releng/11.2, 11.2-RC3)
2018-06-21 05:17:13 UTC (releng/11.1, 11.1-RELEASE-p11)
CVE Name: CVE-2018-3665
Special Note: This advisory only addresses this issue for FreeBSD 11.x on
i386 and amd64. We expect to update this advisory to include
10.x in the near future.
For general information regarding FreeBSD Security Advisories,
including descriptions of the fields above, security branches, and the
following sections, please visit <URL:https://security.FreeBSD.org/>.
I. Background
Modern CPUs have a floating point unit (FPU) which needs to maintain state
per thread. One technique is to only save and to only restore the FPU state
for a thread when a thread attempts to utilize the FPU. This technique is
called Lazy FPU state restore.
II. Problem Description
A subset of Intel processors can allow a local thread to infer data from
another thread through a speculative execution side channel when Lazy FPU
state restore is used.
III. Impact
Any local thread can potentially read FPU state information from other
threads running on the host. This could include cryptographic keys when the
AES-NI CPU feature is present.
IV. Workaround
No workaround is available, but non-Intel branded CPUs are not believed
to be vulnerable.
V. Solution
The patch changes from Lazy FPU state restore to Eager FPU state restore.
This new technique is the recommended practice from Intel and in some cases
can actually increase performance, depending on workload.
Perform one of the following:
1) Upgrade your vulnerable system to a supported FreeBSD stable or
release / security branch (releng) dated after the correction date.
Afterward, reboot the system.
2) To update your vulnerable system via a binary patch:
Systems running a RELEASE version of FreeBSD on the i386 or amd64
platforms can be updated via the freebsd-update(8) utility:
# freebsd-update fetch
# freebsd-update install
Afterward, reboot the system.
3) To update your vulnerable system via a source code patch:
The following patches have been verified to apply to the applicable
FreeBSD release branches.
a) Download the relevant patch from the location below, and verify the
detached PGP signature using your PGP utility.
[FreeBSD 11.1]
# fetch https://security.FreeBSD.org/patches/SA-18:07/lazyfpu-11.patch
# fetch https://security.FreeBSD.org/patches/SA-18:07/lazyfpu-11.patch.asc
# gpg --verify lazyfpu-11.patch.asc
b) Apply the patch. Execute the following commands as root:
# cd /usr/src
# patch < /path/to/patch
c) Recompile your kernel as described in
<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
system.
VI. Correction details
The following list contains the correction revision numbers for each
affected branch.
Branch/path Revision
- -------------------------------------------------------------------------
stable/11/ r335169
releng/11.2/ r335196
releng/11.1/ r335465
- -------------------------------------------------------------------------
To see which files were modified by a particular revision, run the
following command, replacing NNNNNN with the revision number, on a
machine with Subversion installed:
# svn diff -cNNNNNN --summarize svn://svn.freebsd.org/base
Or visit the following URL, replacing NNNNNN with the revision number:
<URL:https://svnweb.freebsd.org/base?view=revision&revision=NNNNNN>
VII. References
<URL:https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00145.html>
<URL:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3665>
The latest revision of this advisory is available at
<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-18:07.lazyfpu.asc>
-----BEGIN PGP SIGNATURE-----
iQKTBAEBCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN1hfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cJTLA/+Kt7QLkNCVudaiE+d+VMuC2f1aGhqoyd+36xL9rNsn2ShZhIo+gq1dhXn
2lJiOYCPN5cJkasj1YdP2bSIv25nTcFMp0rKOww0A1scOnzi66LAD+DXmGVUhmaA
MPyrnuL7rbuPq9ls9FGAO2XURwB9IrGYtqPuVWmNyn+HyKBYcGCkL5+UEnHeUCg8
oopJudZgrGBVMFCsqG6K/b+3uc397Hyq0PZzpyWFfkaxrbTwVMMwgWyTxIYaPVs7
2g7WK2JWjJNk0IWQGot9qpKYDRyxc9PPFX/0blwOLe1Wwrt5nEF+9av89HQJ6PXF
+Ws5w8Gnhi9wWuK19ew1j0nvP+f0zw09r4GuEzhZXADAz733HNK5dtsS/dMJi2wa
9fQ0s1joT3JFDvWZKUQS2mNuhpvBfYoI0d0OEJT2H2eycFYe4B+VNhB2V1e9wLn6
9X4+Vbc2LEOF09klQQFMYNMEyQzLtfq2gHIoD37sCw9mMrYKWjgy3NhY5AKrfGHG
OcBsvnaXCW/x9/kV9Pfoel/psrmjcQdp4QEKAZbRNwvJG5sGhtsQXTp0Nk+BCuVy
G0NNB9306dLfk0OTZ02SiOUjVagXObyo+LgWTBO6FryDlHVkopsYNkB5oRx9fLrm
68r7OXidl0ndGqnh87meMVH1/Fu/rr09Jd4osIzS+Gc0Dt7NOEQ=
=8fnI
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,78 @@
--- sys/x86/xen/xen_apic.c.orig
+++ sys/x86/xen/xen_apic.c
@@ -41,6 +41,7 @@
#include <machine/cpufunc.h>
#include <machine/cpu.h>
#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
#include <machine/smp.h>
#include <x86/apicreg.h>
@@ -439,6 +440,46 @@
invltlb_pcid_handler();
return (FILTER_HANDLED);
}
+
+static int
+xen_invltlb_invpcid_pti(void *arg)
+{
+
+ invltlb_invpcid_pti_handler();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_invlpg_invpcid_handler(void *arg)
+{
+
+ invlpg_invpcid_handler();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_invlpg_pcid_handler(void *arg)
+{
+
+ invlpg_pcid_handler();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_invlrng_invpcid_handler(void *arg)
+{
+
+ invlrng_invpcid_handler();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_invlrng_pcid_handler(void *arg)
+{
+
+ invlrng_pcid_handler();
+ return (FILTER_HANDLED);
+}
#endif
static int
@@ -529,8 +570,18 @@
#ifdef __amd64__
if (pmap_pcid_enabled) {
- xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = invpcid_works ?
- xen_invltlb_invpcid : xen_invltlb_pcid;
+ if (pti)
+ xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter =
+ invpcid_works ? xen_invltlb_invpcid_pti :
+ xen_invltlb_pcid;
+ else
+ xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter =
+ invpcid_works ? xen_invltlb_invpcid :
+ xen_invltlb_pcid;
+ xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = invpcid_works ?
+ xen_invlpg_invpcid_handler : xen_invlpg_pcid_handler;
+ xen_ipis[IPI_TO_IDX(IPI_INVLRNG)].filter = invpcid_works ?
+ xen_invlrng_invpcid_handler : xen_invlrng_pcid_handler;
}
#endif
CPU_FOREACH(i)

View file

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN4FfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cI6+Q//dTnLur/Dtcz8y2b00OBdUvC1GL3kcFjFhk/fwcvceIdY1m6cC6u6ypxp
Mehewv2YENgLw0fkIu61OsqtyCDmQ+O1LKuFNZpkYqPuiVRvhwAlXTHEWjVHmP8f
52oSgspKxuZbpMKIDIZaQUiH3Ff7BcGIx8ru50wcsfe4dWXD0YJebqkK1etPuUYV
HuMNrqbq7cH8BgBBaRzlAABqz6qeXjLZryyE3bDT4QGEdQPvyrs0muj/TtKzqmZB
axX/V+aClQwnXARQ+EhGxCHDU+OoX4inH1N20+ZPwq7aGTjo0B19Yo/03cV1C7vs
3NDJWKk4oxM6QP1bUIYZ37qlX+WSXH25q8PGtWucd/YdVZR04iXOwC4G1ncmEUWi
1jEj9V7FOBzoLqCGdL2izibemVbKjza5FvODW2gq+Xzbe2F4eube0v12wOiLRED/
mTn71RWsImgzsRvywIsGMkaZCZm4j7gWi53dgBqNteitmw75esM000tcKhy5T5yl
VuxkhttAODFAujz7k4BRpUebzAf0autiRjec6QTHWek5jqD+bM3nGnlPVJMIzQrX
GVibFJga+zrqHhXVXAEKM6QEgcF4nPOlwWOIJ1mBGxomnCM5dKt+Fr1W9lFsurun
w83zqwX12Wz+gUENgBYeAawk9O86KoXC0gqf2pphjPnihN6x7Pc=
=6sV+
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,373 @@
--- sys/amd64/amd64/cpu_switch.S.orig
+++ sys/amd64/amd64/cpu_switch.S
@@ -105,10 +105,10 @@
/* have we used fp, and need a save? */
cmpq %rdi,PCPU(FPCURTHREAD)
- jne 3f
+ jne 2f
movq PCB_SAVEFPU(%r8),%r8
clts
- cmpl $0,use_xsave
+ cmpl $0,use_xsave(%rip)
jne 1f
fxsave (%r8)
jmp 2f
@@ -120,12 +120,7 @@
/* This is patched to xsaveopt if supported, see fpuinit_bsp1() */
xsave (%r8)
movq %rcx,%rdx
-2: smsw %ax
- orb $CR0_TS,%al
- lmsw %ax
- xorl %eax,%eax
- movq %rax,PCPU(FPCURTHREAD)
-3:
+2:
/* Save is done. Now fire up new thread. Leave old vmspace. */
movq %rsi,%r12
movq %rdi,%r13
@@ -212,6 +207,8 @@
movq PCB_RBX(%r8),%rbx
movq PCB_RIP(%r8),%rax
movq %rax,(%rsp)
+ movq PCPU(CURTHREAD),%rdi
+ call fpu_activate_sw
ret
/*
--- sys/amd64/amd64/fpu.c.orig
+++ sys/amd64/amd64/fpu.c
@@ -139,6 +139,11 @@
SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
SYSCTL_NULL_INT_PTR, 1, "Floating point instructions executed in hardware");
+int lazy_fpu_switch = 0;
+SYSCTL_INT(_hw, OID_AUTO, lazy_fpu_switch, CTLFLAG_RWTUN | CTLFLAG_NOFETCH,
+ &lazy_fpu_switch, 0,
+ "Lazily load FPU context after context switch");
+
int use_xsave; /* non-static for cpu_switch.S */
uint64_t xsave_mask; /* the same */
static uma_zone_t fpu_save_area_zone;
@@ -204,6 +209,7 @@
u_int cp[4];
uint64_t xsave_mask_user;
+ TUNABLE_INT_FETCH("hw.lazy_fpu_switch", &lazy_fpu_switch);
if ((cpu_feature2 & CPUID2_XSAVE) != 0) {
use_xsave = 1;
TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
@@ -611,6 +617,45 @@
return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
}
+static void
+restore_fpu_curthread(struct thread *td)
+{
+ struct pcb *pcb;
+
+ /*
+ * Record new context early in case frstor causes a trap.
+ */
+ PCPU_SET(fpcurthread, td);
+
+ stop_emulating();
+ fpu_clean_state();
+ pcb = td->td_pcb;
+
+ if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
+ /*
+ * This is the first time this thread has used the FPU or
+ * the PCB doesn't contain a clean FPU state. Explicitly
+ * load an initial state.
+ *
+ * We prefer to restore the state from the actual save
+ * area in PCB instead of directly loading from
+ * fpu_initialstate, to ignite the XSAVEOPT
+ * tracking engine.
+ */
+ bcopy(fpu_initialstate, pcb->pcb_save,
+ cpu_max_ext_state_size);
+ fpurestore(pcb->pcb_save);
+ if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
+ fldcw(pcb->pcb_initial_fpucw);
+ if (PCB_USER_FPU(pcb))
+ set_pcb_flags(pcb, PCB_FPUINITDONE |
+ PCB_USERFPUINITDONE);
+ else
+ set_pcb_flags(pcb, PCB_FPUINITDONE);
+ } else
+ fpurestore(pcb->pcb_save);
+}
+
/*
* Device Not Available (DNA, #NM) exception handler.
*
@@ -621,7 +666,9 @@
void
fpudna(void)
{
+ struct thread *td;
+ td = curthread;
/*
* This handler is entered with interrupts enabled, so context
* switches may occur before critical_enter() is executed. If
@@ -635,49 +682,38 @@
KASSERT((curpcb->pcb_flags & PCB_FPUNOSAVE) == 0,
("fpudna while in fpu_kern_enter(FPU_KERN_NOCTX)"));
- if (PCPU_GET(fpcurthread) == curthread) {
- printf("fpudna: fpcurthread == curthread\n");
+ if (__predict_false(PCPU_GET(fpcurthread) == td)) {
+ /*
+ * Some virtual machines seems to set %cr0.TS at
+ * arbitrary moments. Silently clear the TS bit
+ * regardless of the eager/lazy FPU context switch
+ * mode.
+ */
stop_emulating();
- critical_exit();
- return;
+ } else {
+ if (__predict_false(PCPU_GET(fpcurthread) != NULL)) {
+ panic(
+ "fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
+ PCPU_GET(fpcurthread),
+ PCPU_GET(fpcurthread)->td_tid, td, td->td_tid);
+ }
+ restore_fpu_curthread(td);
}
- if (PCPU_GET(fpcurthread) != NULL) {
- panic("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
- PCPU_GET(fpcurthread), PCPU_GET(fpcurthread)->td_tid,
- curthread, curthread->td_tid);
- }
- stop_emulating();
- /*
- * Record new context early in case frstor causes a trap.
- */
- PCPU_SET(fpcurthread, curthread);
+ critical_exit();
+}
- fpu_clean_state();
+void fpu_activate_sw(struct thread *td); /* Called from the context switch */
+void
+fpu_activate_sw(struct thread *td)
+{
- if ((curpcb->pcb_flags & PCB_FPUINITDONE) == 0) {
- /*
- * This is the first time this thread has used the FPU or
- * the PCB doesn't contain a clean FPU state. Explicitly
- * load an initial state.
- *
- * We prefer to restore the state from the actual save
- * area in PCB instead of directly loading from
- * fpu_initialstate, to ignite the XSAVEOPT
- * tracking engine.
- */
- bcopy(fpu_initialstate, curpcb->pcb_save,
- cpu_max_ext_state_size);
- fpurestore(curpcb->pcb_save);
- if (curpcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
- fldcw(curpcb->pcb_initial_fpucw);
- if (PCB_USER_FPU(curpcb))
- set_pcb_flags(curpcb,
- PCB_FPUINITDONE | PCB_USERFPUINITDONE);
- else
- set_pcb_flags(curpcb, PCB_FPUINITDONE);
- } else
- fpurestore(curpcb->pcb_save);
- critical_exit();
+ if (lazy_fpu_switch || (td->td_pflags & TDP_KTHREAD) != 0 ||
+ !PCB_USER_FPU(td->td_pcb)) {
+ PCPU_SET(fpcurthread, NULL);
+ start_emulating();
+ } else if (PCPU_GET(fpcurthread) != td) {
+ restore_fpu_curthread(td);
+ }
}
void
--- sys/i386/i386/swtch.s.orig
+++ sys/i386/i386/swtch.s
@@ -293,6 +293,12 @@
cpu_switch_load_gs:
mov PCB_GS(%edx),%gs
+ pushl %edx
+ pushl PCPU(CURTHREAD)
+ call npxswitch
+ popl %edx
+ popl %edx
+
/* Test if debug registers should be restored. */
testl $PCB_DBREGS,PCB_FLAGS(%edx)
jz 1f
--- sys/i386/isa/npx.c.orig
+++ sys/i386/isa/npx.c
@@ -191,6 +191,11 @@
SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
&hw_float, 0, "Floating point instructions executed in hardware");
+int lazy_fpu_switch = 0;
+SYSCTL_INT(_hw, OID_AUTO, lazy_fpu_switch, CTLFLAG_RWTUN | CTLFLAG_NOFETCH,
+ &lazy_fpu_switch, 0,
+ "Lazily load FPU context after context switch");
+
int use_xsave;
uint64_t xsave_mask;
static uma_zone_t fpu_save_area_zone;
@@ -327,6 +332,7 @@
u_int cp[4];
uint64_t xsave_mask_user;
+ TUNABLE_INT_FETCH("hw.lazy_fpu_switch", &lazy_fpu_switch);
if (cpu_fxsr && (cpu_feature2 & CPUID2_XSAVE) != 0) {
use_xsave = 1;
TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
@@ -785,47 +791,20 @@
return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
}
-/*
- * Implement device not available (DNA) exception
- *
- * It would be better to switch FP context here (if curthread != fpcurthread)
- * and not necessarily for every context switch, but it is too hard to
- * access foreign pcb's.
- */
-
-static int err_count = 0;
-
-int
-npxdna(void)
+static void
+restore_npx_curthread(struct thread *td, struct pcb *pcb)
{
- if (!hw_float)
- return (0);
- critical_enter();
- if (PCPU_GET(fpcurthread) == curthread) {
- printf("npxdna: fpcurthread == curthread %d times\n",
- ++err_count);
- stop_emulating();
- critical_exit();
- return (1);
- }
- if (PCPU_GET(fpcurthread) != NULL) {
- printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
- PCPU_GET(fpcurthread),
- PCPU_GET(fpcurthread)->td_proc->p_pid,
- curthread, curthread->td_proc->p_pid);
- panic("npxdna");
- }
- stop_emulating();
/*
* Record new context early in case frstor causes a trap.
*/
- PCPU_SET(fpcurthread, curthread);
+ PCPU_SET(fpcurthread, td);
+ stop_emulating();
if (cpu_fxsr)
fpu_clean_state();
- if ((curpcb->pcb_flags & PCB_NPXINITDONE) == 0) {
+ if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
/*
* This is the first time this thread has used the FPU or
* the PCB doesn't contain a clean FPU state. Explicitly
@@ -836,18 +815,54 @@
* npx_initialstate, to ignite the XSAVEOPT
* tracking engine.
*/
- bcopy(npx_initialstate, curpcb->pcb_save, cpu_max_ext_state_size);
- fpurstor(curpcb->pcb_save);
- if (curpcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
- fldcw(curpcb->pcb_initial_npxcw);
- curpcb->pcb_flags |= PCB_NPXINITDONE;
- if (PCB_USER_FPU(curpcb))
- curpcb->pcb_flags |= PCB_NPXUSERINITDONE;
+ bcopy(npx_initialstate, pcb->pcb_save, cpu_max_ext_state_size);
+ fpurstor(pcb->pcb_save);
+ if (pcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
+ fldcw(pcb->pcb_initial_npxcw);
+ pcb->pcb_flags |= PCB_NPXINITDONE;
+ if (PCB_USER_FPU(pcb))
+ pcb->pcb_flags |= PCB_NPXUSERINITDONE;
} else {
- fpurstor(curpcb->pcb_save);
+ fpurstor(pcb->pcb_save);
}
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (if curthread != fpcurthread)
+ * and not necessarily for every context switch, but it is too hard to
+ * access foreign pcb's.
+ */
+int
+npxdna(void)
+{
+ struct thread *td;
+
+ if (!hw_float)
+ return (0);
+ td = curthread;
+ critical_enter();
+ if (__predict_false(PCPU_GET(fpcurthread) == td)) {
+ /*
+ * Some virtual machines seems to set %cr0.TS at
+ * arbitrary moments. Silently clear the TS bit
+ * regardless of the eager/lazy FPU context switch
+ * mode.
+ */
+ stop_emulating();
+ } else {
+ if (__predict_false(PCPU_GET(fpcurthread) != NULL)) {
+ printf(
+ "npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
+ PCPU_GET(fpcurthread),
+ PCPU_GET(fpcurthread)->td_proc->p_pid,
+ td, td->td_proc->p_pid);
+ panic("npxdna");
+ }
+ restore_npx_curthread(td, td->td_pcb);
+ }
critical_exit();
-
return (1);
}
@@ -869,10 +884,22 @@
xsaveopt((char *)addr, xsave_mask);
else
fpusave(addr);
- start_emulating();
- PCPU_SET(fpcurthread, NULL);
}
+void npxswitch(struct thread *td, struct pcb *pcb);
+void
+npxswitch(struct thread *td, struct pcb *pcb)
+{
+
+ if (lazy_fpu_switch || (td->td_pflags & TDP_KTHREAD) != 0 ||
+ !PCB_USER_FPU(pcb)) {
+ start_emulating();
+ PCPU_SET(fpcurthread, NULL);
+ } else if (PCPU_GET(fpcurthread) != td) {
+ restore_npx_curthread(td, pcb);
+ }
+}
+
/*
* Unconditionally save the current co-processor state across suspend and
* resume.

View file

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN2xfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cJY2Q/+KyfnyHr1YphdZkXYLPTtIKCJasfR1jWSh+6Amr/QDCSvMSvvjvbg6PL0
snVq9108ycrKU7xOBebBQRYNYuS1KlRsjcw396dhpjoVwaoQ5mxuWqeiRbSudy/N
hFuX91E22832j1o4AsovV/vpqTREz0o4BnMrw9fUiZvuhEiPXs3VHoBcn3lCflXf
ubJVptVVCjIK7miVY/oGtvUnzNoSujjNQekpdhHmKyWxU+PrHHhh/kJg+CVEKNr9
IkeJV8w2NkpbXEkf59rMUxoMd4OkxlVlNuoPqWekXBwcLGwd5Uux7GAeI+X8crGA
cim6F8zniozsip7AptQU5e8yQL/mKYsoWpsghASEu1uanvwTjkmu82f3ER7/FX08
0MmhWcSkqGEvKlenQAajCLA7CTzXiMcB3QoCd3VYUmXZOJqcnDAijaDRZ/FMuVJV
wGDFus4cMiDhuC+WJTE699DGmveov3C3N6O65K7KNMdsECFwfP38xzzv+wvjzCbj
JzaYW14YYr5cgsBdL24z0Yl8Pz9vXexiFdPH+VxOaRIHZGMSQqRe0TXG85M8Pv9F
X0tje/gbMMnBpgHui3lUY3x45srRLSn8qt/v/j3W5zoxXINZTDTdqoZT7T9pKWpD
EmWdlLMRDDDvQceXdDebZytM/cMAUf2PS2RtWipSwC4Frqz9eYY=
=dd45
-----END PGP SIGNATURE-----

View file

@ -7,6 +7,19 @@
<year> <year>
<name>2018</name> <name>2018</name>
<month>
<name>6</name>
<day>
<name>21</name>
<advisory>
<name>FreeBSD-SA-18:07.lazyfpu</name>
</advisory>
</day>
</month>
<month> <month>
<name>5</name> <name>5</name>

View file

@ -7,6 +7,19 @@
<year> <year>
<name>2018</name> <name>2018</name>
<month>
<name>6</name>
<day>
<name>21</name>
<notice>
<name>FreeBSD-EN-18:07.pmap</name>
</notice>
</day>
</month>
<month> <month>
<name>5</name> <name>5</name>