update ldosboot from hg 798e0b02fedc

From https://hg.pushbx.org/ecm/ldosboot/file/798e0b02fedc
This commit is contained in:
C. Masloch 2023-03-29 20:36:39 +02:00 committed by E. C. Masloch
parent adbc31edea
commit cba5ee259d
10 changed files with 1018 additions and 333 deletions

View File

@ -30,7 +30,7 @@ Public domain by C. Masloch, 2012
strdef LOAD_NAME, "LDOS" strdef LOAD_NAME, "LDOS"
strdef LOAD_EXT, "COM" ; name of file to load strdef LOAD_EXT, "COM" ; name of file to load
numdef LOAD_ADR, 02000h ; where to load numdef LOAD_ADR, 02000h ; where to load
numdef LOAD_MIN_PARA, paras(1536) numdef LOAD_MIN_PARA, paras(4096)
numdef LOAD_NON_FAT, 0, 2048 ; use FAT-less loading (value is amount bytes) numdef LOAD_NON_FAT, 0, 2048 ; use FAT-less loading (value is amount bytes)
numdef EXEC_SEG_ADJ, 0 ; how far cs will be from _LOAD_ADR numdef EXEC_SEG_ADJ, 0 ; how far cs will be from _LOAD_ADR
numdef EXEC_OFS, 400h ; what value ip will be numdef EXEC_OFS, 400h ; what value ip will be
@ -41,12 +41,16 @@ Public domain by C. Masloch, 2012
strdef ADD_NAME, "" strdef ADD_NAME, ""
strdef ADD_EXT, "" ; name of second file to search strdef ADD_EXT, "" ; name of second file to search
numdef ADD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere) numdef ADD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere)
numdef CHECK_ATTRIB, 0 ; check attribute for LFN, label, directory
numdef ATTRIB_SAVE, _CHECK_ATTRIB
gendef _ADR_DIRBUF, end -start+7C00h ; 07E00h gendef _ADR_DIRBUF, end -start+7C00h ; 07E00h
gendef _ADR_FATBUF, end -start+7C00h ; 07E00h gendef _ADR_FATBUF, end -start+7C00h ; 07E00h
numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access)
numdef QUERY_GEOMETRY_DISABLED, 0
numdef USE_PART_INFO, 1 ; use ds:si-> partition info from MBR, if any numdef USE_PART_INFO, 1 ; use ds:si-> partition info from MBR, if any
numdef USE_PART_INFO_DISABLED, 0
numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl
numdef RPL, 1 ; support RPL and do not overwrite it numdef RPL, 1 ; support RPL and do not overwrite it
numdef RPL_GRACE_AREA, 130 * 1024 numdef RPL_GRACE_AREA, 130 * 1024
@ -73,6 +77,7 @@ Public domain by C. Masloch, 2012
numdef LBA_SET_TYPE, 0 ; if to set third byte to LBA partition type numdef LBA_SET_TYPE, 0 ; if to set third byte to LBA partition type
numdef SET_LOAD_SEG, 1 ; if to set load_seg (word [ss:bp - 6]) numdef SET_LOAD_SEG, 1 ; if to set load_seg (word [ss:bp - 6])
numdef SET_FAT_SEG, 1 ; if to set fat_seg (word [ss:bp - 8]) numdef SET_FAT_SEG, 1 ; if to set fat_seg (word [ss:bp - 8])
numdef SET_FAT_SEG_NORMAL, 1 ; do not use aggressive optimisation
numdef SET_CLUSTER, 1 ; if to set first_cluster (word [ss:bp - 16]) numdef SET_CLUSTER, 1 ; if to set first_cluster (word [ss:bp - 16])
numdef ZERO_ES, 0 ; if to set es = 0 before jump numdef ZERO_ES, 0 ; if to set es = 0 before jump
numdef ZERO_DS, 0 ; if to set ds = 0 before jump numdef ZERO_DS, 0 ; if to set ds = 0 before jump
@ -83,11 +88,18 @@ Public domain by C. Masloch, 2012
numdef FIX_CLUSTER_SIZE_SKIP_CHECK, 0 ; don't check cluster size numdef FIX_CLUSTER_SIZE_SKIP_CHECK, 0 ; don't check cluster size
numdef NO_LIMIT, 0 ; allow using more memory than a boot sector numdef NO_LIMIT, 0 ; allow using more memory than a boot sector
; also will not write 0AA55h signature! ; also will not write 0AA55h signature!
numdef WARN_PART_SIZE, 0
numdef LBA_SKIP_CHECK, 1 ; don't use proper LBA extensions check numdef LBA_SKIP_CHECK, 1 ; don't use proper LBA extensions check
numdef LBA_SKIP_CY, 1 ; skip check: set up CY before 13.42
numdef LBA_SKIP_ANY, 0 ; skip check: try CHS on any error
incdef _LBA_SKIP_ANY, LBA_SKIP_CY
numdef LBA_RETRY, 0 ; retry LBA reads one time numdef LBA_RETRY, 0 ; retry LBA reads one time
numdef CHS_RETRY, 1 ; retry CHS reads one time numdef CHS_RETRY, 1 ; retry CHS reads one time
numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times
; (value of the def is used as count) ; (value of the def is used as count)
numdef CHS_RETRY_NORMAL,1 ; do not use aggressive optimisation
numdef RETRY_RESET, 1 ; call reset disk system 13.00 on retries
numdef MEDIAID, 0F0h ; media ID numdef MEDIAID, 0F0h ; media ID
numdef UNIT, 0 ; load unit in BPB numdef UNIT, 0 ; load unit in BPB
@ -133,7 +145,7 @@ Public domain by C. Masloch, 2012
%if (!!_COMPAT_FREEDOS + !!_COMPAT_IBM + \ %if (!!_COMPAT_FREEDOS + !!_COMPAT_IBM + \
!!_COMPAT_MS7 + !!_COMPAT_MS6 + \ !!_COMPAT_MS7 + !!_COMPAT_MS6 + \
!!_COMPAT_LDOS || _COMPAT_KERNEL7E) > 1 !!_COMPAT_LDOS + !!_COMPAT_KERNEL7E) > 1
%error At most one set must be selected. %error At most one set must be selected.
%endif %endif
@ -244,7 +256,7 @@ Public domain by C. Masloch, 2012
strdef LOAD_NAME, "LDOS" strdef LOAD_NAME, "LDOS"
strdef LOAD_EXT, "COM" strdef LOAD_EXT, "COM"
numdef LOAD_ADR, 02000h numdef LOAD_ADR, 02000h
numdef LOAD_MIN_PARA, paras(1536) numdef LOAD_MIN_PARA, paras(4096)
numdef EXEC_SEG_ADJ, 0 numdef EXEC_SEG_ADJ, 0
numdef EXEC_OFS, 400h numdef EXEC_OFS, 400h
numdef CHECKOFFSET, 1020 numdef CHECKOFFSET, 1020
@ -613,19 +625,73 @@ start:
ADR_STACK_START equ _LASTVARIABLE -start+POSITION ADR_STACK_START equ _LASTVARIABLE -start+POSITION
%ifn _FIX_CLUSTER_SIZE
; (word) actual sectors per cluster
nextvariable adj_sectors_per_cluster, 2, relocatestart
%endif
%ifn _FIX_SECTOR_SIZE %ifn _FIX_SECTOR_SIZE
; (word) number of 16-byte paragraphs per sector ; (word) number of 16-byte paragraphs per sector
nextvariable para_per_sector, 2, relocatestart nextvariable para_per_sector, 2, relocatestart
%endif %endif
%assign DIRSEARCHSTACK_CL_FIRST 0
%assign DIRSEARCHSTACK_CL_SECOND 0
%assign PLACEHOLDER 0
%if _ATTRIB_SAVE && ! (_ADD_SEARCH || _LOAD_DIR_SEG)
%if _LASTVARIABLE == start - 12h
%assign DIRSEARCHSTACK_CL_FIRST 1
%elif _LASTVARIABLE == start - 10h
%assign DIRSEARCHSTACK_CL_SECOND 1
%endif
%ifn _DIR_ENTRY_500
; three words left on the stack after directory search
nextvariable dirsearchstack, 6, relocatestart
%else
; two words left on the stack after directory search
nextvariable dirsearchstack, 4, relocatestart
%endif
%elifn !_RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL
%if _LASTVARIABLE == start - 12h
nextvariable cmdline_signature_placeholder, 2, relocatestart
%assign PLACEHOLDER 1
%elif _LASTVARIABLE == start - 10h
%if _PUSH_DPT
nextvariable cmdline_signature_placeholder, 4, relocatestart
%assign PLACEHOLDER 2
; In this case, part of the original DPT pointer may
; overlap the CL signature word. Therefore allocate
; two placeholder words to insure no CL match.
%else
; In this case the last_available_sector variable
; will be at word [ss:bp - 12h] (or none) and the
; stack pointer will be equal to bp - 12h (or - 10h)
; at handover time. Thus no placeholder is needed.
%endif
%else
%error Placeholder not placed
%endif
; This stack slot is used to insure that
; the "CL" signature is not present at this
; location. If not relocate and load address
; is below loader then the next variable
; (last_available_sector) will always receive
; a value < 7C0h so cannot hold "CL".
; If _ATTRIB_SAVE is in use and neither the
; _ADD_SEARCH nor the _LOAD_DIR_SEG options
; are set, the first word of dirsearchstack
; will be at word [ss:bp - 14h].
%endif
%ifn ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE %ifn ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE
; (word) segment of last available memory for sector ; (word) segment of last available memory for sector
nextvariable last_available_sector, 2 nextvariable last_available_sector, 2
%else
%if _LASTVARIABLE == start - 12h
nextvariable cmdline_signature_placeholder, 2, relocatestart
%assign PLACEHOLDER 1
%elif _LASTVARIABLE == start - 10h
%if _PUSH_DPT
nextvariable cmdline_signature_placeholder, 4, relocatestart
%assign PLACEHOLDER 2
%endif
%endif
%endif %endif
lowest_variable equ _LASTVARIABLE lowest_variable equ _LASTVARIABLE
@ -706,8 +772,6 @@ add_name:
; This happens to be aligned anyway. But even if ; This happens to be aligned anyway. But even if
; it didn't, we'd rather save that byte than use ; it didn't, we'd rather save that byte than use
; it to align these fields. So comment this out. ; it to align these fields. So comment this out.
filename:
dw add_name
dirseg: dirseg:
dw _ADD_DIR_SEG dw _ADD_DIR_SEG
%endif %endif
@ -724,6 +788,8 @@ dirseg:
[list -] [list -]
%else %else
; === error.tmp === ; === error.tmp ===
error_start:
read_sector.err: read_sector.err:
mov al, 'R' ; Disk 'R'ead error mov al, 'R' ; Disk 'R'ead error
%if ! _MEMORY_CONTINUE || _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM %if ! _MEMORY_CONTINUE || _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM
@ -751,6 +817,11 @@ error:
int 16h int 16h
int 19h ; re-start the boot process int 19h ; re-start the boot process
%if _WARN_PART_SIZE
%assign num $ - error_start
%warning error size is num bytes
%endif
; === eof === ; === eof ===
%endif %endif
%if _TMPINC %if _TMPINC
@ -765,6 +836,7 @@ error:
[list -] [list -]
%else %else
; === read.tmp === ; === read.tmp ===
read_sector_start:
; INP: dx:ax = sector ; INP: dx:ax = sector
; OUT: only if successful ; OUT: only if successful
; dx:ax = incremented ; dx:ax = incremented
@ -775,8 +847,24 @@ error:
%if ADR_DIRBUF == ADR_FATBUF %if ADR_DIRBUF == ADR_FATBUF
read_sector_dirbuf: read_sector_dirbuf:
%endif %endif
%if _FAT16 && ! _LOAD_NON_FAT
read_sector_fatbuf: read_sector_fatbuf:
%endif
%if (ADR_DIRBUF == ADR_FATBUF) || (_FAT16 && ! _LOAD_NON_FAT)
mov bx, ADR_FATBUF>>4 mov bx, ADR_FATBUF>>4
%if _FAT16 && _SET_FAT_SEG && ! _LOAD_NON_FAT
mov word [VAR(fat_seg)], bx
; Optimisation: Set FAT buffer segment here where
; we have it ready in a register, instead of
; wasting a word immediate on it. If the FAT is
; never read then we do not need to set the
; variable anyway, only the sector variable has
; to contain a -1 to indicate it's uninitialised.
; If we get here from read_sector_dirbuf we will
; also initialise this variable but that does not
; cause any problems.
%endif
%endif
%endif %endif
; Read a sector using Int13.02 or Int13.42 ; Read a sector using Int13.02 or Int13.42
@ -797,7 +885,7 @@ read_sector:
push ax push ax
push si push si
push bx mov es, bx ; => buffer
; DX:AX==LBA sector number ; DX:AX==LBA sector number
; add partition start (= number of hidden sectors) ; add partition start (= number of hidden sectors)
@ -839,17 +927,22 @@ read_sector:
jc .no_lba jc .no_lba
cmp bx, 0AA55h cmp bx, 0AA55h
jne .no_lba jne .no_lba
test cl, 1 ; support bitmap bit 0 shr cl, 1 ; support bitmap bit 0
jz .no_lba jnc .no_lba
%endif %endif
%if _LBA_RETRY %if _LBA_RETRY
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h mov ah, 42h
int 13h ; 13.42 extensions read int 13h ; 13.42 extensions read
jnc .lba_done jnc .lba_done
%if _RETRY_RESET
xor ax, ax xor ax, ax
int 13h int 13h ; reset disk
%endif
; have to reset the LBAPACKET's lpCount, as the handler may ; have to reset the LBAPACKET's lpCount, as the handler may
; set it to "the number of blocks successfully transferred". ; set it to "the number of blocks successfully transferred".
@ -857,10 +950,17 @@ read_sector:
mov byte [si + 2], 1 mov byte [si + 2], 1
%endif %endif
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h mov ah, 42h
int 13h int 13h
%if _LBA_SKIP_CHECK && _CHS %if _LBA_SKIP_CHECK && _CHS
%if _LBA_SKIP_ANY
jc .no_lba
%else
jc .lba_check_error_1 jc .lba_check_error_1
%endif
%else %else
.cy_err: .cy_err:
jc .lba_error jc .lba_error
@ -871,10 +971,8 @@ read_sector:
mov byte [bp + 2], 0Eh ; LBA-enabled FAT16 FS partition type mov byte [bp + 2], 0Eh ; LBA-enabled FAT16 FS partition type
%endif %endif
add sp, 10h add sp, 10h
pop bx
mov es, bx
%if _CHS %if _CHS
jmp short .chs_done jmp short .done
%endif %endif
.lba_error: equ .err .lba_error: equ .err
@ -883,10 +981,12 @@ read_sector:
.no_lba: equ .err .no_lba: equ .err
%else %else
%if _LBA_SKIP_CHECK %if _LBA_SKIP_CHECK
%if ! _LBA_SKIP_ANY
.lba_check_error_1: .lba_check_error_1:
cmp ah, 1 ; invalid function? cmp ah, 1 ; invalid function?
jne .lba_error ; no, other error --> jne .lba_error ; no, other error -->
; try CHS instead ; try CHS instead
%endif
.cy_err: equ .err .cy_err: equ .err
%endif %endif
.no_lba: .no_lba:
@ -955,29 +1055,50 @@ read_sector:
; we call INT 13h AH=02h once for each sector. Multi-sector reads ; we call INT 13h AH=02h once for each sector. Multi-sector reads
; may fail if we cross a track or 64K boundary ; may fail if we cross a track or 64K boundary
pop es
%if _CHS_RETRY_REPEAT %if _CHS_RETRY_REPEAT
mov si, _CHS_RETRY_REPEAT + 1 mov si, _CHS_RETRY_REPEAT + 1
%if _CHS_RETRY_NORMAL && _RETRY_RESET
db __TEST_IMM16 ; (skip int 13h)
.loop_chs_retry_repeat:
int 13h ; reset disk
%elif _RETRY_RESET
.loop_chs_retry_repeat: .loop_chs_retry_repeat:
mov ax, 0201h
int 13h ; read one sector
jnc .done
xor ax, ax xor ax, ax
int 13h ; reset disk int 13h ; reset disk
%else
.loop_chs_retry_repeat:
%endif
dec si ; another attempt ? dec si ; another attempt ?
jnz .loop_chs_retry_repeat ; yes --> js .nz_err ; no -->
jmp .err
%else
%if _CHS_RETRY
mov ax, 0201h mov ax, 0201h
int 13h ; read one sector int 13h ; read one sector
%if _CHS_RETRY_NORMAL && _RETRY_RESET
mov ax, bx ; ax = 0
%endif
jc .loop_chs_retry_repeat
; fall through to .done
%else
mov ax, 0201h
%if _CHS_RETRY
%if _RETRY_RESET
; In this case we cannot store to the stack and
; pop the value at the right moment for both
; cases of the "jnc .done" branch. So use the
; original code to re-init ax to 0201h.
int 13h ; read one sector
jnc .done jnc .done
; reset drive ; reset drive
xor ax, ax xor ax, ax
int 13h int 13h
mov ax, 0201h
%else
push ax
int 13h ; read one sector
pop ax ; restore ax = 0201h
jnc .done
%endif
%endif %endif
; try read again ; try read again
mov ax, 0201h
int 13h int 13h
%if _LBA_SKIP_CHECK %if _LBA_SKIP_CHECK
inc bx inc bx
@ -987,12 +1108,11 @@ read_sector:
%endif %endif
%endif %endif
%endif ; _CHS
.done: .done:
; increment segment ; increment segment
mov bx, es mov bx, es
%endif
.chs_done:
%if _FIX_SECTOR_SIZE %if _FIX_SECTOR_SIZE
add bx, _FIX_SECTOR_SIZE >> 4 add bx, _FIX_SECTOR_SIZE >> 4
%else %else
@ -1010,6 +1130,11 @@ read_sector:
@@: @@:
retn retn
%if _WARN_PART_SIZE
%assign num $ - read_sector_start
%warning read_sector size is num bytes
%endif
; === eof === ; === eof ===
%endif %endif
%if _TMPINC %if _TMPINC
@ -1020,6 +1145,11 @@ read_sector:
[list +] [list +]
%endif %endif
%if _WARN_PART_SIZE
%assign num $ - start
%warning BPB + data size is num bytes
%endif
; Code ; Code
@ -1045,6 +1175,8 @@ skip_bpb:
; FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected ; FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected
; as a valid partition table entry by this handling. Therefore, we ; as a valid partition table entry by this handling. Therefore, we
; only accept partition information when booting from a hard disk now. ; only accept partition information when booting from a hard disk now.
; start of magic byte sequence for instsect
test dl, dl ; floppy ? test dl, dl ; floppy ?
jns @F ; don't attempt detection --> jns @F ; don't attempt detection -->
; Check whether an MBR left us partition information. ; Check whether an MBR left us partition information.
@ -1058,15 +1190,23 @@ skip_bpb:
; Assume the movsw instructions won't run with si = FFFFh. ; Assume the movsw instructions won't run with si = FFFFh.
mov di, hidden_sectors ; -> BPB field mov di, hidden_sectors ; -> BPB field
add si, 8 ; -> partition start sector in info add si, 8 ; -> partition start sector in info
%if _USE_PART_INFO_DISABLED
nop
nop ; size has to match enabled code
%else
movsw movsw
movsw ; overwrite BPB field with value from info movsw ; overwrite BPB field with value from info
%endif
@@: @@:
; end of magic byte sequence for instsect
%endif %endif
mov ds, cx mov ds, cx
sti sti
%if _QUERY_GEOMETRY ; +27 bytes %if _QUERY_GEOMETRY ; +27 bytes
; start of magic byte sequence for instsect
; test dl, dl ; floppy? ; test dl, dl ; floppy?
; jns @F ; don't attempt query, might fail --> ; jns @F ; don't attempt query, might fail -->
; Note that while the original PC BIOS doesn't support this function ; Note that while the original PC BIOS doesn't support this function
@ -1076,7 +1216,12 @@ skip_bpb:
; xor cx, cx ; initialise cl to 0 ; xor cx, cx ; initialise cl to 0
; Already from prologue cx = 0. ; Already from prologue cx = 0.
stc ; initialise to CY stc ; initialise to CY
%if _QUERY_GEOMETRY_DISABLED
nop
nop ; size has to match enabled code
%else
int 13h ; query drive geometry int 13h ; query drive geometry
%endif
jc @F ; apparently failed --> jc @F ; apparently failed -->
and cx, 3Fh ; get sectors and cx, 3Fh ; get sectors
jz @F ; invalid (S is 1-based), don't use --> jz @F ; invalid (S is 1-based), don't use -->
@ -1085,6 +1230,7 @@ skip_bpb:
inc cx ; cx = number of heads (H is 0-based) inc cx ; cx = number of heads (H is 0-based)
mov [VAR(heads)], cx mov [VAR(heads)], cx
@@: @@:
; end of magic byte sequence for instsect
%endif %endif
%if _FIX_SECTOR_SIZE %if _FIX_SECTOR_SIZE
@ -1100,15 +1246,6 @@ skip_bpb:
mov al, 'C' mov al, 'C'
jne error jne error
%endif %endif
%else
; calculate some values that we need:
; adjusted sectors per cluster (store in a word,
; and decode EDR-DOS's special value 0 meaning 256)
xor ax, ax
mov al, [VAR(sectors_per_cluster)]
dec al
inc ax
push ax ; push into word [VAR(adj_sectors_per_cluster)]
%endif %endif
mov ch, 0 ; ! ch = 0 mov ch, 0 ; ! ch = 0
%else %else
@ -1123,16 +1260,7 @@ skip_bpb:
jne error jne error
%endif %endif
%else %else
; calculate some values that we need:
; adjusted sectors per cluster (store in a word,
; and decode EDR-DOS's special value 0 meaning 256)
; ! ch = 0 ; ! ch = 0
mov cl, [VAR(sectors_per_cluster)]
; therefore cx = sectors_per_cluster
dec cl
inc cx
push cx ; push into word [VAR(adj_sectors_per_cluster)]
dec cx ; ! ch = 0
%endif %endif
push bx ; push into word [VAR(para_per_sector)] push bx ; push into word [VAR(para_per_sector)]
@ -1140,6 +1268,14 @@ skip_bpb:
shr bx, 1 ; /2 = 32-byte entries per sector shr bx, 1 ; /2 = 32-byte entries per sector
%endif %endif
%if _WARN_PART_SIZE
%assign num $ - skip_bpb
%warning init size is num bytes
%endif
dirsearch_start:
; number of sectors used for root directory (store in CX) ; number of sectors used for root directory (store in CX)
mov si, [VAR(num_root_dir_ents)] mov si, [VAR(num_root_dir_ents)]
mov ax, bx mov ax, bx
@ -1194,21 +1330,48 @@ next_sect:
xor di, di ; es:di-> first entry in this sector xor di, di ; es:di-> first entry in this sector
next_ent: next_ent:
%if DIRSEARCHSTACK_CL_FIRST
push cx ; first dirsearchstack word = entries-in-sector
push si ; other: entries total
%else
push si push si
push di push cx ; second dirsearchstack word = entries-in-sector
push cx %endif
push di ; dirsearchstack
%if _CHECK_ATTRIB && ! _ATTRIB_SAVE
test byte [es:di + deAttrib], ATTR_DIRECTORY | ATTR_VOLLABEL
jnz @F ; directory, label, or LFN entry --> (NZ)
%endif
%if _ADD_SEARCH %if _ADD_SEARCH
mov si, [VAR(filename)] mov si, add_name
filename equ $ - 2 ; SMC to update to load_name later
%else %else
mov si, load_name ; ds:si-> name to match mov si, load_name ; ds:si-> name to match
%endif %endif
mov cx, 11 ; length of padded 8.3 FAT filename mov cx, 11 ; length of padded 8.3 FAT filename
repe cmpsb ; check entry repe cmpsb ; check entry
pop cx %if _ATTRIB_SAVE
%if _CHECK_ATTRIB
jnz @F
; deAttrib == 11, right after the 11-byte name
test byte [es:di], ATTR_DIRECTORY | ATTR_VOLLABEL
; directory, label, or LFN entry ?
%endif
jz found_it ; found entry -->
%endif
@@:
pop di pop di
%if DIRSEARCHSTACK_CL_FIRST
pop si pop si
pop cx ; pop from dirsearchstack
%else
pop cx
pop si ; pop from dirsearchstack
%endif
lea di, [di + DIRENTRY_size] lea di, [di + DIRENTRY_size]
je found_it ; found entry --> %if ! _ATTRIB_SAVE
jz found_it ; found entry -->
%endif
dec si ; count down entire root's entries dec si ; count down entire root's entries
loopnz next_ent ; count down sector's entries (jumps iff si >0 && cx >0) loopnz next_ent ; count down sector's entries (jumps iff si >0 && cx >0)
@ -1249,9 +1412,14 @@ Reference: https://bugs.launchpad.net/qemu/+bug/1888165
found_it: found_it:
%if _ADD_SEARCH || _LOAD_DIR_SEG %if _ADD_SEARCH || _LOAD_DIR_SEG
%if _ATTRIB_SAVE
pop di ; es:di -> dir entry (pop from dirsearchstack)
%endif
mov cx, 32 mov cx, 32
mov ax, _LOAD_DIR_SEG mov ax, _LOAD_DIR_SEG
%if ! _ATTRIB_SAVE
sub di, cx ; es:di -> dir entry sub di, cx ; es:di -> dir entry
%endif
%if _ADD_SEARCH %if _ADD_SEARCH
xchg ax, word [VAR(dirseg)] xchg ax, word [VAR(dirseg)]
%endif %endif
@ -1281,12 +1449,18 @@ found_it:
%else %else
%error Must not store directory entries to same segment %error Must not store directory entries to same segment
%endif %endif
%if _ATTRIB_SAVE
pop si ; discard cx/si
pop si ; discard si/cx (dirsearchstack)
%endif
pop si pop si
pop ax pop ax
pop dx ; restore root start and count pop dx ; restore root start and count
; (bx still holds entries per sector) ; (bx still holds entries per sector)
je next_dir_search ; jump to search load file next --> je next_dir_search ; jump to search load file next -->
%endif %endif
times PLACEHOLDER push bx
; push into cmdline_signature_placeholder
%if _RELOCATE %if _RELOCATE
push word [es:di + deClusterLow] push word [es:di + deClusterLow]
; (word on stack) = first cluster number ; (word on stack) = first cluster number
@ -1294,10 +1468,14 @@ found_it:
%else %else
%if _DIR_ENTRY_500 ; +24 bytes, probably %if _DIR_ENTRY_500 ; +24 bytes, probably
mov cx, 32 mov cx, 32
push ds %if _ATTRIB_SAVE
push es pop si ; es:si -> dir entry (pop from dirsearchstack)
%else
xchg si, di xchg si, di
sub si, cx sub si, cx
%endif
push ds
push es
push es push es
pop ds ; ds:si -> directory entry pop ds ; ds:si -> directory entry
xor ax, ax xor ax, ax
@ -1312,14 +1490,30 @@ found_it:
pop ds pop ds
xchg si, di ; es:di -> behind (second) directory entry xchg si, di ; es:di -> behind (second) directory entry
%endif %endif
times PLACEHOLDER push bx
; push into cmdline_signature_placeholder
; Push the entries per sector value into this
; stack slot to ensure that it does not hold "CL".
%if _RELOCATE %if _RELOCATE
%if _DIR_ENTRY_500 || !_ATTRIB_SAVE
push word [es:di + deClusterLow - DIRENTRY_size \ push word [es:di + deClusterLow - DIRENTRY_size \
- (DIRENTRY_size * !!_DIR_ENTRY_520)] - (DIRENTRY_size * !!_DIR_ENTRY_520)]
; (word on stack) = first cluster number ; (word on stack) = first cluster number
%else
push word [es:di + deClusterLow - (deName + 11)]
; (word on stack) = first cluster number
%endif
%endif %endif
%endif %endif
%if _WARN_PART_SIZE
%assign num $ - dirsearch_start
%warning dirsearch size is num bytes
%endif
%if _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM %if _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM
memory_start:
; Get conventional memory size and store it ; Get conventional memory size and store it
int 12h int 12h
mov cl, 6 mov cl, 6
@ -1406,6 +1600,11 @@ found_it:
rep movsw ; relocate stack, sector rep movsw ; relocate stack, sector
retf ; jump to relocated code retf ; jump to relocated code
%if _WARN_PART_SIZE
%assign num $ - memory_start
%warning memory size is num bytes
%endif
readhandler readhandler
@ -1442,10 +1641,13 @@ relocated:
push ax ; push into word [VAR(last_available_sector)] push ax ; push into word [VAR(last_available_sector)]
%endif %endif
read_fat_start:
; get starting cluster of file ; get starting cluster of file
%if ! _RELOCATE %if ! _RELOCATE
%if _ADD_SEARCH || _LOAD_DIR_SEG %if _ADD_SEARCH || _LOAD_DIR_SEG
mov si,[es:di + deClusterLow] mov si,[es:di + deClusterLow]
%elif _ATTRIB_SAVE && ! _DIR_ENTRY_500
mov si,[es:di - deAttrib + deClusterLow]
%else %else
mov si,[es:di + deClusterLow - DIRENTRY_size \ mov si,[es:di + deClusterLow - DIRENTRY_size \
- (DIRENTRY_size * !!_DIR_ENTRY_520)] - (DIRENTRY_size * !!_DIR_ENTRY_520)]
@ -1510,10 +1712,9 @@ relocated:
mov bx, _LOAD_ADR>>4 ; => load address mov bx, _LOAD_ADR>>4 ; => load address
%if _FAT16 && !_LOAD_NON_FAT %if _FAT16 && !_LOAD_NON_FAT
mov di, -1 ; = no FAT sector read yet mov di, -1 ; = no FAT sector read yet
%if _SET_FAT_SEG %if _SET_FAT_SEG && _SET_FAT_SEG_NORMAL
%if ! _RELOCATE ; This is not strictly needed because a FAT sector is
mov word [VAR(fat_seg)], ADR_FATBUF>>4 ; read in any case, initialising this variable later.
%endif
mov word [VAR(fat_sector)], di mov word [VAR(fat_sector)], di
%endif %endif
%endif %endif
@ -1637,7 +1838,10 @@ next_cluster:
%else ; _LOAD_NON_FAT %else ; _LOAD_NON_FAT
mov di, _LOAD_NON_FAT mov di, _LOAD_NON_FAT
mov ax, word [VAR(adj_sectors_per_cluster)] mov al, [VAR(sectors_per_cluster)]
dec ax
mov ah, 0
inc ax
mov cx, ax mov cx, ax
mul word [VAR(bytes_per_sector)] mul word [VAR(bytes_per_sector)]
test dx, dx test dx, dx
@ -1656,7 +1860,12 @@ next_cluster:
%if _FIX_CLUSTER_SIZE %if _FIX_CLUSTER_SIZE
mov cx, _FIX_CLUSTER_SIZE mov cx, _FIX_CLUSTER_SIZE
%else %else
mov cx, [VAR(adj_sectors_per_cluster)] ; adjusted sectors per cluster
; decode EDR-DOS's special value 0 meaning 256
mov cl, [VAR(sectors_per_cluster)]
dec cx
mov ch, 0
inc cx
%endif %endif
%endif %endif
@ -1669,7 +1878,7 @@ next_cluster:
; xxx - this will always load an entire cluster (e.g. 64 sectors), ; xxx - this will always load an entire cluster (e.g. 64 sectors),
; even if the file is shorter than this ; even if the file is shorter than this
@@: @@:
%if _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE %if ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE
cmp bx, (ADR_FREE_UNTIL >> 4) - (_FIX_SECTOR_SIZE >> 4) cmp bx, (ADR_FREE_UNTIL >> 4) - (_FIX_SECTOR_SIZE >> 4)
%else %else
cmp bx, [VAR(last_available_sector)] cmp bx, [VAR(last_available_sector)]
@ -1708,8 +1917,21 @@ next_cluster:
%endif ; _LOAD_NON_FAT %endif ; _LOAD_NON_FAT
@@: @@:
%if _WARN_PART_SIZE
%assign num $ - read_fat_start
%warning read_fat size is num bytes
%endif
finish_start:
%if _LOAD_MIN_PARA %if _LOAD_MIN_PARA
%if ((_LOAD_ADR >> 4) + _LOAD_MIN_PARA) & 255 == 0
; If the value is divisible by 256 we can compare only the
; high byte for the same CF result: NC iff bx >= limit.
cmp bh, ((_LOAD_ADR >> 4) + _LOAD_MIN_PARA) >> 8
%else
cmp bx, (_LOAD_ADR >> 4) + _LOAD_MIN_PARA cmp bx, (_LOAD_ADR >> 4) + _LOAD_MIN_PARA
%endif
mov al, 'E' mov al, 'E'
jb error jb error
%endif %endif
@ -1827,6 +2049,12 @@ CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET
jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS
%if _WARN_PART_SIZE
%assign num $ - finish_start
%warning finish size is num bytes
%endif
%if ! _RELOCATE %if ! _RELOCATE
errorhandler errorhandler

View File

@ -44,7 +44,9 @@ Public domain by C. Masloch, 2012
numdef ADD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere) numdef ADD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere)
numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access)
numdef QUERY_GEOMETRY_DISABLED, 0
numdef USE_PART_INFO, 1 ; use ds:si-> partition info from MBR, if any numdef USE_PART_INFO, 1 ; use ds:si-> partition info from MBR, if any
numdef USE_PART_INFO_DISABLED, 0
numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl
numdef RPL, 1 ; support RPL and do not overwrite it numdef RPL, 1 ; support RPL and do not overwrite it
numdef CHS, 1 ; support CHS (if it fits) numdef CHS, 1 ; support CHS (if it fits)
@ -75,11 +77,18 @@ Public domain by C. Masloch, 2012
numdef FIX_CLUSTER_SIZE_SKIP_CHECK, 0 ; don't check cluster size numdef FIX_CLUSTER_SIZE_SKIP_CHECK, 0 ; don't check cluster size
numdef NO_LIMIT, 0 ; allow using more memory than a boot sector numdef NO_LIMIT, 0 ; allow using more memory than a boot sector
; also will not write 0AA55h signature! ; also will not write 0AA55h signature!
numdef WARN_PART_SIZE, 0
numdef LBA_SKIP_CHECK, 1 ; don't use proper LBA extensions check numdef LBA_SKIP_CHECK, 1 ; don't use proper LBA extensions check
numdef LBA_SKIP_CY, 1 ; skip check: set up CY before 13.42
numdef LBA_SKIP_ANY, 0 ; skip check: try CHS on any error
incdef _LBA_SKIP_ANY, LBA_SKIP_CY
numdef LBA_RETRY, 0 ; retry LBA reads one time numdef LBA_RETRY, 0 ; retry LBA reads one time
numdef CHS_RETRY, 1 ; retry CHS reads one time numdef CHS_RETRY, 1 ; retry CHS reads one time
numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times
; (value of the def is used as count) ; (value of the def is used as count)
numdef CHS_RETRY_NORMAL,1 ; do not use aggressive optimisation
numdef RETRY_RESET, 1 ; call reset disk system 13.00 on retries
; Unlike the 1440 KiB diskette image defaults for the FAT12 ; Unlike the 1440 KiB diskette image defaults for the FAT12
; loader we just fill the BPB with zeros by default. ; loader we just fill the BPB with zeros by default.
@ -615,6 +624,14 @@ fsiboot_table: ; this table is used by the FSIBOOT stage
; => directory sector buffer (one sector) ; => directory sector buffer (one sector)
%endif %endif
.writedirentry: dw writedirentry.loaddir .writedirentry: dw writedirentry.loaddir
; INP: es:bx -> found dir entry in dir sector buffer
; si:di = loaded sector-in-FAT
; CHG: ax, cx, dx
; STT: ss:bp -> boot sector
; ds = ss
; UP
; OUT: directory entry copied if so desired
; (is a no-op if not to copy dir entry)
.filename: dw .load_name .filename: dw .load_name
; -> name to search ; -> name to search
.minpara: dw _LOAD_MIN_PARA .minpara: dw _LOAD_MIN_PARA
@ -628,6 +645,11 @@ fsiboot_table: ; this table is used by the FSIBOOT stage
fsiboot_name: fsiboot_name:
fill 8, 32, db _FSIBOOTNAME fill 8, 32, db _FSIBOOTNAME
%if _WARN_PART_SIZE
%assign num $ - start
%warning BPB + data size is num bytes
%endif
; Code ; Code
@ -654,6 +676,8 @@ skip_bpb:
; FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected ; FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected
; as a valid partition table entry by this handling. Therefore, we ; as a valid partition table entry by this handling. Therefore, we
; only accept partition information when booting from a hard disk now. ; only accept partition information when booting from a hard disk now.
; start of magic byte sequence for instsect
test dl, dl ; floppy ? test dl, dl ; floppy ?
jns @F ; don't attempt detection --> jns @F ; don't attempt detection -->
; Check whether an MBR left us partition information. ; Check whether an MBR left us partition information.
@ -667,15 +691,23 @@ skip_bpb:
; Assume the movsw instructions won't run with si = FFFFh. ; Assume the movsw instructions won't run with si = FFFFh.
mov di, hidden_sectors ; -> BPB field mov di, hidden_sectors ; -> BPB field
add si, 8 ; -> partition start sector in info add si, 8 ; -> partition start sector in info
%if _USE_PART_INFO_DISABLED
nop
nop ; size has to match enabled code
%else
movsw movsw
movsw ; overwrite BPB field with value from info movsw ; overwrite BPB field with value from info
%endif
@@: @@:
; end of magic byte sequence for instsect
%endif %endif
mov ds, cx mov ds, cx
sti sti
%if _QUERY_GEOMETRY ; +27 bytes %if _QUERY_GEOMETRY ; +27 bytes
; start of magic byte sequence for instsect
; test dl, dl ; floppy? ; test dl, dl ; floppy?
; jns @F ; don't attempt query, might fail --> ; jns @F ; don't attempt query, might fail -->
; Note that while the original PC BIOS doesn't support this function ; Note that while the original PC BIOS doesn't support this function
@ -685,7 +717,12 @@ skip_bpb:
; xor cx, cx ; initialise cl to 0 ; xor cx, cx ; initialise cl to 0
; Already from prologue cx = 0. ; Already from prologue cx = 0.
stc ; initialise to CY stc ; initialise to CY
%if _QUERY_GEOMETRY_DISABLED
nop
nop ; size has to match enabled code
%else
int 13h ; query drive geometry int 13h ; query drive geometry
%endif
jc @F ; apparently failed --> jc @F ; apparently failed -->
and cx, 3Fh ; get sectors and cx, 3Fh ; get sectors
jz @F ; invalid (S is 1-based), don't use --> jz @F ; invalid (S is 1-based), don't use -->
@ -694,6 +731,7 @@ skip_bpb:
inc cx ; cx = number of heads (H is 0-based) inc cx ; cx = number of heads (H is 0-based)
mov [VAR(heads)], cx mov [VAR(heads)], cx
@@: @@:
; end of magic byte sequence for instsect
%endif %endif
@ -854,6 +892,13 @@ load_fsiboot:
%endif %endif
%if _WARN_PART_SIZE
%assign num $ - skip_bpb
%warning init size is num bytes
%endif
finish_start:
; INP: es:bx -> found dir entry in dir sector buffer ; INP: es:bx -> found dir entry in dir sector buffer
; si:di = loaded sector-in-FAT ; si:di = loaded sector-in-FAT
; CHG: ax, cx, dx ; CHG: ax, cx, dx
@ -1030,6 +1075,13 @@ CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET
; ss:bp-> boot sector with BPB ; ss:bp-> boot sector with BPB
jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS
%if _WARN_PART_SIZE
%assign num $ - finish_start
%warning finish size is num bytes
%endif
error_start:
error_fsiboot: error_fsiboot:
mov al,'I' mov al,'I'
@ -1057,6 +1109,11 @@ error:
int 19h ; re-start the boot process int 19h ; re-start the boot process
%if _WARN_PART_SIZE
%assign num $ - error_start
%warning error size is num bytes
%endif
; Read a sector using Int13.02 or Int13.42 ; Read a sector using Int13.02 or Int13.42
; ;
@ -1076,7 +1133,7 @@ read_sector:
push ax push ax
push si push si
push bx mov es, bx ; => buffer
; DX:AX==LBA sector number ; DX:AX==LBA sector number
; add partition start (= number of hidden sectors) ; add partition start (= number of hidden sectors)
@ -1118,17 +1175,22 @@ read_sector:
jc .no_lba jc .no_lba
cmp bx, 0AA55h cmp bx, 0AA55h
jne .no_lba jne .no_lba
test cl, 1 ; support bitmap bit 0 shr cl, 1 ; support bitmap bit 0
jz .no_lba jnc .no_lba
%endif %endif
%if _LBA_RETRY %if _LBA_RETRY
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h mov ah, 42h
int 13h ; 13.42 extensions read int 13h ; 13.42 extensions read
jnc .lba_done jnc .lba_done
%if _RETRY_RESET
xor ax, ax xor ax, ax
int 13h int 13h ; reset disk
%endif
; have to reset the LBAPACKET's lpCount, as the handler may ; have to reset the LBAPACKET's lpCount, as the handler may
; set it to "the number of blocks successfully transferred". ; set it to "the number of blocks successfully transferred".
@ -1136,15 +1198,24 @@ read_sector:
mov byte [si + 2], 1 mov byte [si + 2], 1
%endif %endif
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h mov ah, 42h
int 13h int 13h
%if _LBA_SKIP_CHECK && _CHS %if _LBA_SKIP_CHECK && _CHS
%if _LBA_SKIP_ANY
jc .no_lba
.err_CY: equ .err
.err_2: equ .err
%else
jnc .lba_done jnc .lba_done
cmp ah, 1 ; invalid function? cmp ah, 1 ; invalid function?
je .no_lba ; try CHS instead --> je .no_lba ; try CHS instead -->
.err_CY: .err_CY:
.err_2: .err_2:
jmp .lba_error jmp .lba_error
%endif
%else %else
.err_CY: .err_CY:
jc .lba_error jc .lba_error
@ -1156,10 +1227,8 @@ read_sector:
mov byte [bp + 2], 0Ch ; LBA-enabled FAT32 FS partition type mov byte [bp + 2], 0Ch ; LBA-enabled FAT32 FS partition type
%endif %endif
add sp, 10h add sp, 10h
pop bx
mov es, bx
%if _CHS %if _CHS
jmp short .chs_done jmp short .done
%endif %endif
.lba_error: equ .err .lba_error: equ .err
@ -1225,34 +1294,56 @@ read_sector:
; ah has bits set iff it was >= 4, indicating a cylinder >= 1024. ; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
or bl, ah ; collect set bits from ah or bl, ah ; collect set bits from ah
mov dl,[VAR(boot_unit)] ; dl = drive mov dl,[VAR(boot_unit)] ; dl = drive
.nz_err:
jnz .err_2 ; error if cylinder >= 1024 --> jnz .err_2 ; error if cylinder >= 1024 -->
; ! bx = 0 (for 13.02 call) ; ! bx = 0 (for 13.02 call)
; we call INT 13h AH=02h once for each sector. Multi-sector reads ; we call INT 13h AH=02h once for each sector. Multi-sector reads
; may fail if we cross a track or 64K boundary ; may fail if we cross a track or 64K boundary
pop es
%if _CHS_RETRY_REPEAT %if _CHS_RETRY_REPEAT
mov si, _CHS_RETRY_REPEAT + 1 mov si, _CHS_RETRY_REPEAT + 1
%if _CHS_RETRY_NORMAL && _RETRY_RESET
db __TEST_IMM16 ; (skip int 13h)
.loop_chs_retry_repeat:
int 13h ; reset disk
%elif _RETRY_RESET
.loop_chs_retry_repeat: .loop_chs_retry_repeat:
mov ax, 0201h
int 13h ; read one sector
jnc .done
xor ax, ax xor ax, ax
int 13h ; reset disk int 13h ; reset disk
%else
.loop_chs_retry_repeat:
%endif
dec si ; another attempt ? dec si ; another attempt ?
jnz .loop_chs_retry_repeat ; yes --> js .nz_err ; no -->
jmp .err_2
%else
%if _CHS_RETRY
mov ax, 0201h mov ax, 0201h
int 13h ; read one sector int 13h ; read one sector
%if _CHS_RETRY_NORMAL && _RETRY_RESET
mov ax, bx ; ax = 0
%endif
jc .loop_chs_retry_repeat
; fall through to .done
%else
mov ax, 0201h
%if _CHS_RETRY
%if _RETRY_RESET
; In this case we cannot store to the stack and
; pop the value at the right moment for both
; cases of the "jnc .done" branch. So use the
; original code to re-init ax to 0201h.
int 13h ; read one sector
jnc .done jnc .done
; reset drive ; reset drive
xor ax, ax xor ax, ax
int 13h int 13h
mov ax, 0201h
%else
push ax
int 13h ; read one sector
pop ax ; restore ax = 0201h
jnc .done
%endif
%endif %endif
; try read again ; try read again
mov ax, 0201h
int 13h int 13h
jc .err_CY jc .err_CY
%endif %endif
@ -1260,12 +1351,11 @@ read_sector:
.err_CY: equ .err .err_CY: equ .err
%endif %endif
%endif ; _CHS
.done: .done:
; increment segment ; increment segment
mov bx, es mov bx, es
%endif
.chs_done:
%if _FIX_SECTOR_SIZE %if _FIX_SECTOR_SIZE
add bx, _FIX_SECTOR_SIZE >> 4 add bx, _FIX_SECTOR_SIZE >> 4
%else %else
@ -1285,6 +1375,11 @@ read_sector:
.retn: .retn:
retn retn
%if _WARN_PART_SIZE
%assign num $ - read_sector
%warning read_sector size is num bytes
%endif
%if _ADD_SEARCH %if _ADD_SEARCH
add_name: ; = blank-padded 11-byte filename to search for add_name: ; = blank-padded 11-byte filename to search for
@ -1381,9 +1476,9 @@ fsiboot:
; adjusted sectors per cluster (store in a word, ; adjusted sectors per cluster (store in a word,
; and decode EDR-DOS's special value 0 meaning 256) ; and decode EDR-DOS's special value 0 meaning 256)
xor ax, ax
mov al, [VAR(sectors_per_cluster)] mov al, [VAR(sectors_per_cluster)]
dec al dec ax
mov ah, 0
inc ax inc ax
push ax ; push into word [VAR(adj_sectors_per_cluster)] push ax ; push into word [VAR(adj_sectors_per_cluster)]
dec ax ; ! ah = 0 dec ax ; ! ah = 0
@ -1483,13 +1578,11 @@ found_load_file:
jc ..@CY_3_fsiboot_error_badchain jc ..@CY_3_fsiboot_error_badchain
next_load_cluster: next_load_cluster:
push dx
push ax ; preserve cluster number for later
call clust_to_first_sector call clust_to_first_sector
; dx:ax = first sector of cluster ; dx:ax = first sector of cluster
; cx:bx = cluster value ; cx = adjusted sectors per cluster
push cx
push bx ; preserve cluster number for later
mov cx, [VAR(adj_sectors_per_cluster)]
; xxx - this will always load an entire cluster (e.g. 64 sectors), ; xxx - this will always load an entire cluster (e.g. 64 sectors),
; even if the file is shorter than this ; even if the file is shorter than this
@ -1510,8 +1603,8 @@ next_load_cluster:
jbe @F ; read enough --> jbe @F ; read enough -->
loop @BB loop @BB
pop bx pop ax
pop cx pop dx
call clust_next call clust_next
jnc next_load_cluster jnc next_load_cluster
@ -1536,10 +1629,11 @@ dirsearch:
jc fsiboot_error_badchain jc fsiboot_error_badchain
next_root_clust: next_root_clust:
push dx
push ax
call clust_to_first_sector call clust_to_first_sector
push cx ; dx:ax = first sector of cluster
push bx ; cx = adjusted sectors per cluster
mov cx, [VAR(adj_sectors_per_cluster)]
next_root_sect: next_root_sect:
push cx push cx
mov cx, [VAR(entries_per_sector)] mov cx, [VAR(entries_per_sector)]
@ -1572,8 +1666,8 @@ next_ent:
pop di pop di
pop cx pop cx
loop next_root_sect loop next_root_sect
pop bx pop ax
pop cx pop dx
call clust_next call clust_next
jnc next_root_clust jnc next_root_clust
file_not_found: file_not_found:
@ -1587,22 +1681,22 @@ fsiboot_error:
; INP: dx:ax = cluster - 2 (0-based cluster) ; INP: dx:ax = cluster - 2 (0-based cluster)
; OUT: cx:bx = input dx:ax ; OUT: dx:ax = first sector of that cluster
; dx:ax = first sector of that cluster ; cx = adjusted sectors per cluster
; CHG: - ; CHG: bx
clust_to_first_sector: clust_to_first_sector:
push dx mov cx, word [VAR(adj_sectors_per_cluster)]
push ax
push dx push dx
mul word [VAR(adj_sectors_per_cluster)] mul cx
xchg bx, ax xchg bx, ax
xchg cx, dx
pop ax pop ax
mul word [VAR(adj_sectors_per_cluster)] push dx
mul cx
test dx, dx test dx, dx
jnz fsiboot_error_badchain jnz fsiboot_error_badchain
xchg dx, ax xchg dx, ax
add dx, cx pop ax
add dx, ax
jc ..@CY_fsiboot_error_badchain jc ..@CY_fsiboot_error_badchain
xchg ax, bx xchg ax, bx
@ -1611,8 +1705,6 @@ clust_to_first_sector:
..@CY_fsiboot_error_badchain: ..@CY_fsiboot_error_badchain:
jc fsiboot_error_badchain jc fsiboot_error_badchain
; dx:ax = first sector in cluster ; dx:ax = first sector in cluster
pop bx
pop cx ; cx:bx = cluster
retn retn
@ -1638,16 +1730,14 @@ found_it:
retn retn
; INP: cx:bx = cluster (0-based) ; INP: dx:ax = cluster (0-based)
; si:di = loaded FAT sector, -1 if none ; si:di = loaded FAT sector, -1 if none
; OUT: CY if no next cluster ; OUT: CY if no next cluster
; NC if next cluster found, ; NC if next cluster found
; dx:ax = next cluster value (0-based) ; dx:ax = next cluster value (0-based)
; si:di = loaded FAT sector ; si:di = loaded FAT sector
; CHG: cx, bx, es ; CHG: cx, bx, es
clust_next: clust_next:
xchg ax, bx ; ax = low word cluster, clobbers bx
mov dx, cx
add ax, 2 add ax, 2
adc dx, 0 adc dx, 0

View File

@ -13,6 +13,7 @@
\cfg{html-leaf-level}{0} \cfg{html-leaf-level}{0}
\cfg{html-template-fragment}{%k}{%b} \cfg{html-template-fragment}{%k}{%b}
\cfg{html-head-end}{<meta name="viewport" content="width=device-width, initial-scale=1.0">} \cfg{html-head-end}{<meta name="viewport" content="width=device-width, initial-scale=1.0">}
\cfg{html-heading-hashtag-links}{true}
\cfg{pdf-filename}{ldosboot.pdf} \cfg{pdf-filename}{ldosboot.pdf}
@ -53,6 +54,27 @@ The entrypoint is found by applying no segment adjustment (0)
and choosing the offset 400h (1024). and choosing the offset 400h (1024).
\S{protocol-sector-iniload-file} File properties
The file must be at least 4096 bytes long.
This is now required, beyond the former lower bound of 1536 bytes,
to support an optimisation of the FAT12 and FAT16 boot sector loaders.
The lDebug loader and the FAT32+FSIBOOT loader currently retain the 1536 bytes limit.
The file may allow multi-use as a flat .COM format executable,
flat .SYS format device driver, or MZ .EXE format executable
and/or device driver.
It is also valid to append arbitrary sized data such as a .ZIP archive.
The file needs to be placed in the root directory for the boot sector loaders.
The lDebug loader allows to load a file
from any subdirectory and this is also allowed.
The file may be fragmented in any part.
The file data may be located anywhere in the file system.
The supported cluster sizes should be between 32 Bytes and 2 MiB, inclusive.
The sector size should be between 32 Bytes and 8 KiB, inclusive.
\S{protocol-sector-iniload-signatures} Signatures \S{protocol-sector-iniload-signatures} Signatures
At offset 1020 (3FCh) there is the signature \cq{lD}. At offset 1020 (3FCh) there is the signature \cq{lD}.
@ -79,6 +101,10 @@ Currently the following signatures are defined:
\dd lDDebug (debuggable lDebug) \dd lDDebug (debuggable lDebug)
\dt \cq{lDbC}
\dd lCDebug (conditionally debuggable lDebug)
\dt \cq{lDTP} \dt \cq{lDTP}
\dd lDOS test payload kernel (testpl.asm) \dd lDOS test payload kernel (testpl.asm)
@ -92,6 +118,7 @@ Currently the following signatures are defined:
Under this protocol, the pointer \cq{ss:bp} is passed. Under this protocol, the pointer \cq{ss:bp} is passed.
It points to a boot sector with (E)BPB. It points to a boot sector with (E)BPB.
\cq{bp} must be even for compatibility with older iniload (before 2023-March).
The stack pointer must be at most \cq{bp - 10h}. The stack pointer must be at most \cq{bp - 10h}.
Below the pointed to location there live the Load Stack Variables. Below the pointed to location there live the Load Stack Variables.
These follow this structure: These follow this structure:
@ -144,6 +171,7 @@ Allows iniload to determine how much of it is already loaded.
An LSV extension allows to pass a command line to the kernel. An LSV extension allows to pass a command line to the kernel.
The base pointer must be at least \cq{114h} then.
The stack pointer must be at most \cq{bp - 114h} then. The stack pointer must be at most \cq{bp - 114h} then.
This follows the structure like this: This follows the structure like this:
@ -179,8 +207,8 @@ must not equal the string \cq{CL}.
\b dosemu2's RxDOS.3 support sets \cq{sp = bp - 10h} \b dosemu2's RxDOS.3 support sets \cq{sp = bp - 10h}
\b ldosboot boot.asm (FAT12/FAT16) loader \b ldosboot boot.asm (FAT12/FAT16) loader
uses the variable for a \q{paragraphs per sector} value makes sure not to pass the variable with the content "CL".
which is always a power of two and always below-or-equal 200h. Refer to placeholder and DIRSEARCHSTACK_CL_FIRST uses in the source.
\b ldosboot boot32.asm (FAT32) loader \b ldosboot boot32.asm (FAT32) loader
uses the variable for an \q{entries per sector} value uses the variable for an \q{entries per sector} value
@ -190,6 +218,101 @@ which is always a power of two and always below-or-equal 100h.
sets \cq{sp = bp - 10h} sets \cq{sp = bp - 10h}
\S{protocol-sector-iniload-memory} Memory map
The initial loader part that is loaded must be loaded
at above or equal to linear 00600h.
The FAT buffer segment (if used) must also be stored
at above or equal to linear 00600h.
The stack (which should extend at least 512 bytes below \cq{ss:bp})
and boot sector (pointed to by \cq{ss:bp}, at least 512 bytes length)
should also be stored at above or equal to linear 00600h.
There is an additional memory area,
the Low Memory Area top reservation,
which should be unused by the load protocol at handoff time
but be at least 20 KiB in size.
It is located below the usable Low Memory Area top.
That is, directly below the EBDA, RPL-reserved memory, video memory,
or otherwise UMA.
This area is reserved in order to facilitate initial loader operation.
None of the memory areas may overlap.
This does not include the FAT buffer in case it is uninitialised.
\S{protocol-sector-iniload-loadname} Load filename in the boot sector
The boot sector may be expected to contain a valid
8.3 format (blank-padded FCB) filename
in the area of the boot sector starting behind the (E)BPB,
extending up to below the boot sector signature word with value AA55h
(at offset 510 in the boot sector).
This name should not contain blanks other than trailing in the
file name portion or trailing in the file extension portion.
It should consist of printable ASCII codepoints.
That is, byte values between 20h and 7Eh inclusive.
It should not consist of eleven times the same byte value.
Additional FAT Short File Name restrictions may be assumed.
Although a loader should not depend on this for crucial operation,
it may want to detect the kernel name it was presumably loaded from
for informational or optional purposes.
The canonical implementation of this is currently the function
\cq{findname} in the \cw{testpl.asm} test payload kernel.
It is found within
\W{https://hg.pushbx.org/ecm/ldosboot/file/e0c17723f953/testpl.asm#l668}{the ldosboot repo}.
This handling is based on the function of the same name
\W{https://hg.pushbx.org/ecm/instsect/file/53e4327aacd6/instsect.asm#l2442}{in the instsect application}.
\S{protocol-sector-iniload-patch} Query patch support
The ldosboot repo includes a patch Script for lDebug (.sld) file
which allows to patch the initial loader stage.
The patches concern handling of the CHS geometry detection,
and whether LBA or CHS access is used.
There are several legacy patch sites in which patch.sld
can directly patch the initial loader's code.
However, the preferred way is to find the query patch sequence.
It should appear within the first 1536 bytes,
that is within the part of the initial loader that must be loaded.
This is the sequence:
\c 8A5640 mov dl, byte [bp + 40h]
\c B8xxyy mov ax, yyxxh
\c 84D2 test dl, dl
\c 7902 jns @F
\c 86C4 xchg al, ah
\c @@:
The immediate word of the \cw{mov ax} instruction is to be patched.
The sequence should be scanned for without regard as to what
the current contents of this word are.
The following flag values are used:
\b 01h Force CHS access, do not detect LBA support with 13.41
\b 02h Force LBA access, do not detect LBA support with 13.41
\b 04h Force use of BPB's CHS geometry, do not detect with 13.08
\b 80h Used by lDebug. If this value is set for the load unit,
then lDebug will make use of the other flags set up for that unit.
The corresponding flags will be saved in lDebug's load_unit_flags.
This affects only the load unit (LD in lDebug terminology),
which suffices to pass commands in the startup Script for lDebug.
The flag 01h takes precedence over 02h if both are set.
The low byte (xxh) is used in case the loader loads
from a diskette unit, that is a unit number below 80h.
The high byte (yyh) is used otherwise, in case the loader loads
from a hard disk unit, that is a unit number above-or-equal 80h.
\H{protocol-iniload-payload} Iniload to payload protocol \H{protocol-iniload-payload} Iniload to payload protocol
The payload is loaded to an arbitrary segment. The payload is loaded to an arbitrary segment.
@ -236,7 +359,9 @@ Below the LSV, iniload passes the LOADDATA (1) structure.
\c ldHasLBA: resb 1 \c ldHasLBA: resb 1
\c ldClusterSize: resw 1 \c ldClusterSize: resw 1
\c ldParaPerSector:resw 1 \c ldParaPerSector:resw 1
\c ldLoadingSeg: resw 1 \c ldLoadingSeg:
\c ldQueryPatchValue:
\c resw 1
\c ldLoadUntilSeg: resw 1 \c ldLoadUntilSeg: resw 1
\c endstruc \c endstruc
@ -293,6 +418,15 @@ May be given as zero for non-FAT filesystems.
\dd Word. Internally used by iniload. \dd Word. Internally used by iniload.
Available for re-use by payload. Available for re-use by payload.
However, ldQueryPatchValue re-uses the same field.
\dt ldQueryPatchValue
\dd Word. Passes the query patch value from the initial loader.
This provides an opportunity to patch a well-known site
in the initial loader to change its behaviour in some ways.
Near the end of its operation, the initial loader
passes along this value in this variable for the next stage to use.
\dt ldLoadUntilSeg \dt ldLoadUntilSeg
@ -320,6 +454,6 @@ that is there is an empty command line
the terminator of which is followed by a byte with the value 0FFh, the terminator of which is followed by a byte with the value 0FFh,
then no command line was passed to iniload. then no command line was passed to iniload.
Currently lDebug can pass a command line to iniload when Currently lDebug can pass a command line to iniload when
loading with its lDOS, RxDOS.2, or RxDOS.3 protocols. loading with its lDOS, RxDOS.2, RxDOS.3, or FreeDOS protocols.
When iniload is loaded as a Multiboot1 or Multiboot2 specification kernel, When iniload is loaded as a Multiboot1 or Multiboot2 specification kernel,
it is also assumed that a command line can be passed. it is also assumed that a command line can be passed.

View File

@ -78,6 +78,7 @@ ldHasLBA: resb 1
ldClusterSize: resw 1 ldClusterSize: resw 1
ldParaPerSector:resw 1 ldParaPerSector:resw 1
ldLoadingSeg: ; word ldLoadingSeg: ; word
ldQueryPatchValue: ; word
lsvCommandLine: ; word lsvCommandLine: ; word
.start: equ $ - lsvclBufferLength .start: equ $ - lsvclBufferLength
.signature: resw 1 .signature: resw 1
@ -124,6 +125,14 @@ ptLinux: equ 83h
ptExtendedLinux: equ 85h ptExtendedLinux: equ 85h
query_no_geometry equ 4
query_no_chs equ 2
query_no_lba equ 1
query_fd_multiplier equ 1
query_hd_multiplier equ 256
query_all_multiplier equ query_fd_multiplier + query_hd_multiplier
%ifndef _MAP %ifndef _MAP
%elifempty _MAP %elifempty _MAP
%else ; defined non-empty, str or non-str %else ; defined non-empty, str or non-str
@ -132,6 +141,8 @@ ptExtendedLinux: equ 85h
defaulting defaulting
numdef QUERY_PATCH, 1 ; use new style patch of CHS/LBA/geometry
numdef QUERY_DEFAULT, 0
numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access)
numdef RPL, 1 ; support RPL and do not overwrite it numdef RPL, 1 ; support RPL and do not overwrite it
numdef CHS, 1 ; support CHS (if it fits) numdef CHS, 1 ; support CHS (if it fits)
@ -163,6 +174,7 @@ ptExtendedLinux: equ 85h
%include "inicheck.mac" %include "inicheck.mac"
%endif %endif
numdef PADDING, 0
strdef PAYLOAD_FILE, "lDOSLOAD.BIN" strdef PAYLOAD_FILE, "lDOSLOAD.BIN"
numdef EXEC_OFFSET, 0 numdef EXEC_OFFSET, 0
numdef EXEC_SEGMENT, 0 numdef EXEC_SEGMENT, 0
@ -328,8 +340,16 @@ ms6_entry:
d3 call d3_display_two_characters d3 call d3_display_two_characters
d3 test ax, "00" d3 test ax, "00"
; test dx, dx mov cx, cs
; jnz @FF cmp cx, 60h
jne @F
.freedos_or_msdos1_com_entry:
jmp freedos_or_msdos1_com_entry
@@:
; xor cx, cx
;; test dx, dx
;; jnz @FF
; Actual DOS will always put a zero word on top of ; Actual DOS will always put a zero word on top of
; the stack. But when the debugger loads us as ; the stack. But when the debugger loads us as
; a flat format binary it may set up another ; a flat format binary it may set up another
@ -339,15 +359,10 @@ d3 test ax, "00"
call @F call @F
@@: @@:
pop cx pop cx
cmp cx, @B + 100h sub cx, @B ; cx == 0 iff entered at offset 0
je msdos1_com_entry jne .freedos_or_msdos1_com_entry
@@: @@:
; cx = 0
mov cx, cs
cmp cx, 60h
je freedos_entry
xor cx, cx
; Note: It has been observed that some IBMBIO.COM / IO.SYS ; Note: It has been observed that some IBMBIO.COM / IO.SYS
; boot sector loaders pass the int 1Eh address on the ; boot sector loaders pass the int 1Eh address on the
@ -380,29 +395,50 @@ error:
int 16h int 16h
int 19h int 19h
disp_error:
.: disp_error.loop:
lodsb
test al, al
jz .ret
mov ah, 0Eh mov ah, 0Eh
mov bx, 7 mov bx, 7
; push bp ; push bp
; (call may change bp, but it is not used here any longer.) ; (call may change bp, but it is not used here any longer.)
int 10h int 10h
; pop bp ; pop bp
jmp short . disp_error:
lodsb
msg: test al, al
.error: db "Load error: ", 0 jnz .loop
retn
query_geometry: query_geometry:
%if _QUERY_GEOMETRY ; +30 bytes %if _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
; magic bytes start
mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
; magic bytes
%if _QUERY_PATCH
mov ax, _QUERY_DEFAULT ; magic bytes, checked by patch script
..@query_patch_site equ $ - 2
test dl, dl ; hard disk unit ?
jns @F ; no -->
xchg al, ah ; get high byte into al
; magic bytes end
@@:
%endif
%endif
%if _QUERY_GEOMETRY ; +30 bytes
%if !_LBA_SKIP_CHECK %if !_LBA_SKIP_CHECK
push dx push dx
%if _QUERY_PATCH
push ax
%endif
%endif %endif
%if _QUERY_PATCH
test al, 4 ; don't query geometry ?
jnz @F ; yes -->
%endif
; test dl, dl ; floppy? ; test dl, dl ; floppy?
; jns @F ; don't attempt query, might fail --> ; jns @F ; don't attempt query, might fail -->
; Note that while the original PC BIOS doesn't support this function ; Note that while the original PC BIOS doesn't support this function
@ -423,30 +459,38 @@ query_geometry:
%endif %endif
%if !_LBA_SKIP_CHECK %if !_LBA_SKIP_CHECK
mov ah, 41h
%if _QUERY_GEOMETRY %if _QUERY_GEOMETRY
pop dx %if _QUERY_PATCH
%else pop ax ; restore query patch flags in al
mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] %endif
pop dx ; restore unit number in dl
%endif %endif
%if _QUERY_PATCH
shr al, 1 ; CY if force CHS
jc @F ; if so -->
and al, 1 ; force LBA ?
jnz .done_lba ; yes -->
%endif
mov ah, 41h
mov bx, 55AAh mov bx, 55AAh
stc stc
int 13h ; 13.41.bx=55AA extensions installation check int 13h ; 13.41.bx=55AA extensions installation check
@@:
mov al, 0 ; zero in case of no LBA support mov al, 0 ; zero in case of no LBA support
jc .no_lba jc .no_lba
cmp bx, 0AA55h cmp bx, 0AA55h
jne .no_lba jne .no_lba
test cl, 1 ; support bitmap bit 0 shr cl, 1 ; support bitmap bit 0
jz .no_lba jnc .no_lba
inc ax ; al = 1 to indicate LBA support inc ax ; al = 1 to indicate LBA support
.no_lba: .no_lba:
.done_lba:
mov byte [bp + ldHasLBA], al mov byte [bp + ldHasLBA], al
%else %else
mov byte [bp + ldHasLBA], 0 mov byte [bp + ldHasLBA], 0
%endif %endif
%if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
disp_error.ret:
retn retn
%endif %endif
@ -474,7 +518,7 @@ read_sector:
push ax push ax
push si push si
push bx mov es, bx
; DX:AX==LBA sector number ; DX:AX==LBA sector number
; add partition start (= number of hidden sectors) ; add partition start (= number of hidden sectors)
@ -530,9 +574,9 @@ read_sector:
jne .lba_error jne .lba_error
; push word [si + 4 + 0] ; push word [si + 4 + 0]
push word [si + 4 + 2] ; user buffer push es ; => user buffer
push word [bp + ldSectorSeg] mov es, word [bp + ldSectorSeg]
pop word [si + 4 + 2] mov word [si + 4 + 2], es
; and word [si + 4 + 0], byte 0 ; and word [si + 4 + 0], byte 0
mov ah, 42h mov ah, 42h
@ -550,12 +594,12 @@ read_sector:
pop es pop es
; pop cx ; pop cx
call .sectorseg_helper add sp, 10h
jmp .sectorseg_helper_then_done
.lba_done: .lba_done:
add sp, 10h add sp, 10h
pop bx jmp short .done
jmp short .chs_done
.lba_error: equ .err .lba_error: equ .err
@ -640,7 +684,6 @@ read_sector:
; we call INT 13h AH=02h once for each sector. Multi-sector reads ; we call INT 13h AH=02h once for each sector. Multi-sector reads
; may fail if we cross a track or 64K boundary ; may fail if we cross a track or 64K boundary
pop es
mov ax, 0201h ; read one sector mov ax, 0201h ; read one sector
%if _CHS_RETRY %if _CHS_RETRY
@ -664,24 +707,42 @@ read_sector:
int 13h int 13h
%endif %endif
.err_CY_1: .err_CY_1:
jc .err jnc .sectorseg_helper_es
%endif ; _CHS
.err:
error_diskaccess: equ $
call error
db "Disk read error.", 0
%if _CHS
.sectorseg_helper_es:
pop es pop es
call .sectorseg_helper %endif
.sectorseg_helper_then_done:
xor si, si
mov ds, word [bp + ldSectorSeg]
push di
; mov di, cx
xor di, di
mov cx, word [bp + bsBPB + bpbBytesPerSector]
rep movsb
pop di
push ss
pop ds
.done: .done:
; increment segment ; increment segment
mov bx, es mov bx, es
%endif
.chs_done:
mov es, bx
add bx, word [bp + ldParaPerSector] add bx, word [bp + ldParaPerSector]
pop si pop si
pop ax pop ax
pop cx pop cx
pop dx pop dx
.increment_sector_number:
; increment LBA sector number ; increment LBA sector number
inc ax inc ax
jne @F jne @F
@ -703,21 +764,21 @@ read_sector:
; reset drive ; reset drive
xor ax, ax xor ax, ax
int 13h int 13h
jc @F ; CY, reset failed, error in ah --> jnc @FF ; NC, reset succeeded -->
; CY, reset failed, error in ah
; try read again
pop ax ; restore function number
%if _LBA
call .int13_preserve_lpcount
%else
int 13h ; retry, CF error status, ah error number
%endif
retn
@@: ; NC or CY, stack has function number @@: ; NC or CY, stack has function number
inc sp inc sp
inc sp ; discard word on stack, preserve CF inc sp ; discard word on stack, preserve CF
retn retn
@@:
; try read again
pop ax ; restore function number
%if ! _LBA
int 13h ; retry, CF error status, ah error number
retn
%endif ; else: fall through to .int13_preserve_lpcount
%endif %endif
%if _LBA %if _LBA
@ -736,24 +797,6 @@ read_sector:
retn retn
%endif %endif
.sectorseg_helper:
xor si, si
mov ds, word [bp + ldSectorSeg]
push di
; mov di, cx
xor di, di
mov cx, word [bp + bsBPB + bpbBytesPerSector]
rep movsb
pop di
push ss
pop ds
retn
.err:
error_diskaccess:
call error
db "Disk read error.", 0
error_shortfile: error_shortfile:
call error call error
@ -795,28 +838,25 @@ ms7_entry:
; load unit field set, hidden sectors set ; load unit field set, hidden sectors set
inc dx inc dx
dec dx ; "BJ" signature (apparently not about FAT32 support) dec dx ; "BJ" signature (apparently not about FAT32 support)
cli
cld
jmp .continue ; jump to handler above 600h (sector loads 800h bytes) jmp .continue ; jump to handler above 600h (sector loads 800h bytes)
.ms6_common: .ms6_common: ; cx = 0
mov ax, cs mov ax, 70h + ((3 * 512) >> 4) ; MS6 entry has 3 sectors loaded
add ax, (3 * 512) >> 4 ; (and is always segment 70h)
.continue2_set_extra_and_empty_cmdline: .continue2_set_extra_and_empty_cmdline: ; cx = 0, ax => behind loaded
%if _LSVEXTRA %if _LSVEXTRA
and word [bp + lsvExtra], 0 mov word [bp + lsvExtra], cx
%endif %endif
and word [bp + lsvCommandLine], 0 mov word [bp + lsvCommandLine], cx
.continue2: .continue2: ; cx = 0, ax => behind loaded
mov word [bp + lsvLoadSeg], ax mov word [bp + lsvLoadSeg], ax
xor ax, ax mov word [bp + lsvFATSeg], cx ; initialise to zero (for FAT12)
mov word [bp + lsvFATSeg], ax ; initialise to zero (for FAT12) dec cx
dec ax mov word [bp + lsvFATSector + 0], cx
mov word [bp + lsvFATSector + 0], ax mov word [bp + lsvFATSector + 2], cx ; initialise to -1
mov word [bp + lsvFATSector + 2], ax ; initialise to -1
; Actually it seems that the MS-DOS 7 loaders load 4 sectors ; Actually it seems that the MS-DOS 7 loaders load 4 sectors
; instead of only three (as the MS-DOS 6 loaders do). ; instead of only three (as the MS-DOS 6 loaders do).
@ -824,21 +864,30 @@ ms7_entry:
jmp ldos_entry.ms7_common jmp ldos_entry.ms7_common
msg:
.error: db "Load error: ", 0
finish_continue: finish_continue:
mov bx, cs
add ax, bx ; = cs + rounded up length add ax, bx ; = cs + rounded up length
sub ax, word [bp + ldLoadTop] ; = paras to move down sub ax, word [bp + ldLoadTop] ; = paras to move down
jbe short finish_load jbe short finish_load
push ax mov cx, word [bp + lsvLoadSeg]
; => after end of loaded data
sub word [bp + lsvLoadSeg], ax
; relocate this pointer already
neg ax neg ax
add ax, bx ; ax = cs - paras to move down add ax, bx ; ax = cs - paras to move down
; want to relocate cs to this
jnc short error_outofmemory_j1 jnc short error_outofmemory_j1
mov di, relocate_to mov di, relocate_to
push ax push ax
push di ; dword on stack: relocate_to push di ; dword on stack: relocate_to
cmp ax, 60h + 1 cmp ax, 60h + 1
jb short error_outofmemory_j1 jb short error_outofmemory_j1
push ax ; word on stack => where to relocate to
dec ax ; one less to allow relocator dec ax ; one less to allow relocator
mov es, ax mov es, ax
@ -850,17 +899,18 @@ finish_relocation:
push di ; dword on stack: relocator destination push di ; dword on stack: relocator destination
mov ds, bx ; ds => unrelocated cs mov ds, bx ; ds => unrelocated cs
inc ax ; ax => where to relocate to
mov si, relocator ; ds:si -> relocator mov si, relocator ; ds:si -> relocator
relocator_size equ relocator.end - relocator relocator_size equ relocator.end - relocator
%rep (relocator_size + 1) / 2 %rep (relocator_size + 1) / 2
movsw ; place relocator movsw ; place relocator
%endrep %endrep
mov es, ax %if relocator_size > 16
xor di, di ; -> where to relocate to %error Relocator is too large
%endif
xor di, di ; word [ss:sp+4]:di -> where to relocate to
xor si, si ; ds:si = cs:0 xor si, si ; ds:si = cs:0
mov cx, word [bp + lsvLoadSeg] ; cx => after end of loaded data
sub cx, bx ; length of currently loaded fragment sub cx, bx ; length of currently loaded fragment
mov bx, 1000h mov bx, 1000h
mov ax, cx mov ax, cx
@ -907,8 +957,6 @@ relocate_to:
test ax, ax ; another round needed? test ax, ax ; another round needed?
jnz @BB ; yes --> jnz @BB ; yes -->
pop ax
sub word [bp + lsvLoadSeg], ax
push ss push ss
pop ds pop ds
@ -926,7 +974,6 @@ finish_load:
; ldLoadUntilSeg => after last to-be-loaded paragraph ; ldLoadUntilSeg => after last to-be-loaded paragraph
mov bx, word [bp + lsvLoadSeg] mov bx, word [bp + lsvLoadSeg]
mov word [bp + ldLoadingSeg], bx
cmp bx, ax cmp bx, ax
jae short loaded_all_if_ae ; (for FreeDOS entrypoint) already loaded --> jae short loaded_all_if_ae ; (for FreeDOS entrypoint) already loaded -->
@ -940,32 +987,26 @@ finish_load:
jc short error_badchain_j jc short error_badchain_j
skip_next_clust: skip_next_clust:
push dx
push ax
call clust_to_first_sector call clust_to_first_sector
push cx
push bx
mov cx, [bp + ldClusterSize]
skip_next_sect: skip_next_sect:
push cx
mov bx, [bp + ldLoadingSeg] mov bx, [bp + ldLoadingSeg]
cmp bx, [bp + ldLoadUntilSeg] cmp bx, [bp + ldLoadUntilSeg]
jae loaded_all.3stack jae loaded_all.2stack
mov cx, bx add bx, [bp + ldParaPerSector]
add cx, [bp + ldParaPerSector] ; bx += paras per sector
cmp cx, [bp + lsvLoadSeg] cmp bx, [bp + lsvLoadSeg]
ja skipped_all ja skipped_all
inc ax ; emulate read_sector: ; emulate read_sector:
jnz @F call read_sector.increment_sector_number
inc dx ; dx:ax += 1 ; dx:ax += 1
@@:
mov bx, cx ; bx += paras per sector
mov [bp + ldLoadingSeg], bx mov [bp + ldLoadingSeg], bx
pop cx
loop skip_next_sect loop skip_next_sect
pop bx pop ax
pop cx pop dx
call clust_next call clust_next
jnc skip_next_clust jnc skip_next_clust
end_of_chain: end_of_chain:
@ -982,6 +1023,8 @@ loaded_all_if_ae:
skipped_all: skipped_all:
sub bx, [bp + ldParaPerSector]
; restore bx => next sector to read
call read_sector call read_sector
; we can depend on the fact that at least ; we can depend on the fact that at least
; up to end was already loaded, so this ; up to end was already loaded, so this
@ -997,31 +1040,32 @@ error_badchain_j:
; ds => first chunk of to be relocated data ; ds => first chunk of to be relocated data
; es => first chunk of relocation destination ; word [ss:sp] => first chunk of relocation destination
; cx = number of words in first chunk ; cx = number of words in first chunk
relocator: relocator:
pop es ; => where to relocate to
rep movsw rep movsw
retf ; jump to relocated relocate_to retf ; jump to relocated relocate_to
.end: .end:
; INP: dx:ax = cluster - 2 (0-based cluster) ; INP: dx:ax = cluster - 2 (0-based cluster)
; OUT: cx:bx = input dx:ax ; OUT: dx:ax = first sector of that cluster
; dx:ax = first sector of that cluster ; cx = adjusted sectors per cluster
; CHG: - ; CHG: bx
clust_to_first_sector: clust_to_first_sector:
push dx mov cx, word [bp + ldClusterSize]
push ax
push dx push dx
mul word [bp + ldClusterSize] mul cx
xchg bx, ax xchg bx, ax
xchg cx, dx
pop ax pop ax
mul word [bp + ldClusterSize] push dx
mul cx
test dx, dx test dx, dx
jnz short error_badchain_j jnz short error_badchain_j
xchg dx, ax xchg dx, ax
add dx, cx pop ax
add dx, ax
.cy_error_badchain: .cy_error_badchain:
jc short error_badchain_j jc short error_badchain_j
xchg ax, bx xchg ax, bx
@ -1030,21 +1074,17 @@ clust_to_first_sector:
adc dx, [bp + lsvDataStart + 2] adc dx, [bp + lsvDataStart + 2]
jc short .cy_error_badchain jc short .cy_error_badchain
; dx:ax = first sector in cluster ; dx:ax = first sector in cluster
pop bx
pop cx ; cx:bx = cluster
retn retn
; INP: cx:bx = cluster (0-based) ; INP: dx:ax = cluster (0-based)
; si:di = loaded FAT sector, -1 if none ; si:di = loaded FAT sector, -1 if none
; OUT: CY if no next cluster ; OUT: CY if no next cluster
; NC if next cluster found, ; NC if next cluster found
; dx:ax = next cluster value (0-based) ; dx:ax = next cluster value (0-based)
; si:di = loaded FAT sector ; si:di = loaded FAT sector
; CHG: cx, bx ; CHG: cx, bx
clust_next: clust_next:
mov ax, bx
mov dx, cx
add ax, 2 add ax, 2
adc dx, 0 adc dx, 0
@ -1153,25 +1193,25 @@ check_clust:
ms6_continue1: ms6_continue1:
mov es, cx mov es, cx ; cx = 0
mov bp, 7C00h mov bp, 7C00h ; 0:bp -> boot sector with BPB
mov word [es:di], si mov word [es:di], si
mov word [es:di + 2], ds ; restore old int 1Eh address mov word [es:di + 2], ds ; restore old int 1Eh address
mov ss, cx mov ss, cx ; = 0
mov sp, 7C00h + lsvCommandLine mov sp, 7C00h + lsvCommandLine
mov dx, word [es:500h + 26] push word [es:500h + 20]
mov cx, word [es:500h + 20] push word [es:500h + 26]
mov word [bp + lsvFirstCluster + 0], dx pop word [bp + lsvFirstCluster + 0]
mov word [bp + lsvFirstCluster + 2], cx pop word [bp + lsvFirstCluster + 2]
sub bx, word [bp + bsBPB + bpbHiddenSectors + 0] sub bx, word [bp + bsBPB + bpbHiddenSectors + 0]
sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2] sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2]
mov word [bp + lsvDataStart + 0], bx mov word [bp + lsvDataStart + 0], bx
mov word [bp + lsvDataStart + 2], ax mov word [bp + lsvDataStart + 2], ax
jmp ms7_entry.ms6_common jmp ms7_entry.ms6_common ; passing cx = 0
%assign num 1020-($-$$) %assign num 1020-($-$$)
@ -1193,7 +1233,8 @@ ldos_entry:
cli cli
cld cld
; cs:ip = 70h:400h ; ip = 400h
; cs = arbitrary; typically 60h, 70h, or 200h
; dwo [ss:bp - 4] = first data sector (without hidden sectors) ; dwo [ss:bp - 4] = first data sector (without hidden sectors)
; wo [ss:bp - 6] = load_seg, => after last loaded data ; wo [ss:bp - 6] = load_seg, => after last loaded data
; wo [ss:bp - 8] = fat_seg, 0 if invalid ; wo [ss:bp - 8] = fat_seg, 0 if invalid
@ -1214,6 +1255,7 @@ ldos_entry:
; ;
; Extension 2: ; Extension 2:
; word [ss:bp - 20] = signature "CL" if valid ; word [ss:bp - 20] = signature "CL" if valid
; bp >= 20 + 256 if valid
; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string ; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string
xor ax, ax xor ax, ax
@ -1277,9 +1319,9 @@ init_memory:
dec cx ; => last paragraph of higher buffer (16-byte trailer) dec cx ; => last paragraph of higher buffer (16-byte trailer)
mov dx, ax ; => first paragraph of higher buffer mov dx, ax ; => first paragraph of higher buffer
mov bx, cx mov bx, cx
and dx, 0F000h ; 64 KiB chunk of first paragraph of higher buffer and dh, 0F0h ; 64 KiB chunk of first paragraph of higher buffer
and bx, 0F000h ; 64 KiB chunk of last paragraph of higher buffer and bh, 0F0h ; 64 KiB chunk of last paragraph of higher buffer
cmp bx, dx ; in same chunk? cmp bh, dh ; in same chunk?
mov bx, ax mov bx, ax
je .gotsectorseg ; yes, use higher buffer as sector buffer -> je .gotsectorseg ; yes, use higher buffer as sector buffer ->
; bx = use higher buffer as FAT buffer ; bx = use higher buffer as FAT buffer
@ -1341,33 +1383,42 @@ init_memory:
inc cx ; => stack + BPB buffer inc cx ; => stack + BPB buffer
push ss push ss
pop ds pop ds
lea si, [bp + lsvCommandLine.start]
mov es, cx mov es, cx
push cx ; top of memory below buffers
push ax ; => sector seg
xor cx, cx
lea si, [bp + lsvCommandLine.start]
cmp bp, si ; can have command line ?
; (also makes sure movsw and lodsw never run
; with si = 0FFFFh which'd cause a fault.)
jb .no_cmdline
mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start
; -> cmd line target ; -> cmd line target
push cx ; top of memory below buffers mov cl, (LOADCMDLINE_size + 1) >> 1
mov cx, (LOADCMDLINE_size + 1) >> 1
rep movsw ; copy cmd line rep movsw ; copy cmd line
%if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature %if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature
%error Unexpected structure layout %error Unexpected structure layout
%endif %endif
cmp word [si], lsvclSignature lodsw
cmp ax, lsvclSignature
je @F ; if command line given --> je @F ; if command line given -->
.no_cmdline:
mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl
; truncate as if empty line given ; truncate as if empty line given
dec cx ; cl = 0FFh dec cx ; cl = 0FFh
@@: @@:
mov byte [es:di - 1], cl mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start \
+ fromwords(words(LOADCMDLINE_size)) - 1 ], cl
; remember whether command line given ; remember whether command line given
; = 0 if given (also truncates if too long) ; = 0 if given (also truncates if too long)
; = 0FFh if not given ; = 0FFh if not given
push ax ; si happens to be already correct here if we didn't
%if lsvCommandLine.signature + 2 != lsvExtra ; branch to .no_cmdline, however make sure to set
%error Unexpected structure layout ; it here to support this case.
%endif lea si, [bp + lsvExtra]
lodsw
; lea si, [bp + lsvExtra]
; ds:si -> lsv + BPB ; ds:si -> lsv + BPB
mov di, _STACKSIZE - LOADCMDLINE + lsvExtra mov di, _STACKSIZE - LOADCMDLINE + lsvExtra
; es:di -> where to place lsv ; es:di -> where to place lsv
@ -1413,7 +1464,8 @@ init_memory:
test bx, bx test bx, bx
jz .is_fat32 jz .is_fat32
lea si, [bp + 510] ; -> last source word ; lea si, [bp + 510] ; -> last source word
mov si, _STACKSIZE - LOADCMDLINE + 510
lea di, [si + (ebpbNew - bpbNew)] ; -> last dest word lea di, [si + (ebpbNew - bpbNew)] ; -> last dest word
mov cx, (512 - bsBPB - bpbNew + 1) >> 1 mov cx, (512 - bsBPB - bpbNew + 1) >> 1
; move sector up, except common BPB start part ; move sector up, except common BPB start part
@ -1457,9 +1509,9 @@ init_memory:
; adjusted sectors per cluster (store in a word, ; adjusted sectors per cluster (store in a word,
; and decode EDR-DOS's special value 0 meaning 256) ; and decode EDR-DOS's special value 0 meaning 256)
xor ax, ax
mov al, [bp + bsBPB + bpbSectorsPerCluster] mov al, [bp + bsBPB + bpbSectorsPerCluster]
dec al dec ax
mov ah, 0
inc ax inc ax
mov [bp + ldClusterSize], ax mov [bp + ldClusterSize], ax
@ -1512,7 +1564,7 @@ init_memory:
@@: @@:
cmp ax, 0FFF7h - 2 cmp ax, 0FFF7h - 2
ja .badclusters ja .badclusters
mov byte [bp + ldFATType], 16 shr byte [bp + ldFATType], 1 ; = 16
cmp ax, 0FF7h - 2 cmp ax, 0FF7h - 2
ja .got_fat_type ja .got_fat_type
@ -1569,42 +1621,30 @@ init_memory:
and ax, bx ; rounded up, and ax, bx ; rounded up,
; ((payload.actual_end -$$+0 +15) >> 4 + pps - 1) & ~ (pps - 1) ; ((payload.actual_end -$$+0 +15) >> 4 + pps - 1) & ~ (pps - 1)
mov bx, cs
jmp finish_continue jmp finish_continue
%assign num 1024+512-4-($-$$) %assign num 1024+512-($-$$)
%warning num bytes in front of end %warning num bytes in front of end
_fill 1024+512-4,38,start _fill 1024+512,38,start
; -4 is for the following two instructions.
; they want execution to fall through to
; load_next_clust_continue. placing them
; at the very end of the 3 sectors allows
; not to use a jump here.
load_next_clust:
call clust_to_first_sector
push cx
align 16, nop
_fill 1024+512,90h,start ; check that we are at 3 sectors end
end: end:
load_next_clust_continue:
push bx load_next_clust:
mov cx, [bp + ldClusterSize] push dx
push ax
call clust_to_first_sector
load_next_sect: load_next_sect:
push cx
mov bx, [bp + ldLoadingSeg] mov bx, [bp + ldLoadingSeg]
cmp bx, [bp + ldLoadUntilSeg] cmp bx, [bp + ldLoadUntilSeg]
jae loaded_all.3stack_j jae loaded_all.2stack_j
call read_sector call read_sector
skipped_all_continue: skipped_all_continue:
mov [bp + ldLoadingSeg], bx mov [bp + ldLoadingSeg], bx
pop cx
loop load_next_sect loop load_next_sect
pop bx pop ax
pop cx pop dx
call clust_next call clust_next
jnc load_next_clust jnc load_next_clust
jmp end_of_chain jmp end_of_chain
@ -1616,11 +1656,13 @@ skipped_all_continue:
; if we jump to here, then the whole file has ; if we jump to here, then the whole file has
; been loaded, so this jump doesn't have to ; been loaded, so this jump doesn't have to
; stay in the 32 bytes after the end label. ; stay in the 32 bytes after the end label.
loaded_all.3stack_j: loaded_all.2stack_j:
jmp loaded_all.3stack jmp loaded_all.2stack
ms7_entry.continue: ms7_entry.continue:
cli
cld
pop bx pop bx
pop es pop es
pop word [es:bx] pop word [es:bx]
@ -1640,8 +1682,8 @@ ms7_entry.continue:
sbb word [bp + lsvDataStart + 2], dx sbb word [bp + lsvDataStart + 2], dx
mov ax, cs mov ax, cs
add ax, (4 * 512) >> 4 add ax, (4 * 512) >> 4 ; MS7 entry has 4 sectors loaded
xor cx, cx ; cx = 0
jmp ms7_entry.continue2_set_extra_and_empty_cmdline jmp ms7_entry.continue2_set_extra_and_empty_cmdline
@ -1656,8 +1698,7 @@ end2:
; This handling is in the second header part, ; This handling is in the second header part,
; behind the needed part to finish loading. ; behind the needed part to finish loading.
; It is only used when the file is completely loaded. ; It is only used when the file is completely loaded.
loaded_all.3stack: loaded_all.2stack:
pop ax
pop ax pop ax
pop ax pop ax
loaded_all: loaded_all:
@ -1723,6 +1764,13 @@ loaded_all:
; al = 0 else ; al = 0 else
rep stosb ; clear remainder of buffer rep stosb ; clear remainder of buffer
%if _QUERY_PATCH
mov ax, word [cs:..@query_patch_site]
%else
mov ax, _QUERY_DEFAULT
%endif
mov word [bp + ldQueryPatchValue], ax
mov ax, cs mov ax, cs
add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT
push ax push ax
@ -1754,6 +1802,13 @@ error_data_checksum_failed:
%endif %endif
freedos_or_msdos1_com_entry:
call @F
@@:
pop cx
cmp cx, @B
jne msdos1_com_entry
freedos_entry: freedos_entry:
; This is the FreeDOS compatible entry point. ; This is the FreeDOS compatible entry point.
; Supports FAT32 too. ; Supports FAT32 too.
@ -1815,7 +1870,8 @@ d3 test ax, "F0"
.multiboot_entry: .multiboot_entry:
mov ax, cs mov ax, cs
add ax, (payload.actual_end -$$+0 +15) >> 4 add ax, (payload.actual_end -$$+0 +15) >> 4
; Multiboot1/2 and FreeDOS have whole image
xor cx, cx ; cx = 0
jmp ms7_entry.continue2 jmp ms7_entry.continue2
@ -2475,3 +2531,14 @@ second_payload:
.end: .end:
%endif %endif
%if ($ - start) < 4096
_fill 4096, 38, start ; fill to new minimum limit
%endif
%if _PADDING
%if ($ - $$) > _PADDING
%warning No padding needed
%else
times _PADDING - ($ - $$) db 0
%endif
%endif

View File

@ -31,15 +31,15 @@ header:
dw (payload -$$+0) >> 4 ; exeHeaderSize dw (payload -$$+0) >> 4 ; exeHeaderSize
dw 0 ; exeMinAlloc dw 0 ; exeMinAlloc
dw -1 ; exeMaxAlloc dw -1 ; exeMaxAlloc
dw 0 ; exeInitSS dw (payload.end + 15 - payload) / 16 ; exeInitSS
dw -2 ; exeInitSP dw 512 ; exeInitSP
dw 0 ; exeChecksum dw 0 ; exeChecksum
dw 0, 0 ; exeInitCSIP dw 0, 0 ; exeInitCSIP
dw 0 ; exeRelocTable dw 0 ; exeRelocTable
endarea header endarea header
align 16, db 38 align 16, db 0
payload: payload:
jmp strict short entry jmp strict short entry
db "CONFIG" db "CONFIG"
@ -50,7 +50,7 @@ payload:
entry: equ $ entry: equ $
jmp entry_common jmp entry_common
times 0xC0 - ($ - payload) db 0 times 0xC0 - ($ - payload) nop
entry_common: equ $ entry_common: equ $
incbin _FILE incbin _FILE

View File

@ -13,20 +13,88 @@ DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
@:help @:help
; Available patches: ; Available patches:
; ;
; :patch_iniload_no_query_geometry ; :patch_iniload_no_query_geometry (new or old style)
; :patch_iniload_no_lba ; :patch_iniload_no_lba (new or old style)
; :patch_iniload_no_query_geometry_old (old style)
; :patch_iniload_no_lba_old (old style)
; :patch_iniload_no_chs (new style only)
; :patch_iniload_detect_lba (new style only)
; :patch_iniload_detect_geometry (new style only)
; ;
; Inputs: vef = nonzero to debug ; Inputs: vef = nonzero to debug
; cs:0 -> iniload ; cs:ve7 -> iniload
; Output: vee = nonzero if error ; Output: vee = nonzero if error
; iniload patched ; iniload patched if successful
; Change: ve0 to vef, src, sro, aao, stack ; Change: ve0 to vef, src, sro, aao, stack
; ;
; :query_patch_iniload (new style)
;
; Input: ve8 = what to set for new style query patch
; 0 = default, -1 = none (do old style patch)
; ve9 = what to clear for new style query patch
; Requires lDebug release 3 or later ; Requires lDebug release 3 or later
@goto :eof @goto :eof
:query_patch_iniload
@if not (vef) then r ysf |= C000
@:query_patch_common
r ve0 word (sp - 100)
a ss:ve0
mov dl, byte [bp + 40]
mov ax, 0
.
r ve1 := aao - 2
r vec := ve1 - ve0
s cs:ve7 l #1536 range ss:ve0 l vec
if (src == 0 && vee == -1) then goto :eof
if not (src) then goto :query_patch_error
a ss:ve0
test dl, dl
jns (ve0 + 6)
db 86,C4 ; xchg al, ah
.
if (word [srs:sro + vec + 2] != word [ss:ve0 + 0]) then goto :query_patch_error
if (word [srs:sro + vec + 4] != word [ss:ve0 + 2]) then goto :query_patch_error
if (word [srs:sro + vec + 6] != word [ss:ve0 + 4]) then goto :query_patch_error
if not (ve8 or ve9) then goto :query_patch_found
r word [srs:sro + vec] or:= ve8
r word [srs:sro + vec] and:= ~ve9
:query_patch_success
r ve8 := 0
r ve9 := 0
r vee := 0
r ysf &= ~C000
; Patched successfully (new style)
@goto :eof
:query_patch_found
r ve8 := 0
r ve9 := 0
r vee := 0
r ysf &= ~C000
; Patch site found, no patch requested (new style)
@goto :eof
:query_patch_error
r ve8 := 0
r ve9 := 0
r vee := 1
r ysf &= ~C000
; Patch failed (new style)
@goto :eof
:patch_iniload_no_query_geometry :patch_iniload_no_query_geometry
@if not (vef) then r ysf |= C000 @if not (vef) then r ysf |= C000
r vee := -1
r ve8 := 404
r ve9 := 0
y :query_patch_common
@if not (vee == -1) then goto :eof
:patch_iniload_no_query_geometry_old
@if not (vef) then r ysf |= C000
r ve0 word (sp - 100) r ve0 word (sp - 100)
a ss:ve0 a ss:ve0
mov ah, 08 mov ah, 08
@ -37,13 +105,22 @@ a ss:ve0
. .
r ve1 := aao - 1 r ve1 := aao - 1
r vec := ve1 - ve0 r vec := ve1 - ve0
s cs:0 l #8192 range ss:ve0 l vec s cs:ve7 l #1536 range ss:ve0 l vec
if not (src) then goto :error if not (src) then goto :error
r byte [srs:sro + vec - 1] := EB r word [srs:sro + vec - 3] := 9090
goto :success goto :success
:patch_iniload_no_lba :patch_iniload_no_lba
@if not (vef) then r ysf |= C000 @if not (vef) then r ysf |= C000
r vee := -1
r ve8 := 101
r ve9 := 0
y :query_patch_common
@if not (vee == -1) then goto :eof
:patch_iniload_no_lba_old
@if not (vef) then r ysf |= C000
r ve0 word (sp - 100) r ve0 word (sp - 100)
a ss:ve0 a ss:ve0
mov ah, 41 mov ah, 41
@ -56,7 +133,7 @@ a ss:ve0
. .
r ve1 := aao - 1 r ve1 := aao - 1
r vec := ve1 - ve0 r vec := ve1 - ve0
s cs:0 l #8192 range ss:ve0 l vec s cs:ve7 l #1536 range ss:ve0 l vec
if (src) then goto :patch_iniload_no_lba.success if (src) then goto :patch_iniload_no_lba.success
a ss:ve0 a ss:ve0
mov ah, 41 mov ah, 41
@ -69,20 +146,64 @@ a ss:ve0
. .
r ve1 := aao - 1 r ve1 := aao - 1
r vec := ve1 - ve0 r vec := ve1 - ve0
s cs:0 l #8192 range ss:ve0 l vec s cs:ve7 l #1536 range ss:ve0 l vec
if (src) then goto :patch_iniload_no_lba.success
a ss:ve0
mov ah, 41
mov bx, 55AA
stc
int 13
mov al, 0
jc (ve0)
.
r ve1 := aao - 1
r vec := ve1 - ve0
s cs:ve7 l #1536 range ss:ve0 l vec
if not (src) then goto :error if not (src) then goto :error
:patch_iniload_no_lba.success :patch_iniload_no_lba.success
r byte [srs:sro + vec - 1] := EB r word [srs:sro + vec - 5] := 9090
goto :success goto :success
:success :success
r ve8 := 0
r ve9 := 0
r vee := 0 r vee := 0
r ysf &= ~C000 r ysf &= ~C000
; Patched successfully ; Patched successfully
@goto :eof @goto :eof
:patch_iniload_no_chs
@if not (vef) then r ysf |= C000
r vee := -1
r ve9 := 0
r ve8 := 202
y :query_patch_common
@if not (vee == -1) then goto :eof
goto :error
:patch_iniload_detect_lba
@if not (vef) then r ysf |= C000
r vee := -1
r ve8 := 0
r ve9 := 303
y :query_patch_common
@if not (vee == -1) then goto :eof
goto :error
:patch_iniload_detect_geometry
@if not (vef) then r ysf |= C000
r vee := -1
r ve8 := 0
r ve9 := 404
y :query_patch_common
@if not (vee == -1) then goto :eof
goto :error
:error :error
r ve8 := 0
r ve9 := 0
r vee := 1 r vee := 1
r ysf &= ~C000 r ysf &= ~C000
; Patch failed ; Patch failed

View File

@ -32,6 +32,7 @@
[ -z "$BOOT_COMMAND" ] && BOOT_COMMAND=~/.dosemu/drive_c/command.com [ -z "$BOOT_COMMAND" ] && BOOT_COMMAND=~/.dosemu/drive_c/command.com
[ -z "$BOOT_PROTOCOL" ] && BOOT_PROTOCOL=FREEDOS [ -z "$BOOT_PROTOCOL" ] && BOOT_PROTOCOL=FREEDOS
[ -z "$BOOT_OPTIONS" ] && BOOT_OPTIONS=" " [ -z "$BOOT_OPTIONS" ] && BOOT_OPTIONS=" "
[ -z "$MKTMPINC" ] && MKTMPINC=mktmpinc.pl
[ -z "$NASM" ] && NASM=nasm [ -z "$NASM" ] && NASM=nasm
[ -z "$CHECKSUM" ] && CHECKSUM="${INICHECK_DIR%/}"/iniload/checksum [ -z "$CHECKSUM" ] && CHECKSUM="${INICHECK_DIR%/}"/iniload/checksum

View File

@ -270,7 +270,17 @@ fi
echo -ne 'failure\r\n' > result.txt echo -ne 'failure\r\n' > result.txt
TMPINC=""
if command -v "$MKTMPINC" &> /dev/null
then
TMPINC="-D_TMPINC"
fi
if [[ -n "$TMPINC" ]]
then
"$MKTMPINC" "${LDOSBOOT_DIR%/}"/$bootname.asm > /dev/null
fi
"$NASM" "${LDOSBOOT_DIR%/}"/$bootname.asm -w-user \ "$NASM" "${LDOSBOOT_DIR%/}"/$bootname.asm -w-user \
$TMPINC \
-D_LOAD_NAME="'TESTWRIT'" -D_LOAD_EXT="'SYS'" -D_FAT$bpe \ -D_LOAD_NAME="'TESTWRIT'" -D_LOAD_EXT="'SYS'" -D_FAT$bpe \
-D_UNIT=$unit \ -D_UNIT=$unit \
"$@" \ "$@" \
@ -283,6 +293,7 @@ echo -ne 'failure\r\n' > result.txt
"$options_i_ldosboot" \ "$options_i_ldosboot" \
"$options_i_lmacros" \ "$options_i_lmacros" \
"$options_i_scanptab" \ "$options_i_scanptab" \
-D_PADDING='(48 * 1024)' \
-D_PAYLOAD_FILE="'testwrit.bin'" -o testwrit.sys -l testwrin.lst \ -D_PAYLOAD_FILE="'testwrit.bin'" -o testwrit.sys -l testwrin.lst \
-D_INILOAD_SIGNATURE='"TW"' && -D_INILOAD_SIGNATURE='"TW"' &&
"$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \ "$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \
@ -292,8 +303,8 @@ echo -ne 'failure\r\n' > result.txt
-D_BPE="$bpe" -D_SPC="$spc" -D_SPI="$spi" \ -D_BPE="$bpe" -D_SPC="$spc" -D_SPI="$spi" \
-D_SPF="$(( (spi / spc * bpe / 8 + 511) / 512 ))" \ -D_SPF="$(( (spi / spc * bpe / 8 + 511) / 512 ))" \
-D_NUMROOT="$nr" \ -D_NUMROOT="$nr" \
-o $name.img -l $name.lst \ -D_MAP=$name.map -o $name.img -l $name.lst \
-D_PAYLOADFILE="testwrit.sys,result.txt" \ -D_PAYLOADFILE="testwrit.sys,result.txt,::chdir,dir" \
-D_BOOTFILE="'$bootfile'" \ -D_BOOTFILE="'$bootfile'" \
-D_UNIT=$unit \ -D_UNIT=$unit \
"$@" \ "$@" \
@ -301,6 +312,10 @@ echo -ne 'failure\r\n' > result.txt
"$options_i_lmacros" \ "$options_i_lmacros" \
"$options_i_bootimg" "$options_i_bootimg"
(($?)) && exit $? (($?)) && exit $?
if [[ -n "$TMPINC" ]]
then
rm -f *.tmp
fi
pgid="$(ps -o pgid= $$)" pgid="$(ps -o pgid= $$)"
function handle_timeout_process() { function handle_timeout_process() {
@ -366,11 +381,16 @@ then
cp -aL "$BOOT_KERNEL" "${BOOT_KERNEL##*/}" cp -aL "$BOOT_KERNEL" "${BOOT_KERNEL##*/}"
cp -aL "$BOOT_COMMAND" "${BOOT_COMMAND##*/}" cp -aL "$BOOT_COMMAND" "${BOOT_COMMAND##*/}"
echo -ne "@echo off\r\ninst${bpe}tw.com C:\r\nquit.com\r\n" > autoexec.bat echo -ne "@echo off\r\ninst${bpe}tw.com C:\r\nquit.com\r\n" > autoexec.bat
if [[ -n "$TMPINC" ]]
then
"$MKTMPINC" "${LDOSBOOT_DIR%/}"/boot.asm > /dev/null
fi
"$NASM" quit.asm \ "$NASM" quit.asm \
"$options_i_lmacros" \ "$options_i_lmacros" \
-o quit.com && -o quit.com &&
"$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \ "$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \
"$options_i_lmacros" \ "$options_i_lmacros" \
$TMPINC \
-D_COMPAT_"$BOOT_PROTOCOL"=1 \ -D_COMPAT_"$BOOT_PROTOCOL"=1 \
-D_LBA=0 -D_USE_PART_INFO=0 -D_QUERY_GEOMETRY=0 \ -D_LBA=0 -D_USE_PART_INFO=0 -D_QUERY_GEOMETRY=0 \
$BOOT_OPTIONS \ $BOOT_OPTIONS \
@ -384,6 +404,10 @@ then
-D_PAYLOADFILE="${BOOT_KERNEL##*/},${BOOT_COMMAND##*/},autoexec.bat,inst${bpe}tw.com,quit.com" \ -D_PAYLOADFILE="${BOOT_KERNEL##*/},${BOOT_COMMAND##*/},autoexec.bat,inst${bpe}tw.com,quit.com" \
-D_BOOTFILE="'bootinst.bin'" -D_BOOTFILE="'bootinst.bin'"
(($?)) && exit $? (($?)) && exit $?
if [[ -n "$TMPINC" ]]
then
rm -f *.tmp
fi
timeout --foreground 10 "$QEMU" -fda diskinst.img "$qemu_switch" "$name".img -boot order=a -display none 2> /dev/null timeout --foreground 10 "$QEMU" -fda diskinst.img "$qemu_switch" "$name".img -boot order=a -display none 2> /dev/null
rc=$? rc=$?
handle_timeout_process handle_timeout_process
@ -397,8 +421,13 @@ fi
if ((! direct)) if ((! direct))
then then
if [[ -n "$TMPINC" ]]
then
"$MKTMPINC" "${LDOSBOOT_DIR%/}"/boot.asm > /dev/null
fi
"$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \ "$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \
"$options_i_lmacros" \ "$options_i_lmacros" \
$TMPINC \
-D_LOAD_NAME="'LDEBUG'" -D_LOAD_EXT="'COM'" \ -D_LOAD_NAME="'LDEBUG'" -D_LOAD_EXT="'COM'" \
-D_MAP=boot12db.map -l boot12db.lst -o boot12db.bin && -D_MAP=boot12db.map -l boot12db.lst -o boot12db.bin &&
"$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \ "$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \
@ -409,6 +438,10 @@ then
-o diskldbg.img -l diskldbg.lst \ -o diskldbg.img -l diskldbg.lst \
-D_PAYLOADFILE="ldebug.com" -D_BOOTFILE="'boot12db.bin'" -D_PAYLOADFILE="ldebug.com" -D_BOOTFILE="'boot12db.bin'"
(($?)) && exit $? (($?)) && exit $?
if [[ -n "$TMPINC" ]]
then
rm -f *.tmp
fi
if ((dosemu)) if ((dosemu))
then then

View File

@ -863,5 +863,9 @@ signature2:
dw 2638h dw 2638h
%if _PADDING %if _PADDING
%if ($ - $$) > _PADDING
%warning No padding needed
%else
times _PADDING - ($ - $$) db 0 times _PADDING - ($ - $$) db 0
%endif
%endif %endif

View File

@ -128,6 +128,7 @@ ATTR_ARCHIVE equ 20h
numdef LBA_RETRY, 1 ; retry LBA reads numdef LBA_RETRY, 1 ; retry LBA reads
numdef CHS_RETRY, 1 ; retry CHS reads numdef CHS_RETRY, 1 ; retry CHS reads
numdef PADDING, 0
strdef FILE_NAME, "RESULT" strdef FILE_NAME, "RESULT"
strdef FILE_EXT, "TXT" ; name of file to write strdef FILE_EXT, "TXT" ; name of file to write
strdef FILE_SUCCESS_MSG,"success" strdef FILE_SUCCESS_MSG,"success"
@ -501,7 +502,7 @@ write_sector:
push ax push ax
push si push si
push bx mov es, bx
; DX:AX==LBA sector number ; DX:AX==LBA sector number
; add partition start (= number of hidden sectors) ; add partition start (= number of hidden sectors)
@ -557,7 +558,8 @@ write_sector:
testopt [bp + ldHasLBA], 2 testopt [bp + ldHasLBA], 2
jz @F jz @F
mov es, word [si + 4 + 2] ; user buffer ; es => user buffer
push es
call .sectorseg_helper_write call .sectorseg_helper_write
mov word [si + 4 + 2], es ; => sector buffer mov word [si + 4 + 2], es ; => sector buffer
mov ah, 43h mov ah, 43h
@ -567,14 +569,16 @@ write_sector:
int 13h int 13h
; (don't need .int13_preserve_lpcount as no further call) ; (don't need .int13_preserve_lpcount as no further call)
%endif %endif
pop es ; ! restore es => user buffer
jc .lba_error jc .lba_error
jmp .lba_done jmp .lba_done
@@: @@:
; push word [si + 4 + 0] ; push word [si + 4 + 0]
push word [si + 4 + 2] ; user buffer push es ; => user buffer
push word [bp + ldSectorSeg] mov es, word [bp + ldSectorSeg]
pop word [si + 4 + 2] mov word [si + 4 + 2], es
; => sector buffer
; and word [si + 4 + 0], byte 0 ; and word [si + 4 + 0], byte 0
mov ah, 42h mov ah, 42h
@ -586,14 +590,13 @@ write_sector:
%endif %endif
jc .lba_error jc .lba_error
pop es pop es ; => user buffer
; pop cx ; pop cx
call .sectorseg_helper_read call .sectorseg_helper_read
.lba_done: .lba_done:
add sp, 10h add sp, 10h
pop bx jmp short .done
jmp short .chs_done
.lba_error: equ .err .lba_error: equ .err
@ -678,7 +681,6 @@ write_sector:
; we call INT 13h AH=02h once for each sector. Multi-sector reads ; we call INT 13h AH=02h once for each sector. Multi-sector reads
; may fail if we cross a track or 64K boundary ; may fail if we cross a track or 64K boundary
pop es
call .get_ah_3_write_2_read call .get_ah_3_write_2_read
mov al, 01h ; access one sector mov al, 01h ; access one sector
@ -722,14 +724,11 @@ write_sector:
pop es pop es
call .sectorseg_helper_read call .sectorseg_helper_read
%endif ; _CHS
.done: .done:
; increment segment ; increment segment
mov bx, es mov bx, es
%endif
.chs_done:
mov es, bx
add bx, word [bp + ldParaPerSector] add bx, word [bp + ldParaPerSector]
pop si pop si
@ -757,21 +756,21 @@ write_sector:
; reset drive ; reset drive
xor ax, ax xor ax, ax
int 13h int 13h
jc @F ; CY, reset failed, error in ah --> jnc @FF ; NC, reset succeeded -->
; CY, reset failed, error in ah
; try read again
pop ax ; restore function number
%if _LBA
call .int13_preserve_lpcount
%else
int 13h ; retry, CF error status, ah error number
%endif
retn
@@: ; NC or CY, stack has function number @@: ; NC or CY, stack has function number
inc sp inc sp
inc sp ; discard word on stack, preserve CF inc sp ; discard word on stack, preserve CF
retn retn
@@:
; try read again
pop ax ; restore function number
%if ! _LBA
int 13h ; retry, CF error status, ah error number
retn
%endif ; else: fall through to .int13_preserve_lpcount
%endif %endif
%if _LBA %if _LBA
@ -1021,3 +1020,11 @@ check_clust:
align 16, db 38 align 16, db 38
end: end:
%if _PADDING
%if ($ - $$) > _PADDING
%warning No padding needed
%else
times _PADDING - ($ - $$) db 0
%endif
%endif