i386: hvf: implement vga dirty page tracking
This patch implements setting the tracking of dirty vga pages, using hvf's interface to protect guest memory. It uses the MemoryListener callback mechanism through .log_start/stop/sync Signed-off-by: Sergio Andres Gomez Del Real <Sergio.G.DelReal@gmail.com> Message-Id: <20170913090522.4022-13-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
d6dcc5583e
commit
babfa20ca4
@ -34,11 +34,16 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
|||||||
#define hvf_get_supported_cpuid(func, idx, reg) 0
|
#define hvf_get_supported_cpuid(func, idx, reg) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* hvf_slot flags */
|
||||||
|
#define HVF_SLOT_LOG (1 << 0)
|
||||||
|
|
||||||
typedef struct hvf_slot {
|
typedef struct hvf_slot {
|
||||||
uint64_t start;
|
uint64_t start;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint8_t *mem;
|
uint8_t *mem;
|
||||||
int slot_id;
|
int slot_id;
|
||||||
|
uint32_t flags;
|
||||||
|
MemoryRegion *region;
|
||||||
} hvf_slot;
|
} hvf_slot;
|
||||||
|
|
||||||
typedef struct hvf_vcpu_caps {
|
typedef struct hvf_vcpu_caps {
|
||||||
|
@ -193,6 +193,7 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
|||||||
mem->size = int128_get64(section->size);
|
mem->size = int128_get64(section->size);
|
||||||
mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
|
mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
|
||||||
mem->start = section->offset_within_address_space;
|
mem->start = section->offset_within_address_space;
|
||||||
|
mem->region = area;
|
||||||
|
|
||||||
if (do_hvf_set_memory(mem)) {
|
if (do_hvf_set_memory(mem)) {
|
||||||
error_report("Error registering new memory slot\n");
|
error_report("Error registering new memory slot\n");
|
||||||
@ -289,8 +290,7 @@ void hvf_cpu_synchronize_post_init(CPUState *cpu_state)
|
|||||||
run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: ept fault handlig */
|
static bool ept_emulation_fault(hvf_slot *slot, addr_t gpa, uint64_t ept_qual)
|
||||||
static bool ept_emulation_fault(uint64_t ept_qual)
|
|
||||||
{
|
{
|
||||||
int read, write;
|
int read, write;
|
||||||
|
|
||||||
@ -306,6 +306,14 @@ static bool ept_emulation_fault(uint64_t ept_qual)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (write && slot) {
|
||||||
|
if (slot->flags & HVF_SLOT_LOG) {
|
||||||
|
memory_region_set_dirty(slot->region, gpa - slot->start, 1);
|
||||||
|
hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
|
||||||
|
HV_MEMORY_READ | HV_MEMORY_WRITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The EPT violation must have been caused by accessing a
|
* The EPT violation must have been caused by accessing a
|
||||||
* guest-physical address that is a translation of a guest-linear
|
* guest-physical address that is a translation of a guest-linear
|
||||||
@ -316,7 +324,58 @@ static bool ept_emulation_fault(uint64_t ept_qual)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return !slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
|
||||||
|
{
|
||||||
|
hvf_slot *slot;
|
||||||
|
|
||||||
|
slot = hvf_find_overlap_slot(
|
||||||
|
section->offset_within_address_space,
|
||||||
|
section->offset_within_address_space + int128_get64(section->size));
|
||||||
|
|
||||||
|
/* protect region against writes; begin tracking it */
|
||||||
|
if (on) {
|
||||||
|
slot->flags |= HVF_SLOT_LOG;
|
||||||
|
hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
|
||||||
|
HV_MEMORY_READ);
|
||||||
|
/* stop tracking region*/
|
||||||
|
} else {
|
||||||
|
slot->flags &= ~HVF_SLOT_LOG;
|
||||||
|
hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
|
||||||
|
HV_MEMORY_READ | HV_MEMORY_WRITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_log_start(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section, int old, int new)
|
||||||
|
{
|
||||||
|
if (old != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hvf_set_dirty_tracking(section, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_log_stop(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section, int old, int new)
|
||||||
|
{
|
||||||
|
if (new != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hvf_set_dirty_tracking(section, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_log_sync(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* sync of dirty pages is handled elsewhere; just make sure we keep
|
||||||
|
* tracking the region.
|
||||||
|
*/
|
||||||
|
hvf_set_dirty_tracking(section, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hvf_region_add(MemoryListener *listener,
|
static void hvf_region_add(MemoryListener *listener,
|
||||||
@ -335,6 +394,9 @@ static MemoryListener hvf_memory_listener = {
|
|||||||
.priority = 10,
|
.priority = 10,
|
||||||
.region_add = hvf_region_add,
|
.region_add = hvf_region_add,
|
||||||
.region_del = hvf_region_del,
|
.region_del = hvf_region_del,
|
||||||
|
.log_start = hvf_log_start,
|
||||||
|
.log_stop = hvf_log_stop,
|
||||||
|
.log_sync = hvf_log_sync,
|
||||||
};
|
};
|
||||||
|
|
||||||
void hvf_reset_vcpu(CPUState *cpu) {
|
void hvf_reset_vcpu(CPUState *cpu) {
|
||||||
@ -607,7 +669,7 @@ int hvf_vcpu_exec(CPUState *cpu)
|
|||||||
|
|
||||||
slot = hvf_find_overlap_slot(gpa, gpa);
|
slot = hvf_find_overlap_slot(gpa, gpa);
|
||||||
/* mmio */
|
/* mmio */
|
||||||
if (ept_emulation_fault(exit_qual) && !slot) {
|
if (ept_emulation_fault(slot, gpa, exit_qual)) {
|
||||||
struct x86_decode decode;
|
struct x86_decode decode;
|
||||||
|
|
||||||
load_regs(cpu);
|
load_regs(cpu);
|
||||||
@ -618,9 +680,6 @@ int hvf_vcpu_exec(CPUState *cpu)
|
|||||||
store_regs(cpu);
|
store_regs(cpu);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef DIRTY_VGA_TRACKING
|
|
||||||
/* TODO: handle dirty page tracking */
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EXIT_REASON_INOUT:
|
case EXIT_REASON_INOUT:
|
||||||
|
Loading…
Reference in New Issue
Block a user