blob: ee01c09935f739aec5df7995a9ff391fcb4a1977 [file]
// Copyright 2018 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 <lib/fzl/vmar-manager.h>
#include <utility>
#include <fbl/alloc_checker.h>
namespace fzl {
fbl::RefPtr<VmarManager> VmarManager::Create(size_t size, fbl::RefPtr<VmarManager> parent,
zx_vm_option_t options) {
if (!size || (parent && !parent->vmar().is_valid())) {
return nullptr;
}
fbl::AllocChecker ac;
fbl::RefPtr<VmarManager> ret = fbl::AdoptRef(new (&ac) VmarManager());
if (!ac.check()) {
return nullptr;
}
zx_status_t res;
zx_handle_t p = parent ? parent->vmar().get() : zx::vmar::root_self()->get();
uintptr_t child_addr;
res = zx_vmar_allocate(p, options, 0, size, ret->vmar_.reset_and_get_address(), &child_addr);
if (res != ZX_OK) {
return nullptr;
}
ret->parent_ = std::move(parent);
ret->start_ = reinterpret_cast<void*>(child_addr);
ret->size_ = size;
ret->unowned_vmar_ = false;
return ret;
}
zx::result<fbl::RefPtr<VmarManager>> VmarManager::Use(const zx::unowned_vmar& vmar) {
fbl::AllocChecker ac;
fbl::RefPtr<VmarManager> ret = fbl::AdoptRef(new (&ac) VmarManager());
if (!ac.check()) {
return zx::error(ZX_ERR_NO_MEMORY);
}
if (!vmar->is_valid()) {
return zx::error(ZX_ERR_INVALID_ARGS);
}
zx_info_vmar_t info;
zx_status_t status = vmar->get_info(ZX_INFO_VMAR, &info, sizeof(info), nullptr, nullptr);
if (status != ZX_OK) [[unlikely]] {
return zx::error(status);
}
zx_info_handle_basic_t basic_info;
status = vmar->get_info(ZX_INFO_HANDLE_BASIC, &basic_info, sizeof(basic_info), nullptr, nullptr);
if (status != ZX_OK) [[unlikely]] {
return zx::error(status);
}
zx_info_handle_basic_t root_basic_info;
status = zx::vmar::root_self()->get_info(ZX_INFO_HANDLE_BASIC, &root_basic_info,
sizeof(root_basic_info), nullptr, nullptr);
if (status != ZX_OK) [[unlikely]] {
return zx::error(status);
}
if (basic_info.koid == root_basic_info.koid) {
// The nullptr is the sentinel for the root vmar.
return zx::ok(nullptr);
}
status = vmar->duplicate(ZX_RIGHT_SAME_RIGHTS, &ret->vmar_);
if (status != ZX_OK) {
return zx::error(status);
}
ret->parent_ = nullptr;
ret->start_ = reinterpret_cast<void*>(info.base);
ret->size_ = info.len;
ret->unowned_vmar_ = true;
return zx::ok(std::move(ret));
}
} // namespace fzl