OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
GrubVars.c
Go to the documentation of this file.
1
6#include "LinuxBootInternal.h"
7
8#include <Library/BaseLib.h>
9#include <Library/BaseMemoryLib.h>
10#include <Library/MemoryAllocationLib.h>
13#include <Library/OcStringLib.h>
14#include <Library/OcStringLib.h>
15
17
18STATIC OC_FLEX_ARRAY *mGrubVars = NULL;
19
20EFI_STATUS
22 VOID
23 )
24{
25 mGrubVars = OcFlexArrayInit (sizeof (GRUB_VAR), NULL);
26 if (mGrubVars == NULL) {
27 return EFI_OUT_OF_RESOURCES;
28 }
29
30 return EFI_SUCCESS;
31}
32
33VOID
35 VOID
36 )
37{
38 if (mGrubVars != NULL) {
40 }
41}
42
43EFI_STATUS
45 CHAR8 *Key,
46 CHAR8 *Value,
47 UINTN Errors
48 )
49{
50 GRUB_VAR *Var;
51 UINTN Index;
52 UINTN WereErrors;
53
54 ASSERT (mGrubVars != NULL);
55 ASSERT (Key[0] != '\0');
56
57 for (Index = 0; Index < mGrubVars->Count; ++Index) {
58 Var = OcFlexArrayItemAt (mGrubVars, Index);
59 if (AsciiStrCmp (Var->Key, Key) == 0) {
60 break;
61 }
62 }
63
64 if (Index < mGrubVars->Count) {
65 Var->Value = Value;
66 WereErrors = Var->Errors;
67
68 //
69 // Probably not worth the two lines of code (because unlikely to
70 // occur), but: allow later non-indented no-vars value to overwrite
71 // earlier non-indented has-vars value and thereby become usable.
72 //
73 if ((Errors & VAR_ERR_INDENTED) == 0) {
74 Var->Errors &= ~VAR_ERR_HAS_VARS;
75 }
76
77 //
78 // Indentation err stays set because, even if grub.cfg code layout is
79 // reasonable as we are assuming, we are not parsing enough to tell
80 // which order (or none) indented vars are set in.
81 //
82 Var->Errors |= Errors;
83
84 DEBUG ((
85 (gLinuxBootFlags & LINUX_BOOT_LOG_GRUB_VARS) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
86 "LNX: Repeated %a=%a (0x%x->0x%x)\n",
87 Key,
88 Value,
89 WereErrors,
90 Var->Errors
91 ));
92 } else {
94 if (Var == NULL) {
95 return EFI_OUT_OF_RESOURCES;
96 }
97
98 Var->Key = Key;
99 Var->Value = Value;
100 Var->Errors = Errors;
101
102 DEBUG ((
103 (gLinuxBootFlags & LINUX_BOOT_LOG_GRUB_VARS) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
104 "LNX: Added %a=%a (0x%x)\n",
105 Key,
106 Value,
107 Errors
108 ));
109 }
110
111 return EFI_SUCCESS;
112}
113
114//
115// Compatible with Grub2 blscfg's simple definition of what gets replaced,
116// cf InternalExpandGrubVars. (If there was more complex logic, it would
117// probably make most sense just not to have this pre-check.)
118//
119BOOLEAN
121 CHAR8 *Value
122 )
123{
124 return OcAsciiStrChr (Value, '$') != NULL;
125}
126
127GRUB_VAR *
129 IN CONST CHAR8 *Key
130 )
131{
132 UINTN Index;
133 GRUB_VAR *Var;
134
135 for (Index = 0; Index < mGrubVars->Count; Index++) {
136 Var = OcFlexArrayItemAt (mGrubVars, Index);
137 if (AsciiStrCmp (Var->Key, Key) == 0) {
138 return Var;
139 }
140 }
141
142 return NULL;
143}
144
145EFI_STATUS
147 IN OUT OC_FLEX_ARRAY *Options
148 )
149{
150 EFI_STATUS Status;
151 UINTN Index;
152 CHAR8 **Value;
153 CHAR8 *Result;
154
155 for (Index = 0; Index < Options->Count; Index++) {
156 Value = OcFlexArrayItemAt (Options, Index);
157 if (InternalHasGrubVars (*Value)) {
158 Status = InternalExpandGrubVars (*Value, &Result);
159 if (EFI_ERROR (Status)) {
160 return Status;
161 }
162
163 FreePool (*Value);
164 *Value = Result;
165 }
166 }
167
168 return EFI_SUCCESS;
169}
170
171EFI_STATUS
173 IN CONST CHAR8 *Value,
174 IN OUT CHAR8 **Result
175 )
176{
177 EFI_STATUS Status;
178 UINTN Pos;
179 UINTN LastPos;
180 BOOLEAN InVar;
181 BOOLEAN Retake;
182 GRUB_VAR *Var;
183 CHAR8 Ch;
184 UINTN VarLength;
185 OC_ASCII_STRING_BUFFER *StringBuffer;
186
187 ASSERT (Value != NULL);
188 ASSERT (Result != NULL);
189
190 *Result = NULL;
191
192 if (Value == NULL) {
193 return EFI_INVALID_PARAMETER;
194 }
195
196 StringBuffer = OcAsciiStringBufferInit ();
197 if (StringBuffer == NULL) {
198 return EFI_OUT_OF_RESOURCES;
199 }
200
201 Pos = 0;
202 LastPos = 0;
203 InVar = FALSE;
204 Status = EFI_SUCCESS;
205 Retake = FALSE;
206
207 //
208 // These simple checks for what counts as a var to replace (including
209 // the fact that there is no escape for '$') match Grub2 blscfg module.
210 //
211 do {
212 Ch = Value[Pos];
213 if (!InVar) {
214 if ((Ch == '$') || (Ch == '\0')) {
215 Status = OcAsciiStringBufferAppendN (StringBuffer, &Value[LastPos], Pos - LastPos);
216
217 InVar = TRUE;
218 LastPos = Pos + 1;
219 }
220 } else if (!((Ch == '_') || IS_DIGIT (Ch) || IS_ALPHA (Ch))) {
221 ((CHAR8 *)Value)[Pos] = '\0';
222 Var = InternalGetGrubVar (&Value[LastPos]);
223 if (Var == NULL) {
224 DEBUG ((DEBUG_WARN, "LNX: Missing required grub var $%a\n", &Value[LastPos]));
225 Status = EFI_INVALID_PARAMETER;
226 } else if (Var->Errors != 0) {
227 DEBUG ((DEBUG_WARN, "LNX: Unusable grub var $%a - 0x%x\n", &Value[LastPos], Var->Errors));
228 Status = EFI_INVALID_PARAMETER;
229 }
230
231 ((CHAR8 *)Value)[Pos] = Ch;
232
233 //
234 // Blscfg always appends a space to each expanded token (and the var values
235 // are often set up to end with a space, too), then later GRUB tokenization
236 // of the options as grub booter options (which we do not currently do - may
237 // be needed in some escaped cases?) cleans it up. Here, we try to combine
238 // obvious doubled up spaces right away.
239 //
240 if (!EFI_ERROR (Status)) {
241 if (Var->Value != NULL) {
242 VarLength = AsciiStrLen (Var->Value);
243 if ((VarLength > 0) && (Var->Value[VarLength - 1] == ' ')) {
244 --VarLength;
245 }
246 }
247
248 Status = OcAsciiStringBufferAppendN (StringBuffer, Var->Value, VarLength);
249 }
250
251 if (!EFI_ERROR (Status) && !((Ch == ' ') || (Ch == '\0'))) {
252 Status = OcAsciiStringBufferAppend (StringBuffer, " ");
253 }
254
255 InVar = FALSE;
256 Retake = TRUE;
257 LastPos = Pos;
258 }
259
260 if (Retake) {
261 Retake = FALSE;
262 } else {
263 ++Pos;
264 }
265 } while (Ch != '\0' && !EFI_ERROR (Status));
266
267 *Result = OcAsciiStringBufferFreeContainer (&StringBuffer);
268
269 if (EFI_ERROR (Status)) {
270 if (*Result != NULL) {
271 FreePool (*Result);
272 *Result = NULL;
273 }
274 }
275
276 DEBUG ((
277 (gLinuxBootFlags & LINUX_BOOT_LOG_GRUB_VARS) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
278 "LNX: Expanding '%a' => '%a' - %r\n",
279 Value,
280 *Result,
281 Status
282 ));
283
284 return Status;
285}
EFI_STATUS InternalInitGrubVars(VOID)
Definition GrubVars.c:21
EFI_STATUS InternalSetGrubVar(CHAR8 *Key, CHAR8 *Value, UINTN Errors)
Definition GrubVars.c:44
BOOLEAN InternalHasGrubVars(CHAR8 *Value)
Definition GrubVars.c:120
VOID InternalFreeGrubVars(VOID)
Definition GrubVars.c:34
STATIC OC_FLEX_ARRAY * mGrubVars
Definition GrubVars.c:18
EFI_STATUS InternalExpandGrubVars(IN CONST CHAR8 *Value, IN OUT CHAR8 **Result)
Definition GrubVars.c:172
GRUB_VAR * InternalGetGrubVar(IN CONST CHAR8 *Key)
Definition GrubVars.c:128
EFI_STATUS InternalExpandGrubVarsForArray(IN OUT OC_FLEX_ARRAY *Options)
Definition GrubVars.c:146
#define VAR_ERR_INDENTED
#define IS_DIGIT(c)
UINTN gLinuxBootFlags
#define LINUX_BOOT_LOG_GRUB_VARS
#define IS_ALPHA(c)
VOID OcFlexArrayFree(IN OUT OC_FLEX_ARRAY **FlexArray)
CHAR8 * OcAsciiStringBufferFreeContainer(IN OUT OC_ASCII_STRING_BUFFER **StringBuffer)
OC_FLEX_ARRAY * OcFlexArrayInit(IN CONST UINTN ItemSize, IN CONST OC_FLEX_ARRAY_FREE_ITEM FreeItem OPTIONAL)
Definition FlexArray.c:31
EFI_STATUS OcAsciiStringBufferAppendN(IN OUT OC_ASCII_STRING_BUFFER *Buffer, IN CONST CHAR8 *AppendString, OPTIONAL IN CONST UINTN Length)
VOID * OcFlexArrayAddItem(IN OUT OC_FLEX_ARRAY *FlexArray)
Definition FlexArray.c:136
EFI_STATUS OcAsciiStringBufferAppend(IN OUT OC_ASCII_STRING_BUFFER *Buffer, IN CONST CHAR8 *AppendString OPTIONAL)
VOID * OcFlexArrayItemAt(IN CONST OC_FLEX_ARRAY *FlexArray, IN CONST UINTN Index)
Definition FlexArray.c:189
OC_ASCII_STRING_BUFFER * OcAsciiStringBufferInit(VOID)
CHAR8 *EFIAPI OcAsciiStrChr(IN CONST CHAR8 *String, IN CHAR8 Char)
Definition OcAsciiLib.c:369
#define ASSERT(x)
Definition coder.h:55
ush Pos
Definition deflate.h:92