专注于操作系统20之启动分页
来源:互联网 发布:淘宝运营每天要做什么 编辑:程序博客网 时间:2024/04/29 17:17
启动分页的步骤: 1.建立页目录表,2.建立页表,3.将页目录表的地址放到CR3中,4.将CR0中的PG置1表示启动分页。
这里建立一个页目录表(有1024项,每一项对应一个页表),建立1024个页表(每个页表有1024项,每一项对应一个物理页)。
下面是程序的代码, 参考了《自己动手写操作系统》
;;nasm 2.04 ;;nasm fenye.asm -o fenye.comorg 0100H%macro Descriptor 3 ;定义Descriptor结构体宏dw%2 & 0FFFFh; 段界限 1(2 字节)dw%1 & 0FFFFh; 段基址 1(2 字节)db(%1 >> 16) & 0FFh; 段基址 2(1 字节)dw((%2 >> 8) & 0F00h) | (%3 & 0F0FFh); 属性 1 + 段界限 2 + 属性 2(2 字节)db(%1 >> 24) & 0FFh; 段基址 3(1 字节)%endmacro ; 共 8 字节DA_CEQU98h; 只读代码段的属性值DA_DRWEQU92h; 允许读写的数据段的属性值DA_32EQU4000h;32位段的属性值DA_LIMIT_4KEQU8000h; 段界限粒度为 4K 字节PG_PEQU1; 页存在属性位PG_RWREQU0; R/W 属性位值, 读/执行PG_RWWEQU2; R/W 属性位值, 读/写/执行PG_USSEQU0; U/S 属性位值, 系统级PG_USUEQU4; U/S 属性位值, 用户级CatalogPageTableBase equ 200000h ; 页目录表的基址:2MPageTableBase equ 201000h ;页表的基址 :2M+4kjmpLABEL_BEGIN ;现在进行第一步:建立GDT表[SECTION .gdt] ;用于放GDT表的段;GDTLABEL_GDT: Descriptor 0,0,0 ;空描述符,当一个任务没有LDT时,会把LDTR清空,这时,LDTR便指向空描述符。LABEL_CODE32: Descriptor 0,SegCode32Len-1,DA_C + DA_32 ; 代码段的描述符LABEL_VIDEO: Descriptor 0B8000h,0ffffh,DA_DRW ;显存的描述符,0b8000h是显存的首地址;GDT 结束LABEL_CATALOG_TABLE: Descriptor CatalogPageTableBase, 4095 ,DA_DRW ;目录表的描述符,大小为4kLABEL_PAGE_TABLE: Descriptor PageTableBase , 1023 , DA_DRW | DA_LIMIT_4K ;页表的描述符,大小为1024*4K=4MGdtLenth equ $ - LABEL_GDT ;计算GDT表的长度GdtPtr dw GdtLenth - 1 ; 准备存入GDTR的信息 dd 0 ; 用于存放GDT表的物理地址,后面会计算;GDT选择子SelectorCatalogTable equ LABEL_CATALOG_TABLE - LABEL_GDT ;页目录表的选择子SelectorPageTable equ LABEL_PAGE_TABLE - LABEL_GDT ;页表的选择子SelectorCode32 equ LABEL_CODE32 - LABEL_GDT ;代码段的选择子SelectorVideo equ LABEL_VIDEO - LABEL_GDT ;显存所在段的选择子;[SECTION .gdt]结束[SECTION .s16][BITS 16];目标处理器模式LABEL_BEGIN:mov ax,csmov ds,axmov es,axmov ss,axmov sp,0100h;初始化32位段的描述符xor eax,eax ; 同或运算,这里是将eax清零mov ax,csshl eax,4 ;左移四位,相当于乘以16,实模式下计算物理地址add eax,LABEL_SEG_CODE32 ;eax中为32位段的物理地址mov word [LABEL_CODE32 + 2],ax ;将32位段的物理地址存入段的描述符中shr eax,16mov byte [LABEL_CODE32 + 4],almov byte [LABEL_CODE32 + 7],ah;计算GDT表的物理地址,将GDT表的物理地址信息存入GdtPtr中xor eax,eaxmov ax,csshl eax,4add eax,LABEL_GDTmov dword [GdtPtr + 2],eax;现在进行第二步:将GDT表的信息加载到GDTR中lgdt [GdtPtr] ;装载GDTR;关中断cli;现在进行第三步:打开地址线in al,92hor al,00000010bout 92h,al;现在进行第四步:置PE为1,表示CPU处于保护模式下mov eax,cr0or eax,1mov cr0,eax;现在进入第五步:跳到保护模式的代码jmp dword SelectorCode32:0 ;这里将SelectorCode32存入CS中作为选择子;[SECTION .s16] 结束;保护模式下的代码,32位代码[SECTION .s32][BITS 32] LABEL_SEG_CODE32:call SetupPaging ;启动分页mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符mov gs,ax mov edi,(80 * 10 + 0)*2 ;屏幕的第10行,第0列mov ah,0Chmov al,'p'mov [gs:edi],ax ;将字符‘p’输出到屏幕jmp $SetupPaging:;为简单,这里让线性地址等于物理地址;初始化页目录表mov ax,SelectorCatalogTable ;将页目录表的选择子放到es中mov es,axmov ecx,1024 ;1024送到cx,表示循环1024次xor edi,edi ;edi清零xor eax,eax ;ax清零mov eax,PageTableBase | PG_P | PG_USU | PG_RWW ;将第一个页表的信息(页目录表中的一个项)放到eax中,准备放到页目录表中 s1:stosdadd eax,4096 ;eax加4096表示下一个页表的地址(一个页表有4096的大小)loop s1;初始化页表的信息mov ax,SelectorPageTable ;将第一个页表的选择符放到esmov es,axmov ecx,1024*1024 ;循环1024*1024次,因为一个目录表有1024个项,每一个项对应一个页表,而每个页表有1024个项,每一个项xor edi,edi ;对应一个物理页xor eax,eaxmov eax,PG_P | PG_USU | PG_RWW s2:stosdadd eax,4096 ;每一页有4k的大小loop s2mov eax,CatalogPageTableBase ;将页目录表的地址存入cr3中mov cr3,eaxmov eax,cr0 ;将cr0的最高位置1,表示启动分页or eax,80000000hmov cr0,eaxretSegCode32Len equ $ - LABEL_SEG_CODE32 ;计算32位代码段的长度
- 专注于操作系统20之启动分页
- 专注于操作系统19之走进分页
- 专注于操作系统21之分页进阶
- 专注于操作系统3之计算机的启动过程
- 专注于操作系统4之引导程序
- 专注于操作系统5之引导程序代码
- 专注于操作系统13之LDT
- 专注于操作系统15之特权级
- 专注于操作系统22之中断
- 专注于操作系统23之中断进阶
- 专注于操作系统29之从loader进入保护模式并分页
- 专注于操作系统1之操作系统的从无到有a
- 专注于操作系统2之操作系统的从无到有b
- 专注于操作系统6之导入操作系统内核
- 专注于操作系统7之初识保护模式
- 专注于操作系统8之保护模式基础知识a
- 专注于操作系统9之保护模式基础知识b
- 专注于操作系统10之走进保护模式
- android源码结构
- 四极管:在menuconfig中选择m和 y的区别
- 伪静态网站如何做301重定向?
- Array && ArrayList C#
- ListView 实现像Android Market那样分页
- 专注于操作系统20之启动分页
- 程序员需要具备的基本技能
- ranger:linuxer&vimer的福音,一款非常好用的命令行文件管理器
- java中String Date Timestamp Calendar 之间的关系及转换
- linux 内核定时器编程
- linux下mysql的编码统一
- 关于内存对其问题(三)
- C# Textbox的ImeMode取值对中文输入法的影响
- 网络录音程序的录音部分实现