⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cstart.asm

📁 与MS-DOS兼容的DOS操作系统
💻 ASM
📖 第 1 页 / 共 5 页
字号:
; Entry
;	none
; Exit
;	none (side effect: DBCS table initialised)

	push	bp
	mov	bp, sp
	sub	sp, DI_LOCALS		; allocate local variables
	push	ds
	push	es
	push	di
	push	si

	mov	dbcs_table_seg, ds	; assume DBCS call will fail

	mov	ax, 06507h		; Extended Country Info: get DBCS ptr
	mov	bx, 0FFFFh		; codepage number: -1 for global cp
	mov	cx, 00005h		; size of info. buffer
	mov	dx, 0FFFFh		; country code: -1 for current country
	lea	di, DI_BUF[bp]
	push	ss
	pop	es			; es:di -> DI_BUF
	int	21h			; returns with DI_BUF filled in
	 jc	di_exit			; just exit if function fails

	cmp	DI_BUF_ID[bp], 7	; is table for DBCS?
	 jne	di_exit			;  no - exit
	les	ax, DI_BUF_PTR[bp]	; es:ax -> system DBCS table

	mov	dbcs_table_off,ax
	mov	dbcs_table_seg,es	; fixup pointer to system DBCS table

di_exit:
	pop	si
	pop	di
	pop	es
	pop	ds
	mov	sp, bp
	pop	bp
	ret
dbcs_init	endp

endif

; I want to do
;	db	(C_HEAP_SIZE - 6 - ($ - stack_start)) dup (0DDh)
; but MASM requires dup's be absolute, so instead
rept	C_HEAP_SIZE
if (offset $ - offset stack_start) LT (C_HEAP_SIZE - 6)
	db	0ddh
endif

endm

stack_top	label	word
stack_ip	dw	?		; Initial Offset	
stack_cs	dw	?		; Initial Code Segment (Unknown)
stack_flags	dw	?		; Initial Flags (Unknown)
STACK	ENDS

ED_TEXT	SEGMENT
;
;	Return the CheckSum of All the C code and Static Data. DS:SI 
;	are initialised to point at the C_code_start. AX contains the
;	CheckSum on return.
;
calc_crc:
	mov	cx,real_code		; Number of bytes to move is always
	shr	cx,1			; even because of the segment def.
	dec	cx
	mov	bx,0EDCh		; Checksum Seed
cc_10:					; Sum the words of the image while
	lodsw				; rotating the check value
	add	bx,ax
	rol	bx,1
	loop	cc_10
	xchg	ax,bx
	ret

page
;
;	Return the code segment of the C main routine.
;
get_cs:
	mov	ax,cs:code_seg
	ret

;
;	Return the Data segment of the C data area
;
get_ds:
	mov	ax,cs:data_seg
	ret

	
; Get remaining memory size, subtract code size and allocate high memory for
; transient portion of command processor
;	Exit	AX=Segment of high memory
;		CY set if none available
; 
; This used to allocate only just enough space for the code at the top of
; memory and leave the reset free for use as copy buffers.
; But then came SideKick Plus - this assumes COMMAND.COM only uses the top
; 20K of it's hi-mem partion and overwrites the rest as it gets it's
; overlays. As we are bigger the 20K the result is the system crashes when
; you exit back to the command line.
; In order to minimise this possibility we reserve some space (currently 50K)
; for use as copy buffers and allocate all the rest to the hi-mem portion
; of COMMAND.COM. Since SK starts overwriting from the bottom of memory it
; doesn't usually reach the code.
; The real solution is of course to make sure we are smaller than 20K too...
; (Or transfer the ReadLine code into the resident portion and checksum the
; hi-mem before returning to the hi-mem code ???).
; --ij

public	alloc_com_memory
alloc_com_memory:
	push	es
	mov	bx,0FFFFh		; Allocate more paras than there are
	mov	ah,MS_M_ALLOC		; to find out how many there are.
	int 	DOS_INT
	mov	ah,MS_M_ALLOC
	int	DOS_INT			; allocate it

	mov	si,code_length		; then convert the CODE_LENGTH to 
	mov	cl,4			; paragraphs and check if enough memory
	shr	si,cl			; is available to copy the code high
	add	si,1 			; + para for a memory descriptor 
	sub	bx,si			; Is there enough for the code ?
	 jc	acm_10			; if not exit with error


	cmp	bx,Copy_Buffer_Size	; allocate some memory for Copy Buffers
	 jb	acm_5
	mov	bx,Copy_Buffer_Size	; limit the maximum Copy Buffer size
acm_5:
	mov	es,ax
	mov	ah,MS_M_SETBLOCK
	int	DOS_INT			; shrink to fit
	push	es			; save buffer address
	
; Now allocate remaining memory for step aside code
	mov	bx,0FFFFh		; allocate all memory
	mov	ah,MS_M_ALLOC		; to find out how much there is.
	int 	DOS_INT
	mov	ah,MS_M_ALLOC		; block at the end of memory
	int	DOS_INT			; AX=Segment of new block of memory
	mov	alloc_seg,ax		; save address so we can free it
if ThreeCOM
	cmp	bx,1000h		; do we have at least 64k ?
	 jb	acm_6			; if so do 3-Com fix and start
	mov	si,1000h		; Transient portion 64k down
acm_6:
endif
	add	ax,bx			; go to top of memory we allocated

	cmp	ax,0a000h		; dont use memory above A000 as this
	jb	acm_6a			; may disappear when user does
	mov	ax,0a000h		; MEMMAX -V
acm_6a:

	dec	si
	sub	ax,si			; adjust address we run cmd proc at
; Deallocate intervening block of memory
	pop	es
	push	ax
	mov	ah,MS_M_FREE		; Now free it up
	int	DOS_INT
	pop	ax
	mov	cs:_gp_far_buff,real_code
	mov	cs:_gp_far_buff+2,ax	; save address of temp buffer
	clc				; allocated OK
acm_10:
	pop	es
	ret
	
; called to free up the cmd processor's high memory
free_com_memory:
	
	push	es
	push	ax
	mov	es,alloc_seg
	mov	ah,MS_M_FREE
	int	DOS_INT
	pop	ax
	pop	es
	ret


;Control_Break:
;	The Break handler makes the following checks taking the
;	appropriate action after each test:-
;
;	1) Is COMMAND.COM the current process (Get PSP) if NO ABORT
;	2) Is the break_flag SET if YES jump to the C break handler
;	   "break_handler" after insuring that the segment registers
;	   have all be set correctly.
;	
	assume cs:DGROUP, ds:nothing, es:nothing

;	Set up the default Control Break Handler.
handler_init:
ifndef DOSPLUS
	mov	ax,4453h			; Get the address of the
	int	DOS_INT				; internal Critical Error
	jc	handler_i10			; handler Ignore on Error
	mov	word ptr critical+0,ax		; Save the handler Offset (AX)
	mov	word ptr critical+2,bx		; and Segment (BX)
endif
	mov	al,24h				; Set the default Critical
	mov	dx,dataOFFSET critical_error	; Error Handler
	mov	bx,dataOFFSET crit_error_entry
	call	set_vector			; Setup correct ISR
	
handler_i10:
	mov	al,23h				; Set the default Control
	mov	dx,dataOFFSET control_break	; Break Handler
	mov	bx,dataOFFSET control_break_entry
;;	jmp	set_vector			; Setup correct ISR
;
;	Convert the address of the interrupt #AL service routine, whose
;	address is CS:DX to be PSP:xxxx. Five NOP must be coded after the
;	interrupt service routine for the JMPF instruction which corrects
;	the code segment.
;
set_vector:
	push	ds
	push	es
	mov	es,[low_seg]
	mov	es:byte ptr 0[bx],0EAh	; JMPF opcode
	mov	es:word ptr 1[bx],dx	; Offset of Interrupt vector
	mov	es:word ptr 3[bx],cs	; Insert the correct code seg
	mov	dx,bx
	mov	bx,es	
	sub	bx,__psp		; Calculate the correct offset for
	mov	cl,4			; the interrupt handler if the segment
	shl	bx,cl			; must be that of our PSP
	add	dx,bx
	mov	ds,__psp
	mov	ah,MS_S_SETINT
	int	DOS_INT
	pop	es
	pop	ds
	ret

	;extrn	_int_break:near			; C Break/Error handling routine 

	assume cs:DGROUP, ds:DGROUP, es:nothing

control_break	PROC	FAR
	;;db	5 dup(90h)		; Reserve space for JMPF CS:$+5
	push	ax			; Save the Users registers
	push	bx
	push	ds
	call	get_ds			; Get our Local DS
	mov	ds,ax
	cmp	_cbreak_ok,0		; is our handler initialised ?
	 je	break_05		;  no, don't call it
	cmp	reload_flag,0		; Are we part way through reloading
	clc				;  the command processor?
	 jnz	break_05		; if so do not abort.

	mov	ah, MS_P_GETPSP		; Get the current PSP address
	int	DOS_INT
	cmp	bx,[__psp]		; Is this our address
	stc				; Assume not and Set the carry flag
	jz	break_10		; if internal, restart the command loop
					; if external, abort process
break_05:
	pop	ds
	pop	bx
	pop	ax
	ret

;
;	This section of code corrects the stack and jumps to the 
;	C code Control Break Handler _int_break. Beware that the
;	stack segment need not be the DS because the READ_LINE routine
;	executes on a high stack and the CED programs will emulates
;	a Control-Break on the wrong Stack.
;
break_10:
	cli				; Swap to the correct stack not
	mov	ax,ds			; forgetting that we might be running
	mov	es,ax			; on old 8088 or 8086 so interrupts
	mov	ss,ax			; must be disabled
	mov	sp,stack_min		; Get the lowest possible stack address
	add	sp,12			; Add a little to avoid problems with
	sti				; the stack check code.

	mov	ax,0100h		; Termination Code Control-C Abort
	push	ax			; Save on the Stack for C routine
	push	ax			; Force a dummy return address on the
					; stack (NOT USED)
	call	get_cs			; Put the Segment and Offset address
	push	ax			; of the C break Handler on the stack
	mov	ax,codeOFFSET _int_break; and execute a RETF to it.
	push	ax
	ret 
control_break	ENDP

critical_error	PROC FAR
	;;db	5 dup(90h)		; Reserve space for JMPF CS:$+5
	push	ds			; Save the Critical Error DS
	push	ax
	call	get_ds			; Get the Command Processor DS
	mov		ds,ax			; and call the original routine
ifdef DOSPLUS
	mov 	ax, _n_option	; check for /n command line option
	cmp		ax, 0
	pop		ax
	jne		skip_criterr
	call	com_criterr		; local criterr handler
	jmp		criterr_cont
skip_criterr:
	mov		al,3			; /n option => always return fail
criterr_cont:
else
	pop		ax
	pushf
	call	critical		; stored previous handler
endif
	cmp	al,02h			; Did the user request a Terminate
	 jne	critical_e20		; Yes so check if they are trying to
	push	ax			; terminate the command processor
	push	bx

	mov	ah, MS_P_GETPSP		; Get the current PSP address
	int	DOS_INT
	cmp	bx,[__psp]		; Is this our address?
	 jne	critical_e10		; no so return with Abort code

	cmp	in_exec,0		; are we EXECing a program ?
	 jne	critical_e10		;  then return the error
	cmp	reload_flag,0		; then unless we are reloading command
	 je	break_10		;  processor break here to prevent
critical_e10:				;  higher levels generating repeated
	pop	bx			;  critical errors (eg. when searching
	pop	ax			;  a path)
critical_e20:
	pop	ds
	iret

critical_error ENDP

;
;	INT2E is a backdoor entry to the "Permanent" Command interpreter 
;	which will execute the command at DS:SI.
;

int2E_far_entry	proc	far
	db	5 dup(90h)		; Reserve space for JMPF CS:$+5

;	ds:si -> command line preceded by byte count

;	check we're not re-entering

	mov	ax, 1
	xchg	cs:i2e_lock, ax
	test	ax, ax
	 jz	i2e_10

	iret

i2e_10:
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	bp
	push	ds
	push	es
	
	; if ds = si = 0 then set batch_seg_ptr to zero and get out.
	; This is a clean way of halting batch processing.
	mov	ax,ds
	cmp	ax,0
	jne	i2e_15
	cmp	si,0
	jne	i2e_15

	mov	si,cs:_batch_seg_ptr
	mov	ds,cs:_batch_seg_ptr+2
	mov	[si],ax
	jmp	i2e_exit2
i2e_15:	

;	swap stack

	mov	cs:i2e_user_ss, ss
	mov	cs:i2e_user_sp, sp
	
	cli
	mov	ss, cs:exec_ss
	mov	sp, cs:exec_sp
	sti
	
;	allocate 128 bytes for command line, since the C code needs a 128 
;	byte buffer anyway

	mov	cx, 128

;	save stack p

	mov	cs:i2e_stack, sp

;	have we got enough room for command line 

	mov	ax, sp
	sub	ax, cx
	sub	ax, cs:heap_top
	cmp	ax, 256
	 jge	i2e_25
	jmp	i2e_exit
i2e_25:	
	sub	sp, cx
	mov	cs:i2e_cmd, sp
	
;	copy command line

	push	ss
	pop	es
	mov	di, sp
	lodsb				; get line count
	and	ax,7fh			; limit to 128 bytes
	add	ax,sp			; terminating NULL goes here
	rep	movsb			; copy the command line
	xchg	ax,di			; DI -> NUL posn
	xor	al,al
	stosb				; replace CR with NUL
	push	cs
	pop	ds

;	reload non-resident code if necessary

	cmp	high_code, TRUE
	 jnz	i2e_30
	mov	reload_flag, 1
	call	reload_code
	mov	reload_flag, 0

i2e_30:
;	install our own Break and Criterr handlers - e.g. if second copy
;	of the command processor is running, install original handlers so
;	that they are looking at the same data as we are.
;	N.B. __psp is currently that of original command processor

	mov	ax, (MS_S_GETINT*256) + 23h
	int	DOS_INT
	mov	i2e_i23seg, es
	mov	i2e_i23off, bx
	
	mov	ax, (MS_S_GETINT*256) + 24h
	int	DOS_INT
	mov	i2e_i24seg, es
	mov	i2e_i24off, bx
	
	call	handler_init

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -