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

📄 mem32.asm

📁 高速同步串口芯片PEB20534的驱动程序
💻 ASM
字号:
;---------------------------------------------------------------
; Assembler code to provide 32bit flat memory access
;---------------------------------------------------------------

	.MODEL		MEDIUM, C

;---------------------------------------------------------------
; I/O Ports
;---------------------------------------------------------------
	KBC_CTL 	equ	060h	; 8042 control port
	KBC_STAT	equ	064h	; 8042 status port

;---------------------------------------------------------------
; Keyboard Controller
;---------------------------------------------------------------
	inpt_buf_full	equ	2	; Input buffer full
	enable_a20	equ	0dfh	; enable A20 command
	disable_a20	equ	0ddh	; disable A20 command

;---------------------------------------------------------------
; Segment access
;---------------------------------------------------------------
	CS_access	equ	10011011b ; EXE/READ-only access
	DS_access	equ	10010011b ; R/W Data segment

;---------------------------------------------------------------
; Macro definitions
;---------------------------------------------------------------
Minit_descriptor	macro	segment,offset,desc_name
	mov	dx,&segment		;; get segment name
	mov	ax,&offset		;;   to form 32 bit addr
	Call	Calc_pm_address 	;; calculate 32 bit addr
	mov	&desc_name.Base_A15_A00,ax ;; Save 32-bit linear
	mov	&desc_name.Base_A23_A16,dl ;; segment address in
	mov	&desc_name.Base_A31_A24,dh ;; GDT entry
	endm

Mfarjmp macro	destination,selector	;dynamic JMP FAR SEG:OFF
	db	0eah			;; jmp instruction
	dw	offset destination	;; offset word
	dw	selector		;; segment selector word
	endm

;---------------------------------------------------------------
; Structure definitions
;---------------------------------------------------------------
    Descriptor	STRUC
	Seg_limit	dw	?	; Segment limit
	Base_A15_A00	dw	?	; A00..A15 of base addr
	Base_A23_A16	db	?	; A16..A23 of base addr
	Access_rights	db	?	; Segment access rights
	GDLimit_A19_A16 db	?	; Granularity, Op-size,
					;   Limit A16..A19
	Base_A31_A24	db	?	; A24..A31 of base addr
    Descriptor	ENDS


.DATA
;---------------------------------------------------------------
; Global Descriptor Table & pointers
;---------------------------------------------------------------
	GDT_386	Descriptor	<>	; NULL DESCRIPTOR
	CSEG2	Descriptor	<0ffffh,,,CS_access>	; CS
	DSEG2	Descriptor	<0ffffh,,,DS_access>	; DS
	SSEG2	Descriptor	<0ffffh,,,DS_access>	; SS
	ESEG2	Descriptor	<0ffffh,0,0,DS_access,0dfh,0>	; ES
	Gdt386_len	equ	$-Gdt_386

	GDT_PTR Label	Fword
		dw	Gdt386_len-1	; length of table
	GDT_LW	dw	0
	GDT_HW	dw	0

;---------------------------------------------------------------
; XMS call address
;---------------------------------------------------------------
	XMS_CALL	dw	0,0


.CODE
;---------------------------------------------------------------
; Stack segment backup location (must be in code space)
;---------------------------------------------------------------
	stack_seg	dw	?

;---------------------------------------------------------------
; CALC_PM_ADDRESS:  Calculate 32-bit protected mode address.
;                   Used for building descriptor tables.
;---------------------------------------------------------------
; Input:   DX:AX = Real mode address
; Output:  DX:AX = 32-bit linear address
; Register(s) modified:  AX, CX, DX
;---------------------------------------------------------------
Calc_pm_address	proc	near
;---------------------------------------------------------------
	mov     cx,ax           ; point to control block
	mov	ax,dx		; load segment into AX
	xor     dh,dh           ; clear upper register
	mov     dl,ah           ; build high byte of 32-bit addr
	shr     dl,4            ; use only high nibble from (AX)
	shl     ax,4            ; strip high nibble from segment
	add     ax,cx           ; add GDT offset for low word
	adc     dx,0            ; adj high byte if CY from low
	ret                     ; back to calling program
calc_pm_address endp


;---------------------------------------------------------------
; Wait_KBC: This routine waits for the 8042 buffer to empty.
;---------------------------------------------------------------
; Input:   None
; Output:  AL = 0, 8042 input buffer empty:     ZF
;          AL = 2, Time out; 8042 buffer full:  NZ
; Register(s) modified:  AX, CX
;---------------------------------------------------------------
Wait_KBC	proc	near
;---------------------------------------------------------------
	xor     cx,cx           	; CX=0: timeout value
Try_KBC:
	in      al,KBC_STAT     	; read 8042 status port
	and     al,inpt_buf_full	; input buffer full flag
	loopnz  Try_KBC         	; loop until buffer empty
	ret
Wait_KBC	endp


;---------------------------------------------------------------
; Test_A20:  This routine will test if the A20 address
;            line is REALLY active
;---------------------------------------------------------------
Test_A20	proc	near
;---------------------------------------------------------------
	push	ds		; save segment registers
	push	es
	xor	ax,ax		; set A20 test segments
	mov	ds,ax		; DS = 0000H
	dec	ax
	mov	es,ax		; ES = FFFFH
	mov	al,ds:[0]	; get byte from 0:0
	mov	ah,al		; preserve old byte
	not	al		; modify byte
	xchg	al,es:[10h]	; put modified byte to 0ffffh:10h
	cmp	ah,ds:[0]	; set zero if byte at 0:0 not modified
	mov	es:[10h],al	; put back old byte at 0ffffh:10h
	pop	es		; restore segment registers
	pop	ds
	ret
Test_A20	endp


;---------------------------------------------------------------
; Wait_A20: This routine waits for gate A20 address line 
;           activation
;---------------------------------------------------------------
Wait_A20	proc near
;---------------------------------------------------------------
	xor     cx,cx		; CX=0: timeout value
Try_A20:
	Call	Test_A20	; test A20 state
	loopnz	Try_A20		; loop until A20 is enabled
	ret
Wait_A20	endp


;---------------------------------------------------------------
; XMS_A20:  This routine enables the A20 address line using
;           an XMS memory manager (himem.sys) if present
;---------------------------------------------------------------
XMS_A20	proc	near
;---------------------------------------------------------------
	push es			; preserve ES, INT 2Fh destroys it

	mov ax,4300h		; check for XMS
	int 2fh
	cmp al,80h		; XMS present?
	jnz XMS_Err

	mov ax,4310h		; get XMS driver address
	int 2fh
	mov XMS_CALL,bx		; store XMS driver address
	mov XMS_CALL+2,es

	mov ah,3		; enable A20
	call dword ptr XMS_CALL
XMS_Err:
	pop es			; restore ES (buffer segment)
	ret
XMS_A20	endp


;---------------------------------------------------------------
; KBC_A20:  This routine controls a signal which gates address
;           line 20 (A20). The gate A20 signal is an output of
;           of the 8042 slave processor (keyboard controller).
;           A20 should be gated on before entering protected
;           mode, to allow addressing of the entire 4G address
;           space of the 80386 & 80486.
;---------------------------------------------------------------
; Register(s) modified:  AX, CX
;---------------------------------------------------------------
KBC_A20	proc	near
;---------------------------------------------------------------
	Call	Wait_KBC	; insure 8042 input buffer empty
	mov	al,0D1h		; 8042 cmd to write output port
	out	KBC_STAT,al	; output cmd to 8042
	Call	Wait_KBC	; wait for 8042 to accept cmd
	mov	al,enable_a20	; gate address bit 20 on
	out	KBC_CTL,al	; output port data to 8042
	Call	Wait_KBC	; wait for 8042 to port data
	ret
KBC_A20	endp


.386P
;---------------------------------------------------------------
; WriteL:  This routine writes a 32 bit value at a 32 bit
;          physical address.
;---------------------------------------------------------------
PUBLIC	WriteL
WriteL	proc	far
;---------------------------------------------------------------
	push	bp			; set up stack and
	mov	bp,sp			; local pointer
	push	ds
	push	es

;---------------------------------------------------------------
; 1) Disable interrupts
; 2) Set up descriptor table entries w/ run time addresses
; 3) Initialize pointer to GDT
; 4) Enable A20 on the address bus
;---------------------------------------------------------------
; (1)
	pushf				; save flags
	cli				; disable interrupts
; (2)
	Minit_descriptor        cs,0,CSEG2
	Minit_descriptor        ss,0,SSEG2
	Minit_descriptor        ds,0,DSEG2
; (3)
	mov     cs:stack_seg,SS		; save SS
	mov	dx,ds			; GDT linear address
	mov     ax,offset GDT_386
	Call    Calc_PM_Address
	mov     GDT_LW,ax
	mov     GDT_HW,dx
	Lgdt	GDT_PTR			; load GDT register
; (4)
	Call	Test_A20		; A20 already active ?
	jz	@OK_A20W

	Call	XMS_A20			; set A20 line via XMS driver
	Call	Test_A20
	jz	@OK_A20W

	Call	KBC_A20			; set A20 line via KBC
	Call	Wait_A20		; wait for activation
	jnz	@RM_386W
@OK_A20W:

;---------------------------------------------------------------
; 1) Enable protected mode
; 2) FAR JUMP to protected mode routine
;---------------------------------------------------------------
; (1)
	mov     eax,cr0         	; get CPU control register
	or      al,1            	; enable protected mode bit
	mov	cr0,eax              	; now in protected mode
; (2)
	Mfarjmp <@PM_386W>,<CSEG2-GDT_386>

;---------------------------------------------------------------
; Now, fully in protected mode:  Initialize protected mode
; segment registers.
;---------------------------------------------------------------
@PM_386W:
	mov     ax,ESEG2-GDT_386	; Pointer to extra segment
	mov     es,ax
	mov     ax,DSEG2-GDT_386	; Pointer to current data seg
	mov     ds,ax
	mov     ax,SSEG2-GDT_386	; Pointer to stack segment
	mov     ss,ax

;---------------------------------------------------------------
; Write data in protected mode
;---------------------------------------------------------------
	mov	eax,[bp+10]
	mov	ebx,[bp+6]
	mov	es:[ebx],eax

;---------------------------------------------------------------
; Now we are done and can begin the process of exiting
; protected mode.
;---------------------------------------------------------------
	mov     eax,cr0         	; get CPU control register
	and     al,0feh         	; clear protected mode bit
	mov     cr0,eax         	; now, we are out of prot mode
	Mfarjmp <@RM_386W>,<@CODE>

;---------------------------------------------------------------
; Restore segment registers w/ real mode compatible values
;---------------------------------------------------------------
@RM_386W:
	mov     ss,cs:stack_seg		; restore SS
	popf				; restore interrupt flag
	pop	es			; restore ES,DS,BP
	pop	ds
	pop	bp
	retf
WriteL	endp


;---------------------------------------------------------------
; ReadL:  This routine reads a 32 bit value from a 32 bit
;         physical address.
;---------------------------------------------------------------
PUBLIC	ReadL
ReadL	proc	far
;---------------------------------------------------------------
	push	bp			; set up stack and
	mov	bp,sp			; local pointer
	push	ds
	push	es

;---------------------------------------------------------------
; 1) Disable interrupts
; 2) Set up descriptor table entries w/ run time addresses
; 3) Initialize pointer to GDT
; 4) Enable A20 on the address bus
;---------------------------------------------------------------
; (1)
	pushf				; save flags
	cli				; disable interrupts
; (2)
	Minit_descriptor        cs,0,CSEG2
	Minit_descriptor        ss,0,SSEG2
	Minit_descriptor        ds,0,DSEG2
; (3)
	mov     cs:stack_seg,SS		; save SS
	mov	dx,ds			; GDT linear address
	mov     ax,offset GDT_386
	Call    Calc_PM_Address
	mov     GDT_LW,ax
	mov     GDT_HW,dx
	Lgdt	GDT_PTR			; load GDT register
; (4)
	Call	Test_A20		; A20 already active ?
	jz	@OK_A20R

	Call	XMS_A20			; set A20 line via XMS driver
	Call	Test_A20
	jz	@OK_A20R

	Call	KBC_A20			; set A20 line via KBC
	Call	Wait_A20		; wait for activation
	jnz	@RM_386R
@OK_A20R:

;---------------------------------------------------------------
; 1) Enable protected mode
; 2) FAR JUMP to protected mode routine
;---------------------------------------------------------------
; (1)
	mov     eax,cr0         	; get CPU control register
	or      al,1            	; enable protected mode bit
	mov	cr0,eax              	; now in protected mode
; (2)
	Mfarjmp <@PM_386R>,<CSEG2-GDT_386>

;---------------------------------------------------------------
; Now, fully in protected mode:  Initialize protected mode
; segment registers.
;---------------------------------------------------------------
@PM_386R:
	mov     ax,ESEG2-GDT_386	; Pointer to extra segment
	mov     es,ax
	mov     ax,DSEG2-GDT_386	; Pointer to current data seg
	mov     ds,ax
	mov     ax,SSEG2-GDT_386	; Pointer to stack segment
	mov     ss,ax

;---------------------------------------------------------------
; Read data in protected mode
;---------------------------------------------------------------
	mov	ebx,[bp+6]
	mov	eax,es:[ebx]
	mov	edx,eax
	and	eax,0ffffh		; AX = low word
	shr	edx,16			; DX = high word

;---------------------------------------------------------------
; Now we are done and can begin the process of exiting
; protected mode.
;---------------------------------------------------------------
	mov     ebx,cr0         	; get CPU control register
	and     bl,0feh         	; clear protected mode bit
	mov     cr0,ebx         	; now, we are out of prot mode
	Mfarjmp <@RM_386R>,<@CODE>

;---------------------------------------------------------------
; Restore segment registers w/ real mode compatible values
;---------------------------------------------------------------
@RM_386R:
	mov     ss,cs:stack_seg		; Restore SS,ES,DS
	popf				; restore interrupt flag
	pop	es			; restore ES,DS,BP
	pop	ds
	pop	bp
	retf
ReadL	endp

	END

⌨️ 快捷键说明

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