diff options
author | Balbir Singh <bsingharora@gmail.com> | 2016-04-03 20:38:00 +1000 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2016-04-11 11:59:57 +0100 |
commit | 015785d4efcc6fde5f6d1c79e4adced42283efb2 (patch) | |
tree | 6f31fa707b7fc01beca168fcefc582da6c6b1a09 | |
parent | e300a5eef43ed25dc415b47d67cdf8d8987a9bf8 (diff) | |
download | kvmtool-015785d4efcc6fde5f6d1c79e4adced42283efb2.tar.gz |
Implement H_SET_MODE for ppc64le
Use the infrastructure for queuing a task to a specific vCPU and
sett ILE (Little Endian Interrupt Handling) on power via h_set_mode
hypercall
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | powerpc/include/kvm/kvm-cpu-arch.h | 2 | ||||
-rw-r--r-- | powerpc/kvm.c | 2 | ||||
-rw-r--r-- | powerpc/spapr.h | 15 | ||||
-rw-r--r-- | powerpc/spapr_hcall.c | 66 |
4 files changed, 82 insertions, 3 deletions
diff --git a/powerpc/include/kvm/kvm-cpu-arch.h b/powerpc/include/kvm/kvm-cpu-arch.h index f2bfbb5b..a69e0cc3 100644 --- a/powerpc/include/kvm/kvm-cpu-arch.h +++ b/powerpc/include/kvm/kvm-cpu-arch.h @@ -38,6 +38,8 @@ #define POWER7_EXT_IRQ 0 +#define LPCR_ILE (1 << (63-38)) + struct kvm; struct kvm_cpu { diff --git a/powerpc/kvm.c b/powerpc/kvm.c index d061c981..f9314802 100644 --- a/powerpc/kvm.c +++ b/powerpc/kvm.c @@ -291,7 +291,7 @@ static int setup_fdt(struct kvm *kvm) uint32_t int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; char hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0" "hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0" - "hcall-splpar\0hcall-bulk"; + "hcall-splpar\0hcall-bulk\0hcall-set-mode"; int i, j; char cpu_name[30]; u8 staging_fdt[FDT_MAX_SIZE]; diff --git a/powerpc/spapr.h b/powerpc/spapr.h index 8b294d17..f851f4ab 100644 --- a/powerpc/spapr.h +++ b/powerpc/spapr.h @@ -27,7 +27,7 @@ typedef uintptr_t target_phys_addr_t; #define H_HARDWARE -1 /* Hardware error */ #define H_FUNCTION -2 /* Function not supported */ #define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting */ - +#define H_P2 -55 #define H_SET_DABR 0x28 #define H_LOGICAL_CI_LOAD 0x3c #define H_LOGICAL_CI_STORE 0x40 @@ -41,7 +41,18 @@ typedef uintptr_t target_phys_addr_t; #define H_EOI 0x64 #define H_IPI 0x6c #define H_XIRR 0x74 -#define MAX_HCALL_OPCODE H_XIRR +#define H_SET_MODE 0x31C +#define MAX_HCALL_OPCODE H_SET_MODE + +/* Values for 2nd argument to H_SET_MODE */ +#define H_SET_MODE_RESOURCE_SET_CIABR 1 +#define H_SET_MODE_RESOURCE_SET_DAWR 2 +#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3 +#define H_SET_MODE_RESOURCE_LE 4 + +/* Flags for H_SET_MODE_RESOURCE_LE */ +#define H_SET_MODE_ENDIAN_BIG 0 +#define H_SET_MODE_ENDIAN_LITTLE 1 /* * The hcalls above are standardized in PAPR and implemented by pHyp diff --git a/powerpc/spapr_hcall.c b/powerpc/spapr_hcall.c index ff1d63ac..25bec829 100644 --- a/powerpc/spapr_hcall.c +++ b/powerpc/spapr_hcall.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <assert.h> +#include <sys/eventfd.h> static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - @@ -74,6 +75,70 @@ static target_ulong h_logical_dcbf(struct kvm_cpu *vcpu, target_ulong opcode, ta return H_SUCCESS; } +struct lpcr_data { + struct kvm_cpu *cpu; + int mode; +}; + +static void get_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr) +{ + struct kvm_one_reg reg = { + .id = KVM_REG_PPC_LPCR_64, + .addr = (__u64)lpcr + }; + + if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®)) + die("Couldn't read vcpu reg?!"); +} + +static void set_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr) +{ + struct kvm_one_reg reg = { + .id = KVM_REG_PPC_LPCR_64, + .addr = (__u64)lpcr + }; + + if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®)) + die("Couldn't write vcpu reg?!"); +} + +static void set_endian_task(struct kvm_cpu *vcpu, void *data) +{ + target_ulong mflags = (target_ulong)data; + target_ulong lpcr; + + get_cpu_lpcr(vcpu, &lpcr); + + if (mflags == H_SET_MODE_ENDIAN_BIG) + lpcr &= ~LPCR_ILE; + else + lpcr |= LPCR_ILE; + + set_cpu_lpcr(vcpu, &lpcr); +} + +static target_ulong h_set_mode(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args) +{ + int ret; + + switch (args[1]) { + case H_SET_MODE_RESOURCE_LE: { + struct kvm_cpu_task task; + task.func = set_endian_task; + task.data = (void *)args[0]; + kvm_cpu__run_on_all_cpus(vcpu->kvm, &task); + ret = H_SUCCESS; + break; + } + default: + ret = H_FUNCTION; + break; + } + + return ret; +} + + void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) { spapr_hcall_fn *slot; @@ -128,6 +193,7 @@ void hypercall_init(void) spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store); spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi); spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf); + spapr_register_hypercall(H_SET_MODE, h_set_mode); /* KVM-PPC specific hcalls */ spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); |