enum ftt_type _fp_read_extword( const uint64_t *address, /* FPU data address. */ uint64_t *pvalue, /* Place for extended word value. */ 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 (fuword64(address, pvalue) == -1) { pfpsd->fp_trapaddr = (caddr_t)address; pfpsd->fp_traprw = S_READ; return (ftt_fault); } return (ftt_none); }
int fuword64_nowatch(const void *addr, uint64_t *value) { int watched, ret; watched = watch_disable_addr(addr, sizeof (*value), S_READ); ret = fuword64(addr, value); if (watched) watch_enable_addr(addr, sizeof (*value), S_READ); 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)); } }
static int pmc_next_uframe(register_t *pc, register_t *sp, register_t *ra) { int offset, registers_on_stack; uint32_t opcode, mask; register_t function_start; int stksize; InstFmt i; registers_on_stack = 0; mask = 0; function_start = 0; offset = 0; stksize = 0; while (offset < MAX_FUNCTION_SIZE) { opcode = fuword32((void *)(*pc - offset)); /* [d]addiu sp, sp, -X*/ if (((opcode & 0xffff8000) == 0x27bd8000) || ((opcode & 0xffff8000) == 0x67bd8000)) { function_start = *pc - offset; registers_on_stack = 1; break; } /* lui gp, X */ if ((opcode & 0xffff8000) == 0x3c1c0000) { /* * Function might start with this instruction * Keep an eye on "jr ra" and sp correction * with positive value further on */ function_start = *pc - offset; } if (function_start) { /* * Stop looking further. Possible end of * function instruction: it means there is no * stack modifications, sp is unchanged */ /* [d]addiu sp,sp,X */ if (((opcode & 0xffff8000) == 0x27bd0000) || ((opcode & 0xffff8000) == 0x67bd0000)) break; if (opcode == 0x03e00008) break; } offset += sizeof(int); } if (!function_start) return (-1); if (registers_on_stack) { offset = 0; while ((offset < MAX_PROLOGUE_SIZE) && ((function_start + offset) < *pc)) { i.word = fuword32((void *)(function_start + offset)); switch (i.JType.op) { case OP_SW: /* look for saved registers on the stack */ if (i.IType.rs != 29) break; /* only restore the first one */ if (mask & (1 << i.IType.rt)) break; mask |= (1 << i.IType.rt); if (i.IType.rt == 31) *ra = fuword32((void *)(*sp + (short)i.IType.imm)); break; #if defined(__mips_n64) case OP_SD: /* look for saved registers on the stack */ if (i.IType.rs != 29) break; /* only restore the first one */ if (mask & (1 << i.IType.rt)) break; mask |= (1 << i.IType.rt); /* ra */ if (i.IType.rt == 31) *ra = fuword64((void *)(*sp + (short)i.IType.imm)); break; #endif case OP_ADDI: case OP_ADDIU: case OP_DADDI: case OP_DADDIU: /* look for stack pointer adjustment */ if (i.IType.rs != 29 || i.IType.rt != 29) break; stksize = -((short)i.IType.imm); } offset += sizeof(int); } } /* * We reached the end of backtrace */ if (*pc == *ra) return (-1); *pc = *ra; *sp += stksize; return (0); }