上次咱们利用BIOS的中断来实现打印字符擦到屏幕,然后用jmp自身这个指令来实现类似while循环这种功能,所以打印字符串之后就无线循环停那儿了,今天我们把他的功能完善一下
显示器,显卡,显存
显示器也属于外设,他要同计算机进行数据交换,那必然需要存在一个IO接口,而负责显示器与计算机的交互的IO接口大家肯定已经耳熟能详,那就是显卡,一般来说显卡需要满足显存的刷新需要,他所运算的速度是十分之高的。显存是显卡内部自行包含的一块存储区域,此时显卡的交换可以不用只限于端口交换,也可以用显存进行数据交换,实际上用显存来实现数据交换更为广泛。
我们能在显示器看见色彩斑斓的图片这是因为显卡可以让显示器工作在图形模式,而我们能在显示器看见那些黑底白字的图片也是因为显卡能让显示器工作在字符模式,这里我们还可以吧他们归纳在一起描述,那就是咱们的显示屏是由一个个极小的像素点来构成的,你在日常生活中看图片是否放的越大就发现图片变成一个一个正方形了呢,没错那就是一个像素块,而咱们计算机也是通过01这种bit串来表示像素快的。
这里举个例子,如果说咱们的像素块是有1bit表示,那么我们的像素块就只有两种情况,要么是0,要么是1,所以也只能表现两种颜色,那么就是黑色和白色,如果说咱们想要多种多样的色彩的话,咱们的像素块就必须使用多个bit进行组合。
这里还得注意的一个点就是使用显卡进行输出的时候,字符得使用ASCII码来进行表示,所以一个字符得占用1个字节(8bit)。在这里为了方便咱们接下来的实际操作,我将显存分布放在下面进行给大家参考:
起始 | 结束 | 大小 | 用途 |
---|---|---|---|
C0000 | C7FFF | 32KB | 显示适配器BIOS |
B8000 | BFFFF | 32KB | 用于文本模式显示适配器 |
B0000 | B7FFF | 32KB | 用于黑白显示适配器 |
A0000 | AFFFF | 64KB | 用于彩色显示适配器 |
显卡支持文本、黑白、彩色显示三种模式,这里我们只需关注文本即可,因为我们需要实现的是类似于Linux的终端操作系统。
由上表可以知道,当地址处于0xB8000到0xBFFFF时,在此输出的数据会直接落到显存之中,显存中有了数据,就相当于到了中间商手中,剩下的作为显示器的客户就可以直接拿到CPU所输出的数据啦。
显卡的文本模式也分多种,其中的差别也就是一页所包含的数据行列不同,也即可容纳的数据大小不同,在默认模式下为80×25(表示一行80个字符,共有25行),也就是一页可以打印2000个字符。
这里需要注意,在文本模式下也可以打印彩色字符,但是ASCII字符都是一字节大小,如何表示彩色字符呢,这里给出答案我们不用一字节来表示字符,而是用两字节,两字节的低8位来使用ASCII码(占7位)正常表示,而高八位则用来表示字符的属性,属性结构图如下:
这里的图片解释的很清楚,RGB大家也应该知道三原色,这里给出几种简单的组合让大家试试:
让MBR支持显卡
抛弃BIOS的输出了,这里使用IO来实现打印功能。
;主引导程序
;
;LOADER_BASE_ADDR equ 0xA000
;LOADER_START_SECTIOR equ 0x2
;------------------------------------------
SECTION MBR vstart=0x7c00 ; 向编译器表示咱们这儿起始地址应为0x7c00
mov ax,cs
mov ds,ax ; 由于BIOS通过 0:0x7c00跳转MBR,所以此时cs为0,因此借他来初始化寄存器
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00
mov ax,0xb800 ;使用文本模式,所以得把文本范围类的地址输入gs当作段基地址
mov gs,ax
;清屏
;利用0x06号子功能,上卷全部行即可清屏
;-------------------------------------------
; INT 0x10 功能号:0x06 功能:上卷窗口
;-------------------------------------------
;输入:
;AH 功能号:0x06
;AL = 上卷行数(若为0则表示全部行,太适合我们辣)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值
mov ax,0x600
mov bx,0x700
mov cx,0 ; 左上角(0,0)
mov dx,0x184f ; 右下角(0x4f,0x18),在VGA文本模式中一行只能容纳80字符
int 0x10
;;;;;;;;;;; 打印字符串 ;;;;;;;;;;;;;;;;
;输出背景色为绿色,前景色为红色且跳动的字符串“Hi,lfh”,注意为小端序
mov byte [gs:0x00], 'H'
mov byte [gs:0x01], 0xA4
mov byte [gs:0x02], 'i'
mov byte [gs:0x03], 0xA4
mov byte [gs:0x04], ','
mov byte [gs:0x05], 0xA4
mov byte [gs:0x06], 'l'
mov byte [gs:0x07], 0xA4
mov byte [gs:0x08], 'f'
mov byte [gs:0x09], 0xA4
mov byte [gs:0x0a], 'h'
mov byte [gs:0x0b], 0xA4
;;;;;;;;;; 打印字符串结束 ;;;;;;;;;;;;;;;
jmp $ ;悬停指针
times 510-($-$$) db 0 ;$-$$表示该指令行距离section起始地址的偏移,这里也可表示为目前指令大小
db 0x55,0xaa
接下来咱们同上篇一样,将修改好的汇编代码进行汇编然后打入咱们的虚拟磁盘,并运行测试
nasm -o mbr.bin mbr.S
dd if=/你的路径/mbr.bin of=/你的路径/bochs/hd60M.img bs=512 count=1 conv=notrunc
bin/bochs -f bochsrc.disk