import ldosboot from snapshot of hg b9b7d2cf8971
From https://hg.pushbx.org/ecm/ldosboot/file/b9b7d2cf8971
This commit is contained in:
parent
fb689c1372
commit
f84d9290b6
1854
test/ldosboot/boot.asm
Normal file
1854
test/ldosboot/boot.asm
Normal file
File diff suppressed because it is too large
Load Diff
1730
test/ldosboot/boot32.asm
Normal file
1730
test/ldosboot/boot32.asm
Normal file
File diff suppressed because it is too large
Load Diff
325
test/ldosboot/doc/ldosboot.src
Normal file
325
test/ldosboot/doc/ldosboot.src
Normal 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
10
test/ldosboot/doc/mak.sh
Executable 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
246
test/ldosboot/fdkernpl.asm
Normal 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
2477
test/ldosboot/iniload.asm
Normal file
File diff suppressed because it is too large
Load Diff
58
test/ldosboot/kernshim.asm
Normal file
58
test/ldosboot/kernshim.asm
Normal 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
566
test/ldosboot/multboot.asm
Normal 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
89
test/ldosboot/patch.sld
Normal 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
38
test/ldosboot/test/cfg.sh
Normal 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
|
60
test/ldosboot/test/quit.asm
Normal file
60
test/ldosboot/test/quit.asm
Normal 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
20
test/ldosboot/test/run.sh
Executable 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
491
test/ldosboot/test/test.sh
Executable 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
867
test/ldosboot/testpl.asm
Normal 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
1023
test/ldosboot/testwrit.asm
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user