]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDebug1CommandsLib/SetVar.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / SetVar.c
1 /** @file
2 Main file for SetVar shell Debug1 function.
3
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UefiShellDebug1CommandsLib.h"
11
12 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
13 { L"-guid", TypeValue },
14 { L"-bs", TypeFlag },
15 { L"-rt", TypeFlag },
16 { L"-nv", TypeFlag },
17 { NULL, TypeMax }
18 };
19
20 typedef enum {
21 DataTypeHexNumber = 0,
22 DataTypeHexArray = 1,
23 DataTypeAscii = 2,
24 DataTypeUnicode = 3,
25 DataTypeDevicePath = 4,
26 DataTypeUnKnow = 5
27 } DATA_TYPE;
28
29 typedef union {
30 UINT8 HexNumber8;
31 UINT16 HexNumber16;
32 UINT32 HexNumber32;
33 UINT64 HexNumber64;
34 } HEX_NUMBER;
35
36 /**
37 Check if the input is a (potentially empty) string of hexadecimal nibbles.
38
39 @param[in] String The CHAR16 string to check.
40
41 @retval FALSE A character has been found in String for which
42 ShellIsHexaDecimalDigitCharacter() returned FALSE.
43
44 @retval TRUE Otherwise. (Note that this covers the case when String is
45 empty.)
46 **/
47 BOOLEAN
48 IsStringOfHexNibbles (
49 IN CONST CHAR16 *String
50 )
51 {
52 CONST CHAR16 *Pos;
53
54 for (Pos = String; *Pos != L'\0'; ++Pos) {
55 if (!ShellIsHexaDecimalDigitCharacter (*Pos)) {
56 return FALSE;
57 }
58 }
59
60 return TRUE;
61 }
62
63 /**
64 Function to check the TYPE of Data.
65
66 @param[in] Data The Data to be check.
67
68 @retval DATA_TYPE The TYPE of Data.
69 **/
70 DATA_TYPE
71 TestDataType (
72 IN CONST CHAR16 *Data
73 )
74 {
75 if ((Data[0] == L'0') && ((Data[1] == L'x') || (Data[1] == L'X'))) {
76 if (IsStringOfHexNibbles (Data+2) && (StrLen (Data + 2) <= 16)) {
77 return DataTypeHexNumber;
78 } else {
79 return DataTypeUnKnow;
80 }
81 } else if (Data[0] == L'H') {
82 if (IsStringOfHexNibbles (Data + 1) && (StrLen (Data + 1) % 2 == 0)) {
83 return DataTypeHexArray;
84 } else {
85 return DataTypeUnKnow;
86 }
87 } else if (Data[0] == L'S') {
88 return DataTypeAscii;
89 } else if (Data[0] == L'L') {
90 return DataTypeUnicode;
91 } else if ((Data[0] == L'P') || (StrnCmp (Data, L"--", 2) == 0)) {
92 return DataTypeDevicePath;
93 }
94
95 if (IsStringOfHexNibbles (Data) && (StrLen (Data) % 2 == 0)) {
96 return DataTypeHexArray;
97 }
98
99 return DataTypeAscii;
100 }
101
102 /**
103 Function to parse the Data by the type of Data, and save in the Buffer.
104
105 @param[in] Data A pointer to a buffer to be parsed.
106 @param[out] Buffer A pointer to a buffer to hold the return data.
107 @param[in,out] BufferSize On input, indicates the size of Buffer in bytes.
108 On output,indicates the size of data return in Buffer.
109 Or the size in bytes of the buffer needed to obtain.
110
111 @retval EFI_INVALID_PARAMETER The Buffer or BufferSize is NULL.
112 @retval EFI_BUFFER_TOO_SMALL The Buffer is too small to hold the data.
113 @retval EFI_OUT_OF_RESOURCES A memory allcation failed.
114 @retval EFI_SUCCESS The Data parsed successful and save in the Buffer.
115 **/
116 EFI_STATUS
117 ParseParameterData (
118 IN CONST CHAR16 *Data,
119 OUT VOID *Buffer,
120 IN OUT UINTN *BufferSize
121 )
122 {
123 UINT64 HexNumber;
124 UINTN HexNumberLen;
125 UINTN Size;
126 CHAR8 *AsciiBuffer;
127 DATA_TYPE DataType;
128 EFI_DEVICE_PATH_PROTOCOL *DevPath;
129 EFI_STATUS Status;
130
131 HexNumber = 0;
132 HexNumberLen = 0;
133 Size = 0;
134 AsciiBuffer = NULL;
135 DevPath = NULL;
136 Status = EFI_SUCCESS;
137
138 if ((Data == NULL) || (BufferSize == NULL)) {
139 return EFI_INVALID_PARAMETER;
140 }
141
142 DataType = TestDataType (Data);
143 if (DataType == DataTypeHexNumber) {
144 //
145 // hex number
146 //
147 StrHexToUint64S (Data + 2, NULL, &HexNumber);
148 HexNumberLen = StrLen (Data + 2);
149 if ((HexNumberLen >= 1) && (HexNumberLen <= 2)) {
150 Size = 1;
151 } else if ((HexNumberLen >= 3) && (HexNumberLen <= 4)) {
152 Size = 2;
153 } else if ((HexNumberLen >= 5) && (HexNumberLen <= 8)) {
154 Size = 4;
155 } else if ((HexNumberLen >= 9) && (HexNumberLen <= 16)) {
156 Size = 8;
157 }
158
159 if ((Buffer != NULL) && (*BufferSize >= Size)) {
160 CopyMem (Buffer, (VOID *)&HexNumber, Size);
161 } else {
162 Status = EFI_BUFFER_TOO_SMALL;
163 }
164
165 *BufferSize = Size;
166 } else if (DataType == DataTypeHexArray) {
167 //
168 // hex array
169 //
170 if (*Data == L'H') {
171 Data = Data + 1;
172 }
173
174 Size = StrLen (Data) / 2;
175 if ((Buffer != NULL) && (*BufferSize >= Size)) {
176 StrHexToBytes (Data, StrLen (Data), (UINT8 *)Buffer, Size);
177 } else {
178 Status = EFI_BUFFER_TOO_SMALL;
179 }
180
181 *BufferSize = Size;
182 } else if (DataType == DataTypeAscii) {
183 //
184 // ascii text
185 //
186 if (*Data == L'S') {
187 Data = Data + 1;
188 }
189
190 AsciiBuffer = AllocateZeroPool (StrSize (Data) / 2);
191 if (AsciiBuffer == NULL) {
192 Status = EFI_OUT_OF_RESOURCES;
193 } else {
194 AsciiSPrint (AsciiBuffer, StrSize (Data) / 2, "%s", (CHAR8 *)Data);
195
196 Size = StrSize (Data) / 2 - 1;
197 if ((Buffer != NULL) && (*BufferSize >= Size)) {
198 CopyMem (Buffer, AsciiBuffer, Size);
199 } else {
200 Status = EFI_BUFFER_TOO_SMALL;
201 }
202
203 *BufferSize = Size;
204 }
205
206 SHELL_FREE_NON_NULL (AsciiBuffer);
207 } else if (DataType == DataTypeUnicode) {
208 //
209 // unicode text
210 //
211 if (*Data == L'L') {
212 Data = Data + 1;
213 }
214
215 Size = StrSize (Data) - sizeof (CHAR16);
216 if ((Buffer != NULL) && (*BufferSize >= Size)) {
217 CopyMem (Buffer, Data, Size);
218 } else {
219 Status = EFI_BUFFER_TOO_SMALL;
220 }
221
222 *BufferSize = Size;
223 } else if (DataType == DataTypeDevicePath) {
224 if (*Data == L'P') {
225 Data = Data + 1;
226 } else if (StrnCmp (Data, L"--", 2) == 0) {
227 Data = Data + 2;
228 }
229
230 DevPath = ConvertTextToDevicePath (Data);
231 if (DevPath == NULL) {
232 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");
233 Status = EFI_INVALID_PARAMETER;
234 } else {
235 Size = GetDevicePathSize (DevPath);
236 if ((Buffer != NULL) && (*BufferSize >= Size)) {
237 CopyMem (Buffer, DevPath, Size);
238 } else {
239 Status = EFI_BUFFER_TOO_SMALL;
240 }
241
242 *BufferSize = Size;
243 }
244
245 SHELL_FREE_NON_NULL (DevPath);
246 } else {
247 Status = EFI_INVALID_PARAMETER;
248 }
249
250 return Status;
251 }
252
253 /**
254 Function to get each data from parameters.
255
256 @param[in] Package The package of checked values.
257 @param[out] Buffer A pointer to a buffer to hold the return data.
258 @param[out] BufferSize Indicates the size of data in bytes return in Buffer.
259
260 @retval EFI_INVALID_PARAMETER Buffer or BufferSize is NULL.
261 @retval EFI_OUT_OF_RESOURCES A memory allcation failed.
262 @retval EFI_SUCCESS Get each parameter data was successful.
263 **/
264 EFI_STATUS
265 GetVariableDataFromParameter (
266 IN CONST LIST_ENTRY *Package,
267 OUT UINT8 **Buffer,
268 OUT UINTN *BufferSize
269 )
270 {
271 CONST CHAR16 *TempData;
272 UINTN Index;
273 UINTN TotalSize;
274 UINTN Size;
275 UINT8 *BufferWalker;
276 EFI_STATUS Status;
277
278 TotalSize = 0;
279 Size = 0;
280 Status = EFI_SUCCESS;
281
282 if ((BufferSize == NULL) || (Buffer == NULL) || (ShellCommandLineGetCount (Package) < 3)) {
283 return EFI_INVALID_PARAMETER;
284 }
285
286 for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) {
287 TempData = ShellCommandLineGetRawValue (Package, Index);
288 ASSERT (TempData != NULL);
289
290 if (TempData[0] != L'=') {
291 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData);
292 return EFI_INVALID_PARAMETER;
293 }
294
295 TempData = TempData + 1;
296 Size = 0;
297 Status = ParseParameterData (TempData, NULL, &Size);
298 if (EFI_ERROR (Status)) {
299 if (Status == EFI_BUFFER_TOO_SMALL) {
300 //
301 // We expect return EFI_BUFFER_TOO_SMALL when pass 'NULL' as second parameter to the function ParseParameterData.
302 //
303 TotalSize += Size;
304 } else {
305 if (Status == EFI_INVALID_PARAMETER) {
306 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData);
307 } else if (Status == EFI_NOT_FOUND) {
308 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");
309 }
310
311 return Status;
312 }
313 }
314 }
315
316 *BufferSize = TotalSize;
317 *Buffer = AllocateZeroPool (TotalSize);
318
319 if (*Buffer == NULL) {
320 Status = EFI_OUT_OF_RESOURCES;
321 } else {
322 BufferWalker = *Buffer;
323 for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) {
324 TempData = ShellCommandLineGetRawValue (Package, Index);
325 TempData = TempData + 1;
326
327 Size = TotalSize;
328 Status = ParseParameterData (TempData, (VOID *)BufferWalker, &Size);
329 if (!EFI_ERROR (Status)) {
330 BufferWalker = BufferWalker + Size;
331 TotalSize = TotalSize - Size;
332 } else {
333 return Status;
334 }
335 }
336 }
337
338 return EFI_SUCCESS;
339 }
340
341 /**
342 Function for 'setvar' command.
343
344 @param[in] ImageHandle Handle to the Image (NULL if Internal).
345 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
346 **/
347 SHELL_STATUS
348 EFIAPI
349 ShellCommandRunSetVar (
350 IN EFI_HANDLE ImageHandle,
351 IN EFI_SYSTEM_TABLE *SystemTable
352 )
353 {
354 EFI_STATUS Status;
355 RETURN_STATUS RStatus;
356 LIST_ENTRY *Package;
357 CHAR16 *ProblemParam;
358 SHELL_STATUS ShellStatus;
359 CONST CHAR16 *VariableName;
360 EFI_GUID Guid;
361 CONST CHAR16 *StringGuid;
362 UINT32 Attributes;
363 VOID *Buffer;
364 UINTN Size;
365 UINTN LoopVar;
366
367 ShellStatus = SHELL_SUCCESS;
368 Status = EFI_SUCCESS;
369 Buffer = NULL;
370 Size = 0;
371 Attributes = 0;
372
373 //
374 // initialize the shell lib (we must be in non-auto-init...)
375 //
376 Status = ShellInitialize ();
377 ASSERT_EFI_ERROR (Status);
378
379 Status = CommandInit ();
380 ASSERT_EFI_ERROR (Status);
381
382 //
383 // parse the command line
384 //
385 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
386 if (EFI_ERROR (Status)) {
387 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
388 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"setvar", ProblemParam);
389 FreePool (ProblemParam);
390 ShellStatus = SHELL_INVALID_PARAMETER;
391 } else {
392 ASSERT (FALSE);
393 }
394 } else if (ShellCommandLineCheckDuplicate (Package, &ProblemParam) != EFI_SUCCESS) {
395 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DUPLICATE), gShellDebug1HiiHandle, L"setvar", ProblemParam);
396 FreePool (ProblemParam);
397 ShellStatus = SHELL_INVALID_PARAMETER;
398 } else {
399 if (ShellCommandLineGetCount (Package) < 2) {
400 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"setvar");
401 ShellStatus = SHELL_INVALID_PARAMETER;
402 } else {
403 VariableName = ShellCommandLineGetRawValue (Package, 1);
404 if (!ShellCommandLineGetFlag (Package, L"-guid")) {
405 CopyGuid (&Guid, &gEfiGlobalVariableGuid);
406 } else {
407 StringGuid = ShellCommandLineGetValue (Package, L"-guid");
408 RStatus = StrToGuid (StringGuid, &Guid);
409 if (RETURN_ERROR (RStatus) || (StringGuid[GUID_STRING_LENGTH] != L'\0')) {
410 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", StringGuid);
411 ShellStatus = SHELL_INVALID_PARAMETER;
412 }
413 }
414
415 if (ShellCommandLineGetCount (Package) == 2) {
416 //
417 // Display
418 //
419 Status = gRT->GetVariable ((CHAR16 *)VariableName, &Guid, &Attributes, &Size, Buffer);
420 if (Status == EFI_BUFFER_TOO_SMALL) {
421 Buffer = AllocateZeroPool (Size);
422 Status = gRT->GetVariable ((CHAR16 *)VariableName, &Guid, &Attributes, &Size, Buffer);
423 }
424
425 if (!EFI_ERROR (Status) && (Buffer != NULL)) {
426 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_PRINT), gShellDebug1HiiHandle, &Guid, VariableName, Size);
427 for (LoopVar = 0; LoopVar < Size; LoopVar++) {
428 ShellPrintEx (-1, -1, L"%02x ", ((UINT8 *)Buffer)[LoopVar]);
429 }
430
431 ShellPrintEx (-1, -1, L"\r\n");
432 } else {
433 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_GET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
434 ShellStatus = SHELL_ACCESS_DENIED;
435 }
436 } else {
437 //
438 // Create, Delete or Modify.
439 //
440 Status = gRT->GetVariable ((CHAR16 *)VariableName, &Guid, &Attributes, &Size, Buffer);
441 if (Status == EFI_BUFFER_TOO_SMALL) {
442 Buffer = AllocateZeroPool (Size);
443 Status = gRT->GetVariable ((CHAR16 *)VariableName, &Guid, &Attributes, &Size, Buffer);
444 }
445
446 if (EFI_ERROR (Status) || (Buffer == NULL)) {
447 //
448 // Creating a new variable. determine attributes from command line.
449 //
450 Attributes = 0;
451 if (ShellCommandLineGetFlag (Package, L"-bs")) {
452 Attributes |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
453 }
454
455 if (ShellCommandLineGetFlag (Package, L"-rt")) {
456 Attributes |= EFI_VARIABLE_RUNTIME_ACCESS |
457 EFI_VARIABLE_BOOTSERVICE_ACCESS;
458 }
459
460 if (ShellCommandLineGetFlag (Package, L"-nv")) {
461 Attributes |= EFI_VARIABLE_NON_VOLATILE;
462 }
463 }
464
465 SHELL_FREE_NON_NULL (Buffer);
466
467 Size = 0;
468 Status = GetVariableDataFromParameter (Package, (UINT8 **)&Buffer, &Size);
469 if (!EFI_ERROR (Status)) {
470 Status = gRT->SetVariable ((CHAR16 *)VariableName, &Guid, Attributes, Size, Buffer);
471 }
472
473 if (EFI_ERROR (Status)) {
474 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
475 ShellStatus = SHELL_ACCESS_DENIED;
476 } else {
477 ASSERT (ShellStatus == SHELL_SUCCESS);
478 }
479 }
480 }
481
482 ShellCommandLineFreeVarList (Package);
483 }
484
485 if (Buffer != NULL) {
486 FreePool (Buffer);
487 }
488
489 return (ShellStatus);
490 }