1 /** @file
2   Functions to deal with Disk buffer.
3 
4   Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "HexEditor.h"
10 #include <Protocol/BlockIo.h>
11 
12 extern EFI_HANDLE                 HImageHandleBackup;
13 extern HEFI_EDITOR_BUFFER_IMAGE   HBufferImage;
14 
15 extern BOOLEAN                    HBufferImageNeedRefresh;
16 extern BOOLEAN                    HBufferImageOnlyLineNeedRefresh;
17 extern BOOLEAN                    HBufferImageMouseNeedRefresh;
18 
19 extern HEFI_EDITOR_GLOBAL_EDITOR  HMainEditor;
20 
21 HEFI_EDITOR_DISK_IMAGE            HDiskImage;
22 HEFI_EDITOR_DISK_IMAGE            HDiskImageBackupVar;
23 
24 //
25 // for basic initialization of HDiskImage
26 //
27 HEFI_EDITOR_DISK_IMAGE            HDiskImageConst = {
28   NULL,
29   0,
30   0,
31   0
32 };
33 
34 /**
35   Initialization function for HDiskImage.
36 
37   @retval EFI_SUCCESS     The operation was successful.
38   @retval EFI_LOAD_ERROR  A load error occurred.
39 **/
40 EFI_STATUS
HDiskImageInit(VOID)41 HDiskImageInit (
42   VOID
43   )
44 {
45   //
46   // basically initialize the HDiskImage
47   //
48   CopyMem (&HDiskImage, &HDiskImageConst, sizeof (HDiskImage));
49 
50   CopyMem (&HDiskImageBackupVar, &HDiskImageConst, sizeof (HDiskImageBackupVar));
51 
52   return EFI_SUCCESS;
53 }
54 
55 /**
56   Backup function for HDiskImage. Only a few fields need to be backup.
57   This is for making the Disk buffer refresh as few as possible.
58 
59   @retval EFI_SUCCESS           The operation was successful.
60   @retval EFI_OUT_OF_RESOURCES  gST->ConOut of resources.
61 **/
62 EFI_STATUS
HDiskImageBackup(VOID)63 HDiskImageBackup (
64   VOID
65   )
66 {
67   //
68   // backup the disk name, offset and size
69   //
70   //
71   SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name);
72 
73   HDiskImageBackupVar.Name = CatSPrint(NULL, L"%s", HDiskImage.Name);
74   if (HDiskImageBackupVar.Name == NULL) {
75     return EFI_OUT_OF_RESOURCES;
76   }
77 
78   HDiskImageBackupVar.Offset  = HDiskImage.Offset;
79   HDiskImageBackupVar.Size    = HDiskImage.Size;
80 
81   return EFI_SUCCESS;
82 }
83 
84 /**
85   Cleanup function for HDiskImage.
86 
87   @retval EFI_SUCCESS           The operation was successful.
88 **/
89 EFI_STATUS
HDiskImageCleanup(VOID)90 HDiskImageCleanup (
91   VOID
92   )
93 {
94   SHELL_FREE_NON_NULL (HDiskImage.Name);
95   SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name);
96 
97   return EFI_SUCCESS;
98 }
99 
100 /**
101   Set FileName field in HFileImage.
102 
103   @param[in] Str      File name to set.
104   @param[in] Offset   The offset.
105   @param[in] Size     The size.
106 
107   @retval EFI_SUCCESS           The operation was successful.
108   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
109 **/
110 EFI_STATUS
HDiskImageSetDiskNameOffsetSize(IN CONST CHAR16 * Str,IN UINTN Offset,IN UINTN Size)111 HDiskImageSetDiskNameOffsetSize (
112   IN CONST CHAR16   *Str,
113   IN UINTN    Offset,
114   IN UINTN    Size
115   )
116 {
117   if (Str == HDiskImage.Name) {
118     //
119     // This function might be called using HDiskImage.FileName as Str.
120     // Directly return without updating HDiskImage.FileName.
121     //
122     return EFI_SUCCESS;
123   }
124 
125   //
126   // free the old file name
127   //
128   SHELL_FREE_NON_NULL (HDiskImage.Name);
129   HDiskImage.Name = AllocateCopyPool (StrSize (Str), Str);
130   if (HDiskImage.Name == NULL) {
131     return EFI_OUT_OF_RESOURCES;
132   }
133 
134   HDiskImage.Offset     = Offset;
135   HDiskImage.Size       = Size;
136 
137   return EFI_SUCCESS;
138 }
139 
140 /**
141   Read a disk from disk into HBufferImage.
142 
143   @param[in] DeviceName   filename to read.
144   @param[in] Offset       The offset.
145   @param[in] Size         The size.
146   @param[in] Recover      if is for recover, no information print.
147 
148   @retval EFI_SUCCESS           The operation was successful.
149   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
150   @retval EFI_LOAD_ERROR        A load error occurred.
151   @retval EFI_INVALID_PARAMETER A parameter was invalid.
152 **/
153 EFI_STATUS
HDiskImageRead(IN CONST CHAR16 * DeviceName,IN UINTN Offset,IN UINTN Size,IN BOOLEAN Recover)154 HDiskImageRead (
155   IN CONST CHAR16   *DeviceName,
156   IN UINTN    Offset,
157   IN UINTN    Size,
158   IN BOOLEAN  Recover
159   )
160 {
161   CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
162   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;
163   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePathForFree;
164   EFI_HANDLE                      Handle;
165   EFI_BLOCK_IO_PROTOCOL           *BlkIo;
166   EFI_STATUS                      Status;
167 
168   VOID                            *Buffer;
169   CHAR16                          *Str;
170   UINTN                           Bytes;
171 
172   HEFI_EDITOR_LINE                *Line;
173 
174   HBufferImage.BufferType = FileTypeDiskBuffer;
175 
176   DevicePath              = gEfiShellProtocol->GetDevicePathFromMap(DeviceName);
177   if (DevicePath == NULL) {
178     StatusBarSetStatusString (L"Cannot Find Device");
179     return EFI_INVALID_PARAMETER;
180   }
181   DupDevicePath = DuplicateDevicePath(DevicePath);
182   DupDevicePathForFree = DupDevicePath;
183   //
184   // get blkio interface
185   //
186   Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle);
187   FreePool(DupDevicePathForFree);
188   if (EFI_ERROR (Status)) {
189     StatusBarSetStatusString (L"Read Disk Failed");
190     return Status;
191   }
192   Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
193   if (EFI_ERROR (Status)) {
194     StatusBarSetStatusString (L"Read Disk Failed");
195     return Status;
196   }
197   //
198   // if Offset exceeds LastBlock,
199   //   return error
200   //
201   if (Offset > BlkIo->Media->LastBlock || Offset + Size > BlkIo->Media->LastBlock) {
202     StatusBarSetStatusString (L"Invalid Offset + Size");
203     return EFI_LOAD_ERROR;
204   }
205 
206   Bytes   = BlkIo->Media->BlockSize * Size;
207   Buffer  = AllocateZeroPool (Bytes);
208 
209   if (Buffer == NULL) {
210     StatusBarSetStatusString (L"Read Disk Failed");
211     return EFI_OUT_OF_RESOURCES;
212   }
213 
214   //
215   // read from disk
216   //
217   Status = BlkIo->ReadBlocks (
218                     BlkIo,
219                     BlkIo->Media->MediaId,
220                     Offset,
221                     Bytes,
222                     Buffer
223                     );
224 
225   if (EFI_ERROR (Status)) {
226     FreePool (Buffer);
227     StatusBarSetStatusString (L"Read Disk Failed");
228     return EFI_LOAD_ERROR;
229   }
230 
231   HBufferImageFree ();
232 
233   //
234   // convert buffer to line list
235   //
236   Status = HBufferImageBufferToList (Buffer, Bytes);
237   FreePool (Buffer);
238 
239   if (EFI_ERROR (Status)) {
240     StatusBarSetStatusString (L"Read Disk Failed");
241     return Status;
242   }
243 
244   Status = HDiskImageSetDiskNameOffsetSize (DeviceName, Offset, Size);
245   if (EFI_ERROR (Status)) {
246     StatusBarSetStatusString (L"Read Disk Failed");
247     return EFI_OUT_OF_RESOURCES;
248   }
249   //
250   // initialize some variables
251   //
252   HDiskImage.BlockSize                = BlkIo->Media->BlockSize;
253 
254   HBufferImage.DisplayPosition.Row    = 2;
255   HBufferImage.DisplayPosition.Column = 10;
256 
257   HBufferImage.MousePosition.Row      = 2;
258   HBufferImage.MousePosition.Column   = 10;
259 
260   HBufferImage.LowVisibleRow          = 1;
261   HBufferImage.HighBits               = TRUE;
262 
263   HBufferImage.BufferPosition.Row     = 1;
264   HBufferImage.BufferPosition.Column  = 1;
265 
266   if (!Recover) {
267     Str = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines);
268     if (Str == NULL) {
269       StatusBarSetStatusString (L"Read Disk Failed");
270       return EFI_OUT_OF_RESOURCES;
271     }
272 
273     StatusBarSetStatusString (Str);
274     SHELL_FREE_NON_NULL (Str);
275 
276     HMainEditor.SelectStart = 0;
277     HMainEditor.SelectEnd   = 0;
278 
279   }
280 
281   //
282   // has line
283   //
284   if (HBufferImage.Lines != NULL) {
285     HBufferImage.CurrentLine = CR (
286                                 HBufferImage.ListHead->ForwardLink,
287                                 HEFI_EDITOR_LINE,
288                                 Link,
289                                 EFI_EDITOR_LINE_LIST
290                                 );
291   } else {
292     //
293     // create a dummy line
294     //
295     Line = HBufferImageCreateLine ();
296     if (Line == NULL) {
297       StatusBarSetStatusString (L"Read Disk Failed");
298       return EFI_OUT_OF_RESOURCES;
299     }
300 
301     HBufferImage.CurrentLine = Line;
302   }
303 
304   HBufferImage.Modified           = FALSE;
305   HBufferImageNeedRefresh         = TRUE;
306   HBufferImageOnlyLineNeedRefresh = FALSE;
307   HBufferImageMouseNeedRefresh    = TRUE;
308 
309   return EFI_SUCCESS;
310 }
311 
312 /**
313   Save lines in HBufferImage to disk.
314   NOT ALLOW TO WRITE TO ANOTHER DISK!!!!!!!!!
315 
316   @param[in] DeviceName   The device name.
317   @param[in] Offset       The offset.
318   @param[in] Size         The size.
319 
320   @retval EFI_SUCCESS           The operation was successful.
321   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
322   @retval EFI_LOAD_ERROR        A load error occurred.
323   @retval EFI_INVALID_PARAMETER A parameter was invalid.
324 **/
325 EFI_STATUS
HDiskImageSave(IN CHAR16 * DeviceName,IN UINTN Offset,IN UINTN Size)326 HDiskImageSave (
327   IN CHAR16 *DeviceName,
328   IN UINTN  Offset,
329   IN UINTN  Size
330   )
331 {
332 
333   CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
334   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;
335   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePathForFree;
336   EFI_BLOCK_IO_PROTOCOL           *BlkIo;
337   EFI_STATUS                      Status;
338   EFI_HANDLE                      Handle;
339   VOID                            *Buffer;
340   UINTN                           Bytes;
341 
342   //
343   // if not modified, directly return
344   //
345   if (HBufferImage.Modified == FALSE) {
346     return EFI_SUCCESS;
347   }
348 
349   HBufferImage.BufferType = FileTypeDiskBuffer;
350 
351   DevicePath              = gEfiShellProtocol->GetDevicePathFromMap(DeviceName);
352   if (DevicePath == NULL) {
353 //    StatusBarSetStatusString (L"Cannot Find Device");
354     return EFI_INVALID_PARAMETER;
355   }
356   DupDevicePath = DuplicateDevicePath(DevicePath);
357   DupDevicePathForFree = DupDevicePath;
358 
359   //
360   // get blkio interface
361   //
362   Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle);
363   FreePool(DupDevicePathForFree);
364   if (EFI_ERROR (Status)) {
365 //    StatusBarSetStatusString (L"Read Disk Failed");
366     return Status;
367   }
368   Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
369   if (EFI_ERROR (Status)) {
370 //    StatusBarSetStatusString (L"Read Disk Failed");
371     return Status;
372   }
373 
374   Bytes   = BlkIo->Media->BlockSize * Size;
375   Buffer  = AllocateZeroPool (Bytes);
376 
377   if (Buffer == NULL) {
378     return EFI_OUT_OF_RESOURCES;
379   }
380   //
381   // concatenate the line list to a buffer
382   //
383   Status = HBufferImageListToBuffer (Buffer, Bytes);
384   if (EFI_ERROR (Status)) {
385     FreePool (Buffer);
386     return Status;
387   }
388 
389   //
390   // write the buffer to disk
391   //
392   Status = BlkIo->WriteBlocks (
393                     BlkIo,
394                     BlkIo->Media->MediaId,
395                     Offset,
396                     Bytes,
397                     Buffer
398                     );
399 
400   FreePool (Buffer);
401 
402   if (EFI_ERROR (Status)) {
403     return EFI_LOAD_ERROR;
404   }
405   //
406   // now not modified
407   //
408   HBufferImage.Modified = FALSE;
409 
410   return EFI_SUCCESS;
411 }
412