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