📄 cstart.asm
字号:
; 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 + -