[syslinux] Enhanced MDISKCHK.COM and MEMDISK patches

Gert Hulselmans gerth at zytor.com
Tue Mar 30 17:43:37 PDT 2010


Shao Miller wrote:
> Good day to all,
>
> Gert Hulselmans requested a feature for MDISKCHK.COM that would function
> roughly like GETARGS.COM[1] by Murali Krishnan Ganapathy: DOS SET
> command output for MEMDISK kernel arguments passed by previous
> boot-loaders.  He also needed to support the case for
> MEMDISK-in-a-MEMDISK type situations, where all MEMDISK kernel arguments
> could be gathered together and output as a list of DOS SET commands.
>
> - Shao Miller

I just found out that the Freedos image used by UBCD, didn't use
GETARGS.COM by Murali Krishnan Ganapathy.

It uses GETARGS.COM by Eric Auer. More specific, the
"combined-drivecheck-memdisk-getargs" variant:
http://www.mail-archive.com/freedos-user@lists.sourceforge.net/msg01631.html

Eric Auer wrote:
>> In addition to
>>   http://www.coli.uni-sb.de/~eric/stuff/soft/specials/tiny-memdisk-getargs.zip
>>   (which is less than 512 bytes and checks MEMDISK load args, if MD.
present)
>> there now is
>>   http://www.coli.uni-sb.de/~eric/stuff/soft/specials/combined-drivecheck-memdisk-getargs.zip
>> (which is 1024 bytes small and can detect both MEMDISK and NORMAL
>> drives, e.g. useful for finding out whether a B: drive exists, whether
>> and for which drive letter MEMDISKs are loaded, and which load args were
>> used. Plus it checks the boot loader ID - but only for MEMDISK of
>> SYSLINUX/ISOLINUX/... 3.0 and newer!)

Sadly the links don't work anymore.
Luckily the Wayback Machine exists:
http://web.archive.org/web/20060620033233/http://www.coli.uni-saarland.de/~eric/stuff/soft/specials/combined-drivecheck-memdisk-getargs.zip

It is written in assembler. This might explain why this version was so
much smaller than your version, Shao ;-).

- Gert Hulselmans

$ cat getargs.asm
; Public domain tool to fetch the load arguments of a MEMDISK

; (virtual disk, created by SYSLINUX MEMDISK tool in int 15h

; memory space after booting with SYSLINUX / ISOLINUX / ...

; to simplyfy booting non-Linux operating systems). Based

; on the IFMEMDSK tool. By Eric Auer 9/2004, BIOS mode and

; MAGIC mode and WHO feature added by Eric Auer 3/2005.



%define MAGIC 1	; magic M option, useful for boot loader ID check

		; by errorlevel.

%define WHO 0	; enable to have WHO=char variable in normal

		; output to report boot loader ID. Only useful

		; for boot loader IDs which are also ASCII chars.



; Returned NORMAL Errorlevel: (without / with Win32 running)

; 0 / 16 - 386 or better CPU but no MEMDISK

; 1 / 17 - A: is a MEMDISK

; 2 / 18 - B: is a MEMDISK

; 3 / 19 - C:, or to be more exact, the first harddisk, BIOS disk

;     number 80h, is a MEMDISK

; 253 - invalid command line argument (new 3/2005)

; 254 - the CPU is older than an 80286

; 255 - the CPU is an 80286 only, so no MEMDISK possible



%if MAGIC

; Returned MAGIC Errorlevel: If command line option M (upper case)

; given, errorlevel is the boot loader ID, 49 .. 52 ("1" .. "4"),

; if a syslinux 3.0+ family memdisk is found. If no memdisk or an

%if WHO

; older memdisk is found, errorlevel is 88 ("X") or the version of

%else

; older memdisk is found, errorlevel is 0 or the version of

%endif

; syslinux/memdisk found (at most 2, for 2.xx).

%endif



; Returned BIOS MODE Errorlevel: (check type of user-selected drive)

;      0  - no such drive

;  1..63  - drive is CHS with n sectors per track

; 65..127 - same, but drive supports LBA (64 would be LBA-only drive)

; Specify 0..1 for floppy, 2..9 for harddisks 80h..87h.





%imacro	FLAGCHECK 0

	pushf		; save

	push ax		; test value

	popf		; try to set flags

	pushf		; check what happened

	pop ax		; test results

	popf		; restore

%endmacro





	org 100h	; a .COM file



start:	mov si,81h

cmd:	lodsb

	cmp al,' '

	jz cmd

	cmp al,9

	jz cmd

	cmp al,13

	jbe memdsk	; CLASSIC mode: check for memdisks

	; cmp al,'?'	; implicit, all invalid args trigger help

	; jz help

%if MAGIC

	cmp al,'M'	; "undocumented" MAGIC mode: ask memdisk

	jz memdsk_magic	; for boot loader type, if memdisk found.

	cmp al,'m'	; "undocumented" MAGIC mode: ask memdisk

	jz memdsk_magic	; for boot loader type, if memdisk found.

%endif

	cmp al,'0'

	jb help		; invalid argument

	cmp al,'9'

	ja help		; invalid argument

	sub al,'0'

	cbw		; argument AX: drive number

	cmp al,2

	jb floppy	; floppy, or rather harddisk?

	add al,80h-2	; 2..9 -> 80h..87h

floppy:	jmp biosdsk	; NEW MODE: check BIOS disk properties





help:	mov ah,9	; string$ output

	mov dx,helpmsg	; help text

	int 21h		; DOS API

	mov ax,4cfdh	; return errorlevel 253

	int 21h		; DOS API - exit





%if MAGIC

memdsk_magic:

	mov byte [magjmp+1],0	; zap the jump-over-magic-errorlevel,

				; enable boot loader ID in errorlevel.

%endif



memdsk:	xor bp,bp	; errorlevel

	dec bp

	dec bp



	xor ax,ax	; try to zero all flags

	mov bx,0f000h	; bit mask for high bits

	FLAGCHECK

	and ax,bx	; high bits...

	cmp ax,bx	; ...stuck to 1? 80186 or older!

	jz known	; *** is186: errorlevel 254, PC XT

	inc bp		; next assumption: 286

	mov ax,bx	; try to set all high bits

	FLAGCHECK

	test ax,bx	; all stuck to 0? 80286!

	jz known	; *** is286: errorlevel 255, PC AT but no 386+

	inc bp		; next: 386, but no memdisk found yet.



is386:	inc bp		; assumption: errorlevel 1, A: is a memdisk

	mov dl,0	; A:

	call memdiskcheck

	jc known	; only return first match

	inc bp		; assumption: errorlevel 2, B: is a memdisk

	mov dl,1	; B:

	call memdiskcheck

	jc known	; only return first match

	inc bp		; assumption: errorlevel 3, "C:" is a memdisk

	mov dl,80h	; "C:"

	call memdiskcheck

	jc known	; only return first match

noABCmemdisk:

	xor bp,bp	; errorlevel 0, no memdisk but at least a 386.



known:	mov ax,bp	; fetch errorlevel

	cbw		; sign-extend AL to AX

	add ax,ax

	mov bx,ax

	mov ah,9	; string$ output ds:dx

	mov dx,echomsg

	int 21h

	mov dx,[cs:stringtable+bx]	; fetch appropriate message

; - done:

	mov ah,9	; string$ output ds:dx

	int 21h		; DOS API

	mov dx,memdisk	; write " MEMDISK." and carriage return, line break

	mov ah,9

	int 21h

	mov ax,bp	; fetch errorlevel

	call WinCheck	; check for Win32, add 16 to errorlevel if found

%if MAGIC

magjmp:	jmp short skipmagic	; patch this to enable the next mov al,...

	mov al,[syslver]	; will be "X" or "1" ... "4"

skipmagic:

%endif

	mov ah,4ch	; leave program, errorlevel in AL

	int 21h		; DOS API





memdiskcheck:

	mov eax,454d0800h	; magic1 + AH=8 (get geometry)

	mov ecx,444d0000h	; magic2

	push dx

	mov edx,53490000h	; magic3 +

	pop dx			; ... drive number in DL

	mov ebx,3f4b0000h	; magic4

	int 13h			; BIOS DISK API

	shr eax,16		; ignore AX

	shr ebx,16		; ignore BX

	shr ecx,16		; ignore CX (geometry C/S)

	shr edx,16		; ignore DX (geometry H in DH)

	cmp ax,4d21h		; magic5

	jnz nomemdisk

	cmp cx,4d45h		; magic6

	jnz nomemdisk

	cmp dx,4944h		; magic7

	jnz nomemdisk

	cmp bx,4b53h		; magic8

	jnz nomemdisk



	mov al,[es:di+3]	; major version

	cmp al,3		; not supported before SYSLINUX 3.0

	jb oldsyslinux

	mov al,[es:di+26]	; boot loader ID

	mov [syslver],al	; "1".."4" for sys/pxe/iso/extlinux

oldsyslinux:

%if MAGIC && WHO		; have to save/restore value if both

	push ax

%endif

	push es

	push di

	les di,[es:di+12]

	call printcommandline

	pop di

	pop es

%if MAGIC && WHO

	pop ax

	mov [syslver],al	; "1".."4" for sys/pxe/iso/extlinux

%endif



	; ES:DI now points to a data structure...

	; dw bytes, dw version, dd disk address in RAM,

	; dd size in sectors, dd pointer to commandline,

	; dd old int 13h vector, dd old int 15h vector

	; dw old [40h:13h] low memory size value



	stc			; return success

	ret



nomemdisk:

	clc			; return failure

	ret





		dw pcxt, pcat	; entries -2 and -1 of stringtable!

stringtable	dw xmem, amem, bmem, cmem



echomsg	db "@echo $"

pcxt	db "8086, can't have$"	; 254

pcat	db "80286, can't have$"	; 255

xmem	db "found no$"	 	; (in A B HDA)	; 0 (or 16)

amem	db "A: is$"		; 1 (or 17)

bmem	db "B: is$"		; 2 (or 18)

cmem	db "1st harddisk is$"	; 3 (or 19)

memdisk	db " MEMDISK.",13,10,"$"



iswin	db "@echo Win/"		; "Win (16 bit)" or "Win (NT-ish)" or ...

winbits	db "32 DOS box!",13,10,"$"	; editable part

	; --- winbits	db "32 bit) DOS box!",13,10,"$"	; editable part

	; shorter: Win/16, Win/32 or Win/NT



WinCheck:

	push bx

	push cx

	push dx



	push ax

	mov ax,1683h	; get current virtual machine number

	xor bx,bx	; preset to 0 if no Win at all running

	int 2fh

	or bx,bx

	pop ax

	jnz IsWin



	push ax

	mov ax,1600h	; Win32 install check

	int 2fh

	test al,7fh	; 0 / 80 no Win32, 1 Win2, -1 Win2, 3.. Win 3..

	pop ax

	jnz IsWin



	push ax

	mov ax,160ah	; Win3+ version check

	int 2fh		; (modifies BX and CX as well)

	or ax,ax	; 0 means Win3+ version check supported

	pop ax

	jz IsWin

	; version is BH.BL for CPU type CX



	push ax

	mov ax,3306h	; get internal DOS version (DOS 5+)

	int 21h		; returns AL=-1 for older DOS versions

	cmp bx,3205h	; WinNT/2k/XP/... DOS boxes report version 5.50

	pop ax		; (modifies BX and DX as well)

	jnz WinChecked

	add al,16	; change errorlevel

	mov bx,"NT"	; WinNT family

	; --- mov dword [winbits+2],"-ish"	; not " bit", but "-ish" :-)

	jmp short WinIs32



IsWin:	add al,16	; change errorlevel



	push ax

	mov ax,1600h	; do Win32 install check

	int 2fh

	or al,al	; major version number, or (Win2) +1/-1

	pop ax

	mov bx,"32"	; assume Win32-ish mode

	jnz WinIs32	; ah is minor version number.

	mov bx,"16"	; not in enhanced / Win386 / Win32 mode

	; (the Win3.x 286 (standard mode) DOS extender has no version check)

WinIs32:

	mov word [winbits],bx	; not in enhanced / Win386 / Win32 mode

	push ax

	mov dx,iswin

	mov ah,9

	int 21h

	pop ax



WinChecked:

	pop dx

	pop cx

	pop bx

	ret







printcommandline:	; string at ES:DI, 0 terminated, space separated

; http://people.cs.uchicago.edu/~gmurali/gui/comboot/getargs.c skips over

; leading and trailing spaces and treats args without = inside as special.

	push ax

	push bx

	push bp

%if WHO

	jmp short dosyslver	; FIRST, create "SET WHO=loader" line

%endif



nextcl:	mov bx,setline+5	; target pointer

	xor bp,bp		; "no = yet"

skipcl:	mov al,[es:di]

	inc di

	or al,al

	jz donecl

	cmp al,' '

	jz skipcl		; skip leading spaces



copycl:	cmp al,' '		; suppress control chars

	jb evil			; those are evil, skip them

	cmp al,'='

	jnz nosign

issign:	inc bp			; found a = sign, remember that

nosign:	mov [bx],al		; save useful byte

	inc bx

evil:	mov al,[es:di]		; check next source byte

	inc di

	or al,al

	jz donecl

	cmp al,' '

	jnz copycl		; neither eof nor space? keep copying!



donecl:	cmp bx,setline+5

	jz nocl

	or bp,bp		; already saw a = sign? else add one!

	jnz hadsign

	mov word [bx],"=Y"

	inc bx

	inc bx

hadsign:

	mov word [bx],0a0dh	; 13,10 (carriage return, linefeed)

	mov byte [bx+2],'$'	; end of string

dosyslver:

	mov ah,9

	mov dx,setline

	int 21h			; print string to stdout

nocl:	dec di			; rewind

	mov al,[es:di]		; the byte which ended THIS argument

	or al,al		; end of the whole thing?

	jnz nextcl		; otherwise repeat for NEXT argument

	pop bp

	pop bx

	pop ax

	ret



%if WHO

setline	db "@SET WHO="		; first item: "@SET WHO=bootloaderID"

syslver	db "X",13,10,"$"	; BUFFER for strings follows

%else

syslver	db 0			; storage space for boot loader ID

setline	db "@SET "		; BUFFER for strings follows this

%endif

	; (will overwrite the biosdsk code in getargs mode, no problem)





biosdsk:			; check BIOS disk AX properties

	mov dl,al		; selected drive number

	push dx

	mov ah,8		; get geometry

	push es			; push di not needed here

	int 13h			; BIOS DISK API

	pop es			; pop di not needed here

	mov al,dl		; number of disks in this "category"

	pop dx

	jc nosuchdrive

	or al,al

	jz nosuchdrive

	and cl,63

	mov dh,cl		; intermediate result...

	push dx

	mov ax,4100h		; LBA presence check

	mov bx,55aah		; magic value

	int 13h			; BIOS DISK API

	pop dx			; ignore further register messing here

	cmp bx,0aa55h

	mov ax,nolbamsg

	jnz nolbadrive

	test cx,1

	jz nolbadrive

	mov ax,lbadrivemsg

	add dh,64		; flag LBA capability

nolbadrive:

	push dx

	mov dx,ax		; message

	mov ah,9		; show string$

	int 21h			; DOS API

	pop dx

	mov al,dh		; errorlevel

	jmp short godos



nosuchdrive:

	mov ah,9		; show string$

	mov dx,nodrivemsg

	int 21h			; DOS API

	mov al,0		; return errorlevel 0

godos:	mov ah,4ch		; exit with errorlevel AH

	int 21h			; DOS API





nodrivemsg	db "No drive.",13,10,"$"

nolbamsg	db "Normal CHS drive.",13,10,"$"

lbadrivemsg	db "LBA-enabled drive.",13,10,"$"

	; PS: int 13.15 returned AH is 2 if with disk change detector





helpmsg	db "Public Domain. Finds MEMDISK, writes SET lines with MD params."

	db 13,10

	db "Returns: 0 no MD, 254/255 pre-386 CPU,",13,10

	db "  1-3 found MD on A:-C:, add 16 if inside WinXX",13,10

%if MAGIC	; save space: short help if magic on...

	db "GETARGS n: n=0/1/2/3-9 check A:/B:/1st-8th harddisk, not MD."

	db 13,10

	db "Returns: 0 none, 1-63 sectors, 64-127 LBA"

%else

	db "Or do 'GETARGS n': n=0/1 check A:/B: disk, "

	db   "n=2..9 check 0x80..0x87 harddisk.",13,10

	db "Returns: 0 no disk, 1..63 geometry (S), add 64 if LBA okay."

%endif

	db 13,10

%if MAGIC > WHO	; magic on, but who not (have to save space else)

	db "GETARGS M:",13,10

	db "Returns: 0-2 no/old MD, 3-? boot loader ID",13,10

%endif

%if MAGIC && WHO

	db "GETARGS M: Returns MD 3+ boot loader ID.",13,10

%endif

	db "$"




More information about the Syslinux mailing list