]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenBootSector/GenBootSector.c
License header updated to match correct format.
[mirror_edk2.git] / BaseTools / Source / C / GenBootSector / GenBootSector.c
1 /** @file
2 Reading/writing MBR/DBR.
3 NOTE:
4 If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written.
5 If we process DBR, we will patch MBR to set first partition active if no active partition exists.
6
7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include <windows.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <Common/UefiBaseTypes.h>
22
23 #include "ParseInf.h"
24 #include "EfiUtilityMsgs.h"
25 #include "CommonLib.h"
26
27 //
28 // Utility Name
29 //
30 #define UTILITY_NAME "GenBootSector"
31
32 //
33 // Utility version information
34 //
35 #define UTILITY_MAJOR_VERSION 0
36 #define UTILITY_MINOR_VERSION 2
37
38 #define MAX_DRIVE 26
39 #define PARTITION_TABLE_OFFSET 0x1BE
40
41 #define SIZE_OF_PARTITION_ENTRY 0x10
42
43 #define PARTITION_ENTRY_STARTLBA_OFFSET 8
44
45 #define PARTITION_ENTRY_NUM 4
46
47 INT
48 GetDrvNumOffset (
49 IN VOID *BootSector
50 );
51
52 typedef enum {
53 PatchTypeUnknown,
54 PatchTypeFloppy,
55 PatchTypeIde,
56 PatchTypeUsb,
57 PatchTypeFileImage // input and output are all file image, patching action is same as PatchTypeFloppy
58 } PATCH_TYPE;
59
60 typedef enum {
61 PathUnknown,
62 PathFile,
63 PathFloppy,
64 PathUsb,
65 PathIde
66 } PATH_TYPE;
67
68 typedef enum {
69 ErrorSuccess,
70 ErrorFileCreate,
71 ErrorFileReadWrite,
72 ErrorNoMbr,
73 ErrorFatType,
74 ErrorPath,
75 } ERROR_STATUS;
76
77 CHAR *ErrorStatusDesc[] = {
78 "Success",
79 "Failed to create files",
80 "Failed to read/write files",
81 "No MBR exists",
82 "Failed to detect Fat type",
83 "Inavlid path"
84 };
85
86 typedef struct _DRIVE_TYPE_DESC {
87 UINT Type;
88 CHAR *Description;
89 } DRIVE_TYPE_DESC;
90
91 #define DRIVE_TYPE_ITEM(x) {x, #x}
92 DRIVE_TYPE_DESC DriveTypeDesc[] = {
93 DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),
94 DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),
95 DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),
96 DRIVE_TYPE_ITEM (DRIVE_FIXED),
97 DRIVE_TYPE_ITEM (DRIVE_REMOTE),
98 DRIVE_TYPE_ITEM (DRIVE_CDROM),
99 DRIVE_TYPE_ITEM (DRIVE_RAMDISK),
100 (UINT) -1, NULL
101 };
102
103 typedef struct _DRIVE_INFO {
104 CHAR VolumeLetter;
105 DRIVE_TYPE_DESC *DriveType;
106 UINT DiskNumber;
107 } DRIVE_INFO;
108
109 typedef struct _PATH_INFO {
110 CHAR *Path;
111 CHAR PhysicalPath[260];
112 PATH_TYPE Type;
113 BOOL Input;
114 } PATH_INFO;
115
116 #define BOOT_SECTOR_LBA_OFFSET 0x1FA
117
118 #define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
119
120 BOOL
121 GetDriveInfo (
122 CHAR VolumeLetter,
123 DRIVE_INFO *DriveInfo
124 )
125 /*++
126 Routine Description:
127 Get drive information including disk number and drive type,
128 where disknumber is useful for reading/writing disk raw data.
129 NOTE: Floppy disk doesn't have disk number but it doesn't matter because
130 we can reading/writing floppy disk without disk number.
131
132 Arguments:
133 VolumeLetter : volume letter, e.g.: C for C:, A for A:
134 DriveInfo : pointer to DRIVE_INFO structure receiving drive information.
135
136 Return:
137 TRUE : successful
138 FALSE : failed
139 --*/
140 {
141 HANDLE VolumeHandle;
142 STORAGE_DEVICE_NUMBER StorageDeviceNumber;
143 DWORD BytesReturned;
144 BOOL Success;
145 UINT DriveType;
146 UINT Index;
147
148 CHAR RootPath[] = "X:\\"; // "X:\" -> for GetDriveType
149 CHAR VolumeAccessPath[] = "\\\\.\\X:"; // "\\.\X:" -> to open the volume
150
151 RootPath[0] = VolumeAccessPath[4] = VolumeLetter;
152 DriveType = GetDriveType(RootPath);
153 if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) {
154 return FALSE;
155 }
156
157 DriveInfo->VolumeLetter = VolumeLetter;
158 VolumeHandle = CreateFile (
159 VolumeAccessPath,
160 0,
161 FILE_SHARE_READ | FILE_SHARE_WRITE,
162 NULL,
163 OPEN_EXISTING,
164 0,
165 NULL
166 );
167 if (VolumeHandle == INVALID_HANDLE_VALUE) {
168 fprintf (
169 stderr,
170 "error E0005: CreateFile failed: Volume = %s, LastError = 0x%x\n",
171 VolumeAccessPath,
172 GetLastError ()
173 );
174 return FALSE;
175 }
176
177 //
178 // Get Disk Number. It should fail when operating on floppy. That's ok
179 // because Disk Number is only needed when operating on Hard or USB disk.
180 //
181 // To direct write to disk:
182 // for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number
183 // for floppy: use path = \\.\X:, where X can be A or B
184 //
185 Success = DeviceIoControl(
186 VolumeHandle,
187 IOCTL_STORAGE_GET_DEVICE_NUMBER,
188 NULL,
189 0,
190 &StorageDeviceNumber,
191 sizeof(StorageDeviceNumber),
192 &BytesReturned,
193 NULL
194 );
195 //
196 // DeviceIoControl should fail if Volume is floppy or network drive.
197 //
198 if (!Success) {
199 DriveInfo->DiskNumber = (UINT) -1;
200 } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) {
201 //
202 // Only care about the disk.
203 //
204 return FALSE;
205 } else{
206 DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber;
207 }
208 CloseHandle(VolumeHandle);
209
210 //
211 // Fill in the type string
212 //
213 DriveInfo->DriveType = NULL;
214 for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) {
215 if (DriveType == DriveTypeDesc[Index].Type) {
216 DriveInfo->DriveType = &DriveTypeDesc[Index];
217 break;
218 }
219 }
220
221 if (DriveInfo->DriveType == NULL) {
222 //
223 // Should have a type.
224 //
225 fprintf (stderr, "error E3005: Fatal Error!!!\n");
226 return FALSE;
227 }
228 return TRUE;
229 }
230
231 VOID
232 ListDrive (
233 VOID
234 )
235 /*++
236 Routine Description:
237 List every drive in current system and their information.
238
239 --*/
240 {
241 UINT Index;
242 DRIVE_INFO DriveInfo;
243
244 UINT Mask = GetLogicalDrives();
245
246 for (Index = 0; Index < MAX_DRIVE; Index++) {
247 if (((Mask >> Index) & 0x1) == 1) {
248 if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) {
249 if (Index < 2) {
250 // Floppy will occupy 'A' and 'B'
251 fprintf (
252 stdout,
253 "%c: - Type: %s\n",
254 DriveInfo.VolumeLetter,
255 DriveInfo.DriveType->Description
256 );
257 } else {
258 fprintf (
259 stdout,
260 "%c: - DiskNum: %u, Type: %s\n",
261 DriveInfo.VolumeLetter,
262 (unsigned) DriveInfo.DiskNumber,
263 DriveInfo.DriveType->Description
264 );
265 }
266 }
267 }
268 }
269
270 }
271
272 INT
273 GetBootSectorOffset (
274 HANDLE DiskHandle,
275 PATH_INFO *PathInfo
276 )
277 /*++
278 Description:
279 Get the offset of boot sector.
280 For non-MBR disk, offset is just 0
281 for disk with MBR, offset needs to be caculated by parsing MBR
282
283 NOTE: if no one is active, we will patch MBR to select first partition as active.
284
285 Arguments:
286 DiskHandle : HANDLE of disk
287 PathInfo : PATH_INFO structure.
288 WriteToDisk : TRUE indicates writing
289
290 Return:
291 -1 : failed
292 o.w. : Offset to boot sector
293 --*/
294 {
295 BYTE DiskPartition[0x200];
296 DWORD BytesReturn;
297 DWORD DbrOffset;
298 DWORD Index;
299 BOOL HasMbr;
300
301 DbrOffset = 0;
302 HasMbr = FALSE;
303
304 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
305 if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
306 return -1;
307 }
308
309 //
310 // Check Signature, Jmp, and Boot Indicator.
311 // if all pass, we assume MBR found.
312 //
313
314 // Check Signature: 55AA
315 if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) {
316 // Check Jmp: (EB ?? 90) or (E9 ?? ??)
317 if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) &&
318 (DiskPartition[0] != 0xE9)) {
319 // Check Boot Indicator: 0x00 or 0x80
320 // Boot Indicator is the first byte of Partition Entry
321 HasMbr = TRUE;
322 for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) {
323 if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) {
324 HasMbr = FALSE;
325 break;
326 }
327 }
328 }
329 }
330
331 if (HasMbr) {
332 //
333 // Skip MBR
334 //
335 for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) {
336 //
337 // Found Boot Indicator.
338 //
339 if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) {
340 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET];
341 break;
342 }
343 }
344 //
345 // If no boot indicator, we manually select 1st partition, and patch MBR.
346 //
347 if (Index == PARTITION_ENTRY_NUM) {
348 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET];
349 if (!PathInfo->Input && (PathInfo->Type == PathUsb)) {
350 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
351 DiskPartition[PARTITION_TABLE_OFFSET] = 0x80;
352 WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL);
353 }
354 }
355 }
356
357 return DbrOffset;
358 }
359
360 /**
361 * Get window file handle for input/ouput disk/file.
362 *
363 * @param PathInfo
364 * @param ProcessMbr
365 * @param FileHandle
366 *
367 * @return ERROR_STATUS
368 */
369 ERROR_STATUS
370 GetFileHandle (
371 PATH_INFO *PathInfo,
372 BOOL ProcessMbr,
373 HANDLE *FileHandle,
374 DWORD *DbrOffset
375 )
376 {
377 DWORD OpenFlag;
378
379 OpenFlag = OPEN_ALWAYS;
380 if (PathInfo->Input || PathInfo->Type != PathFile) {
381 OpenFlag = OPEN_EXISTING;
382 }
383
384 *FileHandle = CreateFile(
385 PathInfo->PhysicalPath,
386 GENERIC_READ | GENERIC_WRITE,
387 FILE_SHARE_READ,
388 NULL,
389 OpenFlag,
390 FILE_ATTRIBUTE_NORMAL,
391 NULL
392 );
393 if (*FileHandle == INVALID_HANDLE_VALUE) {
394 return ErrorFileCreate;
395 }
396
397 if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){
398 *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo);
399 if (!ProcessMbr) {
400 //
401 // 1. Process boot sector, set file pointer to the beginning of boot sector
402 //
403 SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN);
404 } else if(*DbrOffset == 0) {
405 //
406 // If user want to process Mbr, but no Mbr exists, simply return FALSE
407 //
408 return ErrorNoMbr;
409 } else {
410 //
411 // 2. Process MBR, set file pointer to 0
412 //
413 SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN);
414 }
415 }
416
417 return ErrorSuccess;
418 }
419
420 /**
421 Writing or reading boot sector or MBR according to the argument.
422
423 @param InputInfo PATH_INFO instance for input path
424 @param OutputInfo PATH_INFO instance for output path
425 @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector
426
427 @return ERROR_STATUS
428 **/
429 ERROR_STATUS
430 ProcessBsOrMbr (
431 PATH_INFO *InputInfo,
432 PATH_INFO *OutputInfo,
433 BOOL ProcessMbr
434 )
435 {
436 BYTE DiskPartition[0x200] = {0};
437 BYTE DiskPartitionBackup[0x200] = {0};
438 DWORD BytesReturn;
439 INT DrvNumOffset;
440 HANDLE InputHandle;
441 HANDLE OutputHandle;
442 ERROR_STATUS Status;
443 DWORD InputDbrOffset;
444 DWORD OutputDbrOffset;
445
446 //
447 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
448 //
449 Status = GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset);
450 if (Status != ErrorSuccess) {
451 return Status;
452 }
453
454 //
455 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
456 //
457 Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset);
458 if (Status != ErrorSuccess) {
459 return Status;
460 }
461
462 //
463 // Read boot sector from source disk/file
464 //
465 if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
466 return ErrorFileReadWrite;
467 }
468
469 if (InputInfo->Type == PathUsb) {
470 // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR.
471 // offset of BS_DrvNum is 0x24 for FAT12/16
472 // 0x40 for FAT32
473 //
474 DrvNumOffset = GetDrvNumOffset (DiskPartition);
475 if (DrvNumOffset == -1) {
476 return ErrorFatType;
477 }
478 //
479 // Some legacy BIOS require 0x80 discarding MBR.
480 // Question left here: is it needed to check Mbr before set 0x80?
481 //
482 DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0);
483 }
484
485 if (InputInfo->Type == PathIde) {
486 //
487 // Patch LBAOffsetForBootSector
488 //
489 *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset;
490 }
491
492 if (OutputInfo->Type != PathFile) {
493 if (ProcessMbr) {
494 //
495 // Use original partition table
496 //
497 if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) {
498 return ErrorFileReadWrite;
499 }
500 memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40);
501 SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN);
502
503 }
504 }
505
506 //
507 // Write boot sector to taget disk/file
508 //
509 if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
510 return ErrorFileReadWrite;
511 }
512
513 CloseHandle (InputHandle);
514 CloseHandle (OutputHandle);
515
516 return ErrorSuccess;
517 }
518
519 void
520 Version (
521 void
522 )
523 /*++
524
525 Routine Description:
526
527 Displays the standard utility information to SDTOUT
528
529 Arguments:
530
531 None
532
533 Returns:
534
535 None
536
537 --*/
538 {
539 printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
540 }
541
542 VOID
543 PrintUsage (
544 void
545 )
546 {
547 printf ("Usage: GenBootSector [options] --cfg-file CFG_FILE\n\n\
548 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.\n\n\
549 Utility to retrieve and update the boot sector or MBR.\n\n\
550 optional arguments:\n\
551 -h, --help Show this help message and exit\n\
552 --version Show program's version number and exit\n\
553 -d [DEBUG], --debug [DEBUG]\n\
554 Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
555 - 9 (max)\n\
556 -v, --verbose Print informational statements\n\
557 -q, --quiet Returns the exit code, error messages will be\n\
558 displayed\n\
559 -s, --silent Returns only the exit code; informational and error\n\
560 messages are not displayed\n\
561 -l, --list List disk drives\n\
562 -i INPUT_FILENAME, --input INPUT_FILENAME\n\
563 Input file name\n\
564 -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
565 Output file name\n\
566 -m, --mbr Also process the MBR\n\
567 --sfo Reserved for future use\n");
568
569 }
570
571 /**
572 Get path information, including physical path for windows platform.
573
574 @param PathInfo Point to PATH_INFO structure.
575
576 @return whether path is valid.
577 **/
578 ERROR_STATUS
579 GetPathInfo (
580 PATH_INFO *PathInfo
581 )
582 {
583 DRIVE_INFO DriveInfo;
584 CHAR VolumeLetter;
585 CHAR DiskPathTemplate[] = "\\\\.\\PHYSICALDRIVE%u";
586 CHAR FloppyPathTemplate[] = "\\\\.\\%c:";
587 FILE *f;
588
589 //
590 // If path is disk path
591 //
592 if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) {
593 VolumeLetter = PathInfo->Path[0];
594 if ((VolumeLetter == 'A') || (VolumeLetter == 'a') ||
595 (VolumeLetter == 'B') || (VolumeLetter == 'b')) {
596 PathInfo->Type = PathFloppy;
597 sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter);
598 return ErrorSuccess;
599 }
600
601 if (!GetDriveInfo(VolumeLetter, &DriveInfo)) {
602 fprintf (stderr, "ERROR: GetDriveInfo - 0x%x\n", GetLastError ());
603 return ErrorPath;
604 }
605
606 if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) {
607 fprintf (stderr, "ERROR: Could patch own IDE disk!\n");
608 return ErrorPath;
609 }
610
611 sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber);
612 if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) {
613 PathInfo->Type = PathUsb;
614 } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) {
615 PathInfo->Type = PathIde;
616 } else {
617 fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path);
618 return ErrorPath;
619 }
620
621 return ErrorSuccess;
622 }
623
624 PathInfo->Type = PathFile;
625 if (PathInfo->Input) {
626 //
627 // If path is file path, check whether file is valid.
628 //
629 f = fopen (LongFilePath (PathInfo->Path), "r");
630 if (f == NULL) {
631 fprintf (stderr, "error E2003: File was not provided!\n");
632 return ErrorPath;
633 }
634 }
635 PathInfo->Type = PathFile;
636 strcpy(PathInfo->PhysicalPath, PathInfo->Path);
637
638 return ErrorSuccess;
639 }
640
641 INT
642 main (
643 INT argc,
644 CHAR *argv[]
645 )
646 {
647 CHAR8 *AppName;
648 INTN Index;
649 BOOLEAN ProcessMbr;
650 ERROR_STATUS Status;
651 EFI_STATUS EfiStatus;
652 PATH_INFO InputPathInfo = {0};
653 PATH_INFO OutputPathInfo = {0};
654 UINT64 LogLevel;
655
656 SetUtilityName (UTILITY_NAME);
657
658 AppName = *argv;
659 argv ++;
660 argc --;
661
662 ProcessMbr = FALSE;
663
664 if (argc == 0) {
665 PrintUsage();
666 return 0;
667 }
668
669 //
670 // Parse command line
671 //
672 for (Index = 0; Index < argc; Index ++) {
673 if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {
674 ListDrive ();
675 return 0;
676 }
677
678 if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {
679 ProcessMbr = TRUE;
680 continue;
681 }
682
683 if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {
684 InputPathInfo.Path = argv[Index + 1];
685 InputPathInfo.Input = TRUE;
686 if (InputPathInfo.Path == NULL) {
687 Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");
688 return 1;
689 }
690 if (InputPathInfo.Path[0] == '-') {
691 Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");
692 return 1;
693 }
694 ++Index;
695 continue;
696 }
697
698 if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {
699 OutputPathInfo.Path = argv[Index + 1];
700 OutputPathInfo.Input = FALSE;
701 if (OutputPathInfo.Path == NULL) {
702 Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");
703 return 1;
704 }
705 if (OutputPathInfo.Path[0] == '-') {
706 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");
707 return 1;
708 }
709 ++Index;
710 continue;
711 }
712
713 if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {
714 PrintUsage ();
715 return 0;
716 }
717
718 if (stricmp (argv[Index], "--version") == 0) {
719 Version ();
720 return 0;
721 }
722
723 if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {
724 continue;
725 }
726
727 if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {
728 continue;
729 }
730
731 if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {
732 EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);
733 if (EFI_ERROR (EfiStatus)) {
734 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);
735 return 1;
736 }
737 if (LogLevel > 9) {
738 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);
739 return 1;
740 }
741 SetPrintLevel (LogLevel);
742 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);
743 ++Index;
744 continue;
745 }
746
747 //
748 // Don't recognize the parameter.
749 //
750 Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);
751 return 1;
752 }
753
754 if (InputPathInfo.Path == NULL) {
755 Error (NULL, 0, 1001, "Missing options", "Input file is missing");
756 return 1;
757 }
758
759 if (OutputPathInfo.Path == NULL) {
760 Error (NULL, 0, 1001, "Missing options", "Output file is missing");
761 return 1;
762 }
763
764 if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {
765 Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");
766 return 1;
767 }
768
769 if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {
770 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");
771 return 1;
772 }
773
774 //
775 // Process DBR (Patch or Read)
776 //
777 Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);
778
779 if (Status == ErrorSuccess) {
780 fprintf (
781 stdout,
782 "%s %s: successful!\n",
783 (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
784 ProcessMbr ? "MBR" : "DBR"
785 );
786 return 0;
787 } else {
788 fprintf (
789 stderr,
790 "%s: %s %s: failed - %s (LastError: 0x%x)!\n",
791 (Status == ErrorNoMbr) ? "WARNING" : "ERROR",
792 (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
793 ProcessMbr ? "MBR" : "DBR",
794 ErrorStatusDesc[Status],
795 GetLastError ()
796 );
797 return 1;
798 }
799 }