You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
13 KiB
421 lines
13 KiB
/* |
|
* Copyright (C) 2016 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <inttypes.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
|
|
#include <hardware/nvram.h> |
|
|
|
#define countof(array) (sizeof(array) / sizeof((array)[0])) |
|
|
|
// Exit status codes. These are all negative as the positive ones are used for |
|
// the NV_RESULT_ codes. |
|
enum StatusCode { |
|
kStatusInvalidArg = -1, |
|
kStatusHALError = -2, |
|
kStatusAllocationFailure = -3, |
|
}; |
|
|
|
static struct { |
|
int status; |
|
const char* description; |
|
} kStatusStringTable[] = { |
|
{kStatusInvalidArg, "Bad parameter"}, |
|
{kStatusHALError, "NVRAM HAL initialization error"}, |
|
{kStatusAllocationFailure, "Memory allocation error"}, |
|
{NV_RESULT_SUCCESS, "Success"}, |
|
{NV_RESULT_INTERNAL_ERROR, "Internal error"}, |
|
{NV_RESULT_ACCESS_DENIED, "Access denied"}, |
|
{NV_RESULT_INVALID_PARAMETER, "Invalid NVRAM parameter"}, |
|
{NV_RESULT_SPACE_DOES_NOT_EXIST, "Space does not exist"}, |
|
{NV_RESULT_SPACE_ALREADY_EXISTS, "Space already exists"}, |
|
{NV_RESULT_OPERATION_DISABLED, "Operation disabled"}, |
|
}; |
|
|
|
// Returns a string describing |status|. |
|
static const char* StatusToString(int status) { |
|
for (size_t i = 0; i < countof(kStatusStringTable); ++i) { |
|
if (kStatusStringTable[i].status == status) { |
|
return kStatusStringTable[i].description; |
|
} |
|
} |
|
|
|
return "unknown error"; |
|
} |
|
|
|
// A table mapping control values to names. |
|
static struct { |
|
nvram_control_t control; |
|
const char* name; |
|
} kControlNameTable[] = { |
|
{NV_CONTROL_PERSISTENT_WRITE_LOCK, "PERSISTENT_WRITE_LOCK"}, |
|
{NV_CONTROL_BOOT_WRITE_LOCK, "BOOT_WRITE_LOCK"}, |
|
{NV_CONTROL_BOOT_READ_LOCK, "BOOT_READ_LOCK"}, |
|
{NV_CONTROL_WRITE_AUTHORIZATION, "WRITE_AUTHORIZATION"}, |
|
{NV_CONTROL_READ_AUTHORIZATION, "READ_AUTHORIZATION"}, |
|
{NV_CONTROL_WRITE_EXTEND, "WRITE_EXTEND"}, |
|
}; |
|
|
|
// Returns the string representation of |control|, or NULL if |control| isn't a |
|
// valid control value. |
|
static const char* ControlToString(nvram_control_t control) { |
|
for (size_t i = 0; i < countof(kControlNameTable); ++i) { |
|
if (kControlNameTable[i].control == control) { |
|
return kControlNameTable[i].name; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
// Sets |control| to the NV_CONTROL_ value corresponding to the string control |
|
// representation found in |name|. Returns 0 if successful, 1 if name doesn't |
|
// match any control string. |
|
static int StringToControl(const char* name, nvram_control_t* control) { |
|
for (size_t i = 0; i < countof(kControlNameTable); ++i) { |
|
if (strcmp(kControlNameTable[i].name, name) == 0) { |
|
*control = kControlNameTable[i].control; |
|
return 0; |
|
} |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
static int HandleGetTotalSize(nvram_device_t* device, char* args[]) { |
|
(void)args; |
|
uint64_t total_size = 0; |
|
nvram_result_t result = device->get_total_size_in_bytes(device, &total_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%" PRIu64 "\n", total_size); |
|
return 0; |
|
} |
|
|
|
static int HandleGetAvailableSize(nvram_device_t* device, char* args[]) { |
|
(void)args; |
|
uint64_t available_size = 0; |
|
nvram_result_t result = |
|
device->get_available_size_in_bytes(device, &available_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%" PRIu64 "\n", available_size); |
|
return 0; |
|
} |
|
|
|
static int HandleGetMaxSpaceSize(nvram_device_t* device, char* args[]) { |
|
(void)args; |
|
uint64_t max_space_size = 0; |
|
nvram_result_t result = |
|
device->get_max_space_size_in_bytes(device, &max_space_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%" PRIu64 "\n", max_space_size); |
|
return 0; |
|
} |
|
|
|
static int HandleGetMaxSpaces(nvram_device_t* device, char* args[]) { |
|
(void)args; |
|
uint32_t max_spaces = 0; |
|
nvram_result_t result = device->get_max_spaces(device, &max_spaces); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%" PRIu32 "\n", max_spaces); |
|
return 0; |
|
} |
|
|
|
static int HandleGetSpaceList(nvram_device_t* device, char* args[]) { |
|
(void)args; |
|
uint32_t list_size = 0; |
|
nvram_result_t result = device->get_space_list(device, 0, NULL, &list_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
uint32_t* space_index_list = calloc(list_size, sizeof(uint32_t)); |
|
if (!space_index_list) { |
|
return kStatusAllocationFailure; |
|
} |
|
|
|
result = |
|
device->get_space_list(device, list_size, space_index_list, &list_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
free(space_index_list); |
|
return result; |
|
} |
|
|
|
for (uint32_t i = 0; i < list_size; ++i) { |
|
if (i != 0) { |
|
fputs(",", stdout); |
|
} |
|
printf("%" PRIu32, space_index_list[i]); |
|
} |
|
fputs("\n", stdout); |
|
|
|
free(space_index_list); |
|
return 0; |
|
} |
|
|
|
static int HandleGetSpaceSize(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
uint64_t space_size = 0; |
|
nvram_result_t result = device->get_space_size(device, index, &space_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%" PRIu64 "\n", space_size); |
|
return 0; |
|
} |
|
|
|
static int HandleGetSpaceControls(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
uint32_t list_size = 0; |
|
nvram_result_t result = |
|
device->get_space_controls(device, index, 0, NULL, &list_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
uint32_t* controls_list = calloc(list_size, sizeof(nvram_control_t)); |
|
if (!controls_list) { |
|
return kStatusAllocationFailure; |
|
} |
|
|
|
result = device->get_space_controls(device, index, list_size, controls_list, |
|
&list_size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
free(controls_list); |
|
return result; |
|
} |
|
|
|
for (uint32_t i = 0; i < list_size; ++i) { |
|
if (i != 0) { |
|
fputs(",", stdout); |
|
} |
|
const char* name = ControlToString(controls_list[i]); |
|
if (name) { |
|
fputs(name, stdout); |
|
} else { |
|
printf("<unknown_control_%" PRIu32 ">", controls_list[i]); |
|
} |
|
} |
|
fputs("", stdout); |
|
|
|
free(controls_list); |
|
return 0; |
|
} |
|
|
|
static int HandleIsSpaceReadLocked(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
int read_locked = 0; |
|
int write_locked = 0; |
|
nvram_result_t result = |
|
device->is_space_locked(device, index, &read_locked, &write_locked); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%d\n", read_locked); |
|
return 0; |
|
} |
|
|
|
static int HandleIsSpaceWriteLocked(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
int read_locked = 0; |
|
int write_locked = 0; |
|
nvram_result_t result = |
|
device->is_space_locked(device, index, &read_locked, &write_locked); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
printf("%d\n", write_locked); |
|
return 0; |
|
} |
|
|
|
static int HandleCreateSpace(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
uint64_t size = strtoull(args[1], NULL, 0); |
|
uint32_t list_size = 0; |
|
nvram_control_t* controls_list = NULL; |
|
char* tail = args[2]; |
|
while (tail) { |
|
++list_size; |
|
nvram_control_t* new_controls_list = |
|
realloc(controls_list, sizeof(nvram_control_t) * list_size); |
|
if (new_controls_list) { |
|
controls_list = new_controls_list; |
|
} else { |
|
free(controls_list); |
|
return kStatusAllocationFailure; |
|
} |
|
|
|
if (StringToControl(strsep(&tail, ","), &(controls_list[list_size - 1]))) { |
|
free(controls_list); |
|
return kStatusInvalidArg; |
|
} |
|
} |
|
|
|
return device->create_space(device, index, size, controls_list, list_size, |
|
(uint8_t*)args[3], strlen(args[3])); |
|
} |
|
|
|
static int HandleDeleteSpace(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
return device->delete_space(device, index, (uint8_t*)args[3], |
|
strlen(args[3])); |
|
} |
|
|
|
static int HandleDisableCreate(nvram_device_t* device, char* args[]) { |
|
(void)args; |
|
return device->disable_create(device); |
|
} |
|
|
|
static int HandleWriteSpace(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
return device->write_space(device, index, (uint8_t*)args[1], strlen(args[1]), |
|
(uint8_t*)args[2], strlen(args[2])); |
|
} |
|
|
|
static int HandleReadSpace(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
uint64_t size = 0; |
|
nvram_result_t result = device->get_space_size(device, index, &size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
return result; |
|
} |
|
|
|
uint8_t* buffer = calloc(sizeof(uint8_t), size); |
|
if (!buffer) { |
|
return kStatusAllocationFailure; |
|
} |
|
|
|
result = device->read_space(device, index, size, (uint8_t*)args[1], |
|
strlen(args[1]), buffer, &size); |
|
if (result != NV_RESULT_SUCCESS) { |
|
free(buffer); |
|
return result; |
|
} |
|
|
|
fwrite(buffer, sizeof(uint8_t), size, stdout); |
|
fputs("\n", stdout); |
|
free(buffer); |
|
return 0; |
|
} |
|
|
|
static int HandleEnableWriteLock(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
return device->enable_write_lock(device, index, (uint8_t*)args[1], |
|
strlen(args[1])); |
|
} |
|
|
|
static int HandleEnableReadLock(nvram_device_t* device, char* args[]) { |
|
uint32_t index = strtoul(args[0], NULL, 0); |
|
return device->enable_read_lock(device, index, (uint8_t*)args[1], |
|
strlen(args[1])); |
|
} |
|
|
|
struct CommandHandler { |
|
const char* name; |
|
const char* params_desc; |
|
int nparams; |
|
int (*run)(nvram_device_t*, char* args[]); |
|
}; |
|
|
|
struct CommandHandler kCommandHandlers[] = { |
|
{"get_total_size", "", 0, &HandleGetTotalSize}, |
|
{"get_available_size", "", 0, &HandleGetAvailableSize}, |
|
{"get_max_space_size", "", 0, &HandleGetMaxSpaceSize}, |
|
{"get_max_spaces", "", 0, &HandleGetMaxSpaces}, |
|
{"get_space_list", "", 0, &HandleGetSpaceList}, |
|
{"get_space_size", "<index>", 1, &HandleGetSpaceSize}, |
|
{"get_space_controls", "<index>", 1, &HandleGetSpaceControls}, |
|
{"is_space_read_locked", "<index>", 1, &HandleIsSpaceReadLocked}, |
|
{"is_space_write_locked", "<index>", 1, &HandleIsSpaceWriteLocked}, |
|
{"create_space", "<index> <size> <controls> <auth>", 4, &HandleCreateSpace}, |
|
{"delete_space", "<index> <auth>", 2, &HandleDeleteSpace}, |
|
{"disable_create", "", 0, &HandleDisableCreate}, |
|
{"write_space", "<index> <data> <auth>", 3, &HandleWriteSpace}, |
|
{"read_space", "<index> <auth>", 2, &HandleReadSpace}, |
|
{"enable_write_lock", "<index> <auth>", 2, &HandleEnableWriteLock}, |
|
{"enable_read_lock", "<index> <auth>", 2, &HandleEnableReadLock}, |
|
}; |
|
|
|
int main(int argc, char* argv[]) { |
|
if (argc < 2) { |
|
fprintf(stderr, "Usage: %s <command> <command-args>\n", argv[0]); |
|
fprintf(stderr, "Valid commands are:\n"); |
|
for (size_t i = 0; i < countof(kCommandHandlers); ++i) { |
|
fprintf(stderr, " %s %s\n", kCommandHandlers[i].name, |
|
kCommandHandlers[i].params_desc); |
|
} |
|
return kStatusInvalidArg; |
|
} |
|
|
|
const struct CommandHandler* cmd = NULL; |
|
for (size_t i = 0; i < countof(kCommandHandlers); ++i) { |
|
if (strcmp(kCommandHandlers[i].name, argv[1]) == 0) { |
|
cmd = &kCommandHandlers[i]; |
|
} |
|
} |
|
|
|
if (!cmd) { |
|
fprintf(stderr, "Bad command: %s\n", argv[1]); |
|
return kStatusInvalidArg; |
|
} |
|
|
|
if (argc - 2 != cmd->nparams) { |
|
fprintf(stderr, "Command %s takes %d parameters, %d given.\n", argv[1], |
|
cmd->nparams, argc - 2); |
|
return kStatusInvalidArg; |
|
} |
|
|
|
const hw_module_t* module = NULL; |
|
nvram_device_t* nvram_device = NULL; |
|
if (hw_get_module(NVRAM_HARDWARE_MODULE_ID, &module) != 0 || |
|
module->methods->open(module, NVRAM_HARDWARE_DEVICE_ID, |
|
(hw_device_t**)&nvram_device) != 0) { |
|
fprintf(stderr, "Failed to open NVRAM HAL.\n"); |
|
return kStatusHALError; |
|
} |
|
|
|
if (nvram_device->common.version != NVRAM_DEVICE_API_VERSION_1_1) { |
|
fprintf(stderr, "Unsupported NVRAM HAL version.\n"); |
|
nvram_device->common.close(&nvram_device->common); |
|
return kStatusHALError; |
|
} |
|
|
|
int ret = cmd->run(nvram_device, argv + 2); |
|
if (ret != 0) { |
|
fprintf(stderr, "Command execution failure: %s (%d).\n", |
|
StatusToString(ret), ret); |
|
} |
|
|
|
nvram_device->common.close(&nvram_device->common); |
|
return ret; |
|
}
|
|
|