{
const union hsr hsr = { .bits = regs->hsr };
const struct hsr_dabt dabt = hsr.dabt;
+ const uint8_t access_size = (1U << dabt.size) * 8;
+ const uint64_t access_mask = GENMASK_ULL(access_size - 1, 0);
/* Code is similar to handle_read */
register_t r = v->io.req.data;
if ( dabt.write )
return IO_HANDLED;
+ /*
+ * The Arm Arm requires the value to be zero-extended to the size
+ * of the register. The Device Model is not meant to touch the bits
+ * outside of the access size, but let's not trust that.
+ */
+ r &= access_mask;
r = sign_extend(dabt, r);
set_user_reg(regs, dabt.reg, r);
struct vcpu_io *vio = &v->io;
const struct instr_details instr = info->dabt_instr;
struct hsr_dabt dabt = info->dabt;
+ const uint8_t access_size = (1U << dabt.size) * 8;
+ const uint64_t access_mask = GENMASK_ULL(access_size - 1, 0);
ioreq_t p = {
.type = IOREQ_TYPE_COPY,
.addr = info->gpa,
ASSERT(dabt.valid);
- p.data = get_user_reg(regs, info->dabt.reg);
+ /*
+ * During a write access, the Device Model only need to know the content
+ * of the bits associated with the access size (e.g. for 8-bit, the lower 8-bits).
+ * During a read access, the Device Model don't need to know any value.
+ * So restrict the value it can access.
+ */
+ p.data = p.dir ? 0 : get_user_reg(regs, info->dabt.reg) & access_mask;
vio->req = p;
vio->suspended = false;
vio->info.dabt_instr = instr;