1 /** @file
2   Function definitions for shell simple text in and out on top of file handles.
3 
4   (C) Copyright 2013 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 "Shell.h"
11 
12 extern BOOLEAN AsciiRedirection;
13 
14 typedef struct {
15   EFI_SIMPLE_TEXT_INPUT_PROTOCOL  SimpleTextIn;
16   SHELL_FILE_HANDLE               FileHandle;
17   EFI_HANDLE                      TheHandle;
18   UINT64                          RemainingBytesOfInputFile;
19 } SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
20 
21 typedef struct {
22   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOut;
23   SHELL_FILE_HANDLE               FileHandle;
24   EFI_HANDLE                      TheHandle;
25   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OriginalSimpleTextOut;
26 } SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
27 
28 /**
29   Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
30   Signal the event if there is key available
31 
32   @param  Event                    Indicates the event that invoke this function.
33   @param  Context                  Indicates the calling context.
34 
35 **/
36 VOID
37 EFIAPI
ConInWaitForKey(IN EFI_EVENT Event,IN VOID * Context)38 ConInWaitForKey (
39   IN  EFI_EVENT       Event,
40   IN  VOID            *Context
41   )
42 {
43   gBS->SignalEvent (Event);
44 }
45 
46 /**
47   Reset function for the fake simple text input.
48 
49   @param[in] This     A pointer to the SimpleTextIn structure.
50   @param[in] ExtendedVerification TRUE for extra validation, FALSE otherwise.
51 
52   @retval   EFI_SUCCESS The reset was successful.
53 **/
54 EFI_STATUS
55 EFIAPI
FileBasedSimpleTextInReset(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)56 FileBasedSimpleTextInReset(
57   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
58   IN BOOLEAN                        ExtendedVerification
59   )
60 {
61   return (EFI_SUCCESS);
62 }
63 
64 /**
65   ReadKeyStroke function for the fake simple text input.
66 
67   @param[in] This      A pointer to the SimpleTextIn structure.
68   @param[in, out] Key  A pointer to the Key structure to fill.
69 
70   @retval   EFI_SUCCESS The read was successful.
71 **/
72 EFI_STATUS
73 EFIAPI
FileBasedSimpleTextInReadKeyStroke(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * This,IN OUT EFI_INPUT_KEY * Key)74 FileBasedSimpleTextInReadKeyStroke(
75   IN      EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
76   IN OUT  EFI_INPUT_KEY                  *Key
77   )
78 {
79   UINTN Size;
80   UINTN CharSize;
81 
82   //
83   // Verify the parameters
84   //
85   if (Key == NULL || This == NULL) {
86     return (EFI_INVALID_PARAMETER);
87   }
88 
89   //
90   // Check if we have any characters left in the stream.
91   //
92   if (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile == 0) {
93     return (EFI_NOT_READY);
94   }
95 
96   Size = sizeof(CHAR16);
97 
98   if(!AsciiRedirection) {
99     CharSize = sizeof(CHAR16);
100   } else {
101     CharSize = sizeof(CHAR8);
102   }
103   //
104   // Decrement the amount of free space by Size or set to zero (for odd length files)
105   //
106   if (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile > CharSize) {
107     ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile -= CharSize;
108   } else {
109     ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile = 0;
110   }
111 
112   Key->ScanCode = 0;
113   return (ShellInfoObject.NewEfiShellProtocol->ReadFile(
114     ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->FileHandle,
115     &Size,
116     &Key->UnicodeChar));
117 }
118 
119 /**
120   Function to create a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a
121   SHELL_FILE_HANDLE to support redirecting input from a file.
122 
123   @param[in]  FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use.
124   @param[in]  HandleLocation  The pointer of a location to copy handle with protocol to.
125 
126   @retval NULL                There was insufficient memory available.
127   @return                     A pointer to the allocated protocol structure;
128 **/
129 EFI_SIMPLE_TEXT_INPUT_PROTOCOL*
CreateSimpleTextInOnFile(IN SHELL_FILE_HANDLE FileHandleToUse,IN EFI_HANDLE * HandleLocation)130 CreateSimpleTextInOnFile(
131   IN SHELL_FILE_HANDLE  FileHandleToUse,
132   IN EFI_HANDLE         *HandleLocation
133   )
134 {
135   SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *ProtocolToReturn;
136   EFI_STATUS                            Status;
137   UINT64                                CurrentPosition;
138   UINT64                                FileSize;
139 
140   if (HandleLocation == NULL || FileHandleToUse == NULL) {
141     return (NULL);
142   }
143 
144   ProtocolToReturn = AllocateZeroPool(sizeof(SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL));
145   if (ProtocolToReturn == NULL) {
146     return (NULL);
147   }
148 
149   ShellGetFileSize    (FileHandleToUse, &FileSize);
150   ShellGetFilePosition(FileHandleToUse, &CurrentPosition);
151 
152   //
153   // Initialize the protocol members
154   //
155   ProtocolToReturn->RemainingBytesOfInputFile  = FileSize - CurrentPosition;
156   ProtocolToReturn->FileHandle                 = FileHandleToUse;
157   ProtocolToReturn->SimpleTextIn.Reset         = FileBasedSimpleTextInReset;
158   ProtocolToReturn->SimpleTextIn.ReadKeyStroke = FileBasedSimpleTextInReadKeyStroke;
159 
160   Status = gBS->CreateEvent (
161                   EVT_NOTIFY_WAIT,
162                   TPL_NOTIFY,
163                   ConInWaitForKey,
164                   &ProtocolToReturn->SimpleTextIn,
165                   &ProtocolToReturn->SimpleTextIn.WaitForKey
166                   );
167 
168   if (EFI_ERROR(Status)) {
169     FreePool(ProtocolToReturn);
170     return (NULL);
171   }
172   ///@todo possibly also install SimpleTextInputEx on the handle at this point.
173   Status = gBS->InstallProtocolInterface(
174     &(ProtocolToReturn->TheHandle),
175     &gEfiSimpleTextInProtocolGuid,
176     EFI_NATIVE_INTERFACE,
177     &(ProtocolToReturn->SimpleTextIn));
178   if (!EFI_ERROR(Status)) {
179     *HandleLocation = ProtocolToReturn->TheHandle;
180     return ((EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)ProtocolToReturn);
181   } else {
182     FreePool(ProtocolToReturn);
183     return (NULL);
184   }
185 }
186 
187 /**
188   Function to close a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a
189   SHELL_FILE_HANDLE to support redirecting input from a file.
190 
191   @param[in]  SimpleTextIn    The pointer to the SimpleTextIn to close.
192 
193   @retval EFI_SUCCESS         The object was closed.
194 **/
195 EFI_STATUS
CloseSimpleTextInOnFile(IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * SimpleTextIn)196 CloseSimpleTextInOnFile(
197   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *SimpleTextIn
198   )
199 {
200   EFI_STATUS Status;
201   EFI_STATUS Status1;
202 
203   if (SimpleTextIn == NULL) {
204     return (EFI_INVALID_PARAMETER);
205   }
206 
207   Status = gBS->CloseEvent(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)SimpleTextIn)->SimpleTextIn.WaitForKey);
208 
209   Status1 = gBS->UninstallProtocolInterface(
210     ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)SimpleTextIn)->TheHandle,
211     &gEfiSimpleTextInProtocolGuid,
212     &(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)SimpleTextIn)->SimpleTextIn));
213 
214   FreePool(SimpleTextIn);
215   if (!EFI_ERROR(Status)) {
216     return (Status1);
217   } else {
218     return (Status);
219   }
220 }
221 
222 /**
223   Reset the text output device hardware and optionally run diagnostics.
224 
225   @param  This                pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
226   @param ExtendedVerification Indicates that a more extensive test may be performed
227 
228   @retval EFI_SUCCESS         The text output device was reset.
229 **/
230 EFI_STATUS
231 EFIAPI
FileBasedSimpleTextOutReset(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)232 FileBasedSimpleTextOutReset (
233   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
234   IN  BOOLEAN                         ExtendedVerification
235   )
236 {
237   return (EFI_SUCCESS);
238 }
239 
240 /**
241   Verifies that all characters in a Unicode string can be output to the
242   target device.
243 
244   @param[in] This     Protocol instance pointer.
245   @param[in] WString  The NULL-terminated Unicode string to be examined.
246 
247   @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
248 **/
249 EFI_STATUS
250 EFIAPI
FileBasedSimpleTextOutTestString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * WString)251 FileBasedSimpleTextOutTestString (
252   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
253   IN  CHAR16                          *WString
254   )
255 {
256   return (EFI_SUCCESS);
257 }
258 
259 /**
260   Returns information for an available text mode that the output device(s)
261   supports.
262 
263   @param[in] This               Protocol instance pointer.
264   @param[in] ModeNumber         The mode number to return information on.
265   @param[out] Columns           Upon return, the number of columns in the selected geometry
266   @param[out] Rows              Upon return, the number of rows in the selected geometry
267 
268   @retval EFI_UNSUPPORTED       The mode number was not valid.
269 **/
270 EFI_STATUS
271 EFIAPI
FileBasedSimpleTextOutQueryMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber,OUT UINTN * Columns,OUT UINTN * Rows)272 FileBasedSimpleTextOutQueryMode (
273   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
274   IN  UINTN                           ModeNumber,
275   OUT UINTN                           *Columns,
276   OUT UINTN                           *Rows
277   )
278 {
279   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *PassThruProtocol;
280 
281   PassThruProtocol = ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)This)->OriginalSimpleTextOut;
282 
283   // Pass the QueryMode call thru to the original SimpleTextOutProtocol
284   return (PassThruProtocol->QueryMode(
285     PassThruProtocol,
286     ModeNumber,
287     Columns,
288     Rows));
289 }
290 
291 /**
292   Sets the output device(s) to a specified mode.
293 
294   @param[in] This               Protocol instance pointer.
295   @param[in] ModeNumber         The mode number to set.
296 
297   @retval EFI_UNSUPPORTED       The mode number was not valid.
298 **/
299 EFI_STATUS
300 EFIAPI
FileBasedSimpleTextOutSetMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber)301 FileBasedSimpleTextOutSetMode (
302   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
303   IN  UINTN                         ModeNumber
304   )
305 {
306   return (EFI_UNSUPPORTED);
307 }
308 
309 /**
310   Sets the background and foreground colors for the OutputString () and
311   ClearScreen () functions.
312 
313   @param[in] This               Protocol instance pointer.
314   @param[in] Attribute          The attribute to set. Bits 0..3 are the foreground color, and
315                                 bits 4..6 are the background color. All other bits are undefined
316                                 and must be zero. The valid Attributes are defined in this file.
317 
318   @retval EFI_SUCCESS           The attribute was set.
319 **/
320 EFI_STATUS
321 EFIAPI
FileBasedSimpleTextOutSetAttribute(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Attribute)322 FileBasedSimpleTextOutSetAttribute (
323   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
324   IN  UINTN                           Attribute
325   )
326 {
327   return (EFI_SUCCESS);
328 }
329 
330 /**
331   Clears the output device(s) display to the currently selected background
332   color.
333 
334   @param[in] This               Protocol instance pointer.
335 
336   @retval EFI_UNSUPPORTED       The output device is not in a valid text mode.
337 **/
338 EFI_STATUS
339 EFIAPI
FileBasedSimpleTextOutClearScreen(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This)340 FileBasedSimpleTextOutClearScreen (
341   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This
342   )
343 {
344   return (EFI_SUCCESS);
345 }
346 
347 /**
348   Sets the current coordinates of the cursor position
349 
350   @param[in] This               Protocol instance pointer.
351   @param[in] Column             Column to put the cursor in.  Must be between zero and Column returned from QueryMode
352   @param[in] Row                Row to put the cursor in.  Must be between zero and Row returned from QueryMode
353 
354   @retval EFI_SUCCESS           The operation completed successfully.
355 **/
356 EFI_STATUS
357 EFIAPI
FileBasedSimpleTextOutSetCursorPosition(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Column,IN UINTN Row)358 FileBasedSimpleTextOutSetCursorPosition (
359   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
360   IN  UINTN                         Column,
361   IN  UINTN                         Row
362   )
363 {
364   return (EFI_SUCCESS);
365 }
366 
367 /**
368   Makes the cursor visible or invisible
369 
370   @param[in] This       Protocol instance pointer.
371   @param[in] Visible    If TRUE, the cursor is set to be visible. If FALSE, the cursor is
372                         set to be invisible.
373 
374   @retval EFI_SUCCESS           The operation completed successfully.
375 **/
376 EFI_STATUS
377 EFIAPI
FileBasedSimpleTextOutEnableCursor(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN Visible)378 FileBasedSimpleTextOutEnableCursor (
379   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
380   IN  BOOLEAN                       Visible
381   )
382 {
383   return (EFI_SUCCESS);
384 }
385 
386 /**
387   Write a Unicode string to the output device.
388 
389   @param[in] This                 Protocol instance pointer.
390   @param[in] WString              The NULL-terminated Unicode string to be displayed on the output
391                                   device(s). All output devices must also support the Unicode
392                                   drawing defined in this file.
393   @retval EFI_SUCCESS             The string was output to the device.
394   @retval EFI_DEVICE_ERROR        The device reported an error while attempting to output
395                                   the text.
396   @retval EFI_UNSUPPORTED         The output device's mode is not currently in a
397                                   defined text mode.
398   @retval EFI_WARN_UNKNOWN_GLYPH  This warning code indicates that some of the
399                                   characters in the Unicode string could not be
400                                   rendered and were skipped.
401 **/
402 EFI_STATUS
403 EFIAPI
FileBasedSimpleTextOutOutputString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * WString)404 FileBasedSimpleTextOutOutputString (
405   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
406   IN  CHAR16                          *WString
407   )
408 {
409   UINTN Size;
410   Size = StrLen(WString) * sizeof(CHAR16);
411   return (ShellInfoObject.NewEfiShellProtocol->WriteFile(
412     ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)This)->FileHandle,
413     &Size,
414     WString));
415 }
416 
417 /**
418   Function to create a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a
419   SHELL_FILE_HANDLE to support redirecting output from a file.
420 
421   @param[in]  FileHandleToUse  The pointer to the SHELL_FILE_HANDLE to use.
422   @param[in]  HandleLocation   The pointer of a location to copy handle with protocol to.
423   @param[in]  OriginalProtocol The pointer to the original output protocol for pass thru of functions.
424 
425   @retval NULL                There was insufficient memory available.
426   @return                     A pointer to the allocated protocol structure;
427 **/
428 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*
CreateSimpleTextOutOnFile(IN SHELL_FILE_HANDLE FileHandleToUse,IN EFI_HANDLE * HandleLocation,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * OriginalProtocol)429 CreateSimpleTextOutOnFile(
430   IN SHELL_FILE_HANDLE               FileHandleToUse,
431   IN EFI_HANDLE                      *HandleLocation,
432   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OriginalProtocol
433   )
434 {
435   SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ProtocolToReturn;
436   EFI_STATUS                            Status;
437 
438   if (HandleLocation == NULL || FileHandleToUse == NULL) {
439     return (NULL);
440   }
441 
442   ProtocolToReturn = AllocateZeroPool(sizeof(SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL));
443   if (ProtocolToReturn == NULL) {
444     return (NULL);
445   }
446   ProtocolToReturn->FileHandle                      = FileHandleToUse;
447   ProtocolToReturn->OriginalSimpleTextOut           = OriginalProtocol;
448   ProtocolToReturn->SimpleTextOut.Reset             = FileBasedSimpleTextOutReset;
449   ProtocolToReturn->SimpleTextOut.TestString        = FileBasedSimpleTextOutTestString;
450   ProtocolToReturn->SimpleTextOut.QueryMode         = FileBasedSimpleTextOutQueryMode;
451   ProtocolToReturn->SimpleTextOut.SetMode           = FileBasedSimpleTextOutSetMode;
452   ProtocolToReturn->SimpleTextOut.SetAttribute      = FileBasedSimpleTextOutSetAttribute;
453   ProtocolToReturn->SimpleTextOut.ClearScreen       = FileBasedSimpleTextOutClearScreen;
454   ProtocolToReturn->SimpleTextOut.SetCursorPosition = FileBasedSimpleTextOutSetCursorPosition;
455   ProtocolToReturn->SimpleTextOut.EnableCursor      = FileBasedSimpleTextOutEnableCursor;
456   ProtocolToReturn->SimpleTextOut.OutputString      = FileBasedSimpleTextOutOutputString;
457   ProtocolToReturn->SimpleTextOut.Mode              = AllocateZeroPool(sizeof(EFI_SIMPLE_TEXT_OUTPUT_MODE));
458   if (ProtocolToReturn->SimpleTextOut.Mode == NULL) {
459     FreePool(ProtocolToReturn);
460     return (NULL);
461   }
462   ProtocolToReturn->SimpleTextOut.Mode->MaxMode       = OriginalProtocol->Mode->MaxMode;
463   ProtocolToReturn->SimpleTextOut.Mode->Mode          = OriginalProtocol->Mode->Mode;
464   ProtocolToReturn->SimpleTextOut.Mode->Attribute     = OriginalProtocol->Mode->Attribute;
465   ProtocolToReturn->SimpleTextOut.Mode->CursorColumn  = OriginalProtocol->Mode->CursorColumn;
466   ProtocolToReturn->SimpleTextOut.Mode->CursorRow     = OriginalProtocol->Mode->CursorRow;
467   ProtocolToReturn->SimpleTextOut.Mode->CursorVisible = OriginalProtocol->Mode->CursorVisible;
468 
469   Status = gBS->InstallProtocolInterface(
470     &(ProtocolToReturn->TheHandle),
471     &gEfiSimpleTextOutProtocolGuid,
472     EFI_NATIVE_INTERFACE,
473     &(ProtocolToReturn->SimpleTextOut));
474   if (!EFI_ERROR(Status)) {
475     *HandleLocation = ProtocolToReturn->TheHandle;
476     return ((EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)ProtocolToReturn);
477   } else {
478     SHELL_FREE_NON_NULL(ProtocolToReturn->SimpleTextOut.Mode);
479     SHELL_FREE_NON_NULL(ProtocolToReturn);
480     return (NULL);
481   }
482 }
483 
484 /**
485   Function to close a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a
486   SHELL_FILE_HANDLE to support redirecting output from a file.
487 
488   @param[in] SimpleTextOut    The pointer to the SimpleTextOUT to close.
489 
490   @retval EFI_SUCCESS         The object was closed.
491 **/
492 EFI_STATUS
CloseSimpleTextOutOnFile(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * SimpleTextOut)493 CloseSimpleTextOutOnFile(
494   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *SimpleTextOut
495   )
496 {
497   EFI_STATUS  Status;
498   if (SimpleTextOut == NULL) {
499     return (EFI_INVALID_PARAMETER);
500   }
501   Status = gBS->UninstallProtocolInterface(
502     ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)SimpleTextOut)->TheHandle,
503     &gEfiSimpleTextOutProtocolGuid,
504     &(((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)SimpleTextOut)->SimpleTextOut));
505   FreePool(SimpleTextOut->Mode);
506   FreePool(SimpleTextOut);
507   return (Status);
508 }
509