aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorMattias Nissler <mnissler@chromium.org>2016-01-28 23:45:28 +0100
committerMattias Nissler <mnissler@google.com>2016-02-15 10:07:59 +0100
commitaa4a1a8c35e0b944fbf721ff00fd03b52a59f8aa (patch)
tree156c7c1866683f31d1742a82852e9122bec05e17 /core
parentb07c8946c00857d2e843d2ec5d49f9a753d451e0 (diff)
downloadnvram-aa4a1a8c35e0b944fbf721ff00fd03b52a59f8aa.tar.gz
Implement info operation and space creation.
This implements the first batch of NVRAM operations: GetInfo, CreateSpace, GetSpaceInfo and DisableCreate. Operations to manipulate individual spaces will follow in a subsequent CL. BUG: 25762540 Change-Id: I74c6bcf7804cecbe7630479fbdd6bb0a0a668c7b
Diffstat (limited to 'core')
-rw-r--r--core/include/nvram/core/nvram_manager.h47
-rw-r--r--core/nvram_manager.cpp255
2 files changed, 302 insertions, 0 deletions
diff --git a/core/include/nvram/core/nvram_manager.h b/core/include/nvram/core/nvram_manager.h
index 1cce0a6..5e05e3c 100644
--- a/core/include/nvram/core/nvram_manager.h
+++ b/core/include/nvram/core/nvram_manager.h
@@ -31,6 +31,16 @@ namespace nvram {
// objects and uses the persistence layer to read and write them from persistent
// storage.
class NvramManager {
+ public:
+ nvram_result_t GetInfo(const GetInfoRequest& request,
+ GetInfoResponse* response);
+ nvram_result_t CreateSpace(const CreateSpaceRequest& request,
+ CreateSpaceResponse* response);
+ nvram_result_t GetSpaceInfo(const GetSpaceInfoRequest& request,
+ GetSpaceInfoResponse* response);
+ nvram_result_t DisableCreate(const DisableCreateRequest& request,
+ DisableCreateResponse* response);
+
private:
// Holds transient state corresponding to an allocated NVRAM space, i.e. meta
// data valid for a single boot. One instance of this struct is kept in memory
@@ -41,14 +51,51 @@ class NvramManager {
bool read_locked = false;
};
+ // |SpaceRecord| holds all information known about a space. It includes both
+ // an index and pointer to the transient information held in the
+ // |SpaceListEntry| in the |spaces_| array and the persistent |NvramSpace|
+ // state held in permanent storage. We only load the persistent space data
+ // from storage when it is needed for an operation, such as reading and
+ // writing space contents.
+ struct SpaceRecord {
+ // Access control check for write access to the space. The
+ // |authorization_value| is only relevant if the space was configured to
+ // require authorization. Returns RESULT_SUCCESS if write access is
+ // permitted and a suitable result code to return to the client on failure.
+ nvram_result_t CheckWriteAccess(const Blob& authorization_value);
+
+ // Access control check for read access to the space. The
+ // |authorization_value| is only relevant if the space was configured to
+ // require authorization. Returns RESULT_SUCCESS if write access is
+ // permitted and a suitable result code to return the client on failure.
+ nvram_result_t CheckReadAccess(const Blob& authorization_value);
+
+ size_t array_index = 0;
+ SpaceListEntry* transient = nullptr;
+ NvramSpace persistent;
+ };
+
// Initializes |header_| from storage if that hasn't happened already. Returns
// true if NvramManager object is initialized and ready to serve requests. May
// be called again after failure to attempt initialization again.
bool Initialize();
+ // Finds the array index in |spaces_| that corresponds to |space_index|.
+ // Returns |kMaxSpaces| if there is no matching space.
+ size_t FindSpace(uint32_t space_index);
+
+ // Loads space data for |index|. Fills in |space_record| and returns true if
+ // successful. Returns false and sets |result| on error.
+ bool LoadSpaceRecord(uint32_t index,
+ SpaceRecord* space_record,
+ nvram_result_t* result);
+
// Writes the header to storage and returns a suitable status code.
nvram_result_t WriteHeader(Optional<uint32_t> provisional_index);
+ // Write |space| data for |index|.
+ nvram_result_t WriteSpace(uint32_t index, const NvramSpace& space);
+
// Maximum number of NVRAM spaces we're willing to allocate.
static constexpr size_t kMaxSpaces = 32;
diff --git a/core/nvram_manager.cpp b/core/nvram_manager.cpp
index dbbe68d..19e23dd 100644
--- a/core/nvram_manager.cpp
+++ b/core/nvram_manager.cpp
@@ -18,8 +18,212 @@
#include <nvram/core/logger.h>
+extern "C" {
+#include <string.h>
+} // extern "C"
+
+using namespace nvram::storage;
+
namespace nvram {
+namespace {
+
+// Maximum size of a single space's contents.
+constexpr size_t kMaxSpaceSize = 1024;
+
+// Maximum authorization blob size;
+constexpr size_t kMaxAuthSize = 32;
+
+// The bitmask of all supported control flags.
+constexpr uint32_t kSupportedControlsMask =
+ (1 << NV_CONTROL_PERSISTENT_WRITE_LOCK) |
+ (1 << NV_CONTROL_BOOT_WRITE_LOCK) |
+ (1 << NV_CONTROL_BOOT_READ_LOCK) |
+ (1 << NV_CONTROL_WRITE_AUTHORIZATION) |
+ (1 << NV_CONTROL_READ_AUTHORIZATION) |
+ (1 << NV_CONTROL_WRITE_EXTEND);
+
+// Convert the |space.controls| bitmask to vector representation.
+nvram_result_t GetControlsVector(const NvramSpace& space,
+ Vector<nvram_control_t>* controls) {
+ for (size_t control = 0; control < sizeof(uint32_t) * 8; ++control) {
+ if (space.HasControl(control)) {
+ if (!controls->Resize(controls->size() + 1)) {
+ NVRAM_LOG_ERR("Allocation failure.");
+ return NV_RESULT_INTERNAL_ERROR;
+ }
+ (*controls)[controls->size() - 1] = static_cast<nvram_control_t>(control);
+ }
+ }
+ return NV_RESULT_SUCCESS;
+}
+
+} // namespace
+
+nvram_result_t NvramManager::GetInfo(const GetInfoRequest& /* request */,
+ GetInfoResponse* response) {
+ NVRAM_LOG_INFO("GetInfo");
+
+ if (!Initialize())
+ return NV_RESULT_INTERNAL_ERROR;
+
+ // TODO: Get better values for total and available size from the storage
+ // layer.
+ response->total_size = kMaxSpaceSize * kMaxSpaces;
+ response->available_size = kMaxSpaceSize * (kMaxSpaces - num_spaces_);
+ response->max_spaces = kMaxSpaces;
+ Vector<uint32_t>& space_list = response->space_list;
+ if (!space_list.Resize(num_spaces_)) {
+ NVRAM_LOG_ERR("Allocation failure.");
+ return NV_RESULT_INTERNAL_ERROR;
+ }
+ for (size_t i = 0; i < num_spaces_; ++i) {
+ space_list[i] = spaces_[i].index;
+ }
+
+ return NV_RESULT_SUCCESS;
+}
+
+nvram_result_t NvramManager::CreateSpace(const CreateSpaceRequest& request,
+ CreateSpaceResponse* /* response */) {
+ const uint32_t index = request.index;
+ NVRAM_LOG_INFO("CreateSpace Ox%x", index);
+
+ if (!Initialize())
+ return NV_RESULT_INTERNAL_ERROR;
+
+ if (disable_create_) {
+ NVRAM_LOG_INFO("Creation of further spaces is disabled.");
+ return NV_RESULT_OPERATION_DISABLED;
+ }
+
+ if (FindSpace(index) != kMaxSpaces) {
+ NVRAM_LOG_INFO("Space 0x%x already exists.", index);
+ return NV_RESULT_SPACE_ALREADY_EXISTS;
+ }
+
+ if (num_spaces_ + 1 > kMaxSpaces) {
+ NVRAM_LOG_INFO("Too many spaces.");
+ return NV_RESULT_INVALID_PARAMETER;
+ }
+
+ if (request.size > kMaxSpaceSize) {
+ NVRAM_LOG_INFO("Create request exceeds max space size.");
+ return NV_RESULT_INVALID_PARAMETER;
+ }
+
+ if (request.authorization_value.size() > kMaxAuthSize) {
+ NVRAM_LOG_INFO("Authorization blob too large.");
+ return NV_RESULT_INVALID_PARAMETER;
+ }
+
+ uint32_t controls = 0;
+ for (uint32_t control : request.controls) {
+ controls |= (1 << control);
+ }
+ if ((controls & ~kSupportedControlsMask) != 0) {
+ NVRAM_LOG_INFO("Bad controls.");
+ return NV_RESULT_INVALID_PARAMETER;
+ }
+ if ((controls & (1 << NV_CONTROL_PERSISTENT_WRITE_LOCK)) != 0 &&
+ (controls & (1 << NV_CONTROL_BOOT_WRITE_LOCK)) != 0) {
+ NVRAM_LOG_INFO("Write lock controls are exclusive.");
+ return NV_RESULT_INVALID_PARAMETER;
+ }
+
+ // Mark the index as allocated.
+ spaces_[num_spaces_].index = index;
+ spaces_[num_spaces_].write_locked = false;
+ spaces_[num_spaces_].read_locked = false;
+ ++num_spaces_;
+
+ // Create a space record.
+ NvramSpace space;
+ space.flags = 0;
+ space.controls = controls;
+
+ // Copy the auth blob.
+ if (space.HasControl(NV_CONTROL_WRITE_AUTHORIZATION) ||
+ space.HasControl(NV_CONTROL_READ_AUTHORIZATION)) {
+ if (!space.authorization_value.Assign(request.authorization_value.data(),
+ request.authorization_value.size())) {
+ NVRAM_LOG_ERR("Allocation failure.");
+ return NV_RESULT_INTERNAL_ERROR;
+ }
+ }
+
+ // Initialize the space content.
+ if (!space.contents.Resize(request.size)) {
+ NVRAM_LOG_ERR("Allocation failure.");
+ return NV_RESULT_INTERNAL_ERROR;
+ }
+ memset(space.contents.data(), 0, request.size);
+
+ // Write the header before the space data. This ensures that all space
+ // definitions present in storage are also recorded in the header. Thus, the
+ // set of spaces present in the header is always a superset of the set of
+ // spaces that have state in storage. If there's a crash after writing the
+ // header but before writing the space information, the space data will be
+ // missing in storage. The initialization code handles this by checking the
+ // for the space data corresponding to the index marked as provisional in the
+ // header.
+ nvram_result_t result;
+ if ((result = WriteHeader(Optional<uint32_t>(index))) != NV_RESULT_SUCCESS ||
+ (result = WriteSpace(index, space)) != NV_RESULT_SUCCESS) {
+ --num_spaces_;
+ }
+ return result;
+}
+
+nvram_result_t NvramManager::GetSpaceInfo(const GetSpaceInfoRequest& request,
+ GetSpaceInfoResponse* response) {
+ const uint32_t index = request.index;
+ NVRAM_LOG_INFO("GetSpaceInfo Ox%x", index);
+
+ if (!Initialize())
+ return NV_RESULT_INTERNAL_ERROR;
+
+ SpaceRecord space_record;
+ nvram_result_t result;
+ if (!LoadSpaceRecord(index, &space_record, &result)) {
+ return result;
+ }
+
+ response->size = space_record.persistent.contents.size();
+
+ result = GetControlsVector(space_record.persistent, &response->controls);
+ if (result != NV_RESULT_SUCCESS) {
+ return NV_RESULT_INTERNAL_ERROR;
+ }
+
+ if (space_record.persistent.HasControl(NV_CONTROL_BOOT_READ_LOCK)) {
+ response->read_locked = space_record.transient->read_locked;
+ }
+
+ if (space_record.persistent.HasControl(NV_CONTROL_PERSISTENT_WRITE_LOCK)) {
+ response->write_locked =
+ space_record.persistent.HasFlag(NvramSpace::kFlagWriteLocked);
+ } else if (space_record.persistent.HasControl(NV_CONTROL_BOOT_WRITE_LOCK)) {
+ response->write_locked = space_record.transient->write_locked;
+ }
+
+ return NV_RESULT_SUCCESS;
+}
+
+nvram_result_t NvramManager::DisableCreate(
+ const DisableCreateRequest& /* request */,
+ DisableCreateResponse* /* response */) {
+ NVRAM_LOG_INFO("DisableCreate");
+
+ if (!Initialize())
+ return NV_RESULT_INTERNAL_ERROR;
+
+ // Set the |disable_create_| flag and call |WriteHeader| to persist the flag
+ // such that it remains effective after a reboot.
+ disable_create_ = true;
+ return WriteHeader(Optional<uint32_t>());
+}
+
bool NvramManager::Initialize() {
if (initialized_)
return true;
@@ -141,6 +345,47 @@ bool NvramManager::Initialize() {
return true;
}
+size_t NvramManager::FindSpace(uint32_t space_index) {
+ for (size_t i = 0; i < num_spaces_; ++i) {
+ if (spaces_[i].index == space_index) {
+ return i;
+ }
+ }
+
+ return kMaxSpaces;
+}
+
+bool NvramManager::LoadSpaceRecord(uint32_t index,
+ SpaceRecord* space_record,
+ nvram_result_t* result) {
+ space_record->array_index = FindSpace(index);
+ if (space_record->array_index == kMaxSpaces) {
+ *result = NV_RESULT_SPACE_DOES_NOT_EXIST;
+ return false;
+ }
+
+ space_record->transient = &spaces_[space_record->array_index];
+
+ switch (persistence::LoadSpace(index, &space_record->persistent)) {
+ case storage::Status::kStorageError:
+ NVRAM_LOG_ERR("Failed to load space 0x%x data.", index);
+ *result = NV_RESULT_INTERNAL_ERROR;
+ return false;
+ case storage::Status::kNotFound:
+ // This should never happen if the header contains the index.
+ NVRAM_LOG_ERR("Space index 0x%x present in header, but data missing.",
+ index);
+ *result = NV_RESULT_INTERNAL_ERROR;
+ return false;
+ case storage::Status::kSuccess:
+ *result = NV_RESULT_SUCCESS;
+ return true;
+ }
+
+ *result = NV_RESULT_INTERNAL_ERROR;
+ return false;
+}
+
nvram_result_t NvramManager::WriteHeader(Optional<uint32_t> provisional_index) {
NvramHeader header;
header.version = NvramHeader::kVersion;
@@ -166,4 +411,14 @@ nvram_result_t NvramManager::WriteHeader(Optional<uint32_t> provisional_index) {
return NV_RESULT_SUCCESS;
}
+nvram_result_t NvramManager::WriteSpace(uint32_t index,
+ const NvramSpace& space) {
+ if (persistence::StoreSpace(index, space) != storage::Status::kSuccess) {
+ NVRAM_LOG_ERR("Failed to store space 0x%x.", index);
+ return NV_RESULT_INTERNAL_ERROR;
+ }
+
+ return NV_RESULT_SUCCESS;
+}
+
} // namespace nvram