版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Zllvincent/article/details/83550490
简介
上一博文我们实现了从实模式到保护模式的切换并在屏幕上显示了简单的字符,对于保护模式给我们带来的寻址范围的变化体会可能不深入,很难体会在保护模式下的地址寻址变化。
目标
在保护模式下将一段字符串复制到1M以外的地址空间,并将字符从该地址空间显示到屏幕上。
1、kernel.s 文件如下
;全局描述符结构 8字节
; byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0
; byte6低四位和 byte1 byte0 表示段偏移上限
; byte7 byte4 byte3 byte2 表示段基址
;定义全局描述符数据结构
;3 表示有3个参数分别用 %1、%2、%3引用参数
;%1:段基址 %2:段偏移上限 %3:段属性
%macro GDescriptor 3
dw %2 & 0xffff
dw %1 & 0xffff
db (%1>>16) & 0xff
dw ((%2>>8) & 0x0f00) | (%3 & 0xf0ff)
db (%1>>24) & 0xff
%endmacro
DA_32 EQU 0x4000 ; 32 位段
DA_CODE EQU 0x98 ; 只执行代码段属性值
DA_RW EQU 0x92 ; 可读写数据段属性值
org 0x9000
jmp entry
[SECTION .gdt]
;定义全局描述符 段基址 段偏移上限 段属性
LABEL_GDT: GDescriptor 0, 0, 0
LABEL_DESC_CODE: GDescriptor 0, SegCodeLen-1, DA_CODE+DA_32
LABEL_DESC_VIDEO: GDescriptor 0xb8000, 0xffff, DA_RW
LABEL_DESC_7M: GDescriptor 0x0700000, 0xffff, DA_RW
;gdt 表大小
GdtLen equ $-LABEL_GDT
;gdt表偏移上限和基地址
GdtPtr dw GdtLen-1
dd 0
;cpu开机进入实模式时使用的段寄存器 cs,ds,es,ss 和偏移地址组成内存地址,内存地址=段寄存器 * 16 + 偏移地址
;保护模式中段寄存器保存的是gdt 描述表中各个描述符的偏移,也叫选择子
SelectorCode32 EQU LABEL_DESC_CODE-LABEL_GDT
SelectorVideo EQU LABEL_DESC_VIDEO-LABEL_GDT
Selector7M EQU LABEL_DESC_7M-LABEL_GDT
[SECTION .s16]
[BITS 16]
entry:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x100
;设置LABEL_DESC_CODE描述符段基址
mov eax,0
mov ax,cs
shl eax,4
add eax,SEG_CODE32
mov word [LABEL_DESC_CODE+2],ax
shr eax,16
mov [LABEL_DESC_CODE+4],al
mov [LABEL_DESC_CODE+7],ah
mov eax,0
mov ax,ds
shl eax,4
add eax,LABEL_GDT
mov dword [GdtPtr+2],eax
;设置GDTR 寄存器
lgdt [GdtPtr]
cli ;关闭可可屏蔽中断,如键盘中断
in al,0x92
or al,0x02
out 0x92,al
mov eax,cr0
or eax,1
mov cr0,eax
jmp dword SelectorCode32:0
[SECTION .s32]
[BITS 32]
SEG_CODE32:
mov esi,msg
mov ax,Selector7M
mov es,ax
mov edi,0
copy_msg_to_7M:
mov al,[esi]
mov [es:edi],al
inc edi
inc esi
cmp al,0
je show_char
jmp copy_msg_to_7M
show_char:
mov ax,SelectorVideo
;gs 寄存器是80386新增的辅助段寄存器
mov gs,ax
;在屏幕中间显示字符串,屏幕为每行80个字符,共25行。低字节为ascii字符编码,高字节为字符显示属性
;可参考 《汇编语言》 王爽,屏幕显示相关章节
;在屏幕11行20列开始显示字符
mov ax,(80*11+20)
mov ecx,2
mul ecx
mov edi,eax
mov ah,10000110b
mov esi,0
putloop:
mov al,[es:esi]
cmp al,0
je fin
mov [gs:edi],ax
add edi,2
inc esi
jmp putloop
fin:
hlt
jmp fin
msg:
db 'message from 0x0500000',0
SEG_CODE32_END: nop
;32为模式代码长度
SegCodeLen EQU SEG_CODE32_END-SEG_CODE32
相比于上一博文,该程序代码没有太大的变化。
1)添加了LABEL_DESC_7M段描述符和Selector7M选择子,
2)并将字符串复制到该选择子指向的内存空间,
3)修改字符显示属性为 mov ah,10000110b 实现闪烁功能
boot.s、main.c文件参考上一博文,运行结果如下
总结
保护模式与实模式对边最大的变化时寻址方式的变化,保护模式下地址=短地址*16+偏移地址
,保护模式下地址不再是段地址左移4位(向左移动一位二进制相当于扩大2倍,222*2即16)加上偏移地址,保护模式下寻址都通过寄存器GDT,段寄存器保存的是GDT中段索引。一句话总结就是地址映射方式发生变化。
题外话
博主在编程中特别喜欢使用数学上的映射来概括抽象的东西,y = f(x),一个函数(方法)功能是映射,甚至感觉整个人类科技文明都可以使用映射来描述,道可道,非常道。细细体会