Print.S

段选择子

x86保护模式中的一个16位的值,用来标识特定段描述符。段描述符存储在全局描述符表 (GDT) 或局部描述符表 (LDT) 中,段选择子通过指定索引和额外信息来访问这些描述符。

一个段选择子由以下部分组成:

位数 名称 描述
0-1 RPL (Request Privilege Level) 请求特权级,指明访问该段时的最低特权要求。
2 TI (Table Indicator) 表指示符,0 表示使用全局描述符表 (GDT),1 表示使用局部描述符表 (LDT)。
3-15 Index 段描述符在 GDT 或 LDT 中的索引位置,从 0 开始。

TI_GDT

选择子中的TI位的值

RPL0

选择子中的RPL位的值,定义为0,指示了段访问的特权级

特权级别(Privilege Levels)

在 x86 保护模式中,特权级别有 4 个,从 0 到 3,权限从高到低:

  • RPL 0:内核态,最高权限。

  • RPL 1:操作系统服务权限。

  • RPL 2:中间特权级,一般为驱动程序。

  • RPL 3:用户态,最低权限。

RPL的作用

指定当前请求访问段时的特权级

  1. 访问控制,将RPL与当前任务的特权级(CPL)以及段描述符中的特权级(DPL)进行比较,决定是否允许访问

  2. 优先级覆盖,RPL可以用来降低当前任务的特权级

pushad: 保存所有通用寄存器的值到栈上

具体作用

执行 pushad 后,会按照以下顺序将寄存器的值依次压入栈:

  1. EAX

  2. ECX

  3. EDX

  4. EBX

  5. ESP(注意,这里是 执行pushad前的ESP值

  6. EBP

  7. ESI

  8. EDI

这样,所有的 8 个通用寄存器的值都被保存到了栈中。

对应的逆操作:

popad:从栈中按相反顺序依次恢复寄存器

VGA寄存器

显卡和显示设备之间的接口,用于控制屏幕显示的各种参数,包括分辨率、颜色深度、刷新率、光标位置等。VGA寄存器是通过特定的端口进行访问的,并分为多个类别,每类寄存器负责不同的功能。

VGA 的寄存器访问需要两个端口:

  1. 索引端口 (0x03D40x03B4):用于选择要访问的寄存器索引。

  2. 数据端口 (0x03D50x03B5):用于读写索引对应的寄存器数据。

0x03D4 是一个常见的地址,在计算机硬件编程中,通常与 VGA(视频图形阵列)控制器的端口有关。它是 VGA寄存器索引端口 的地址。


VGA 寄存器访问概述

VGA 的寄存器访问需要两个端口:

  1. 索引端口 (0x03D40x03B4):用于选择要访问的寄存器索引。

  2. 数据端口 (0x03D50x03B5):用于读写索引对应的寄存器数据。

这两个端口允许程序直接与显卡的寄存器交互,用于控制屏幕显示的各种参数。


端口地址解释

  • 0x03D40x03D5

    • 用于 彩色模式 下的 VGA 寄存器访问。

  • 0x03B40x03B5

    • 用于 单色模式 下的 VGA 寄存器访问。

通过0x03D4选择光标位置寄存器

在0x03D5写入具体数据,调整光标在文本模式中的位置

彩色模式和单色模式

彩色模式:

支持多种颜色显示,通过RGB(红绿蓝)模型组合颜色

常用于现代计算机显示器

单色模式:

仅支持两种颜色(黑白或黑绿)

输出的颜色少,但对比度高

常用于早期单色显示器,现代系统中主要用于兼容模式或调试

滚屏

屏幕通常用显存中的固定区域表示,显存是有限的,因此需要不断腾出空间以显示新内容。

将屏幕内容向上滚动一行,同时清空最后一行的内容

ecx = 960

  • 每个字符在显存中占两个字节 字符+属性

  • 屏幕总共有2000个字符(80列x25行)

  • 去掉最后一行,剩余1920个字符

  • 1920字符对应显存大小为1920 x 2 = 3840字节

  • movsd一次搬运4字节,最后需要3840 ÷ 4 = 960次

为什么是最后一行:

滚屏的操作是把当前的向上复制一遍,原来的内容会被新复制的内容替换,但是最后一行的内容没有新内容覆盖,所以需要直接清除而不是搬运

光标位置

print.S中bx记录的是光标位置的字符索引

屏幕一共2000个字符(80列x25行)

bx值的范围是0-1999,对应屏幕的字符位置。

;原来是你!!!!!
global set_cursor:
set_cursor:

    mov dx,0x03d4       ;指定VGA寄存器索引端口
    mov al,0x0e         ;指定访问光标位置的高字节寄存器
    out dx,al           ;将 0x0E 写入 0x3D4,选择高字节寄存器
    mov dx,0x03d5       ;通过读写数据端口0x3d5来获得或设置光标位置
    mov al,bh           ;从bx的高字节获取光标位置的高8位
    out dx,al           ;将光标位置高字节写入VGA控制器

    mov dx,0x03d4
    mov al,0x0f         ;指定低字节寄存器
    out dx,al
    mov dx,0x03d5
    mov al,bl
    out dx,al
.put_char_done:
    popad
    ret

这段代码的逻辑就是获取光标位置并存入bx,之后按照一个字符2字节,每次移动光标就是shr 1或者shl 1。

比如:

;退格键
.is_backspace:

    dec bx
    shl bx,1
    mov byte [gs:bx],0x20       ;0x20:空格字符
    inc bx
    mov byte [gs:bx],0x07
    shr bx,1                    ;将bx右移1位,将显示地址偏移量转换回字符索引,恢复光标逻辑位置
    jmp set_cursor
;显示一个字符,并更新光标位置
.put_other:
    shl bx,1                    ;将光标位置左移一位,即乘2,每个字符占2字节。
    mov [gs:bx],cl      ;要显示的字符cl,写入显存,显存由gs段寄存器和bx偏移量指定的位置
    inc bx
    mov byte [gs:bx],0x07
    shr bx,1
    inc bx
    cmp bx, 2000
    jl set_cursor

版权声明:
作者:Paul
链接:https://www.15ivyy.site/index.php/2024/12/11/print-s/
来源:somethingFromPaul
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录