summaryrefslogtreecommitdiff
path: root/util/smmstoretool/vs.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/smmstoretool/vs.c')
-rw-r--r--util/smmstoretool/vs.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/util/smmstoretool/vs.c b/util/smmstoretool/vs.c
new file mode 100644
index 0000000000..a1167ca2de
--- /dev/null
+++ b/util/smmstoretool/vs.c
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "vs.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "udk2017.h"
+#include "utils.h"
+
+static size_t get_var_hdr_size(bool auth_vars)
+{
+ if (auth_vars)
+ return sizeof(AUTHENTICATED_VARIABLE_HEADER);
+ return sizeof(VARIABLE_HEADER);
+}
+
+struct var_store_t vs_load(struct mem_range_t vs_data, bool auth_vars)
+{
+ uint8_t *var_hdr = vs_data.start;
+
+ struct var_store_t vs = {
+ .auth_vars = auth_vars,
+ .vars = NULL,
+ };
+
+ struct var_t *last_var = NULL;
+
+ const size_t var_hdr_size = get_var_hdr_size(auth_vars);
+ while (var_hdr + var_hdr_size < vs_data.start + vs_data.length) {
+ uint16_t start_id;
+ uint8_t state;
+ struct var_t var = {0};
+ uint8_t *var_data = var_hdr;
+
+ if (auth_vars) {
+ const AUTHENTICATED_VARIABLE_HEADER *auth_hdr =
+ (void *)var_data;
+
+ start_id = auth_hdr->StartId;
+ state = auth_hdr->State;
+
+ var.reserved = auth_hdr->Reserved;
+ var.attrs = auth_hdr->Attributes;
+ var.name_size = auth_hdr->NameSize;
+ var.data_size = auth_hdr->DataSize;
+ var.guid = auth_hdr->VendorGuid;
+ } else {
+ const VARIABLE_HEADER *no_auth_hdr = (void *)var_data;
+
+ start_id = no_auth_hdr->StartId;
+ state = no_auth_hdr->State;
+
+ var.reserved = no_auth_hdr->Reserved;
+ var.attrs = no_auth_hdr->Attributes;
+ var.name_size = no_auth_hdr->NameSize;
+ var.data_size = no_auth_hdr->DataSize;
+ var.guid = no_auth_hdr->VendorGuid;
+ }
+
+ var_hdr += HEADER_ALIGN(var_hdr_size +
+ var.name_size +
+ var.data_size);
+
+ if (start_id != VARIABLE_DATA)
+ break;
+
+ if (state != VAR_ADDED)
+ continue;
+
+ if (var.data_size == UINT32_MAX ||
+ var.name_size == UINT32_MAX ||
+ var.attrs == UINT32_MAX)
+ continue;
+
+ CHAR16 *name = (void *)(var_data + var_hdr_size);
+ var.name = xmalloc(var.name_size);
+ memcpy(var.name, name, var.name_size);
+
+ uint8_t *data =
+ (void *)(var_data + var_hdr_size + var.name_size);
+ var.data = xmalloc(var.data_size);
+ memcpy(var.data, data, var.data_size);
+
+ struct var_t *var_node = xmalloc(sizeof(*var_node));
+ *var_node = var;
+ if (last_var != NULL)
+ last_var->next = var_node;
+ else if (vs.vars == NULL)
+ vs.vars = var_node;
+ last_var = var_node;
+ }
+
+ return vs;
+}
+
+static void store_var(const struct var_t *var, bool auth_vars, uint8_t *data)
+{
+ if (auth_vars) {
+ AUTHENTICATED_VARIABLE_HEADER hdr;
+ memset(&hdr, 0xff, sizeof(hdr));
+
+ hdr.StartId = VARIABLE_DATA;
+ hdr.State = VAR_ADDED;
+ hdr.Reserved = var->reserved;
+ hdr.Attributes = var->attrs;
+ hdr.VendorGuid = var->guid;
+ hdr.NameSize = var->name_size;
+ hdr.DataSize = var->data_size;
+
+ memcpy(data, &hdr, sizeof(hdr));
+ data += sizeof(hdr);
+ } else {
+ VARIABLE_HEADER hdr;
+ memset(&hdr, 0xff, sizeof(hdr));
+
+ hdr.StartId = VARIABLE_DATA;
+ hdr.State = VAR_ADDED;
+ hdr.Reserved = var->reserved;
+ hdr.Attributes = var->attrs;
+ hdr.VendorGuid = var->guid;
+ hdr.NameSize = var->name_size;
+ hdr.DataSize = var->data_size;
+
+ memcpy(data, &hdr, sizeof(hdr));
+ data += sizeof(hdr);
+ }
+
+ memcpy(data, var->name, var->name_size);
+ memcpy(data + var->name_size, var->data, var->data_size);
+}
+
+bool vs_store(struct var_store_t *vs, struct mem_range_t vs_data)
+{
+ uint8_t *out_data = vs_data.start;
+
+ const size_t var_hdr_size = get_var_hdr_size(vs->auth_vars);
+ for (struct var_t *var = vs->vars; var != NULL; var = var->next) {
+ const size_t var_size =
+ var_hdr_size + var->name_size + var->data_size;
+ if (out_data + var_size > vs_data.start + vs_data.length) {
+ fprintf(stderr,
+ "Not enough space to serialize Variable Store.\n");
+ return false;
+ }
+
+ store_var(var, vs->auth_vars, out_data);
+ out_data += HEADER_ALIGN(var_size);
+ }
+
+ // The rest is "uninitialized".
+ memset(out_data, 0xff, vs_data.length - (out_data - vs_data.start));
+
+ return true;
+}
+
+struct var_t *vs_new_var(struct var_store_t *vs)
+{
+ struct var_t *new_var = xmalloc(sizeof(*new_var));
+
+ memset(new_var, 0, sizeof(*new_var));
+ new_var->attrs = EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS;
+
+ struct var_t *var = vs->vars;
+ if (var == NULL) {
+ vs->vars = new_var;
+ } else {
+ while (var->next != NULL)
+ var = var->next;
+ var->next = new_var;
+ }
+
+ return new_var;
+}
+
+struct var_t *vs_find(struct var_store_t *vs,
+ const char name[],
+ const EFI_GUID *guid)
+{
+ size_t name_size;
+ CHAR16 *uchar_name = to_uchars(name, &name_size);
+
+ struct var_t *var;
+ for (var = vs->vars; var != NULL; var = var->next) {
+ if (var->name_size != name_size)
+ continue;
+ if (memcmp(var->name, uchar_name, name_size) != 0)
+ continue;
+ if (memcmp(&var->guid, guid, sizeof(*guid)) != 0)
+ continue;
+ break;
+ }
+
+ free(uchar_name);
+ return var;
+}
+
+static void free_var(struct var_t *var)
+{
+ free(var->name);
+ free(var->data);
+ free(var);
+}
+
+void vs_delete(struct var_store_t *vs, struct var_t *var)
+{
+ if (vs->vars == var) {
+ vs->vars = var->next;
+ free_var(var);
+ return;
+ }
+
+ for (struct var_t *v = vs->vars; v != NULL; v = v->next) {
+ if (v->next == var) {
+ v->next = var->next;
+ free_var(var);
+ return;
+ }
+ }
+}
+
+void vs_free(struct var_store_t *vs)
+{
+ for (struct var_t *next, *var = vs->vars; var != NULL; var = next) {
+ next = var->next;
+ free_var(var);
+ }
+}