Пример #1
0
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);
}
Пример #2
0
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);
}
Пример #3
0
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, &regs->c3,
		    reqsize, reqperms, 0);
		if (error != 0)
			return (error);
	}

	switch (uap->op) {
	case MIPS_SET_TLS:
		return (cheriabi_set_user_tls(td, &regs->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));
	}
}