lib: uefi: add volatile UEFI variable support
GBL needs to read an UEFI variable called "gbl_debug". We add 2 commands. "uefi_set_var" to set an UEFI variable. And "uefi_list_var" to list the UEFI variables. For GBL, we can use "uefi_set_var gbl_debug 1" to enable its debug mode. Signed-off-by: Ying-Chun Liu (PaulLiu) <paulliu@debian.org>
This commit is contained in:
committed by
Kelvin Zhang
parent
de3e831eae
commit
45d7da5640
@@ -22,6 +22,7 @@ MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/io_stack.cpp \
|
||||
$(LOCAL_DIR)/debug_support.cpp \
|
||||
$(LOCAL_DIR)/charset.cpp \
|
||||
$(LOCAL_DIR)/variable_mem.cpp \
|
||||
|
||||
|
||||
include make/module.mk
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <uefi/system_table.h>
|
||||
|
||||
#include "boot_service_provider.h"
|
||||
#include "charset.h"
|
||||
#include "configuration_table.h"
|
||||
#include "defer.h"
|
||||
#include "memory_protocols.h"
|
||||
@@ -43,6 +44,7 @@
|
||||
#include "text_protocol.h"
|
||||
#include "uefi_platform.h"
|
||||
#include "debug_support.h"
|
||||
#include "variable_mem.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -170,8 +172,31 @@ int cmd_uefi_load(int argc, const console_cmd_args *argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_uefi_set_variable(int argc, const console_cmd_args *argv) {
|
||||
if (argc != 3) {
|
||||
printf("Usage: %s <variable> <data>\n", argv[0].str);
|
||||
return 1;
|
||||
}
|
||||
EfiGuid guid = EFI_GLOBAL_VARIABLE_GUID;
|
||||
char16_t buffer[128];
|
||||
utf8_to_utf16(buffer, argv[1].str, sizeof(buffer) / sizeof(buffer[0]));
|
||||
efi_set_variable(buffer,
|
||||
&guid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
||||
argv[2].str,
|
||||
strlen(argv[2].str));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_uefi_list_variable(int argc, const console_cmd_args *argv) {
|
||||
efi_list_variable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC_COMMAND_START
|
||||
STATIC_COMMAND("uefi_load", "load UEFI application and run it", &cmd_uefi_load)
|
||||
STATIC_COMMAND("uefi_set_var", "set UEFI variable", &cmd_uefi_set_variable)
|
||||
STATIC_COMMAND("uefi_list_var", "list UEFI variable", &cmd_uefi_list_variable)
|
||||
STATIC_COMMAND_END(uefi);
|
||||
|
||||
} // namespace
|
||||
|
||||
176
lib/uefi/variable_mem.cpp
Normal file
176
lib/uefi/variable_mem.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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 SUCCESS;
|
||||
}
|
||||
return 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
46
lib/uefi/variable_mem.h
Normal file
46
lib/uefi/variable_mem.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VARIABLE_MEM_
|
||||
#define __VARIABLE_MEM_
|
||||
|
||||
#include <uefi/types.h>
|
||||
|
||||
static constexpr auto EFI_GLOBAL_VARIABLE_GUID =
|
||||
EfiGuid{0x8be4df61,
|
||||
0x93ca,
|
||||
0x11d2,
|
||||
{0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c}};
|
||||
|
||||
static constexpr uint32_t EFI_VARIABLE_NON_VOLATILE = 0x01;
|
||||
static constexpr uint32_t EFI_VARIABLE_BOOTSERVICE_ACCESS = 0x02;
|
||||
static constexpr uint32_t EFI_VARIABLE_RUNTIME_ACCESS = 0x04;
|
||||
static constexpr uint32_t EFI_VARIABLE_HARDWARE_ERROR_RECORD = 0x08;
|
||||
|
||||
EfiStatus efi_get_variable(const char16_t *variable_name,
|
||||
const EfiGuid *guid,
|
||||
uint32_t *attribute,
|
||||
char **data,
|
||||
size_t *data_size);
|
||||
void efi_set_variable(const char16_t *variable_name,
|
||||
const EfiGuid *guid,
|
||||
uint32_t attribute,
|
||||
const char *data,
|
||||
size_t data_len);
|
||||
|
||||
void efi_list_variable(void);
|
||||
#endif
|
||||
Reference in New Issue
Block a user