diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index b559b67073..c022984e44 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -228,6 +228,7 @@ typedef struct DisasContext DisasContext; typedef struct ppc_spr_t ppc_spr_t; typedef union ppc_avr_t ppc_avr_t; typedef union ppc_tlb_t ppc_tlb_t; +typedef struct ppc_hash_pte64 ppc_hash_pte64_t; /* SPR access micro-ops generations callbacks */ struct ppc_spr_t { diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 52bbea514a..79c1da6638 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -2596,89 +2596,85 @@ void kvm_arch_init_irq_routing(KVMState *s) { } -struct kvm_get_htab_buf { - struct kvm_get_htab_header header; - /* - * We require one extra byte for read - */ - target_ulong hpte[(HPTES_PER_GROUP * 2) + 1]; -}; - -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index) +void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n) { - int htab_fd; - struct kvm_get_htab_fd ghf; - struct kvm_get_htab_buf *hpte_buf; + struct kvm_get_htab_fd ghf = { + .flags = 0, + .start_index = ptex, + }; + int fd, rc; + int i; - ghf.flags = 0; - ghf.start_index = pte_index; - htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf); - if (htab_fd < 0) { - goto error_out; + fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf); + if (fd < 0) { + hw_error("kvmppc_read_hptes: Unable to open HPT fd"); } - hpte_buf = g_malloc0(sizeof(*hpte_buf)); - /* - * Read the hpte group - */ - if (read(htab_fd, hpte_buf, sizeof(*hpte_buf)) < 0) { - goto out_close; + i = 0; + while (i < n) { + struct kvm_get_htab_header *hdr; + int m = n < HPTES_PER_GROUP ? n : HPTES_PER_GROUP; + char buf[sizeof(*hdr) + m * HASH_PTE_SIZE_64]; + + rc = read(fd, buf, sizeof(buf)); + if (rc < 0) { + hw_error("kvmppc_read_hptes: Unable to read HPTEs"); + } + + hdr = (struct kvm_get_htab_header *)buf; + while ((i < n) && ((char *)hdr < (buf + rc))) { + int invalid = hdr->n_invalid; + + if (hdr->index != (ptex + i)) { + hw_error("kvmppc_read_hptes: Unexpected HPTE index %"PRIu32 + " != (%"HWADDR_PRIu" + %d", hdr->index, ptex, i); + } + + memcpy(hptes + i, hdr + 1, HASH_PTE_SIZE_64 * hdr->n_valid); + i += hdr->n_valid; + + if ((n - i) < invalid) { + invalid = n - i; + } + memset(hptes + i, 0, invalid * HASH_PTE_SIZE_64); + i += hdr->n_invalid; + + hdr = (struct kvm_get_htab_header *) + ((char *)(hdr + 1) + HASH_PTE_SIZE_64 * hdr->n_valid); + } } - close(htab_fd); - return (uint64_t)(uintptr_t) hpte_buf->hpte; - -out_close: - g_free(hpte_buf); - close(htab_fd); -error_out: - return 0; + close(fd); } -void kvmppc_hash64_free_pteg(uint64_t token) +void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1) { - struct kvm_get_htab_buf *htab_buf; - - htab_buf = container_of((void *)(uintptr_t) token, struct kvm_get_htab_buf, - hpte); - g_free(htab_buf); - return; -} - -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, - target_ulong pte0, target_ulong pte1) -{ - int htab_fd; + int fd, rc; struct kvm_get_htab_fd ghf; - struct kvm_get_htab_buf hpte_buf; + struct { + struct kvm_get_htab_header hdr; + uint64_t pte0; + uint64_t pte1; + } buf; ghf.flags = 0; ghf.start_index = 0; /* Ignored */ - htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf); - if (htab_fd < 0) { - goto error_out; + fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf); + if (fd < 0) { + hw_error("kvmppc_write_hpte: Unable to open HPT fd"); } - hpte_buf.header.n_valid = 1; - hpte_buf.header.n_invalid = 0; - hpte_buf.header.index = pte_index; - hpte_buf.hpte[0] = pte0; - hpte_buf.hpte[1] = pte1; - /* - * Write the hpte entry. - * CAUTION: write() has the warn_unused_result attribute. Hence we - * need to check the return value, even though we do nothing. - */ - if (write(htab_fd, &hpte_buf, sizeof(hpte_buf)) < 0) { - goto out_close; + buf.hdr.n_valid = 1; + buf.hdr.n_invalid = 0; + buf.hdr.index = ptex; + buf.pte0 = cpu_to_be64(pte0); + buf.pte1 = cpu_to_be64(pte1); + + rc = write(fd, &buf, sizeof(buf)); + if (rc != sizeof(buf)) { + hw_error("kvmppc_write_hpte: Unable to update KVM HPT"); } - -out_close: - close(htab_fd); - return; - -error_out: - return; + close(fd); } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 8da2ee418a..8e9f42d0c6 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -49,11 +49,8 @@ int kvmppc_get_htab_fd(bool write); int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns); int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, uint16_t n_valid, uint16_t n_invalid); -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index); -void kvmppc_hash64_free_pteg(uint64_t token); - -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, - target_ulong pte0, target_ulong pte1); +void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n); +void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1); bool kvmppc_has_cap_fixup_hcalls(void); bool kvmppc_has_cap_htm(void); int kvmppc_enable_hwrng(void); @@ -234,20 +231,13 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, abort(); } -static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, - target_ulong pte_index) +static inline void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, + hwaddr ptex, int n) { abort(); } -static inline void kvmppc_hash64_free_pteg(uint64_t token) -{ - abort(); -} - -static inline void kvmppc_hash64_write_pte(CPUPPCState *env, - target_ulong pte_index, - target_ulong pte0, target_ulong pte1) +static inline void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1) { abort(); } diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 76669ed82c..862e50e981 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -438,10 +438,12 @@ uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index) pte_offset = pte_index * HASH_PTE_SIZE_64; if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) { + ppc_hash_pte64_t *pteg = g_malloc(HASH_PTEG_SIZE_64); /* * HTAB is controlled by KVM. Fetch the PTEG into a new buffer. */ - token = kvmppc_hash64_read_pteg(cpu, pte_index); + kvmppc_read_hptes(pteg, pte_index, HPTES_PER_GROUP); + token = (uint64_t)(uintptr_t)pteg; } else if (cpu->env.external_htab) { /* * HTAB is controlled by QEMU. Just point to the internally @@ -457,7 +459,7 @@ uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index) void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token) { if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) { - kvmppc_hash64_free_pteg(token); + g_free((void *)token); } } @@ -916,7 +918,7 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu, CPUPPCState *env = &cpu->env; if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) { - kvmppc_hash64_write_pte(env, pte_index, pte0, pte1); + kvmppc_write_hpte(pte_index, pte0, pte1); return; } diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index 7a0b7fca41..73aeaa3b64 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -127,7 +127,7 @@ static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu, } } -typedef struct { +typedef struct ppc_hash_pte64 { uint64_t pte0, pte1; } ppc_hash_pte64_t;