• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
4 
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "FdtPlatform.h"
16 
17 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
18   {L"-i", TypeFlag },
19   {NULL , TypeMax  }
20 };
21 
22 /**
23   Display FDT device paths.
24 
25   Display in text form the device paths used to install the FDT from the
26   highest to the lowest priority.
27 
28 **/
29 STATIC
30 VOID
DisplayFdtDevicePaths(VOID)31 DisplayFdtDevicePaths (
32   VOID
33   )
34 {
35   EFI_STATUS  Status;
36   UINTN       DataSize;
37   CHAR16      *TextDevicePath;
38   CHAR16      *TextDevicePaths;
39   CHAR16      *TextDevicePathSeparator;
40 
41   ShellPrintHiiEx (
42     -1, -1, NULL,
43     STRING_TOKEN (STR_SETFDT_DEVICE_PATH_LIST),
44     mFdtPlatformDxeHiiHandle
45     );
46 
47   if (FeaturePcdGet (PcdOverridePlatformFdt)) {
48     DataSize = 0;
49     Status = gRT->GetVariable (
50                     L"Fdt",
51                     &gFdtVariableGuid,
52                     NULL,
53                     &DataSize,
54                     NULL
55                     );
56 
57     //
58     // Keep going only if the "Fdt" variable is defined.
59     //
60 
61     if (Status == EFI_BUFFER_TOO_SMALL) {
62       TextDevicePath = AllocatePool (DataSize);
63       if (TextDevicePath == NULL) {
64         return;
65       }
66 
67       Status = gRT->GetVariable (
68                       L"Fdt",
69                       &gFdtVariableGuid,
70                       NULL,
71                       &DataSize,
72                       TextDevicePath
73                       );
74       if (!EFI_ERROR (Status)) {
75         ShellPrintHiiEx (
76           -1, -1, NULL,
77           STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
78           mFdtPlatformDxeHiiHandle,
79           TextDevicePath
80           );
81       }
82 
83       FreePool (TextDevicePath);
84     }
85   }
86 
87   //
88   // Loop over the device path list provided by "PcdFdtDevicePaths". The device
89   // paths are in text form and separated by a semi-colon.
90   //
91 
92   TextDevicePaths = AllocateCopyPool (
93                       StrSize ((CHAR16*)PcdGetPtr (PcdFdtDevicePaths)),
94                       (CHAR16*)PcdGetPtr (PcdFdtDevicePaths)
95                       );
96   if (TextDevicePaths == NULL) {
97     return;
98   }
99 
100   for (TextDevicePath = TextDevicePaths;
101        *TextDevicePath != L'\0'        ; ) {
102     TextDevicePathSeparator = StrStr (TextDevicePath, L";");
103 
104     if (TextDevicePathSeparator != NULL) {
105       *TextDevicePathSeparator = L'\0';
106     }
107 
108     ShellPrintHiiEx (
109       -1, -1, NULL,
110       STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
111       mFdtPlatformDxeHiiHandle,
112       TextDevicePath
113       );
114 
115     if (TextDevicePathSeparator == NULL) {
116       break;
117     }
118     TextDevicePath = TextDevicePathSeparator + 1;
119   }
120 
121   FreePool (TextDevicePaths);
122 }
123 
124 /**
125   Update the text device path stored in the "Fdt" UEFI variable given
126   an EFI Shell file path or a text device path.
127 
128   This function is a subroutine of the ShellDynCmdSetFdtHandler() function
129   to make its code easier to read.
130 
131   @param[in]  Shell          The instance of the shell protocol used in the
132                              context of processing the "setfdt" command.
133   @param[in]  FilePath       EFI Shell path or the device path to the FDT file.
134 
135   @return  SHELL_SUCCESS            The text device path was succesfully updated.
136   @return  SHELL_INVALID_PARAMETER  The Shell file path is not valid.
137   @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
138   @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.
139   @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.
140   @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.
141   @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.
142   @return  SHELL_NOT_FOUND          Device path to text protocol not found.
143   @return  SHELL_ABORTED            Operation aborted.
144 
145 **/
146 STATIC
147 SHELL_STATUS
UpdateFdtTextDevicePath(IN EFI_SHELL_PROTOCOL * Shell,IN CONST CHAR16 * FilePath)148 UpdateFdtTextDevicePath (
149   IN EFI_SHELL_PROTOCOL  *Shell,
150   IN CONST CHAR16        *FilePath
151   )
152 {
153   EFI_STATUS                          Status;
154   EFI_DEVICE_PATH                     *DevicePath;
155   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL    *EfiDevicePathToTextProtocol;
156   CHAR16                              *TextDevicePath;
157   CHAR16                              *FdtVariableValue;
158   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
159   SHELL_STATUS                        ShellStatus;
160 
161   ASSERT (FilePath != NULL);
162   DevicePath       = NULL;
163   TextDevicePath   = NULL;
164   FdtVariableValue = NULL;
165 
166   if (*FilePath != L'\0') {
167     DevicePath = Shell->GetDevicePathFromFilePath (FilePath);
168     if (DevicePath != NULL) {
169       Status = gBS->LocateProtocol (
170                       &gEfiDevicePathToTextProtocolGuid,
171                       NULL,
172                       (VOID **)&EfiDevicePathToTextProtocol
173                       );
174       if (EFI_ERROR (Status)) {
175         goto Error;
176       }
177 
178       TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText (
179                                                       DevicePath,
180                                                       FALSE,
181                                                       FALSE
182                                                       );
183       if (TextDevicePath == NULL) {
184         Status = EFI_OUT_OF_RESOURCES;
185         goto Error;
186       }
187       FdtVariableValue = TextDevicePath;
188     } else {
189       //
190       // Try to convert back the EFI Device Path String into a EFI device Path
191       // to ensure the format is valid
192       //
193       Status = gBS->LocateProtocol (
194                       &gEfiDevicePathFromTextProtocolGuid,
195                       NULL,
196                       (VOID **)&EfiDevicePathFromTextProtocol
197                       );
198       if (EFI_ERROR (Status)) {
199         goto Error;
200       }
201 
202       DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
203                                                     FilePath
204                                                     );
205       if (DevicePath == NULL) {
206         Status = EFI_INVALID_PARAMETER;
207         goto Error;
208       }
209       FdtVariableValue = (CHAR16*)FilePath;
210     }
211   }
212 
213   Status = gRT->SetVariable (
214                   (CHAR16*)L"Fdt",
215                   &gFdtVariableGuid,
216                   EFI_VARIABLE_RUNTIME_ACCESS    |
217                   EFI_VARIABLE_NON_VOLATILE      |
218                   EFI_VARIABLE_BOOTSERVICE_ACCESS ,
219                   (FdtVariableValue != NULL) ?
220                   StrSize (FdtVariableValue) : 0,
221                   FdtVariableValue
222                   );
223 
224 Error:
225   ShellStatus = EfiCodeToShellCode (Status);
226   if (!EFI_ERROR (Status)) {
227     if (FdtVariableValue != NULL) {
228       ShellPrintHiiEx (
229         -1, -1, NULL,
230         STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED),
231         mFdtPlatformDxeHiiHandle,
232         FdtVariableValue
233         );
234     } else {
235       ShellPrintHiiEx (
236         -1, -1, NULL,
237         STRING_TOKEN (STR_SETFDT_UPDATE_DELETED),
238         mFdtPlatformDxeHiiHandle
239         );
240     }
241   } else {
242     if (Status == EFI_INVALID_PARAMETER) {
243       ShellPrintHiiEx (
244         -1, -1, NULL,
245         STRING_TOKEN (STR_SETFDT_INVALID_PATH),
246         mFdtPlatformDxeHiiHandle,
247         FilePath
248         );
249     } else {
250       ShellPrintHiiEx (
251         -1, -1, NULL,
252         STRING_TOKEN (STR_SETFDT_ERROR),
253         mFdtPlatformDxeHiiHandle,
254         Status
255         );
256     }
257   }
258 
259   if (DevicePath != NULL) {
260     FreePool (DevicePath);
261   }
262   if (TextDevicePath != NULL) {
263     FreePool (TextDevicePath);
264   }
265 
266   return ShellStatus;
267 }
268 
269 /**
270   This is the shell command "setfdt" handler function. This function handles
271   the command when it is invoked in the shell.
272 
273   @param[in]  This             The instance of the
274                                EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
275   @param[in]  SystemTable      The pointer to the UEFI system table.
276   @param[in]  ShellParameters  The parameters associated with the command.
277   @param[in]  Shell            The instance of the shell protocol used in the
278                                context of processing this command.
279 
280   @return  SHELL_SUCCESS            The operation was successful.
281   @return  SHELL_ABORTED            Operation aborted due to internal error.
282   @return  SHELL_INVALID_PARAMETER  The parameters of the command are not valid.
283   @return  SHELL_INVALID_PARAMETER  The EFI Shell file path is not valid.
284   @return  SHELL_NOT_FOUND          Failed to locate a protocol or a file.
285   @return  SHELL_UNSUPPORTED        Device path not supported.
286   @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
287   @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.
288   @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.
289   @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.
290   @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.
291 
292 **/
293 SHELL_STATUS
294 EFIAPI
ShellDynCmdSetFdtHandler(IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL * This,IN EFI_SYSTEM_TABLE * SystemTable,IN EFI_SHELL_PARAMETERS_PROTOCOL * ShellParameters,IN EFI_SHELL_PROTOCOL * Shell)295 ShellDynCmdSetFdtHandler (
296   IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
297   IN EFI_SYSTEM_TABLE                    *SystemTable,
298   IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,
299   IN EFI_SHELL_PROTOCOL                  *Shell
300   )
301 {
302   SHELL_STATUS  ShellStatus;
303   EFI_STATUS    Status;
304   LIST_ENTRY    *ParamPackage;
305   BOOLEAN       FilePath;
306   CONST CHAR16  *ValueStr;
307   CHAR16        *TextDevicePath;
308 
309   ShellStatus  = SHELL_SUCCESS;
310   ParamPackage = NULL;
311   FilePath     = FALSE;
312 
313   //
314   // Install the Shell and Shell Parameters Protocols on the driver
315   // image. This is necessary for the initialisation of the Shell
316   // Library to succeed in the next step.
317   //
318   Status = gBS->InstallMultipleProtocolInterfaces (
319                   &gImageHandle,
320                   &gEfiShellProtocolGuid, Shell,
321                   &gEfiShellParametersProtocolGuid, ShellParameters,
322                   NULL
323                   );
324   if (EFI_ERROR (Status)) {
325     return SHELL_ABORTED;
326   }
327 
328   //
329   // Initialise the Shell Library as we are going to use it.
330   // Assert that the return code is EFI_SUCCESS as it should.
331   // To anticipate any change is the codes returned by
332   // ShellInitialize(), leave in case of error.
333   //
334   Status = ShellInitialize ();
335   if (EFI_ERROR (Status)) {
336     ASSERT_EFI_ERROR (Status);
337     return SHELL_ABORTED;
338   }
339 
340   Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
341   if (!EFI_ERROR (Status)) {
342     switch (ShellCommandLineGetCount (ParamPackage)) {
343     case 1:
344       //
345       // Case "setfdt" or "setfdt -i"
346       //
347       if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) {
348         DisplayFdtDevicePaths ();
349       }
350       break;
351 
352     case 2:
353       //
354       // Case "setfdt file_path"    or
355       //      "setfdt -i file_path" or
356       //      "setfdt file_path -i"
357       //
358       FilePath = TRUE;
359       break;
360 
361     default:
362       Status = EFI_INVALID_PARAMETER;
363     }
364   }
365   if (EFI_ERROR (Status)) {
366     ShellStatus = EfiCodeToShellCode (Status);
367     ShellPrintHiiEx (
368       -1, -1, NULL,
369       STRING_TOKEN (STR_SETFDT_ERROR),
370       mFdtPlatformDxeHiiHandle,
371       Status
372       );
373     goto Error;
374   }
375 
376   //
377   // Update the preferred device path for the FDT if asked for.
378   //
379   if (FilePath) {
380     ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);
381     ShellPrintHiiEx (
382       -1, -1, NULL,
383       STRING_TOKEN (STR_SETFDT_UPDATING),
384       mFdtPlatformDxeHiiHandle
385       );
386     ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr);
387     if (ShellStatus != SHELL_SUCCESS) {
388       goto Error;
389     }
390   }
391 
392   //
393   // Run the FDT installation process if asked for.
394   //
395   if (ShellCommandLineGetFlag (ParamPackage, L"-i")) {
396     ShellPrintHiiEx (
397       -1, -1, NULL,
398       STRING_TOKEN (STR_SETFDT_INSTALLING),
399       mFdtPlatformDxeHiiHandle
400       );
401     Status = RunFdtInstallation (&TextDevicePath);
402     ShellStatus = EfiCodeToShellCode (Status);
403     if (!EFI_ERROR (Status)) {
404       ShellPrintHiiEx (
405         -1, -1, NULL,
406         STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED),
407         mFdtPlatformDxeHiiHandle,
408         TextDevicePath
409         );
410       FreePool (TextDevicePath);
411     } else {
412       if (Status == EFI_INVALID_PARAMETER) {
413         ShellPrintHiiEx (
414           -1, -1, NULL,
415           STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH),
416           mFdtPlatformDxeHiiHandle
417           );
418       } else {
419         ShellPrintHiiEx (
420           -1, -1, NULL,
421           STRING_TOKEN (STR_SETFDT_ERROR),
422           mFdtPlatformDxeHiiHandle,
423           Status
424           );
425       }
426       DisplayFdtDevicePaths ();
427     }
428   }
429 
430 Error:
431   gBS->UninstallMultipleProtocolInterfaces (
432          gImageHandle,
433          &gEfiShellProtocolGuid, Shell,
434          &gEfiShellParametersProtocolGuid, ShellParameters,
435          NULL
436          );
437   ShellCommandLineFreeVarList (ParamPackage);
438 
439   return ShellStatus;
440 }
441 
442 /**
443   This is the shell command "setfdt" help handler function. This
444   function returns the formatted help for the "setfdt" command.
445   The format matchs that in Appendix B of the revision 2.1 of the
446   UEFI Shell Specification.
447 
448   @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
449   @param[in]  Language  The pointer to the language string to use.
450 
451   @return  CHAR16*  Pool allocated help string, must be freed by caller.
452 **/
453 CHAR16*
454 EFIAPI
ShellDynCmdSetFdtGetHelp(IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL * This,IN CONST CHAR8 * Language)455 ShellDynCmdSetFdtGetHelp (
456   IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
457   IN CONST CHAR8                         *Language
458   )
459 {
460   //
461   // This allocates memory. The caller has to free the allocated memory.
462   //
463   return HiiGetString (
464                 mFdtPlatformDxeHiiHandle,
465                 STRING_TOKEN (STR_GET_HELP_SETFDT),
466                 Language
467                 );
468 }
469