
%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 "lmacros2.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

	struc LOADDATA, LOADSTACKVARS - 10h
ldMemoryTop:	resw 1
ldLoadTop:	resw 1
ldSectorSeg:	resw 1
ldFATType:	resb 1
		resb 1
ldClusterSize:	resw 1
ldParaPerSector:resw 1
ldLoadingSeg:	resw 1
ldLoadUntilSeg:	resw 1
	endstruc


	cpu 8086
	org 0
start:

	xor cx, cx
	 push cs
	 pop ds
	mov si, relocator
	mov ax, 60h - ((relocator.end - relocator + 15) >> 4)
	mov es, ax
	xor di, di
	push ax
	push di		; stack: 5Ch (or thereabouts):0
	mov cx, (relocator.end - relocator + 1) >> 1
	rep movsw
	mov bx, 1000h
	mov ax, 60h
	mov es, ax
	mov ax, cs
	add ax, (payload -$$+0) >> 4
	mov ds, ax
	mov cx, (payload.end - payload) >> 4
	xor si, si
	xor di, di
	retf

relocator:
	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
@@:

	mov ax, 60h + ((payload.end - payload) >> 4)
	mov es, ax
	xor di, di
	xor si, si
	lea cx, [ bp + 512 ]
	rep movsb
	mov ss, ax
	mov sp, bp

	jmp 60h:0
.end:

	align 16
payload:
	incbin _PAYLOAD_FILE
	align 16, db 38
.end:

