/** @file | |
Reading/writing MBR/DBR. | |
NOTE: | |
If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written. | |
If we process DBR, we will patch MBR to set first partition active if no active partition exists. | |
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "CommonLib.h" | |
#include <errno.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <Common/UefiBaseTypes.h> | |
#include "ParseInf.h" | |
#include "EfiUtilityMsgs.h" | |
// | |
// Utility Name | |
// | |
#define UTILITY_NAME "GnuGenBootSector" | |
// | |
// Utility version information | |
// | |
#define UTILITY_MAJOR_VERSION 0 | |
#define UTILITY_MINOR_VERSION 1 | |
#define MAX_DRIVE 26 | |
#define PARTITION_TABLE_OFFSET 0x1BE | |
#define SIZE_OF_PARTITION_ENTRY 0x10 | |
#define PARTITION_ENTRY_STARTLBA_OFFSET 8 | |
#define PARTITION_ENTRY_NUM 4 | |
#define DRIVE_UNKNOWN 0 | |
#define DRIVE_NO_ROOT_DIR 1 | |
#define DRIVE_REMOVABLE 2 | |
#define DRIVE_FIXED 3 | |
#define DRIVE_REMOTE 4 | |
#define DRIVE_CDROM 5 | |
#define DRIVE_RAMDISK 6 | |
typedef struct _DRIVE_TYPE_DESC { | |
UINTN Type; | |
CHAR8 *Description; | |
} DRIVE_TYPE_DESC; | |
#define DRIVE_TYPE_ITEM(x) {x, #x} | |
DRIVE_TYPE_DESC DriveTypeDesc[] = { | |
DRIVE_TYPE_ITEM (DRIVE_UNKNOWN), | |
DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR), | |
DRIVE_TYPE_ITEM (DRIVE_REMOVABLE), | |
DRIVE_TYPE_ITEM (DRIVE_FIXED), | |
DRIVE_TYPE_ITEM (DRIVE_REMOTE), | |
DRIVE_TYPE_ITEM (DRIVE_CDROM), | |
DRIVE_TYPE_ITEM (DRIVE_RAMDISK), | |
{(UINTN) -1, NULL} | |
}; | |
typedef struct _DRIVE_INFO { | |
CHAR8 VolumeLetter; | |
DRIVE_TYPE_DESC *DriveType; | |
UINTN DiskNumber; | |
} DRIVE_INFO; | |
typedef enum { | |
PathUnknown, | |
PathFile, | |
PathFloppy, | |
PathUsb, | |
PathIde | |
} PATH_TYPE; | |
typedef struct _PATH_INFO { | |
CHAR8 *Path; | |
CHAR8 PhysicalPath[260]; | |
PATH_TYPE Type; | |
BOOLEAN Input; | |
} PATH_INFO; | |
typedef enum { | |
ErrorSuccess, | |
ErrorFileCreate, | |
ErrorFileReadWrite, | |
ErrorNoMbr, | |
ErrorFatType, | |
ErrorPath, | |
} ERROR_STATUS; | |
CHAR8 *ErrorStatusDesc[] = { | |
"Success", | |
"Failed to create files", | |
"Failed to read/write files", | |
"No MBR exists", | |
"Failed to detect Fat type", | |
"Inavlid path" | |
}; | |
//UnSupported Windows API functions. | |
UINTN GetLogicalDrives(void) { return 1; } | |
/** | |
Get path information, including physical path for Linux platform. | |
@param PathInfo Point to PATH_INFO structure. | |
@return whether path is valid. | |
**/ | |
ERROR_STATUS | |
GetPathInfo ( | |
PATH_INFO *PathInfo | |
) | |
{ | |
FILE *f; | |
if (strncmp(PathInfo->Path, "/dev/", 5) == 0) { | |
// | |
// Process disk path here. | |
// | |
// Process floppy disk | |
if (PathInfo->Path[5] == 'f' && PathInfo->Path[6] == 'd' && PathInfo->Path[8] == '\0') { | |
PathInfo->Type = PathFloppy; | |
strcpy (PathInfo->PhysicalPath, PathInfo->Path); | |
return ErrorSuccess; | |
} else { | |
// Other disk types is not supported yet. | |
fprintf (stderr, "ERROR: It's not a floppy disk!\n"); | |
return ErrorPath; | |
} | |
// Try to open the device. | |
f = fopen (LongFilePath (PathInfo->Path),"r"); | |
if (f == NULL) { | |
printf ("error :open device failed!\n"); | |
return ErrorPath; | |
} | |
fclose (f); | |
return ErrorSuccess; | |
} | |
// Process file path here. | |
PathInfo->Type = PathFile; | |
if (PathInfo->Input) { | |
// If path is file path, check whether file is valid. | |
printf("Path = %s\n",PathInfo->Path); | |
f = fopen (LongFilePath (PathInfo->Path), "r"); | |
if (f == NULL) { | |
fprintf (stderr, "Test error E2003: File was not provided!\n"); | |
return ErrorPath; | |
} | |
fclose (f); | |
} | |
strcpy(PathInfo->PhysicalPath, PathInfo->Path); | |
return ErrorSuccess; | |
} | |
VOID | |
ListDrive ( | |
VOID | |
) | |
{ | |
printf("-l or -list not supported!\n"); | |
} | |
/** | |
Writing or reading boot sector or MBR according to the argument. | |
@param InputInfo PATH_INFO instance for input path | |
@param OutputInfo PATH_INFO instance for output path | |
@param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector | |
@return ERROR_STATUS | |
**/ | |
ERROR_STATUS | |
ProcessBsOrMbr ( | |
PATH_INFO *InputInfo, | |
PATH_INFO *OutputInfo, | |
BOOLEAN ProcessMbr | |
) | |
{ | |
CHAR8 FirstSector[0x200] = {0}; | |
CHAR8 FirstSectorBackup[0x200] = {0}; | |
FILE *InputFile; | |
FILE *OutputFile; | |
InputFile = fopen (LongFilePath (InputInfo->PhysicalPath), "r"); | |
if (InputFile == NULL) { | |
return ErrorFileReadWrite; | |
} | |
if (0x200 != fread(FirstSector, 1, 0x200, InputFile)) { | |
fclose(InputFile); | |
return ErrorFileReadWrite; | |
} | |
fclose(InputFile); | |
//Not support USB and IDE. | |
if (InputInfo->Type == PathUsb) { | |
printf("USB has not been supported yet!"); | |
return ErrorSuccess; | |
} | |
if (InputInfo->Type == PathIde) { | |
printf("IDE has not been supported yet!"); | |
return ErrorSuccess; | |
} | |
//Process Floppy Disk | |
OutputFile = fopen (LongFilePath (OutputInfo->PhysicalPath), "r+"); | |
if (OutputFile == NULL) { | |
OutputFile = fopen (LongFilePath (OutputInfo->PhysicalPath), "w"); | |
if (OutputFile == NULL) { | |
return ErrorFileReadWrite; | |
} | |
} | |
if (OutputInfo->Type != PathFile) { | |
if (ProcessMbr) { | |
// | |
// Use original partition table | |
// | |
if (0x200 != fread (FirstSectorBackup, 1, 0x200, OutputFile)) { | |
fclose(OutputFile); | |
return ErrorFileReadWrite; | |
} | |
memcpy (FirstSector + 0x1BE, FirstSectorBackup + 0x1BE, 0x40); | |
} | |
} | |
if(0x200 != fwrite(FirstSector, 1, 0x200, OutputFile)) { | |
fclose(OutputFile); | |
return ErrorFileReadWrite; | |
} | |
fclose(OutputFile); | |
return ErrorSuccess; | |
} | |
/** | |
Displays the standard utility information to SDTOUT | |
**/ | |
VOID | |
Version ( | |
VOID | |
) | |
{ | |
printf ("%s v%d.%d %s-Utility to retrieve and update the boot sector or MBR.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); | |
printf ("Copyright (c) 2007-2014 Intel Corporation. All rights reserved.\n"); | |
} | |
VOID | |
PrintUsage ( | |
VOID | |
) | |
{ | |
Version(); | |
printf ("\nUsage: \n\ | |
GenBootSector\n\ | |
[-l, --list list disks]\n\ | |
[-i, --input Filename]\n\ | |
[-o, --output Filename]\n\ | |
[-m, --mbr process the MBR also]\n\ | |
[-v, --verbose]\n\ | |
[--version]\n\ | |
[-q, --quiet disable all messages except fatal errors]\n\ | |
[-d, --debug[#]\n\ | |
[-h, --help]\n"); | |
} | |
int | |
main ( | |
int argc, | |
char *argv[] | |
) | |
{ | |
INTN Index; | |
BOOLEAN ProcessMbr; | |
ERROR_STATUS Status; | |
EFI_STATUS EfiStatus; | |
PATH_INFO InputPathInfo; | |
PATH_INFO OutputPathInfo; | |
UINT64 LogLevel; | |
SetUtilityName (UTILITY_NAME); | |
ZeroMem(&InputPathInfo, sizeof(PATH_INFO)); | |
ZeroMem(&OutputPathInfo, sizeof(PATH_INFO)); | |
argv ++; | |
argc --; | |
ProcessMbr = FALSE; | |
if (argc == 0) { | |
PrintUsage(); | |
return 0; | |
} | |
// | |
// Parse command line | |
// | |
for (Index = 0; Index < argc; Index ++) { | |
if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) { | |
ListDrive (); | |
return 0; | |
} | |
if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) { | |
ProcessMbr = TRUE; | |
continue; | |
} | |
if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) { | |
InputPathInfo.Path = argv[Index + 1]; | |
InputPathInfo.Input = TRUE; | |
if (InputPathInfo.Path == NULL) { | |
Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL"); | |
return 1; | |
} | |
if (InputPathInfo.Path[0] == '-') { | |
Error (NULL, 0, 1003, "Invalid option value", "Input file is missing"); | |
return 1; | |
} | |
++Index; | |
continue; | |
} | |
if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) { | |
OutputPathInfo.Path = argv[Index + 1]; | |
OutputPathInfo.Input = FALSE; | |
if (OutputPathInfo.Path == NULL) { | |
Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL"); | |
return 1; | |
} | |
if (OutputPathInfo.Path[0] == '-') { | |
Error (NULL, 0, 1003, "Invalid option value", "Output file is missing"); | |
return 1; | |
} | |
++Index; | |
continue; | |
} | |
if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) { | |
PrintUsage (); | |
return 0; | |
} | |
if (stricmp (argv[Index], "--version") == 0) { | |
Version (); | |
return 0; | |
} | |
if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) { | |
continue; | |
} | |
if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) { | |
continue; | |
} | |
if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) { | |
EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel); | |
if (EFI_ERROR (EfiStatus)) { | |
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]); | |
return 1; | |
} | |
if (LogLevel > 9) { | |
Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel); | |
return 1; | |
} | |
SetPrintLevel (LogLevel); | |
DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]); | |
++Index; | |
continue; | |
} | |
// | |
// Don't recognize the parameter. | |
// | |
Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]); | |
return 1; | |
} | |
if (InputPathInfo.Path == NULL) { | |
Error (NULL, 0, 1001, "Missing options", "Input file is missing"); | |
return 1; | |
} | |
if (OutputPathInfo.Path == NULL) { | |
Error (NULL, 0, 1001, "Missing options", "Output file is missing"); | |
return 1; | |
} | |
if (GetPathInfo(&InputPathInfo) != ErrorSuccess) { | |
Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found."); | |
return 1; | |
} | |
if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) { | |
Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found."); | |
return 1; | |
} | |
// | |
// Process DBR (Patch or Read) | |
// | |
Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr); | |
if (Status == ErrorSuccess) { | |
fprintf ( | |
stdout, | |
"%s %s: successful!\n", | |
(OutputPathInfo.Type != PathFile) ? "Write" : "Read", | |
ProcessMbr ? "MBR" : "DBR" | |
); | |
return 0; | |
} else { | |
fprintf ( | |
stderr, | |
"%s: %s %s: failed - %s (LastError: 0x%x)!\n", | |
(Status == ErrorNoMbr) ? "WARNING" : "ERROR", | |
(OutputPathInfo.Type != PathFile) ? "Write" : "Read", | |
ProcessMbr ? "MBR" : "DBR", | |
ErrorStatusDesc[Status], | |
errno | |
); | |
return 1; | |
} | |
} |