diff options
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/emulate.c | 14 | ||||
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 29 |
2 files changed, 43 insertions, 0 deletions
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 | { |