Last active
January 9, 2024 13:23
-
-
Save yottatsa/0f1daa5a5f5c7199096dbc1d0e454ef1 to your computer and use it in GitHub Desktop.
PCP/M-86 loader for Apricot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; nasm bootcpm.com.asm -fbin -o bootcpm.com | |
; runs from dos to load the bootloader from drive 0 | |
CPU 8086 | |
USE16 | |
disklabeloff equ 0x040a | |
disklabelseg equ 0x040c | |
bootfrom equ 0x0408 | |
boot_locn equ 0x1a | |
boot_size equ 0x1e | |
section .text start=0x100 | |
xor ax, ax | |
mov es, ax ; bios data | |
mov word es:[bootfrom], 0 | |
mov ax, ds | |
mov [bufseg], ax | |
mov es:[disklabelseg], ax | |
mov si, disklabel | |
mov es:[disklabeloff], si | |
mov [bufoff], si | |
mov word [sector], 0 | |
mov word [sec_n], 1 | |
call diskio | |
mov ax, disklabel | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
mov bx, ds | |
add ax, bx | |
mov es, ax | |
mov si, loader | |
mov [bufoff], si | |
mov ax, word es:boot_locn | |
mov word [sector], ax | |
mov ax, es:boot_size | |
mov word [sec_n], ax | |
call diskio | |
mov ax, loader | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
mov bx, ds | |
add ax, bx | |
add ax, 8 | |
push ax | |
mov es, ax | |
; live-patching LOADER.SYS with new CPM3.SYS location | |
mov ax, cpm3 | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
mov bx, ds | |
add ax, bx | |
mov es:[0xc8], ax | |
mov es:[0xec], ax | |
mov es:[0xef], ax | |
add ax, 0x8 | |
mov es:[0x121], ax | |
mov es:[0x267], ax | |
xor ax, ax | |
push ax | |
retf | |
diskio: | |
push bx | |
push cx | |
mov bx, 0x39 | |
mov cx, 0x0b | |
mov dx, ds | |
mov si, diskio_s | |
int 0xfc | |
pop cx | |
pop bx | |
or ax, ax | |
ret | |
diskio_s: | |
drvn: dw 0 | |
op: dw 0 | |
sector: dw 0 | |
sec_n: dw 0 | |
bufoff: dw 0 | |
bufseg: dw 0 | |
section .data align=0x10 | |
disklabel: | |
loader equ disklabel + 0x200 | |
cpm3 equ loader + 0x600 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; | |
; ╔═════════════════════════════════════════════════════════════════════════╗ | |
; ║ This file is generated by The Interactive Disassembler (IDA) ║ | |
; ║ Copyright (c) 2000 by DataRescue sa/nv, <[email protected]> ║ | |
; ╚═════════════════════════════════════════════════════════════════════════╝ | |
; | |
; LOADER.SYS from http://actapricot.org/disks/aprid5ks.htm#apr00301.dsk | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Regular | |
interrupt segment byte private '' | |
assume cs:interrupt | |
assume es:nothing, ss:nothing, ds:nothing | |
db 380h dup(?) | |
intE0off dw ? ;DATA XREF: _cpmentry+D↓w | |
; _cpmentry+87↓w ... | |
intE0seg dw ? ;DATA XREF: _cpmentry+13↓w | |
; _cpmentry+8D↓w | |
db 6Ch dup(?) | |
BIOSCtlDevInt dw ? ;DATA XREF: cpmcode:61BE↓r | |
; cpmcode:61F3↓r ... | |
dw ? | |
dd ? | |
ExecInt dd ? ;DATA XREF: cpmcode:2BA0↓r | |
dd ? | |
interrupt ends | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Regular | |
bios segment byte private '' | |
assume cs:bios | |
;org 400h | |
assume es:nothing, ss:nothing, ds:nothing | |
db 7 | |
public machinetype | |
machinetype db 0 ;DATA XREF: sub_158CE+2D↓r _entry+E↓r | |
public ramsize | |
ramsize dw 4000h ;DATA XREF: _entry+13↓r | |
dd 56781234h | |
public bootfrom | |
bootfrom dw 0 ;DATA XREF: read_disk+D↓r | |
public disklabelptr | |
disklabelptr dw 0B0h ;DATA XREF: _entry+1C↓r _entry+7D↓r ... | |
dw 3E00h | |
dd 0 | |
db 0 | |
db 0 | |
db 0 | |
db 0 | |
public n_flphdd | |
n_flphdd dw 0 ;DATA XREF: _entry+12F↓r _entry+14C↓r ... | |
floppybpbptr dd 0 | |
dd 0 | |
dw 7FFFh | |
public usercodearea | |
usercodearea dw 0 ;DATA XREF: _entry+1CC↓r _entry+216↓r | |
dd 0 | |
db 0D8h dup(0) | |
dq 0FD100F040003h | |
dq 0 | |
db 0F0h dup(0) | |
db 0F9h dup(0) | |
dd 0 | |
dw 0 | |
afontptroff dw 0 ;DATA XREF: _entry+5E↓w | |
afontptrseg dw 0 ;DATA XREF: _entry+69↓w | |
dw 0 | |
mfontptroff dw 0 ;DATA XREF: _entry+62↓w | |
mfontptrseg dw 0 ;DATA XREF: _entry+6D↓w | |
dw 0 | |
keytabptroff dw 0 ;DATA XREF: _entry+A6↓w | |
keytabptrseg dw 0 ;DATA XREF: _entry+AA↓w | |
dw 0 | |
dd 0 | |
dw 0 | |
dd 0 | |
dd 0 | |
dd 0 | |
dd 0 | |
dd 0 | |
db 0CEh dup(0) | |
bios ends | |
; File Name : CPM3.SYS | |
; | |
; included for the reference | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Pure code | |
cpmhead segment byte private 'C86CMDHEAD' | |
assume cs:cpmhead | |
assume es:nothing, ss:nothing, ds:nothing | |
cpmcodesize dw 88Ch ;DATA XREF: _entry+F3↓r | |
dw seg cpmcode | |
dw 88Ch | |
dw 0 | |
cpmdatasize dw 65Ch ;DATA XREF: _entry+F7↓r | |
dw seg cpmdata | |
dw 723h | |
dw 0 | |
db 6Eh dup(0) | |
cpmhead ends | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Pure code | |
cpmcode segment page private 'CODE' | |
assume cs:cpmcode | |
assume es:nothing, ss:nothing, ds:nothing | |
; ███████████████ S U B R O U T I N E ███████████████████████████████████████ | |
_cpmentry proc far | |
jmp loc_F088 | |
; ─────────────────────────────────────────────────────────────────────────── | |
jmp near ptr intE0 | |
; ─────────────────────────────────────────────────────────────────────────── | |
cpmdataseg dw seg cpmdata ;DATA XREF: _cpmentry+17↓r intE0+1↓r ... | |
; ─────────────────────────────────────────────────────────────────────────── | |
loc_F088: ;CODE XREF: _cpmentry↑j | |
cli | |
xor ax, ax | |
mov ds, ax | |
assume ds:bios | |
mov intE0off, offset intE0 | |
mov intE0seg, cs | |
mov bx, cs:cpmdataseg | |
mov ds, bx | |
assume ds:cpmdata | |
mov ax, stackseg | |
mov cl, 4 | |
shr ax, cl | |
add ax, bx | |
mov stackseg, ax | |
mov word_17990, ax | |
mov word_1798A, ax | |
mov ss, ax | |
mov sp, 160h | |
loc_F0B5: ;CODE XREF: _cpmentry+53↓j | |
mov es, ax | |
mov word ptr es:70h, offset word_F225 | |
mov es:72h, cs | |
mov ax, es:2 | |
test ax, ax | |
jz loc_F0D5 | |
shr ax, cl | |
add ax, bx | |
mov es:2, ax | |
jmp short loc_F0B5 | |
; ─────────────────────────────────────────────────────────────────────────── | |
loc_F0D5: ;CODE XREF: _cpmentry+49↑j | |
mov es, stackseg | |
mov es:54h, cs | |
cld | |
push dx | |
mov cx, 7 | |
mov bx, 2 | |
loc_F0E6: ;CODE XREF: _cpmentry+6F↓j | |
push bx | |
push cx | |
call word ptr [bx] | |
pop cx | |
pop bx | |
add bx, 4 | |
loop loc_F0E6 | |
pop dx | |
call dword ptr word_1796C | |
sti | |
mov al, byte_179D2 | |
mov es:36h, al | |
mov byte_17AF6, al | |
push es | |
xor si, si | |
push ds | |
mov ds, si | |
assume ds:bios | |
mov intE0off, offset intE0 | |
mov intE0seg, cs | |
mov di, 56h ; 'V' | |
mov cx, 4 | |
repe movsw | |
mov cl, 4 | |
add si, cx | |
repe movsw | |
mov si, 380h | |
mov cl, 4 | |
repe movsw | |
pop es | |
pop ds | |
assume ds:nothing | |
mov di, 2B9h | |
mov si, 56h ; 'V' | |
mov cl, 0Ch | |
repe movsw | |
xor cx, cx | |
mov dx, cx | |
int 0E0h ; ; CP/M interupt? | |
retn | |
_cpmentry endp | |
; ─────────────────────────────────────────────────────────────────────────── | |
word_F225 dw 0E9CBh ;DATA XREF: _cpmentry+37↑o | |
; ─────────────────────────────────────────────────────────────────────────── | |
cpmcode ends | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Pure data | |
cpmdata segment byte private 'DATA' | |
assume cs:cpmdata | |
word_1796C dw 0 ;DATA XREF: _cpmentry+72↑r | |
off_17978 dd loc_FF31 ;DATA XREF: cpmcode:62B2↑r | |
off_1797C dd sub_1078B ;DATA XREF: cpmcode:6278↑r | |
word_1798A dw 8A0h ;DATA XREF: _cpmentry+2D↑w | |
stackseg dw 8A0h ;DATA XREF: _cpmentry+1E↑r | |
; _cpmentry+27↑w ... | |
word_17990 dw 0 ;DATA XREF: _cpmentry+2A↑w | |
word_17998 dw 10h ;DATA XREF: _entry+231↓r _entry+234↓w ... | |
word_1799A dw 1000h ;DATA XREF: _entry+22B↓r | |
byte_179D2 db 0 ;DATA XREF: _cpmentry+77↑r | |
byte_17AF6 db 0 ;DATA XREF: _cpmentry+7E↑w | |
word_17C10 dw 0 ;DATA XREF: read_disk+1F↓w | |
word_18888 dw 11F2h ;DATA XREF: cpmcode:6270↑r | |
byte_18B9A db 0 ;DATA XREF: cpmcode:6284↑w | |
cpmdata ends | |
; File Name : LOADER.SYS | |
; Format : Binary File | |
; Base Address: 3E00h Range: 3E000h - 3E580h Loaded length: 0580h | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Regular | |
head segment byte public 'C86CMDHEAD' | |
assume cs:head | |
assume es:nothing, ss:nothing, ds:nothing | |
db 1 | |
dw 3Eh | |
dw 0 ; relocatable | |
dw 3Eh | |
dw 0 | |
db 2 | |
dw 10h | |
dw 0 ; relocatable | |
dw 10h | |
dw 0 | |
db 6Eh dup(0) | |
head ends | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Regular | |
code segment page public '' | |
assume cs:code | |
assume es:nothing, ss:nothing, ds:nothing | |
; ███████████████ S U B R O U T I N E ███████████████████████████████████████ | |
; Attributes: noreturn static | |
public _entry | |
_entry proc far | |
mov ax, cs | |
mov ds, ax | |
assume ds:stack | |
mov ss, ax | |
assume ss:stack | |
mov sp, offset stacktop | |
mov ax, 0 | |
mov es, ax | |
assume es:bios | |
mov dl, es:machinetype | |
mov bx, es:ramsize | |
mov temp, bx | |
les di, dword ptr es:disklabelptr | |
assume es:nothing | |
mov ax, es:[di+disklabel.CNF_FONT_sec] | |
or ax, ax | |
jz loadkeys | |
mov sector, ax | |
cmp dl, 0 ; if machine type is Xi | |
jz xifont | |
add sector, 10h | |
mov sec_n, 9 | |
sub bx, 120h | |
mov bufseg, bx | |
jmp short loadfont | |
; ─────────────────────────────────────────────────────────────────────────── | |
xifont: ;CODE XREF: _entry+30↑j | |
mov bufseg, 80h | |
mov sec_n, 10h | |
loadfont: ;CODE XREF: _entry+45↑j | |
call read_disk | |
or ax, ax | |
jnz loadkeys | |
xor ax, ax | |
mov es, ax | |
assume es:bios | |
mov es:afontptroff, ax | |
mov es:mfontptroff, ax | |
mov ax, bufseg | |
mov es:afontptrseg, ax | |
mov es:mfontptrseg, ax | |
mov temp, bx | |
loadkeys: ;CODE XREF: _entry+28↑j _entry+58↑j | |
xor ax, ax | |
mov es, ax | |
mov bx, temp | |
les di, dword ptr es:disklabelptr | |
assume es:nothing | |
mov ax, es:[di+disklabel.CNF_KEYS_sec] | |
or ax, ax | |
jz loadcpmhead | |
mov sector, ax | |
mov sec_n, 2 | |
sub bx, 40h ; 2 sectors from the end of RAM | |
mov bufseg, bx | |
call read_disk | |
or ax, ax | |
jnz loadcpmhead | |
xor ax, ax | |
mov es, ax | |
assume es:bios | |
mov es:keytabptroff, ax | |
mov es:keytabptrseg, bx | |
mov temp, bx | |
loadcpmhead: ;CODE XREF: _entry+89↑j _entry+A0↑j | |
xor ax, ax | |
mov es, ax | |
les di, dword ptr es:disklabelptr | |
mov ax, es:[di+disklabel.CNF_DOS_sec] | |
mov sector, ax | |
mov bufseg, seg cpmhead | |
mov sec_n, 1 | |
call read_disk | |
or ax, ax | |
jz $+2 | |
xor ax, ax | |
mov es, ax | |
les di, dword ptr es:disklabelptr | |
assume es:cpmhead | |
mov ax, es:[di+8Ah] | |
mov sector, ax | |
mov bufseg, seg cpmhead | |
mov ax, seg cpmhead | |
mov es, ax | |
mov ax, es:cpmcodesize | |
add ax, es:cpmdatasize | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
shr ax, 1 | |
inc ax | |
inc ax | |
mov sec_n, ax | |
call read_disk | |
or ax, ax | |
jz $+2 ; delay after reading the disk | |
mov si, 0F08h | |
cmp sec_n, 80h | |
jb fillfdds ; si=0C18h if CPM3.SYS > 80 sectors | |
mov si, 0C18h | |
fillfdds: ;CODE XREF: _entry+11B↑j | |
mov ax, seg cpmcode | |
mov es, ax | |
assume es:cpmcode | |
mov ax, es:cpmdataseg | |
mov ds, ax | |
assume ds:cpmdata | |
xor ax, ax | |
mov es, ax | |
assume es:bios | |
mov ax, es:n_flphdd | |
test al, al ; if no floppies | |
jz fillhdds | |
mov bx, [si+4] | |
push ax | |
call sub_3E301 | |
call sub_3E2EE | |
pop ax | |
cmp al, 1 | |
jz fillhdds | |
mov bx, [si+6] | |
call sub_3E2EE | |
fillhdds: ;CODE XREF: _entry+135↑j _entry+144↑j | |
mov ax, es:n_flphdd | |
test ah, ah ; if no hdds | |
jz setfdd2 | |
push ax | |
mov bx, [si] | |
call sub_3E301 | |
call sub_3E2EE | |
mov ax, [bx+0Eh] | |
mov bx, [si+4] | |
mov [bx+0Eh], ax | |
mov bx, [si+6] | |
mov [bx+0Eh], ax | |
pop ax | |
cmp ah, 1 | |
jz setfdd2 | |
mov bx, [si+2] | |
call sub_3E2EE | |
setfdd2: ;CODE XREF: _entry+152↑j _entry+170↑j | |
mov ax, es:n_flphdd | |
cmp al, 2 ; 2 or more floppies | |
jnb setfdd1 | |
mov word ptr [si+6], 0 | |
setfdd1: ;CODE XREF: _entry+17E↑j | |
cmp al, 1 ; 1 or more floppies | |
jnb sethdd2 | |
mov word ptr [si+4], 0 | |
sethdd2: ;CODE XREF: _entry+187↑j | |
cmp ah, 2 ; 2 or more hdds | |
jnb sethdd1 | |
mov cx, [si+4] | |
mov [si+2], cx | |
mov cx, [si+6] | |
mov [si+4], cx | |
mov word ptr [si+6], 0 | |
sethdd1: ;CODE XREF: _entry+191↑j | |
cmp ah, 1 ; 1 or more hdds | |
jnb loc_3E239 | |
mov cx, [si+2] | |
mov [si], cx | |
mov cx, [si+4] | |
mov [si+2], cx | |
mov word ptr [si+4], 0 | |
loc_3E239: ;CODE XREF: _entry+1A7↑j | |
cmp cs:sec_n, 80h | |
jnb loc_3E28D | |
mov si, 0F56h ; if CPM3.SYS < 80s | |
xor ax, ax | |
mov es, ax | |
mov cx, 7 | |
cmp es:usercodearea, 500h | |
jnz loc_3E25B | |
dec cx | |
add si, 6 | |
jmp short loc_3E26C | |
; ─────────────────────────────────────────────────────────────────────────── | |
loc_3E25B: ;CODE XREF: _entry+1D3↑j | |
mov ax, [si+6] | |
mov [si], ax | |
mov ax, [si+8] | |
mov [si+2], ax | |
mov ax, [si+0Ah] | |
mov [si+4], ax | |
loc_3E26C: ;CODE XREF: _entry+1D9↑j | |
mov ax, cs:temp | |
sub ax, [si] | |
mov [si+2], ax | |
add si, 6 | |
loc_3E278: ;CODE XREF: _entry+208↓j | |
mov word ptr [si], 0 | |
mov word ptr [si+2], 0 | |
mov byte ptr [si+4], 0FFh | |
add si, 6 | |
loop loc_3E278 | |
jmp boot | |
; ─────────────────────────────────────────────────────────────────────────── | |
loc_3E28D: ;CODE XREF: _entry+1C0↑j | |
xor ax, ax ; if CPM3.SYS >= 80s | |
mov es, ax | |
mov cx, cs:temp | |
mov dx, es:usercodearea | |
mov bx, 5Ah | |
loc_3E29E: ;CODE XREF: _entry+229↓j | |
mov si, bx | |
mov bx, [bx] | |
test bx, bx | |
jz loc_3E2AB | |
cmp dx, [bx+2] | |
ja loc_3E29E | |
loc_3E2AB: ;CODE XREF: _entry+224↑j | |
cmp word_1799A, bx | |
jz loc_3E2BA | |
mov ax, word_17998 | |
mov word_17998, bx | |
mov [si], ax | |
loc_3E2BA: ;CODE XREF: _entry+22F↑j | |
mov bx, 5Ah | |
loc_3E2BD: ;CODE XREF: _entry+24D↓j | |
mov si, bx | |
mov bx, [bx] | |
test bx, bx | |
jz boot | |
mov ax, [bx+2] | |
add ax, [bx+4] | |
cmp ax, cx | |
jbe loc_3E2BD | |
mov word ptr [si], 0 | |
mov si, bx | |
loc_3E2D5: ;CODE XREF: _entry+25B↓j | |
mov di, bx | |
mov bx, [bx] | |
test bx, bx | |
jnz loc_3E2D5 | |
mov ax, word_17998 | |
mov word_17998, si | |
mov [di], ax | |
boot: ;CODE XREF: _entry+20A↑j _entry+243↑j | |
mov ax, seg cpmcode | |
push ax | |
xor ax, ax | |
push ax | |
retf | |
_entry endp ; sp = -4 | |
; ███████████████ S U B R O U T I N E ███████████████████████████████████████ | |
sub_3E2EE proc near ;CODE XREF: _entry+13E↑p _entry+149↑p ... | |
push si | |
mov dx, cs:temp | |
sub dx, [bx+12h] | |
mov [bx+12h], dx | |
mov cs:temp, dx | |
pop si | |
retn | |
sub_3E2EE endp | |
; ███████████████ S U B R O U T I N E ███████████████████████████████████████ | |
sub_3E301 proc near ;CODE XREF: _entry+13B↑p _entry+157↑p | |
push si | |
mov si, [bx+10h] | |
mov si, [si] | |
mov dx, cs:temp | |
loc_3E30C: ;CODE XREF: sub_3E301+16↓j | |
sub dx, [si+0Ah] | |
mov [si+0Ah], dx | |
mov si, [si+0Ch] | |
or si, si | |
jnz loc_3E30C | |
mov cs:temp, dx | |
pop si | |
retn | |
sub_3E301 endp | |
; ███████████████ S U B R O U T I N E ███████████████████████████████████████ | |
read_disk proc near ;CODE XREF: _entry+53↑p _entry+9B↑p ... | |
push bx | |
push cx | |
push es | |
mov bx, 39h ; DEV: FDD | |
mov cx, 0Bh ; COM: READ | |
xor ax, ax | |
mov es, ax | |
mov ax, es:bootfrom | |
cmp ax, 2 ; if boot from id>=2, means hdd | |
jb loc_3E33F | |
sub ax, 2 | |
mov bx, 40h ; DEV: HDD | |
mov cx, 5 ; COM: READ | |
loc_3E33F: ;CODE XREF: read_disk+14↑j | |
mov word_17C10, ax | |
mov dx, ds | |
mov si, offset drive_no | |
int 0FCh | |
pop es | |
assume es:nothing | |
pop cx | |
pop bx | |
or ax, ax | |
retn | |
read_disk endp | |
; ─────────────────────────────────────────────────────────────────────────── | |
db 0 | |
drive_no dw 0 ;DATA XREF: read_disk+24↑o | |
dw 0 | |
sector dw 0 ;DATA XREF: _entry+2A↑w _entry+32↑w ... | |
sec_n dw 0 ;DATA XREF: _entry+37↑w _entry+4D↑w ... | |
dw 0 | |
bufseg dw seg bios ;DATA XREF: _entry+41↑w _entry+47↑w ... | |
temp dw 0 ;DATA XREF: _entry+18↑w _entry+71↑w ... | |
code ends | |
; ═══════════════════════════════════════════════════════════════════════════ | |
; Segment type: Regular | |
stack segment byte public '' | |
assume cs:stack | |
;org 2DEh | |
assume es:nothing, ss:nothing, ds:nothing | |
db 100h dup(0) | |
stacktop db 0 ; ;DATA XREF: _entry+6↑o | |
db 121h dup(0) | |
stack ends | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
boot fails on loadingCPM3.SYS
fully in memory