diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-06-18 20:21:37 +0000 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2012-06-24 01:04:45 +0200 |
commit | c73e3771ea79ab3898da3ba51ff6fc5b05948d85 (patch) | |
tree | d72d67e012b6a59c2eaa6b26f3741550e25e6d5c /hw | |
parent | a4d8e8daee324e230b0155915f562743f4fff5d8 (diff) | |
download | qemu-c73e3771ea79ab3898da3ba51ff6fc5b05948d85.zip qemu-c73e3771ea79ab3898da3ba51ff6fc5b05948d85.tar.gz qemu-c73e3771ea79ab3898da3ba51ff6fc5b05948d85.tar.bz2 |
spapr: Add "memop" hypercall
This adds a qemu-specific hypervisor call to the pseries machine
which allows to do what amounts to memmove, memcpy and xor over
regions of physical memory such as the framebuffer.
This is the simplest way to get usable framebuffer speed from
SLOF since the framebuffer isn't mapped in the VRMA and so would
otherwise require an hcall per 8 bytes access.
The performance is still not great but usable, and can be improved
with a more complex implementation of the hcall itself if needed.
This also adds some documentation for the qemu-specific hypercalls
that we add to PAPR along with a new qemu,hypertas-functions property
that mirrors ibm,hypertas-functions and provides some discoverability
for the new calls.
Note: I chose note to advertise H_RTAS to the guest via that mechanism.
This is done on purpose, the guest uses the normal RTAS interfaces
provided by qemu (including SLOF) which internally calls H_RTAS.
We might in the future implement part (or even all) of RTAS inside the
guest like IBM's firmware does and replace H_RTAS with some finer grained
set of private hypercalls.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
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
@@ -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)))); @@ -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 94bb504..a5990a9 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); |