07.保护模式下字符显示

版权声明:本文为博主原创文章,未经博主允许不得转载。 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),一个函数(方法)功能是映射,甚至感觉整个人类科技文明都可以使用映射来描述,道可道,非常道。细细体会

猜你喜欢

转载自blog.csdn.net/Zllvincent/article/details/83550490
今日推荐