diff options
author | Cameron Esfahani | 2019-11-24 21:05:23 +0100 |
---|---|---|
committer | Paolo Bonzini | 2019-11-26 09:58:33 +0100 |
commit | fbafbb6db77428d9a0bf22ea8e9c4a07140ae7d9 (patch) | |
tree | 7fa26d7b7b619a103cb9ef8fb06b2643022cc655 /target/i386 | |
parent | target/i386: add two missing VMX features for Skylake and CascadeLake Server (diff) | |
download | qemu-fbafbb6db77428d9a0bf22ea8e9c4a07140ae7d9.tar.gz qemu-fbafbb6db77428d9a0bf22ea8e9c4a07140ae7d9.tar.xz qemu-fbafbb6db77428d9a0bf22ea8e9c4a07140ae7d9.zip |
hvf: non-RAM, non-ROMD memory ranges are now correctly mapped in
If an area is non-RAM and non-ROMD, then remove mappings so accesses
will trap and can be emulated. Change hvf_find_overlap_slot() to take
a size instead of an end address: it wouldn't return a slot because
callers would pass the same address for start and end. Don't always
map area as read/write/execute, respect area flags.
Signed-off-by: Cameron Esfahani <dirty@apple.com>
Message-Id: <1d8476c8f86959273fbdf23c86f8b4b611f5e2e1.1574625592.git.dirty@apple.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386')
-rw-r--r-- | target/i386/hvf/hvf.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 231732aaf7..0b50cfcbc6 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -107,14 +107,14 @@ static void assert_hvf_ok(hv_return_t ret) } /* Memory slots */ -hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t end) +hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size) { hvf_slot *slot; int x; for (x = 0; x < hvf_state->num_slots; ++x) { slot = &hvf_state->slots[x]; if (slot->size && start < (slot->start + slot->size) && - end > slot->start) { + (start + size) > slot->start) { return slot; } } @@ -129,12 +129,10 @@ struct mac_slot { }; struct mac_slot mac_slots[32]; -#define ALIGN(x, y) (((x) + (y) - 1) & ~((y) - 1)) -static int do_hvf_set_memory(hvf_slot *slot) +static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags) { struct mac_slot *macslot; - hv_memory_flags_t flags; hv_return_t ret; macslot = &mac_slots[slot->slot_id]; @@ -151,8 +149,6 @@ static int do_hvf_set_memory(hvf_slot *slot) return 0; } - flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC; - macslot->present = 1; macslot->gpa_start = slot->start; macslot->size = slot->size; @@ -165,14 +161,24 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add) { hvf_slot *mem; MemoryRegion *area = section->mr; + bool writeable = !area->readonly && !area->rom_device; + hv_memory_flags_t flags; if (!memory_region_is_ram(area)) { - return; + if (writeable) { + return; + } else if (!memory_region_is_romd(area)) { + /* + * If the memory device is not in romd_mode, then we actually want + * to remove the hvf memory slot so all accesses will trap. + */ + add = false; + } } mem = hvf_find_overlap_slot( section->offset_within_address_space, - section->offset_within_address_space + int128_get64(section->size)); + int128_get64(section->size)); if (mem && add) { if (mem->size == int128_get64(section->size) && @@ -186,7 +192,7 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add) /* Region needs to be reset. set the size to 0 and remap it. */ if (mem) { mem->size = 0; - if (do_hvf_set_memory(mem)) { + if (do_hvf_set_memory(mem, 0)) { error_report("Failed to reset overlapping slot"); abort(); } @@ -196,6 +202,13 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add) return; } + if (area->readonly || + (!memory_region_is_ram(area) && memory_region_is_romd(area))) { + flags = HV_MEMORY_READ | HV_MEMORY_EXEC; + } else { + flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC; + } + /* Now make a new slot. */ int x; @@ -216,7 +229,7 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add) mem->start = section->offset_within_address_space; mem->region = area; - if (do_hvf_set_memory(mem)) { + if (do_hvf_set_memory(mem, flags)) { error_report("Error registering new memory slot"); abort(); } @@ -345,7 +358,14 @@ static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual) return false; } - return !slot; + if (!slot) { + return true; + } + if (!memory_region_is_ram(slot->region) && + !(read && memory_region_is_romd(slot->region))) { + return true; + } + return false; } static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on) @@ -354,7 +374,7 @@ static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on) slot = hvf_find_overlap_slot( section->offset_within_address_space, - section->offset_within_address_space + int128_get64(section->size)); + int128_get64(section->size)); /* protect region against writes; begin tracking it */ if (on) { @@ -720,7 +740,7 @@ int hvf_vcpu_exec(CPUState *cpu) ret = EXCP_INTERRUPT; break; } - /* Need to check if MMIO or unmmaped fault */ + /* Need to check if MMIO or unmapped fault */ case EXIT_REASON_EPT_FAULT: { hvf_slot *slot; @@ -731,7 +751,7 @@ int hvf_vcpu_exec(CPUState *cpu) vmx_set_nmi_blocking(cpu); } - slot = hvf_find_overlap_slot(gpa, gpa); + slot = hvf_find_overlap_slot(gpa, 1); /* mmio */ if (ept_emulation_fault(slot, gpa, exit_qual)) { struct x86_decode decode; |