Introduce cpu_icache_sync_range_checked(), that does the same thing as

cpu_icache_sync_range(), except that it sets pcb_onfault to catch any page
fault, as doing cache maintenance operations for non-mapped generates a
data abort, and use it in freebsd32_sysarch(), so that a userland program
attempting to sync the icache with unmapped addresses doesn't crash the
kernel.

Spotted out by:	andrew
This commit is contained in:
Olivier Houchard 2019-01-13 23:29:46 +00:00
parent 7dff7eda1a
commit 9cd27257d5
3 changed files with 24 additions and 1 deletions

View File

@ -147,3 +147,24 @@ ENTRY(arm64_icache_sync_range)
ic ialluis
dsb ish
END(arm64_icache_sync_range)
/*
* int arm64_icache_sync_range_checked(vm_offset_t, vm_size_t)
*/
ENTRY(arm64_icache_sync_range_checked)
adr x5, cache_maint_fault
SET_FAULT_HANDLER(x5, x6)
/* XXX: See comment in arm64_icache_sync_range */
cache_handle_range dcop = cvau
ic ialluis
dsb ish
SET_FAULT_HANDLER(xzr, x6)
mov x0, #0
ret
END(arm64_icache_sync_range_checked)
ENTRY(cache_maint_fault)
SET_FAULT_HANDLER(xzr, x1)
mov x0, #EFAULT
ret
END(cache_maint_fault)

View File

@ -85,7 +85,7 @@ freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
return (error);
if ((uint64_t)args.addr + (uint64_t)args.size > 0xffffffff)
return (EINVAL);
cpu_icache_sync_range(args.addr, args.size);
cpu_icache_sync_range_checked(args.addr, args.size);
return 0;
}
case ARM_GET_VFPSTATE:

View File

@ -138,12 +138,14 @@ extern int64_t dczva_line_size;
#define cpu_idcache_wbinv_range(a, s) arm64_idcache_wbinv_range((a), (s))
#define cpu_icache_sync_range(a, s) arm64_icache_sync_range((a), (s))
#define cpu_icache_sync_range_checked(a, s) arm64_icache_sync_range_checked((a), (s))
void arm64_nullop(void);
void arm64_setttb(vm_offset_t);
void arm64_tlb_flushID(void);
void arm64_tlb_flushID_SE(vm_offset_t);
void arm64_icache_sync_range(vm_offset_t, vm_size_t);
int arm64_icache_sync_range_checked(vm_offset_t, vm_size_t);
void arm64_idcache_wbinv_range(vm_offset_t, vm_size_t);
void arm64_dcache_wbinv_range(vm_offset_t, vm_size_t);
void arm64_dcache_inv_range(vm_offset_t, vm_size_t);