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的作用
指定当前请求访问段时的特权级
-
访问控制,将RPL与当前任务的特权级(CPL)以及段描述符中的特权级(DPL)进行比较,决定是否允许访问
-
优先级覆盖,RPL可以用来降低当前任务的特权级
pushad: 保存所有通用寄存器的值到栈上。
具体作用
执行 pushad
后,会按照以下顺序将寄存器的值依次压入栈:
-
EAX
-
ECX
-
EDX
-
EBX
-
ESP(注意,这里是 执行
pushad
前的ESP值) -
EBP
-
ESI
-
EDI
这样,所有的 8 个通用寄存器的值都被保存到了栈中。
对应的逆操作:
popad:从栈中按相反顺序依次恢复寄存器
VGA寄存器
显卡和显示设备之间的接口,用于控制屏幕显示的各种参数,包括分辨率、颜色深度、刷新率、光标位置等。VGA寄存器是通过特定的端口进行访问的,并分为多个类别,每类寄存器负责不同的功能。
VGA 的寄存器访问需要两个端口:
-
索引端口 (
0x03D4
或0x03B4
):用于选择要访问的寄存器索引。 -
数据端口 (
0x03D5
或0x03B5
):用于读写索引对应的寄存器数据。
0x03D4
是一个常见的地址,在计算机硬件编程中,通常与 VGA(视频图形阵列)控制器的端口有关。它是 VGA寄存器索引端口 的地址。
VGA 寄存器访问概述
VGA 的寄存器访问需要两个端口:
-
索引端口 (
0x03D4
或0x03B4
):用于选择要访问的寄存器索引。 -
数据端口 (
0x03D5
或0x03B5
):用于读写索引对应的寄存器数据。
这两个端口允许程序直接与显卡的寄存器交互,用于控制屏幕显示的各种参数。
端口地址解释
-
0x03D4
和0x03D5
-
用于 彩色模式 下的 VGA 寄存器访问。
-
-
0x03B4
和0x03B5
-
用于 单色模式 下的 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
文章版权归作者所有,未经允许请勿转载。
Paul
完成的打印的部分
主要是打印16进制正数,打印字符,向上滚动,以及光标位置的控制