diff --git a/res/mbr/mbr.S b/res/mbr/mbr.S index 3b20c903..dedf7ddc 100644 --- a/res/mbr/mbr.S +++ b/res/mbr/mbr.S @@ -1,5 +1,5 @@ /********************************************************************************/ -/* Rufus - The Reliable USB Formatting Utility, bootable USB MBR */ +/* Rufus - The Reliable USB Formatting Utility, bootable MBR with user prompt */ /* */ /* Copyright (c) 2012 Pete Batard */ /* */ @@ -39,6 +39,7 @@ PT_MAX = 0x04 # Number of partition entries in the partition table PT_ENTRY_SIZE = 0x10 # Size of a partition entry in the partition table INT_RTC = 0x08 INT_DSK = 0x13 +DEBUG = 0 # Set to 1 to debug INT13h (shows AH and DL values) /********************************************************************************/ @@ -82,10 +83,9 @@ mbr: # From this point forward, we are running the copy at the same base but different segment 0: mov ds, ax # AX = ES = CS, only DS points back to old seg => fix this - push 0 - pop es # ES remains set to segment 0 from here on xor ebx, ebx # Sector #1 in 64 bit address mode (#0) - mov cx, 0x0001 # Sector #1 in CHS address mode (#1) + mov es, bx # ES remains set to segment 0 from here on + inc cx # Sector #1 in CHS address mode (#1) (and CX = 0 from rep movsb) mov dx, 0x0081 # drive number (DL), track 0 (DH) call read_sector jb boot_usb # If we couldn't get data => just boot USB @@ -123,7 +123,7 @@ wait_for_keyboard: and al, 0x04 # AL = shift status bits jnz boot_usb cmpb ds:counter_dot, 0x00 - jg short check_timeout + jg check_timeout print_dot: # Every so often, we print a dot mov si, offset dot_string @@ -136,14 +136,17 @@ check_timeout: boot_fixed_disk: # Timeout occured => boot second bootable disk (non USB) call restore_rtc_vect # Remove our RTC override - mov dx, offset dsk_interrupt # Set interrupt override to have - mov si, offset dsk_interrupt_org # disk 0x81 is seen as 0x80 - call set_int_vect + movb ds:partition_table, 0x81 # target we want to swap with 0x80 + push 0x0080 boot_drive: + mov dx, offset dsk_interrupt # Set interrupt override for int13h + mov si, offset dsk_interrupt_org + call set_int_vect + + pop dx # retrieve disk index to feed BR pop es pop ds - mov dx, 0x0080 # In both case, we pretend the disk is the first bootable jmp 0:MBR_ADDR # --------------------------------------------------------------------------- @@ -154,13 +157,13 @@ boot_usb: call flush_keyboard # Make sure the keyboard buffer is clear mov bx, offset partition_table mov dx, ds:[bx] + push dx + mov dl, 0x80 # Override disk number, as we're not using our int yet mov cx, ds:[bx+2] mov ebx, ds:[bx+8] # Must come last since it modifies BX call read_sector jnb boot_drive - -exit: # failed to read PBR from USB - exit back to BIOS - pop es + pop es # failed to read PBR from USB - exit back to BIOS pop ds retf @@ -215,7 +218,7 @@ no_ext: # http://en.wikipedia.org/wiki/INT_13H#INT_13h_AH.3D02h:_Read_Sectors_Fr set_int_vect: # Set the interrupt vector cli # SI = pointer to backup vector (must contain the interrupt #) mov bx, ds:[si] - mov eax, es:[bx] # Backup the original vector + mov eax, es:[bx] # Backup the original vector (ES = 0) mov ds:[si], eax mov es:[bx], dx mov es:[bx+2], cs @@ -257,21 +260,26 @@ print_string: # Print NUL terminated string in DS:SI to console # --------------------------------------------------------------------------- -disk_swap: # Swap disks 0x80 and 0x81 - push dx - and dl, 0xfe +disk_swap: # Swap disk according to part table entry + push ax + mov al, cs:partition_table cmp dl, 0x80 - pop dx jne 0f - xor dl, 0x01 -0: ret + mov dl, al # 0x80 -> cs:pt + jmp 1f +0: cmp dl, al # cs:pt -> 0x80 + jne 1f + mov dl, 0x80 +1: pop ax + ret # --------------------------------------------------------------------------- -.if 0 -print_hex: # Hex dump of the word at address ES:BX +.if DEBUG +print_hex: # Hex dump of AH,DL + pusha mov cx, 0x04 - mov dx, es:[bx] + mov dh, ah 0: rol dx, 0x04 mov ax, 0xe0f and al, dl @@ -280,6 +288,7 @@ print_hex: # Hex dump of the word at address ES:BX adc al, 0x40 int 0x10 loop 0b + popa ret .endif @@ -290,44 +299,56 @@ print_hex: # Hex dump of the word at address ES:BX # RTC (INT 8) interrupt override rtc_interrupt: - pushf cli cmpb cs:counter_timeout, 0x00 - jz rtc_exec_org + jz 0f # Don't decrement counters if timeout expired decb cs:counter_dot decb cs:counter_timeout -rtc_exec_org: rtc_interrupt_org = .+1 # Same trick used by the LILO mapper - call 0:INT_RTC*4 # These CS:IP values will be changed at runtime - iret +0: jmp 0:INT_RTC*4 # These CS:IP values will be changed at runtime # --------------------------------------------------------------------------- # DISK (INT 13h) interrupt override dsk_interrupt: pushf - cli +.if DEBUG + call print_hex +.endif + # Some machines (eg. IBM T43p) have a BIOS that reenters INT 13h to issue + # an SCSI passthrough (AH = 50h). Therefore swapping the drive on each call + # would result in failure. To ensure that the disk is only swapped once + # we keep a counter, and swap only if that counter is 0. + # NB: If concurrent INT 13h calls are issued, this approach will break + incb cs:already_mapped + jnz 0f call disk_swap - dsk_interrupt_org = .+1 - call 0:INT_DSK*4 # These CS:IP values will be changed at runtime +0: call 0:INT_DSK*4 # These CS:IP values will be changed at runtime # NB: subcommands 0x08 and 0x15 (disk props) modify DL, but they only - # do so to return the number of drives => unless your computer has 128 - # or 129 drives, disk_swap will not touch those values. + # do so to return the number of drives => unless your computer has more + # than 128 drives, disk_swap will not touch those values. pushf # Don't modify the returned flags + decb cs:already_mapped + jns 0f call disk_swap - popf - iret +0: popf + retf 2 /********************************************************************************/ /* Data section */ /********************************************************************************/ +already_mapped: .byte 0xff counter_timeout:.byte DOT_NUMBER*DOT_TIMEOUT + 1 counter_dot: .byte DOT_TIMEOUT +.if !DEBUG prompt_string: .string "\r\nPress any key to boot from USB." +.else +prompt_string: .string "USB." +.endif dot_string = .-2 # Reuse the end of previous string diff --git a/res/mbr/mbr.bin b/res/mbr/mbr.bin index 41c40e14..2e433d1a 100644 Binary files a/res/mbr/mbr.bin and b/res/mbr/mbr.bin differ diff --git a/res/mbr/readme.txt b/res/mbr/readme.txt index 0c917e8a..5c39bca2 100644 --- a/res/mbr/readme.txt +++ b/res/mbr/readme.txt @@ -4,11 +4,16 @@ Rufus: The Reliable USB Formatting Utility - Custom MBR This directory contains all the resources required to create an MBR that prompts the user for boot selection, when a second bootable device (typically bootable -fixed HDD) is reported by the BIOS. +fixed HDD) is reported by the BIOS at 0x81. This aims at mimicking the Microsoft Windows optical installation media feature, which may be necessary on for WinPE 2.x or earlier based installations. +This MBR will also masquerade a bootable USB drive booted as 0x80 by the BIOS to +a different ID according to the one found in its partition table entry. Eg. if +the partition table lists the disk ID for the first partition as 0x81, then it +will be swapped for 0x80. + # Compilation Any gcc suite (except possibly the X-Code one on OS-X) should be able to compile @@ -35,15 +40,19 @@ The way this bootloader achieves the feature highlighted above is as follows: BIOS disk access, behave as if there was no USB drive inserted. 6. In case there was a failure to read the second bootable drive's MBR, or no active partition was detected there, the USB is booted without prompts. +7. In case USB is booted, and the drive ID of first partition of the USB (which + is always assumed bootable) is read and if different from 0x80, then it is + also swapped with 0x80 in the INT_13h override. # Limitations * If you are using software RAID or a non-conventional setup, the second bootable disk may not be accessible through the BIOS and therefore the USB - will always be booted -* If the bootable HDD uses LILO, a "LILO - Keytable read/checksum error" will - be displayed when trying to boot it. -* This MBR currently does not masquerade the bootable USB drive as secondary - (0x81) therefore an installation program ran from USB to install an OS on - an HDD may still configure that disk as the second drive, and prevent it to - properly boot later on. + will always be booted. +* Some processes (notably XP's ntdetect.com) do not seem to like gaps in the + bootable drive sequence, which means that if you set your bootable USB + partition as 0x82 or higher, and it leaves any of 0x80/0x81 free as a result + then these processes may report an error. +* DOS also does not allow anything but 0x80 to be used as bootable disk. Thus + it is not possible to run MS-DOS or FreeDOS off an USB drive unless the disk + ID is 0x80 and not masqueraded. \ No newline at end of file diff --git a/src/ms-sys/.msvc/ms-sys.vcxproj b/src/ms-sys/.msvc/ms-sys.vcxproj index a749930e..0de43532 100644 --- a/src/ms-sys/.msvc/ms-sys.vcxproj +++ b/src/ms-sys/.msvc/ms-sys.vcxproj @@ -45,7 +45,6 @@ - diff --git a/src/ms-sys/.msvc/ms-sys.vcxproj.filters b/src/ms-sys/.msvc/ms-sys.vcxproj.filters index cbf09424..3dd1e24c 100644 --- a/src/ms-sys/.msvc/ms-sys.vcxproj.filters +++ b/src/ms-sys/.msvc/ms-sys.vcxproj.filters @@ -107,9 +107,6 @@ Header Files - - Header Files - diff --git a/src/ms-sys/br.c b/src/ms-sys/br.c index 4b9891c3..86379856 100644 --- a/src/ms-sys/br.c +++ b/src/ms-sys/br.c @@ -100,16 +100,6 @@ int is_win7_mbr(FILE *fp) contains_data(fp, 0x1FE, aucRef, sizeof(aucRef)); } /* is_win7_mbr */ -int is_rufus_mbr(FILE *fp) -{ - #include "mbr_rufus.h" - unsigned char aucRef[] = {0x55, 0xAA}; - - return - contains_data(fp, 0x0, mbr_rufus_0x0, sizeof(mbr_rufus_0x0)) && - contains_data(fp, 0x1FE, aucRef, sizeof(aucRef)); -} /* is_rufus_mbr */ - int is_syslinux_mbr(FILE *fp) { #include "mbr_syslinux.h" @@ -180,16 +170,6 @@ int write_win7_mbr(FILE *fp) write_data(fp, 0x1FE, aucRef, sizeof(aucRef)); } /* write_win7_mbr */ -int write_rufus_mbr(FILE *fp) -{ - #include "mbr_rufus.h" - unsigned char aucRef[] = {0x55, 0xAA}; - - return - write_data(fp, 0x0, mbr_rufus_0x0, sizeof(mbr_rufus_0x0)) && - write_data(fp, 0x1FE, aucRef, sizeof(aucRef)); -} /* write_rufus_mbr */ - int write_syslinux_mbr(FILE *fp) { #include "mbr_syslinux.h" diff --git a/src/ms-sys/inc/mbr_rufus.h b/src/ms-sys/inc/mbr_rufus.h deleted file mode 100644 index 2a097843..00000000 --- a/src/ms-sys/inc/mbr_rufus.h +++ /dev/null @@ -1,40 +0,0 @@ -/* First 446 bytes of boot selection MBR from Rufus */ -unsigned char mbr_rufus_0x0[440] = { - 0x41, 0x4b, 0x45, 0x4f, 0xfc, 0x31, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, - 0x7c, 0xfb, 0x89, 0xe6, 0x89, 0xe7, 0x1e, 0x06, 0x8e, 0xd8, 0xbb, 0x13, - 0x04, 0x8b, 0x07, 0x48, 0x89, 0x07, 0xc1, 0xe0, 0x06, 0x2d, 0xc0, 0x07, - 0x8e, 0xc0, 0xb9, 0x00, 0x02, 0xf3, 0xa4, 0x50, 0x68, 0x30, 0x7c, 0xcb, - 0x8e, 0xd8, 0x6a, 0x00, 0x07, 0x66, 0x31, 0xdb, 0xb9, 0x01, 0x00, 0xba, - 0x81, 0x00, 0xe8, 0x80, 0x00, 0x72, 0x67, 0xbb, 0xbe, 0x7d, 0xb9, 0x04, - 0x00, 0x26, 0x80, 0x3f, 0x00, 0x7c, 0x09, 0x75, 0x05, 0x83, 0xc3, 0x10, - 0xe2, 0xf3, 0xeb, 0x52, 0xbe, 0x78, 0x7d, 0xe8, 0xd1, 0x00, 0xe8, 0xc1, - 0x00, 0xba, 0x4c, 0x7d, 0xbe, 0x61, 0x7d, 0xe8, 0x97, 0x00, 0xb4, 0x01, - 0xcd, 0x16, 0x75, 0x37, 0xb4, 0x02, 0xcd, 0x16, 0x24, 0x04, 0x75, 0x32, - 0x80, 0x3e, 0x77, 0x7d, 0x00, 0x7f, 0x0b, 0xbe, 0x98, 0x7d, 0xe8, 0xaa, - 0x00, 0xc6, 0x06, 0x77, 0x7d, 0x12, 0x80, 0x3e, 0x76, 0x7d, 0x00, 0x75, - 0xd9, 0xe8, 0x80, 0x00, 0xba, 0x66, 0x7d, 0xbe, 0x6c, 0x7d, 0xe8, 0x64, - 0x00, 0x07, 0x1f, 0xba, 0x80, 0x00, 0xea, 0x00, 0x7c, 0x00, 0x00, 0xe8, - 0x6a, 0x00, 0xe8, 0x75, 0x00, 0xbb, 0xbe, 0x7d, 0x8b, 0x17, 0x8b, 0x4f, - 0x02, 0x66, 0x8b, 0x5f, 0x08, 0xe8, 0x05, 0x00, 0x73, 0xdf, 0x07, 0x1f, - 0xcb, 0x60, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0xcd, 0x13, 0x72, 0x2c, 0x81, - 0xfb, 0x55, 0xaa, 0x75, 0x26, 0xf7, 0xc1, 0x01, 0x00, 0x74, 0x20, 0x61, - 0x1e, 0x66, 0x31, 0xc0, 0x8e, 0xd8, 0x66, 0x50, 0x66, 0x53, 0x50, 0x68, - 0x00, 0x7c, 0x40, 0x50, 0x6a, 0x10, 0x89, 0xe6, 0xb4, 0x42, 0xcd, 0x13, - 0x9f, 0x83, 0xc4, 0x10, 0x9e, 0x1f, 0xc3, 0x61, 0xbb, 0x00, 0x7c, 0xb8, - 0x01, 0x02, 0xcd, 0x13, 0xc3, 0xfa, 0x8b, 0x1c, 0x26, 0x66, 0x8b, 0x07, - 0x66, 0x89, 0x04, 0x26, 0x89, 0x17, 0x26, 0x8c, 0x4f, 0x02, 0xfb, 0xc3, - 0xfa, 0xbb, 0x20, 0x00, 0x66, 0xa1, 0x61, 0x7d, 0x26, 0x66, 0x89, 0x07, - 0xfb, 0xc3, 0xb4, 0x01, 0xcd, 0x16, 0x74, 0x06, 0xb4, 0x00, 0xcd, 0x16, - 0xe2, 0xf4, 0xc3, 0xac, 0x3c, 0x00, 0x74, 0x09, 0xb4, 0x0e, 0xbb, 0x07, - 0x00, 0xcd, 0x10, 0xeb, 0xf2, 0xc3, 0x52, 0x80, 0xe2, 0xfe, 0x80, 0xfa, - 0x80, 0x5a, 0x75, 0x03, 0x80, 0xf2, 0x01, 0xc3, 0x9c, 0xfa, 0x2e, 0x80, - 0x3e, 0x76, 0x7d, 0x00, 0x74, 0x0a, 0x2e, 0xfe, 0x0e, 0x77, 0x7d, 0x2e, - 0xfe, 0x0e, 0x76, 0x7d, 0x9a, 0x20, 0x00, 0x00, 0x00, 0xcf, 0x9c, 0xfa, - 0xe8, 0xd3, 0xff, 0x9a, 0x4c, 0x00, 0x00, 0x00, 0x9c, 0xe8, 0xca, 0xff, - 0x9d, 0xcf, 0x49, 0x12, 0x0d, 0x0a, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, - 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x62, - 0x6f, 0x6f, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x55, 0x53, 0x42, - 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; diff --git a/src/resource.h b/src/resource.h index b26f92f2..a00b7821 100644 --- a/src/resource.h +++ b/src/resource.h @@ -9,6 +9,7 @@ #define IDD_LICENSE 105 #define IDD_ISO_EXTRACT 106 #define IDS_VERSION 107 +#define IDR_BR_MBR_BIN 200 #define IDR_FD_COMMAND_COM 300 #define IDR_FD_KERNEL_SYS 301 #define IDR_FD_DISPLAY_EXE 302 diff --git a/src/rufus.rc b/src/rufus.rc index 75ccef27..24a6e6c9 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 289 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW -CAPTION "Rufus v1.1.6.157" +CAPTION "Rufus v1.1.6.158" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,248,50,14 @@ -74,7 +74,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP CONTROL "http://rufus.akeo.ie",IDC_ABOUT_RUFUS_URL, "SysLink",WS_TABSTOP,46,47,114,9 - LTEXT "Version 1.1.6 (Build 157)",IDC_STATIC,46,19,78,8 + LTEXT "Version 1.1.6 (Build 158)",IDC_STATIC,46,19,78,8 PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8 @@ -224,8 +224,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,6,157 - PRODUCTVERSION 1,1,6,157 + FILEVERSION 1,1,6,158 + PRODUCTVERSION 1,1,6,158 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -242,13 +242,13 @@ BEGIN BEGIN VALUE "CompanyName", "akeo.ie" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.1.6.157" + VALUE "FileVersion", "1.1.6.158" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.1.6.157" + VALUE "ProductVersion", "1.1.6.158" END END BLOCK "VarFileInfo" @@ -279,6 +279,7 @@ IDI_ICON ICON "../res/rufus.ico" IDR_SL_LDLINUX_BSS RCDATA "../res/syslinux/ldlinux.bss" IDR_SL_LDLINUX_SYS RCDATA "../res/syslinux/ldlinux.sys" +IDR_BR_MBR_BIN RCDATA "../res/mbr/mbr.bin" // Only include these in rufus_fd #if defined(WITH_FREEDOS) IDR_FD_COMMAND_COM RCDATA "../res/freedos/COMMAND.COM"