blob: 7747a0a33c3357f084ea2e661e46710c99502c60 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/virtualization/bin/vmm/device/phys_mem.h"
#include <lib/zx/vmar.h>
zx_status_t PhysMem::Init(zx::vmo vmo) {
size_t vmo_size;
zx_status_t status = vmo.get_size(&vmo_size);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to query VMO size";
return status;
}
// This PhysMem instantiation is not using a device memory aware VMAR mapping, so create a single
// guest memory region encompassing all guest physical memory.
std::vector<GuestMemoryRegion> guest_mem = {{.base = 0, .size = vmo_size}};
return Init(guest_mem, std::move(vmo));
}
zx_status_t PhysMem::Init(const std::vector<GuestMemoryRegion>& guest_mem, zx::vmo vmo) {
vmo_ = std::move(vmo);
const GuestMemoryRegion& final_region =
*std::max_element(guest_mem.begin(), guest_mem.end(), GuestMemoryRegion::CompareMinByBase);
vmo_size_ = final_region.base + final_region.size;
zx_status_t status = zx::vmar::root_self()->allocate(
ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, vmo_size_, &child_vmar_,
&addr_);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to create child VMAR of size " << vmo_size_;
return status;
}
static const uint32_t page_size = zx_system_get_page_size();
for (const GuestMemoryRegion& region : guest_mem) {
FX_CHECK(region.base % page_size == 0)
<< std::hex
<< "Guest memory region must start at a page aligned address, but region begins at 0x"
<< region.base;
FX_CHECK(region.size % page_size == 0)
<< std::hex
<< "Guest memory region must end at a page aligned address, but region ends at 0x"
<< (region.base + region.size);
zx_gpaddr_t addr_within_child;
status = child_vmar_.map(
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC | ZX_VM_REQUIRE_NON_RESIZABLE,
region.base, vmo_, region.base, region.size, &addr_within_child);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to map guest physical memory region " << region.base
<< " - " << region.base + region.size;
return status;
}
}
return ZX_OK;
}
PhysMem::~PhysMem() {
if (child_vmar_.is_valid()) {
zx_status_t status = child_vmar_.destroy();
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to destroy child VMAR";
}
}
}