1 /*
2 * Copyright (C) 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #include "variable_mem.h"
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <malloc.h>
23 #include <lk/list.h>
24 #include <uefi/types.h>
25 #include "charset.h"
26
27 namespace {
28 constexpr size_t kVarNameMax = 128;
29
30 struct EfiVariable {
31 struct list_node node;
32 char16_t VariableName[kVarNameMax];
33 EfiGuid VendorGuid;
34 uint32_t Attributes;
35 char* Data;
36 size_t DataLen;
37 };
38 }
39
40 static list_node variables_in_mem = LIST_INITIAL_VALUE(variables_in_mem);
41
search_existing_variable(const char16_t * varname,const EfiGuid * guid)42 static EfiVariable * search_existing_variable(const char16_t *varname,
43 const EfiGuid *guid) {
44 /* search for existing variable */
45 struct EfiVariable *var = nullptr;
46 list_for_every_entry(&variables_in_mem, var, struct EfiVariable, node) {
47 if (guid != NULL && memcmp(&var->VendorGuid, guid, sizeof(EfiGuid)) != 0) {
48 continue;
49 }
50 if (utf16_strcmp(varname, var->VariableName) != 0) {
51 continue;
52 }
53 return var;
54 }
55 return nullptr;
56 }
57
efi_get_variable(const char16_t * variable_name,const EfiGuid * guid,uint32_t * attribute,char ** data,size_t * data_size)58 EfiStatus efi_get_variable(const char16_t *variable_name,
59 const EfiGuid *guid,
60 uint32_t *attribute,
61 char **data,
62 size_t *data_size) {
63 struct EfiVariable *var = search_existing_variable(variable_name, guid);
64
65 if (data)
66 *data = nullptr;
67 if (data_size)
68 *data_size = 0;
69 if (attribute)
70 *attribute = 0;
71 if (var) {
72 if (data)
73 *data = var->Data;
74 if (data_size)
75 *data_size = var->DataLen;
76 if (attribute)
77 *attribute = var->Attributes;
78 return SUCCESS;
79 }
80 return NOT_FOUND;
81 }
82
efi_set_variable(const char16_t * variable_name,const EfiGuid * guid,uint32_t attribute,const char * data,size_t data_len)83 void efi_set_variable(const char16_t *variable_name,
84 const EfiGuid *guid,
85 uint32_t attribute,
86 const char *data,
87 size_t data_len) {
88 struct EfiVariable *var = search_existing_variable(variable_name, guid);
89
90 /* alloc new variable if it is not existed */
91 if (!var) {
92 var = reinterpret_cast<struct EfiVariable *>(malloc(sizeof(struct EfiVariable)));
93 memset(var, 0, sizeof(struct EfiVariable));
94 var->node = LIST_INITIAL_CLEARED_VALUE;
95 size_t name_len = utf16_strlen(variable_name);
96 if (name_len >= kVarNameMax)
97 name_len = kVarNameMax - 1;
98 memcpy(var->VariableName, variable_name, name_len * sizeof(char16_t));
99 list_add_tail(&variables_in_mem, &var->node);
100 }
101 if (var->Data) {
102 free(var->Data);
103 }
104 var->Data = nullptr;
105 var->DataLen = 0;
106 if (data_len > 0) {
107 var->Data = reinterpret_cast<char *>(malloc(data_len));
108 memcpy(var->Data, data, data_len);
109 var->DataLen = data_len;
110 }
111 var->Attributes = attribute;
112 if (guid) {
113 memcpy(&var->VendorGuid, guid, sizeof(EfiGuid));
114 }
115 }
116
efi_list_variable(void)117 void efi_list_variable(void) {
118 struct EfiVariable *var = nullptr;
119 list_for_every_entry(&variables_in_mem, var, struct EfiVariable, node) {
120 char varname[kVarNameMax];
121
122 utf16_to_utf8(varname, var->VariableName, sizeof(varname));
123 printf("%s\n", varname);
124 /* print GUID */
125 printf(" %08x-%04x-%04x",
126 var->VendorGuid.data1,
127 var->VendorGuid.data2,
128 var->VendorGuid.data3);
129 for (int i = 0; i < 8 ; i++) {
130 if (i == 0 || i == 2) {
131 printf("-");
132 }
133 printf("%02x", var->VendorGuid.data4[i]);
134 }
135 printf("\n");
136 printf(" ");
137 /* print attributes */
138 for (uint32_t attr = 1; attr <= var->Attributes; attr <<= 1) {
139 if (var->Attributes & attr) {
140 if (attr == EFI_VARIABLE_NON_VOLATILE) {
141 printf("NV");
142 } else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) {
143 printf("BS");
144 } else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) {
145 printf("RT");
146 } else {
147 printf("0x%02x", attr);
148 }
149 if (attr << 1 <= var->Attributes) {
150 printf("|");
151 }
152 }
153 }
154 printf(", DataSize = 0x%zx\n", var->DataLen);
155 /* dump data */
156 for (size_t i = 0; i < var->DataLen ; i+=16) {
157 printf(" %08zx:", i);
158 for (size_t j = 0; j < 16; j++) {
159 if (i + j < var->DataLen) {
160 printf(" %02x", var->Data[i + j]);
161 } else {
162 printf(" ");
163 }
164 }
165 printf(" ");
166 for (size_t j = 0; j < 16 && i + j < var->DataLen; j++) {
167 if (var->Data[i + j] >= 0x20 && var->Data[i + j] < 0x7e) {
168 printf("%c", var->Data[i + j]);
169 } else {
170 printf(".");
171 }
172 }
173 printf("\n");
174 }
175 }
176 }
177