qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH v2 2/2] hw/ppc: Moved TCG code to spapr_hcall_tcg


From: David Gibson
Subject: Re: [RFC PATCH v2 2/2] hw/ppc: Moved TCG code to spapr_hcall_tcg
Date: Mon, 3 May 2021 14:34:21 +1000

On Fri, Apr 30, 2021 at 03:40:47PM -0300, Lucas Mateus Castro (alqotel) wrote:
> Moved h_enter, remove_hpte, h_remove, h_bulk_remove,h_protect and
> h_read to spapr_hcall_tcg.c, added h_tcg_only to be used in a !TCG
> environment in spapr_hcall.c and changed build options to only build
> spapr_hcall_tcg.c when CONFIG_TCG is enabled.

This looks good.  I'd suggest the name 'spapr_softmmu.c' instead,
which more specifically describes what's special about these
functions.

h_resize_hpt_prepare(), h_resize_hpt_commit() and the functions they
depend on belong in the softmmu set as well.

> Added the function h_tcg_only to be used for hypercalls that should be
> called only in TCG environment but have been called in a TCG-less
> one.

Again, 'h_softmmu' would be a better name.

> 
> Right now, a #ifndef is used to know if there is a need of a h_tcg_only
> function to be implemented and used as hypercalls, I initially thought
> of always having that option turned on and having spapr_hcall_tcg.c
> overwrite those hypercalls when TCG is enabled, but
> spapr_register_hypercalls checks if a hypercall already exists for that
> opcode so that wouldn't work, so if anyone has any suggestions I'm
> interested.

The ifdef is fine.  We don't want to litter the code with them, but a
few is fine.  Especially in this context where it's pretty clearly
just excluding some things from a simple list of calls.

> 
> Also spapr_hcall_tcg.c only has 2 duplicated functions (valid_ptex and
> is_ram_address), what is the advised way to deal with these
> duplications?

valid_ptex() is only used by softmmu functions that are moving, so it
should travel with them, no need for duplication.  is_ram_address() is
also used by h_page_init() which is also needed in !TCG code.  So,
leave it in spapr_hcall.c and just export it for use in the TCG only
code.

> 
> Signed-off-by: Lucas Mateus Castro (alqotel) <lucas.araujo@eldorado.org.br>
> ---
>  hw/ppc/meson.build       |   3 +
>  hw/ppc/spapr_hcall.c     | 300 ++--------------------------------
>  hw/ppc/spapr_hcall_tcg.c | 343 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 363 insertions(+), 283 deletions(-)
>  create mode 100644 hw/ppc/spapr_hcall_tcg.c
> 
> diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
> index 218631c883..3c7f2f08b7 100644
> --- a/hw/ppc/meson.build
> +++ b/hw/ppc/meson.build
> @@ -29,6 +29,9 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files(
>    'spapr_numa.c',
>    'pef.c',
>  ))
> +ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_TCG'], if_true: files(
> +  'spapr_hcall_tcg.c'
> +))
>  ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c'))
>  ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_LINUX'], if_true: files(
>    'spapr_pci_vfio.c',
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 4b0ba69841..b37fbdc32e 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -22,6 +22,15 @@
>  #include "mmu-book3s-v3.h"
>  #include "hw/mem/memory-device.h"
>  
> +#ifndef CONFIG_TCG
> +static target_ulong h_tcg_only(PowerPCCPU *cpu, SpaprMachineState *spapr,
> +                            target_ulong opcode, target_ulong *args)
> +{
> +    g_assert_not_reached();
> +    return 0;
> +}
> +#endif /* !CONFIG_TCG */
> +
>  static bool has_spr(PowerPCCPU *cpu, int spr)
>  {
>      /* We can test whether the SPR is defined by checking for a valid name */
> @@ -55,284 +64,6 @@ static bool is_ram_address(SpaprMachineState *spapr, 
> hwaddr addr)
>      return false;
>  }
>  
> -static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
> -                            target_ulong opcode, target_ulong *args)
> -{
> -    target_ulong flags = args[0];
> -    target_ulong ptex = args[1];
> -    target_ulong pteh = args[2];
> -    target_ulong ptel = args[3];
> -    unsigned apshift;
> -    target_ulong raddr;
> -    target_ulong slot;
> -    const ppc_hash_pte64_t *hptes;
> -
> -    apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
> -    if (!apshift) {
> -        /* Bad page size encoding */
> -        return H_PARAMETER;
> -    }
> -
> -    raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1);
> -
> -    if (is_ram_address(spapr, raddr)) {
> -        /* Regular RAM - should have WIMG=0010 */
> -        if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
> -            return H_PARAMETER;
> -        }
> -    } else {
> -        target_ulong wimg_flags;
> -        /* Looks like an IO address */
> -        /* FIXME: What WIMG combinations could be sensible for IO?
> -         * For now we allow WIMG=010x, but are there others? */
> -        /* FIXME: Should we check against registered IO addresses? */
> -        wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M));
> -
> -        if (wimg_flags != HPTE64_R_I &&
> -            wimg_flags != (HPTE64_R_I | HPTE64_R_M)) {
> -            return H_PARAMETER;
> -        }
> -    }
> -
> -    pteh &= ~0x60ULL;
> -
> -    if (!valid_ptex(cpu, ptex)) {
> -        return H_PARAMETER;
> -    }
> -
> -    slot = ptex & 7ULL;
> -    ptex = ptex & ~7ULL;
> -
> -    if (likely((flags & H_EXACT) == 0)) {
> -        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> -        for (slot = 0; slot < 8; slot++) {
> -            if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
> -                break;
> -            }
> -        }
> -        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
> -        if (slot == 8) {
> -            return H_PTEG_FULL;
> -        }
> -    } else {
> -        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
> -        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
> -            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
> -            return H_PTEG_FULL;
> -        }
> -        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> -    }
> -
> -    spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
> -
> -    args[0] = ptex + slot;
> -    return H_SUCCESS;
> -}
> -
> -typedef enum {
> -    REMOVE_SUCCESS = 0,
> -    REMOVE_NOT_FOUND = 1,
> -    REMOVE_PARM = 2,
> -    REMOVE_HW = 3,
> -} RemoveResult;
> -
> -static RemoveResult remove_hpte(PowerPCCPU *cpu
> -                                , target_ulong ptex,
> -                                target_ulong avpn,
> -                                target_ulong flags,
> -                                target_ulong *vp, target_ulong *rp)
> -{
> -    const ppc_hash_pte64_t *hptes;
> -    target_ulong v, r;
> -
> -    if (!valid_ptex(cpu, ptex)) {
> -        return REMOVE_PARM;
> -    }
> -
> -    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> -    v = ppc_hash64_hpte0(cpu, hptes, 0);
> -    r = ppc_hash64_hpte1(cpu, hptes, 0);
> -    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> -
> -    if ((v & HPTE64_V_VALID) == 0 ||
> -        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
> -        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
> -        return REMOVE_NOT_FOUND;
> -    }
> -    *vp = v;
> -    *rp = r;
> -    spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
> -    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
> -    return REMOVE_SUCCESS;
> -}
> -
> -static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
> -                             target_ulong opcode, target_ulong *args)
> -{
> -    CPUPPCState *env = &cpu->env;
> -    target_ulong flags = args[0];
> -    target_ulong ptex = args[1];
> -    target_ulong avpn = args[2];
> -    RemoveResult ret;
> -
> -    ret = remove_hpte(cpu, ptex, avpn, flags,
> -                      &args[0], &args[1]);
> -
> -    switch (ret) {
> -    case REMOVE_SUCCESS:
> -        check_tlb_flush(env, true);
> -        return H_SUCCESS;
> -
> -    case REMOVE_NOT_FOUND:
> -        return H_NOT_FOUND;
> -
> -    case REMOVE_PARM:
> -        return H_PARAMETER;
> -
> -    case REMOVE_HW:
> -        return H_HARDWARE;
> -    }
> -
> -    g_assert_not_reached();
> -}
> -
> -#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
> -#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
> -#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
> -#define   H_BULK_REMOVE_END            0xc000000000000000ULL
> -#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
> -#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
> -#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
> -#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
> -#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
> -#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
> -#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
> -#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
> -#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
> -#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
> -#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
> -
> -#define H_BULK_REMOVE_MAX_BATCH        4
> -
> -static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
> -                                  target_ulong opcode, target_ulong *args)
> -{
> -    CPUPPCState *env = &cpu->env;
> -    int i;
> -    target_ulong rc = H_SUCCESS;
> -
> -    for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
> -        target_ulong *tsh = &args[i*2];
> -        target_ulong tsl = args[i*2 + 1];
> -        target_ulong v, r, ret;
> -
> -        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
> -            break;
> -        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
> -            return H_PARAMETER;
> -        }
> -
> -        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
> -        *tsh |= H_BULK_REMOVE_RESPONSE;
> -
> -        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
> -            *tsh |= H_BULK_REMOVE_PARM;
> -            return H_PARAMETER;
> -        }
> -
> -        ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl,
> -                          (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
> -                          &v, &r);
> -
> -        *tsh |= ret << 60;
> -
> -        switch (ret) {
> -        case REMOVE_SUCCESS:
> -            *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
> -            break;
> -
> -        case REMOVE_PARM:
> -            rc = H_PARAMETER;
> -            goto exit;
> -
> -        case REMOVE_HW:
> -            rc = H_HARDWARE;
> -            goto exit;
> -        }
> -    }
> - exit:
> -    check_tlb_flush(env, true);
> -
> -    return rc;
> -}
> -
> -static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
> -                              target_ulong opcode, target_ulong *args)
> -{
> -    CPUPPCState *env = &cpu->env;
> -    target_ulong flags = args[0];
> -    target_ulong ptex = args[1];
> -    target_ulong avpn = args[2];
> -    const ppc_hash_pte64_t *hptes;
> -    target_ulong v, r;
> -
> -    if (!valid_ptex(cpu, ptex)) {
> -        return H_PARAMETER;
> -    }
> -
> -    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> -    v = ppc_hash64_hpte0(cpu, hptes, 0);
> -    r = ppc_hash64_hpte1(cpu, hptes, 0);
> -    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> -
> -    if ((v & HPTE64_V_VALID) == 0 ||
> -        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
> -        return H_NOT_FOUND;
> -    }
> -
> -    r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
> -           HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
> -    r |= (flags << 55) & HPTE64_R_PP0;
> -    r |= (flags << 48) & HPTE64_R_KEY_HI;
> -    r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
> -    spapr_store_hpte(cpu, ptex,
> -                     (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
> -    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
> -    /* Flush the tlb */
> -    check_tlb_flush(env, true);
> -    /* Don't need a memory barrier, due to qemu's global lock */
> -    spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
> -    return H_SUCCESS;
> -}
> -
> -static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
> -                           target_ulong opcode, target_ulong *args)
> -{
> -    target_ulong flags = args[0];
> -    target_ulong ptex = args[1];
> -    int i, ridx, n_entries = 1;
> -    const ppc_hash_pte64_t *hptes;
> -
> -    if (!valid_ptex(cpu, ptex)) {
> -        return H_PARAMETER;
> -    }
> -
> -    if (flags & H_READ_4) {
> -        /* Clear the two low order bits */
> -        ptex &= ~(3ULL);
> -        n_entries = 4;
> -    }
> -
> -    hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries);
> -    for (i = 0, ridx = 0; i < n_entries; i++) {
> -        args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i);
> -        args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i);
> -    }
> -    ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries);
> -
> -    return H_SUCCESS;
> -}
> -
>  struct SpaprPendingHpt {
>      /* These fields are read-only after initialization */
>      int shift;
> @@ -2021,14 +1752,17 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, 
> target_ulong opcode,
>  
>  static void hypercall_register_types(void)
>  {
> +
> +#ifndef CONFIG_TCG
>      /* hcall-pft */
> -    spapr_register_hypercall(H_ENTER, h_enter);
> -    spapr_register_hypercall(H_REMOVE, h_remove);
> -    spapr_register_hypercall(H_PROTECT, h_protect);
> -    spapr_register_hypercall(H_READ, h_read);
> +    spapr_register_hypercall(H_ENTER, h_tcg_only);
> +    spapr_register_hypercall(H_REMOVE, h_tcg_only);
> +    spapr_register_hypercall(H_PROTECT, h_tcg_only);
> +    spapr_register_hypercall(H_READ, h_tcg_only);
>  
>      /* hcall-bulk */
> -    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
> +    spapr_register_hypercall(H_BULK_REMOVE, h_tcg_only);
> +#endif /* !CONFIG_TCG */
>  
>      /* hcall-hpt-resize */
>      spapr_register_hypercall(H_RESIZE_HPT_PREPARE, h_resize_hpt_prepare);
> diff --git a/hw/ppc/spapr_hcall_tcg.c b/hw/ppc/spapr_hcall_tcg.c
> new file mode 100644
> index 0000000000..92ff24c8dc
> --- /dev/null
> +++ b/hw/ppc/spapr_hcall_tcg.c
> @@ -0,0 +1,343 @@
> +#include "qemu/osdep.h"
> +#include "qemu/cutils.h"
> +#include "qapi/error.h"
> +#include "sysemu/hw_accel.h"
> +#include "sysemu/runstate.h"
> +#include "qemu/log.h"
> +#include "qemu/main-loop.h"
> +#include "qemu/module.h"
> +#include "qemu/error-report.h"
> +#include "cpu.h"
> +#include "exec/exec-all.h"
> +#include "helper_regs.h"
> +#include "hw/ppc/spapr.h"
> +#include "hw/ppc/spapr_cpu_core.h"
> +#include "mmu-hash64.h"
> +#include "mmu-misc.h"
> +#include "cpu-models.h"
> +#include "trace.h"
> +#include "kvm_ppc.h"
> +#include "hw/ppc/fdt.h"
> +#include "hw/ppc/spapr_ovec.h"
> +#include "mmu-book3s-v3.h"
> +#include "hw/mem/memory-device.h"
> +
> +static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
> +{
> +    /*
> +     * hash value/pteg group index is normalized by HPT mask
> +     */
> +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
> +        return false;
> +    }
> +    return true;
> +}
> +
> +static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr)
> +{
> +    MachineState *machine = MACHINE(spapr);
> +    DeviceMemoryState *dms = machine->device_memory;
> +
> +    if (addr < machine->ram_size) {
> +        return true;
> +    }
> +    if ((addr >= dms->base)
> +        && ((addr - dms->base) < memory_region_size(&dms->mr))) {
> +        return true;
> +    }
> +
> +    return false;
> +}
> +
> +static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
> +                            target_ulong opcode, target_ulong *args)
> +{
> +    target_ulong flags = args[0];
> +    target_ulong ptex = args[1];
> +    target_ulong pteh = args[2];
> +    target_ulong ptel = args[3];
> +    unsigned apshift;
> +    target_ulong raddr;
> +    target_ulong slot;
> +    const ppc_hash_pte64_t *hptes;
> +
> +    apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
> +    if (!apshift) {
> +        /* Bad page size encoding */
> +        return H_PARAMETER;
> +    }
> +
> +    raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1);
> +
> +    if (is_ram_address(spapr, raddr)) {
> +        /* Regular RAM - should have WIMG=0010 */
> +        if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
> +            return H_PARAMETER;
> +        }
> +    } else {
> +        target_ulong wimg_flags;
> +        /* Looks like an IO address */
> +        /* FIXME: What WIMG combinations could be sensible for IO?
> +         * For now we allow WIMG=010x, but are there others? */
> +        /* FIXME: Should we check against registered IO addresses? */
> +        wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M));
> +
> +        if (wimg_flags != HPTE64_R_I &&
> +            wimg_flags != (HPTE64_R_I | HPTE64_R_M)) {
> +            return H_PARAMETER;
> +        }
> +    }
> +
> +    pteh &= ~0x60ULL;
> +
> +    if (!valid_ptex(cpu, ptex)) {
> +        return H_PARAMETER;
> +    }
> +
> +    slot = ptex & 7ULL;
> +    ptex = ptex & ~7ULL;
> +
> +    if (likely((flags & H_EXACT) == 0)) {
> +        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> +        for (slot = 0; slot < 8; slot++) {
> +            if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
> +                break;
> +            }
> +        }
> +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
> +        if (slot == 8) {
> +            return H_PTEG_FULL;
> +        }
> +    } else {
> +        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
> +        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
> +            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
> +            return H_PTEG_FULL;
> +        }
> +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> +    }
> +
> +    spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
> +
> +    args[0] = ptex + slot;
> +    return H_SUCCESS;
> +}
> +
> +typedef enum {
> +    REMOVE_SUCCESS = 0,
> +    REMOVE_NOT_FOUND = 1,
> +    REMOVE_PARM = 2,
> +    REMOVE_HW = 3,
> +} RemoveResult;
> +
> +static RemoveResult remove_hpte(PowerPCCPU *cpu
> +                                , target_ulong ptex,
> +                                target_ulong avpn,
> +                                target_ulong flags,
> +                                target_ulong *vp, target_ulong *rp)
> +{
> +    const ppc_hash_pte64_t *hptes;
> +    target_ulong v, r;
> +
> +    if (!valid_ptex(cpu, ptex)) {
> +        return REMOVE_PARM;
> +    }
> +
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> +
> +    if ((v & HPTE64_V_VALID) == 0 ||
> +        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
> +        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
> +        return REMOVE_NOT_FOUND;
> +    }
> +    *vp = v;
> +    *rp = r;
> +    spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
> +    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
> +    return REMOVE_SUCCESS;
> +}
> +
> +static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
> +                             target_ulong opcode, target_ulong *args)
> +{
> +    CPUPPCState *env = &cpu->env;
> +    target_ulong flags = args[0];
> +    target_ulong ptex = args[1];
> +    target_ulong avpn = args[2];
> +    RemoveResult ret;
> +
> +    ret = remove_hpte(cpu, ptex, avpn, flags,
> +                      &args[0], &args[1]);
> +
> +    switch (ret) {
> +    case REMOVE_SUCCESS:
> +        check_tlb_flush(env, true);
> +        return H_SUCCESS;
> +
> +    case REMOVE_NOT_FOUND:
> +        return H_NOT_FOUND;
> +
> +    case REMOVE_PARM:
> +        return H_PARAMETER;
> +
> +    case REMOVE_HW:
> +        return H_HARDWARE;
> +    }
> +
> +    g_assert_not_reached();
> +}
> +
> +#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
> +#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
> +#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
> +#define   H_BULK_REMOVE_END            0xc000000000000000ULL
> +#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
> +#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
> +#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
> +#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
> +#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
> +#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
> +#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
> +#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
> +#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
> +#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
> +#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
> +
> +#define H_BULK_REMOVE_MAX_BATCH        4
> +
> +static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
> +                                  target_ulong opcode, target_ulong *args)
> +{
> +    CPUPPCState *env = &cpu->env;
> +    int i;
> +    target_ulong rc = H_SUCCESS;
> +
> +    for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
> +        target_ulong *tsh = &args[i*2];
> +        target_ulong tsl = args[i*2 + 1];
> +        target_ulong v, r, ret;
> +
> +        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
> +            break;
> +        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
> +            return H_PARAMETER;
> +        }
> +
> +        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
> +        *tsh |= H_BULK_REMOVE_RESPONSE;
> +
> +        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
> +            *tsh |= H_BULK_REMOVE_PARM;
> +            return H_PARAMETER;
> +        }
> +
> +        ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl,
> +                          (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
> +                          &v, &r);
> +
> +        *tsh |= ret << 60;
> +
> +        switch (ret) {
> +        case REMOVE_SUCCESS:
> +            *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
> +            break;
> +
> +        case REMOVE_PARM:
> +            rc = H_PARAMETER;
> +            goto exit;
> +
> +        case REMOVE_HW:
> +            rc = H_HARDWARE;
> +            goto exit;
> +        }
> +    }
> + exit:
> +    check_tlb_flush(env, true);
> +
> +    return rc;
> +}
> +
> +static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
> +                              target_ulong opcode, target_ulong *args)
> +{
> +    CPUPPCState *env = &cpu->env;
> +    target_ulong flags = args[0];
> +    target_ulong ptex = args[1];
> +    target_ulong avpn = args[2];
> +    const ppc_hash_pte64_t *hptes;
> +    target_ulong v, r;
> +
> +    if (!valid_ptex(cpu, ptex)) {
> +        return H_PARAMETER;
> +    }
> +
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> +
> +    if ((v & HPTE64_V_VALID) == 0 ||
> +        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
> +        return H_NOT_FOUND;
> +    }
> +
> +    r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
> +           HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
> +    r |= (flags << 55) & HPTE64_R_PP0;
> +    r |= (flags << 48) & HPTE64_R_KEY_HI;
> +    r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
> +    spapr_store_hpte(cpu, ptex,
> +                     (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
> +    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
> +    /* Flush the tlb */
> +    check_tlb_flush(env, true);
> +    /* Don't need a memory barrier, due to qemu's global lock */
> +    spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
> +    return H_SUCCESS;
> +}
> +
> +static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
> +                           target_ulong opcode, target_ulong *args)
> +{
> +    target_ulong flags = args[0];
> +    target_ulong ptex = args[1];
> +    int i, ridx, n_entries = 1;
> +    const ppc_hash_pte64_t *hptes;
> +
> +    if (!valid_ptex(cpu, ptex)) {
> +        return H_PARAMETER;
> +    }
> +
> +    if (flags & H_READ_4) {
> +        /* Clear the two low order bits */
> +        ptex &= ~(3ULL);
> +        n_entries = 4;
> +    }
> +
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries);
> +    for (i = 0, ridx = 0; i < n_entries; i++) {
> +        args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i);
> +        args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i);
> +    }
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries);
> +
> +    return H_SUCCESS;
> +}
> +
> +
> +static void hypercall_register_types(void)
> +{
> +    /* hcall-pft */
> +    spapr_register_hypercall(H_ENTER, h_enter);
> +    spapr_register_hypercall(H_REMOVE, h_remove);
> +    spapr_register_hypercall(H_PROTECT, h_protect);
> +    spapr_register_hypercall(H_READ, h_read);
> +
> +    /* hcall-bulk */
> +    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
> +}
> +
> +type_init(hypercall_register_types)

-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
                                | _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]