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>
master
Cameron Esfahani 2019-11-24 12:05:23 -08:00 committed by Paolo Bonzini
parent c6f3215ffa
commit fbafbb6db7
1 changed files with 35 additions and 15 deletions

View File

@ -107,14 +107,14 @@ static void assert_hvf_ok(hv_return_t ret)
} }
/* Memory slots */ /* 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; hvf_slot *slot;
int x; int x;
for (x = 0; x < hvf_state->num_slots; ++x) { for (x = 0; x < hvf_state->num_slots; ++x) {
slot = &hvf_state->slots[x]; slot = &hvf_state->slots[x];
if (slot->size && start < (slot->start + slot->size) && if (slot->size && start < (slot->start + slot->size) &&
end > slot->start) { (start + size) > slot->start) {
return slot; return slot;
} }
} }
@ -129,12 +129,10 @@ struct mac_slot {
}; };
struct mac_slot mac_slots[32]; 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; struct mac_slot *macslot;
hv_memory_flags_t flags;
hv_return_t ret; hv_return_t ret;
macslot = &mac_slots[slot->slot_id]; macslot = &mac_slots[slot->slot_id];
@ -151,8 +149,6 @@ static int do_hvf_set_memory(hvf_slot *slot)
return 0; return 0;
} }
flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC;
macslot->present = 1; macslot->present = 1;
macslot->gpa_start = slot->start; macslot->gpa_start = slot->start;
macslot->size = slot->size; macslot->size = slot->size;
@ -165,14 +161,24 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
{ {
hvf_slot *mem; hvf_slot *mem;
MemoryRegion *area = section->mr; MemoryRegion *area = section->mr;
bool writeable = !area->readonly && !area->rom_device;
hv_memory_flags_t flags;
if (!memory_region_is_ram(area)) { 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( mem = hvf_find_overlap_slot(
section->offset_within_address_space, section->offset_within_address_space,
section->offset_within_address_space + int128_get64(section->size)); int128_get64(section->size));
if (mem && add) { if (mem && add) {
if (mem->size == int128_get64(section->size) && 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. */ /* Region needs to be reset. set the size to 0 and remap it. */
if (mem) { if (mem) {
mem->size = 0; mem->size = 0;
if (do_hvf_set_memory(mem)) { if (do_hvf_set_memory(mem, 0)) {
error_report("Failed to reset overlapping slot"); error_report("Failed to reset overlapping slot");
abort(); abort();
} }
@ -196,6 +202,13 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
return; 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. */ /* Now make a new slot. */
int x; int x;
@ -216,7 +229,7 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
mem->start = section->offset_within_address_space; mem->start = section->offset_within_address_space;
mem->region = area; mem->region = area;
if (do_hvf_set_memory(mem)) { if (do_hvf_set_memory(mem, flags)) {
error_report("Error registering new memory slot"); error_report("Error registering new memory slot");
abort(); abort();
} }
@ -345,7 +358,14 @@ static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual)
return false; 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) 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( slot = hvf_find_overlap_slot(
section->offset_within_address_space, 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 */ /* protect region against writes; begin tracking it */
if (on) { if (on) {
@ -720,7 +740,7 @@ int hvf_vcpu_exec(CPUState *cpu)
ret = EXCP_INTERRUPT; ret = EXCP_INTERRUPT;
break; break;
} }
/* Need to check if MMIO or unmmaped fault */ /* Need to check if MMIO or unmapped fault */
case EXIT_REASON_EPT_FAULT: case EXIT_REASON_EPT_FAULT:
{ {
hvf_slot *slot; hvf_slot *slot;
@ -731,7 +751,7 @@ int hvf_vcpu_exec(CPUState *cpu)
vmx_set_nmi_blocking(cpu); vmx_set_nmi_blocking(cpu);
} }
slot = hvf_find_overlap_slot(gpa, gpa); slot = hvf_find_overlap_slot(gpa, 1);
/* mmio */ /* mmio */
if (ept_emulation_fault(slot, gpa, exit_qual)) { if (ept_emulation_fault(slot, gpa, exit_qual)) {
struct x86_decode decode; struct x86_decode decode;