blob: 6cd1d0a63e69855bb9c97f95d3108d88301934be [file] [log] [blame]
// 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.
#ifndef BITMAP_STORAGE_H_
#define BITMAP_STORAGE_H_
#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_.data(); }
const void* GetData() const { return storage_.data(); }
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>(zx_system_get_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>(zx_system_get_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
#endif // BITMAP_STORAGE_H_