import ldosboot from snapshot of hg b9b7d2cf8971

From https://hg.pushbx.org/ecm/ldosboot/file/b9b7d2cf8971
This commit is contained in:
C. Masloch 2022-05-26 21:30:34 +02:00 committed by E. C. Masloch
parent fb689c1372
commit f84d9290b6
15 changed files with 9854 additions and 0 deletions

1854
test/ldosboot/boot.asm Normal file

File diff suppressed because it is too large Load Diff

1730
test/ldosboot/boot32.asm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,325 @@
\cfg{chapter}{Section}
\cfg{text-filename}{ldosboot.txt}
\cfg{text-chapter-numeric}{true}
\cfg{text-indent-preamble}{false}
\cfg{text-quotes}{"}{"}
\cfg{text-indent}{4}
\cfg{text-width}{72}
\cfg{html-chapter-numeric}{true}
\cfg{html-suppress-address}{true}
\cfg{html-single-filename}{ldosboot.htm}
\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{pdf-filename}{ldosboot.pdf}
\cfg{ps-filename}{ldosboot.ps}
\cfg{info-filename}{ldosboot.info}
\cfg{chm-filename}{ldosboot.chm}
\cfg{winhelp-filename}{ldosboot.hlp}
\cfg{man-filename}{ldosboot.7}
\cfg{man-identity}{ldosboot}{7}{2020}{}{C. Masloch}
\title lDOS boot documentation
\copyright 2020 by C. Masloch.
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
This document has been compiled on \date{%Y-%m-%d}.
\C{protocols} lDOS boot protocols
\H{protocol-sector-iniload} Sector to iniload protocol
The iniload kernel is loaded to an arbitrary segment.
The segment must be at least 60h.
Common choices are 60h, 70h, and 200h.
At least 1536 bytes of the file must be loaded.
Current loaders will load at least 8192 bytes
if the file is as large or larger than that.
The entrypoint is found by applying no segment adjustment (0)
and choosing the offset 400h (1024).
\S{protocol-sector-iniload-signatures} Signatures
At offset 1020 (3FCh) there is the signature \cq{lD}.
Behind that there are two bytes with printable non-blank ASCII codepoints.
Currently the following signatures are defined:
\dt \cq{lDOS}
\dd lDOS kernel (not yet in use)
\dt \cq{lDRx}
\dd RxDOS kernel
\dt \cq{lDFD}
\dd FreeDOS kernel wrapped in iniload (fdkernpl.asm)
\dt \cq{lDeb}
\dd lDebug
\dt \cq{lDDb}
\dd lDDebug (debuggable lDebug)
\dt \cq{lDTP}
\dd lDOS test payload kernel (testpl.asm)
\dt \cq{lDTW}
\dd lDOS test result writer kernel (testwrit.asm)
\S{protocol-sector-iniload-lsv} Load Stack Variables (LSV)
Under this protocol, the pointer \cq{ss:bp} is passed.
It points to a boot sector with (E)BPB.
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:
\c struc LOADSTACKVARS, -10h
\c lsvFirstCluster: resd 1
\c lsvFATSector: resd 1
\c lsvFATSeg: resw 1
\c lsvLoadSeg: resw 1
\c lsvDataStart: resd 1
\c endstruc
\dt lsvFirstCluster
\dd (FAT12, FAT16) Low word gives starting cluster of file.
High word uninitialised.
\dd (FAT32) Dword gives starting cluster of file.
\dd (else) Should be zero.
\dt lsvFATSector
\dd (FAT16) Low word gives loaded sector-in-FAT.
-1 if none loaded yet.
High word uninitialised.
\dd (FAT32) Dword gives loaded sector-in-FAT.
-1 if none loaded yet.
\dd (FAT12, else) Unused.
\dt lsvFATSeg
\dd (FAT16, FAT32) Word gives segment of FAT buffer
if word/dword [lsvFATSector] != -1.
\dd (FAT12) Word gives segment of FAT buffer.
Zero if none.
Otherwise, buffer holds entire FAT data, up to 6 KiB.
\dt lsvLoadSeg
\dd Word points to segment beyond last loaded paragraph.
Allows iniload to determine how much of it is already loaded.
\dt lsvDataStart
\dd Dword gives sector-in-partition of first cluster's data.
An LSV extension allows to pass a command line to the kernel.
The stack pointer must be at most \cq{bp - 114h} then.
This follows the structure like this:
\c lsvclSignature equ "CL"
\c lsvclBufferLength equ 256
\c
\c struc LSVCMDLINE, LOADSTACKVARS - lsvclBufferLength - 4
\c lsvCommandLine:
\c .start: resb lsvclBufferLength
\c .signature: resw 1
\c lsvExtra: resw 1
\c endstruc
\dt lsvCommandLine.start
\dd Command line buffer. Contains zero-terminated command line string.
\dt lsvCommandLine.signature
\dd Contains the signature value \cq{CL} if command line is given.
\dt lsvExtra
\dd Used internally by iniload.
Space for this must be reserved when passing a command line.
If no command line is passed then either the stack pointer
must be \cq{bp - 10h}, or \cq{bp - 12h}, or
the word in the lsvCommandLine.signature variable
(\cw{word [ss:bp - 14h]})
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.
\b ldosboot boot32.asm (FAT32) loader
uses the variable for an \q{entries per sector} value
which is always a power of two and always below-or-equal 100h.
\b lDebug with protocol options \cw{cmdline=0 push_dpt=0}
sets \cq{sp = bp - 10h}
\H{protocol-iniload-payload} Iniload to payload protocol
The payload is loaded to an arbitrary segment.
The segment must be at least 60h.
The entire payload must be loaded.
The size of the payload is determined at iniload build time.
The entrypoint is found by applying a segment adjustment
and choosing an offset.
The segment adjustment is specified at iniload build time
by the numeric define \cw{_EXEC_SEGMENT} (default 0),
and the offset by the define \cw{_EXEC_OFFSET} (default 0).
\S{protocol-iniload-payload-ebpb} Extended BIO Parameter Block (EBPB)
Above the LSV, \cw{ss:bp} points to an EBPB and surrrounding boot sector.
Note that this is always a FAT32-style EBPB.
If the filesystem that is loaded from is not FAT32,
and is therefore FAT16 or FAT12,
then the FAT16/FAT12 BPBN structure is moved up.
It is placed where the FAT32 BPBN is usually expected.
In this case, the entire boot sector contents behind the BPBN
are also moved up by the size of the FAT32-specific fields.
The FAT32-specific fields are filled with zeros,
except for the FAT32 \q{sectors per FAT} field.
It is filled with the contents of the FAT16/FAT12
\q{sectors per FAT} field.
\S{protocol-iniload-payload-lsv} Load Stack Variables (LSV)
Refer to \k{protocol-sector-iniload-lsv}.
\S{protocol-iniload-payload-ld} Load Data 1 (LD)
Below the LSV, iniload passes the LOADDATA (1) structure.
\c struc LOADDATA, LOADSTACKVARS - 10h
\c ldMemoryTop: resw 1
\c ldLoadTop: resw 1
\c ldSectorSeg: resw 1
\c ldFATType: resb 1
\c ldHasLBA: resb 1
\c ldClusterSize: resw 1
\c ldParaPerSector:resw 1
\c ldLoadingSeg: resw 1
\c ldLoadUntilSeg: resw 1
\c endstruc
\dt ldMemoryTop
\dd Word. Segment pointer to behind usable memory.
Points at the first of the EBDA, RPL-reserved memory, or
video memory or otherwise UMA.
Indicates how much memory may be used by a typical kernel.
(lDebug detects the EBDA to move that below where it installs.)
\dt ldLoadTop
\dd Word. Segment pointer to lowest lDOS boot memory in use.
All memory between linear 600h and the segment indicated here
is usable by the payload.
Only the payload itself is stored in this area.
The other buffers, stack, and structures passed by iniload
must live above this segment.
\dt ldSectorSeg
\dd Word. Segment pointer to an 8 KiB transfer buffer.
It is insured that this buffer does not cross a 64 KiB boundary.
This may be needed by some disk units.
The buffer is not initialised to anything generally.
\dt ldFATType
\dd Byte. Indicates length of FAT entry in bits.
12 indicates FAT12, 16 FAT16, 32 FAT32.
It is planned to allow zero for non-FAT filesystems.
\dt ldHasLBA
\dd Byte. Only least significant bit used.
Bit on indicates LBA extensions available for the load disk unit.
Bit off indicates LBA extensions not available.
\dt ldClusterSize
\dd Word. Contains amount of sectors per cluster.
Unlike the byte field for the same purpose in the BPB,
this field can encode 256 (EDR-DOS compatible) without any masking.
May be given as zero for non-FAT filesystems.
\dt ldParaPerSector
\dd Word. Contains amount of paragraphs per sector.
Must be a power of two between 2 (32 B/s) and 200h (8192 B/s).
May be given as zero for non-FAT filesystems.
\dt ldLoadingSeg
\dd Word. Internally used by iniload.
Available for re-use by payload.
\dt ldLoadUntilSeg
\dd Word. Internally used by iniload.
Available for re-use by payload.
\S{protocol-iniload-payload-lcl} Load Command Line (LCL)
Below the LOADDATA structure, iniload passes the LOADCMDLINE structure.
\c lsvclBufferLength equ 256
\c
\c struc LOADCMDLINE, LOADDATA - lsvclBufferLength
\c ldCommandLine:
\c .start: resb lsvclBufferLength
\c endstruc
This buffer is always initialised to an ASCIZ string.
At most 255 bytes may be initialised to string data.
At most the 256th byte is a zero.
If the first word of the buffer is equal to 0FF00h,
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.
When iniload is loaded as a Multiboot1 or Multiboot2 specification kernel,
it is also assumed that a command line can be passed.

10
test/ldosboot/doc/mak.sh Executable file
View File

@ -0,0 +1,10 @@
#! /bin/bash
# Usage of the works is permitted provided that this
# instrument is retained with the works, so that any entity
# that uses the works is notified of this instrument.
#
# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
echo -ne "\\U Source Control Revision ID\n\nhg $(hg id -i), from commit on at $(hg log -r . --template="{date|isodatesec}\n")\n\nIf this is in ecm's repository, you can find it at \\W{https://hg.pushbx.org/ecm/ldosboot/rev/$(hg log -r . --template "{node|short}")}{https://hg.pushbx.org/ecm/ldosboot/rev/$(hg log -r . --template "{node|short}")}\n" > screvid.src
halibut --precise ldosboot.src screvid.src --html --text --pdf

246
test/ldosboot/fdkernpl.asm Normal file
View File

@ -0,0 +1,246 @@
%if 0
Loader adjustment to load FreeDOS kernel
by C. Masloch, 2017
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
%include "lmacros3.mac"
struc BS
bsJump: resb 3
bsOEM: resb 8
bsBPB:
endstruc
struc EBPB ; BPB sec
bpbBytesPerSector: resw 1 ; offset 00h 0Bh
bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh
bpbReservedSectors: resw 1 ; offset 03h 0Eh
bpbNumFATs: resb 1 ; offset 05h 10h
bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32
bpbTotalSectors: resw 1 ; offset 08h 13h
bpbMediaID: resb 1 ; offset 0Ah 15h
bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32
bpbCHSSectors: resw 1 ; offset 0Dh 18h
bpbCHSHeads: resw 1 ; offset 0Fh 1Ah
bpbHiddenSectors: resd 1 ; offset 11h 1Ch
bpbTotalSectorsLarge: resd 1 ; offset 15h 20h
bpbNew: ; offset 19h 24h
ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h
ebpbFSFlags: resw 1 ; offset 1Dh 28h
ebpbFSVersion: resw 1 ; offset 1Fh 2Ah
ebpbRootCluster: resd 1 ; offset 21h 2Ch
ebpbFSINFOSector: resw 1 ; offset 25h 30h
ebpbBackupSector: resw 1 ; offset 27h 32h
ebpbReserved: resb 12 ; offset 29h 34h
ebpbNew: ; offset 35h 40h
endstruc
struc BPBN ; ofs B16 S16 B32 S32
bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h
resb 1 ; 01h 1Ah 25h 36h 41h
bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN
bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h
bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h
bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h
endstruc ; 1Ah 33h 3Eh 4Fh 5Ah
%ifndef _MAP
%elifempty _MAP
%else ; defined non-empty, str or non-str
[map all _MAP]
%endif
strdef PAYLOAD_FILE, "KERNEL.SYS"
struc LOADSTACKVARS, -10h
lsvFirstCluster: resd 1
lsvFATSector: resd 1
lsvFATSeg: resw 1
lsvLoadSeg: resw 1
lsvDataStart: resd 1
endstruc
lsvclSignature equ "CL"
lsvclBufferLength equ 256
struc LOADDATA, LOADSTACKVARS - 10h
ldMemoryTop: resw 1
ldLoadTop: resw 1
ldSectorSeg: resw 1
ldFATType: resb 1
ldHasLBA: resb 1
ldClusterSize: resw 1
ldParaPerSector:resw 1
ldLoadingSeg: ; word
lsvCommandLine: ; word
.start: equ $ - lsvclBufferLength
.signature: resw 1
ldLoadUntilSeg: ; word
lsvExtra: ; word
.partition: resb 1 ; byte
.flags: resb 1 ; byte
endstruc
lsvefNoDataStart equ 1
lsvefPartitionNumber equ 2
struc LOADCMDLINE, LOADDATA - lsvclBufferLength
ldCommandLine:
.start: resb lsvclBufferLength
endstruc
cpu 8086
org 0
addsection ENTRY, start=0 vstart=0
entry:
mov ax, cs
add ax, entry_size_p + payload_size_p
xor bx, bx
push ax
push bx
retf
align 16
endarea entry
addsection PAYLOAD, follows=ENTRY
payload:
realpayload:
incbin _PAYLOAD_FILE
align 16, db 38
endarea realpayload
addsection STACKRELOCATE, follows=PAYLOAD vstart=0
stackrelocate:
mov ax, 60h + payload_size_p
mov es, ax
xor di, di
xor si, si
lea cx, [ bp + 512 ]
rep movsb
mov ds, ax
mov si, bp
xor di, di
cmp word [ds:bp + ldCommandLine], 0FF00h
je @F
lea si, [bp + ldCommandLine + lsvclBufferLength - 2]
lea di, [bp + lsvCommandLine.start + lsvclBufferLength - 2]
mov cx, words(lsvclBufferLength)
%if words(lsvclBufferLength) <= 20
%error AMD erratum 109 workaround needed
%endif
std
rep movsw
cld
lea si, [bp + lsvCommandLine.start]
mov di, lsvclSignature
@@:
cli
mov ss, ax
mov sp, si
mov word [bp + lsvCommandLine.signature], di
; Note that this access uses the new ss.
; Also note: If no command line is passed,
; si will equal bp. That means the word
; written here is technically below sp,
; that is it belongs to the unused stack.
; This does not cause any problems however.
; It hardens the next load stage against
; accidentally expecting a command line if
; it does not check the offsets properly.
sti
jmp 60h:0
align 16
endarea stackrelocate
payload_size equ realpayload_size + stackrelocate_size
endarea payload, 1
addsection RELOCATE, follows=STACKRELOCATE vstart=0
relocate:
mov bx, 1000h
mov ax, 60h
mov es, ax
mov cx, payload_size_p
mov ax, cs
sub ax, cx
mov ds, ax
xor si, si
xor di, di
mov ax, cx
cmp ax, bx
jbe @F
mov cx, bx
@@:
sub ax, cx
shl cx, 1
shl cx, 1
shl cx, 1
rep movsw
@@:
mov dx, es
add dx, bx
mov es, dx ; next segment
mov dx, ds
add dx, bx
mov ds, dx ; next segment
sub ax, bx ; = how much to relocate after this round
mov cx, 1000h << 3 ; in case another full 64 KiB to relocate
jae @F ; another full 64 KiB to relocate -->
add ax, bx ; restore
shl ax, 1
shl ax, 1
shl ax, 1 ; convert paragraphs to words
mov cx, ax ; that many words
xor ax, ax ; no more to relocate after this round
@@:
xor si, si
xor di, di
rep movsw ; relocate next chunk
test ax, ax ; another round needed?
jnz @BB ; yes -->
; ax = 0
mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
mov bl, dl
push ss
pop ds
cmp word [bp + bsBPB + bpbSectorsPerFAT], ax
je @F
push ss
pop es
lea si, [bp + bsBPB + ebpbNew]
lea di, [bp + bsBPB + bpbNew]
mov cx, (512 - bsBPB - bpbNew + 1) >> 1
rep movsw
@@:
jmp 60h + realpayload_size_p:0

2477
test/ldosboot/iniload.asm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
%if 0
FreeDOS kernel executable MZ header shim
by C. Masloch, 2022
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
%include "lmacros2.mac"
defaulting
strdef FILE, ""
%ifidn _FILE,""
%fatal Has to specify a file!
%endif
org 0
header:
db "MZ" ; exeSignature
dw (payload.end - $$) % 512 ; exeExtraBytes
dw (payload.end - $$ + 511) / 512 ; exePages
dw 0 ; exeRelocItems
dw (payload -$$+0) >> 4 ; exeHeaderSize
dw 0 ; exeMinAlloc
dw -1 ; exeMaxAlloc
dw 0 ; exeInitSS
dw -2 ; exeInitSP
dw 0 ; exeChecksum
dw 0, 0 ; exeInitCSIP
dw 0 ; exeRelocTable
endarea header
align 16, db 38
payload:
jmp strict short entry
db "CONFIG"
dw 1
db -1
times 32 - ($ - payload) db 0
entry: equ $
jmp entry_common
times 0xC0 - ($ - payload) db 0
entry_common: equ $
incbin _FILE
.actual_end:
.end:

566
test/ldosboot/multboot.asm Normal file
View File

@ -0,0 +1,566 @@
%if 0
Multiboot header and loader
2008--2019 by C. Masloch
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
%macro mbootchecksummed 1-2.nolist 1BADB002h
dd %2 ; signature
dd %1 ; flags
dd -((%2+%1) & 0FFFF_FFFFh)
; checksum: dword sum of these three = 0
%endmacro
%macro mboot2checksummed 0-1.nolist 0E852_50D6h
dd %1 ; signature
dd 0 ; platform (i386)
dd mboot2_header_end - mboot2_header
; size of header, including header tags
dd -((%1 + (mboot2_header_end - mboot2_header))) & 0FFFF_FFFFh
; checksum
%endmacro
MULTIBOOT_CMDLINE_LENGTH equ lsvclBufferLength
MULTIBOOT_BASE equ (1024+64)*1024 ; one paragraph above the HMA
MULTIBOOT_END equ MULTIBOOT_BASE + (payload.actual_end - $$ + 0)
MULTIBOOT_BSS_END equ MULTIBOOT_END \
+ fromdwords(dwords(MULTIBOOT_CMDLINE_LENGTH))
MULTIBOOT_TARGET_SEGMENT equ 200h
MULTIBOOT_TARGET equ MULTIBOOT_TARGET_SEGMENT << 4
MULTIBOOT_BPB equ MULTIBOOT_TARGET - 512 - 16
MULTIBOOT_CMDLINE_START equ MULTIBOOT_BPB + lsvCommandLine.start
MULTIBOOT_STACK_TOP equ MULTIBOOT_CMDLINE_START
%if _MULTIBOOT1
; Multiboot header
; must be dword aligned and in first 8 KiB!
align 4, db 0
mbootheader:
mbootchecksummed 00010000h
; flags: provides info where to load image
dd MULTIBOOT_BASE + mbootheader ; load address of header
dd MULTIBOOT_BASE ; load address
dd MULTIBOOT_END ; load area end (0 = load whole file)
dd MULTIBOOT_BSS_END ; uninitialised area end (0 = none)
dd MULTIBOOT_BASE + mbootentry ; entry point
%endif
%if _MULTIBOOT2
; Multiboot2 header
; qword (64-bit) aligned and in first 32 KiB
align 8, db 0
mboot2_header:
mboot2checksummed
mboot2_tag_information_request:
.:
.type: dw 1
.flags: dw 0
.size: dd .end - .
dd 1 ; command line
dd 5 ; ROM-BIOS boot device
.end:
align 8, db 0
mboot2_tag_addresses:
.:
.type: dw 2
.flags: dw 0
.size: dd .end - .
dd MULTIBOOT_BASE + mboot2_header
; load address of header
dd MULTIBOOT_BASE ; load address
dd MULTIBOOT_END ; load area end (0 = load whole file)
dd MULTIBOOT_BSS_END ; uninitialised area end (0 = none)
.end:
align 8, db 0
mboot2_tag_entrypoint:
.:
.type: dw 3
.flags: dw 0
.size: dd .end - .
dd MULTIBOOT_BASE + mboot2entry ; entry point
.end:
align 8, db 0
mboot2_tag_end:
.:
.type: dw 0
.flags: dw 0
.size: dd .end - .
.end:
mboot2_header_end:
%endif
%unmacro mbootchecksummed 1-2.nolist 1BADB002h
%unmacro mboot2checksummed 0-1.nolist 0E85250D6h
%if ($-$$) > 8192
%fatal Multiboot header must be in the first 8 KiB
%endif
struc MBI
mbiFlags: resd 1
resb 8
mbiBootDevice: resd 1
mbiCmdLine: resd 1
mbiModuleCount: resd 1
mbiModuleTable: resd 1
; (More data follows but none which seems useful.)
endstruc
[cpu 386]
[bits 32]
numdef MULTIBOOT_CHECKS, 1
numdef MULTIBOOT_DEBUG, 0
numdef MULTIBOOT_HALT, 0
numdef MULTIBOOT_PROGRESS, 0
%if _MULTIBOOT_CHECKS || _MULTIBOOT_HALT
mbootentry.halt:
mboot2entry.halt:
; Unfortunately, as the environment is unknown, we can only
; literally halt here, as we don't know how to do I/O.
cli
@@:
hlt
jmp short @B
%endif
%if _MULTIBOOT1
; INP: eax = 2BADB002h
; ebx-> multiboot info structure
; STT: loaded and executed according to Multiboot header, ie
; loaded at MULTIBOOT_BASE
; eip = MULTIBOOT_BASE+mbootentry
; in PM32 with paging disabled
; CPL 0
; cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors
; DI
; ! stack not set up
; ! GDT might not be set up
; ! IDT might not be set up
; A20 on
;
; Note: Although A20 is on, HMA access without an XMM
; to manage it might be undesirable. Multiboot
; also doesn't tell us whether and if so then
; how we can switch A20.
mbootentry:
%if _MULTIBOOT_HALT
jmp .halt
%endif
%if _MULTIBOOT_CHECKS
[bits 16]
test ax, 0 ; (test eax if in 32-bit segment)
jmp short .halt ; (skipped if in 32-bit segment)
[bits 32]
cmp eax, 2BADB002h ; signature ?
jne short .halt ; no -->
smsw eax
rol eax, 1 ; 2 = protection, 1 = paging
and al, 3 ; mask off others
cmp al, 2 ; PE but not PG ?
jne short .halt ; no -->
mov eax, cs
and al, 3 ; CPL 0 ?
jnz short .halt ; no -->
%endif
%if _MULTIBOOT_PROGRESS
mov ebp, 0B8000h + 2 * 80 * 20
mov word [ebp], 5000h | '1'
inc ebp
inc ebp
%endif
; prepare this and that
or edx, -1
; locate boot drive in Multiboot info structure
test byte [ ebx + mbiFlags ], 2 ; boot device info valid ?
jz @F
mov eax, [ ebx + mbiBootDevice ]; get the info
rol eax, 16
xchg al, ah
mov edx, eax ; dl = boot load unit (or 0FFh),
; dh = partition (or 0FFh)
; (edxh = subpartition numbers)
@@:
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | '2'
inc ebp
inc ebp
%endif
xor eax, eax
mov edi, MULTIBOOT_END
mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
test byte [ ebx + mbiFlags ], 4 ; command line valid ?
jz @F
mov esi, [ ebx + mbiCmdLine ]
rep movsd
mov byte [ edi - 1 ], 0 ; insure it is terminated
; (this may truncate the line)
@@:
rep stosd
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | '3'
inc ebp
inc ebp
%endif
%if _MULTIBOOT2
jmp multiboot_1_2_common
%endif
%endif
%if _MULTIBOOT2
; INP: eax = 36D7_6289h
; ebx-> multiboot2 info structure
; STT: loaded and executed according to Multiboot2 header, ie
; loaded at MULTIBOOT_BASE
; eip = MULTIBOOT_BASE+mboot2entry
; in PM32 with paging disabled
; CPL 0
; cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors
; DI
; ! stack not set up
; ! GDT might not be set up
; ! IDT might not be set up
; A20 on
;
; Note: Although A20 is on, HMA access without an XMM
; to manage it might be undesirable. Multiboot
; also doesn't tell us whether and if so then
; how we can switch A20.
mboot2entry:
%if _MULTIBOOT_HALT
jmp .halt
%endif
%if _MULTIBOOT_CHECKS
[bits 16]
test ax, 0 ; (test eax if in 32-bit segment)
jmp short .halt ; (skipped if in 32-bit segment)
[bits 32]
cmp eax, 36D7_6289h ; signature ?
jne .halt ; no -->
smsw eax
rol eax, 1 ; 2 = protection, 1 = paging
and al, 3 ; mask off others
cmp al, 2 ; PE but not PG ?
jne .halt ; no -->
mov eax, cs
and al, 3 ; CPL 0 ?
jnz .halt ; no -->
%endif
%if _MULTIBOOT_PROGRESS
mov ebp, 0B8000h + 2 * 80 * 20
mov word [ebp], 5000h | 'A'
inc ebp
inc ebp
%endif
or edx, -1 ; initialise boot partition info
xor eax, eax
mov edi, MULTIBOOT_END
mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
rep stosd ; initialise command line buffer
add ebx, 8 ; skip fixed header (size, reserved)
.tags_loop:
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'B'
inc ebp
inc ebp
%endif
mov eax, dword [ebx]
test eax, eax ; end of tags ?
jz .tags_end ; yes -->
cmp eax, 1
je .cmdline
cmp eax, 5
je .partition
.tags_next:
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'C'
inc ebp
inc ebp
%endif
add ebx, dword [ebx + 4]
; -> after end of tag
; (at padding or next tag)
add ebx, 7
and ebx, ~7 ; skip any padding
jmp .tags_loop
.cmdline:
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'D'
inc ebp
inc ebp
%endif
lea esi, [ebx + 8]
mov edi, MULTIBOOT_END
mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
rep movsd ; copy command line
mov byte [ edi - 1 ], 0
; insure it is terminated
; (this may truncate the line)
jmp .tags_next
.partition:
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'E'
inc ebp
inc ebp
%endif
mov eax, dword [ebx + 8]
cmp eax, 100h
jae @F
mov dl, al ; get ROM-BIOS unit
@@:
mov eax, dword [ebx + 12]
cmp eax, 100h
jae @F
mov dh, al ; get partition number (0 = first primary)
@@:
jmp .tags_next
.tags_end:
xor eax, eax
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'F'
inc ebp
inc ebp
%endif
%endif
multiboot_1_2_common:
mov esp, MULTIBOOT_STACK_TOP ; set a valid stack, at 8 KiB
; (also required by 86M entry later)
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 's'
inc ebp
inc ebp
%endif
; A20 is on. set up some things
xor ecx, ecx
mov edi, 1024*1024
mov cl, 10h ; (ecx = 10h)
rep stosd ; clear this area so A20 tests succeed
; The above writes to 10_0000h..10_003Fh, leaving edi = 10_0040h
mov al, 0C0h ; (eax = C0h)
mov byte [ edi-40h+eax ], 0EAh
mov [ edi-40h+eax+1 ], eax ; write jump for CP/M entry hack here
; The above writes to 10_00C0h..10_00C4h
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 't'
inc ebp
inc ebp
%endif
; relocate image to a good location, 2000h
mov esi, MULTIBOOT_BASE ; -> iniload image
mov edi, MULTIBOOT_TARGET
mov ecx, (payload.actual_end - $$ + 0 + 3) / 4
rep movsd
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'u'
inc ebp
inc ebp
%endif
MULTIBOOT_ESI_AFTER equ MULTIBOOT_BASE + (payload.actual_end - $$ + 0 + 3) / 4 * 4
%if MULTIBOOT_ESI_AFTER != MULTIBOOT_END
mov esi, MULTIBOOT_END
%endif
mov edi, MULTIBOOT_CMDLINE_START
mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
rep movsd
%if _MULTIBOOT_PROGRESS
mov word [ebp], 5000h | 'v'
inc ebp
inc ebp
%endif
; now back to real mode
o32 lgdt [ MULTIBOOT_BASE+mbootgdtdesc ]
; set our GDT
mov ax, 10h
mov ds, ax
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax ; set 64 KiB segment limits
o32 push byte 0
o32 popf ; reset all flags
jmp 08h:.pm16 ; use 16-bit selector
[bits 16]
; now really switch to real mode
; (already executing relocated code)
.pm16:
mov eax, cr0
dec ax
mov cr0, eax ; clear PE bit
jmp dword MULTIBOOT_TARGET_SEGMENT:.rm ; reload cs
; Set up registers and the environment for
; the kernel entry point. It doesn't need initialised
; segment registers but we'll initialise them in case
; they still contain selector content.
.rm:
; some sources indicate we should set the IDT
o32 lidt [cs:mbootidtdesc] ; set IDT to RM IVT
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; (cs should be = 200h now, need no far jump)
; cs = 200h, ip = mboot_86m_entry
; ds = es = fs = gs = ss = 0
; sp = 2000h - 512 - 16 + lsvCommandLine.start
; dl = boot unit (or -1)
; dh = boot partition (0..3 = primary, 4+ = logical, or -1)
mov bp, MULTIBOOT_BPB ; -> pseudo BPB
mov di, MULTIBOOT_BPB + lsvCommandLine.signature
mov ax, lsvclSignature
stosw ; store signature
mov cx, (- (lsvCommandLine.signature + 2) + 512 + 3) / 4
xor eax, eax
rep stosd ; clear
; lsvFirstCluster = 0 (same as for FreeDOS entrypoint)
; bsBPB + bpbHiddenSectors = 0 (invalid or unpartitioned)
; bsBPB + bpbCHSSectors = 0
; bsBPB + bpbCHSHeads = 0
inc ax
mov dword [bp + lsvDataStart], eax
; lsvDataStart = 1 (placeholder)
__CPU__
mov word [bp + bsBPB + bpbNumRootDirEnts], ax
mov word [bp + bsBPB + bpbSectorsPerFAT], ax
; do not detect as FAT32
mov byte [bp + bsBPB + bpbSectorsPerCluster], al
mov word [bp + bsBPB + bpbBytesPerSector], 512
mov word [bp + bsBPB + bpbTotalSectors], 8192
; 1 C/s * 8 Ki sectors = 8 Ki clusters, detect as FAT16
; that is, do not load FAT at all (would load a FAT12)
mov byte [bp + bsBPB + bpbNew + bpbnBootUnit], dl
; set boot load unit
%if _LSVEXTRA
%if _MULTIBOOT_DEBUG
mov ax, dx
call mb_disp_ax_hex
%endif
xchg dl, dh ; dl = Multiboot spec partition number
; (0..3 primary, 4+ logical, -1 invalid)
inc dx ; 0 invalid, 1..4 primary, 5+ logical
mov dh, lsvefPartitionNumber
mov word [bp + lsvExtra], dx
%endif
jmp freedos_entry.multiboot_entry
%if _MULTIBOOT_DEBUG
mb_disp_ax_hex: ; ax
xchg al,ah
call mb_disp_al_hex ; display former ah
xchg al,ah ; and fall trough for al
mb_disp_al_hex: ; al
push cx
mov cl,4
ror al,cl
call mb_disp_al_lownibble_hex ; display former high-nibble
rol al,cl
pop cx
; and fall trough for low-nibble
mb_disp_al_lownibble_hex:
push ax ; save ax for call return
and al,00001111b ; high nibble must be zero
add al,'0' ; if number is 0-9, now it's the correct character
cmp al,'9'
jna .decimalnum ; if we get decimal number with this, ok -->
add al,7 ; otherwise, add 7 and we are inside our alphabet
.decimalnum:
call mb_disp_al
pop ax
retn
mb_disp_al:
push ax
push bx
push bp
mov ah, 0Eh
mov bx, 7
int 10h
pop bp
pop bx
pop ax
retn
%endif
align 16, db 0
mbootgdt:
dw 0,0
db 0,0,0,0
; selector 8: 16-bit real mode CS
; base = 00002000h, limit 0FFFFh (1 B Granularity), present
; type = 16-bit code execute/read only/conforming, DPL = 0
dw 0FFFFh,MULTIBOOT_TARGET
db 0,9Eh,0,0
; selector 10h: 16-bit real mode DS
; base = 00000000h, limit 0FFFFh (1 B Granularity), present
; type = 16-bit data read/write, DPL = 0
dw 0FFFFh,0
db 0,92h,0,0
endarea mbootgdt
mbootgdtdesc:
dw mbootgdt_size-1 ; limit
dd MULTIBOOT_BASE+mbootgdt ; address
mbootidtdesc:
dw 400h-1 ; limit
dd 0 ; address (86M IVT)

89
test/ldosboot/patch.sld Normal file
View File

@ -0,0 +1,89 @@
@goto :help
Patch iniload script
by C. Masloch, 2021
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
@:help
; Available patches:
;
; :patch_iniload_no_query_geometry
; :patch_iniload_no_lba
;
; Inputs: vef = nonzero to debug
; cs:0 -> iniload
; Output: vee = nonzero if error
; iniload patched
; Change: ve0 to vef, src, sro, aao, stack
;
; Requires lDebug release 3 or later
@goto :eof
:patch_iniload_no_query_geometry
@if not (vef) then r ysf |= C000
r ve0 word (sp - 100)
a ss:ve0
mov ah, 08
xor cx, cx
stc
int 13
jc (ve0)
.
r ve1 := aao - 1
r vec := ve1 - ve0
s cs:0 l #8192 range ss:ve0 l vec
if not (src) then goto :error
r byte [srs:sro + vec - 1] := EB
goto :success
:patch_iniload_no_lba
@if not (vef) then r ysf |= C000
r ve0 word (sp - 100)
a ss:ve0
mov ah, 41
mov dl, byte [bp + 40]
mov bx, 55AA
stc
int 13
mov al, 0
jc (ve0)
.
r ve1 := aao - 1
r vec := ve1 - ve0
s cs:0 l #8192 range ss:ve0 l vec
if (src) then goto :patch_iniload_no_lba.success
a ss:ve0
mov ah, 41
pop dx
mov bx, 55AA
stc
int 13
mov al, 0
jc (ve0)
.
r ve1 := aao - 1
r vec := ve1 - ve0
s cs:0 l #8192 range ss:ve0 l vec
if not (src) then goto :error
:patch_iniload_no_lba.success
r byte [srs:sro + vec - 1] := EB
goto :success
:success
r vee := 0
r ysf &= ~C000
; Patched successfully
@goto :eof
:error
r vee := 1
r ysf &= ~C000
; Patch failed
@goto :eof

38
test/ldosboot/test/cfg.sh Normal file
View File

@ -0,0 +1,38 @@
#! /bin/bash
# Usage of the works is permitted provided that this
# instrument is retained with the works, so that any entity
# that uses the works is notified of this instrument.
#
# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
# If you want to override configuration without the
# hassle of having to exclude differences in this file
# (cfg.sh) from the SCM, you may provide ovr.sh.
# The meaning of this line allows you to copy cfg.sh
# to serve as a template for ovr.sh without changes.
[ -f ovr.sh ] && [[ "${BASH_SOURCE[0]##*/}" != ovr.sh ]] && . ovr.sh
# As the below only are set if no value is provided
# yet, any value can be overridden from the shell.
[ -z "$LMACROS_DIR" ] && LMACROS_DIR=../../lmacros/
[ -z "$LDOSBOOT_DIR" ] && LDOSBOOT_DIR=../
[ -z "$SCANPTAB_DIR" ] && SCANPTAB_DIR=../../scanptab/
[ -z "$INICHECK_DIR" ] && INICHECK_DIR=../../crc16-t/
[ -z "$BOOTIMG_DIR" ] && BOOTIMG_DIR=../../bootimg/
[ -z "$LDEBUG_DIR" ] && LDEBUG_DIR=../../ldebug/bin/
[ -z "$LDOSMBR_DIR" ] && LDOSMBR_DIR=../../ldosmbr/
[ -z "$INSTSECT_DIR" ] && INSTSECT_DIR=../../instsect/
[ -z "$DOSEMU" ] && DOSEMU=dosemu
[ -z "$QEMU" ] && QEMU=qemu-system-i386
[ -z "$DEFAULT_MACHINE" ] && DEFAULT_MACHINE=dosemu
[ -z "$SENDKEYS" ] && SENDKEYS=sendkeys
[ -z "$BOOT_KERNEL" ] && BOOT_KERNEL=~/.dosemu/drive_c/kernel.sys
[ -z "$BOOT_COMMAND" ] && BOOT_COMMAND=~/.dosemu/drive_c/command.com
[ -z "$BOOT_PROTOCOL" ] && BOOT_PROTOCOL=FREEDOS
[ -z "$BOOT_OPTIONS" ] && BOOT_OPTIONS=" "
[ -z "$NASM" ] && NASM=nasm
[ -z "$CHECKSUM" ] && CHECKSUM="${INICHECK_DIR%/}"/iniload/checksum
[ -z "$use_build_inicheck" ] && use_build_inicheck=0

View File

@ -0,0 +1,60 @@
%if 0
Shut down machine
by C. Masloch, 2020
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
cpu 8086
org 256
quit:
int3
mov ax, 0F000h
mov es, ax
mov di, 0FFF5h
mov si, msg.dosemudate
mov cx, 4
repe cmpsw ; running in DosEmu?
jne .quit_not_dosemu
xor bx, bx
mov ax, -1
int 0E6h ; dosemu quit
.quit_not_dosemu:
; from https://stackoverflow.com/a/5240330/738287
mov ax, 5301h
xor bx, bx
int 15h ; connect to APM API
mov ax, 530Eh
xor bx, bx
mov cx, 0102h
int 15h ; set APM version to 1.02
mov ax, 5307h
mov bx, 1
mov cx, 3
int 15h ; shut down system
mov dx, msg.failed
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
align 4
msg:
.dosemudate: db "02/25/93"
.failed: db "Quit failed.",13,10,36

20
test/ldosboot/test/run.sh Executable file
View File

@ -0,0 +1,20 @@
#! /bin/bash
# Usage of the works is permitted provided that this
# instrument is retained with the works, so that any entity
# that uses the works is notified of this instrument.
#
# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
testrunname="fat12 default: " \
./test.sh diskette
testrunname="fat12 direct: " \
./test.sh diskette direct
testrunname="fat12 hdimage: " \
./test.sh hdimage
testrunname="fat12 16spc 20MiB: " \
./test.sh hdimage aligndata bpe 12 spc 16 mib 20 nr 512
testrunname="fat16 4spc 32MiB: " \
./test.sh hdimage aligndata bpe 16 spc 4 mib 32 nr 512
testrunname="fat32 1spc 34MiB: " \
./test.sh hdimage aligndata bpe 32 spc 1 mib 34

491
test/ldosboot/test/test.sh Executable file
View File

@ -0,0 +1,491 @@
#! /bin/bash
# Usage of the works is permitted provided that this
# instrument is retained with the works, so that any entity
# that uses the works is notified of this instrument.
#
# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
if [[ "$1" != selfcall ]]
then
setsid -w "$0" selfcall "$@"
exit $?
fi
shift
. cfg.sh
if [ -n "$LMACROS_DIR" ]; then {
options_i_lmacros=-I"${LMACROS_DIR%/}"/
} fi
if [ -n "$LDOSBOOT_DIR" ]; then {
options_i_ldosboot=-I"${LDOSBOOT_DIR%/}"/
} fi
if [ -n "$SCANPTAB_DIR" ]; then {
options_i_scanptab=-I"${SCANPTAB_DIR%/}"/
} fi
if [ -n "$BOOTIMG_DIR" ]; then {
options_i_bootimg=-I"${BOOTIMG_DIR%/}"/
} fi
if [ -n "$LDEBUG_DIR" ]; then {
options_i_ldebug=-I"${LDEBUG_DIR%/}"/
} fi
if [ -n "$LDOSMBR_DIR" ]; then {
options_i_ldosmbr=-I"${LDOSMBR_DIR%/}"/
} fi
if [ -n "$INSTSECT_DIR" ]; then {
options_i_instsect=-I"${INSTSECT_DIR%/}"/
} fi
direct=0
options_dosemu_direct="-A"
bpe=12
spc=1
spi=2880
nr=224
pitype=""
chsheads=8
chssectors=8
((debug)) && echo DEFAULT_MACHINE="$DEFAULT_MACHINE" parameters="$@"
machine="$DEFAULT_MACHINE"
if [[ "$1" == dosemu ]]
then
machine="$1"
shift
elif [[ "$1" == qemu ]]
then
machine="$1"
shift
fi
driveletters=( {C..Z} )
unitletters=( {a..z} )
dosemu=0
qemu=0
if [[ "$machine" == dosemu ]]
then
dosemu=1
if [ -z "$dosemu_drives" ] || [ "$dosemu_drives" == test ]
then
# Depending on the dosemu2 configuration, dosemu may
# set up 2, 3, or 4 system drives. To support all
# these cases, the variable dosemu_drives may now
# be set to indicate the amount of drives.
# If it is not set or set to "test" we do a bit of
# magic detection: Run dosemu -E lredir and count
# the amount of redirections displayed. Also check
# that all of the redirections are on the expected
# drives, starting with C:.
# We assume that each of the system drives corresponds
# to its own ROM-BIOS unit.
# Discussed here: https://github.com/dosemu2/dosemu2/discussions/1456
driveslist="$("$DOSEMU" -dumb -quiet -E lredir -te 2> /dev/null < /dev/null |
sed -re '/^about to execute|^current drive redirections/Id' )"
dosemu_drives="$(echo "$driveslist" | wc -l)"
for checkdrivenumber in $(seq 0 "$((dosemu_drives - 1))")
do
driveletter="${driveletters[checkdrivenumber]}"
if ! echo "$driveslist" | grep -Eiq "^$driveletter:"
then
echo "Error: Drive $driveletter: not found in lredir list" >&2
exit 1
fi
done
fi
((debug)) && echo "Drive ${driveletters[dosemu_drives]}:"
elif [[ "$machine" == qemu ]]
then
qemu=1
dosemu_drives=0
else
echo "Error: invalid machine \"$machine\" selected" >&2
exit 1
fi
if [[ "$1" == hdimage ]]
then
shift
options_hdimage="-D_MBR"
if ((dosemu))
then
options_hdimage="$options_hdimage -D_MBR_DOSEMU_IMAGE_HEADER"
fi
dosemu_category="disk"
dosemu_device="hdimage"
dosemu_drive="${driveletters[dosemu_drives]}:"
qemu_switch="-hda"
name="hdimage"
bootfile=""
unit="$(printf "%03Xh" "$((0x80 + $dosemu_drives))")"
options_ldebug_unit="hd${unitletters[dosemu_drives]}"
diskette=0
if [[ "$1" == direct ]]
then
shift
# output of the following command is either:
# 1. "CPU set to 486", followed by the sign ons for dosemu, FreeDOS,
# and config.sys and autoexec.bat output, then executing "exitemu"
# (if -C4 switch is not supported, parsed as -C -4).
# 2. Only the dosemu sign on with the error message as follows:
# "ERROR: Drive G not defined, can't boot!" (execution aborted).
if ((dosemu)) && "$DOSEMU" -dumb -E exitemu -C4 < /dev/null 2>&1 | grep "CPU set to 486" > /dev/null
then
echo "Error: dosemu lacks support for -C4 switch" >&2
exit 1
fi
options_dosemu_direct="-C$dosemu_drives"
unit=80h
direct=1
fi
if ((qemu))
then
unit=80h
options_ldebug_unit="hda"
fi
((debug)) && echo "unit=\"$unit\""
while true
do
if [[ "$1" == bpe && -n "$2" ]]
then
((bpe="$2"))
if (($?)) || [[ "$bpe" != 32 && "$bpe" != 16 && "$bpe" != 12 ]]
then
echo "Error: Invalid bpe \"$2\" given, expected 12, 16, 32" >&2
exit 1
fi
shift
shift
elif [[ "$1" == spc && -n "$2" ]]
then
((spc="($2)"))
(($?)) && exit $?
shift
shift
elif [[ "$1" == mib && -n "$2" ]]
then
((spi="(($2) * 1024 * 2)"))
(($?)) && exit $?
shift
shift
elif [[ "$1" == spi && -n "$2" ]]
then
((spi="($2)"))
(($?)) && exit $?
shift
shift
elif [[ "$1" == nr && -n "$2" ]]
then
((nr="($2)"))
(($?)) && exit $?
shift
shift
elif [[ "$1" == pitype && -n "$2" ]]
then
pitype="$2"
shift
shift
elif [[ "$1" == aligndata ]]
then
options_hdimage="$options_hdimage -D_ALIGNDATA"
shift
elif [[ "$1" == chsheads && -n "$2" ]]
then
((chsheads="($2)"))
(($?)) && exit $?
shift
shift
elif [[ "$1" == chssectors && -n "$2" ]]
then
((chssectors="($2)"))
(($?)) && exit $?
shift
shift
else
break
fi
done
if ((qemu && chsheads > 16))
then
echo "Warning: qemu autodetection requires CHS heads <= 16" >&2
fi
if ((dosemu))
then
options_mcopy_offset="@@$((16 + chsheads * chssectors))s"
else
options_mcopy_offset="@@$((chsheads * chssectors))s"
fi
options_hdimage="$options_hdimage -D_CHS_HEADS=$chsheads -D_CHS_SECTORS=$chssectors"
elif [[ "$1" == diskette ]]
then
shift
options_hdimage=""
dosemu_category="floppy"
dosemu_device="device"
dosemu_drive="A:"
qemu_switch="-fdb"
name="diskette"
bootfile="boot${bpe}tw.bin"
unit=01h
options_ldebug_unit="fdb"
options_mcopy_offset=""
diskette=1
if [[ "$1" == direct ]]
then
shift
qemu_switch="-fda"
unit=00h
direct=1
fi
else
echo "Error: Invalid disk type \"$1\" specified , must be hdimage or diskette" >&2
exit 1
fi
if [[ "$bpe" == 32 ]]
then
if [[ -z "$pitype" ]]
then
pitype=ptFAT32
fi
bootname=boot32
else
if [[ -z "$pitype" ]]
then
if [[ "$bpe" == 16 ]]
then
pitype=ptFAT16
else
pitype=ptFAT12
fi
fi
bootname=boot
fi
echo -ne 'failure\r\n' > result.txt
"$NASM" "${LDOSBOOT_DIR%/}"/$bootname.asm -w-user \
-D_LOAD_NAME="'TESTWRIT'" -D_LOAD_EXT="'SYS'" -D_FAT$bpe \
-D_UNIT=$unit \
"$@" \
"$options_i_lmacros" \
-D_MAP=boot${bpe}tw.map -l boot${bpe}tw.lst -o boot${bpe}tw.bin &&
"$NASM" "${LDOSBOOT_DIR%/}"/testwrit.asm \
"$options_i_lmacros" \
-o testwrit.bin -l testwrit.lst &&
"$NASM" "${LDOSBOOT_DIR%/}"/iniload.asm -w-user \
"$options_i_ldosboot" \
"$options_i_lmacros" \
"$options_i_scanptab" \
-D_PAYLOAD_FILE="'testwrit.bin'" -o testwrit.sys -l testwrin.lst \
-D_INILOAD_SIGNATURE='"TW"' &&
"$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \
-D_WARN_DEFAULT_OFF=1 \
-D_WARN_TOOMANYFAT=0 -D_WARN_ALIGNDATA=0 \
$options_hdimage -D_MBR_PART_TYPE="$pitype" \
-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_BOOTFILE="'$bootfile'" \
-D_UNIT=$unit \
"$@" \
-I ./ \
"$options_i_lmacros" \
"$options_i_bootimg"
(($?)) && exit $?
pgid="$(ps -o pgid= $$)"
function handle_timeout_process() {
stty sane
((debug)) && ps -e -o pgid=,comm=,pid= | grep -E "^\s*$pgid "
pidlist="$(ps -e -o pgid=,comm=,pid= |
grep -E "^\s*$pgid " |
grep -Ev " (bash|test.sh|ps|grep) ")"
pidlist="$(echo "$pidlist" |
sed -re 's/^\s+//g' |
tr -s " " | cut -d" " -f 3)"
if [[ -n "$pidlist" ]]
then
((debug)) && ps $pidlist
kill $pidlist
fi
}
if ((! diskette))
then
if ((dosemu))
then
seekmbr=8192
else
seekmbr=0
fi
"$NASM" "${LDOSMBR_DIR%/}"/oldmbr.asm -w-user \
"$options_i_ldosmbr" \
"$options_i_lmacros" \
-o oldmbr.bin &&
dd if=oldmbr.bin of=hdimage.img seek="$seekmbr" bs=1 count=440 conv=notrunc status=none
(($?)) && exit $?
"$NASM" "${INSTSECT_DIR%/}"/instsect.asm \
-w-macro-params-legacy \
-I ./ \
"$options_i_instsect" \
"$options_i_lmacros" \
-D_FAT12=0 -D_FAT16=0 -D_FAT32=0 -D_FAT$bpe=1 \
-D_PAYLOAD_FAT$bpe="'boot${bpe}tw.bin'" \
-o inst${bpe}tw.com -l inst${bpe}tw.lst -D_MAP=inst${bpe}tw.map
(($?)) && exit $?
if ((dosemu))
then
timeout --foreground 10 "$DOSEMU" \
-I "$dosemu_category { $dosemu_device $name.img }" \
-dumb -quiet > result.log 2>&1 -K "$PWD" \
-E "inst${bpe}tw.com $dosemu_drive" < /dev/null
rc=$?
handle_timeout_process
if ((rc))
then
if ((rc == 124))
then
echo "Error: instsect run timed out" >&2
fi
cat result.log
exit 1
fi
# && "$DOSEMU" -I "..." -dumb -K "$PWD" -E dirg.bat;
elif ((qemu))
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
"$NASM" quit.asm \
"$options_i_lmacros" \
-o quit.com &&
"$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \
"$options_i_lmacros" \
-D_COMPAT_"$BOOT_PROTOCOL"=1 \
-D_LBA=0 -D_USE_PART_INFO=0 -D_QUERY_GEOMETRY=0 \
$BOOT_OPTIONS \
-D_MAP=bootinst.map -l bootinst.lst -o bootinst.bin &&
"$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \
-I ./ \
"$options_i_ldebug" \
"$options_i_bootimg" \
"$options_i_lmacros" \
-o diskinst.img -l diskinst.lst \
-D_PAYLOADFILE="${BOOT_KERNEL##*/},${BOOT_COMMAND##*/},autoexec.bat,inst${bpe}tw.com,quit.com" \
-D_BOOTFILE="'bootinst.bin'"
(($?)) && exit $?
timeout --foreground 10 "$QEMU" -fda diskinst.img "$qemu_switch" "$name".img -boot order=a -display none 2> /dev/null
rc=$?
handle_timeout_process
if ((rc == 124))
then
echo "Error: instsect run timed out" >&2
exit 1
fi
fi
fi
if ((! direct))
then
"$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \
"$options_i_lmacros" \
-D_LOAD_NAME="'LDEBUG'" -D_LOAD_EXT="'COM'" \
-D_MAP=boot12db.map -l boot12db.lst -o boot12db.bin &&
"$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \
-I ./ \
"$options_i_ldebug" \
"$options_i_bootimg" \
"$options_i_lmacros" \
-o diskldbg.img -l diskldbg.lst \
-D_PAYLOADFILE="ldebug.com" -D_BOOTFILE="'boot12db.bin'"
(($?)) && exit $?
if ((dosemu))
then
timeout --foreground 10 "$DOSEMU" -input \
"$(echo -ne "boot $options_ldebug_unit"'\rif (rc) then boot quit\rq\r')" \
-I "floppy { device diskldbg.img }" \
-I "$dosemu_category { $dosemu_device $name.img }" \
-A -dumb 2> result.err > result.log < /dev/null
elif ((qemu))
then
( (sleep 2; "$SENDKEYS" "boot $options_ldebug_unit<ret>if (rc) then boot quit<ret>q<ret>" | socat - UNIX-CONNECT:qemu-monitor > /dev/null ) & > /dev/null)
timeout --foreground 10 "$QEMU" -fda diskldbg.img "$qemu_switch" "$name".img -boot order=a -monitor unix:qemu-monitor,server,nowait -display none 2> /dev/null
fi
else
if ((dosemu))
then
timeout --foreground 10 "$DOSEMU" \
-I "$dosemu_category { $dosemu_device $name.img }" \
"$options_dosemu_direct" -dumb 2> result.err > result.log < /dev/null
elif ((qemu))
then
timeout --foreground 10 "$QEMU" "$qemu_switch" "$name".img -display none 2> /dev/null
fi
fi
rc=$?
handle_timeout_process
if ((rc == 124))
then
echo "${testrunname}timeout"
fi
if [[ "$(mtype -t -i $name.img$options_mcopy_offset ::RESULT.TXT 2> /dev/null)" == success ]]
then
echo "${testrunname}success"
elif ((dosemu))
then
echo "${testrunname}failure, log contains:"
if [ ! -s result.log ]
then
echo "Result log file empty, dosemu error?"
fi
cat result.log | perl -e '
my %errorlookup = (
V => "Check value mismatch",
F => "File not found",
E => "Not enough file data",
R => "Disk read error",
B => "Bad chain / bad FS",
M => "Out of memory",
I => "FSIBOOT error",
S => "Fix sector size mismatch",
C => "Fix cluster size mismatch",
N => "Non-FAT load needs larger cluster size",
);
my $empty = 1;
while (<>) {
next if $empty and /^\s*$/;
next if /^(dosemu2 2|Configured: |Please test against)/;
next if /^(Get the latest code|Submit Bugs via|Ask for help in)/;
next if /^(This program comes with|This is free software,)/;
$empty = 0;
if (/^([A-Z])\x7/ and defined $errorlookup{$1}) {
s/^(.).//;
print "lDOS boot error condition letter \"$1\" = $errorlookup{$1}\n";
s/[\x7\n]//g;
s/^\s*$//;
next if /^(dosemu2 2|Configured: |Please test against)/;
next if /^(Get the latest code|Submit Bugs via|Ask for help in)/;
next if /^(This program comes with|This is free software,)/;
print;
print "\n" unless /^$/;
} else {
s/[\x7\n]//g;
print;
print "\n";
};
};'
else
echo "${testrunname}failure"
fi

867
test/ldosboot/testpl.asm Normal file
View File

@ -0,0 +1,867 @@
%if 0
Loader test payload
by C. Masloch, 2017
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
%endif
%include "lmacros2.mac"
numdef LARGE, 1
numdef PADDING, 0
struc BS
bsJump: resb 3
bsOEM: resb 8
bsBPB:
endstruc
struc EBPB ; BPB sec
bpbBytesPerSector: resw 1 ; offset 00h 0Bh
bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh
bpbReservedSectors: resw 1 ; offset 03h 0Eh
bpbNumFATs: resb 1 ; offset 05h 10h
bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32
bpbTotalSectors: resw 1 ; offset 08h 13h
bpbMediaID: resb 1 ; offset 0Ah 15h
bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32
bpbCHSSectors: resw 1 ; offset 0Dh 18h
bpbCHSHeads: resw 1 ; offset 0Fh 1Ah
bpbHiddenSectors: resd 1 ; offset 11h 1Ch
bpbTotalSectorsLarge: resd 1 ; offset 15h 20h
bpbNew: ; offset 19h 24h
ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h
ebpbFSFlags: resw 1 ; offset 1Dh 28h
ebpbFSVersion: resw 1 ; offset 1Fh 2Ah
ebpbRootCluster: resd 1 ; offset 21h 2Ch
ebpbFSINFOSector: resw 1 ; offset 25h 30h
ebpbBackupSector: resw 1 ; offset 27h 32h
ebpbReserved: resb 12 ; offset 29h 34h
ebpbNew: ; offset 35h 40h
endstruc
struc BPBN ; ofs B16 S16 B32 S32
bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h
resb 1 ; 01h 1Ah 25h 36h 41h
bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN
bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h
bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h
bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h
endstruc ; 1Ah 33h 3Eh 4Fh 5Ah
struc LOADSTACKVARS, -10h
lsvFirstCluster: resd 1
lsvFATSector: resd 1
lsvFATSeg: resw 1
lsvLoadSeg: resw 1
lsvDataStart: resd 1
endstruc
lsvclSignature equ "CL"
lsvclBufferLength equ 256
struc LOADDATA, LOADSTACKVARS - 10h
ldMemoryTop: resw 1
ldLoadTop: resw 1
ldSectorSeg: resw 1
ldFATType: resb 1
ldHasLBA: resb 1
ldClusterSize: resw 1
ldParaPerSector:resw 1
ldLoadingSeg: ; word
lsvCommandLine: ; word
.start: equ $ - lsvclBufferLength
.signature: resw 1
ldLoadUntilSeg: ; word
lsvExtra: ; word
.partition: resb 1 ; byte
.flags: resb 1 ; byte
endstruc
lsvefNoDataStart equ 1
lsvefPartitionNumber equ 2
struc LOADCMDLINE, LOADDATA - lsvclBufferLength
ldCommandLine:
.start: resb lsvclBufferLength
endstruc
%ifndef _MAP
%elifempty _MAP
%else ; defined non-empty, str or non-str
[map all _MAP]
%endif
cpu 8086
org 0
payload:
; The device header is of a fixed format.
; For our purposes, the 4-byte code for
; each the strategy entry and the
; interrupt entry is part of this format.
; (DOS may read the attributes or entrypoint
; offsets before calling either, so the
; inicomp stage needs to recreate in its
; entrypoints part exactly what we have here.)
device_header:
.next:
fill 2, -1, jmp strict short j_zero_entrypoint
dw -1
.attributes:
dw 8000h ; character device
.strategy:
dw .strategy_entry ; -> strategy entry
.interrupt:
dw .interrupt_entry ; -> interrupt entry
.name:
fill 8, 32, db "TESTPL$$" ; character device name
.strategy_entry:
fill 4, 90h, jmp device_entrypoint
.interrupt_entry:
fill 4, 90h, retf
j_zero_entrypoint:
jmp zero_entrypoint
nop
align 32, nop
kernel_entrypoint:
; cs:ip = load seg : 32 here
%if ($ - $$) != 32
%error Wrong kernel mode entrypoint
%endif
; S0 +28
pushf ; +26
push ax ; +24
push cs ; +22
call .push_ip
.push_ip:
pop ax
sub ax, .push_ip - kernel_entrypoint
push ax ; +20 IP
common_entrypoint:
push es ; +18 ES
push bx ; +16 BX
cmp word [cs:signature], 2638h
je sig1_valid
jmp sig_invalid
align 64, nop
dos_exe_entrypoint:
; cs:ip = PSP : 256 + 64 here
;
; Code must be position independent enough.
%if ($ - $$) != 64
%error Wrong EXE mode entrypoint
%endif
; S0 +28
pushf ; +26
push ax ; +24
push cs ; +22
call .push_ip
.push_ip:
pop ax
sub ax, .push_ip - dos_exe_entrypoint
push ax ; +20 IP
dos_com_entrypoint:
mov byte [cs:100h + loadmode], 1
mov ax, cs
add ax, 10h ; simulate kernel loading
push ax
jump_common_entrypoint:
mov ax, common_entrypoint
push ax
retf ; jump to cs + 10h : common_entrypoint
zero_entrypoint:
; S0 +28
pushf ; +26
push ax ; +24
push cs ; +22
call .push_ip
.push_ip:
pop ax
sub ax, .push_ip
push ax ; +20 IP
cmp word [cs:0], 20CDh
jne @F
cmp ax, 100h
je dos_com_entrypoint
@@:
push cx
mov cl, 4
shr ax, cl
mov cx, cs
add ax, cx
pop cx
push ax
jmp jump_common_entrypoint
device_entrypoint:
pushf
push ax
push cs
call .push_ip
.push_ip:
pop ax
sub ax, .push_ip - device_header.strategy_entry
push ax
mov byte [cs:loadmode], 2
mov word [cs:dev_sp], sp
mov word [cs:dev_exit], dev_exit.1
jmp common_entrypoint
sig_invalid:
call error
db "Signature invalid.", 0
sig1_valid:
push ds
push bx
mov bx, cs
add bx, (signature2 -$$+0) >> 4
mov ds, bx
cmp word [(signature2 -$$+0) & 0Fh], 2638h
pop bx
pop ds
jne sig_invalid
jmp sig_valid
msg:
.error: db "Test payload error: ", 0
.test: db "Test payload loaded.", 13, 10, 0
.psp_and_size_before: asciz "PSP at "
.psp_and_size_between: asciz "h, size of memory block is "
.psp_and_size_after: asciz "h paragraphs.",13,10
.cmdline.kern.none: asciz "No kernel command line given!",13,10
.cmdline_before.kern: asciz "Kernel command line = ",'"'
.cmdline_before.app: asciz "Application command line = ",'"'
.cmdline_before.device: asciz "Device command line = ",'"'
.cmdline_after: asciz '"',13,10
align 4
.foundname:
times 8+1+3+1 db 0
; buffer for base name (8) + dot (1) + ext (3) + NUL (1)
align 2
.foundname_none:
asciz "(None)"
.foundname_none_size: equ $ - .foundname_none
align 2
.names:
dw .name_first, 0
dw .name_second, 0
dw .name_third, 0
dw .name_fourth, 0
dw 0
.name_first: asciz "1st name"
.name_second: asciz "2nd name"
.name_third: asciz "3rd name"
.name_fourth: asciz "4th name"
.name_before: asciz ": "
.name_quote: asciz '"'
.name_after: asciz 13,10
align 4
dev_request_header:
dd 0
loadmode: dw 0 ; 0 = loaded as boot payload,
; 1 = loaded as DOS application,
; 2 = loaded as DOS device driver
dev_sp: dw 0
dev_exit: dw 0
.1:
mov sp, word [cs:dev_sp]
jmp .common_1
.2: mov sp, word [cs:dev_sp]
jmp .common_2
.common_2:
pop ax ; ss
pop ds
pop ax ; sp
pop bp
pop di
pop si
pop dx
pop cx
.common_1:
pop bx ; bx
pop es ; es
pop ax ; (IP)
pop ax ; (CS)
pop ax ; ax
mov word [es:bx + 3], 8103h
; error, done, error code: unknown command
popf ; flags
retf ; far return to DOS
error:
push cs
pop ds
mov si, msg.error
call disp_msg
pop si
call disp_msg
test byte [cs:loadmode], 2
jz .dos_or_bios
jmp near [cs:dev_exit]
.dos_or_bios:
test byte [cs:loadmode], 1
jz .bios
mov ax, 4C01h
int 21h
.bios:
xor ax, ax
int 16h
int 19h
disp_msg_asciz:
push ds
push si
push ax
push cs
pop ds
mov si, dx
call disp_msg
pop ax
pop si
pop ds
retn
disp_msg:
@@:
lodsb
test al, al
jz @F
call disp_al
jmp short @B
disp_al:
push ax
push bx
push dx
push bp
test byte [cs:loadmode], 1 | 2
jz .bios
mov dl, al
mov ah, 02h
int 21h
jmp .common
.bios:
mov ah, 0Eh
mov bx, 7
int 10h
.common:
pop bp
pop dx
pop bx
pop ax
@@:
retn
disp_msg_length:
push cx
jcxz .ret
.loop:
lodsb
call disp_al
loop .loop
.ret:
pop cx
retn
sig_valid:
; S0 +28
; pushf ; +26
; push ax ; +24
; push cs ; +22
; call .push_ip
;.push_ip:
; pop ax
; sub ax, .push_ip
; push ax ; +20 IP
; push es ; +18
; push bx ; +16
sti
cld
push cx ; +14
push dx ; +12
push si ; +10
push di ; +8
push bp ; +6
mov ax, sp
add ax, 22
push ax ; +4 SP
push ds ; +2
push ss ; +0
test byte [cs:loadmode], 2
jz @F
mov word [cs:dev_sp], sp
mov word [cs:dev_exit], dev_exit.2
mov word [cs:dev_request_header], bx
mov word [cs:dev_request_header + 2], es
cmp byte [es:bx + 2], 0 ; command code 0 (init) ?
jne dev_exit.2 ; else immediately return -->
mov byte [es:bx + 13], 0 ; number of units = 0
mov word [es:bx + 14 + 2], cs
and word [es:bx + 14], 0 ; -> after end of memory to allocate
or word [cs:device_header.next], -1
; fill in offset of device header link
@@:
mov si, sp
push ss
pop ds
mov di, table
push cs
pop es
loop_table:
mov bx, [es:di + 0]
mov al, 32
call disp_al
mov ax, [es:di + 2]
call disp_al
xchg al, ah
call disp_al
cmp bx, -1
je @F
mov al, '='
call disp_al
mov ax, [si + bx]
call disp_ax_hex
@@:
add di, 4
cmp di, table.end
jb loop_table
listnames:
test byte [cs:loadmode], 1 | 2
jnz .skip
mov bx, msg.names
push ss
pop ds
lea si, [bp + bsBPB + ebpbNew + BPBN_size]
mov cx, (512 - (bsBPB + ebpbNew + BPBN_size)) - 2
; -2 = AA55h sig
cmp word [bp + bsBPB + bpbSectorsPerFAT], 0
je @F
mov cx, (512 + (ebpbNew - bpbNew) - (bsBPB + ebpbNew + BPBN_size)) - 2
@@:
.nextname:
call findname
lahf
mov dx, [cs:bx]
call disp_msg_asciz
mov dx, msg.name_before
call disp_msg_asciz
sahf
jc @F ; skip quote if no name -->
mov dx, msg.name_quote
call disp_msg_asciz
@@:
mov dx, msg.foundname
call disp_msg_asciz
sahf
jc @F ; skip quote if no name -->
mov dx, msg.name_quote
call disp_msg_asciz
@@:
mov dx, msg.name_after
call disp_msg_asciz
sahf
mov ax, 0
jc @F ; set to zero if no name -->
lea ax, [si - 11] ; -> name in buffer
@@:
mov word [cs:bx + 2], ax ; -> name in buffer, or 0
add bx, 4
cmp word [cs:bx], 0
jne .nextname
.skip:
push cs
pop ds
mov si, msg.test
call disp_msg
test byte [cs:loadmode], 1
jz .skip_psp_dos
mov si, msg.psp_and_size_before
call disp_msg
mov ah, 51h
int 21h
mov ax, bx
call disp_ax_hex
mov si, msg.psp_and_size_between
call disp_msg
dec bx
mov es, bx
mov ax, word [es:3]
call disp_ax_hex
mov si, msg.psp_and_size_after
call disp_msg
mov si, msg.cmdline_before.app
call disp_msg
mov ah, 51h
int 21h
mov ds, bx
mov si, 81h
xor cx, cx
mov cl, byte [si - 1]
call disp_msg_length
push cs
pop ds
mov si, msg.cmdline_after
call disp_msg
jmp .after_cmdline
.skip_psp_dos:
test byte [cs:loadmode], 2
jz .skip_device
mov si, msg.cmdline_before.device
call disp_msg
les bx, [cs:dev_request_header]
les di, [es:bx + 18]
push es
pop ds
mov si, di
; Writing MS-DOS Device Drivers, second edition, page 349
; specifies the following as to the command line termination:
; "Note that the DEVICE= command string is terminated by an
; Ah when there are no arguments. When there are arguments,
; the string is terminated with the following sequence:
; 0h, Dh, Ah."
db __TEST_IMM8
@@:
inc di
cmp byte [di], 0
je @F
cmp byte [di], 13
je @F
cmp byte [di], 10
jne @B
@@: ; di -> at terminator
sub di, si
mov cx, di
call disp_msg_length
push cs
pop ds
mov si, msg.cmdline_after
call disp_msg
jmp .after_cmdline
.skip_device:
mov si, msg.cmdline.kern.none
cmp word [bp + ldCommandLine], 0FF00h
je .no_kernel_cmdline
mov si, msg.cmdline_before.kern
call disp_msg
push ss
pop ds
lea si, [bp + ldCommandLine]
call disp_msg
push cs
pop ds
mov si, msg.cmdline_after
.no_kernel_cmdline:
call disp_msg
.after_cmdline:
int3
test byte [cs:loadmode], 2
jz .dos_or_bios
jmp near [cs:dev_exit]
.dos_or_bios:
test byte [cs:loadmode], 1
jz .bios
mov ax, 4C00h
int 21h
.bios:
xor ax, ax
int 16h
int 19h
disp_ax_hex: ; ax
xchg al,ah
call disp_al_hex ; display former ah
xchg al,ah ; and fall trough for al
disp_al_hex: ; al
push cx
mov cl,4
ror al,cl
call disp_al_lownibble_hex ; display former high-nibble
rol al,cl
pop cx
; and fall trough for low-nibble
disp_al_lownibble_hex:
push ax ; save ax for call return
and al,00001111b ; high nibble must be zero
add al,'0' ; if number is 0-9, now it's the correct character
cmp al,'9'
jna .decimalnum ; if we get decimal number with this, ok -->
add al,7 ; otherwise, add 7 and we are inside our alphabet
.decimalnum:
call disp_al
pop ax
retn
; INP: ds:si -> first byte to check for name
; cx = number of bytes left
; OUT: (8+1+3+1)bytes[es:msg.foundname] = found name,
; converted to 8.3 ASCIZ format,
; "(None)" if none
; CY if no filename found,
; si = INP:si + INP:cx
; cx = 0
; NC if filename found,
; ds:si -> byte behind the name, thus ds:(si-11)-> name
; cx = number of bytes left
; CHG: di, ax
findname:
.:
cmp cx, 11 ; enough for another name ?
jb .none ; no -->
; (cx == 0 jumps here too)
.check:
push cx
push si
mov cx, 11
lodsb
mov ah, al ; check for same char in all 11 places
cmp al, 32 ; first character must not be blank
je .check_fail ; if it is -->
; cmp al, 5 ; first character may be 05h to indicate 0E5h
; je .check_pass
db __TEST_IMM8 ; (skip lodsb)
.check_loop_same:
lodsb
cmp ah, al
jne .check_loop_differs
call .check_character
jc .check_fail
loop .check_loop_same
; if we arrive here, all characters (while valid) are the
; same character repeated 11 times. we disallow this in case
; that the padding character is an allowed one (eg '&' 26h).
.check_fail:
pop si
pop cx
dec cx ; lessen the counter
inc si ; -> next position to check
jmp .
.check_character:
cmp al, 32
jb .check_character_fail
cmp al, 127
; je .check_character_fail
jae .check_character_fail
; note: with all characters >= 128 allowed,
; we get false positives in our sectors.
cmp al, '.'
je .check_character_fail
cmp al, '/'
je .check_character_fail
cmp al, '\'
je .check_character_fail
cmp al, 'a'
jb .check_character_pass
cmp al, 'z'
ja .check_character_pass
.check_character_fail:
stc
retn
.check_character_pass:
clc
retn
.check_loop:
lodsb
.check_loop_differs:
call .check_character
jc .check_fail
.check_pass:
loop .check_loop
pop ax ; (discard si)
sub si, 11 ; -> at name
call convert_name_to_asciz
; si -> behind name
pop cx
sub cx, 11 ; lessen the counter
clc
retn
.none:
add si, cx
mov di, msg.foundname
push si
push ds
push cs
pop ds
mov si, msg.foundname_none
mov cx, (msg.foundname_none_size + 1) >> 1
rep movsw
pop ds
pop si
xor cx, cx
stc
retn
; INP: ds:si -> 11-byte blank-padded name
; es:msg.foundname -> (8+1+3+1)-byte buffer
; OUT: ds:si -> behind 11-byte blank-padded name
; es:msg.foundname filled
; CHG: cx, di, ax
convert_name_to_asciz:
mov di, msg.foundname
mov cx, 8
rep movsb ; copy over base name, si -> extension
cmp byte [es:di - 8], 05h ; is it 05h ?
jne @F ; no -->
mov byte [es:di - 8], 0E5h ; yes, convert to 0E5h
@@:
db __TEST_IMM8 ; (skip dec)
@@:
dec di ; decrement -> at previous trailing blank
cmp byte [es:di - 1], 32 ; trailing blank ?
je @B ; yes -->
mov al, '.'
stosb ; store dot (if needed)
mov cl, 3
rep movsb ; copy over extension, si -> behind name
db __TEST_IMM8 ; (skip dec)
@@:
dec di ; decrement -> at previous trailing blank
cmp byte [es:di - 1], 32 ; trailing blank ?
je @B ; yes -->
cmp byte [es:di - 1], '.' ; trailing dot ? (only occurs if all-blank ext)
jne @F ; no -->
dec di ; -> at the dot
@@:
mov al, 0
stosb ; store filename terminator
retn
align 4
table:
dw +0, "SS"
dw +6, "BP"
dw +4, "SP"
dw +22, "CS"
dw +20, "IP"
dw +26, "FL"
db -1, -1, 13,10
dw +2, "DS"
dw +10, "SI"
dw +18, "ES"
dw +8, "DI"
db -1, -1, 13,10
dw +24, "AX"
dw +16, "BX"
dw +14, "CX"
dw +12, "DX"
db -1, -1, 13,10
dw +28, "S0"
dw +30, "S1"
dw +32, "S2"
dw +34, "S3"
dw +36, "S4"
dw +38, "S5"
dw +40, "S6"
dw +42, "S7"
db -1, -1, 13,10
dw +44, "S8"
dw +46, "S9"
dw +48, "SA"
dw +50, "SB"
dw +52, "SC"
dw +54, "SD"
dw +56, "SE"
dw +58, "SF"
db -1, -1, 13,10
.end:
signature:
dw 2638h
align 16, db 0
%if _LARGE
times 64 * 1024 db 0
%endif
signature2:
dw 2638h
%if _PADDING
times _PADDING - ($ - $$) db 0
%endif

1023
test/ldosboot/testwrit.asm Normal file

File diff suppressed because it is too large Load Diff