diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2023-10-27 00:24:30 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2023-11-06 18:49:33 -0800 |
commit | d7553f3591bbf495b4c35355179c793d03e106dc (patch) | |
tree | cd4467d1966f16e720133e57dfdf2f9ccdb7152a /target/hppa/machine.c | |
parent | 09cae8255ffc6d133b32073b6d8d99b56b3379b5 (diff) |
target/hppa: Populate an interval tree with valid tlb entries
Complete the data structure conversion started earlier. This reduces
the perf overhead of hppa_get_physical_address from ~5% to ~0.25%.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/hppa/machine.c')
-rw-r--r-- | target/hppa/machine.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/target/hppa/machine.c b/target/hppa/machine.c index 4535195ca2..ab3e8c81fa 100644 --- a/target/hppa/machine.c +++ b/target/hppa/machine.c @@ -72,8 +72,6 @@ static int get_tlb(QEMUFile *f, void *opaque, size_t size, HPPATLBEntry *ent = opaque; uint32_t val; - memset(ent, 0, sizeof(*ent)); - ent->itree.start = qemu_get_be64(f); ent->pa = qemu_get_betr(f); val = qemu_get_be32(f); @@ -122,6 +120,53 @@ static const VMStateInfo vmstate_tlb = { .put = put_tlb, }; +static int tlb_pre_load(void *opaque) +{ + CPUHPPAState *env = opaque; + + /* + * Zap the entire tlb, on-the-side data structures and all. + * Each tlb entry will have data re-filled by put_tlb. + */ + memset(env->tlb, 0, sizeof(env->tlb)); + memset(&env->tlb_root, 0, sizeof(env->tlb_root)); + env->tlb_unused = NULL; + env->tlb_partial = NULL; + + return 0; +} + +static int tlb_post_load(void *opaque, int version_id) +{ + CPUHPPAState *env = opaque; + HPPATLBEntry **unused = &env->tlb_unused; + HPPATLBEntry *partial = NULL; + + /* + * Re-create the interval tree from the valid entries. + * Truely invalid entries should have start == end == 0. + * Otherwise it should be the in-flight tlb_partial entry. + */ + for (uint32_t i = 0; i < ARRAY_SIZE(env->tlb); ++i) { + HPPATLBEntry *e = &env->tlb[i]; + + if (e->entry_valid) { + interval_tree_insert(&e->itree, &env->tlb_root); + } else if (i < HPPA_BTLB_ENTRIES) { + /* btlb not in unused list */ + } else if (partial == NULL && e->itree.start < e->itree.last) { + partial = e; + } else { + *unused = e; + unused = &e->unused_next; + } + } + env->tlb_partial = partial; + *unused = NULL; + + return 0; +} + static VMStateField vmstate_env_fields[] = { VMSTATE_UINTTR_ARRAY(gr, CPUHPPAState, 32), VMSTATE_UINT64_ARRAY(fr, CPUHPPAState, 32), @@ -164,6 +209,8 @@ static const VMStateDescription vmstate_env = { .version_id = 1, .minimum_version_id = 1, .fields = vmstate_env_fields, + .pre_load = tlb_pre_load, + .post_load = tlb_post_load, }; static VMStateField vmstate_cpu_fields[] = { |