;*****************************************************
;*
;*	Program Load
;*
;*****************************************************
;
;	LDTAB Entry Format:
; 0           2           4           6           8
; +-----+-----+-----+-----+-----+-----+-----+-----+
; |   START   |    MIN    |    MAX    |    PD     |
; +-----+-----+-----+-----+-----+-----+-----+-----+
;
; 8           10(A)       12(C)       14(E)       16(10) 17(11)
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
; |    ATR    |   FSTRT   |   FLEN    | TYPE|    ID     |
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
;
;
;	start		Absolute Address requested
;	min		Min memory wanted
;	max		Max memory wanted
;	pd		PD to allocate to
;	atr		Attributes, Memory Flags
;	fstrt		Starting paragraph in File
;	flen		# of paragraphs in file
;	type		Group type
;	id		Segment Address of this group
;
;	The Load Table contains 9 entries, One for each
;	potential Group in Command File and One extra
;	for Independent Memory Allocations.

ldt_start	equ	word ptr 0
ldt_min		equ	word ptr ldt_start + word
ldt_max		equ	word ptr ldt_min + word
ldt_pd		equ	word ptr ldt_max + word
ldt_atr		equ	word ptr ldt_pd + word
ldt_fstrt	equ	word ptr ldt_atr + word
ldt_flen	equ	word ptr ldt_fstrt + word
ldt_type	equ	byte ptr ldt_flen + word
ldt_id		equ	word ptr ldt_type + byte
ldtlen		equ	ldt_id + word


;=========
cload_ent:	; entry point to load for a chain command
;=========
;	Assumes UDA is set in passed PD.

	push bx ! mov bx,1
	jmps load

;========
load_ent:	; User entry point to load .CMD file for execution
;========
;	input:	DX = address of open FCB in u_wrkseg
;	output:	BX = segment addr of Base Page
;		   = 0ffffh if error
;		CX = Error Code

	sub bx,bx
	;jmp load
;====
load:		; Intermodule entry point to load .CMD file
;====
;	input:	DX = addr of open FCB in u_wrkseg
;		BX = addr of unused PD to initialize
;		     0 - do not init PD
;		     1 - chain load (PD addr on stack)
;	output:	BX = seg addr of Base Page
;		   = 0ffffh if error
;		CX = Error Code

		; Get MXLoad Queue

	push dx ! push bx
	mov cx,f_qread ! mov dx,offset mxloadqpb
	call osif
	mov lod_chain,false
	pop lod_pd ! pop si
	cmp lod_pd,1 ! jne ld_cf
	    pop lod_pd ! mov lod_chain,true

		; Copy FCB into lod_fcb
		; SI-> user FCB in u_wrkseg

ld_cf:	mov cx,fcblen/2 ! mov di,offset lod_fcb
	push es ! push ds ! push ds
	mov ds,u_wrkseg ! pop es
	rep movsw
	pop ds ! pop es


		; Read the Header

	mov bx,offset lod_fcb
	mov byte ptr fcb_r0+2[bx],0
	mov ax,0			;record #
	mov bx,1			;# of sectors
	mov dx,offset lod_dma		;DMA offset
	mov cx,sysdat			;DMA segment
	call drd ! cmp di,1             ;check for EOF in header read
          je lod_eof
           jcxz ndpchk
lod_eof:
        mov cx, e_bad_load              ; tried to load a 0 length cmd file
        mov bx, 0ffffh                  ; or one whose header is incorrect
        jmp lod_exit
ndpchk:                                 ;see if 8087 required
        mov lod_ndp,0                   ;default = no
        mov bx, offset lod_dma
        test ch_lbyte[bx],need_8087
         jz ndp_flg                     ;not required - but is it optional?
        cmp owner_8087,0ffffh           ;needs it,but is there one in system?
         jnz ndp_yes                    ;yes- flag it
        mov cx,e_nondp                  ;no - abandon load & return
        mov bx, 0ffffh
         jmp lod_exit 
ndp_flg:
        test ch_lbyte[bx],opt_8087      ;will use it if present?
         jz h_hdr                       ;doesn't want it at all
        cmp owner_8087,0ffffh           ;will use it,but is there one ?
         jnz ndp_yes                    ;if not, flag it as an emulator user
        mov lod_ndp,1
         jmp h_hdr
ndp_yes:
        mov lod_ndp,0ffh                ;flag it as an 8087 user           
h_hdr:
        mov lod_suspnd,0                ;default = no suspend needed
        test ch_lbyte[bx],susp_mode     ;require background suspension ?
        jz h_hdr1                       ;no...
        mov lod_suspnd,0ffh             ;yes, flag pd later

h_hdr1:
	mov lod_indma,0

		; initialize Load Disk and User
		; from FCB

	mov bx,rlr
	mov al,p_user[bx]
	mov lod_user,al
	mov al,p_dsk[bx]	;default disk of calling PD
	mov lod_disk,al		;1-15 -> A-P
	mov bx,offset lod_fcb
	mov al,fcb_dr[bx]
	mov lod_fifty,al	;base page address 50H, 0=default
	test al,al ! jz use_ddsk
	    dec al		;1-15 -> A-P
	    mov lod_disk,al
use_ddsk:
	test byte ptr fcb_name+7[bx],080h ! jz use_dusr
	    mov lod_user,0
use_dusr:

		; Initialize ldtab

			; Zero ldtab
	mov cx,ldtabsiz/2 ! sub ax,ax
	mov di,offset ldtab
	push es ! mov es,sysdat
	rep stos ax ! pop es

			; 1st ldtab entry is UDA and LSTK
			; if a PD was specified...

	mov lod_nldt,0
	mov si,offset ldtab
	cmp lod_pd,0 ! jne sel_uda
		jmp gc_ifo
sel_uda: cmp lod_ndp,0                               ;see if 8087 user and long
          jz form_uda                                ;uda is needed
         cmp lod_ndp,0ffh                            ;no...
          jz form_87uda
form_emuda: mov ldt_min[si],(lstklen+em87len)/16     ;8087 emulator user
            mov ldt_max[si],(lstklen+em87len)/16     ;64 byte extension
             jmp cont_uda
form_87uda: mov ldt_min[si],(lstklen+u8087len)/16    ;8087 user
            mov ldt_max[si],(lstklen+u8087len)/16    ;96 byte extension
             jmp cont_uda
form_uda:   mov ldt_min[si],(lstklen+ulen)/16	     ;min=max=UDA+STK paragraphs
	    mov ldt_max[si],(lstklen+ulen)/16
cont_uda:   mov ax,lod_pd ! mov ldt_pd[si],ax
	    mov ldt_atr[si],mf_load
	    add si,ldtlen
	    inc lod_nldt
	    cmp lod_chain,true ! jne gc_ifo

			;We are CHAINING.  Free all memory
			; except UDA area and LDSTK.  This will keep
			; the first partition for the chain
			; as well as not crash the system.

		push si
		mov cx,f_freeall ! call osif

			;transfer memory to new pd

		mov bx,rlr
		mov ax,p_mem[bx] ! mov p_mem[bx],0
		mov bx,lod_pd ! mov p_mem[bx],ax
		pop si
		
gc_ifo:
			;go through CMD header and init
			;a ldtab entry per header entry.
			;alloc abs mem

	mov bx,offset lod_dma
        mov al,ch_lbyte[bx]     ; save fixup flag
        mov lod_lbyte,al
        mov ax,ch_fixrec[bx]    ; save record # of fixups, if any
        mov lod_fixrec,ax
	mov lod_fixrec1,ax

	mov cx,ch_entmax 	; BX = offset LOD_DMA
	mov dx,8		; DX = position in file
ch_more:cmp ch_form[bx],0 ! jne ch_doit
	jmp ch_next
ch_doit:    mov al,ch_form[bx] ! mov ldt_type[si],al	 ;type of seg
	    mov ax,ch_length[bx] ! mov ldt_flen[si],ax	;length
	    mov ldt_fstrt[si],dx ! add dx,ax		 ;pos in file
	    mov ax,ch_base[bx] ! mov ldt_start[si],ax	 ;abs seg
	    mov ax,ch_min[bx] ! mov ldt_min[si],ax	 ;min needed
	    mov ax,ch_max[bx]
	    cmp ax,0 ! jne setmax
		mov ax,ch_min[bx]
setmax:	    mov ldt_max[si],ax			 ;max wanted
	    mov ax,lod_pd ! mov ldt_pd[si],ax	 ;pd to alloc to
	    cmp ax,0 ! je not_load
		mov ax,mf_load
		jmps not_load
skipjmp:jmps ch_more

;if mpm

not_load:   cmp ch_form[bx],1 ! jne try_sh
		add ax,mf_code ! jmps s_atr
try_sh:	    cmp ch_form[bx],9 ! jne s_atr
		add ax,mf_code+mf_share
s_atr:      mov ldt_atr[si],ax			;memory flags

			;if abs, allocate memory
	    cmp ldt_start[si],0 ! je ch_nabs	;see if abs mem
		jmps ch_al
ch_nabs:    cmp ldt_type[si],9
	    jne ch_nxt		;see if shared code
	      push cx
	      push bx ! push dx	;save load DMA and position in file
	      call get_sh
	      pop dx ! pop bx
	      cmp cx,0 ! pop cx
	      je ch_nxt
		jmp ld_out
ch_al:		push bx ! push dx ! push cx ! push si
		mov cx,f_malloc ! mov dx,si
		call osif ! pop si
		mov ax,ldt_start[si] ! mov ldt_id[si],ax
		cmp cx,0 ! pop cx ! pop dx ! pop bx
		je ch_nxt
		    	;couldn't find memory
		    mov bx,0ffffh ! mov cx,e_no_memory
		    jmp ld_out

;endif

;if ccpm

;not_load:   cmp ch_form[bx],9 ! jne try_code
;		mov ch_form[bx],1
;		mov ldt_type[si],1
;try_code:   cmp ch_form[bx],1 ! jne s_atr
;		add ax,mf_code
;s_atr:	    mov ldt_atr[si],ax			;memory flags
;
;			;if abs, allocate memory
;	    cmp ldt_start[si],0 ! je ch_nxt	;see if abs mem
;ch_al:		push bx ! push dx ! push cx ! push si
;		mov cx,f_malloc ! mov dx,si
;		call osif ! pop si
;		mov ax,ldt_start[si] ! mov ldt_id[si],ax
;		cmp cx,0 ! pop cx ! pop dx ! pop bx
;		je ch_nxt
;		    	;couldn't find memory
;		    mov bx,0ffffh ! mov cx,e_no_memory
;		    jmp ld_out
;
;endif

ch_nxt:	add si,ldtlen
	inc lod_nldt
ch_next:add bx,chlen
	loop skipjmp

		; alloc all other memory
		; SI -> mpb for non_abs mem req.
			;add all parts together for a single malloc
	mov bx,offset ldtab
	mov cx,lod_nldt
	mov lod_nrels,0
lt_more:cmp ldt_min[bx],0 ! je lt_next
	    cmp ldt_start[bx],0 ! jne lt_next
		mov ax,ldt_min[bx]
		mov dx,ax
		add ldt_min[si],ax
		cmp dx,ldt_min[si] ! jbe lt_m	; check for ovrflw
		    mov ldt_min[si],0ffffh
lt_m:		mov ax,ldt_max[bx]
		mov dx,ax
		add ldt_max[si],ax
		cmp dx,ldt_max[si] ! jbe lt_m1	; check for ovrflw
		    mov ldt_max[si],0ffffh
lt_m1:		inc lod_nrels
lt_next:add bx,ldtlen ! loop lt_more

			;malloc
	cmp lod_pd,0 ! je noloadf
	    mov ldt_atr[si],mf_load
noloadf:mov ax,lod_pd ! mov ldt_pd[si],ax
	push si ! mov dx,si ! mov cx,f_malloc
	call osif ! pop si
	mov ax,ldt_start[si] ! mov ldt_id[si],ax
	cmp bx,0ffffh ! jne lt_sprd

	    		;Not Enough Memory - release any
			; memory already allocated
ld_out:	    push cx
	    mov bx,offset ldtab
	    mov cx,lod_nldt ! inc cx
lg_more:    cmp ldt_id[bx],0 ! je lg_next
		push cx ! push bx ! push ds
			;push MFPB on stack
		push ldt_pd[bx]
		push ldt_id[bx]
		mov dx,sp ! push ss ! pop ds		
		mov cx,f_memfree
		call osif
		pop cx ! pop cx

		pop ds ! pop bx ! pop cx
lg_next:    add bx,ldtlen ! loop lg_more
	    mov bx,0ffffh ! pop cx ! jmp lod_exit

lt_sprd:
			;spread the memory allocated
			;amongst the nrels
			;1st give everyone the minimum
	mov bx,offset ldtab
	mov cx,lod_nldt
ls_more:cmp ldt_start[bx],0 ! jne ls_next
	    mov ax,ldt_min[bx]
	    sub ldt_min[si],ax
	    cmp ax,ldt_max[bx] ! jne ls_next
		mov dx,ldt_start[si] ! mov ldt_start[bx],dx
		add ldt_start[si],ax
		dec lod_nrels
ls_next:add bx,ldtlen ! loop ls_more

			;spread whats left amongst those that need more
	mov bx,offset ldtab
	mov cx,lod_nldt
lsl_mre:cmp ldt_start[bx],0 ! jne lsl_nxt
	    mov ax,ldt_start[si] ! mov ldt_start[bx],ax
	    mov ax,ldt_min[si]
	    cmp ax,0 ! je adj_start
		push cx ! sub cx,cx
		mov dx,cx ! mov cl,lod_nrels
		div cx ! pop cx
		cmp dx,0 ! je evendiv
		    inc ax
evendiv:	mov dx,ldt_max[bx] ! sub dx,ldt_min[bx]
		cmp ax,dx ! jbe nottoomuch
		    mov ax,dx
nottoomuch:	add ldt_min[bx],ax ! sub ldt_min[si],ax
adj_start:  mov ax,ldt_min[bx] ! add ldt_start[si],ax
	    dec lod_nrels
lsl_nxt:add bx,ldtlen ! loop lsl_mre

		; fill memory from file

	mov si,offset ldtab
	mov cx,lod_nldt
lf_mre:	cmp ldt_flen[si],0 ! je lf_nxt
	    push cx ! push ldt_start[si] ! push si
	    call lod_group
	    pop si ! pop ldt_start[si]
	    cmp cx,0 ! pop cx
	    je lf_nxt

;if ccpm
;
;		jmp ld_out
;endif

;if mpm

			; error in lod_group
			; if loading shared code we also
			; have to release Shared Code from SCL.
			; It will be the top item in the list.

		cmp ldt_atr[si],mf_load+mf_code+mf_share
		je rm_sh
		    jmp ld_out
rm_sh:		push cx				; remember Err Code

			; Remove PD from SCL
		pushf ! cli
		mov bx,scl
		mov ax,p_thread[bx]
		mov scl,ax
		popf

			; Release the memory

		push ds ! push bx
		mov bx,p_mem[bx] ! push ms_start[bx]
		mov ax,ss ! mov ds,ax
		mov dx,sp ! mov cx,f_memfree
		call osif
		pop ax ! pop bx ! pop ds
		
			; Place PD on PUL

		pushf ! cli
		mov ax,pul
		mov pul,bx
		mov p_link[bx],ax
		popf

		pop cx
		jmp ld_out
;endif

lf_nxt:	add si,ldtlen ! loop lf_mre


;	 Check for fixup records and do fixups

        test lod_lbyte,80h        ; hi bit of last byte in cmd header
        jz init_base              ; is set if fixups
fx_read:
        mov ax,lod_fixrec         ; get record # of fixups in file
	mov bx,1                  ; read one record
        mov cx,ds                               
        mov dx, offset lod_dma
        call drd                  ; do random read
        jcxz fx_read_ok           ; 0=ok,CL=0ff if EOF
	  inc cl		  ; EOF ?
	  jnz fx_err		  ; some read error, not EOF
	    mov ax,lod_fixrec1	  ; make sure one fixup
	    cmp ax,lod_fixrec	  ; record was read since cmd header
	    je fx_err		  ; said we needed them
              jmps init_base

fx_read_ok:                       ; go look for fixup records
        mov bx,offset lod_dma	  ; BX-> at fixup records
fx_chk:
	mov al,fix_grp[bx]        ; any more fixups?
	test al,al
        jz init_base
        and al,0fh		  ; low nibble is target group
        call tblsrch              ; find target group in load table
        mov dx,ldt_start[di]      ; DX = target segment, this is
				  ; what we add to the load image
	mov al,fix_grp[bx]	  ; location group is high nibble
        mov cl,4                  ; put in low nibble of AL
        shr al,cl
        call tblsrch		  ; DI = location load table entry
        mov ax,ldt_start[di]      ; AX = base segment of location
	add ax,fix_para[bx]	  ; add paragraph offset

        push es                   ; absolute paragraph in memory
        mov es,ax
        xor ax,ax
        mov al,fix_offs[bx]       ; get offset of fixup location
	mov di,ax                 
        add es:[di],dx            ; make the fixup (finally)
        pop es

        add bx,fixlen             ; do next fixup
	cmp bx,offset lod_dma + dskrecl	; end of this record ?
        jne fx_chk
          inc lod_fixrec	  ; read another record	
          jmps fx_read		  ; of fixups

tblsrch:
;-------
;	Search for group in load table
;	entry:	AL = group # to match on
;	exit:	DI = load group entry that matches or
;		pop return and exit loader
;		BX,DX preserved

        mov cx,lod_nldt           ; # entries in table
        mov di,offset ldtab
srchloop:
        cmp al,ldt_type[di]
        je srchdn                 ; found group's entry
          add di,ldtlen
          loop srchloop
	  pop ax
	  jmps fx_err
srchdn:
	ret

fx_err:
	mov cx,e_fixuprec
	jmp ld_out


		; init Base Page
		; 	1st Data Group has Base Page
		;	if none then first nonshared
		;	Code Group (8080 model)	
init_base:
	mov lod_8080,0
	mov si,offset ldtab
	mov cx,lod_nldt
lb_more:cmp ldt_type[si],2 ! je lb_fnd
	    add si,ldtlen ! loop lb_more
		mov si,offset ldtab
		mov cx,lod_nldt
lbc_mre:	cmp ldt_type[si],1 ! je lb_fnd80
		    add si,ldtlen ! loop lbc_mre
			mov cx,e_no_cseg ! jmp ld_out
lb_fnd80:	mov lod_8080,1
lb_fnd:
	push es ! mov es,ldt_start[si]
	mov lod_basep,es
	sub ax,ax ! mov di,ax
	mov cx,05bh/2 ! rep stos ax
	mov al,lod_8080 ! mov es:.5,al
	mov si,offset ldtab
	mov cx,lod_nldt
lbb_mre:cmp ldt_type[si],0 ! je lbb_nxt
	    mov ax,6 ! mov bl,ldt_type[si]
	    cmp bl,9 ! jne lbb_nsh
		mov bl,1
lbb_nsh:    dec bl ! mul bl ! mov bx,ax

		;calculate last byte (3 byte value)
		;  =(paragraphs*16)-1
	    push cx ! mov dx,ldt_min[si]
	    push dx ! mov cl,4 ! shl dx,cl
	    push dx ! dec dx ! mov es:[bx],dx
	    pop cx ! pop dx ! push cx
	    mov cl,12 ! shr dx,cl ! pop cx
	    cmp cx,0 ! jne lbb_nzer
		cmp dx,0 ! je lbb_zer
		    dec dl ! jmps lbb_nzer
lbb_zer:	mov es:word ptr [bx],0
lbb_nzer:   mov es:2[bx],dl ! pop cx

		;put starting paragraph in place
	    mov ax,ldt_start[si] ! mov es:3[bx],ax
lbb_nxt:add si,ldtlen ! loop lbb_mre

		;if 8080 model, copy CS info into DS info

	cmp lod_8080,1 ! jne lnot80
	    push ds ! push es ! pop ds ! mov si,0
	    mov di,6 ! mov cx,3
	    rep movsw ! pop ds
lnot80:
	mov al,lod_fifty	;initialize base page load disk
	mov es:.50H,al
	pop es

		; init PD ,UDA and LDSTK

	mov bx,lod_basep
	cmp lod_pd,0 ! jne lip_1
	    jmp lod_exit
lip_1:	mov si,offset ldtab
	mov bx,lod_pd
                ; if 8087 user, flag it
        cmp lod_ndp, 0
         jz lip_2
        cmp lod_ndp, 1
          jnz true_87
        or p_sflag[bx],psf_em87
          jmp lip_2
true_87:
        or p_flag[bx],pf_8087
lip_2:	        
                ;if it requires suspend mode, flag it
        cmp lod_suspnd,0ffh
        jnz lip_3
        or p_sflag[bx],psf_suspend
lip_3:
        mov ax,ldt_start[si]
	mov p_uda[bx],ax
		; remember where lstk,uda are
	mov lod_uda,ax
	push es ! mov es,ax
                ; if 8087 user, use long uda
        cmp lod_ndp,0
         jz shrt_uda   
        cmp lod_ndp,1
         jz med_uda
            add ax,(u8087len/16) ! jmp inter_uda  ; full 8087 user, long uda
med_uda:    add ax,(em87len/16) ! jmp inter_uda   ; uses 87 emulator,medium uda
shrt_uda:   add ax,(ulen/16)                      ; no 8087 activity,short uda
inter_uda:  mov lod_lstk,ax

		; initialize UDA,LDSTK with zeros
	xor di,di ! mov ax,di

                ; if 8087 user, use long uda
	cmp lod_ndp,0
         jz shrt_uda1
                ; if 8087 emulator user, use medium uda
        cmp lod_ndp,1
         jnz long_uda1
        mov cx,(em87len + lstklen)/2 ! jmp inter_uda1
long_uda1:
        mov cx,(u8087len + lstklen)/2 ! jmp inter_uda1
shrt_uda1:  mov cx,(ulen + lstklen)/2
inter_uda1: rep stos ax ! pop es

		; setup p_uda for creat_proc

	mov ax,sysdat
	sub p_uda[bx],ax
	mov p_stat[bx],ps_run
	mov p_prior[bx],200

		; init load disk/user

	mov al,lod_user ! mov p_luser[bx],al
	mov al,lod_disk ! mov p_ldsk[bx],al

			; init UDA

	push es ! mov es,lod_uda
	mov u_dma_ofst,(offset bpg_dma)
	mov bx,lod_basep
	mov u_dma_seg,bx
	mov ax,lod_lstk
        cmp lod_ndp,0ffh          ; if 8087 user, init control word for
        jnz not_8087              ; first dispatch's frstor
        mov u_8087, controlw      ; 03ffh = post-init 8087 state
        push ax
        mov ax,sysvec87_of
        mov u_ivec87_of,ax
        mov ax,sysvec87_sg
        mov u_ivec87_sg,ax
        pop ax 
not_8087:
	push ds ! mov ds,bx
	mov u_initds,bx
	mov u_inites,bx
	mov u_initss,ax
	mov ax,bpg_cseg
	cmp ax,0 ! jne h_cs
	    pop ds ! pop es ! mov cx,e_no_cseg
	    jmp ld_out
h_cs:   mov u_initcs,ax
	mov ax,bpg_eseg
	cmp ax,0 ! je noes
	    mov u_inites,ax
noes:	mov u_stack_sp,(offset ls_sp)
	sub dx,dx ! mov al,bpg_8080
	cmp al,0 ! je n80m
	    mov dx,0100h
n80m:
	mov ds,u_initss
	mov ls_offset,dx		;set up initial stack
	mov ls_flags,0200h		;for a RETF from user
	mov ls_roffset,offset user_retf	;process, see SUPIF.SUP
	mov ls_rcseg,cs			;module for USER_RETF:
	pop ds ! pop es			;code
	mov bx,lod_basep
	sub cx,cx
lod_exit:
	push cx ! push bx
	mov cx,f_qwrite ! mov dx,offset mxloadqpb
	call osif ! pop bx ! pop cx ! ret


lod_group:		;load a group described in ldtab
;----------
;	input:	SI = addr of ldtab entry
;	output:	CX = Error Code

		; see if first part already in DMA
	mov bx,si
	mov ax,lod_indma		;starting paragraph in dma 
	mov cx,ldt_fstrt[bx]
		;AX = starting paragraph in local DMA
		;CX = starting paragraph to transfer
		;BX -> ldtab entry
	cmp cx,ax ! jb rd_first
		;starts at or after the pp. in dma
	    sub cx,ax
	    cmp cx,8 ! jae rd_first
			;starts in the dma
		mov dx,8 ! sub dx,cx
			;CX = # of pp. to skip
			;DX = length of remaining buffer
		cmp dx,ldt_flen[bx] ! jbe xfer
		    mov dx,ldt_flen[bx]
xfer:		mov si,offset lod_dma
		mov ax,cx ! mov cl,4 ! shl ax,cl
		add si,ax
			;SI -> beginning of transfer area
			;	in lod_dma
		mov ax,dx ! mov cl,3 ! shl ax,cl
		mov cx,ax
			;CX = number of words to transfer
		xor di,di
		push es ! mov es,ldt_start[bx]
		rep movsw ! pop es
		add ldt_start[bx],dx
		sub ldt_flen[bx],dx ! add ldt_fstrt[bx],dx
rd_first:
	cmp ldt_flen[bx],0 ! jne rd_1st
	    sub cx,cx ! ret
rd_1st:
	test ldt_fstrt[bx],07h ! jnz rd_indma
	cmp ldt_flen[bx],8 ! jae xf_d
rd_indma:
	    push bx
	    mov ax,ldt_fstrt[bx]
	    shr ax,1 ! shr ax,1 ! shr ax,1	; Record #
	    mov bx,1				; read 1 record
	    mov dx,offset lod_dma		; DMA offset
	    mov cx,sysdat			; DMA segment
	    call drd
	    pop bx
	    jcxz rd_agn
		cmp cx,0ffh ! jne rd_r3
		    mov cx,0
rd_r3:		ret
rd_agn:	    mov ax,ldt_fstrt[bx]
	    and ax,0fff8h			; note starting paragraph
	    mov lod_indma,ax			; in DMA
	    mov si,bx ! jmp lod_group

		; We are at a Sector Boundary with at least
		; a sector to place into the user area
xf_d:
	push bx
	sub dx,dx				; DMA offset
	mov cx,ldt_start[bx]			; DMA segment
	mov ax,ldt_fstrt[bx]
	shr ax,1 ! shr ax,1 ! shr ax,1		; Record #
	mov bx,ldt_flen[bx]
	shr bx,1 ! shr bx,1 ! shr bx,1		; # of records
	push bx
	call drd
	pop ax ! pop bx
	jcxz xfer_n
	    cmp cx,0ffh ! jne rd_r4
		xor cx,cx
rd_r4:	    ret
xfer_n: shl ax,1 ! shl ax,1 ! shl ax,1
	add ldt_start[bx],ax
	add ldt_fstrt[bx],ax
	sub ldt_flen[bx],ax
	jmp rd_first

drd:
;	input:	AX = Record Number
;		BX = Number of Sectors
;		CX = dma segment
;		DX = dma offset
;	output:	CX = 0 if okay
;		CX = 0FFH if End of File
;		     else Error Code

	mov u_dma_ofst,dx
	mov u_dma_seg,cx

		; read BX sectors starting at Record AX
drd_lp:
	push bx				;old # sectors
	push ax				;old record #
	cmp bx,128 ! jbe drd_r
	    mov bx,128

		; Max Mulit-sector count is 128

drd_r:	mov cl,u_mult_cnt
	push cx
	mov u_mult_cnt,bl
	push bx
	mov si,offset lod_fcb
	mov fcb_r0[si],ax
	mov cx,f_freadrdm ! mov dx,si
	push es ! call osif ! pop es
	pop dx				;multi_cnt used
	pop cx ! mov u_mult_cnt,cl
	cmp bl,1 ! jbe dr_r2
	    mov cx,e_bad_read ! mov bx,0ffffh
	    pop ax ! pop ax ! ret
dr_r2:	mov cl,bl 
        xor bh,bh ! mov di,bx           ;save BL for header read check
	pop ax ! add ax,dx		;adjust record #
	pop bx ! sub bx,dx		;adjust # sectors
	shl dx,1 ! shl dx,1 ! shl dx,1
	add u_dma_seg,dx

		; check for CTRL C.  If hit while loading
		; last set of characters, this is the place to
		; clean things up...

	push cx ! push ax ! push bx ! push di
	mov cx,f_ciostat ! call osif
	pop di ! pop bx ! pop ax ! pop cx

		; Now see if CTRL C was hit during the
		; the load.

	mov si,rlr
	test p_flag[si],pf_ctlc ! jz dr_r1
	    mov cx,e_abort ! mov bx,0ffffh
	    ret
dr_r1:	cmp cl,0 ! je dr_r5
	    mov cx,0ffh ! ret
dr_r5:	cmp bx,0 ! jne dr_r6
	    xor cx,cx
	    ret
dr_r6:  jmp drd_lp

;if mpm

get_sh:
;------
; Allocate memory for shared code.  If memory already
; exists then mark LDTAB entry with FLEN=0 for no load.
; START must be non-zero on success.
;
;	input:	SI = LDTAB Entry for shared code
;	output:	CX = 0 on success
;		   = 0ffffh on failure
;		SI is unchanged
;		

		; 1. Look for PD Name on SCL, making sure
		;	LDSK and LUSER are the same.

	mov bx,(offset scl)-p_thread
gs_nxt:	push si
	mov dx,offset lod_fcb ! add dx,fcb_name
	mov cx,f_findpdname ! call osif
			; BX=pd found or 0ffffh
	pop si
	cmp bx,0ffffh ! je no_sh
	    mov al,lod_disk
	    cmp p_ldsk[bx],al ! jne gs_nxt
		mov al,lod_user
		cmp p_luser[bx],al ! jne gs_nxt

		; 2. if (1.) then Share the Memory.
		; 2.1  Set FLEN=0

		    push bx ! push si
		    call shmem
		    pop si ! pop bx
		    cmp cx,0ffffh ! je no_sh  
			mov ldt_flen[si],0

				;  Put SHARE PD on end of SCL
				;  BX = SHARE PD

			pushf ! cli
			mov di,(offset SCL)-p_thread
sh_nin1:		cmp p_thread[di],bx ! je sh_rm	;look for share PD
			    mov di,p_thread[di] ! jmps sh_nin1
sh_rm:			mov ax,p_thread[bx]		;take it off the list
			mov p_thread[di],ax
sh_in:			cmp p_thread[di],0 ! je sh_end	;look for the end
			    mov di,p_thread[di] ! jmps sh_in		
sh_end:			mov p_thread[di],bx		;insert share PD on end
	        	xor cx,cx
	        	mov p_thread[bx],cx
	        	popf ! ret			;success

		; 3. if (NOT 1.) allocate memory to NEW PD
no_sh:

			; get new PD

	pushf ! cli
	mov bx,pul
	cmp bx,0 ! je sherr
	    mov ax,p_link[bx] ! mov pul,ax
	    popf

			; alloc memory for code segment

	    push bx ! push si
	    mov cx,f_malloc
	    mov dx,si
	    call osif
	    pop si ! pop bx
	    cmp cx,0 ! jne merr

			; initialize new PD name
			; BX = New PD
		push si
		mov si,ldt_pd[si]		;SI=old pd
		push si
		mov di,bx
		add si,p_name ! add di,p_name
		mov cx,4
		push es ! mov ax,ds ! mov es,ax
		rep movsw
		pop es ! pop di ! pop si

			; DI = old PD, BX=New PD

		mov al,lod_user ! mov p_luser[bx],al
		mov al,lod_disk ! mov p_ldsk[bx],al

			; share w/new PD

		mov ax,ldt_start[si]
		push bx ! push si ! push ds
		push ax ! push bx ! push di
		mov ax,ss ! mov ds,ax
		mov dx,sp ! mov cx,f_share
		call osif
		add sp,6
		pop ds ! pop si ! pop bx

		; put new PD on SCL

		pushf ! cli
		mov di,(offset SCL)-p_thread
sh_nin:		cmp p_thread[di],0 ! je sh_doit
		    mov di,p_thread[di] ! jmps sh_nin
sh_doit:        mov p_thread[di],bx		;insert new share PD
	        xor cx,cx
	        mov p_thread[bx],cx
	        popf ! ret			;success
merr:	    pushf ! cli
	    mov ax,pul
	    mov p_link[bx],ax
	    mov pul,bx
sherr:	popf
	mov cx,0ffffh ! ret

shmem:
;-----
;input:	SI = LDTAB
;	BX = Owner PD
;	Load_pd = Requestor
;	Have to set LDT_START
;

	lea di,(p_mem-ms_link)[bx]
sm_nxt:
	mov di,ms_link[di]
	cmp di,0 ! je sm_no
	    mov ax,ms_flags[di]
	    and ax,mf_share+mf_code+mf_load
	    cmp ax,mf_share+mf_code+mf_load ! jne sm_nxt
		push si ! push ds
		push ms_start[di]
		push ms_start[di]
		push lod_pd
		push bx
		mov ax,ss ! mov ds,ax
		mov dx,sp ! mov cx,f_share
		call osif

			; This will always work.

		pop ax ! pop ax ! pop ax
		pop dx ! pop ds ! pop si
		mov ldt_start[si],dx
		ret
sm_no:	mov cx,0ffffh ! ret

