base: invalidate entire range on VM-session detach

The requested guest-physical memory range may comprise multiple attached
dataspace regions, which must all be detached. This is not required for
the current vbox5 implementation, but for vbox6 as the current API
suggests these semantics.

This commit can be seen as intermediate fix as a real fix should change
the API to prevent long-running detach loops in core that may lock out
requests by other components.
This commit is contained in:
Christian Helmuth 2021-11-26 17:37:31 +01:00
parent 7eb3da71b5
commit 13dab699b1

View File

@ -123,26 +123,35 @@ void Vm_session_component::attach(Dataspace_capability const cap,
void Vm_session_component::detach(addr_t guest_phys, size_t size) void Vm_session_component::detach(addr_t guest_phys, size_t size)
{ {
if (guest_phys & 0xffful) { if (!size || (guest_phys & 0xffful) || (size & 0xffful)) {
size += 0x1000 - (guest_phys & 0xffful); warning("vm_session: skipping invalid memory detach addr=",
guest_phys &= ~0xffful; (void *)guest_phys, " size=", (void *)size);
return;
} }
if (size & 0xffful) addr_t const guest_phys_end = guest_phys + (size - 1);
size = align_addr(size, 12); addr_t addr = guest_phys;
do {
Rm_region *region = _map.metadata((void *)addr);
if (!size) /* walk region holes page-by-page */
return; size_t iteration_size = 0x1000;
if (region) {
iteration_size = region->size();
{
Rm_region *region = _map.metadata(reinterpret_cast<void *>(guest_phys));
if (region && guest_phys == region->base() && region->size() <= size) {
/* inform dataspace */ /* inform dataspace */
region->dataspace().detached_from(*region); region->dataspace().detached_from(*region);
/* cleanup metadata */ /* cleanup metadata */
_map.free(reinterpret_cast<void *>(region->base())); _map.free(reinterpret_cast<void *>(region->base()));
} }
}
if (addr >= guest_phys_end - (iteration_size - 1))
break;
addr += iteration_size;
} while (true);
/* kernel specific code to detach memory from guest */ /* kernel specific code to detach memory from guest */
_detach_vm_memory(guest_phys, size); _detach_vm_memory(guest_phys, size);