diff options
-rw-r--r-- | arch/powerpc/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_ppc.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kvm/emulate.c | 14 | ||||
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 29 |
4 files changed, 47 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index fb87dcf418bf..119deb4750d9 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -270,6 +270,7 @@ struct kvm_vcpu_arch { | |||
270 | 270 | ||
271 | u8 io_gpr; /* GPR used as IO source/target */ | 271 | u8 io_gpr; /* GPR used as IO source/target */ |
272 | u8 mmio_is_bigendian; | 272 | u8 mmio_is_bigendian; |
273 | u8 mmio_sign_extend; | ||
273 | u8 dcr_needed; | 274 | u8 dcr_needed; |
274 | u8 dcr_is_write; | 275 | u8 dcr_is_write; |
275 | 276 | ||
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index c011170f572b..a288dd2fbb2c 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h | |||
@@ -48,6 +48,9 @@ extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); | |||
48 | extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | 48 | extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, |
49 | unsigned int rt, unsigned int bytes, | 49 | unsigned int rt, unsigned int bytes, |
50 | int is_bigendian); | 50 | int is_bigendian); |
51 | extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
52 | unsigned int rt, unsigned int bytes, | ||
53 | int is_bigendian); | ||
51 | extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | 54 | extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, |
52 | u64 val, unsigned int bytes, int is_bigendian); | 55 | u64 val, unsigned int bytes, int is_bigendian); |
53 | 56 | ||
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index cb72a65f4ecc..11789dd33a13 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c | |||
@@ -62,6 +62,8 @@ | |||
62 | #define OP_STBU 39 | 62 | #define OP_STBU 39 |
63 | #define OP_LHZ 40 | 63 | #define OP_LHZ 40 |
64 | #define OP_LHZU 41 | 64 | #define OP_LHZU 41 |
65 | #define OP_LHA 42 | ||
66 | #define OP_LHAU 43 | ||
65 | #define OP_STH 44 | 67 | #define OP_STH 44 |
66 | #define OP_STHU 45 | 68 | #define OP_STHU 45 |
67 | 69 | ||
@@ -450,6 +452,18 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
450 | kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed); | 452 | kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed); |
451 | break; | 453 | break; |
452 | 454 | ||
455 | case OP_LHA: | ||
456 | rt = get_rt(inst); | ||
457 | emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1); | ||
458 | break; | ||
459 | |||
460 | case OP_LHAU: | ||
461 | ra = get_ra(inst); | ||
462 | rt = get_rt(inst); | ||
463 | emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1); | ||
464 | kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed); | ||
465 | break; | ||
466 | |||
453 | case OP_STH: | 467 | case OP_STH: |
454 | rs = get_rs(inst); | 468 | rs = get_rs(inst); |
455 | emulated = kvmppc_handle_store(run, vcpu, | 469 | emulated = kvmppc_handle_store(run, vcpu, |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index b7858b1e15ec..1266ed02b471 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -301,6 +301,22 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, | |||
301 | } | 301 | } |
302 | } | 302 | } |
303 | 303 | ||
304 | if (vcpu->arch.mmio_sign_extend) { | ||
305 | switch (run->mmio.len) { | ||
306 | #ifdef CONFIG_PPC64 | ||
307 | case 4: | ||
308 | gpr = (s64)(s32)gpr; | ||
309 | break; | ||
310 | #endif | ||
311 | case 2: | ||
312 | gpr = (s64)(s16)gpr; | ||
313 | break; | ||
314 | case 1: | ||
315 | gpr = (s64)(s8)gpr; | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | |||
304 | kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); | 320 | kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); |
305 | 321 | ||
306 | switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) { | 322 | switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) { |
@@ -338,10 +354,23 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
338 | vcpu->arch.mmio_is_bigendian = is_bigendian; | 354 | vcpu->arch.mmio_is_bigendian = is_bigendian; |
339 | vcpu->mmio_needed = 1; | 355 | vcpu->mmio_needed = 1; |
340 | vcpu->mmio_is_write = 0; | 356 | vcpu->mmio_is_write = 0; |
357 | vcpu->arch.mmio_sign_extend = 0; | ||
341 | 358 | ||
342 | return EMULATE_DO_MMIO; | 359 | return EMULATE_DO_MMIO; |
343 | } | 360 | } |
344 | 361 | ||
362 | /* Same as above, but sign extends */ | ||
363 | int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
364 | unsigned int rt, unsigned int bytes, int is_bigendian) | ||
365 | { | ||
366 | int r; | ||
367 | |||
368 | r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian); | ||
369 | vcpu->arch.mmio_sign_extend = 1; | ||
370 | |||
371 | return r; | ||
372 | } | ||
373 | |||
345 | int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | 374 | int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, |
346 | u64 val, unsigned int bytes, int is_bigendian) | 375 | u64 val, unsigned int bytes, int is_bigendian) |
347 | { | 376 | { |