I previously tried to post this, but it was held up ... presumably because
of the attachment.
I have included the patch at the bottom of this file
=========> I have successfully modified/enhanced memdisk so that
> one can chainload a local operating system after
> running diskless FreeDOS.
The attached 'chainmbr.patch' file can be applied to the 3.11
distribution
of syslinux to incorporate this functionality.
The patch incorporates changes to:
memdisk/setup.c
memdisk/memdisk.asm
memdisk/Makefile
memdisk/memdisk.doc
In addition, it includes a *new* file
memdisk/chainmbr.asm
Applying the patch will update the existing files and create the new file.
If you choose to incorporate this into a version control system then do
not forget to add chainmbr.asm to the repository.
Apply the patch in the syslinus-3.11/memdisk subdirector as follows:
[mth at arcoiris syslinux]$ ls -l
total 1248
-rw-rw-r-- 1 mth mth 12628 Mar 13 18:18 chainmbr.patch
-rw-rw-r-- 1 mth mth 1253470 Feb 9 12:03 syslinux-3.11.tar.bz2
[mth at arcoiris syslinux]$ tar xfj syslinux-3.11.tar.bz2
[mth at arcoiris syslinux]$ cd syslinux-3.11/memdisk/
[mth at arcoiris memdisk]$ patch <../../chainmbr.patch
patching file setup.c
patching file memdisk.asm
patching file Makefile
patching file memdisk.doc
patching file chainmbr.asm
[mth at arcoiris memdisk]$ cd ..
[mth at arcoiris syslinux-3.11]$ make
Note that the method of invocation in this version uses an unused int 13h
command (ah = 14h) to invoke the ChainMBR functionality. A more extensive
writeup is in the patched version of memdisk/memdisk.doc
Please contact me if you have any issues/questions/suggestions.
Miguel
=============chainmbr.patch
=============--- setup.c 2005-08-29 16:23:14.000000000 -0400
+++ ../../syslinux-mth/memdisk/setup.c 2006-03-13 13:17:51.000000000 -0500
@@ -72,7 +72,8 @@
uint16_t olddosmem;
uint8_t bootloaderid;
- uint8_t _pad[3];
+ uint8_t oldharddiskcount;
+ uint16_t oldequipmentword;
uint16_t memint1588;
uint16_t cylinders;
@@ -94,6 +95,9 @@
uint16_t statusptr;
dpt_t dpt;
+
+ uint32_t oldlo128vectors[128]; /* low 128 interrupt vectors */
+ uint32_t oldhi128checksum; /* checksum of hi 128 interrupt vectors */
};
/* This is the header in the boot sector/setup area */
@@ -668,6 +672,21 @@
pptr->oldint13 = rdz_32(BIOS_INT13);
pptr->oldint15 = rdz_32(BIOS_INT15);
+ /* Save interrupt vectors and BIOS Data Area settings to allow
+ rollback for chain booting of MBR */
+ pptr->oldharddiskcount = rdz_8(BIOS_HD_COUNT);
+ pptr->oldequipmentword = rdz_16(BIOS_EQUIP);
+ printf("old hard disk count = %d old equipment word = 0x%04x\n",
+ pptr->oldharddiskcount, pptr->oldequipmentword);
+ {
+ uint32_t i;
+ uint32_t *pIntVectors = 0;
+ memcpy(&pptr->oldlo128vectors, pIntVectors, sizeof
pptr->oldlo128vectors);
+ pptr->oldhi128checksum = 0;
+ for (i = 128; i < 256; ++i)
+ pptr->oldhi128checksum += pIntVectors[i];
+ }
+
/* Adjust the E820 table: if there are null ranges (type 0)
at the end, change them to type end of list (-1).
This is necessary for the driver to be able to report end
--- memdisk.asm 2005-08-23 17:11:36.000000000 -0400
+++ ../../syslinux-mth/memdisk/memdisk.asm 2006-03-13
16:37:20.000000000 -\0500
@@ -226,7 +226,7 @@
mov P_AH,bl ; 02h floppy, 03h hard disk
pop ax ; Drop return address
xor ax,ax ; Success...
- jmp short DoneWeird ; But don't stick it into P_AX
+ jmp DoneWeird ; But don't stick it into P_AX
GetStatus:
xor ax,ax
@@ -588,6 +588,108 @@
pop eax
ret
+;;;;
+ChainMbr:
+ TRACER 'C'
+ xor ax,ax
+ mov es,ax
+
+; validate checksum for high 128 interrupt vectors
+ mov di,200h
+ xor eax,eax
+do02:
+ add eax,[es:di]
+ add di,4
+ cmp di,0x400
+ jl do02
+ cmp eax,[OldHi128Checksum]
+ jne BadHi128Checksum
+
+;; next, read directly into 0:7C00h
+;; if the read succeeds, then we may have trashed something ...
+;; ... so there is no turning back
+ TRACER 'Z'
+ mov ax,0201h
+ mov cx,0001h
+ xor bx,bx
+ mov es,bx
+ mov bx,7C00h
+ mov dx,[SavedAX]
+ xor dh,dh
+ pushf
+ call far [cs:OldInt13]
+ jc BadMbrRead
+
+;; we have read into 0:7C00 ... so we must transfer control to mbr or reboot
+ mov ax,[es:7C00h + 01FEh]
+ cmp ax,0xAA55
+ jne BadMbrSignature
+
+;; restore low 128 interrupt vectors
+ xor di,di
+ mov si,OldLo128Vectors
+ mov cx,128
+ cld
+ cli
+ rep movsd
+
+;; restore BIOS Data Area settings
+ mov ax,[OldDosMem]
+ mov [es:413h],ax
+ mov ax,[OldEquipmentWord]
+ mov [es:410h],ax
+ mov al,[OldHardDriveCount]
+ mov [es:475h],al
+ sti
+
+%ifdef DEBUG_TRACERS
+ mov si,szPressKeyToChainload
+ call DisplaySz
+ mov ax,0 ; uncomment to wait for keyboard input
+ int 16h
+%endif
+
+ jmp 0:7C00h
+
+BadHi128Checksum:
+ TRACER 'X'
+ mov ax,0100h
+ ret
+
+BadMbrRead:
+ TRACER 'Y'
+ mov ah,2 ; al contains read error code
+ ret
+
+BadMbrSignature:
+ TRACER 'S'
+ mov si,szBadMbrSignaturePressKeyReboot
+ call DisplaySz
+
+ mov ax,0 ; wait for a key
+ int 16h
+
+ jmp 0FFFFh:0 ; reboot
+
+szBadMbrSignaturePressKeyReboot db 0Dh, 0Ah
+ db "Bad MBR Signature ... press any key to reboot", 0
+%ifdef DEBUG_TRACERS
+szPressKeyToChainload db "MBR successfully read ... press any key", 0
+%endif
+
+DisplaySz:
+ cld
+ mov bx, 7
+do03:
+ lodsb
+ or al,al
+ jz od03
+ mov ah,0Eh
+ int 10h
+ jmp do03
+od03:
+ ret
+
%ifdef DEBUG_TRACERS
debug_tracer: pushad
pushfd
@@ -625,7 +727,7 @@
dw Recalibrate ; 11h - RECALIBRATE
dw Invalid ; 12h
dw Invalid ; 13h
- dw Invalid ; 14h
+ dw ChainMbr ; 14h - ChainMBR extension
dw GetDriveType ; 15h - GET DRIVE TYPE
dw DetectChange ; 16h - DETECT DRIVE CHANGE
%if 0
@@ -730,7 +832,8 @@
OldDosMem dw 0 ; Old position of DOS mem end
BootLoaderID db 0 ; Boot loader ID from header
; ---- MDI structure ends here ---
- db 0, 0, 0 ; pad
+OldHardDriveCount db 0
+OldEquipmentWord dw 0
MemInt1588 dw 0 ; 1MB-65MB memory amount (1K)
@@ -752,6 +855,9 @@
DPT times 16 db 0 ; BIOS parameter table pointer
(floppie\s)
+OldLo128Vectors times 128 dd 0
+OldHi128Checksum dd 0
+
; End patch area
Stack dd 0 ; Saved SS:ESP on invocation
--- Makefile 2005-08-23 17:11:36.000000000 -0400
+++ ../../syslinux-mth/memdisk/Makefile 2006-03-13 17:39:16.000000000 -0500
@@ -40,13 +40,13 @@
CSRC = setup.c msetup.c e820func.c conio.c unzip.c
SSRC -NASMSRC = memdisk.asm memdisk16.asm
+NASMSRC = memdisk.asm memdisk16.asm chainmbr.asm
-all: memdisk e820test
+all: memdisk e820test chainmbr.com
# tidy, clean removes everything except the final binary
tidy:
- rm -f *.o *.s *.o16 *.s16 *.bin *.lst *.elf e820test
+ rm -f *.o *.s *.o16 *.s16 *.bin *.lst *.elf e820test *.com
clean: tidy
@@ -105,6 +105,9 @@
memdisk.o: memdisk.bin
$(LD) -r -b binary -o $@ $<
+chainmbr.com: chainmbr.asm
+ $(NASM) chainmbr.asm -o chainmbr.com
+
.depend:
rm -f .depend
for csrc in *.c ; do $(CC) $(INCLUDE) -MM $$csrc | sed -e
's/\.o/\.s/' \>> .depend ; done
--- memdisk.doc 2005-08-23 17:11:36.000000000 -0400
+++ ../../syslinux-mth/memdisk/memdisk.doc 2006-03-13
17:46:47.000000000 -\0500
@@ -191,3 +191,76 @@
mov byte [es:bx], 0EAh ; FAR JMP
mov [es:bx+1], eax
sti
+
+
+ChainMBR to a local Master Boot Record from memdisk
+---------------------------------------------------
+memdisk now supports booting the master boot record from a local storage
+device. One can use memdisk to boot under FreeDOS or MS-DOS. After running
+in DOS, one can chain-load to the MBR on a local storage device. This
+capability can be used to configure some types of hardware using DOS
+utilities prior to booting an OS from the hard drive.
+
+memdisk does this by copying the lower 128 interrupt vectors before DOS is
+executed. A checksum is calculated on the upper 128 interrupt vectors.
+
+The ChainMBR process restores the pre-DOS system state and boots the MBR of
+the specified drive in a single operation. The sequence is as follows:
+
+ * verify checksum on upper 128 interrupt vectors
+ * read Master Boot Record (at Cylinder/Head/Sector 0/0/1) into 0:7C00
+ * verify Master Boot Record signature: last 2 bytes are 0x55 and 0xAA
+ * restore lower 128 interrupt vectors
+ * restore BIOS equipment word at 0040:0010
+ * restore BIOS hard drive count at 0040:0075
+ * restore BIOS base memory at 0040:0013
+ * transfer control to master boot code at 0:7C00
+
+This sequence is initiated by using an unused int 13h BIOS disk command.
+This command should be used only after verifying that the device is memdisk
+using the installation check API described above.
+
+;;;;;;;;;;;;;;;; memdisk installation check
+ mov eax," ME"
+ mov ecx," MD"
+ mov edx," IS"
+ mov ebx," K?"
+ mov ah,08h ; 08h = parameter query
+ mov dl,[bMemdiskDrive]
+ int 13h
+
+ shr eax,16
+ shr ecx,16
+ shr edx,16
+ shr ebx,16
+ cmp ax,"!M"
+ jne not_memdisk
+ cmp cx,"EM"
+ jne not_memdisk
+ cmp dx,"DI"
+ jne not_memdisk
+ cmp bx,"SK"
+ jne not_memdisk
+;;;;;;;;;;;;;;;;
+ mov ah,14h
+ mov al,[bChainMBRDrive]
+ mov dl,[bMemdiskDrive]
+ int 13h
+
+Register AH holds 14h in order to specify the ChainMBR command to memdisk.
+Register DL contains the drive number of memdisk. This will be 0x00 or
+0x80, depending upon whether you have memdisk configured to emulate a
+floppy drive or a hard drive, respectively.
+
+Register AL contains the drive number of the device from which you want
+to boot the MBR. This will generally be 0x80 for the local hard drive. Note
+that this is the drive number *after* memdisk has been unloaded. If you are
+using memdisk to emulate a hard drive then both AL and DL will contain 0x80.
+
+See the included chainmbr.asm file for a sample implementation.
+
+The following configurations have been tested:
+ memdisk + FreeDOS and MS-DOS 6.22
+ ChainMBR to Linux (via grub), WinXP and MS-DOS 6.22 on local 0x80 hard
drive
+ ChainMBR to FreeDOS and MS-DOS 6.22 on local 0x00 floppy drive
+ Both physical machines and VMware virtual machines
--- chainmbr.asm 1969-12-31 19:00:00.000000000 -0500
+++ ../../syslinux-mth/memdisk/chainmbr.asm 2006-03-13
17:53:08.000000000 -\0500
@@ -0,0 +1,188 @@
+; -*- fundamental -*-
+; $Id: $
+;
****************************************************************************
+;
+; chainmbr.asm
+;
+; unload memdisk and chain boot the master boot record
+;
+; assemble using:
+; $nasm chainmbr.asm -o chainmbr.com
+;
+; Copyright (C) 2006 Miguel Howard, Scalent Systems Inc., www.scalent.com
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+; Boston MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+;
****************************************************************************
+
+ org 100h
+
+ section .text
+start:
+ mov ax,cs
+ mov ds,ax
+ mov es,ax
+
+;;;;;;;;;;;;;;;; memdisk installation check
+ mov eax," ME"
+ mov ecx," MD"
+ mov edx," IS"
+ mov ebx," K?"
+ mov ah,08h ; 08h = parameter query
+ mov dl,[bMemdiskDrive]
+ xor di,di ; ralf brown says guard against BIOS bugs
+ mov es,di
+ int 13h
+
+ shr eax,16
+ shr ecx,16
+ shr edx,16
+ shr ebx,16
+ cmp ax,"!M"
+ jne not_memdisk
+ cmp cx,"EM"
+ jne not_memdisk
+ cmp dx,"DI"
+ jne not_memdisk
+ cmp bx,"SK"
+ jne not_memdisk
+;;;;;;;;;;;;;;;;
+
+ mov si,szBootMbr
+ call DisplaySz
+ mov al,[bChainMBRDrive]
+ call DisplayHexByte
+ call DisplayCrlf
+ mov si,szUnderscores
+ call DisplaySz
+
+ mov ah,14h
+ mov al,[bChainMBRDrive]
+ mov dl,[bMemdiskDrive]
+ int 13h
+
+ cmp ah,01h
+ je bad_hi128checksum
+ cmp ah,02h
+ jz bad_mbr_read
+
+why_am_i_here:
+ mov si,szWhyAmIHere
+ call DisplaySz
+
+return_to_dos:
+ mov ax,4C00h
+ int 21h
+
+not_memdisk:
+ mov si,szNotMemdisk
+ call DisplaySz
+ jmp return_to_dos
+
+bad_hi128checksum:
+ mov si,szBadHi128Checksum
+ call DisplaySz
+ jmp return_to_dos
+
+bad_mbr_read:
+ mov [bReadErrorCode],al
+ mov si,szBadMbrRead
+ call DisplaySz
+ mov al,[bReadErrorCode]
+ call DisplayHexByte
+ mov si,szBadMbrRead2
+ call DisplaySz
+ mov al,[bChainMBRDrive]
+ call DisplayHexByte
+ call DisplayCrlf
+ jmp return_to_dos
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+DisplaySpace:
+ mov al,' '
+
+DisplayChar:
+ mov ah,0Eh
+ mov bx,7
+ int 10h
+ ret
+
+DisplayCrlf:
+ mov si,szCrlf;
+
+DisplaySz:
+ cld
+ mov bx,7
+DisplaySzLoop:
+ lodsb
+ or al,al
+ jz endDisplaySz
+ mov ah,0Eh
+ int 10h
+ jmp DisplaySzLoop
+endDisplaySz:
+ ret
+
+DisplayHexNibble:
+ and al,0Fh
+ add al,30h
+ cmp al,39h
+ jle digit
+ sub al,30h
+ sub al,10
+ add al,'A'
+digit:
+ mov ah, 0Eh
+ int 10h
+ ret
+
+DisplayHexByte:
+ push ax
+ shr al,4
+ call DisplayHexNibble
+ pop ax
+ jmp DisplayHexNibble
+
+DisplayHexWord:
+ push ax
+ mov al,ah
+ call DisplayHexByte
+ pop ax
+ jmp DisplayHexByte
+
+DisplayHexVector
+ cld
+ jcxz endDisplayHexVector
+ lodsb
+ call DisplayHexByte
+ mov ax,0E20h
+ int 10h
+ dec cx
+ jmp DisplayHexVector
+endDisplayHexVector
+ ret
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ section .data
+ alignb 2
+bMemdiskDrive db 00h ; the drive that is running memdisk ... assume floppy
+bChainMBRDrive db 80h ; the drive to boot ... assume default hard drive
+bReadErrorCode db 0
+szCrlf db 0Dh,0Ah,0
+szBootMbr db "chain booting the MBR on drive 0x", 0
+szUnderscores db "-----------------------------------", 0Dh, 0Ah, 0
+szWhyAmIHere db "Why am I here? I should have rebooted", 0Dh, 0Ah,
0
+szNotMemdisk db "Does not look like memdisk", 0Dh, 0Ah, 0
+szBadHi128Checksum db "ERROR - Hi interrupt vectors have changed,"
+ db " cannot restore system state", 0Dh, 0Ah, 0
+szBadMbrRead db "ERROR - code 0x", 0
+szBadMbrRead2 db " reading Master Boot Record from drive 0x", 0
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; end
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;