diff options
author | marcel <marcel@FreeBSD.org> | 2014-09-06 22:17:54 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2014-09-06 22:17:54 +0000 |
commit | 1e706702bd14e7d6c5f41f15ee0b520bd11c4933 (patch) | |
tree | dc3cc8b693f49ed1f3a8b91f4a332f381d0f4403 /sys/ia64/ia64/machdep.c | |
parent | 52ea0d605b89848405b35ae619de564ae70badb5 (diff) | |
download | FreeBSD-src-1e706702bd14e7d6c5f41f15ee0b520bd11c4933.zip FreeBSD-src-1e706702bd14e7d6c5f41f15ee0b520bd11c4933.tar.gz |
Fix the PCPU access macros. It was found that the PCPU pointer, when
held in register r13, is used outside the bounds of critical_enter()
and critical_exit() by virtue of optimizations performed by the
compiler. The net effect being that address computations of fields
in the PCPU structure could be relative to the PCPU structure of the
CPU on which the address computation was performed and not related
to the CPU that executes the actual load or store operation.
The typical failure mode being that the per-CPU cache of UMA got
corrupted due to accesses from other CPUs.
Adding more volatile decorating to the register expression does not
help. The thinking being that volatile is assumed to work on memory
references and not register references. Thus, the fix is to perform
the address computation using a volatile inline assembly statement.
Additionally, since the reference is fundamentally non-atomic on ia64
by virtue of have a distinct address computation followed by the
actual load or store operation, it is required to wrap the entire
PCPU access in a critical section.
With PCPU_GET and friends requiring curthread now that they're in a
critical section, low-level use of these macros in functions like
cpu_switch() is not possible anymore. Consequently, a second order
set of changes is needed to avoid using PCPU_GET and friends where
curthread is either not set yet, or in the process of being changed.
In those cases, explicit dereferencing of pcpup is needed. In those
cases it is also possible to do that.
This is a direct commit to stable/10.
Approved by: re@ (marius)
Diffstat (limited to 'sys/ia64/ia64/machdep.c')
-rw-r--r-- | sys/ia64/ia64/machdep.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c index 46357d1..e2b26ae 100644 --- a/sys/ia64/ia64/machdep.c +++ b/sys/ia64/ia64/machdep.c @@ -458,7 +458,7 @@ cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx) #ifdef COMPAT_FREEBSD32 ia32_savectx(oldpcb); #endif - if (PCPU_GET(fpcurthread) == old) + if (pcpup->pc_fpcurthread == old) old->td_frame->tf_special.psr |= IA64_PSR_DFH; if (!savectx(oldpcb)) { newpcb = new->td_pcb; @@ -472,13 +472,13 @@ cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx) cpu_spinwait(); #endif - PCPU_SET(curthread, new); + pcpup->pc_curthread = new; #ifdef COMPAT_FREEBSD32 ia32_restorectx(newpcb); #endif - if (PCPU_GET(fpcurthread) == new) + if (pcpup->pc_fpcurthread == new) new->td_frame->tf_special.psr &= ~IA64_PSR_DFH; restorectx(newpcb); /* We should not get here. */ @@ -500,7 +500,7 @@ cpu_throw(struct thread *old __unused, struct thread *new) cpu_spinwait(); #endif - PCPU_SET(curthread, new); + pcpup->pc_curthread = new; #ifdef COMPAT_FREEBSD32 ia32_restorectx(newpcb); @@ -833,7 +833,7 @@ ia64_init(void) pcpu_init(pcpup, 0, sizeof(pcpu0)); dpcpu_init(ia64_physmem_alloc(DPCPU_SIZE, PAGE_SIZE), 0); cpu_pcpu_setup(pcpup, ~0U, ia64_get_lid()); - PCPU_SET(curthread, &thread0); + pcpup->pc_curthread = &thread0; /* * Initialize the console before we print anything out. |