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_EXT, "COM" ; name of file 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 EXEC_SEG_ADJ, 0 ; how far cs will be from _LOAD_ADR
numdef EXEC_OFS, 400h ; what value ip will be
@ -41,12 +41,16 @@ Public domain by C. Masloch, 2012
strdef ADD_NAME, ""
strdef ADD_EXT, "" ; name of second file to search
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_FATBUF, end -start+7C00h ; 07E00h
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_DISABLED, 0
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_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 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_NORMAL, 1 ; do not use aggressive optimisation
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_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 NO_LIMIT, 0 ; allow using more memory than a boot sector
; 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_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 CHS_RETRY, 1 ; retry CHS reads one time
numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times
; (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 UNIT, 0 ; load unit in BPB
@ -133,7 +145,7 @@ Public domain by C. Masloch, 2012
%if (!!_COMPAT_FREEDOS + !!_COMPAT_IBM + \
!!_COMPAT_MS7 + !!_COMPAT_MS6 + \
!!_COMPAT_LDOS || _COMPAT_KERNEL7E) > 1
!!_COMPAT_LDOS + !!_COMPAT_KERNEL7E) > 1
%error At most one set must be selected.
%endif
@ -244,7 +256,7 @@ Public domain by C. Masloch, 2012
strdef LOAD_NAME, "LDOS"
strdef LOAD_EXT, "COM"
numdef LOAD_ADR, 02000h
numdef LOAD_MIN_PARA, paras(1536)
numdef LOAD_MIN_PARA, paras(4096)
numdef EXEC_SEG_ADJ, 0
numdef EXEC_OFS, 400h
numdef CHECKOFFSET, 1020
@ -613,19 +625,73 @@ start:
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
; (word) number of 16-byte paragraphs per sector
nextvariable para_per_sector, 2, relocatestart
%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
; (word) segment of last available memory for sector
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
lowest_variable equ _LASTVARIABLE
@ -706,8 +772,6 @@ add_name:
; This happens to be aligned anyway. But even if
; it didn't, we'd rather save that byte than use
; it to align these fields. So comment this out.
filename:
dw add_name
dirseg:
dw _ADD_DIR_SEG
%endif
@ -724,6 +788,8 @@ dirseg:
[list -]
%else
; === error.tmp ===
error_start:
read_sector.err:
mov al, 'R' ; Disk 'R'ead error
%if ! _MEMORY_CONTINUE || _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM
@ -751,6 +817,11 @@ error:
int 16h
int 19h ; re-start the boot process
%if _WARN_PART_SIZE
%assign num $ - error_start
%warning error size is num bytes
%endif
; === eof ===
%endif
%if _TMPINC
@ -765,6 +836,7 @@ error:
[list -]
%else
; === read.tmp ===
read_sector_start:
; INP: dx:ax = sector
; OUT: only if successful
; dx:ax = incremented
@ -775,8 +847,24 @@ error:
%if ADR_DIRBUF == ADR_FATBUF
read_sector_dirbuf:
%endif
%if _FAT16 && ! _LOAD_NON_FAT
read_sector_fatbuf:
%endif
%if (ADR_DIRBUF == ADR_FATBUF) || (_FAT16 && ! _LOAD_NON_FAT)
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
; Read a sector using Int13.02 or Int13.42
@ -797,7 +885,7 @@ read_sector:
push ax
push si
push bx
mov es, bx ; => buffer
; DX:AX==LBA sector number
; add partition start (= number of hidden sectors)
@ -839,17 +927,22 @@ read_sector:
jc .no_lba
cmp bx, 0AA55h
jne .no_lba
test cl, 1 ; support bitmap bit 0
jz .no_lba
shr cl, 1 ; support bitmap bit 0
jnc .no_lba
%endif
%if _LBA_RETRY
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h
int 13h ; 13.42 extensions read
jnc .lba_done
%if _RETRY_RESET
xor ax, ax
int 13h
int 13h ; reset disk
%endif
; have to reset the LBAPACKET's lpCount, as the handler may
; set it to "the number of blocks successfully transferred".
@ -857,10 +950,17 @@ read_sector:
mov byte [si + 2], 1
%endif
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h
int 13h
%if _LBA_SKIP_CHECK && _CHS
%if _LBA_SKIP_ANY
jc .no_lba
%else
jc .lba_check_error_1
%endif
%else
.cy_err:
jc .lba_error
@ -871,10 +971,8 @@ read_sector:
mov byte [bp + 2], 0Eh ; LBA-enabled FAT16 FS partition type
%endif
add sp, 10h
pop bx
mov es, bx
%if _CHS
jmp short .chs_done
jmp short .done
%endif
.lba_error: equ .err
@ -883,10 +981,12 @@ read_sector:
.no_lba: equ .err
%else
%if _LBA_SKIP_CHECK
%if ! _LBA_SKIP_ANY
.lba_check_error_1:
cmp ah, 1 ; invalid function?
jne .lba_error ; no, other error -->
; try CHS instead
%endif
.cy_err: equ .err
%endif
.no_lba:
@ -955,29 +1055,50 @@ read_sector:
; we call INT 13h AH=02h once for each sector. Multi-sector reads
; may fail if we cross a track or 64K boundary
pop es
%if _CHS_RETRY_REPEAT
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:
mov ax, 0201h
int 13h ; read one sector
jnc .done
xor ax, ax
int 13h ; reset disk
%else
.loop_chs_retry_repeat:
%endif
dec si ; another attempt ?
jnz .loop_chs_retry_repeat ; yes -->
jmp .err
%else
%if _CHS_RETRY
js .nz_err ; no -->
mov ax, 0201h
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
; reset drive
xor ax, ax
int 13h
mov ax, 0201h
%else
push ax
int 13h ; read one sector
pop ax ; restore ax = 0201h
jnc .done
%endif
%endif
; try read again
mov ax, 0201h
int 13h
%if _LBA_SKIP_CHECK
inc bx
@ -987,12 +1108,11 @@ read_sector:
%endif
%endif
%endif ; _CHS
.done:
; increment segment
mov bx, es
%endif
.chs_done:
%if _FIX_SECTOR_SIZE
add bx, _FIX_SECTOR_SIZE >> 4
%else
@ -1010,6 +1130,11 @@ read_sector:
@@:
retn
%if _WARN_PART_SIZE
%assign num $ - read_sector_start
%warning read_sector size is num bytes
%endif
; === eof ===
%endif
%if _TMPINC
@ -1020,6 +1145,11 @@ read_sector:
[list +]
%endif
%if _WARN_PART_SIZE
%assign num $ - start
%warning BPB + data size is num bytes
%endif
; 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
; as a valid partition table entry by this handling. Therefore, we
; only accept partition information when booting from a hard disk now.
; start of magic byte sequence for instsect
test dl, dl ; floppy ?
jns @F ; don't attempt detection -->
; Check whether an MBR left us partition information.
@ -1058,15 +1190,23 @@ skip_bpb:
; Assume the movsw instructions won't run with si = FFFFh.
mov di, hidden_sectors ; -> BPB field
add si, 8 ; -> partition start sector in info
%if _USE_PART_INFO_DISABLED
nop
nop ; size has to match enabled code
%else
movsw
movsw ; overwrite BPB field with value from info
%endif
@@:
; end of magic byte sequence for instsect
%endif
mov ds, cx
sti
%if _QUERY_GEOMETRY ; +27 bytes
; start of magic byte sequence for instsect
; test dl, dl ; floppy?
; jns @F ; don't attempt query, might fail -->
; 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
; Already from prologue cx = 0.
stc ; initialise to CY
%if _QUERY_GEOMETRY_DISABLED
nop
nop ; size has to match enabled code
%else
int 13h ; query drive geometry
%endif
jc @F ; apparently failed -->
and cx, 3Fh ; get sectors
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)
mov [VAR(heads)], cx
@@:
; end of magic byte sequence for instsect
%endif
%if _FIX_SECTOR_SIZE
@ -1100,15 +1246,6 @@ skip_bpb:
mov al, 'C'
jne error
%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
mov ch, 0 ; ! ch = 0
%else
@ -1123,16 +1260,7 @@ skip_bpb:
jne error
%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)
; ! 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
push bx ; push into word [VAR(para_per_sector)]
@ -1140,6 +1268,14 @@ skip_bpb:
shr bx, 1 ; /2 = 32-byte entries per sector
%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)
mov si, [VAR(num_root_dir_ents)]
mov ax, bx
@ -1194,21 +1330,48 @@ next_sect:
xor di, di ; es:di-> first entry in this sector
next_ent:
%if DIRSEARCHSTACK_CL_FIRST
push cx ; first dirsearchstack word = entries-in-sector
push si ; other: entries total
%else
push si
push di
push cx
push cx ; second dirsearchstack word = entries-in-sector
%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
mov si, [VAR(filename)]
mov si, add_name
filename equ $ - 2 ; SMC to update to load_name later
%else
mov si, load_name ; ds:si-> name to match
%endif
mov cx, 11 ; length of padded 8.3 FAT filename
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
%if DIRSEARCHSTACK_CL_FIRST
pop si
pop cx ; pop from dirsearchstack
%else
pop cx
pop si ; pop from dirsearchstack
%endif
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
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:
%if _ADD_SEARCH || _LOAD_DIR_SEG
%if _ATTRIB_SAVE
pop di ; es:di -> dir entry (pop from dirsearchstack)
%endif
mov cx, 32
mov ax, _LOAD_DIR_SEG
%if ! _ATTRIB_SAVE
sub di, cx ; es:di -> dir entry
%endif
%if _ADD_SEARCH
xchg ax, word [VAR(dirseg)]
%endif
@ -1281,12 +1449,18 @@ found_it:
%else
%error Must not store directory entries to same segment
%endif
%if _ATTRIB_SAVE
pop si ; discard cx/si
pop si ; discard si/cx (dirsearchstack)
%endif
pop si
pop ax
pop dx ; restore root start and count
; (bx still holds entries per sector)
je next_dir_search ; jump to search load file next -->
%endif
times PLACEHOLDER push bx
; push into cmdline_signature_placeholder
%if _RELOCATE
push word [es:di + deClusterLow]
; (word on stack) = first cluster number
@ -1294,10 +1468,14 @@ found_it:
%else
%if _DIR_ENTRY_500 ; +24 bytes, probably
mov cx, 32
push ds
push es
%if _ATTRIB_SAVE
pop si ; es:si -> dir entry (pop from dirsearchstack)
%else
xchg si, di
sub si, cx
%endif
push ds
push es
push es
pop ds ; ds:si -> directory entry
xor ax, ax
@ -1312,14 +1490,30 @@ found_it:
pop ds
xchg si, di ; es:di -> behind (second) directory entry
%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 _DIR_ENTRY_500 || !_ATTRIB_SAVE
push word [es:di + deClusterLow - DIRENTRY_size \
- (DIRENTRY_size * !!_DIR_ENTRY_520)]
; (word on stack) = first cluster number
%else
push word [es:di + deClusterLow - (deName + 11)]
; (word on stack) = first cluster number
%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
memory_start:
; Get conventional memory size and store it
int 12h
mov cl, 6
@ -1406,6 +1600,11 @@ found_it:
rep movsw ; relocate stack, sector
retf ; jump to relocated code
%if _WARN_PART_SIZE
%assign num $ - memory_start
%warning memory size is num bytes
%endif
readhandler
@ -1442,10 +1641,13 @@ relocated:
push ax ; push into word [VAR(last_available_sector)]
%endif
read_fat_start:
; get starting cluster of file
%if ! _RELOCATE
%if _ADD_SEARCH || _LOAD_DIR_SEG
mov si,[es:di + deClusterLow]
%elif _ATTRIB_SAVE && ! _DIR_ENTRY_500
mov si,[es:di - deAttrib + deClusterLow]
%else
mov si,[es:di + deClusterLow - DIRENTRY_size \
- (DIRENTRY_size * !!_DIR_ENTRY_520)]
@ -1510,10 +1712,9 @@ relocated:
mov bx, _LOAD_ADR>>4 ; => load address
%if _FAT16 && !_LOAD_NON_FAT
mov di, -1 ; = no FAT sector read yet
%if _SET_FAT_SEG
%if ! _RELOCATE
mov word [VAR(fat_seg)], ADR_FATBUF>>4
%endif
%if _SET_FAT_SEG && _SET_FAT_SEG_NORMAL
; This is not strictly needed because a FAT sector is
; read in any case, initialising this variable later.
mov word [VAR(fat_sector)], di
%endif
%endif
@ -1637,7 +1838,10 @@ next_cluster:
%else ; _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
mul word [VAR(bytes_per_sector)]
test dx, dx
@ -1656,7 +1860,12 @@ next_cluster:
%if _FIX_CLUSTER_SIZE
mov cx, _FIX_CLUSTER_SIZE
%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
@ -1669,7 +1878,7 @@ next_cluster:
; xxx - this will always load an entire cluster (e.g. 64 sectors),
; 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)
%else
cmp bx, [VAR(last_available_sector)]
@ -1708,8 +1917,21 @@ next_cluster:
%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_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
%endif
mov al, 'E'
jb error
%endif
@ -1827,6 +2049,12 @@ CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET
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
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 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_DISABLED, 0
numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl
numdef RPL, 1 ; support RPL and do not overwrite it
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 NO_LIMIT, 0 ; allow using more memory than a boot sector
; 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_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 CHS_RETRY, 1 ; retry CHS reads one time
numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times
; (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
; 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)
%endif
.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
; -> name to search
.minpara: dw _LOAD_MIN_PARA
@ -628,6 +645,11 @@ fsiboot_table: ; this table is used by the FSIBOOT stage
fsiboot_name:
fill 8, 32, db _FSIBOOTNAME
%if _WARN_PART_SIZE
%assign num $ - start
%warning BPB + data size is num bytes
%endif
; 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
; as a valid partition table entry by this handling. Therefore, we
; only accept partition information when booting from a hard disk now.
; start of magic byte sequence for instsect
test dl, dl ; floppy ?
jns @F ; don't attempt detection -->
; Check whether an MBR left us partition information.
@ -667,15 +691,23 @@ skip_bpb:
; Assume the movsw instructions won't run with si = FFFFh.
mov di, hidden_sectors ; -> BPB field
add si, 8 ; -> partition start sector in info
%if _USE_PART_INFO_DISABLED
nop
nop ; size has to match enabled code
%else
movsw
movsw ; overwrite BPB field with value from info
%endif
@@:
; end of magic byte sequence for instsect
%endif
mov ds, cx
sti
%if _QUERY_GEOMETRY ; +27 bytes
; start of magic byte sequence for instsect
; test dl, dl ; floppy?
; jns @F ; don't attempt query, might fail -->
; 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
; Already from prologue cx = 0.
stc ; initialise to CY
%if _QUERY_GEOMETRY_DISABLED
nop
nop ; size has to match enabled code
%else
int 13h ; query drive geometry
%endif
jc @F ; apparently failed -->
and cx, 3Fh ; get sectors
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)
mov [VAR(heads)], cx
@@:
; end of magic byte sequence for instsect
%endif
@ -854,6 +892,13 @@ load_fsiboot:
%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
; si:di = loaded sector-in-FAT
; CHG: ax, cx, dx
@ -1030,6 +1075,13 @@ CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET
; ss:bp-> boot sector with BPB
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:
mov al,'I'
@ -1057,6 +1109,11 @@ error:
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
;
@ -1076,7 +1133,7 @@ read_sector:
push ax
push si
push bx
mov es, bx ; => buffer
; DX:AX==LBA sector number
; add partition start (= number of hidden sectors)
@ -1118,17 +1175,22 @@ read_sector:
jc .no_lba
cmp bx, 0AA55h
jne .no_lba
test cl, 1 ; support bitmap bit 0
jz .no_lba
shr cl, 1 ; support bitmap bit 0
jnc .no_lba
%endif
%if _LBA_RETRY
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h
int 13h ; 13.42 extensions read
jnc .lba_done
%if _RETRY_RESET
xor ax, ax
int 13h
int 13h ; reset disk
%endif
; have to reset the LBAPACKET's lpCount, as the handler may
; set it to "the number of blocks successfully transferred".
@ -1136,15 +1198,24 @@ read_sector:
mov byte [si + 2], 1
%endif
%if _LBA_SKIP_CHECK && _LBA_SKIP_CY
stc
%endif
mov ah, 42h
int 13h
%if _LBA_SKIP_CHECK && _CHS
%if _LBA_SKIP_ANY
jc .no_lba
.err_CY: equ .err
.err_2: equ .err
%else
jnc .lba_done
cmp ah, 1 ; invalid function?
je .no_lba ; try CHS instead -->
.err_CY:
.err_2:
jmp .lba_error
%endif
%else
.err_CY:
jc .lba_error
@ -1156,10 +1227,8 @@ read_sector:
mov byte [bp + 2], 0Ch ; LBA-enabled FAT32 FS partition type
%endif
add sp, 10h
pop bx
mov es, bx
%if _CHS
jmp short .chs_done
jmp short .done
%endif
.lba_error: equ .err
@ -1225,34 +1294,56 @@ read_sector:
; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
or bl, ah ; collect set bits from ah
mov dl,[VAR(boot_unit)] ; dl = drive
.nz_err:
jnz .err_2 ; error if cylinder >= 1024 -->
; ! bx = 0 (for 13.02 call)
; we call INT 13h AH=02h once for each sector. Multi-sector reads
; may fail if we cross a track or 64K boundary
pop es
%if _CHS_RETRY_REPEAT
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:
mov ax, 0201h
int 13h ; read one sector
jnc .done
xor ax, ax
int 13h ; reset disk
%else
.loop_chs_retry_repeat:
%endif
dec si ; another attempt ?
jnz .loop_chs_retry_repeat ; yes -->
jmp .err_2
%else
%if _CHS_RETRY
js .nz_err ; no -->
mov ax, 0201h
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
; reset drive
xor ax, ax
int 13h
mov ax, 0201h
%else
push ax
int 13h ; read one sector
pop ax ; restore ax = 0201h
jnc .done
%endif
%endif
; try read again
mov ax, 0201h
int 13h
jc .err_CY
%endif
@ -1260,12 +1351,11 @@ read_sector:
.err_CY: equ .err
%endif
%endif ; _CHS
.done:
; increment segment
mov bx, es
%endif
.chs_done:
%if _FIX_SECTOR_SIZE
add bx, _FIX_SECTOR_SIZE >> 4
%else
@ -1285,6 +1375,11 @@ read_sector:
.retn:
retn
%if _WARN_PART_SIZE
%assign num $ - read_sector
%warning read_sector size is num bytes
%endif
%if _ADD_SEARCH
add_name: ; = blank-padded 11-byte filename to search for
@ -1381,9 +1476,9 @@ fsiboot:
; 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
dec ax
mov ah, 0
inc ax
push ax ; push into word [VAR(adj_sectors_per_cluster)]
dec ax ; ! ah = 0
@ -1483,13 +1578,11 @@ found_load_file:
jc ..@CY_3_fsiboot_error_badchain
next_load_cluster:
push dx
push ax ; preserve cluster number for later
call clust_to_first_sector
; dx:ax = first sector of cluster
; cx:bx = cluster value
push cx
push bx ; preserve cluster number for later
mov cx, [VAR(adj_sectors_per_cluster)]
; cx = adjusted sectors per cluster
; xxx - this will always load an entire cluster (e.g. 64 sectors),
; even if the file is shorter than this
@ -1510,8 +1603,8 @@ next_load_cluster:
jbe @F ; read enough -->
loop @BB
pop bx
pop cx
pop ax
pop dx
call clust_next
jnc next_load_cluster
@ -1536,10 +1629,11 @@ dirsearch:
jc fsiboot_error_badchain
next_root_clust:
push dx
push ax
call clust_to_first_sector
push cx
push bx
mov cx, [VAR(adj_sectors_per_cluster)]
; dx:ax = first sector of cluster
; cx = adjusted sectors per cluster
next_root_sect:
push cx
mov cx, [VAR(entries_per_sector)]
@ -1572,8 +1666,8 @@ next_ent:
pop di
pop cx
loop next_root_sect
pop bx
pop cx
pop ax
pop dx
call clust_next
jnc next_root_clust
file_not_found:
@ -1587,22 +1681,22 @@ fsiboot_error:
; INP: dx:ax = cluster - 2 (0-based cluster)
; OUT: cx:bx = input dx:ax
; dx:ax = first sector of that cluster
; CHG: -
; OUT: dx:ax = first sector of that cluster
; cx = adjusted sectors per cluster
; CHG: bx
clust_to_first_sector:
mov cx, word [VAR(adj_sectors_per_cluster)]
push dx
push ax
push dx
mul word [VAR(adj_sectors_per_cluster)]
mul cx
xchg bx, ax
xchg cx, dx
pop ax
mul word [VAR(adj_sectors_per_cluster)]
push dx
mul cx
test dx, dx
jnz fsiboot_error_badchain
xchg dx, ax
add dx, cx
pop ax
add dx, ax
jc ..@CY_fsiboot_error_badchain
xchg ax, bx
@ -1611,8 +1705,6 @@ clust_to_first_sector:
..@CY_fsiboot_error_badchain:
jc fsiboot_error_badchain
; dx:ax = first sector in cluster
pop bx
pop cx ; cx:bx = cluster
retn
@ -1638,16 +1730,14 @@ found_it:
retn
; INP: cx:bx = cluster (0-based)
; INP: dx:ax = cluster (0-based)
; si:di = loaded FAT sector, -1 if none
; OUT: CY if no next cluster
; NC if next cluster found,
; NC if next cluster found
; dx:ax = next cluster value (0-based)
; si:di = loaded FAT sector
; CHG: cx, bx, es
clust_next:
xchg ax, bx ; ax = low word cluster, clobbers bx
mov dx, cx
add ax, 2
adc dx, 0

View File

@ -13,6 +13,7 @@
\cfg{html-leaf-level}{0}
\cfg{html-template-fragment}{%k}{%b}
\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}
@ -53,6 +54,27 @@ The entrypoint is found by applying no segment adjustment (0)
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
At offset 1020 (3FCh) there is the signature \cq{lD}.
@ -79,6 +101,10 @@ Currently the following signatures are defined:
\dd lDDebug (debuggable lDebug)
\dt \cq{lDbC}
\dd lCDebug (conditionally debuggable lDebug)
\dt \cq{lDTP}
\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.
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}.
Below the pointed to location there live the Load Stack Variables.
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.
The base pointer must be at least \cq{114h} then.
The stack pointer must be at most \cq{bp - 114h} then.
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 ldosboot boot.asm (FAT12/FAT16) loader
uses the variable for a \q{paragraphs per sector} value
which is always a power of two and always below-or-equal 200h.
makes sure not to pass the variable with the content "CL".
Refer to placeholder and DIRSEARCHSTACK_CL_FIRST uses in the source.
\b ldosboot boot32.asm (FAT32) loader
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}
\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
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 ldClusterSize: resw 1
\c ldParaPerSector:resw 1
\c ldLoadingSeg: resw 1
\c ldLoadingSeg:
\c ldQueryPatchValue:
\c resw 1
\c ldLoadUntilSeg: resw 1
\c endstruc
@ -293,6 +418,15 @@ May be given as zero for non-FAT filesystems.
\dd Word. Internally used by iniload.
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
@ -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,
then no command line was passed to iniload.
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,
it is also assumed that a command line can be passed.

View File

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

View File

@ -13,20 +13,88 @@ DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
@:help
; Available patches:
;
; :patch_iniload_no_query_geometry
; :patch_iniload_no_lba
; :patch_iniload_no_query_geometry (new or old style)
; :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
; cs:0 -> iniload
; cs:ve7 -> iniload
; Output: vee = nonzero if error
; iniload patched
; iniload patched if successful
; 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
@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
@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)
a ss:ve0
mov ah, 08
@ -37,13 +105,22 @@ a ss:ve0
.
r ve1 := aao - 1
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
r byte [srs:sro + vec - 1] := EB
r word [srs:sro + vec - 3] := 9090
goto :success
:patch_iniload_no_lba
@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)
a ss:ve0
mov ah, 41
@ -56,7 +133,7 @@ a ss:ve0
.
r ve1 := aao - 1
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
@ -69,20 +146,64 @@ a ss:ve0
.
r ve1 := aao - 1
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
:patch_iniload_no_lba.success
r byte [srs:sro + vec - 1] := EB
r word [srs:sro + vec - 5] := 9090
goto :success
:success
r ve8 := 0
r ve9 := 0
r vee := 0
r ysf &= ~C000
; Patched successfully
@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
r ve8 := 0
r ve9 := 0
r vee := 1
r ysf &= ~C000
; Patch failed

View File

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

View File

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

View File

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

View File

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