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

📄 pcgen.s

📁 用于底层开发的TCPIP协议栈源代码
💻 S
📖 第 1 页 / 共 2 页
字号:

include	asmglobal.h
	LOCALS
	extrn	ctick:proc
	extrn	kbpoll:proc
	extrn	kbsave:proc
	extrn	ksignal:proc
	public	eoi

; Hardware vector for timer linkage
; We use the timer hardware channel here instead of the indirect BIOS
; channel (1ch) because the latter is sluggish when running under DoubleDos
TIMEVEC	EQU	08h

	.DATA
	public	Intstk,Stktop,Spsave,Sssave,Mtasker,Hashtab,Kbvec
	extrn	Isat:word
Spsave	dw	?		; Save location for SP during interrupts
Sssave	dw	?		; Save location for SS during interrupts
Intstk	dw	1024 dup(?)	; Interrupt working stack
Stktop	equ	$		; SP set here when entering interrupt
Mtasker	db	?		; Type of higher multitasker, if any
Hashtab	db	256 dup(?)	; Modulus lookup table for iphash()
Kbvec	dd	?		; Address of BIOS keyboard handler
	.CODE
dbase	dw	@Data
jtable	dw	l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15	
vector	dd	?		; place to stash chained vector
vectlo	equ	word ptr vector
vecthi	equ	word ptr vector+2

; Re-arm 8259 interrupt controller(s)
; Should be called just after taking an interrupt, instead of just
; before returning. This is because the 8259 inputs are edge triggered, and
; new interrupts arriving during an interrupt service routine might be missed.
eoi	proc
	cmp	Isat,1
	jnz	@@1		; Only one 8259, so skip this stuff
	mov	al,0bh		; read in-service register from
	out	0a0h,al		; secondary 8259
	nop			; settling delay
	nop
	nop
	in	al,0a0h		; get it
	or	al,al		; Any bits set?
	jz	@@1		; nope, not a secondary interrupt
	mov	al,20h		; Get EOI instruction
	out	0a0h,al		; Secondary 8259 (PC/AT only)
@@1:	mov	al,20h		; 8259 end-of-interrupt command
	out	20h,al		; Primary 8259
	ret
eoi	endp

; common routine for interrupt return
; Note that all hardware interrupt handlers are expected to return
; the original vector found when the device first attached. We branch
; to it just after we've cleaned up here -- this implements shared
; interrupts through vector chaining. If the original vector isn't
; available, the interrupt handler must return NULL to avoid a crash!
public	doret
	label	doret	far
	cmp	ax,0		; is a chained vector present?
	jne	@@1		; yes
	if	@Datasize NE 0
		cmp	dx,ax
		jne	@@1		; yes
	endif
	pop	es		; nope, return directly from interrupt
	POPALL
	mov	ss,Sssave
	mov	sp,Spsave	; restore original stack context
	pop	ds
	iret

; Code to handle vector chaining
@@1:	mov	cs:vectlo,ax	; stash vector for later branch
	if	@Datasize NE 0
		mov	cs:vecthi,dx
	endif
	pop	es
	POPALL
	mov	ss,Sssave
	mov	sp,Spsave	; restore original stack context
	pop	ds
	if	@Datasize NE 0
		jmp	cs:[vector]	; jump to the original interrupt handler
	else
		jmp	cs:[vectlo]
	endif

; istate - return current interrupt state
	public	istate
istate	proc
	pushf
	pop	ax
	and	ax,200h
	jnz	@@1
	ret
@@1:	mov	ax,1
	ret
istate	endp

; dirps - disable interrupts and return previous state: 0 = disabled,
;	1 = enabled
	public dirps
dirps	proc
	pushf			; save flags on stack
	pop	ax		; flags -> ax
	and	ax,200h		; 1<<9 is IF bit
	jz	@@1		; ints are already off; return 0
	mov	ax,1
	cli			; interrupts now off
@@1:	ret
dirps	endp

; restore - restore interrupt state: 0 = off, nonzero = on
	public	restore
restore	proc
	arg is:word
	test	is,0ffffh
	jz	@@1
	sti
	ret
@@1:	cli	; should already be off, but just in case...
	ret
restore	endp


; multitasker types
NONE		equ	0
DOUBLEDOS	equ	1
DESQVIEW	equ	2
WINDOWS3	equ	3
OS2		equ	4

; Relinquish processor so other task can run
	public	giveup
giveup	proc
	pushf		;save caller's interrupt state
	sti		;re-enable interrupts
	cmp	mtasker, DOUBLEDOS
	jnz	@@1
	mov	al,2	; 110 ms
	mov	ah,0eeh
	int	21h
	POPFLAGS		; restore caller's interrupt state
	ret

@@1:	cmp	mtasker, DESQVIEW
	jnz	@@2
	mov	ax, 1000h
	int	15h
	POPFLAGS		; restore interrupts
	ret

@@2:	cmp	mtasker, WINDOWS3
	jnz	@@3
	mov	ax, 1680h
	int	2fh
	cmp	al, 80h	; call supported?
	jz	@@3	; nope
	POPFLAGS		; yes - restore interrupts
	ret

@@3:	cmp	mtasker, OS2
	jnz	@@4
	mov	ax, 1680h
	int	2fh
	POPFLAGS		; restore interrupts
	ret

@@4:	hlt		; wait for an interrupt

	POPFLAGS		; restore interrupts
	ret
giveup	endp

; check for a multitasker running
	public	chktasker
chktasker	proc
	mov	mtasker,NONE

	; Check for OS/2
	mov	ax,3000h	; Get MS-DOS Version Number call
	int	21h
	cmp	al,20		; Version 20 = OS/2 2.0
	jnz	@@5
	mov	mtasker, OS2
	ret

  	; Check for Microsoft Windows
@@5:	mov	ax,1600h

	; Check for Microsoft Windows
	mov	ax,1600h
	int	2fh
	cmp	al, 00h		; 0 means windows multitasking not running
	jz	@@4
	cmp	al, 80h		; ditto for 80h return
	jz	@@4
	mov	mtasker, WINDOWS3
	ret

	; Check for DoubleDos
@@4:	mov	ah,0e4h
	int	21h
	cmp	al,1
	jz	@@1
	cmp	al,2
	jnz	@@2
@@1:	mov	mtasker, DOUBLEDOS
	ret

	; Check for DESQVIEW
@@2:	mov	ax, 2b01h
	mov	cx, 4445h
	mov	dx, 5351h
	int	21h
	cmp	al, 0ffh
	jnz	@@3
	ret

@@3:	mov	mtasker, DESQVIEW
	ret
chktasker	endp

; getss - Read SS for debugging purposes
	public	getss
getss	proc
	mov	ax,ss
	ret
getss	endp

; clockbits - Read low order bits of timer 0 (the TOD clock)
; This works only for the 8254 chips used in ATs and 386s.
;
; The timer runs in mode 3 (square wave mode), counting down
; by twos, twice for each cycle. So it is necessary to read back the
; OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
; pin forms the most significant bit of the count. Unfortunately,
; the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
;
; The PC's clock design is soooo brain damaged...

	public	clockbits
clockbits	proc
	mov	al,0c2h	; latch timer 0 count and status for reading
@@1:	pushf
	cli		; make chip references atomic
	out	43h,al	; send latch command
	in	al,40h	; get status of timer 0
	mov	bl,al	; save status
	in	al,40h	; get lsb of count
	mov	ah,al	; save lsb
	in	al,40h	; get msb of count
	POPFLAGS		; no more chip references
	test	bl,40h	; test NULL COUNT bit
	jnz	@@1	; count is invalid, try again
	and	bl,80h	; we're only interested in the OUT bit
	xchg	ah,al	; ax = count in correct order
	shr	ax,1	; count /= 2
	jz	@@3	; zero count requires carry propagation
@@2:	or	ah,bl	; combine with OUT bit as most sig bit of count
	ret
@@3:	xor	bl,80h	; propagate carry by toggling OUT bit when cnt == 0
	or	ah,bl	; combine with !OUT bit as most sig bit of count
	ret

clockbits	endp

; Internet checksum subroutine
; Compute 1's-complement sum of data buffer
; Uses an unwound loop inspired by "Duff's Device" for performance
;
; Called from C as
; unsigned short
; lcsum(buf,cnt)
; unsigned short *buf;
; unsigned short cnt;
	public	lcsum
lcsum	proc
	arg	buf:ptr,cnt:word

	if	@Datasize NE 0
		uses	ds,si
		lds	si,buf	; ds:si = buf
	else
		uses	si
		mov	si,buf	; ds:si = buf (ds already set)
	endif

	mov	cx,cnt		; cx = cnt
	cld			; autoincrement si
	mov	ax,cx
	shr	cx,1		; cx /= 16, number of loop iterations
	shr	cx,1
	shr	cx,1
	shr	cx,1

	inc	cx		; make fencepost adjustment for 1st pass
	and	ax,15		; ax = number of words modulo 16
	shl	ax,1		; *=2 for word table index
	lea	bx,jtable	; bx -> branch table
	add	bx,ax		; index into jump table
	clc			; initialize carry = 0
	mov	dx,0		; clear accumulated sum
	jmp	word ptr cs:[bx]	; jump into loop

; Here the real work gets done. The numeric labels on the lodsw instructions
; are the targets for the indirect jump we just made.
;
; Each label corresponds to a possible remainder of (count / 16), while
; the number of times around the loop is determined by the quotient.
;
; The loop iteration count in cx has been incremented by one to adjust for
; the first pass.
; 
deloop:	lodsw
	adc	dx,ax
l15:	lodsw
	adc	dx,ax
l14:	lodsw
	adc	dx,ax
l13:	lodsw
	adc	dx,ax
l12:	lodsw
	adc	dx,ax
l11:	lodsw
	adc	dx,ax
l10:	lodsw
	adc	dx,ax
l9:	lodsw
	adc	dx,ax
l8:	lodsw
	adc	dx,ax
l7:	lodsw
	adc	dx,ax
l6:	lodsw
	adc	dx,ax
l5:	lodsw
	adc	dx,ax
l4:	lodsw
	adc	dx,ax
l3:	lodsw
	adc	dx,ax
l2:	lodsw
	adc	dx,ax
l1:	lodsw
	adc	dx,ax
l0:	loop	deloop		; :-)

	adc	dx,0		; get last carries
	adc	dx,0
	mov	ax,dx		; result into ax
	xchg	al,ah		; byte swap result (8088 is little-endian)
	ret
lcsum	endp

; Link timer handler into timer chain
; Arg == address of timer handler routine
; MUST be called exactly once before uchtimer is called!

toff	dw	?		; save location for old vector
tseg	dw	?		;  must be in code segment

	public	chtimer
chtimer	proc
	arg	vec:far ptr
	uses	ds

	mov	ah,35h		; get current vector
	mov	al,TIMEVEC
	int	21h		; puts vector in es:bx
	mov	cs:tseg,es	; stash
	mov	cs:toff,bx

	mov	ah,25h
	mov	al,TIMEVEC
	lds	dx,vec		; ds:si = vec

	int	21h		; set new vector
	ret
chtimer	endp

; unchain timer handler from timer chain
; MUST NOT be called before chtimer!
	public	uchtimer
uchtimer	proc
	uses	ds

	mov	ah,25h
	mov	al,TIMEVEC
	mov	dx,toff
	mov	ds,tseg
	int	21h		; restore old vector
	ret
uchtimer	endp

; Keyboard hardware interrupt handler.
; First pass the interrupt to the original handler in the BIOS,
; then do a ksignal() to wake up any task sleeping on it.
	public	kbint
	label	kbint	far
	cld
	push	ds
	mov	ds,cs:dbase	; establish interrupt data segment

	pushf			; Make it look like a hardware interrupt
	call dword ptr [Kbvec]	; Call BIOS handler

	mov	Sssave,ss	; stash user stack context
	mov	Spsave,sp
	mov	ss,cs:dbase	; switch to interrupt stack
	lea	sp,Stktop

	PUSHALL
	push	es
	; ksignal(&Kbvec,1);
	mov	ax,1
	push	ax
	push	ds
	mov	ax,offset DGROUP:Kbvec
	push	ax
	call	ksignal
	add	sp,6	; remove args

	pop	es
	POPALL
	mov	ss,Sssave
	mov	sp,Spsave	; restore original stack context
	pop	ds
	iret


; Poll keyboard through BIOS. Returns ascii char in low byte, scan code
; in high byte. If low byte == 0, character is "extended ascii"
	public	kbraw
kbraw	proc
	mov	ah,1	; poll BIOS for character
	int	16h
	jz	nochar	; no character available
	mov	ah,0
	int	16h	; get it for real: ah = scan code, al = ascii char (or 0)
	ret
nochar:	xor	ax,ax
	ret

⌨️ 快捷键说明

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