mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-02 20:44:39 +01:00 
			
		
		
		
	Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yingke Liu <yingke.d.liu@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15971 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			456 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			456 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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;
 | 
						|
  }
 | 
						|
}
 |