[mbr] various fixes and improvements

* Adds USB masquerading according to disk ID in USB part table
* Adds debug feature
* Closes #74 - was due to flags not being properly saved/restored
* Closes #71
* Fixes reentrant INT_13h for some platforms (eg. IBM t43p reenters
  INT_13h to issue an SCSI passthrough, AH=0x50)
* Embed MBR as a resource rather than an ms-sys header
This commit is contained in:
Pete Batard 2012-03-25 21:35:38 +01:00
parent 7874f5ea5d
commit d87f069963
9 changed files with 80 additions and 112 deletions

View File

@ -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 <pete@akeo.ie> */
/* */
@ -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

Binary file not shown.

View File

@ -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.

View File

@ -45,7 +45,6 @@
<ClInclude Include="..\inc\mbr_95b.h" />
<ClInclude Include="..\inc\mbr_dos.h" />
<ClInclude Include="..\inc\mbr_dos_f2.h" />
<ClInclude Include="..\inc\mbr_rufus.h" />
<ClInclude Include="..\inc\mbr_syslinux.h" />
<ClInclude Include="..\inc\mbr_vista.h" />
<ClInclude Include="..\inc\mbr_win7.h" />

View File

@ -107,9 +107,6 @@
<ClInclude Include="..\inc\br_ntfs_0x54.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\mbr_rufus.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\br.c">

View File

@ -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"

View File

@ -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
};

View File

@ -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

View File

@ -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 "<a href=""http://rufus.akeo.ie"">http://rufus.akeo.ie</a>",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"