From d81f83c110de05223041df4e570b29dae992afff Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 20 Dec 2014 00:22:00 +0000 Subject: [PATCH] [core] enable UEFI NTFS support * This allows no-sweat UEFI support of Windows installation ISOs that contain a >4GB file for instance * This is done through UEFI:TOGO (https://github.com/pbatard/uefi-togo) and the efifs NTFS driver (http://efi.akeo.ie) * Closes #414 * This will also be part of our implementation of #126 --- res/grub2/readme.txt | 1 - res/uefi/readme.txt | 12 +++++ res/uefi/uefi-togo.img | Bin 0 -> 131072 bytes src/drive.c | 100 ++++++++++++++++++++++++++++++++--------- src/drive.h | 2 +- src/format.c | 5 ++- src/resource.h | 1 + src/rufus.c | 3 +- src/rufus.h | 2 + src/rufus.rc | 18 ++++---- src/stdfn.c | 5 +++ 11 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 res/uefi/readme.txt create mode 100644 res/uefi/uefi-togo.img diff --git a/res/grub2/readme.txt b/res/grub2/readme.txt index d62ee615..7fc23199 100644 --- a/res/grub2/readme.txt +++ b/res/grub2/readme.txt @@ -4,7 +4,6 @@ This directory contains the Grub 2.0 boot records that are used by Rufus commit 72ec399ad8d6348b6c74ea63d80c79784c8b84ae, on a Debian 7.7.0 x64 system. This was done following the guide from: http://pete.akeo.ie/2014/05/compiling-and-installing-grub2-for.html. - Note that exFAT was not included in core.img in order to keep it under 31.5 KB. * boot.img has been modified to nop the jump @ 0x66 as per grub2's setup.c comments: /* If DEST_DRIVE is a hard disk, enable the workaround, which is diff --git a/res/uefi/readme.txt b/res/uefi/readme.txt new file mode 100644 index 00000000..1af31021 --- /dev/null +++ b/res/uefi/readme.txt @@ -0,0 +1,12 @@ +This directory contains a flat image of the FAT UEFI:TOGO partition added by +Rufus for Windows To Go UEFI mode support as well as seamless installation of +Windows in UEFI, in the case where the original media contains a >4GB file. + +This image, which you can mount as FAT filesystem or open in 7-zip, contains +the following data: +o The NTFS UEFI driver from efifs (https://github.com/pbatard/efifs) which was + compiled, with compression disabled, using Visual Studio 2013 Community Edition. + This is the \EFI\Rufus\ntfs_x64.efi file. +o The UEFI:TOGO binary (https://github.com/pbatard/uefi-togo), which was compiled + using Visual Studio 2013 Community Edition. + This is the \EFI\Boot\bootx64.efi file. diff --git a/res/uefi/uefi-togo.img b/res/uefi/uefi-togo.img new file mode 100644 index 0000000000000000000000000000000000000000..4c427fdc2910ba1922873683b60cdbe3079ddd96 GIT binary patch literal 131072 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 literal 0 HcmV?d00001 diff --git a/src/drive.c b/src/drive.c index fcbf2cd6..852befe0 100644 --- a/src/drive.c +++ b/src/drive.c @@ -645,7 +645,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys { // MBR partition types that can be mounted in Windows const uint8_t mbr_mountable[] = { 0x01, 0x04, 0x06, 0x07, 0x0b, 0x0c, 0x0e, 0xef }; - BOOL r, hasRufusExtra = FALSE, ret = FALSE; + BOOL r, hasRufusExtra = FALSE, ret = FALSE, isUefiTogo; HANDLE hPhysical; DWORD size; BYTE geometry[256], layout[4096], part_type; @@ -695,6 +695,10 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys return 0; } +#if defined(__GNUC__) +// GCC 4.9 bug us about the fact that MS defined an expandable array as array[1] +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif switch (DriveLayout->PartitionStyle) { case PARTITION_STYLE_MBR: SelectedDrive.PartitionType = PARTITION_STYLE_MBR; @@ -709,8 +713,10 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys AnalyzeMBR(hPhysical, "Drive"); for (i=0; iPartitionCount; i++) { if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { - suprintf("Partition %d:\n", i+1); part_type = DriveLayout->PartitionEntry[i].Mbr.PartitionType; + isUefiTogo = (i == 1) && (part_type == 0x01) && + (DriveLayout->PartitionEntry[i].PartitionLength.QuadPart == 131072); + suprintf("Partition %d%s:\n", i+1, isUefiTogo?" (UEFI:TOGO)":""); for (j=0; jPartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors, DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No", DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No"); - if (part_type == RUFUS_EXTRA_PARTITION_TYPE) // This is a partition Rufus created => we can safely ignore it + if ((part_type == RUFUS_EXTRA_PARTITION_TYPE) || (isUefiTogo)) + // This is a partition Rufus created => we can safely ignore it hasRufusExtra = TRUE; if (part_type == 0xee) // Flag a protective MBR for non GPT platforms (XP) SelectedDrive.has_protective_mbr = TRUE; @@ -746,6 +753,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId), SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE), DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / DiskGeometry->Geometry.BytesPerSector, DriveLayout->PartitionEntry[i].Gpt.Attributes); + if (safe_strcmp(tmp, "UEFI:TOGO") == 0) + hasRufusExtra = TRUE; if ( (memcmp(&PARTITION_BASIC_DATA_GUID, &DriveLayout->PartitionEntry[i].Gpt.PartitionType, sizeof(GUID)) == 0) && (nWindowsVersion >= WINDOWS_VISTA) ) ret = TRUE; @@ -756,6 +765,9 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys suprintf("Partition type: RAW\n"); break; } +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Warray-bounds" +#endif safe_closehandle(hPhysical); if (hasRufusExtra) @@ -889,14 +901,15 @@ typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 { * copy it got from the last IOCTL, and ignores your changes until you replug the drive * or issue an IOCTL_DISK_UPDATE_PROPERTIES. */ -BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker) +BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, BOOL add_uefi_togo) { const char* PartitionTypeName[2] = { "MBR", "GPT" }; + unsigned char* buffer; CREATE_DISK CreateDisk = {PARTITION_STYLE_RAW, {{0}}}; DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0}; BOOL r; - DWORD size; - LONGLONG size_in_sectors; + DWORD size, bufsize; + LONGLONG size_in_sectors, extra_size_in_tracks = 1; PrintStatus(0, TRUE, MSG_238, PartitionTypeName[partition_style]); @@ -908,8 +921,18 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart = SelectedDrive.Geometry.BytesPerSector * SelectedDrive.Geometry.SectorsPerTrack; } - // TODO: should we try to align the following to the cluster size as well? size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart) / SelectedDrive.Geometry.BytesPerSector; + // Align on track boundary if the extra part option is checked + if ((partition_style == PARTITION_STYLE_MBR) && ((IsChecked(IDC_EXTRA_PARTITION)) || (add_uefi_togo))) { + if (add_uefi_togo) // Already set to 1 track in non To_Go mode + extra_size_in_tracks = (MIN_EXTRA_PART_SIZE + SelectedDrive.Geometry.SectorsPerTrack - 1) / + SelectedDrive.Geometry.SectorsPerTrack; + uprintf("Reserving %d tracks for extra partition", extra_size_in_tracks); + size_in_sectors = ((size_in_sectors / SelectedDrive.Geometry.SectorsPerTrack) - extra_size_in_tracks) * + SelectedDrive.Geometry.SectorsPerTrack; + if (size_in_sectors <= 0) + return FALSE; + } switch (partition_style) { case PARTITION_STYLE_MBR: @@ -927,13 +950,6 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m // TODO: CHS fixup (32 sectors/track) through a cheat mode, if requested // NB: disk geometry is computed by BIOS & co. by finding a match between LBA and CHS value of first partition // ms-sys's write_partition_number_of_heads() and write_partition_start_sector_number() can be used if needed - - // Align on sector boundary if the extra part option is checked - if (IsChecked(IDC_EXTRA_PARTITION)) { - size_in_sectors = ((size_in_sectors / SelectedDrive.Geometry.SectorsPerTrack)-1) * SelectedDrive.Geometry.SectorsPerTrack; - if (size_in_sectors <= 0) - return FALSE; - } break; case PARTITION_STYLE_GPT: // TODO: (?) As per MSDN: "When specifying a GUID partition table (GPT) as the PARTITION_STYLE of the CREATE_DISK @@ -945,7 +961,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS; DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT; - DriveLayoutEx.PartitionCount = 1; + DriveLayoutEx.PartitionCount = (add_uefi_togo)?2:1; // At the very least, a GPT disk has 34 reserved sectors at the beginning and 33 at the end. DriveLayoutEx.Type.Gpt.StartingUsableOffset.QuadPart = 34 * SelectedDrive.Geometry.BytesPerSector; DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.Geometry.BytesPerSector; @@ -984,18 +1000,24 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m uprintf("Unsupported file system\n"); return FALSE; } - // Create an extra partition on request - can improve BIOS detection as HDD for older BIOSes - if (IsChecked(IDC_EXTRA_PARTITION)) { + // Create an extra partition on request + if (IsChecked(IDC_EXTRA_PARTITION) || (add_uefi_togo)) { DriveLayoutEx.PartitionEntry[1].PartitionStyle = PARTITION_STYLE_MBR; - // Should end on a sector boundary + // Should end on a track boundary DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart + DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPart; - DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = SelectedDrive.Geometry.SectorsPerTrack*SelectedDrive.Geometry.BytesPerSector; + if (add_uefi_togo) { + DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = + GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img"); + } else { + DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = extra_size_in_tracks * + SelectedDrive.Geometry.SectorsPerTrack * SelectedDrive.Geometry.BytesPerSector; + } DriveLayoutEx.PartitionEntry[1].PartitionNumber = 2; DriveLayoutEx.PartitionEntry[1].RewritePartition = TRUE; DriveLayoutEx.PartitionEntry[1].Mbr.BootIndicator = FALSE; DriveLayoutEx.PartitionEntry[1].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack*SelectedDrive.Geometry.BytesPerSector; - DriveLayoutEx.PartitionEntry[1].Mbr.PartitionType = RUFUS_EXTRA_PARTITION_TYPE; + DriveLayoutEx.PartitionEntry[1].Mbr.PartitionType = (add_uefi_togo)?0x01:RUFUS_EXTRA_PARTITION_TYPE; } // For the remaining partitions, PartitionStyle & PartitionType have already // been zeroed => already set to MBR/unused @@ -1003,12 +1025,48 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m case PARTITION_STYLE_GPT: DriveLayoutEx.PartitionEntry[0].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID; wcscpy(DriveLayoutEx.PartitionEntry[0].Gpt.Name, L"Microsoft Basic Data"); + if (add_uefi_togo) { + DriveLayoutEx.PartitionEntry[1].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID; + wcscpy(DriveLayoutEx.PartitionEntry[1].Gpt.Name, L"UEFI:TOGO"); + DriveLayoutEx.PartitionEntry[1].PartitionNumber = 2; + DriveLayoutEx.PartitionEntry[1].RewritePartition = TRUE; + DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart + + DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPart; + DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart = + GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img"); + } IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[0].Gpt.PartitionId)); + IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[1].Gpt.PartitionId)); break; default: break; } + // We need to write the extra partition before we refresh the disk + if (add_uefi_togo) { + uprintf("Writing UEFI:TOGO partition..."); + if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[1].StartingOffset, NULL, FILE_BEGIN)) { + uprintf("Unable to set position"); + safe_closehandle(hDrive); + return FALSE; + } + buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img", &bufsize, FALSE); + if (buffer == NULL) { + uprintf("Could not access uefi-togo.img"); + safe_closehandle(hDrive); + return FALSE; + } + r = WriteFile(hDrive, buffer, bufsize, &size, NULL); + if ((!r) || (size != bufsize)) { + if (!r) + uprintf("Write error: %s", WindowsErrorString()); + else + uprintf("Write error: Wrote %d bytes, expected %d bytes\n", size, bufsize); + safe_closehandle(hDrive); + return FALSE; + } + } + // If you don't call IOCTL_DISK_CREATE_DISK, the next call will fail size = sizeof(CreateDisk); r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, @@ -1019,7 +1077,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m return FALSE; } - size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT)?(3*sizeof(PARTITION_INFORMATION_EX)):0); + size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT)?((add_uefi_togo?2:3)*sizeof(PARTITION_INFORMATION_EX)):0); r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL ); if (!r) { diff --git a/src/drive.h b/src/drive.h index 890f8c72..619d2565 100644 --- a/src/drive.h +++ b/src/drive.h @@ -63,7 +63,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys BOOL UnmountVolume(HANDLE hDrive); BOOL MountVolume(char* drive_name, char *drive_guid); BOOL RemountVolume(char* drive_name); -BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker); +BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, BOOL add_uefi_togo); BOOL DeletePartitions(HANDLE hDrive); BOOL RefreshDriveLayout(HANDLE hDrive); const char* GetPartitionType(BYTE Type); diff --git a/src/format.c b/src/format.c index 7cf1cff2..5fd55621 100644 --- a/src/format.c +++ b/src/format.c @@ -1271,7 +1271,7 @@ DWORD WINAPI CloseFormatPromptThread(LPVOID param) { DWORD WINAPI FormatThread(void* param) { int i, r, pt, bt, fs, dt; - BOOL s, ret, use_large_fat32; + BOOL s, ret, use_large_fat32, add_uefi_togo; const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector; DWORD rSize, wSize, BufSize, LastRefresh = 0, DriveIndex = (DWORD)(uintptr_t)param; HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; @@ -1301,6 +1301,7 @@ DWORD WINAPI FormatThread(void* param) pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)); + add_uefi_togo = (fs == FS_NTFS) && (dt == DT_ISO) && (IS_EFI(iso_report)) && (bt == BT_UEFI); PrintStatus(0, TRUE, MSG_225); hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE); @@ -1531,7 +1532,7 @@ DWORD WINAPI FormatThread(void* param) UpdateProgress(OP_ZERO_MBR, -1.0f); CHECK_FOR_USER_CANCEL; - if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR)&&(bt==BT_UEFI))) { + if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR) && (bt==BT_UEFI), add_uefi_togo)) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; goto out; } diff --git a/src/resource.h b/src/resource.h index 3a2e01fd..df630d71 100644 --- a/src/resource.h +++ b/src/resource.h @@ -73,6 +73,7 @@ #define IDR_GR_GRUB2_CORE_IMG 451 #define IDR_LC_RUFUS_LOC 500 #define IDR_XT_HOGGER 501 +#define IDR_UEFI_TOGO 502 #define IDC_DEVICE 1001 #define IDC_FILESYSTEM 1002 #define IDC_START 1003 diff --git a/src/rufus.c b/src/rufus.c index 46394f52..1550057e 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -460,7 +460,8 @@ static void SetFSFromISO(void) } // Syslinux and EFI have precedence over bootmgr (unless the user selected BIOS as target type) - if ((HAS_SYSLINUX(iso_report)) || (IS_REACTOS(iso_report)) || (iso_report.has_kolibrios) || ( (IS_EFI(iso_report)) && (bt == BT_UEFI))) { + if ((HAS_SYSLINUX(iso_report)) || (IS_REACTOS(iso_report)) || (iso_report.has_kolibrios) || + ((IS_EFI(iso_report)) && (bt == BT_UEFI) && (!iso_report.has_4GB_file))) { if (fs_mask & (1<