diff mbox

[01/10] kvm: split out instruction structure from decoding method.

Message ID 1351077923-17977-2-git-send-email-rusty@rustcorp.com.au (mailing list archive)
State New, archived
Headers show

Commit Message

Rusty Russell Oct. 24, 2012, 11:25 a.m. UTC
From: Rusty Russell <rusty.russell@linaro.org>

Add a new 'struct arm_insn' to represent the decoded instruction; the
decoding logic belong in a separate structure (arm_decode).

Signed-off-by: Rusty Russell <rusty.russell@linaro.org>
---
 arch/arm/kvm/emulate.c |  120 +++++++++++++++++++++++++++---------------------
 1 file changed, 68 insertions(+), 52 deletions(-)
diff mbox

Patch

diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 30124cb..e4fc12b 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -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;