summaryrefslogtreecommitdiff
path: root/BaseTools/Source/C/GenBootSector
diff options
context:
space:
mode:
authorlgao4 <lgao4@6f19259b-4bc3-4df7-8a09-765794883524>2009-07-17 09:10:31 +0000
committerlgao4 <lgao4@6f19259b-4bc3-4df7-8a09-765794883524>2009-07-17 09:10:31 +0000
commit30fdf1140b8d1ce93f3821d986fa165552023440 (patch)
treec45c336a8955b1d03ea56d6c915a0e68a43b4ee9 /BaseTools/Source/C/GenBootSector
parent577e30cdb473e4af8e65fd6f75236691d0c8dfb3 (diff)
downloadedk2-platforms-30fdf1140b8d1ce93f3821d986fa165552023440.tar.xz
Check In tool source code based on Build tool project revision r1655.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8964 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'BaseTools/Source/C/GenBootSector')
-rw-r--r--BaseTools/Source/C/GenBootSector/FatFormat.h152
-rw-r--r--BaseTools/Source/C/GenBootSector/GenBootSector.c795
-rw-r--r--BaseTools/Source/C/GenBootSector/GetDrvNumOffset.c73
-rw-r--r--BaseTools/Source/C/GenBootSector/Makefile10
4 files changed, 1030 insertions, 0 deletions
diff --git a/BaseTools/Source/C/GenBootSector/FatFormat.h b/BaseTools/Source/C/GenBootSector/FatFormat.h
new file mode 100644
index 0000000000..f24b4ee9ac
--- /dev/null
+++ b/BaseTools/Source/C/GenBootSector/FatFormat.h
@@ -0,0 +1,152 @@
+/** @file
+
+ Fat file system structure and definition.
+
+Copyright 2006 - 2008, Intel Corporation
+All rights reserved. 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.
+
+--*/
+
+#ifndef _FAT_BPB_H_
+#define _FAT_BPB_H_
+
+#include "CommonLib.h"
+
+#pragma pack(1)
+
+typedef struct {
+ //
+ // Fat common field
+ //
+ UINT8 BS_jmpBoot[3];
+ CHAR8 BS_OEMName[8];
+ UINT16 BPB_BytsPerSec;
+ UINT8 BPB_SecPerClus;
+ UINT16 BPB_RsvdSecCnt;
+ UINT8 BPB_NumFATs;
+ UINT16 BPB_RootEntCnt;
+ UINT16 BPB_TotSec16;
+ UINT8 BPB_Media;
+ UINT16 BPB_FATSz16;
+ UINT16 BPB_SecPerTrk;
+ UINT16 BPB_NumHeads;
+ UINT32 BPB_HiddSec;
+ UINT32 BPB_TotSec32;
+
+ //
+ // Fat12/16 specific field
+ //
+ UINT8 BS_DrvNum;
+ UINT8 BS_Reserved1;
+ UINT8 BS_BootSig;
+ UINT32 BS_VolID;
+ CHAR8 BS_VolLab[11];
+ CHAR8 BS_FilSysType[8];
+
+ //
+ // Boot Code and Data
+ //
+ UINT8 Reserved[448];
+
+ //
+ // Fat common signature - 0xAA55
+ //
+ UINT16 Signature;
+} FAT12_16_BPB_STRUCT;
+
+typedef struct {
+ //
+ // Fat common field
+ //
+ UINT8 BS_jmpBoot[3];
+ CHAR8 BS_OEMName[8];
+ UINT16 BPB_BytsPerSec;
+ UINT8 BPB_SecPerClus;
+ UINT16 BPB_RsvdSecCnt;
+ UINT8 BPB_NumFATs;
+ UINT16 BPB_RootEntCnt;
+ UINT16 BPB_TotSec16;
+ UINT8 BPB_Media;
+ UINT16 BPB_FATSz16;
+ UINT16 BPB_SecPerTrk;
+ UINT16 BPB_NumHeads;
+ UINT32 BPB_HiddSec;
+ UINT32 BPB_TotSec32;
+
+ //
+ // Fat32 specific field
+ //
+ UINT32 BPB_FATSz32;
+ UINT16 BPB_ExtFlags;
+ UINT16 BPB_FSVer;
+ UINT32 BPB_RootClus;
+ UINT16 BPB_FSInfo;
+ UINT16 BPB_BkBootSec;
+ UINT8 BPB_Reserved[12];
+ UINT8 BS_DrvNum;
+ UINT8 BS_Reserved1;
+ UINT8 BS_BootSig;
+ UINT32 BS_VolID;
+ CHAR8 BS_VolLab[11];
+ CHAR8 BS_FilSysType[8];
+
+ //
+ // Boot Code and Data
+ //
+ UINT8 Reserved[420];
+
+ //
+ // Fat common signature - 0xAA55
+ //
+ UINT16 Signature;
+} FAT32_BPB_STRUCT;
+
+typedef union {
+ FAT12_16_BPB_STRUCT Fat12_16;
+ FAT32_BPB_STRUCT Fat32;
+} FAT_BPB_STRUCT;
+
+typedef enum {
+ FatTypeUnknown,
+ FatTypeFat12,
+ FatTypeFat16,
+ FatTypeFat32,
+ FatTypeMax
+} FAT_TYPE;
+
+typedef struct {
+ CHAR8 DIR_Name[11];
+ UINT8 DIR_Attr;
+ UINT8 DIR_NTRes;
+ UINT8 DIR_CrtTimeTenth;
+ UINT16 DIR_CrtTime;
+ UINT16 DIR_CrtDate;
+ UINT16 DIR_LstAccDate;
+ UINT16 DIR_FstClusHI;
+ UINT16 DIR_WrtTime;
+ UINT16 DIR_WrtDate;
+ UINT16 DIR_FstClusLO;
+ UINT32 DIR_FileSize;
+} FAT_DIRECTORY_ENTRY;
+
+#pragma pack()
+
+#define FAT_MAX_FAT12_CLUSTER 0xFF5
+#define FAT_MAX_FAT16_CLUSTER 0xFFF5
+
+#define FAT_BS_SIGNATURE 0xAA55
+#define FAT_BS_BOOTSIG 0x29
+#define FAT_BS_JMP1 0xEB
+#define FAT_BS_JMP2 0xE9
+#define FAT_FILSYSTYPE "FAT "
+#define FAT12_FILSYSTYPE "FAT12 "
+#define FAT16_FILSYSTYPE "FAT16 "
+#define FAT32_FILSYSTYPE "FAT32 "
+
+#endif
diff --git a/BaseTools/Source/C/GenBootSector/GenBootSector.c b/BaseTools/Source/C/GenBootSector/GenBootSector.c
new file mode 100644
index 0000000000..47b5c5c67a
--- /dev/null
+++ b/BaseTools/Source/C/GenBootSector/GenBootSector.c
@@ -0,0 +1,795 @@
+/** @file
+
+Copyright 2006 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ genbootsector.c
+
+Abstract:
+ 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.
+
+**/
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <Common/UefiBaseTypes.h>
+
+//
+// Utility Name
+//
+#define UTILITY_NAME "GenBootSector"
+
+//
+// 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
+
+INT
+GetDrvNumOffset (
+ IN VOID *BootSector
+ );
+
+typedef enum {
+ PatchTypeUnknown,
+ PatchTypeFloppy,
+ PatchTypeIde,
+ PatchTypeUsb,
+ PatchTypeFileImage // input and output are all file image, patching action is same as PatchTypeFloppy
+} PATCH_TYPE;
+
+typedef enum {
+ PathUnknown,
+ PathFile,
+ PathFloppy,
+ PathUsb,
+ PathIde
+} PATH_TYPE;
+
+typedef enum {
+ ErrorSuccess,
+ ErrorFileCreate,
+ ErrorFileReadWrite,
+ ErrorNoMbr,
+ ErrorFatType,
+ ErrorPath,
+} ERROR_STATUS;
+
+CHAR *ErrorStatusDesc[] = {
+ "Success",
+ "Failed to create files",
+ "Failed to read/write files",
+ "No MBR exists",
+ "Failed to detect Fat type",
+ "Inavlid path"
+};
+
+typedef struct _DRIVE_TYPE_DESC {
+ UINT Type;
+ CHAR *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),
+ (UINT) -1, NULL
+};
+
+typedef struct _DRIVE_INFO {
+ CHAR VolumeLetter;
+ DRIVE_TYPE_DESC *DriveType;
+ UINT DiskNumber;
+} DRIVE_INFO;
+
+typedef struct _PATH_INFO {
+ CHAR *Path;
+ CHAR PhysicalPath[260];
+ PATH_TYPE Type;
+ BOOL Input;
+} PATH_INFO;
+
+#define BOOT_SECTOR_LBA_OFFSET 0x1FA
+
+#define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
+
+BOOL
+GetDriveInfo (
+ CHAR VolumeLetter,
+ DRIVE_INFO *DriveInfo
+ )
+/*++
+Routine Description:
+ Get drive information including disk number and drive type,
+ where disknumber is useful for reading/writing disk raw data.
+ NOTE: Floppy disk doesn't have disk number but it doesn't matter because
+ we can reading/writing floppy disk without disk number.
+
+Arguments:
+ VolumeLetter : volume letter, e.g.: C for C:, A for A:
+ DriveInfo : pointer to DRIVE_INFO structure receiving drive information.
+
+Return:
+ TRUE : successful
+ FALSE : failed
+--*/
+{
+ HANDLE VolumeHandle;
+ STORAGE_DEVICE_NUMBER StorageDeviceNumber;
+ DWORD BytesReturned;
+ BOOL Success;
+ UINT DriveType;
+ UINT Index;
+
+ CHAR RootPath[] = "X:\\"; // "X:\" -> for GetDriveType
+ CHAR VolumeAccessPath[] = "\\\\.\\X:"; // "\\.\X:" -> to open the volume
+
+ RootPath[0] = VolumeAccessPath[4] = VolumeLetter;
+ DriveType = GetDriveType(RootPath);
+ if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) {
+ return FALSE;
+ }
+
+ DriveInfo->VolumeLetter = VolumeLetter;
+ VolumeHandle = CreateFile (
+ VolumeAccessPath,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ if (VolumeHandle == INVALID_HANDLE_VALUE) {
+ fprintf (
+ stderr,
+ "error E0005: CreateFile failed: Volume = %s, LastError = 0x%x\n",
+ VolumeAccessPath,
+ GetLastError ()
+ );
+ return FALSE;
+ }
+
+ //
+ // Get Disk Number. It should fail when operating on floppy. That's ok
+ // because Disk Number is only needed when operating on Hard or USB disk.
+ //
+ // To direct write to disk:
+ // for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number
+ // for floppy: use path = \\.\X:, where X can be A or B
+ //
+ Success = DeviceIoControl(
+ VolumeHandle,
+ IOCTL_STORAGE_GET_DEVICE_NUMBER,
+ NULL,
+ 0,
+ &StorageDeviceNumber,
+ sizeof(StorageDeviceNumber),
+ &BytesReturned,
+ NULL
+ );
+ //
+ // DeviceIoControl should fail if Volume is floppy or network drive.
+ //
+ if (!Success) {
+ DriveInfo->DiskNumber = (UINT) -1;
+ } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) {
+ //
+ // Only care about the disk.
+ //
+ return FALSE;
+ } else{
+ DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber;
+ }
+ CloseHandle(VolumeHandle);
+
+ //
+ // Fill in the type string
+ //
+ DriveInfo->DriveType = NULL;
+ for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) {
+ if (DriveType == DriveTypeDesc[Index].Type) {
+ DriveInfo->DriveType = &DriveTypeDesc[Index];
+ break;
+ }
+ }
+
+ if (DriveInfo->DriveType == NULL) {
+ //
+ // Should have a type.
+ //
+ fprintf (stderr, "error E3005: Fatal Error!!!\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+VOID
+ListDrive (
+ VOID
+ )
+/*++
+Routine Description:
+ List every drive in current system and their information.
+
+--*/
+{
+ UINT Index;
+ DRIVE_INFO DriveInfo;
+
+ UINT Mask = GetLogicalDrives();
+
+ for (Index = 0; Index < MAX_DRIVE; Index++) {
+ if (((Mask >> Index) & 0x1) == 1) {
+ if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) {
+ if (Index < 2) {
+ // Floppy will occupy 'A' and 'B'
+ fprintf (
+ stdout,
+ "%c: - Type: %s\n",
+ DriveInfo.VolumeLetter,
+ DriveInfo.DriveType->Description
+ );
+ } else {
+ fprintf (
+ stdout,
+ "%c: - DiskNum: %d, Type: %s\n",
+ DriveInfo.VolumeLetter,
+ DriveInfo.DiskNumber,
+ DriveInfo.DriveType->Description
+ );
+ }
+ }
+ }
+ }
+
+}
+
+INT
+GetBootSectorOffset (
+ HANDLE DiskHandle,
+ PATH_INFO *PathInfo
+ )
+/*++
+Description:
+ Get the offset of boot sector.
+ For non-MBR disk, offset is just 0
+ for disk with MBR, offset needs to be caculated by parsing MBR
+
+ NOTE: if no one is active, we will patch MBR to select first partition as active.
+
+Arguments:
+ DiskHandle : HANDLE of disk
+ PathInfo : PATH_INFO structure.
+ WriteToDisk : TRUE indicates writing
+
+Return:
+ -1 : failed
+ o.w. : Offset to boot sector
+--*/
+{
+ BYTE DiskPartition[0x200];
+ DWORD BytesReturn;
+ DWORD DbrOffset;
+ DWORD Index;
+ BOOL HasMbr;
+
+ DbrOffset = 0;
+ HasMbr = FALSE;
+
+ SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
+ if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
+ return -1;
+ }
+
+ //
+ // Check Signature, Jmp, and Boot Indicator.
+ // if all pass, we assume MBR found.
+ //
+
+ // Check Signature: 55AA
+ if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) {
+ // Check Jmp: (EB ?? 90) or (E9 ?? ??)
+ if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) &&
+ (DiskPartition[0] != 0xE9)) {
+ // Check Boot Indicator: 0x00 or 0x80
+ // Boot Indicator is the first byte of Partition Entry
+ HasMbr = TRUE;
+ for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) {
+ if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) {
+ HasMbr = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (HasMbr) {
+ //
+ // Skip MBR
+ //
+ for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) {
+ //
+ // Found Boot Indicator.
+ //
+ if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) {
+ DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET];
+ break;
+ }
+ }
+ //
+ // If no boot indicator, we manually select 1st partition, and patch MBR.
+ //
+ if (Index == PARTITION_ENTRY_NUM) {
+ DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET];
+ if (!PathInfo->Input && (PathInfo->Type == PathUsb)) {
+ SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
+ DiskPartition[PARTITION_TABLE_OFFSET] = 0x80;
+ WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL);
+ }
+ }
+ }
+
+ return DbrOffset;
+}
+
+/**
+ * Get window file handle for input/ouput disk/file.
+ *
+ * @param PathInfo
+ * @param ProcessMbr
+ * @param FileHandle
+ *
+ * @return ERROR_STATUS
+ */
+ERROR_STATUS
+GetFileHandle (
+ PATH_INFO *PathInfo,
+ BOOL ProcessMbr,
+ HANDLE *FileHandle,
+ DWORD *DbrOffset
+ )
+{
+ DWORD OpenFlag;
+
+ OpenFlag = OPEN_ALWAYS;
+ if (PathInfo->Input || PathInfo->Type != PathFile) {
+ OpenFlag = OPEN_EXISTING;
+ }
+
+ *FileHandle = CreateFile(
+ PathInfo->PhysicalPath,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OpenFlag,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+ if (*FileHandle == INVALID_HANDLE_VALUE) {
+ return ErrorFileCreate;
+ }
+
+ if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){
+ *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo);
+ if (!ProcessMbr) {
+ //
+ // 1. Process boot sector, set file pointer to the beginning of boot sector
+ //
+ SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN);
+ } else if(*DbrOffset == 0) {
+ //
+ // If user want to process Mbr, but no Mbr exists, simply return FALSE
+ //
+ return ErrorNoMbr;
+ } else {
+ //
+ // 2. Process MBR, set file pointer to 0
+ //
+ SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN);
+ }
+ }
+
+ return ErrorSuccess;
+}
+
+/**
+ 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,
+ BOOL ProcessMbr
+ )
+{
+ BYTE DiskPartition[0x200] = {0};
+ BYTE DiskPartitionBackup[0x200] = {0};
+ DWORD BytesReturn;
+ DWORD DbrOffset;
+ INT DrvNumOffset;
+ HANDLE InputHandle;
+ HANDLE OutputHandle;
+ BOOL WriteToDisk;
+ ERROR_STATUS Status;
+ DWORD InputDbrOffset;
+ DWORD OutputDbrOffset;
+
+ //
+ // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
+ //
+ Status = GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset);
+ if (Status != ErrorSuccess) {
+ return Status;
+ }
+
+ //
+ // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
+ //
+ Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset);
+ if (Status != ErrorSuccess) {
+ return Status;
+ }
+
+ //
+ // Read boot sector from source disk/file
+ //
+ if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
+ return ErrorFileReadWrite;
+ }
+
+ if (InputInfo->Type == PathUsb) {
+ // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR.
+ // offset of BS_DrvNum is 0x24 for FAT12/16
+ // 0x40 for FAT32
+ //
+ DrvNumOffset = GetDrvNumOffset (DiskPartition);
+ if (DrvNumOffset == -1) {
+ return ErrorFatType;
+ }
+ //
+ // Some legacy BIOS require 0x80 discarding MBR.
+ // Question left here: is it needed to check Mbr before set 0x80?
+ //
+ DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0);
+ }
+
+ if (InputInfo->Type == PathIde) {
+ //
+ // Patch LBAOffsetForBootSector
+ //
+ *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset;
+ }
+
+ if (OutputInfo->Type != PathFile) {
+ if (ProcessMbr) {
+ //
+ // Use original partition table
+ //
+ if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) {
+ return ErrorFileReadWrite;
+ }
+ memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40);
+ SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN);
+
+ }
+ }
+
+ //
+ // Write boot sector to taget disk/file
+ //
+ if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
+ return ErrorFileReadWrite;
+ }
+
+ CloseHandle (InputHandle);
+ CloseHandle (OutputHandle);
+
+ return ErrorSuccess;
+}
+
+void
+Version (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Displays the standard utility information to SDTOUT
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ printf ("%s v%d.%d -Utility to retrieve and update the boot sector or MBR.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
+ printf ("Copyright (c) 2009 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");
+
+}
+
+/**
+ Get path information, including physical path for windows platform.
+
+ @param PathInfo Point to PATH_INFO structure.
+
+ @return whether path is valid.
+**/
+ERROR_STATUS
+GetPathInfo (
+ PATH_INFO *PathInfo
+ )
+{
+ DRIVE_INFO DriveInfo;
+ CHAR VolumeLetter;
+ CHAR DiskPathTemplate[] = "\\\\.\\PHYSICALDRIVE%u";
+ CHAR FloppyPathTemplate[] = "\\\\.\\%c:";
+ FILE *f;
+
+ //
+ // If path is disk path
+ //
+ if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) {
+ VolumeLetter = PathInfo->Path[0];
+ if ((VolumeLetter == 'A') || (VolumeLetter == 'a') ||
+ (VolumeLetter == 'B') || (VolumeLetter == 'b')) {
+ PathInfo->Type = PathFloppy;
+ sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter);
+ return ErrorSuccess;
+ }
+
+ if (!GetDriveInfo(VolumeLetter, &DriveInfo)) {
+ fprintf (stderr, "ERROR: GetDriveInfo - 0x%x\n", GetLastError ());
+ return ErrorPath;
+ }
+
+ if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) {
+ fprintf (stderr, "ERROR: Could patch own IDE disk!\n");
+ return ErrorPath;
+ }
+
+ sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber);
+ if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) {
+ PathInfo->Type = PathUsb;
+ } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) {
+ PathInfo->Type = PathIde;
+ } else {
+ fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path);
+ return ErrorPath;
+ }
+
+ return ErrorSuccess;
+ }
+
+ PathInfo->Type = PathFile;
+ if (PathInfo->Input) {
+ //
+ // If path is file path, check whether file is valid.
+ //
+ f = fopen (PathInfo->Path, "r");
+ if (f == NULL) {
+ fprintf (stderr, "error E2003: File was not provided!\n");
+ return ErrorPath;
+ }
+ }
+ PathInfo->Type = PathFile;
+ strcpy(PathInfo->PhysicalPath, PathInfo->Path);
+
+ return ErrorSuccess;
+}
+
+INT
+main (
+ INT argc,
+ CHAR *argv[]
+ )
+{
+ CHAR8 *AppName;
+ INTN Index;
+ BOOLEAN ProcessMbr;
+ ERROR_STATUS Status;
+ EFI_STATUS EfiStatus;
+ PATH_INFO InputPathInfo = {0};
+ PATH_INFO OutputPathInfo = {0};
+ UINT64 LogLevel;
+
+ SetUtilityName (UTILITY_NAME);
+
+ AppName = *argv;
+ 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", 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],
+ GetLastError ()
+ );
+ return 1;
+ }
+}
diff --git a/BaseTools/Source/C/GenBootSector/GetDrvNumOffset.c b/BaseTools/Source/C/GenBootSector/GetDrvNumOffset.c
new file mode 100644
index 0000000000..a55137b557
--- /dev/null
+++ b/BaseTools/Source/C/GenBootSector/GetDrvNumOffset.c
@@ -0,0 +1,73 @@
+/** @file
+
+ Get Drv Num offset from Fat file system.
+
+Copyright 2006 - 2008, Intel Corporation
+All rights reserved. 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 <stdio.h>
+#include "FatFormat.h"
+
+INTN
+GetDrvNumOffset (
+ IN VOID *BootSector
+ )
+{
+ FAT_BPB_STRUCT *FatBpb;
+ UINTN RootDirSectors;
+ UINTN FATSz;
+ UINTN TotSec;
+ UINTN DataSec;
+ UINTN CountOfClusters;
+
+ FatBpb = (FAT_BPB_STRUCT *) BootSector;
+
+ //
+ // Check FAT type algorithm from FAT spec
+ //
+ RootDirSectors = ((FatBpb->Fat12_16.BPB_RootEntCnt * sizeof(FAT_DIRECTORY_ENTRY)) +
+ (FatBpb->Fat12_16.BPB_BytsPerSec - 1)) / FatBpb->Fat12_16.BPB_BytsPerSec;
+
+ if (FatBpb->Fat12_16.BPB_FATSz16 != 0) {
+ FATSz = FatBpb->Fat12_16.BPB_FATSz16;
+ } else {
+ FATSz = FatBpb->Fat32.BPB_FATSz32;
+ }
+ if (FATSz == 0) {
+ fprintf (stderr, "error E3003: FAT - BPB_FATSz16, BPB_FATSz32 - 0, expected: Non-Zero number\n");
+ return -1;
+ }
+
+ if (FatBpb->Fat12_16.BPB_TotSec16 != 0) {
+ TotSec = FatBpb->Fat12_16.BPB_TotSec16;
+ } else {
+ TotSec = FatBpb->Fat12_16.BPB_TotSec32;
+ }
+ if (TotSec == 0) {
+ fprintf (stderr, "error E3003: FAT - BPB_TotSec16, BPB_TotSec32 - 0, expected: Non-Zero number\n");
+ return -1;
+ }
+
+ DataSec = TotSec - (
+ FatBpb->Fat12_16.BPB_RsvdSecCnt +
+ FatBpb->Fat12_16.BPB_NumFATs * FATSz +
+ RootDirSectors
+ );
+
+ CountOfClusters = DataSec / FatBpb->Fat12_16.BPB_SecPerClus;
+
+ if (CountOfClusters < FAT_MAX_FAT16_CLUSTER) {
+ return (INTN) ((UINTN) &FatBpb->Fat12_16.BS_DrvNum - (UINTN) FatBpb);
+ } else {
+ return (INTN) ((UINTN) &FatBpb->Fat32.BS_DrvNum - (UINTN) FatBpb);
+ }
+}
+
diff --git a/BaseTools/Source/C/GenBootSector/Makefile b/BaseTools/Source/C/GenBootSector/Makefile
new file mode 100644
index 0000000000..90fc2fe4ad
--- /dev/null
+++ b/BaseTools/Source/C/GenBootSector/Makefile
@@ -0,0 +1,10 @@
+!INCLUDE ..\Makefiles\ms.common
+
+APPNAME = GenBootSector
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = GenBootSector.obj GetDrvNumOffset.obj
+
+!INCLUDE ..\Makefiles\ms.app
+