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