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