From cba5ee259d57b461297565380b6909bbd9456b8e Mon Sep 17 00:00:00 2001 From: "C. Masloch" Date: Wed, 29 Mar 2023 20:36:39 +0200 Subject: [PATCH] update ldosboot from hg 798e0b02fedc From https://hg.pushbx.org/ecm/ldosboot/file/798e0b02fedc --- test/ldosboot/boot.asm | 350 ++++++++++++++++++++++----- test/ldosboot/boot32.asm | 188 +++++++++++---- test/ldosboot/doc/ldosboot.src | 142 ++++++++++- test/ldosboot/iniload.asm | 429 +++++++++++++++++++-------------- test/ldosboot/kernshim.asm | 8 +- test/ldosboot/patch.sld | 139 ++++++++++- test/ldosboot/test/cfg.sh | 1 + test/ldosboot/test/test.sh | 37 ++- test/ldosboot/testpl.asm | 4 + test/ldosboot/testwrit.asm | 53 ++-- 10 files changed, 1018 insertions(+), 333 deletions(-) diff --git a/test/ldosboot/boot.asm b/test/ldosboot/boot.asm index cd20c63..7f74821 100644 --- a/test/ldosboot/boot.asm +++ b/test/ldosboot/boot.asm @@ -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 diff --git a/test/ldosboot/boot32.asm b/test/ldosboot/boot32.asm index 540596e..a922c70 100644 --- a/test/ldosboot/boot32.asm +++ b/test/ldosboot/boot32.asm @@ -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: - push dx - push ax + mov cx, word [VAR(adj_sectors_per_cluster)] 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, - ; dx:ax = next cluster value (0-based) + ; 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 diff --git a/test/ldosboot/doc/ldosboot.src b/test/ldosboot/doc/ldosboot.src index 72cde2a..e153818 100644 --- a/test/ldosboot/doc/ldosboot.src +++ b/test/ldosboot/doc/ldosboot.src @@ -13,6 +13,7 @@ \cfg{html-leaf-level}{0} \cfg{html-template-fragment}{%k}{%b} \cfg{html-head-end}{} +\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. diff --git a/test/ldosboot/iniload.asm b/test/ldosboot/iniload.asm index 7fabc39..309490c 100644 --- a/test/ldosboot/iniload.asm +++ b/test/ldosboot/iniload.asm @@ -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: - push dx - push ax + mov cx, word [bp + ldClusterSize] 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, - ; dx:ax = next cluster value (0-based) + ; 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 diff --git a/test/ldosboot/kernshim.asm b/test/ldosboot/kernshim.asm index cd995b0..60803cf 100644 --- a/test/ldosboot/kernshim.asm +++ b/test/ldosboot/kernshim.asm @@ -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 diff --git a/test/ldosboot/patch.sld b/test/ldosboot/patch.sld index 14b118f..09796c8 100644 --- a/test/ldosboot/patch.sld +++ b/test/ldosboot/patch.sld @@ -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 diff --git a/test/ldosboot/test/cfg.sh b/test/ldosboot/test/cfg.sh index 9c5cab0..d8979f2 100644 --- a/test/ldosboot/test/cfg.sh +++ b/test/ldosboot/test/cfg.sh @@ -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 diff --git a/test/ldosboot/test/test.sh b/test/ldosboot/test/test.sh index 5775ae8..6d225b3 100755 --- a/test/ldosboot/test/test.sh +++ b/test/ldosboot/test/test.sh @@ -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 diff --git a/test/ldosboot/testpl.asm b/test/ldosboot/testpl.asm index 1071edf..b202b1b 100644 --- a/test/ldosboot/testpl.asm +++ b/test/ldosboot/testpl.asm @@ -863,5 +863,9 @@ signature2: dw 2638h %if _PADDING + %if ($ - $$) > _PADDING + %warning No padding needed + %else times _PADDING - ($ - $$) db 0 + %endif %endif diff --git a/test/ldosboot/testwrit.asm b/test/ldosboot/testwrit.asm index d07c96c..6d60458 100644 --- a/test/ldosboot/testwrit.asm +++ b/test/ldosboot/testwrit.asm @@ -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