VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c

Last change on this file was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 17.8 KB
Line 
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
12STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
13 { L"-n", TypeValue },
14 { L"-s", TypeValue },
15 { NULL, TypeMax }
16};
17
18typedef enum {
19 OutOfDiffPoint,
20 InDiffPoint,
21 InPrevDiffPoint
22} READ_STATUS;
23
24//
25// Buffer type, for reading both file operands in chunks.
26//
27typedef 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**/
45VOID
46PrintDifferentPoint (
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**/
97STATIC
98VOID
99FileBufferInit (
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**/
116STATIC
117VOID
118FileBufferUninit (
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**/
154STATIC
155EFI_STATUS
156FileBufferReadByte (
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**/
200SHELL_STATUS
201EFIAPI
202ShellCommandRunComp (
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 if (TempParam == NULL) {
284 ASSERT (TempParam != NULL);
285 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"comp", TempParam);
286 ShellStatus = SHELL_INVALID_PARAMETER;
287 goto Exit;
288 }
289
290 FileName1 = ShellFindFilePath (TempParam);
291 if (FileName1 == NULL) {
292 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
293 ShellStatus = SHELL_NOT_FOUND;
294 } else {
295 Status = ShellOpenFileByName (FileName1, &FileHandle1, EFI_FILE_MODE_READ, 0);
296 if (EFI_ERROR (Status)) {
297 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
298 ShellStatus = SHELL_NOT_FOUND;
299 }
300 }
301
302 TempParam = ShellCommandLineGetRawValue (Package, 2);
303 if (TempParam == NULL) {
304 ASSERT (TempParam != NULL);
305 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"comp", TempParam);
306 ShellStatus = SHELL_INVALID_PARAMETER;
307 goto Exit;
308 }
309
310 FileName2 = ShellFindFilePath (TempParam);
311 if (FileName2 == NULL) {
312 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
313 ShellStatus = SHELL_NOT_FOUND;
314 } else {
315 Status = ShellOpenFileByName (FileName2, &FileHandle2, EFI_FILE_MODE_READ, 0);
316 if (EFI_ERROR (Status)) {
317 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
318 ShellStatus = SHELL_NOT_FOUND;
319 }
320 }
321
322 if (ShellStatus == SHELL_SUCCESS) {
323 Status = gEfiShellProtocol->GetFileSize (FileHandle1, &Size1);
324 ASSERT_EFI_ERROR (Status);
325 Status = gEfiShellProtocol->GetFileSize (FileHandle2, &Size2);
326 ASSERT_EFI_ERROR (Status);
327
328 if (ShellCommandLineGetFlag (Package, L"-n")) {
329 TempParam = ShellCommandLineGetValue (Package, L"-n");
330 if (TempParam == NULL) {
331 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-n");
332 ShellStatus = SHELL_INVALID_PARAMETER;
333 } else {
334 if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)TempParam, L"all") == 0) {
335 DifferentCount = MAX_UINTN;
336 } else {
337 Status = ShellConvertStringToUint64 (TempParam, &DifferentCount, FALSE, TRUE);
338 if (EFI_ERROR (Status) || (DifferentCount == 0)) {
339 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-n");
340 ShellStatus = SHELL_INVALID_PARAMETER;
341 }
342 }
343 }
344 }
345
346 if (ShellCommandLineGetFlag (Package, L"-s")) {
347 TempParam = ShellCommandLineGetValue (Package, L"-s");
348 if (TempParam == NULL) {
349 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-s");
350 ShellStatus = SHELL_INVALID_PARAMETER;
351 } else {
352 Status = ShellConvertStringToUint64 (TempParam, &DifferentBytes, FALSE, TRUE);
353 if (EFI_ERROR (Status) || (DifferentBytes == 0)) {
354 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-s");
355 ShellStatus = SHELL_INVALID_PARAMETER;
356 } else {
357 if (DifferentBytes > MAX (Size1, Size2)) {
358 DifferentBytes = MAX (Size1, Size2);
359 }
360 }
361 }
362 }
363 }
364
365 if (ShellStatus == SHELL_SUCCESS) {
366 DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes);
367 DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes);
368 FileBufferInit (&FileBuffer1);
369 FileBufferInit (&FileBuffer2);
370 if ((DataFromFile1 == NULL) || (DataFromFile2 == NULL) ||
371 (FileBuffer1.Data == NULL) || (FileBuffer2.Data == NULL))
372 {
373 ShellStatus = SHELL_OUT_OF_RESOURCES;
374 SHELL_FREE_NON_NULL (DataFromFile1);
375 SHELL_FREE_NON_NULL (DataFromFile2);
376 FileBufferUninit (&FileBuffer1);
377 FileBufferUninit (&FileBuffer2);
378 }
379 }
380
381 if (ShellStatus == SHELL_SUCCESS) {
382 while ((UINT64)DiffPointNumber < DifferentCount) {
383 DataSizeFromFile1 = 1;
384 DataSizeFromFile2 = 1;
385 OneByteFromFile1 = 0;
386 OneByteFromFile2 = 0;
387 Status = FileBufferReadByte (
388 FileHandle1,
389 &FileBuffer1,
390 &DataSizeFromFile1,
391 &OneByteFromFile1
392 );
393 ASSERT_EFI_ERROR (Status);
394 Status = FileBufferReadByte (
395 FileHandle2,
396 &FileBuffer2,
397 &DataSizeFromFile2,
398 &OneByteFromFile2
399 );
400 ASSERT_EFI_ERROR (Status);
401
402 TempAddress++;
403
404 //
405 // 1.When end of file and no chars in DataFromFile buffer, then break while.
406 // 2.If no more char in File1 or File2, The ReadStatus is InPrevDiffPoint forever.
407 // So the previous different point is the last one, then break the while block.
408 //
409 if (((DataSizeFromFile1 == 0) && (InsertPosition1 == 0) && (DataSizeFromFile2 == 0) && (InsertPosition2 == 0)) ||
410 ((ReadStatus == InPrevDiffPoint) && ((DataSizeFromFile1 == 0) || (DataSizeFromFile2 == 0)))
411 )
412 {
413 break;
414 }
415
416 if (ReadStatus == OutOfDiffPoint) {
417 if (OneByteFromFile1 != OneByteFromFile2) {
418 ReadStatus = InDiffPoint;
419 DiffPointAddress = TempAddress;
420 if (DataSizeFromFile1 == 1) {
421 DataFromFile1[InsertPosition1++] = OneByteFromFile1;
422 }
423
424 if (DataSizeFromFile2 == 1) {
425 DataFromFile2[InsertPosition2++] = OneByteFromFile2;
426 }
427 }
428 } else if (ReadStatus == InDiffPoint) {
429 if (DataSizeFromFile1 == 1) {
430 DataFromFile1[InsertPosition1++] = OneByteFromFile1;
431 }
432
433 if (DataSizeFromFile2 == 1) {
434 DataFromFile2[InsertPosition2++] = OneByteFromFile2;
435 }
436 } else if (ReadStatus == InPrevDiffPoint) {
437 if (OneByteFromFile1 == OneByteFromFile2) {
438 ReadStatus = OutOfDiffPoint;
439 }
440 }
441
442 //
443 // ReadStatus should be always equal InDiffPoint.
444 //
445 if ((InsertPosition1 == DifferentBytes) ||
446 (InsertPosition2 == DifferentBytes) ||
447 ((DataSizeFromFile1 == 0) && (DataSizeFromFile2 == 0))
448 )
449 {
450 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_DIFFERENCE_POINT), gShellDebug1HiiHandle, ++DiffPointNumber);
451 PrintDifferentPoint (FileName1, L"File1", DataFromFile1, InsertPosition1, DiffPointAddress, DifferentBytes);
452 PrintDifferentPoint (FileName2, L"File2", DataFromFile2, InsertPosition2, DiffPointAddress, DifferentBytes);
453
454 //
455 // One of two buffuers is empty, it means this is the last different point.
456 //
457 if ((InsertPosition1 == 0) || (InsertPosition2 == 0)) {
458 break;
459 }
460
461 for (Index = 1; Index < InsertPosition1 && Index < InsertPosition2; Index++) {
462 if (DataFromFile1[Index] == DataFromFile2[Index]) {
463 ReadStatus = OutOfDiffPoint;
464 break;
465 }
466 }
467
468 if (ReadStatus == OutOfDiffPoint) {
469 //
470 // Try to find a new different point in the rest of DataFromFile.
471 //
472 for ( ; Index < MAX (InsertPosition1, InsertPosition2); Index++) {
473 if (DataFromFile1[Index] != DataFromFile2[Index]) {
474 ReadStatus = InDiffPoint;
475 DiffPointAddress += Index;
476 break;
477 }
478 }
479 } else {
480 //
481 // Doesn't find a new different point, still in the same different point.
482 //
483 ReadStatus = InPrevDiffPoint;
484 }
485
486 CopyMem (DataFromFile1, DataFromFile1 + Index, InsertPosition1 - Index);
487 CopyMem (DataFromFile2, DataFromFile2 + Index, InsertPosition2 - Index);
488
489 SetMem (DataFromFile1 + InsertPosition1 - Index, (UINTN)DifferentBytes - InsertPosition1 + Index, 0);
490 SetMem (DataFromFile2 + InsertPosition2 - Index, (UINTN)DifferentBytes - InsertPosition2 + Index, 0);
491
492 InsertPosition1 -= Index;
493 InsertPosition2 -= Index;
494 }
495 }
496
497 SHELL_FREE_NON_NULL (DataFromFile1);
498 SHELL_FREE_NON_NULL (DataFromFile2);
499 FileBufferUninit (&FileBuffer1);
500 FileBufferUninit (&FileBuffer2);
501
502 if (DiffPointNumber == 0) {
503 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS), gShellDebug1HiiHandle);
504 } else {
505 ShellStatus = SHELL_NOT_EQUAL;
506 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_FAIL), gShellDebug1HiiHandle);
507 }
508 }
509 }
510
511 ShellCommandLineFreeVarList (Package);
512 }
513
514Exit:
515 SHELL_FREE_NON_NULL (FileName1);
516 SHELL_FREE_NON_NULL (FileName2);
517
518 if (FileHandle1 != NULL) {
519 gEfiShellProtocol->CloseFile (FileHandle1);
520 }
521
522 if (FileHandle2 != NULL) {
523 gEfiShellProtocol->CloseFile (FileHandle2);
524 }
525
526 return (ShellStatus);
527}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette