void csky_alignment()

in abiv1/alignment.c [212:301]


void csky_alignment(struct pt_regs *regs)
{
	int ret;
	uint16_t tmp;
	uint32_t opcode = 0;
	uint32_t rx     = 0;
	uint32_t rz     = 0;
	uint32_t imm    = 0;
	uint32_t addr   = 0;

	if (!user_mode(regs))
		goto kernel_area;

	if (!align_usr_enable) {
		pr_err("%s user disabled.\n", __func__);
		goto bad_area;
	}

	align_usr_count++;

	ret = get_user(tmp, (uint16_t *)instruction_pointer(regs));
	if (ret) {
		pr_err("%s get_user failed.\n", __func__);
		goto bad_area;
	}

	goto good_area;

kernel_area:
	if (!align_kern_enable) {
		pr_err("%s kernel disabled.\n", __func__);
		goto bad_area;
	}

	align_kern_count++;

	tmp = *(uint16_t *)instruction_pointer(regs);

good_area:
	opcode = (uint32_t)tmp;

	rx  = opcode & 0xf;
	imm = (opcode >> 4) & 0xf;
	rz  = (opcode >> 8) & 0xf;
	opcode &= 0xf000;

	if (rx == 0 || rx == 1 || rz == 0 || rz == 1)
		goto bad_area;

	switch (opcode) {
	case OP_LDH:
		addr = get_ptreg(regs, rx) + (imm << 1);
		ret = ldh_c(regs, rz, addr);
		break;
	case OP_LDW:
		addr = get_ptreg(regs, rx) + (imm << 2);
		ret = ldw_c(regs, rz, addr);
		break;
	case OP_STH:
		addr = get_ptreg(regs, rx) + (imm << 1);
		ret = sth_c(regs, rz, addr);
		break;
	case OP_STW:
		addr = get_ptreg(regs, rx) + (imm << 2);
		ret = stw_c(regs, rz, addr);
		break;
	}

	if (ret)
		goto bad_area;

	regs->pc += 2;

	return;

bad_area:
	if (!user_mode(regs)) {
		if (fixup_exception(regs))
			return;

		bust_spinlocks(1);
		pr_alert("%s opcode: %x, rz: %d, rx: %d, imm: %d, addr: %x.\n",
				__func__, opcode, rz, rx, imm, addr);
		show_regs(regs);
		bust_spinlocks(0);
		make_task_dead(SIGKILL);
	}

	force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr);
}