| // Copyright 2016 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. |
| |
| #pragma once |
| |
| #include <limits.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <zircon/process.h> |
| #include <zircon/types.h> |
| #include <fbl/algorithm.h> |
| #include <fbl/alloc_checker.h> |
| #include <fbl/array.h> |
| #include <fbl/macros.h> |
| |
| #if !defined _KERNEL && defined __Fuchsia__ |
| #include <lib/zx/vmo.h> |
| #include <zircon/syscalls.h> |
| #endif |
| |
| namespace bitmap { |
| |
| class DefaultStorage { |
| public: |
| DISALLOW_COPY_ASSIGN_AND_MOVE(DefaultStorage); |
| DefaultStorage() = default; |
| |
| zx_status_t Allocate(size_t size) { |
| fbl::AllocChecker ac; |
| auto arr = new (&ac) uint8_t[size]; |
| if (!ac.check()) { |
| return ZX_ERR_NO_MEMORY; |
| } |
| storage_.reset(arr, size); |
| return ZX_OK; |
| } |
| void* GetData() { return storage_.get(); } |
| const void* GetData() const { return storage_.get(); } |
| private: |
| fbl::Array<uint8_t> storage_; |
| }; |
| |
| template <size_t N> |
| class FixedStorage { |
| public: |
| DISALLOW_COPY_ASSIGN_AND_MOVE(FixedStorage); |
| FixedStorage() = default; |
| |
| zx_status_t Allocate(size_t size) { |
| ZX_ASSERT(size <= N); |
| return ZX_OK; |
| } |
| void* GetData() { return storage_; } |
| const void* GetData() const { return storage_; } |
| private: |
| size_t storage_[(N + sizeof(size_t) - 1) / sizeof(size_t)]; |
| }; |
| |
| #if !defined _KERNEL && defined __Fuchsia__ |
| class VmoStorage { |
| public: |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(VmoStorage); |
| VmoStorage() : |
| vmo_(ZX_HANDLE_INVALID), |
| mapped_addr_(0), |
| size_(0) {} |
| |
| VmoStorage(VmoStorage&& rhs) |
| : vmo_(std::move(rhs.vmo_)), mapped_addr_(rhs.mapped_addr_), size_(rhs.size_) { |
| rhs.mapped_addr_ = 0; |
| } |
| |
| VmoStorage& operator=(VmoStorage&& rhs) { |
| Release(); |
| vmo_ = std::move(rhs.vmo_); |
| mapped_addr_ = rhs.mapped_addr_; |
| size_ = rhs.size_; |
| rhs.mapped_addr_ = 0; |
| return *this; |
| } |
| |
| ~VmoStorage() { |
| Release(); |
| } |
| |
| zx_status_t Allocate(size_t size) { |
| Release(); |
| size_ = fbl::round_up(size, static_cast<size_t>(PAGE_SIZE)); |
| zx_status_t status; |
| if ((status = zx::vmo::create(size_, ZX_VMO_RESIZABLE, &vmo_)) != ZX_OK) { |
| return status; |
| } else if ((status = zx_vmar_map(zx_vmar_root_self(), |
| ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, |
| 0, vmo_.get(), 0, size_, &mapped_addr_)) != ZX_OK) { |
| vmo_.reset(); |
| return status; |
| } |
| vmo_.set_property(ZX_PROP_NAME, "vmo-backed-bitmap", strlen("vmo-backed-bitmap")); |
| return ZX_OK; |
| } |
| |
| zx_status_t Grow(size_t size) { |
| if (size <= size_) { |
| return ZX_OK; |
| } |
| |
| size = fbl::round_up(size, static_cast<size_t>(PAGE_SIZE)); |
| zx_status_t status; |
| if ((status = vmo_.set_size(size)) != ZX_OK) { |
| return status; |
| } |
| |
| |
| zx_info_vmar_t vmar_info; |
| if ((status = zx_object_get_info(zx_vmar_root_self(), ZX_INFO_VMAR, |
| &vmar_info, sizeof(vmar_info), NULL, |
| NULL)) != ZX_OK) { |
| return status; |
| } |
| |
| // Try to extend mapping |
| uintptr_t addr; |
| if ((status = zx_vmar_map(zx_vmar_root_self(), |
| ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | |
| ZX_VM_SPECIFIC, |
| mapped_addr_ + size_ - |
| vmar_info.base, vmo_.get(), size_, size - size_, |
| &addr)) != ZX_OK) { |
| // If extension fails, create entirely new mapping and unmap the old one |
| if ((status = zx_vmar_map(zx_vmar_root_self(), |
| ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, |
| 0, vmo_.get(), 0, size, &addr)) != ZX_OK) { |
| return status; |
| } |
| |
| if ((status = zx_vmar_unmap(zx_vmar_root_self(), mapped_addr_, size_)) != ZX_OK) { |
| return status; |
| } |
| |
| mapped_addr_ = addr; |
| } |
| |
| return ZX_OK; |
| } |
| |
| void* GetData() { ZX_DEBUG_ASSERT(mapped_addr_ != 0); return (void*) mapped_addr_; } |
| const void* GetData() const { ZX_DEBUG_ASSERT(mapped_addr_ != 0); return (void*) mapped_addr_; } |
| const zx::vmo& GetVmo() const { ZX_DEBUG_ASSERT(mapped_addr_ != 0); return vmo_; } |
| private: |
| void Release() { |
| if (mapped_addr_ != 0) { |
| zx_vmar_unmap(zx_vmar_root_self(), mapped_addr_, size_); |
| } |
| mapped_addr_ = 0; |
| } |
| zx::vmo vmo_; |
| uintptr_t mapped_addr_; |
| size_t size_; |
| }; |
| #endif |
| |
| } // namespace bitmap |