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

📄 mode_t.asm

📁 实现了分段分页
💻 ASM
字号:
.MODEL HUGE
STACK       SEGMENT STACK PARA 'STACK';设堆栈
            DB 200 DUP(0)
STACK       ENDS
include g_def.asm		;定义描述符结构和选择符
CODE        SEGMENT WORD PUBLIC 'CODE'
            ASSUME CS:CODE,DS:DATA,SS:STACK
MODE_CHANGE PROC FAR
	    
START:      MOV AX,DATA			;实模式
            MOV DS,AX                   ;DS=DATA
            CLI                         ;关中断
            MOV AX,STACK
            MOV SS,AX                   ;SS=STACK
            MOV SAVE_SS,AX		;备份SS
            MOV SP,200
            MOV SAVE_SP,SP		;备份SP
            STI                         ;关中断
            MOV DS:FILE_OVER,1          ;文件没有读完标志位
            ;
            .386P                       ;启用80386保护方式下的指令
            MOV AH,0DFH
            CALL OPEN_A20               ;打开地址线A20,函数在程序文件A20.ASM中
            ; 保存初始(BIOS) GDTR 与 IDTR ,实模式用
            SGDT FWORD PTR SAVE_GDT	;备份GDT
            SIDT FWORD PTR SAVE_IDT	;备份IDT
            ;设置保护模式下要使用的与CS、DS、SS、GDT BUF相应描述符
            MOV DI,OFFSET GDT_CS
            MOV AX,CS
            MOV CX,10H
            MUL CX			;AX*16即左移4位,低位在AX,高位在DX
            MOV [DI].BASE_L,AX          ;GDT_CS.BASE_L = CS×16
            MOV [DI].BASE_M,DL         
            ;set desc for ds  等于初始化GDT,以下给在保护模式下的CS,DS,SS,GDT_BUF的基址和内存段设值
            MOV DI,OFFSET GDT_DS     	;AX*16即左移4位,低位在AX,高位在DX
            MOV DX,0
            MOV AX,DS                   
            MOV CX,10H
            MUL CX
            MOV [DI].BASE_L,AX          ;GDT_DS.BASE_L=DS×16      ___________________________________
            MOV [DI].BASE_M,DL          ;GDT_DS.BASE_M=0           |BASE_H   |  BASE_M   |   BASE_L  |
            MOV [DI].BASE_H,DH          ;GDT_DS.BASE_H=0           |  0      |     0     |   DS×16  |
            ;set desc for ss
            MOV DI,OFFSET GDT_SS	;AX*16即左移4位,低位在AX,高位在DX
            MOV AX,SS
            MOV CX,10H
            MUL CX
            MOV [DI].BASE_L,AX          ;GDT_SS.BASE_L=SS×16
            MOV [DI].BASE_M,DL          ;GDT_SS.BASE_M=0
            ;set desc for gdt_buf
            MOV DI,OFFSET GDT_BUF 
            ;设置GDT_BUF,基址=2M,限长=1M
            MOV [DI].BASE_L,0      	;GDT_BUF.BASE_L=0
            MOV [DI].BASE_M,020H	;GDT_SS.BASE_M=020H,200000H为2MB
            MOV [DI].GRAN,0FH           ;缓冲区最大1M
            ;计算并保存GDT表的基地址(DX:AX)和大小
            CLI
            MOV AX,DS			;AX*16即左移4位,低位在AX,高位在DX
            MOV CX,10H
            MUL CX                      ;AX=DS×16+GDT_DEF
            ADD AX,OFFSET GDT_DEF       ;DX:AX保存GDT表的32位地址(实模式下的实际物理地址(段*16+偏移
                       
            ADC DX,0 
            MOV DTLOAD,AX               ;DTLOAD=GDT_DEF的地址
            MOV DTLOAD+2,DX
            MOV AX,OFFSET GDT_SIZE      ;将GDT_SIZE的偏移地址赋给AX
            SUB AX,OFFSET DTSIZE        ;DTSIZE=(GDT_SIZE的偏移地址-DISIZE的偏移地址+1)
            ADD AX,1
            MOV DTSIZE,AX
            ;***********************************************
                                      ; mov file to c_buffer,打开文件读,句柄放在FILE_HANDLE
            MOV DS:G_BUF_SUM,0
            MOV AX,3D02H              	;AH=3DH表示读取文件,AL=02H表示为读写打开文件
            LEA DX,FILE_NAME		;DX存放文件名串地址
            INT 21H
            ;以上4行代码获得文件的句柄

            JNC READ_FILE0    		;CX=1表示打开文件出错
            LEA DX,ERR_FILE
            MOV AH,9
            INT 21H
            ;以上4行代码显示错误信息

            MOV AH,4CH
            INT 21H			;未发现文件,退出,即带返回码结束

READ_FILE0: MOV DS:FILE_HANDLE,AX       ;保存文件句柄,开始读文件
READ_FILE:  
            MOV DS:SAVE_SS,SS
            MOV DS:SAVE_SP,SP
            SGDT FWORD PTR SAVE_GDT	;保存GDTR & IDTR
            SIDT FWORD PTR SAVE_IDT

            MOV BX,DS:FILE_HANDLE  	;BX放文件句柄
            MOV CX,1024            	;CX存放读取字节
            MOV DX,OFFSET C_BUFFER	;DX存放数据缓冲区的偏移地址
            MOV AH,3FH             	;AH=3FH表示读取文件
            INT 21H			;调用DOS 21H中断
            ;以上5行代码从文件中读1024字节到C_BUFFER中

            JNC READ_FILE1		;CX=1表示读取文件出错,其实是剩下字节不够1024
            MOV AX,0
            MOV DS:C_BUF_SIZE,AX
            MOV DS:FILE_OVER,AX
            MOV AH,3EH            	;关闭文件
            INT 21H
            JMP PROTECT_MODE		;跳到保护模式
READ_FILE1: MOV DS:C_BUF_SIZE,AX  	;不够1024字节,读取剩下的字节后关闭文件
            CMP AX,1024                 ;等于1024字节,则跳转到PROTECT_MODE
            JNL PROTECT_MODE
            MOV DS:FILE_OVER,0          ;读文件结束, 将文件结束标志设置为0
            MOV BX,DS:FILE_HANDLE  
            MOV AH,3EH            ;close file
            INT 21H
            ;*********************************************
PROTECT_MODE:				;切换到保护模式
	    ;用LGDT指令把GDT表的基地址和边界值加载到GDTR,使GDT有效
            cli
            LGDT FWORD PTR DTSIZE	;加载GDTR
            
            MOV AX,GDT_DS_SEL		;加载数据段描述符
            MOV DS,AX
            MOV ES,AX
            MOV FS,AX
            MOV GS,AX
	    ;CR0的PE位置1,允许保护模式,并用JMP指令清指令队列中预取到的实模式代码,再用段间跳转指令进入保护模式。

            sti
            ;
           
	    
            MOV EAX,00000001H           ;CR0的PE位置1,允许保护模式
            MOV CR0,EAX
            JMP EDS_FLUSH        	;清指令预取队列,并真正进入保护模式
EDS_FLUSH:  DB 0EAH			;0EAH其实是短跳转指令,南航汇编书后有介绍
            DW OFFSET MOVE_BUF		;跳转的偏移地址
            DW GDT_CS_SEL		;跳转的段地址
            ;****************************************
MOVE_BUF:   ;保护模式
            MOV AX,GDT_DS_SEL
            MOV FS,AX
            MOV AX,GDT_BUF_SEL
            MOV GS,AX
            CMP FS:C_BUF_SIZE,1         ;C_BUF_SIZE<1 则->VRAM_DISP,显示文件
            JL VRAM_DISP          	;文件已经读完

            MOV ECX,0
            MOV CX,FS:C_BUF_SIZE
            MOV EAX,OFFSET C_BUFFER
            MOV ESI,EAX
            MOV EDI,FS:G_BUF_SUM
MOVE_BUF1:  MOV AL,FS:[ESI]        ;move to 2M  移动数据到扩展内存
            MOV GS:[EDI],AL        ;GDT_BUF_SEL:[EDI]=GDT_DS_SEL:[ESI]
            INC EDI                ;将C_BUFFER的数据移至扩展内存G_BUF_SUM开始后的地方
            INC ESI
            LOOP MOVE_BUF1

            MOV FS:G_BUF_SUM,EDI   ;G_BUF_SUM=数据大小
            CMP FS:FILE_OVER,1
            JL VRAM_DISP            ;FILE_OVER<1  则去显示
            ;***************** 		;若文件未读完回实模式去读文件
            CLI       
            MOV EAX,CR0
            AND AX,NOT PE_ON
            MOV CR0,EAX			;置CR0为实模式
            ;
            DB 0EAH			;同样为跳转指令
            DW OFFSET REAL_MODE0
            DW CODE  
REAL_MODE0: MOV AH,0DDH                 ;进实模式
            CALL CLOSE_A20              ;关闭A20地址线
            ;
            MOV AX,DATA
            MOV DS,AX                   ;置实模式DS、SS、SP的值
            LGDT FWORD PTR SAVE_GDT	;恢复GDTR、IDTR的内容
            LIDT FWORD PTR SAVE_IDT
            cli
            MOV SS,SAVE_SS
            MOV SP,SAVE_SP
            sti
            JMP READ_FILE               ;重新读取文件
            ;***************************************
            ; all of file are moved to g_buf

VRAM_DISP:                              ;在保护模式下访问显示缓存(VRAM),在屏幕上显示文本
            ;文件已经读完时,将扩展内存中数据写到显示缓存 B8000H
            MOV AX,GDT_DS_SEL		;将各个选择子置入段中
            MOV FS,AX
            MOV AX,GDT_BUF_SEL
            MOV GS,AX
            MOV AX,VRAM_SEL
            MOV ES,AX
            MOV CX,08D0H
            MOV BX,0
            ;下面3行代码不停地将VRAM_SEL中的内容全赋为0720H
L1:         MOV ES:[BX],0720H		;高字节存放显示属性,低字节放显示内容
            ADD BX,2
            LOOP L1

            MOV ECX,FS:G_BUF_SUM
            CMP ECX,2048                ;ECX<2048?时则至LL,否则将ECX赋值为2048
            JL  LL
            MOV ECX,2048		;因为2048/2=1024
LL:         MOV ESI,0                   ;ECX<2048
            MOV EBX,480
L2:         MOV AL,GS:[ESI]             ;将GDT_BUF_SEL中的内容转移至VRAM_SEL初始:VRAM_SEL:[480]=GDT_BUF_SEL:[0]
            MOV AH,22
            MOV ES:[EBX],AX		;显存地址为0B000:0000,低字节放显示内容,高字节放显示属性
            ADD EBX,2			;AH=22表示显示属性,显示属性共8个字节
            INC ESI			;7为闪烁标志(1闪)654为背景(000黑,111白)3为亮度(0正常,1加亮),210为前景
            LOOP L2
;turn to real_mode
            CLI
            MOV EAX,CR0
            AND AX,NOT PE_ON
            MOV CR0,EAX
            ;
            DB 0EAH
            DW OFFSET REAL_MODE
            DW CODE
REAL_MODE:  MOV AH,0DDH
            TO_DOS
            .8086;只承认8086指令
MODE_CHANGE ENDP
include a20.asm

CODE        ENDS

;数据段开始
DATA        SEGMENT WORD PUBLIC 'DATA'
FILE_NAME   DB '\TC\G\MODE.TXT',0
FILE_HANDLE DW 0
FILE_OVER   DW 0
ERR_FILE    DB 0DH,0AH,'Open file error$'
OK_MSG      DB 0DH,0AH,'Have a nice day,Bye!   $'
SAVE_GDT    DW 4 DUP(0)
SAVE_IDT    DW 4 DUP(0)
SAVE_SS     DW 0
SAVE_SP     DW 0

;定义GDT表开始
DTSIZE      DW 0
DTLOAD      DW 0,0
GDT_DEF     EQU $
            GDT_DESC <0,0,0,0,0,0>
GDT_CS      GDT_DESC <0FFFFH,0,0,9AH,0,0>
                           ;9AH=exec/read ,DPL=0
GDT_DS      GDT_DESC <0FFFFH,0,0,92H,0,0>
                           ;92H=P ,DPL=0,TYPE=2
GDT_SS      GDT_DESC <0,0,0,96H,0,0>   
                           ;96H=R/W ,DOWN
GDT_VRM     GDT_DESC <0FFFFH,08000H,0BH,92H,0,0>
                           ;92H=P ,DPL=0,TYPE=2
GDT_BUF     GDT_DESC <0FFFFH,0,0,92H,0,0>
                           ;92H=P ,DPL=0,TYPE=2 ,length=1M
GDT_SIZE    DW 0

;定义GDT表结束

C_BUF_SIZE  DW 0
G_BUF_SUM   DD 0
C_BUFFER    DB 1024 DUP(?)
DATA        ENDS
            END START

⌨️ 快捷键说明

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