Example #1
0
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);
}
Example #2
0
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, &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));
	}
}
Example #4
0
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);
}