@@ -288,34 +288,37 @@ out:
/******************************************************************************
* Load-Store instruction emulation
*****************************************************************************/
+enum SRType {
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX
+};
-struct arm_instr {
- /* Instruction decoding */
- u32 opc;
- u32 opc_mask;
-
+struct arm_insn {
/* Decoding for the register write back */
bool register_form;
u32 imm;
- u8 Rm;
u8 type;
+ u8 Rt, Rn, Rm;
u8 shift_n;
/* Common decoding */
u8 len;
bool sign_extend;
bool w;
+};
+
+struct arm_decode {
+ /* Instruction decoding */
+ u32 opc;
+ u32 opc_mask;
bool (*decode)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
- unsigned long instr, struct arm_instr *ai);
-};
+ unsigned long instr, struct arm_insn *ai);
-enum SRType {
- SRType_LSL,
- SRType_LSR,
- SRType_ASR,
- SRType_ROR,
- SRType_RRX
+ struct arm_insn template;
};
/* Modelled after DecodeImmShift() in the ARM ARM */
@@ -383,7 +386,7 @@ u32 shift(u32 value, u8 N, enum SRType type, u8 amount, bool carry_in)
}
static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
- unsigned long instr, const struct arm_instr *ai)
+ unsigned long instr, const struct arm_insn *ai)
{
u8 Rt = (instr >> 12) & 0xf;
u8 Rn = (instr >> 16) & 0xf;
@@ -431,7 +434,7 @@ static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
}
static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
- unsigned long instr, struct arm_instr *ai)
+ unsigned long instr, struct arm_insn *ai)
{
u8 A = (instr >> 25) & 1;
@@ -449,7 +452,7 @@ static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
}
static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
- unsigned long instr, struct arm_instr *ai)
+ unsigned long instr, struct arm_insn *ai)
{
mmio->is_write = ai->w;
mmio->len = ai->len;
@@ -476,56 +479,69 @@ static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
* loads and stores as their encodings mandate the W bit set and the P bit
* clear.
*/
-static const struct arm_instr arm_instr[] = {
+static const struct arm_decode arm_decode[] = {
/**************** Load/Store Word and Byte **********************/
/* Store word with writeback */
- { .opc = 0x04000000, .opc_mask = 0x0c500000, .len = 4, .w = true,
- .sign_extend = false, .decode = decode_arm_ls },
+ { .opc = 0x04000000, .opc_mask = 0x0c500000,
+ .decode = decode_arm_ls,
+ .template = { .len = 4, .w = true, .sign_extend = false, }, },
/* Store byte with writeback */
- { .opc = 0x04400000, .opc_mask = 0x0c500000, .len = 1, .w = true,
- .sign_extend = false, .decode = decode_arm_ls },
+ { .opc = 0x04400000, .opc_mask = 0x0c500000,
+ .decode = decode_arm_ls,
+ .template = { .len = 1, .w = true, .sign_extend = false, }, },
/* Load word with writeback */
- { .opc = 0x04100000, .opc_mask = 0x0c500000, .len = 4, .w = false,
- .sign_extend = false, .decode = decode_arm_ls },
+ { .opc = 0x04100000, .opc_mask = 0x0c500000,
+ .decode = decode_arm_ls,
+ .template = { .len = 4, .w = false, .sign_extend = false, }, },
/* Load byte with writeback */
- { .opc = 0x04500000, .opc_mask = 0x0c500000, .len = 1, .w = false,
- .sign_extend = false, .decode = decode_arm_ls },
+ { .opc = 0x04500000, .opc_mask = 0x0c500000,
+ .decode = decode_arm_ls,
+ .template = { .len = 1, .w = false, .sign_extend = false, }, },
/*************** Extra load/store instructions ******************/
/* Store halfword with writeback */
- { .opc = 0x000000b0, .opc_mask = 0x0c1000f0, .len = 2, .w = true,
- .sign_extend = false, .decode = decode_arm_extra },
+ { .opc = 0x000000b0, .opc_mask = 0x0c1000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 2, .w = true, .sign_extend = false, }, },
/* Load halfword with writeback */
- { .opc = 0x001000b0, .opc_mask = 0x0c1000f0, .len = 2, .w = false,
- .sign_extend = false, .decode = decode_arm_extra },
-
+ { .opc = 0x001000b0, .opc_mask = 0x0c1000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 2, .w = false, .sign_extend = false, }, },
/* Load dual with writeback */
- { .opc = 0x000000d0, .opc_mask = 0x0c1000f0, .len = 8, .w = false,
- .sign_extend = false, .decode = decode_arm_extra },
+ { .opc = 0x000000d0, .opc_mask = 0x0c1000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 8, .w = false, .sign_extend = false, }, },
/* Load signed byte with writeback */
- { .opc = 0x001000d0, .opc_mask = 0x0c1000f0, .len = 1, .w = false,
- .sign_extend = true, .decode = decode_arm_extra },
+ { .opc = 0x001000d0, .opc_mask = 0x0c1000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 1, .w = false, .sign_extend = true, }, },
/* Store dual with writeback */
- { .opc = 0x000000f0, .opc_mask = 0x0c1000f0, .len = 8, .w = true,
- .sign_extend = false, .decode = decode_arm_extra },
+ { .opc = 0x000000f0, .opc_mask = 0x0c1000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 8, .w = true, .sign_extend = false, }, },
/* Load signed halfword with writeback */
- { .opc = 0x001000f0, .opc_mask = 0x0c1000f0, .len = 2, .w = false,
- .sign_extend = true, .decode = decode_arm_extra },
+ { .opc = 0x001000f0, .opc_mask = 0x0c1000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 2, .w = false, .sign_extend = true, }, },
/* Store halfword unprivileged */
- { .opc = 0x002000b0, .opc_mask = 0x0f3000f0, .len = 2, .w = true,
- .sign_extend = false, .decode = decode_arm_extra },
+ { .opc = 0x002000b0, .opc_mask = 0x0f3000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 2, .w = true, .sign_extend = false, }, },
/* Load halfword unprivileged */
- { .opc = 0x003000b0, .opc_mask = 0x0f3000f0, .len = 2, .w = false,
- .sign_extend = false, .decode = decode_arm_extra },
+ { .opc = 0x003000b0, .opc_mask = 0x0f3000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 2, .w = false, .sign_extend = false, }, },
/* Load signed byte unprivileged */
- { .opc = 0x003000d0, .opc_mask = 0x0f3000f0, .len = 1, .w = false,
- .sign_extend = true , .decode = decode_arm_extra },
+ { .opc = 0x003000d0, .opc_mask = 0x0f3000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 1, .w = false, .sign_extend = true, }, },
/* Load signed halfword unprivileged */
- { .opc = 0x003000d0, .opc_mask = 0x0f3000f0, .len = 2, .w = false,
- .sign_extend = true , .decode = decode_arm_extra },
+ { .opc = 0x003000d0, .opc_mask = 0x0f3000f0,
+ .decode = decode_arm_extra,
+ .template = { .len = 2, .w = false, .sign_extend = true, }, },
};
static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr,
@@ -533,11 +549,11 @@ static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr,
{
int i;
- for (i = 0; i < ARRAY_SIZE(arm_instr); i++) {
- const struct arm_instr *ai = &arm_instr[i];
- if ((instr & ai->opc_mask) == ai->opc) {
- struct arm_instr ai_copy = *ai;
- return ai->decode(vcpu, mmio, instr, &ai_copy);
+ for (i = 0; i < ARRAY_SIZE(arm_decode); i++) {
+ const struct arm_decode *d = &arm_decode[i];
+ if ((instr & d->opc_mask) == d->opc) {
+ struct arm_insn ai = d->template;
+ return d->decode(vcpu, mmio, instr, &ai);
}
}
return false;