]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / Comp.c
... / ...
CommitLineData
1/** @file\r
2 Main file for Comp shell Debug1 function.\r
3\r
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "UefiShellDebug1CommandsLib.h"\r
11\r
12STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
13 { L"-n", TypeValue },\r
14 { L"-s", TypeValue },\r
15 { NULL, TypeMax }\r
16};\r
17\r
18typedef enum {\r
19 OutOfDiffPoint,\r
20 InDiffPoint,\r
21 InPrevDiffPoint\r
22} READ_STATUS;\r
23\r
24//\r
25// Buffer type, for reading both file operands in chunks.\r
26//\r
27typedef struct {\r
28 UINT8 *Data; // dynamically allocated buffer\r
29 UINTN Allocated; // the allocated size of Data\r
30 UINTN Next; // next position in Data to fetch a byte at\r
31 UINTN Left; // number of bytes left in Data for fetching at Next\r
32} FILE_BUFFER;\r
33\r
34/**\r
35 Function to print differnt point data.\r
36\r
37 @param[in] FileName File name.\r
38 @param[in] FileTag File tag name.\r
39 @param[in] Buffer Data buffer to be printed.\r
40 @param[in] BufferSize Size of the data to be printed.\r
41 @param[in] Address Address of the differnt point.\r
42 @param[in] DifferentBytes Total size of the buffer.\r
43\r
44**/\r
45VOID\r
46PrintDifferentPoint (\r
47 CONST CHAR16 *FileName,\r
48 CHAR16 *FileTag,\r
49 UINT8 *Buffer,\r
50 UINT64 BufferSize,\r
51 UINTN Address,\r
52 UINT64 DifferentBytes\r
53 )\r
54{\r
55 UINTN Index;\r
56\r
57 ShellPrintEx (-1, -1, L"%s: %s\r\n %08x:", FileTag, FileName, Address);\r
58\r
59 //\r
60 // Print data in hex-format.\r
61 //\r
62 for (Index = 0; Index < BufferSize; Index++) {\r
63 ShellPrintEx (-1, -1, L" %02x", Buffer[Index]);\r
64 }\r
65\r
66 if (BufferSize < DifferentBytes) {\r
67 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_END_OF_FILE), gShellDebug1HiiHandle);\r
68 }\r
69\r
70 ShellPrintEx (-1, -1, L" *");\r
71\r
72 //\r
73 // Print data in char-format.\r
74 //\r
75 for (Index = 0; Index < BufferSize; Index++) {\r
76 if ((Buffer[Index] >= 0x20) && (Buffer[Index] <= 0x7E)) {\r
77 ShellPrintEx (-1, -1, L"%c", Buffer[Index]);\r
78 } else {\r
79 //\r
80 // Print dots for control characters\r
81 //\r
82 ShellPrintEx (-1, -1, L".");\r
83 }\r
84 }\r
85\r
86 ShellPrintEx (-1, -1, L"*\r\n");\r
87}\r
88\r
89/**\r
90 Initialize a FILE_BUFFER.\r
91\r
92 @param[out] FileBuffer The FILE_BUFFER to initialize. On return, the caller\r
93 is responsible for checking FileBuffer->Data: if\r
94 FileBuffer->Data is NULL on output, then memory\r
95 allocation failed.\r
96**/\r
97STATIC\r
98VOID\r
99FileBufferInit (\r
100 OUT FILE_BUFFER *FileBuffer\r
101 )\r
102{\r
103 FileBuffer->Allocated = PcdGet32 (PcdShellFileOperationSize);\r
104 FileBuffer->Data = AllocatePool (FileBuffer->Allocated);\r
105 FileBuffer->Left = 0;\r
106}\r
107\r
108/**\r
109 Uninitialize a FILE_BUFFER.\r
110\r
111 @param[in,out] FileBuffer The FILE_BUFFER to uninitialize. The caller is\r
112 responsible for making sure FileBuffer was first\r
113 initialized with FileBufferInit(), successfully or\r
114 unsuccessfully.\r
115**/\r
116STATIC\r
117VOID\r
118FileBufferUninit (\r
119 IN OUT FILE_BUFFER *FileBuffer\r
120 )\r
121{\r
122 SHELL_FREE_NON_NULL (FileBuffer->Data);\r
123}\r
124\r
125/**\r
126 Read a byte from a SHELL_FILE_HANDLE, buffered with a FILE_BUFFER.\r
127\r
128 @param[in] FileHandle The SHELL_FILE_HANDLE to replenish FileBuffer\r
129 from, if needed.\r
130\r
131 @param[in,out] FileBuffer The FILE_BUFFER to read a byte from. If FileBuffer\r
132 is empty on entry, then FileBuffer is refilled\r
133 from FileHandle, before outputting a byte from\r
134 FileBuffer to Byte. The caller is responsible for\r
135 ensuring that FileBuffer was successfully\r
136 initialized with FileBufferInit().\r
137\r
138 @param[out] BytesRead On successful return, BytesRead is set to 1 if the\r
139 next byte from FileBuffer has been stored to Byte.\r
140 On successful return, BytesRead is set to 0 if\r
141 FileBuffer is empty, and FileHandle is at EOF.\r
142 When an error is returned, BytesRead is not set.\r
143\r
144 @param[out] Byte On output, the next byte from FileBuffer. Only set\r
145 if (a) EFI_SUCCESS is returned and (b) BytesRead\r
146 is set to 1 on output.\r
147\r
148 @retval EFI_SUCCESS BytesRead has been set to 0 or 1. In the latter case,\r
149 Byte has been set as well.\r
150\r
151 @return Error codes propagated from\r
152 gEfiShellProtocol->ReadFile().\r
153**/\r
154STATIC\r
155EFI_STATUS\r
156FileBufferReadByte (\r
157 IN SHELL_FILE_HANDLE FileHandle,\r
158 IN OUT FILE_BUFFER *FileBuffer,\r
159 OUT UINTN *BytesRead,\r
160 OUT UINT8 *Byte\r
161 )\r
162{\r
163 UINTN ReadSize;\r
164 EFI_STATUS Status;\r
165\r
166 if (FileBuffer->Left == 0) {\r
167 ReadSize = FileBuffer->Allocated;\r
168 Status = gEfiShellProtocol->ReadFile (\r
169 FileHandle,\r
170 &ReadSize,\r
171 FileBuffer->Data\r
172 );\r
173 if (EFI_ERROR (Status)) {\r
174 return Status;\r
175 }\r
176\r
177 if (ReadSize == 0) {\r
178 *BytesRead = 0;\r
179 return EFI_SUCCESS;\r
180 }\r
181\r
182 FileBuffer->Next = 0;\r
183 FileBuffer->Left = ReadSize;\r
184 }\r
185\r
186 *BytesRead = 1;\r
187 *Byte = FileBuffer->Data[FileBuffer->Next];\r
188\r
189 FileBuffer->Next++;\r
190 FileBuffer->Left--;\r
191 return EFI_SUCCESS;\r
192}\r
193\r
194/**\r
195 Function for 'comp' command.\r
196\r
197 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
198 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
199**/\r
200SHELL_STATUS\r
201EFIAPI\r
202ShellCommandRunComp (\r
203 IN EFI_HANDLE ImageHandle,\r
204 IN EFI_SYSTEM_TABLE *SystemTable\r
205 )\r
206{\r
207 EFI_STATUS Status;\r
208 LIST_ENTRY *Package;\r
209 CHAR16 *ProblemParam;\r
210 CHAR16 *FileName1;\r
211 CHAR16 *FileName2;\r
212 CONST CHAR16 *TempParam;\r
213 SHELL_STATUS ShellStatus;\r
214 SHELL_FILE_HANDLE FileHandle1;\r
215 SHELL_FILE_HANDLE FileHandle2;\r
216 UINT64 Size1;\r
217 UINT64 Size2;\r
218 UINT64 DifferentBytes;\r
219 UINT64 DifferentCount;\r
220 UINT8 DiffPointNumber;\r
221 UINT8 OneByteFromFile1;\r
222 UINT8 OneByteFromFile2;\r
223 UINT8 *DataFromFile1;\r
224 UINT8 *DataFromFile2;\r
225 FILE_BUFFER FileBuffer1;\r
226 FILE_BUFFER FileBuffer2;\r
227 UINTN InsertPosition1;\r
228 UINTN InsertPosition2;\r
229 UINTN DataSizeFromFile1;\r
230 UINTN DataSizeFromFile2;\r
231 UINTN TempAddress;\r
232 UINTN Index;\r
233 UINTN DiffPointAddress;\r
234 READ_STATUS ReadStatus;\r
235\r
236 ShellStatus = SHELL_SUCCESS;\r
237 Status = EFI_SUCCESS;\r
238 FileName1 = NULL;\r
239 FileName2 = NULL;\r
240 FileHandle1 = NULL;\r
241 FileHandle2 = NULL;\r
242 DataFromFile1 = NULL;\r
243 DataFromFile2 = NULL;\r
244 ReadStatus = OutOfDiffPoint;\r
245 DifferentCount = 10;\r
246 DifferentBytes = 4;\r
247 DiffPointNumber = 0;\r
248 InsertPosition1 = 0;\r
249 InsertPosition2 = 0;\r
250 TempAddress = 0;\r
251 DiffPointAddress = 0;\r
252\r
253 //\r
254 // initialize the shell lib (we must be in non-auto-init...)\r
255 //\r
256 Status = ShellInitialize ();\r
257 ASSERT_EFI_ERROR (Status);\r
258\r
259 Status = CommandInit ();\r
260 ASSERT_EFI_ERROR (Status);\r
261\r
262 //\r
263 // parse the command line\r
264 //\r
265 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
266 if (EFI_ERROR (Status)) {\r
267 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {\r
268 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"comp", ProblemParam);\r
269 FreePool (ProblemParam);\r
270 ShellStatus = SHELL_INVALID_PARAMETER;\r
271 } else {\r
272 ASSERT (FALSE);\r
273 }\r
274 } else {\r
275 if (ShellCommandLineGetCount (Package) > 3) {\r
276 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"comp");\r
277 ShellStatus = SHELL_INVALID_PARAMETER;\r
278 } else if (ShellCommandLineGetCount (Package) < 3) {\r
279 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"comp");\r
280 ShellStatus = SHELL_INVALID_PARAMETER;\r
281 } else {\r
282 TempParam = ShellCommandLineGetRawValue (Package, 1);\r
283 ASSERT (TempParam != NULL);\r
284 FileName1 = ShellFindFilePath (TempParam);\r
285 if (FileName1 == NULL) {\r
286 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);\r
287 ShellStatus = SHELL_NOT_FOUND;\r
288 } else {\r
289 Status = ShellOpenFileByName (FileName1, &FileHandle1, EFI_FILE_MODE_READ, 0);\r
290 if (EFI_ERROR (Status)) {\r
291 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);\r
292 ShellStatus = SHELL_NOT_FOUND;\r
293 }\r
294 }\r
295\r
296 TempParam = ShellCommandLineGetRawValue (Package, 2);\r
297 ASSERT (TempParam != NULL);\r
298 FileName2 = ShellFindFilePath (TempParam);\r
299 if (FileName2 == NULL) {\r
300 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);\r
301 ShellStatus = SHELL_NOT_FOUND;\r
302 } else {\r
303 Status = ShellOpenFileByName (FileName2, &FileHandle2, EFI_FILE_MODE_READ, 0);\r
304 if (EFI_ERROR (Status)) {\r
305 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);\r
306 ShellStatus = SHELL_NOT_FOUND;\r
307 }\r
308 }\r
309\r
310 if (ShellStatus == SHELL_SUCCESS) {\r
311 Status = gEfiShellProtocol->GetFileSize (FileHandle1, &Size1);\r
312 ASSERT_EFI_ERROR (Status);\r
313 Status = gEfiShellProtocol->GetFileSize (FileHandle2, &Size2);\r
314 ASSERT_EFI_ERROR (Status);\r
315\r
316 if (ShellCommandLineGetFlag (Package, L"-n")) {\r
317 TempParam = ShellCommandLineGetValue (Package, L"-n");\r
318 if (TempParam == NULL) {\r
319 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-n");\r
320 ShellStatus = SHELL_INVALID_PARAMETER;\r
321 } else {\r
322 if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)TempParam, L"all") == 0) {\r
323 DifferentCount = MAX_UINTN;\r
324 } else {\r
325 Status = ShellConvertStringToUint64 (TempParam, &DifferentCount, FALSE, TRUE);\r
326 if (EFI_ERROR (Status) || (DifferentCount == 0)) {\r
327 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-n");\r
328 ShellStatus = SHELL_INVALID_PARAMETER;\r
329 }\r
330 }\r
331 }\r
332 }\r
333\r
334 if (ShellCommandLineGetFlag (Package, L"-s")) {\r
335 TempParam = ShellCommandLineGetValue (Package, L"-s");\r
336 if (TempParam == NULL) {\r
337 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-s");\r
338 ShellStatus = SHELL_INVALID_PARAMETER;\r
339 } else {\r
340 Status = ShellConvertStringToUint64 (TempParam, &DifferentBytes, FALSE, TRUE);\r
341 if (EFI_ERROR (Status) || (DifferentBytes == 0)) {\r
342 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-s");\r
343 ShellStatus = SHELL_INVALID_PARAMETER;\r
344 } else {\r
345 if (DifferentBytes > MAX (Size1, Size2)) {\r
346 DifferentBytes = MAX (Size1, Size2);\r
347 }\r
348 }\r
349 }\r
350 }\r
351 }\r
352\r
353 if (ShellStatus == SHELL_SUCCESS) {\r
354 DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes);\r
355 DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes);\r
356 FileBufferInit (&FileBuffer1);\r
357 FileBufferInit (&FileBuffer2);\r
358 if ((DataFromFile1 == NULL) || (DataFromFile2 == NULL) ||\r
359 (FileBuffer1.Data == NULL) || (FileBuffer2.Data == NULL))\r
360 {\r
361 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
362 SHELL_FREE_NON_NULL (DataFromFile1);\r
363 SHELL_FREE_NON_NULL (DataFromFile2);\r
364 FileBufferUninit (&FileBuffer1);\r
365 FileBufferUninit (&FileBuffer2);\r
366 }\r
367 }\r
368\r
369 if (ShellStatus == SHELL_SUCCESS) {\r
370 while (DiffPointNumber < DifferentCount) {\r
371 DataSizeFromFile1 = 1;\r
372 DataSizeFromFile2 = 1;\r
373 OneByteFromFile1 = 0;\r
374 OneByteFromFile2 = 0;\r
375 Status = FileBufferReadByte (\r
376 FileHandle1,\r
377 &FileBuffer1,\r
378 &DataSizeFromFile1,\r
379 &OneByteFromFile1\r
380 );\r
381 ASSERT_EFI_ERROR (Status);\r
382 Status = FileBufferReadByte (\r
383 FileHandle2,\r
384 &FileBuffer2,\r
385 &DataSizeFromFile2,\r
386 &OneByteFromFile2\r
387 );\r
388 ASSERT_EFI_ERROR (Status);\r
389\r
390 TempAddress++;\r
391\r
392 //\r
393 // 1.When end of file and no chars in DataFromFile buffer, then break while.\r
394 // 2.If no more char in File1 or File2, The ReadStatus is InPrevDiffPoint forever.\r
395 // So the previous different point is the last one, then break the while block.\r
396 //\r
397 if (((DataSizeFromFile1 == 0) && (InsertPosition1 == 0) && (DataSizeFromFile2 == 0) && (InsertPosition2 == 0)) ||\r
398 ((ReadStatus == InPrevDiffPoint) && ((DataSizeFromFile1 == 0) || (DataSizeFromFile2 == 0)))\r
399 )\r
400 {\r
401 break;\r
402 }\r
403\r
404 if (ReadStatus == OutOfDiffPoint) {\r
405 if (OneByteFromFile1 != OneByteFromFile2) {\r
406 ReadStatus = InDiffPoint;\r
407 DiffPointAddress = TempAddress;\r
408 if (DataSizeFromFile1 == 1) {\r
409 DataFromFile1[InsertPosition1++] = OneByteFromFile1;\r
410 }\r
411\r
412 if (DataSizeFromFile2 == 1) {\r
413 DataFromFile2[InsertPosition2++] = OneByteFromFile2;\r
414 }\r
415 }\r
416 } else if (ReadStatus == InDiffPoint) {\r
417 if (DataSizeFromFile1 == 1) {\r
418 DataFromFile1[InsertPosition1++] = OneByteFromFile1;\r
419 }\r
420\r
421 if (DataSizeFromFile2 == 1) {\r
422 DataFromFile2[InsertPosition2++] = OneByteFromFile2;\r
423 }\r
424 } else if (ReadStatus == InPrevDiffPoint) {\r
425 if (OneByteFromFile1 == OneByteFromFile2) {\r
426 ReadStatus = OutOfDiffPoint;\r
427 }\r
428 }\r
429\r
430 //\r
431 // ReadStatus should be always equal InDiffPoint.\r
432 //\r
433 if ((InsertPosition1 == DifferentBytes) ||\r
434 (InsertPosition2 == DifferentBytes) ||\r
435 ((DataSizeFromFile1 == 0) && (DataSizeFromFile2 == 0))\r
436 )\r
437 {\r
438 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_DIFFERENCE_POINT), gShellDebug1HiiHandle, ++DiffPointNumber);\r
439 PrintDifferentPoint (FileName1, L"File1", DataFromFile1, InsertPosition1, DiffPointAddress, DifferentBytes);\r
440 PrintDifferentPoint (FileName2, L"File2", DataFromFile2, InsertPosition2, DiffPointAddress, DifferentBytes);\r
441\r
442 //\r
443 // One of two buffuers is empty, it means this is the last different point.\r
444 //\r
445 if ((InsertPosition1 == 0) || (InsertPosition2 == 0)) {\r
446 break;\r
447 }\r
448\r
449 for (Index = 1; Index < InsertPosition1 && Index < InsertPosition2; Index++) {\r
450 if (DataFromFile1[Index] == DataFromFile2[Index]) {\r
451 ReadStatus = OutOfDiffPoint;\r
452 break;\r
453 }\r
454 }\r
455\r
456 if (ReadStatus == OutOfDiffPoint) {\r
457 //\r
458 // Try to find a new different point in the rest of DataFromFile.\r
459 //\r
460 for ( ; Index < MAX (InsertPosition1, InsertPosition2); Index++) {\r
461 if (DataFromFile1[Index] != DataFromFile2[Index]) {\r
462 ReadStatus = InDiffPoint;\r
463 DiffPointAddress += Index;\r
464 break;\r
465 }\r
466 }\r
467 } else {\r
468 //\r
469 // Doesn't find a new different point, still in the same different point.\r
470 //\r
471 ReadStatus = InPrevDiffPoint;\r
472 }\r
473\r
474 CopyMem (DataFromFile1, DataFromFile1 + Index, InsertPosition1 - Index);\r
475 CopyMem (DataFromFile2, DataFromFile2 + Index, InsertPosition2 - Index);\r
476\r
477 SetMem (DataFromFile1 + InsertPosition1 - Index, (UINTN)DifferentBytes - InsertPosition1 + Index, 0);\r
478 SetMem (DataFromFile2 + InsertPosition2 - Index, (UINTN)DifferentBytes - InsertPosition2 + Index, 0);\r
479\r
480 InsertPosition1 -= Index;\r
481 InsertPosition2 -= Index;\r
482 }\r
483 }\r
484\r
485 SHELL_FREE_NON_NULL (DataFromFile1);\r
486 SHELL_FREE_NON_NULL (DataFromFile2);\r
487 FileBufferUninit (&FileBuffer1);\r
488 FileBufferUninit (&FileBuffer2);\r
489\r
490 if (DiffPointNumber == 0) {\r
491 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS), gShellDebug1HiiHandle);\r
492 } else {\r
493 ShellStatus = SHELL_NOT_EQUAL;\r
494 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_FAIL), gShellDebug1HiiHandle);\r
495 }\r
496 }\r
497 }\r
498\r
499 ShellCommandLineFreeVarList (Package);\r
500 }\r
501\r
502 SHELL_FREE_NON_NULL (FileName1);\r
503 SHELL_FREE_NON_NULL (FileName2);\r
504\r
505 if (FileHandle1 != NULL) {\r
506 gEfiShellProtocol->CloseFile (FileHandle1);\r
507 }\r
508\r
509 if (FileHandle2 != NULL) {\r
510 gEfiShellProtocol->CloseFile (FileHandle2);\r
511 }\r
512\r
513 return (ShellStatus);\r
514}\r