Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152959332
D3617.id8638.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D3617.id8638.diff
View Options
Index: sys/arm/arm/pmap-v6-new.c
===================================================================
--- sys/arm/arm/pmap-v6-new.c
+++ sys/arm/arm/pmap-v6-new.c
@@ -6158,8 +6158,9 @@
* All L1 tables should always be mapped and present.
* However, we check only current one herein. For user mode,
* only permission abort from malicious user is not fatal.
+ * And alignment fault as it may have higher priority.
*/
- if (!usermode || (idx != FAULT_PERM_L2)) {
+ if (!usermode || (idx != FAULT_ALIGN && idx != FAULT_PERM_L2)) {
CTR4(KTR_PMAP, "%s: pmap %#x pm_pt1 %#x far %#x",
__func__, pmap, pmap->pm_pt1, far);
panic("%s: pm_pt1 abort", __func__);
@@ -6172,9 +6173,10 @@
* L1 table. However, only existing L2 tables are mapped
* in PT2MAP. For user mode, only L2 translation abort and
* permission abort from malicious user is not fatal.
+ * And alignment fault as it may have higher priority.
*/
- if (!usermode ||
- (idx != FAULT_TRAN_L2 && idx != FAULT_PERM_L2)) {
+ if (!usermode || (idx != FAULT_ALIGN &&
+ idx != FAULT_TRAN_L2 && idx != FAULT_PERM_L2)) {
CTR4(KTR_PMAP, "%s: pmap %#x PT2MAP %#x far %#x",
__func__, pmap, PT2MAP, far);
panic("%s: PT2MAP abort", __func__);
Index: sys/arm/arm/trap-v6.c
===================================================================
--- sys/arm/arm/trap-v6.c
+++ sys/arm/arm/trap-v6.c
@@ -168,6 +168,17 @@
};
+static __inline int
+read_instruction_nofault(vm_offset_t addr, uint32_t *inst)
+{
+
+ if (!ALIGNED_POINTER(addr, uint32_t) || cp15_ats1cpr_check(addr) != 0)
+ return (EFAULT);
+
+ *inst = *((uint32_t*)addr);
+ return (0);
+}
+
static __inline void
call_trapsignal(struct thread *td, int sig, int code, vm_offset_t addr)
{
@@ -275,7 +286,7 @@
{
struct thread *td;
vm_offset_t far, va;
- int idx, usermode;
+ int idx, usermode, usr_copy_fault;
uint32_t fsr;
struct ksig ksig;
struct proc *p;
@@ -300,8 +311,8 @@
if (usermode)
td->td_frame = tf;
- CTR4(KTR_TRAP, "abort_handler: fsr %#x (idx %u) far %#x prefetch %u",
- fsr, idx, far, prefetch);
+ CTR6(KTR_TRAP, "%s: fsr %#x (idx %u) far %#x prefetch %u user %u",
+ __func__, fsr, idx, far, prefetch, usermode);
/*
* Firstly, handle aborts that are not directly related to mapping.
@@ -316,16 +327,40 @@
return;
}
-#ifdef ARM_NEW_PMAP
- rv = pmap_fault(PCPU_GET(curpmap), far, fsr, idx, usermode);
- if (rv == 0) {
- return;
- } else if (rv == EFAULT) {
+ /*
+ * ARM has a set of unprivileged load and store instructions
+ * (LDRT/LDRBT/STRT/STRBT ...) which are supposed to be used in other
+ * than user mode and OS should recognize their aborts and behave
+ * appropriately. However, there is no way how to do that reasonably
+ * in general unless we restrict the handling somehow.
+ *
+ * Thus, we only handle such cases when these instructions are used
+ * while pcb_onfault is not NULL. This is quite reasonable restriction
+ * as the pcb_onfault is used for quick error handling of access to
+ * user address space done in kernel.
+ */
+ usr_copy_fault = 0;
+ pcb = td->td_pcb;
+ if (__predict_false(!usermode && pcb->pcb_onfault != NULL)) {
+ uint32_t inst;
- call_trapsignal(td, SIGSEGV, SEGV_MAPERR, far);
- userret(td, tf);
- return;
+ /* Read instruction safely to not double abort. */
+ if (read_instruction_nofault(TRAPF_PC(tf), &inst) != 0)
+ panic("%s: bad PC %x", __func__, TRAPF_PC(tf));
+
+ /* LDRT/LDRHT/LDRBT/STRT/STRHT/STRBT instruction? */
+ if ((inst & 0x09200000) == 0x00200000 &&
+ (inst & 0x06000000) != 0x02000000)
+ usr_copy_fault = 1;
}
+
+#ifdef ARM_NEW_PMAP
+ rv = pmap_fault(PCPU_GET(curpmap), far, fsr, idx, usermode ||
+ usr_copy_fault);
+ if (rv == 0)
+ return;
+ if (rv == EFAULT)
+ goto nogo;
#endif
/*
* Now, when we handled imprecise and debug aborts, the rest of
@@ -410,7 +445,6 @@
* Don't pass faulting cache operation to vm_fault(). We don't want
* to handle all vm stuff at this moment.
*/
- pcb = td->td_pcb;
if (__predict_false(pcb->pcb_onfault == cachebailout)) {
tf->tf_r0 = far; /* return failing address */
tf->tf_pc = (register_t)pcb->pcb_onfault;
@@ -435,32 +469,18 @@
*/
/* fusubailout is used by [fs]uswintr to avoid page faulting */
- pcb = td->td_pcb;
if (__predict_false(pcb->pcb_onfault == fusubailout)) {
tf->tf_r0 = EFAULT;
tf->tf_pc = (register_t)pcb->pcb_onfault;
return;
}
- /*
- * QQQ: ARM has a set of unprivileged load and store instructions
- * (LDRT/LDRBT/STRT/STRBT ...) which are supposed to be used
- * in other than user mode and OS should recognize their
- * aborts and behaved appropriately. However, there is no way
- * how to do that reasonably in general unless we restrict
- * the handling somehow. One way is to limit the handling for
- * aborts which come from undefined mode only.
- *
- * Anyhow, we do not use these instructions and do not implement
- * any special handling for them.
- */
-
va = trunc_page(far);
if (va >= KERNBASE) {
/*
* Don't allow user-mode faults in kernel address space.
*/
- if (usermode)
+ if (usermode || usr_copy_fault)
goto nogo;
map = kernel_map;
Index: sys/arm/include/cpu-v6.h
===================================================================
--- sys/arm/include/cpu-v6.h
+++ sys/arm/include/cpu-v6.h
@@ -155,8 +155,9 @@
_RF0(cp15_actlr_get, CP15_ACTLR(%0))
_WF1(cp15_actlr_set, CP15_ACTLR(%0))
#if __ARM_ARCH >= 6
-_WF1(cp15_ats1cpr_set, CP15_ATS1CPR(%0));
-_RF0(cp15_par_get, CP15_PAR);
+_WF1(cp15_ats1cpr_set, CP15_ATS1CPR(%0))
+_WF1(cp15_ats1cpw_set, CP15_ATS1CPW(%0))
+_RF0(cp15_par_get, CP15_PAR(%0))
_RF0(cp15_sctlr_get, CP15_SCTLR(%0))
#endif
@@ -531,6 +532,34 @@
tlb_flush_all_ng_local();
}
+/* Check address for privileged (PL1) read access. */
+static __inline int
+cp15_ats1cpr_check(vm_offset_t addr)
+{
+ register_t par, s;
+
+ s = intr_disable();
+ cp15_ats1cpr_set(addr);
+ isb();
+ par = cp15_par_get();
+ intr_restore(s);
+ return (par & 0x01 ? EFAULT : 0);
+}
+
+/* Check address for privileged (PL1) write access. */
+static __inline int
+cp15_ats1cpw_check(vm_offset_t addr)
+{
+ register_t par, s;
+
+ s = intr_disable();
+ cp15_ats1cpw_set(addr);
+ isb();
+ par = cp15_par_get();
+ intr_restore(s);
+ return (par & 0x01 ? EFAULT : 0);
+}
+
#endif /* _KERNEL */
#endif /* !MACHINE_CPU_V6_H */
Index: sys/arm/include/sysreg.h
===================================================================
--- sys/arm/include/sysreg.h
+++ sys/arm/include/sysreg.h
@@ -130,7 +130,7 @@
#define CP15_BPIALLIS p15, 0, r0, c7, c1, 6 /* Branch predictor invalidate all IS */
#endif
-#define CP15_PAR p15, 0, r0, c7, c4, 0 /* Physical Address Register */
+#define CP15_PAR(rr) p15, 0, rr, c7, c4, 0 /* Physical Address Register */
#define CP15_ICIALLU p15, 0, r0, c7, c5, 0 /* Instruction cache invalidate all PoU */
#define CP15_ICIMVAU(rr) p15, 0, rr, c7, c5, 1 /* Instruction cache invalidate */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 19, 8:18 AM (15 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31755758
Default Alt Text
D3617.id8638.diff (6 KB)
Attached To
Mode
D3617: ARMv6 - fix aborts for copyin/out kind of functions
Attached
Detach File
Event Timeline
Log In to Comment