27 x86 系统上的内存分页
参考
https://blog.51cto.com/13475106/category6.html及狄泰软件相关课程
一.x86系列处理器上的页式内存管理
1.硬件层直接支持内存分页机制
2.默认情况下不使用分页机制(段式内存管理)
3.分页机制(进行配置)启动后,使用二级页表对内存进行管理
x86系列处理器的分页方式(32位)
如图所示,32位被分成了三部分
1.在低12位中,表示的是页内偏移地址
2.在中间10位,用于在子页表中查找目标页地址
3.在最高的10位中,用于子页目录中查找页表地址
A.下面由一张图来展示分页机制
B.x86系列处理器的分页方式(32位)
1.在页目录大小中,2的十次方项,每项4字节,一共为4K
2.在子页表大小中,2的十次方项,每项4字节,一共为4K
3.在页大小中,2的十二次方,一共为4K
由上可以得出
1.页目录占用1内存页-可访问1024个子页表
2.单个子页表占用1内存页-可访问1024个页面
3.页面起始地址按4K字节对齐-总是4096整数倍
4.分页后可访问的虚拟内存空间为:4K(1024*1024)=4G
X86简单的分页构建方式
可以通过for循环构建目录,子页表,主要原因是一个一个的生成的
C.x86系列处理器上的页属性
1.由于物理页面的地址必须按照4K字节对齐
2.由此可得,页目录可使用地址的低12位进行属性描述
在x86系列处理器上查看页属性的说明
D.x86对分页的硬件支持--代码上
如下所示
1.将页目录起始地址放置到cr3-该寄存器类似指针指向页目录起始地址
2.将cr0里面的值取出放置到eax寄存器中,
3.将cr0里面的值所对应二进制最高位置1--硬件级开启分页机制
在这里需要注意的是
1.loop指令-该指令表示的是循环指令
1 2 3 4 5 6 | mov ax,0 mov cx,10 Label: add ax,cx loop Label |
在这里表示是将cx减1,对cx进行判断,若cx不为0,则执行标签处Label的代码
2.-stosb/stosw/stosd
表示的是把al/ax/eax中的值存储到edi指向的内存单元中,同时edi的值根据方向标志增加或减少(cld/std)
1 2 3 4 5 | mov es,ax mov edi, mov eax,0XFF cld stosd |
编程实现
loader.asm与inc.asm的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | %include "inc.asm" PageDirBase equ 0x200000 PageTblBase equ 0x201000 org 0x9000 jmp ENTRY_SEGMENT [section .gdt] ; GDT definition ; 段基址, 段界限, 段属性 GDT_ENTRY : Descriptor 0, 0, 0 CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32 VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32 DATA32_DESC : Descriptor 0, Data32SegLen - 1, DA_DRW + DA_32 STACK32_DESC : Descriptor 0, TopOfStack32, DA_DRW + DA_32 PAGE_DIR_DESC : Descriptor PageDirBase, 4095, DA_DRW + DA_32 PAGE_TBL_DESC : Descriptor PageTblBase, 1023, DA_DRW + DA_LIMIT_4K + DA_32 ; GDT end GdtLen equ $ - GDT_ENTRY GdtPtr: dw GdtLen - 1 dd 0 ; GDT Selector Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0 VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL0 Data32Selector equ (0x0003 << 3) + SA_TIG + SA_RPL0 Stack32Selector equ (0x0004 << 3) + SA_TIG + SA_RPL0 PageDirSelector equ (0x0005 << 3) + SA_TIG + SA_RPL0 PageTblSelector equ (0x0006 << 3) + SA_TIG + SA_RPL0 ; end of [section .gdt] TopOfStack16 equ 0x7c00 [section .dat] [bits 32] DATA32_SEGMENT: DTOS db "D.T.OS!" , 0 DTOS_OFFSET equ DTOS - $$ HELLO_WORLD db "Hello World!" , 0 HELLO_WORLD_OFFSET equ HELLO_WORLD - $$ Data32SegLen equ $ - DATA32_SEGMENT [section .s16] [bits 16] ENTRY_SEGMENT: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, TopOfStack16 ; initialize GDT for 32 bits code segment mov esi, CODE32_SEGMENT mov edi, CODE32_DESC call InitDescItem mov esi, DATA32_SEGMENT mov edi, DATA32_DESC call InitDescItem mov esi, STACK32_SEGMENT mov edi, STACK32_DESC call InitDescItem ; initialize GDT pointer struct mov eax, 0 mov ax, ds shl eax, 4 add eax, GDT_ENTRY mov dword [GdtPtr + 2], eax ; 1. load GDT lgdt [GdtPtr] ; 2. close interrupt cli ; 3. open A20 in al, 0x92 or al, 00000010b out 0x92, al ; 4. enter protect mode mov eax, cr0 or eax, 0x01 mov cr0, eax ; 5. jump to 32 bits code jmp dword Code32Selector : 0 ; esi --> code segment label ; edi --> descriptor label InitDescItem: push eax mov eax, 0 mov ax, cs shl eax, 4 add eax, esi mov word [edi + 2], ax shr eax, 16 mov byte [edi + 4], al mov byte [edi + 7], ah pop eax ret [section .s32] [bits 32] CODE32_SEGMENT: mov ax, VideoSelector mov gs, ax mov ax, Stack32Selector mov ss, ax mov eax, TopOfStack32 mov esp, eax mov ax, Data32Selector mov ds, ax mov ebp, DTOS_OFFSET mov bx, 0x0C mov dh, 12 mov dl, 33 call PrintString mov ebp, HELLO_WORLD_OFFSET mov bx, 0x0C mov dh, 13 mov dl, 31 call PrintString call SetupPage jmp $ ; ; SetupPage: push eax push ecx push edi push es mov ax, PageDirSelector mov es, ax mov ecx, 1024 ; 1K sub page tables mov edi, 0 mov eax, PageTblBase | PG_P | PG_USU | PG_RWW cld stdir: stosd add eax, 4096 loop stdir mov ax, PageTblSelector mov es, ax mov ecx, 1024 * 1024 ; 1M pages mov edi, 0 mov eax, PG_P | PG_USU | PG_RWW cld sttbl: stosd add eax, 4096 loop sttbl mov eax, PageDirBase mov cr3, eax mov eax, cr0 or eax, 0x80000000 mov cr0, eax pop es pop edi pop ecx pop eax ret ; ds:ebp --> string address ; bx --> attribute ; dx --> dh : row, dl : col PrintString: push ebp push eax push edi push cx push dx print: mov cl, [ds:ebp] cmp cl, 0 je end mov eax, 80 mul dh add al, dl shl eax, 1 mov edi, eax mov ah, bl mov al, cl mov [gs:edi], ax inc ebp inc dl jmp print end: pop dx pop cx pop edi pop eax pop ebp ret Code32SegLen equ $ - CODE32_SEGMENT [section .gs] [bits 32] STACK32_SEGMENT: times 1024 * 4 db 0 Stack32SegLen equ $ - STACK32_SEGMENT TopOfStack32 equ Stack32SegLen - 1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | ; Segment Attribute DA_32 equ 0x4000 DA_LIMIT_4K EQU 0x8000 DA_DR equ 0x90 DA_DRW equ 0x92 DA_DRWA equ 0x93 DA_C equ 0x98 DA_CR equ 0x9A DA_CCO equ 0x9C DA_CCOR equ 0x9E ; Segment Privilege DA_DPL0 equ 0x00 ; DPL = 0 DA_DPL1 equ 0x20 ; DPL = 1 DA_DPL2 equ 0x40 ; DPL = 2 DA_DPL3 equ 0x60 ; DPL = 3 ; Special Attribute DA_LDT equ 0x82 DA_TaskGate equ 0x85 ; 任务门类型值 DA_386TSS equ 0x89 ; 可用 386 任务状态段类型值 DA_386CGate equ 0x8C ; 386 调用门类型值 DA_386IGate equ 0x8E ; 386 中断门类型值 DA_386TGate equ 0x8F ; 386 陷阱门类型值 ; Selector Attribute SA_RPL0 equ 0 SA_RPL1 equ 1 SA_RPL2 equ 2 SA_RPL3 equ 3 SA_TIG equ 0 SA_TIL equ 4 PG_P equ 1 ; 页存在属性位 PG_RWR equ 0 ; R/W 属性位值, 读/执行 PG_RWW equ 2 ; R/W 属性位值, 读/写/执行 PG_USS equ 0 ; U/S 属性位值, 系统级 PG_USU equ 4 ; U/S 属性位值, 用户级 ; 描述符 ; usage: Descriptor Base, Limit, Attr ; Base: dd ; Limit: dd (low 20 bits available) ; Attr: dw (lower 4 bits of higher byte are always 0) %macro Descriptor 3 ; 段基址, 段界限, 段属性 dw %2 & 0xFFFF ; 段界限1 dw %1 & 0xFFFF ; 段基址1 db (%1 >> 16) & 0xFF ; 段基址2 dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2 db (%1 >> 24) & 0xFF ; 段基址3 %endmacro ; 共 8 字节 ; 门 ; usage: Gate Selector, Offset, DCount, Attr ; Selector: dw ; Offset: dd ; DCount: db ; Attr: db %macro Gate 4 dw (%2 & 0xFFFF) ; 偏移地址1 dw %1 ; 选择子 dw (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性 dw ((%2 >> 16) & 0xFFFF) ; 偏移地址2 %endmacro |
设置的过程如下图所示
通过make之后得到的结果
在这里的打印结果为字符串,并没有分页的显示效果,在后面的博客会对该次实验进行解释
小结
1.x86处理器直接支持内存分页机制
2.分页机制启动后,使用二级页表对内存进行管理
3.页目录和单个子页表占用1内存页
4.页面起始地址按4K字节对齐
5.分页后可访问的虚拟内存空间为4G
posted on 2021-01-08 09:46 lh03061238 阅读(206) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)