enum ftt_type _fp_write_extword( uint64_t *address, /* FPU data address. */ uint64_t value, /* Extended word value to write. */ fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */ { if (((uintptr_t)address & 0x7) != 0) return (ftt_alignment); /* Must be extword-aligned. */ if (get_udatamodel() == DATAMODEL_ILP32) { /* * If this is a 32-bit program, chop the address accordingly. * The intermediate uintptr_t casts prevent warnings under a * certain compiler, and the temporary 32 bit storage is * intended to force proper code generation and break up what * would otherwise be a quadruple cast. */ caddr32_t address32 = (caddr32_t)(uintptr_t)address; address = (uint64_t *)(uintptr_t)address32; } if (suword64(address, value) == -1) { pfpsd->fp_trapaddr = (caddr_t)address; pfpsd->fp_traprw = S_WRITE; return (ftt_fault); } return (ftt_none); }
int suword64_nowatch(void *addr, uint64_t value) { int watched, ret; watched = watch_disable_addr(addr, sizeof (value), S_WRITE); ret = suword64(addr, value); if (watched) watch_enable_addr(addr, sizeof (value), S_WRITE); return (ret); }
int cheriabi_sysarch(struct thread *td, struct cheriabi_sysarch_args *uap) { struct trapframe *regs = &td->td_pcb->pcb_regs; int error; int parms_from_cap = 1; size_t reqsize; register_t reqperms; /* * The sysarch() fill_uap function is machine-independent so can not * check the validity of the capabilty which becomes uap->parms. As * such, it makes no attempt to convert the result. We need to * perform those checks here. */ switch (uap->op) { case MIPS_SET_TLS: reqsize = 0; reqperms = 0; break; case MIPS_GET_TLS: case CHERI_GET_STACK: case CHERI_GET_TYPECAP: reqsize = sizeof(struct chericap); reqperms = CHERI_PERM_STORE|CHERI_PERM_STORE_CAP; break; case CHERI_SET_STACK: reqsize = sizeof(struct chericap); reqperms = CHERI_PERM_LOAD|CHERI_PERM_LOAD_CAP; break; case CHERI_MMAP_GETBASE: case CHERI_MMAP_GETLEN: case CHERI_MMAP_GETOFFSET: case CHERI_MMAP_GETPERM: case CHERI_MMAP_SETOFFSET: case CHERI_MMAP_SETBOUNDS: reqsize = sizeof(uint64_t); reqperms = CHERI_PERM_STORE; break; case CHERI_MMAP_ANDPERM: reqsize = sizeof(uint64_t); reqperms = CHERI_PERM_LOAD|CHERI_PERM_STORE; break; case MIPS_GET_COUNT: parms_from_cap = 0; break; #ifdef CPU_QEMU_MALTA case QEMU_GET_QTRACE: reqsize = sizeof(int); reqperms = CHERI_PERM_STORE; break; case QEMU_SET_QTRACE: reqsize = sizeof(int); reqperms = CHERI_PERM_LOAD; break; #endif default: return (EINVAL); } if (parms_from_cap) { error = cheriabi_cap_to_ptr(&uap->parms, ®s->c3, reqsize, reqperms, 0); if (error != 0) return (error); } switch (uap->op) { case MIPS_SET_TLS: return (cheriabi_set_user_tls(td, ®s->c3)); case MIPS_GET_TLS: error = copyoutcap(&td->td_md.md_tls_cap, uap->parms, sizeof(struct chericap)); return (error); case CHERI_MMAP_GETBASE: { size_t base; PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETBASE(base, CHERI_CR_CTEMP0); PROC_UNLOCK(td->td_proc); if (suword64(uap->parms, base) != 0) return (EFAULT); return (0); } case CHERI_MMAP_GETLEN: { size_t len; PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETLEN(len, CHERI_CR_CTEMP0); PROC_UNLOCK(td->td_proc); if (suword64(uap->parms, len) != 0) return (EFAULT); return (0); } case CHERI_MMAP_GETOFFSET: { ssize_t offset; PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETOFFSET(offset, CHERI_CR_CTEMP0); PROC_UNLOCK(td->td_proc); if (suword64(uap->parms, offset) != 0) return (EFAULT); return (0); } case CHERI_MMAP_GETPERM: { uint64_t perms; PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETPERM(perms, CHERI_CR_CTEMP0); PROC_UNLOCK(td->td_proc); if (suword64(uap->parms, perms) != 0) return (EFAULT); return (0); } case CHERI_MMAP_ANDPERM: { uint64_t perms; perms = fuword64(uap->parms); if (perms == -1) return (EINVAL); PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CANDPERM(CHERI_CR_CTEMP0, CHERI_CR_CTEMP0, (register_t)perms); CHERI_CSC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETPERM(perms, CHERI_CR_CTEMP0); PROC_UNLOCK(td->td_proc); if (suword64(uap->parms, perms) != 0) return (EFAULT); return (0); } case CHERI_MMAP_SETOFFSET: { size_t len; ssize_t offset; offset = fuword64(uap->parms); /* Reject errors and misaligned offsets */ if (offset == -1 || (offset & PAGE_MASK) != 0) return (EINVAL); PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETLEN(len, CHERI_CR_CTEMP0); /* Don't allow out of bounds offsets, they aren't useful */ if (offset < 0 || offset > len) { PROC_UNLOCK(td->td_proc); return (EINVAL); } CHERI_CSETOFFSET(CHERI_CR_CTEMP0, CHERI_CR_CTEMP0, (register_t)offset); CHERI_CSC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); PROC_UNLOCK(td->td_proc); return (0); } case CHERI_MMAP_SETBOUNDS: { size_t len, olen; ssize_t offset; len = fuword64(uap->parms); /* Reject errors or misaligned lengths */ if (len == (size_t)-1 || (len & PAGE_MASK) != 0) return (EINVAL); PROC_LOCK(td->td_proc); CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); CHERI_CGETLEN(olen, CHERI_CR_CTEMP0); CHERI_CGETOFFSET(offset, CHERI_CR_CTEMP0); /* Don't try to set out of bounds lengths */ if (offset > olen || len > olen - offset) { PROC_UNLOCK(td->td_proc); return (EINVAL); } CHERI_CSETBOUNDS(CHERI_CR_CTEMP0, CHERI_CR_CTEMP0, (register_t)len); CHERI_CSC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_proc->p_md.md_cheri_mmap_cap, 0); PROC_UNLOCK(td->td_proc); return (0); } default: return (sysarch(td, (struct sysarch_args*)uap)); } }