aboutsummaryrefslogtreecommitdiff
path: root/sys/i386
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2017-09-19 17:57:04 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2017-09-19 17:57:04 +0000
commit3cabd93e267a63a27d6098106dcb747ee8bd673c (patch)
tree21fe983a1b971ec64aeb7e245a16eb438097f561 /sys/i386
parent9770475ce768cd06e9e88ea23917971f152ba448 (diff)
downloadsrc-3cabd93e267a63a27d6098106dcb747ee8bd673c.tar.gz
src-3cabd93e267a63a27d6098106dcb747ee8bd673c.zip
Do not do torn writes to active LDTs.
Care must be taken when updating the active LDT, since parallel threads might try to load a segment descriptor which is currently updated. Since the results are undefined, this cannot be ignored by claiming to be an application race. Reviewed by: jhb Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D12413
Notes
Notes: svn path=/head/; revision=323772
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/sys_machdep.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
index 3afed49c7b3b..4236d11a58d6 100644
--- a/sys/i386/i386/sys_machdep.c
+++ b/sys/i386/i386/sys_machdep.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
+#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/pcb.h>
#include <machine/pcb_ext.h>
@@ -546,7 +547,7 @@ i386_set_ldt(td, uap, descs)
struct i386_ldt_args *uap;
union descriptor *descs;
{
- int error = 0, i;
+ int error, i;
int largest_ld;
struct mdproc *mdp = &td->td_proc->p_md;
struct proc_ldt *pldt;
@@ -556,6 +557,7 @@ i386_set_ldt(td, uap, descs)
printf("i386_set_ldt: start=%d num=%d descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
+ error = 0;
if (descs == NULL) {
/* Free descriptors */
@@ -578,9 +580,9 @@ i386_set_ldt(td, uap, descs)
largest_ld = uap->start + uap->num;
if (largest_ld > pldt->ldt_len)
largest_ld = pldt->ldt_len;
- i = largest_ld - uap->start;
- bzero(&((union descriptor *)(pldt->ldt_base))[uap->start],
- sizeof(union descriptor) * i);
+ for (i = uap->start; i < largest_ld; i++)
+ atomic_store_rel_64(&((uint64_t *)(pldt->ldt_base))[i],
+ 0);
mtx_unlock_spin(&dt_lock);
return (0);
}
@@ -702,17 +704,27 @@ again:
static int
i386_set_ldt_data(struct thread *td, int start, int num,
- union descriptor *descs)
+ union descriptor *descs)
{
- struct mdproc *mdp = &td->td_proc->p_md;
- struct proc_ldt *pldt = mdp->md_ldt;
+ struct mdproc *mdp;
+ struct proc_ldt *pldt;
+ uint64_t *dst, *src;
+ int i;
mtx_assert(&dt_lock, MA_OWNED);
- /* Fill in range */
- bcopy(descs,
- &((union descriptor *)(pldt->ldt_base))[start],
- num * sizeof(union descriptor));
+ mdp = &td->td_proc->p_md;
+ pldt = mdp->md_ldt;
+ dst = (uint64_t *)(pldt->ldt_base);
+ src = (uint64_t *)descs;
+
+ /*
+ * Atomic(9) is used only to get 64bit atomic store with
+ * cmpxchg8b when available. There is no op without release
+ * semantic.
+ */
+ for (i = 0; i < num; i++)
+ atomic_store_rel_64(&dst[start + i], src[i]);
return (0);
}