| // Copyright 2019 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/media/codec_impl/fake_map_range.h> |
| #include <stdio.h> |
| #include <zircon/assert.h> |
| |
| #include <fbl/algorithm.h> |
| |
| zx_status_t FakeMapRange::Create(size_t size, fit::optional<FakeMapRange>* result_param) { |
| fit::optional<FakeMapRange>& result = *result_param; |
| // We can't emplace without making more constructors public or adding brittle friending of |
| // optional implementation details, so instead we create one locally and move it in, since it's |
| // fine if the move constructor is public. This also avoids putting anything in *result_param |
| // until we know we'll return ZX_OK. |
| FakeMapRange local_result(size); |
| zx_status_t status = local_result.Init(); |
| if (status != ZX_OK) { |
| return status; |
| } |
| result.emplace(std::move(local_result)); |
| return ZX_OK; |
| } |
| |
| FakeMapRange::~FakeMapRange() { |
| // Explicitly destroy(), else the kernel intentionally keeps the VMAR's vaddr range despite the |
| // zx::vmar::~vmar closing the handle. |
| if (vmar_) { |
| vmar_.destroy(); |
| } |
| } |
| |
| FakeMapRange::FakeMapRange(FakeMapRange&& other) |
| : raw_size_(other.raw_size_), |
| vmar_size_(other.vmar_size_), |
| vmar_(std::move(other.vmar_)), |
| vmar_addr_(other.vmar_addr_), |
| is_ready_(other.is_ready_) { |
| // Helps detect usage after moving out. |
| other.is_ready_ = false; |
| } |
| |
| FakeMapRange& FakeMapRange::operator=(FakeMapRange&& other) { |
| if (vmar_) { |
| vmar_.destroy(); |
| } |
| raw_size_ = other.raw_size_; |
| vmar_size_ = other.vmar_size_; |
| vmar_ = std::move(other.vmar_); |
| vmar_addr_ = other.vmar_addr_; |
| is_ready_ = other.is_ready_; |
| other.is_ready_ = false; |
| return *this; |
| } |
| |
| uint8_t* FakeMapRange::base() { |
| ZX_DEBUG_ASSERT(is_ready_); |
| ZX_DEBUG_ASSERT(vmar_addr_); |
| return reinterpret_cast<uint8_t*>(vmar_addr_); |
| } |
| |
| size_t FakeMapRange::size() { |
| // Require that size() only be called after Init() since we can. |
| ZX_DEBUG_ASSERT(is_ready_); |
| return raw_size_; |
| } |
| |
| FakeMapRange::FakeMapRange(size_t size) : raw_size_(size) { |
| ZX_DEBUG_ASSERT(raw_size_); |
| |
| // The worst-case required vmar_size_ will be when this instance is used for a buffer where |
| // vmo_usable_start() % ZX_PAGE_SIZE == ZX_PAGE_SIZE - 1. In that case, we need a whole page just |
| // for the first byte, and also the rest of the page containing the last byte. |
| |
| vmar_size_ = fbl::round_up(ZX_PAGE_SIZE - 1 + raw_size_, ZX_PAGE_SIZE); |
| ZX_DEBUG_ASSERT(vmar_size_ % ZX_PAGE_SIZE == 0); |
| ZX_DEBUG_ASSERT(ZX_PAGE_SIZE - 1 + raw_size_ <= vmar_size_); |
| } |
| |
| zx_status_t FakeMapRange::Init() { |
| // We don't intend to map anything in the VMAR, so don't need ZX_VM_CAN_MAP_READ or WRITE. |
| constexpr uint32_t kAllocateOptions = 0; |
| zx_status_t status = |
| zx::vmar::root_self()->allocate2(kAllocateOptions, 0, vmar_size_, &vmar_, &vmar_addr_); |
| if (status != ZX_OK) { |
| printf("zx::vmar::root_self()->allocate2() failed - status: %d\n", status); |
| return status; |
| } |
| // We don't need to call vmar::protect(0), because a VMAR without any sub-regions already faults |
| // on any access. |
| is_ready_ = true; |
| return ZX_OK; |
| } |