qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

target/ppc: Eliminate htab_base and htab_mask variables

CPUPPCState includes fields htab_base and htab_mask which store the base
address (GPA) and size (as a mask) of the guest's hashed page table (HPT).
These are set when the SDR1 register is updated.

Keeping these in sync with the SDR1 is actually a little bit fiddly, and
probably not useful for performance, since keeping them expands the size of
CPUPPCState. It also makes some upcoming changes harder to implement.

This patch removes these fields, in favour of calculating them directly
from the SDR1 contents when necessary.

This does make a change to the behaviour of attempting to write a bad value
(invalid HPT size) to the SDR1 with an mtspr instruction. Previously, the
bad value would be stored in SDR1 and could be retrieved with a later
mfspr, but the HPT size as used by the softmmu would be, clamped to the
allowed values. Now, writing a bad value is treated as a no-op. An error
message is printed in both new and old versions.

I'm not sure which behaviour, if either, matches real hardware. I don't
think it matters that much, since it's pretty clear that if an OS writes
a bad value to SDR1, it's not going to boot.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>

+73 -62
+2 -2
hw/ppc/spapr_hcall.c
··· 50 50 static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) 51 51 { 52 52 /* 53 - * hash value/pteg group index is normalized by htab_mask 53 + * hash value/pteg group index is normalized by HPT mask 54 54 */ 55 - if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) { 55 + if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { 56 56 return false; 57 57 } 58 58 return true;
-11
target/ppc/cpu.h
··· 306 306 #define TLB_MAS 3 307 307 #endif 308 308 309 - #define SDR_32_HTABORG 0xFFFF0000UL 310 - #define SDR_32_HTABMASK 0x000001FFUL 311 - 312 - #if defined(TARGET_PPC64) 313 - #define SDR_64_HTABORG 0xFFFFFFFFFFFC0000ULL 314 - #define SDR_64_HTABSIZE 0x000000000000001FULL 315 - #endif /* defined(TARGET_PPC64 */ 316 - 317 309 typedef struct ppc_slb_t ppc_slb_t; 318 310 struct ppc_slb_t { 319 311 uint64_t esid; ··· 1006 998 /* tcg TLB needs flush (deferred slb inval instruction typically) */ 1007 999 #endif 1008 1000 /* segment registers */ 1009 - hwaddr htab_base; 1010 - /* mask used to normalize hash value to PTEG index */ 1011 - hwaddr htab_mask; 1012 1001 target_ulong sr[32]; 1013 1002 /* externally stored hash table */ 1014 1003 uint8_t *external_htab;
-1
target/ppc/machine.c
··· 229 229 } 230 230 231 231 if (!env->external_htab) { 232 - /* Restore htab_base and htab_mask variables */ 233 232 ppc_store_sdr1(env, env->spr[SPR_SDR1]); 234 233 } 235 234
+7 -7
target/ppc/mmu-hash32.c
··· 304 304 305 305 hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash) 306 306 { 307 - CPUPPCState *env = &cpu->env; 307 + target_ulong mask = ppc_hash32_hpt_mask(cpu); 308 308 309 - return (hash * HASH_PTEG_SIZE_32) & env->htab_mask; 309 + return (hash * HASH_PTEG_SIZE_32) & mask; 310 310 } 311 311 312 312 static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off, ··· 339 339 target_ulong sr, target_ulong eaddr, 340 340 ppc_hash_pte32_t *pte) 341 341 { 342 - CPUPPCState *env = &cpu->env; 343 342 hwaddr pteg_off, pte_offset; 344 343 hwaddr hash; 345 344 uint32_t vsid, pgidx, ptem; ··· 353 352 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx 354 353 " htab_mask " TARGET_FMT_plx 355 354 " hash " TARGET_FMT_plx "\n", 356 - env->htab_base, env->htab_mask, hash); 355 + ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); 357 356 358 357 /* Primary PTEG lookup */ 359 358 qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx 360 359 " vsid=%" PRIx32 " ptem=%" PRIx32 361 360 " hash=" TARGET_FMT_plx "\n", 362 - env->htab_base, env->htab_mask, vsid, ptem, hash); 361 + ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), 362 + vsid, ptem, hash); 363 363 pteg_off = get_pteg_offset32(cpu, hash); 364 364 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte); 365 365 if (pte_offset == -1) { 366 366 /* Secondary PTEG lookup */ 367 367 qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx 368 368 " vsid=%" PRIx32 " api=%" PRIx32 369 - " hash=" TARGET_FMT_plx "\n", env->htab_base, 370 - env->htab_mask, vsid, ptem, ~hash); 369 + " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu), 370 + ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash); 371 371 pteg_off = get_pteg_offset32(cpu, ~hash); 372 372 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte); 373 373 }
+20 -6
target/ppc/mmu-hash32.h
··· 44 44 /* 45 45 * Hash page table definitions 46 46 */ 47 + #define SDR_32_HTABORG 0xFFFF0000UL 48 + #define SDR_32_HTABMASK 0x000001FFUL 47 49 48 50 #define HPTES_PER_GROUP 8 49 51 #define HASH_PTE_SIZE_32 8 ··· 65 67 #define HPTE32_R_WIMG 0x00000078 66 68 #define HPTE32_R_PP 0x00000003 67 69 70 + static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu) 71 + { 72 + return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG; 73 + } 74 + 75 + static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu) 76 + { 77 + return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) | 0xFFFF; 78 + } 79 + 68 80 static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu, 69 81 hwaddr pte_offset) 70 82 { 71 83 CPUPPCState *env = &cpu->env; 84 + target_ulong base = ppc_hash32_hpt_base(cpu); 72 85 73 86 assert(!env->external_htab); /* Not supported on 32-bit for now */ 74 - return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset); 87 + return ldl_phys(CPU(cpu)->as, base + pte_offset); 75 88 } 76 89 77 90 static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu, 78 91 hwaddr pte_offset) 79 92 { 93 + target_ulong base = ppc_hash32_hpt_base(cpu); 80 94 CPUPPCState *env = &cpu->env; 81 95 82 96 assert(!env->external_htab); /* Not supported on 32-bit for now */ 83 - return ldl_phys(CPU(cpu)->as, 84 - env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2); 97 + return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2); 85 98 } 86 99 87 100 static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu, 88 101 hwaddr pte_offset, target_ulong pte0) 89 102 { 90 103 CPUPPCState *env = &cpu->env; 104 + target_ulong base = ppc_hash32_hpt_base(cpu); 91 105 92 106 assert(!env->external_htab); /* Not supported on 32-bit for now */ 93 - stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0); 107 + stl_phys(CPU(cpu)->as, base + pte_offset, pte0); 94 108 } 95 109 96 110 static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu, 97 111 hwaddr pte_offset, target_ulong pte1) 98 112 { 99 113 CPUPPCState *env = &cpu->env; 114 + target_ulong base = ppc_hash32_hpt_base(cpu); 100 115 101 116 assert(!env->external_htab); /* Not supported on 32-bit for now */ 102 - stl_phys(CPU(cpu)->as, 103 - env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1); 117 + stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1); 104 118 } 105 119 106 120 typedef struct {
+15 -20
target/ppc/mmu-hash64.c
··· 304 304 CPUPPCState *env = &cpu->env; 305 305 target_ulong htabsize = value & SDR_64_HTABSIZE; 306 306 307 - env->spr[SPR_SDR1] = value; 308 307 if (htabsize > 28) { 309 308 error_setg(errp, 310 309 "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1", 311 310 htabsize); 312 - htabsize = 28; 311 + return; 313 312 } 314 - env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1; 315 - env->htab_base = value & SDR_64_HTABORG; 313 + env->spr[SPR_SDR1] = value; 316 314 } 317 315 318 316 void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift, ··· 332 330 error_propagate(errp, local_err); 333 331 return; 334 332 } 335 - 336 - /* Not strictly necessary, but makes it clearer that an external 337 - * htab is in use when debugging */ 338 - env->htab_base = -1; 339 333 340 334 if (kvm_enabled()) { 341 335 if (kvmppc_put_books_sregs(cpu) < 0) { ··· 450 444 * accessible PTEG. 451 445 */ 452 446 hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset); 453 - } else if (cpu->env.htab_base) { 447 + } else if (ppc_hash64_hpt_base(cpu)) { 448 + hwaddr base = ppc_hash64_hpt_base(cpu); 454 449 hwaddr plen = n * HASH_PTE_SIZE_64; 455 - hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset, 456 - &plen, false); 450 + hptes = address_space_map(CPU(cpu)->as, base + pte_offset, 451 + &plen, false); 457 452 if (plen < (n * HASH_PTE_SIZE_64)) { 458 453 hw_error("%s: Unable to map all requested HPTEs\n", __func__); 459 454 } ··· 514 509 target_ulong ptem, 515 510 ppc_hash_pte64_t *pte, unsigned *pshift) 516 511 { 517 - CPUPPCState *env = &cpu->env; 518 512 int i; 519 513 const ppc_hash_pte64_t *pteg; 520 514 target_ulong pte0, pte1; 521 515 target_ulong ptex; 522 516 523 - ptex = (hash & env->htab_mask) * HPTES_PER_GROUP; 517 + ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP; 524 518 pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); 525 519 if (!pteg) { 526 520 return -1; ··· 598 592 qemu_log_mask(CPU_LOG_MMU, 599 593 "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx 600 594 " hash " TARGET_FMT_plx "\n", 601 - env->htab_base, env->htab_mask, hash); 595 + ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), hash); 602 596 603 597 /* Primary PTEG lookup */ 604 598 qemu_log_mask(CPU_LOG_MMU, 605 599 "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx 606 600 " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx 607 601 " hash=" TARGET_FMT_plx "\n", 608 - env->htab_base, env->htab_mask, vsid, ptem, hash); 602 + ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), 603 + vsid, ptem, hash); 609 604 ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift); 610 605 611 606 if (ptex == -1) { ··· 614 609 qemu_log_mask(CPU_LOG_MMU, 615 610 "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx 616 611 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx 617 - " hash=" TARGET_FMT_plx "\n", env->htab_base, 618 - env->htab_mask, vsid, ptem, ~hash); 612 + " hash=" TARGET_FMT_plx "\n", ppc_hash64_hpt_base(cpu), 613 + ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash); 619 614 620 615 ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift); 621 616 } ··· 933 928 stq_p(env->external_htab + offset, pte0); 934 929 stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1); 935 930 } else { 936 - stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0); 937 - stq_phys(CPU(cpu)->as, 938 - env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1); 931 + hwaddr base = ppc_hash64_hpt_base(cpu); 932 + stq_phys(CPU(cpu)->as, base + offset, pte0); 933 + stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1); 939 934 } 940 935 } 941 936
+13
target/ppc/mmu-hash64.h
··· 56 56 * Hash page table definitions 57 57 */ 58 58 59 + #define SDR_64_HTABORG 0xFFFFFFFFFFFC0000ULL 60 + #define SDR_64_HTABSIZE 0x000000000000001FULL 61 + 59 62 #define HPTES_PER_GROUP 8 60 63 #define HASH_PTE_SIZE_64 16 61 64 #define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP) ··· 90 93 91 94 #define HPTE64_V_1TB_SEG 0x4000000000000000ULL 92 95 #define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL 96 + 97 + static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu) 98 + { 99 + return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG; 100 + } 101 + 102 + static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu) 103 + { 104 + return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1; 105 + } 93 106 94 107 void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value, 95 108 Error **errp);
+16 -15
target/ppc/mmu_helper.c
··· 466 466 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, 467 467 target_ulong eaddr, int rw, int type) 468 468 { 469 + PowerPCCPU *cpu = ppc_env_get_cpu(env); 469 470 hwaddr hash; 470 471 target_ulong vsid; 471 472 int ds, pr, target_page_bits; ··· 503 504 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx 504 505 " htab_mask " TARGET_FMT_plx 505 506 " hash " TARGET_FMT_plx "\n", 506 - env->htab_base, env->htab_mask, hash); 507 + ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); 507 508 ctx->hash[0] = hash; 508 509 ctx->hash[1] = ~hash; 509 510 ··· 518 519 uint32_t a0, a1, a2, a3; 519 520 520 521 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx 521 - "\n", env->htab_base, env->htab_mask + 0x80); 522 - for (curaddr = env->htab_base; 523 - curaddr < (env->htab_base + env->htab_mask + 0x80); 522 + "\n", ppc_hash32_hpt_base(cpu), 523 + ppc_hash32_hpt_mask(env) + 0x80); 524 + for (curaddr = ppc_hash32_hpt_base(cpu); 525 + curaddr < (ppc_hash32_hpt_base(cpu) 526 + + ppc_hash32_hpt_mask(cpu) + 0x80); 524 527 curaddr += 16) { 525 528 a0 = ldl_phys(cs->as, curaddr); 526 529 a1 = ldl_phys(cs->as, curaddr + 4); ··· 1205 1208 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf, 1206 1209 CPUPPCState *env) 1207 1210 { 1211 + PowerPCCPU *cpu = ppc_env_get_cpu(env); 1208 1212 ppc6xx_tlb_t *tlb; 1209 1213 target_ulong sr; 1210 1214 int type, way, entry, i; 1211 1215 1212 - cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base); 1213 - cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask); 1216 + cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu)); 1217 + cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu)); 1214 1218 1215 1219 cpu_fprintf(f, "\nSegment registers:\n"); 1216 1220 for (i = 0; i < 32; i++) { ··· 1592 1596 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; 1593 1597 tlb_miss: 1594 1598 env->error_code |= ctx.key << 19; 1595 - env->spr[SPR_HASH1] = env->htab_base + 1599 + env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) + 1596 1600 get_pteg_offset32(cpu, ctx.hash[0]); 1597 - env->spr[SPR_HASH2] = env->htab_base + 1601 + env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) + 1598 1602 get_pteg_offset32(cpu, ctx.hash[1]); 1599 1603 break; 1600 1604 case POWERPC_MMU_SOFT_74xx: ··· 1999 2003 { 2000 2004 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); 2001 2005 assert(!env->external_htab); 2002 - env->spr[SPR_SDR1] = value; 2003 2006 #if defined(TARGET_PPC64) 2004 2007 if (env->mmu_model & POWERPC_MMU_64) { 2005 2008 PowerPCCPU *cpu = ppc_env_get_cpu(env); ··· 2009 2012 if (local_err) { 2010 2013 error_report_err(local_err); 2011 2014 error_free(local_err); 2015 + return; 2012 2016 } 2013 - } else 2014 - #endif /* defined(TARGET_PPC64) */ 2015 - { 2016 - /* FIXME: Should check for valid HTABMASK values */ 2017 - env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF; 2018 - env->htab_base = value & SDR_32_HTABORG; 2019 2017 } 2018 + #endif /* defined(TARGET_PPC64) */ 2019 + /* FIXME: Should check for valid HTABMASK values in 32-bit case */ 2020 + env->spr[SPR_SDR1] = value; 2020 2021 } 2021 2022 2022 2023 /* Segment registers load and store */