Offline SMMSTORE variable modification tool. Can be used to pre-configure ROM image or debug EFI state stored in a dump. Change-Id: I6c1c06f1d0c39c13b5be76a3070f09b715aca6e0 Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/79080 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Michał Żygowski <michal.zygowski@3mdeb.com> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
		
			
				
	
	
		
			233 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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);
 | |
| 	}
 | |
| }
 |