title 'MP /M-86 Loader' ; The MPMLDR consists of this module along with the ; LDBDOS and LDBIOS. The LDBDOS is the same as for ; for CP/M-86, and the LDBIOS has only the login message ; changed. ; MPMLDR resides on the first two tracks of a ; MP/M-86 system diskette and is brought into memory ; by the ROM bootstrap loader to load initiate MP/M-86 ; It opens the file 'MPM.SYS' using the LDBDOS and LDBIOS ; and then reads it into memory. The DS register is set ; to the start of the MPM DATA area, and a JMPF to the ; first byte of the MPM code is executed. ; The first 128 byte record of the MPM.SYS file is a header ; with the following format: ; ty rb 1 ;seg type ; len rw 1 ;length ; abs dw 1 ;absolute segment address for LOADER ; min rw 1 ;minimum mem ; max rw 1 ;max mem needed ; The code is expected first and then the data within MPM.SYS ; This header record is constructed automatically by the ; GENSYS-86 utility. See the variables declared at 'SEC1:' ; where the first sector of MPM.SYS will be read ; MPMLDR may be read into any segment that does not ; overlap the desired system load segment as it makes ; all memory references using copies of the CS: register ; it is entered with. ; ; For debugging under CP/M and DDT a 'IB' can be used to force a ; break to DDT just before 'Far Jumping' to MPM. ; false equ 0 true equ not false cr equ 0dh lf equ 0ah ldbdos_offset equ 406H ;offset of LDBDOS mldbios_offset equ 1200h ;offset of LDBIOS bdos_int equ 224 ;lbdos interrupt number bootdrv equ 0 ; boot drive always zero codetype equ 1 ; code type CMD header datatype equ 2 ; data type CMD header ; dummy section for interrupt vectors dseg 0 org 0 abs_zero rw 2*bdosint bdos_offset rw 1 bdos_segment rw 1 fcb1 equ 5dh ; look here for 'B' to break ddt_int equ 3 ; DDT interrupt ; bdos function numbers coutf equ 2 pstrf equ 9 seldsk equ 14 openf equ 15 readsf equ 20 dmaf equ 26 dmabf equ 51 ;******************************* ;* ;* MPMLDR starts here ;* ;******************************* cseg ; JMPF to here from boot ROM org 0 jmp start ; if loaded under DDT this ; gets overlayed and IP = 100H ; want 100h byte header for ; 'IB' option db 'COPYRIGHT (C) 1981,' ; found by serial program db ' DIGITAL RESEARCH ' db '654321' db ' MP/M-86 Loader V2.0 (9/21/81)' org 80H ; read first sector of MPM.SYS sec1 rb 128 ; here org offset sec1 ;CMD header fields ctype rb 1 ;type clen rw 1 ;length cldseg rw 1 ;abs cmin rw 1 ;minimum cmax rw 1 ;maximum dtype rb 1 dlen rw 1 dldseg rw 1 dmin rw 1 dmax rw 1 org 100H start: ; execution begins here if DDT jmp mldbios ; initialize mldbios ; mldbios returns here: 103H xor ax,ax ! mov ds,ax ; temp DS at absolute zero mov bdos_offset,offset ldbdos_offset ; to patch in interrupt table mov bdos_segment,cs ; offset and segment mov ax,cs ! mov ss,ax ; make ss, ds, es = cs mov ds,ax ! mov es,ax mov sp,offset(stack) ; set up local stack mov dx,offset signon call msg call initlbdos ; warm up lbdos and lbios call openfnc ; open MPM.SYS cmp al,255 ! jne perr ; insure good file mov dx,offset nofile ! call msg ; no MPM.SYS file jmp stop ; then halt the machine perr: mov dx,cs ! call setdmab mov dx,offset sec1 ! call setdma ; read first sector of MPM.SYS call read cmp ctype,codetype ; code should be first jnz badhdr cmp dtype,datatype ; then data jnz badhdr mov ax,cldseg ; code abs + code length add ax,clen ; should be = to data abs cmp ax,dldseg ! jnz badhdr add ax,dlen ! cmp ax,cldseg ; check for wrap around ja hdrok badhdr: mov dx,offset hdrerr ! call msg jmp stop hdrok: mov dx,offset csegment ! call msg ; put memory map on console mov ax,cldseg ! call phex ; print base code segment mov dx,offset dsegment ! call msg ; print base data segment mov ax,dldseg ! call phex ; mov dx,cldseg mov dmab,dx ; initial DMA segment readit1: call setdmab ; set DMA segment for disk IO mov dx,0 ; offset of MPM in segment readit2: call setdma ; set DMA offset for push dx ! call read ; next sector read cmp al,01H ! je done ; check for EOF cmp al,0 ! je prerr ; check for good write mov dx,offset rerr ! call msg ; print READ ERROR message jmp stop ; hard stop on any error prerr: pop dx ! add dx,80H cmp dx,0 ; more than 64K ? jnz readit2 add dmab,1000h ; add 64K to base mov dx,dmab jmp readit1 done: pop ax ; number of bytes read mov cl,4 shr ax,cl ; number of paragraphs read add ax,dmab ; number of 64K segments read sub ax,cldseg ; (dmab - cldseg) mov cx,clen add cx,dlen cmp ax,cx jae lenok ; MPM.SYS at least as long mov dx,offset shortmsg ; as header claims ? call msg ! jmp stop lenok: push cx ; clen + dlen in cx mov dx,offset lenmsg ! call msg ; print length message pop ax add ax,cldseg dec ax ; last paragraph call phex call pcrlf ; and a crlf mov ax,cldseg mov mpmcseg,ax mov ds,dldseg ; MP/M data segment mov al, cs:.fcb1 ; must use CS over-ride cmp al,'B' jnz gompm int ddt_int ; break to mpm gompm: jmpf mpm ; leap to MPM initialization ;***************************** ;* ;* subroutines ;* ;***************************** ;****** phex: ;print 4 hex characters from ax mov cx,0404h ; 4 in both CH and CL lhex: rol ax,cl ; rotate left 4 push cx ! push ax ; save crucial registers call pnib ; print hex nibble pop ax ! pop cx ; restore registers dec ch ! jnz lhex ; and loop four times ret pnib: ;print low nibble in AL as hex char and al,0fh ! cmp al,9 ja p10 ;above 9 ? add al,'0' ;digit jmp prn p10: add al,'A'-10 ;char a-e prn: mov dl,al ;****** putchar: mov cl,coutf jmp sys_vec ;****** initlbdos: mov cl,seldsk ! mov dx,bootdrv ; select boot disk jmp sys_vec ;****** openfnc: mov cl,openf ! mov dx,offset fcb ; fcb already initialized mov cl,openf jmp sys_vec ;******** ; setdma: ;set new dma addr in dx mov cl,dmaf jmp sys_vec ;******** ; setdmab: ; set new dma segment base from DX mov cl,dmabf jmp sys_vec ;****** ; pcrlf: mov dx,offset crlf ;print carriage return, line feed ;****** ; msg: ;print msg starting at dx until $ mov cl,pstrf ;print string function jmp sys_vec ;***** ; read: mov dx,offset fcb ! mov cl,readsf ; jmp sys_vec ;****** ; sys_vec: int bdos_int ret ;****** ; stop: mov ax,0 ; hard stop 8086 for error mov ds,ax mov word ptr .8h,ax mov word ptr .0ah,cs stop2: jmp stop2 ;******************************** ;* ;* DATA AREA ;* ;******************************** signon db cr,lf,lf,'MP/M-86 V2.0 Loader',cr,lf,'$' nofile db cr,lf,'The File MPM.SYS Not Found On This Disk$' rerr db cr,lf,'Error In Reading MPM.SYS$' hdrerr db cr,lf,'Bad Header Record in MPM.SYS$' shortmsg db cr,lf,'MPM.SYS Too Short $' csegment db cr,lf,'Code Paragraph Address = $' dsegment db cr,lf,'Data Paragraph Address = $' lenmsg db cr,lf,'Last Paragragh = $' crlf db cr,lf,'$' ; vector for jmpf indirect to start MP/M mpm dd abs_zero ; (dummy value) org offset mpm ; overlay preceding with DW's mpmstart dw 0 ; first word of MPM code mpmcseg rw 1 ; second is segmet of MPM code dmab rw 1 ; current DMA segment fcb db 0,'MPM ','SYS',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; look on m disk first org (offset $+1) and 0FFFEh ; even address for stack rw 32 stack equ offset $ db 0 ; dummy section for BIOS init label org mldbios_offset mldbios: end