diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/spapr.c | 3 | ||||
| -rw-r--r-- | hw/spapr.h | 3 | ||||
| -rw-r--r-- | hw/spapr_hcall.c | 68 |
3 files changed, 73 insertions, 1 deletions
diff --git a/hw/spapr.c b/hw/spapr.c index 1b01d6475d..09a23ff092 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -197,6 +197,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; + char qemu_hypertas_prop[] = "hcall-memop1"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; @@ -417,6 +418,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, sizeof(hypertas_prop)))); + _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop, + sizeof(qemu_hypertas_prop)))); _FDT((fdt_property(fdt, "ibm,associativity-reference-points", refpoints, sizeof(refpoints)))); diff --git a/hw/spapr.h b/hw/spapr.h index 654a7a8a34..c75172e0c0 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -264,7 +264,8 @@ typedef struct sPAPREnvironment { */ #define KVMPPC_HCALL_BASE 0xf000 #define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) -#define KVMPPC_HCALL_MAX KVMPPC_H_RTAS +#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1) +#define KVMPPC_HCALL_MAX KVMPPC_H_LOGICAL_MEMOP extern sPAPREnvironment *spapr; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 94bb504ca6..a5990a9617 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -608,6 +608,73 @@ static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr, return H_PARAMETER; } +static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong dst = args[0]; /* Destination address */ + target_ulong src = args[1]; /* Source address */ + target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */ + target_ulong count = args[3]; /* Element count */ + target_ulong op = args[4]; /* 0 = copy, 1 = invert */ + uint64_t tmp; + unsigned int mask = (1 << esize) - 1; + int step = 1 << esize; + + if (count > 0x80000000) { + return H_PARAMETER; + } + + if ((dst & mask) || (src & mask) || (op > 1)) { + return H_PARAMETER; + } + + if (dst >= src && dst < (src + (count << esize))) { + dst = dst + ((count - 1) << esize); + src = src + ((count - 1) << esize); + step = -step; + } + + while (count--) { + switch (esize) { + case 0: + tmp = ldub_phys(src); + break; + case 1: + tmp = lduw_phys(src); + break; + case 2: + tmp = ldl_phys(src); + break; + case 3: + tmp = ldq_phys(src); + break; + default: + return H_PARAMETER; + } + if (op == 1) { + tmp = ~tmp; + } + switch (esize) { + case 0: + stb_phys(dst, tmp); + break; + case 1: + stw_phys(dst, tmp); + break; + case 2: + stl_phys(dst, tmp); + break; + case 3: + stq_phys(dst, tmp); + break; + } + dst = dst + step; + src = src + step; + } + + return H_SUCCESS; +} + static target_ulong h_logical_icbi(CPUPPCState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -700,6 +767,7 @@ static void hypercall_register_types(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(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop); /* qemu/KVM-PPC specific hcalls */ spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); |