Files
lk/lib/uefi/variable_mem.cpp
2025-09-04 09:59:22 -07:00

177 lines
5.0 KiB
C++

/*
* Copyright (C) 2025 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 "variable_mem.h"
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <lk/list.h>
#include <uefi/types.h>
#include "charset.h"
namespace {
constexpr size_t kVarNameMax = 128;
struct EfiVariable {
struct list_node node;
char16_t VariableName[kVarNameMax];
EfiGuid VendorGuid;
uint32_t Attributes;
char* Data;
size_t DataLen;
};
}
static list_node variables_in_mem = LIST_INITIAL_VALUE(variables_in_mem);
static EfiVariable * search_existing_variable(const char16_t *varname,
const EfiGuid *guid) {
/* search for existing variable */
struct EfiVariable *var = nullptr;
list_for_every_entry(&variables_in_mem, var, struct EfiVariable, node) {
if (guid != NULL && memcmp(&var->VendorGuid, guid, sizeof(EfiGuid)) != 0) {
continue;
}
if (utf16_strcmp(varname, var->VariableName) != 0) {
continue;
}
return var;
}
return nullptr;
}
EfiStatus efi_get_variable(const char16_t *variable_name,
const EfiGuid *guid,
uint32_t *attribute,
char **data,
size_t *data_size) {
struct EfiVariable *var = search_existing_variable(variable_name, guid);
if (data)
*data = nullptr;
if (data_size)
*data_size = 0;
if (attribute)
*attribute = 0;
if (var) {
if (data)
*data = var->Data;
if (data_size)
*data_size = var->DataLen;
if (attribute)
*attribute = var->Attributes;
return EFI_STATUS_SUCCESS;
}
return EFI_STATUS_NOT_FOUND;
}
void efi_set_variable(const char16_t *variable_name,
const EfiGuid *guid,
uint32_t attribute,
const char *data,
size_t data_len) {
struct EfiVariable *var = search_existing_variable(variable_name, guid);
/* alloc new variable if it is not existed */
if (!var) {
var = reinterpret_cast<struct EfiVariable *>(malloc(sizeof(struct EfiVariable)));
memset(var, 0, sizeof(struct EfiVariable));
var->node = LIST_INITIAL_CLEARED_VALUE;
size_t name_len = utf16_strlen(variable_name);
if (name_len >= kVarNameMax)
name_len = kVarNameMax - 1;
memcpy(var->VariableName, variable_name, name_len * sizeof(char16_t));
list_add_tail(&variables_in_mem, &var->node);
}
if (var->Data) {
free(var->Data);
}
var->Data = nullptr;
var->DataLen = 0;
if (data_len > 0) {
var->Data = reinterpret_cast<char *>(malloc(data_len));
memcpy(var->Data, data, data_len);
var->DataLen = data_len;
}
var->Attributes = attribute;
if (guid) {
memcpy(&var->VendorGuid, guid, sizeof(EfiGuid));
}
}
void efi_list_variable(void) {
struct EfiVariable *var = nullptr;
list_for_every_entry(&variables_in_mem, var, struct EfiVariable, node) {
char varname[kVarNameMax];
utf16_to_utf8(varname, var->VariableName, sizeof(varname));
printf("%s\n", varname);
/* print GUID */
printf(" %08x-%04x-%04x",
var->VendorGuid.data1,
var->VendorGuid.data2,
var->VendorGuid.data3);
for (int i = 0; i < 8 ; i++) {
if (i == 0 || i == 2) {
printf("-");
}
printf("%02x", var->VendorGuid.data4[i]);
}
printf("\n");
printf(" ");
/* print attributes */
for (uint32_t attr = 1; attr <= var->Attributes; attr <<= 1) {
if (var->Attributes & attr) {
if (attr == EFI_VARIABLE_NON_VOLATILE) {
printf("NV");
} else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) {
printf("BS");
} else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) {
printf("RT");
} else {
printf("0x%02x", attr);
}
if (attr << 1 <= var->Attributes) {
printf("|");
}
}
}
printf(", DataSize = 0x%zx\n", var->DataLen);
/* dump data */
for (size_t i = 0; i < var->DataLen ; i+=16) {
printf(" %08zx:", i);
for (size_t j = 0; j < 16; j++) {
if (i + j < var->DataLen) {
printf(" %02x", var->Data[i + j]);
} else {
printf(" ");
}
}
printf(" ");
for (size_t j = 0; j < 16 && i + j < var->DataLen; j++) {
if (var->Data[i + j] >= 0x20 && var->Data[i + j] < 0x7e) {
printf("%c", var->Data[i + j]);
} else {
printf(".");
}
}
printf("\n");
}
}
}