用两种方式输出一个字符

来源:互联网 发布:不能说的秘密知乎 编辑:程序博客网 时间:2024/06/15 14:33
上一节虽然我们的引导扇区被BIOS正确识别并引导了,但是在虚拟机中我们看不到任何现象,想想还是很不开心的。那么这一节我们就在屏幕上显示一个字符吧!显示什么字符呢?嗯,就显示‘B’吧(barras的第一个字母)。
方法一:通过BIOS中断
    在《启动篇》中我们已经直到了BIOS有POST(加电自检)的功能,那么这一节我们要学习它的新功能:通过BIOS中断给内核提供服务。在介绍BIOS中断之前,我们先看一下它的官方说明

Operating systems and other software communicates with the BIOS software, in order to control the installed hardware, via software interrupts.A software interrupt is simply an interrupt that is triggered by a software command; therefore,  software interrupt call does not need to know the address of the ISR, only its interrupt number.
操作系统和其他的一些软件为了控制已经安装的硬件,需要通过BIOS软中断和BIOS软件进行交流。软中断通过命令触发。因此,软中断调用不需要直到中断服务程序的地址,仅仅只需要知道中断号即可。

BIOS interrupt calls can be thought of as a mechanism for passing messages between BIOS and the operating system or other BIOS client software. The messages request data or action from BIOS and return the requested data, status information, and/or the product of the requested action to the caller. The messages are broken into categories, each with its own interrupt number, and most categories contain sub-categories, called "functions" and identified by "function numbers". A BIOS client passes most information to BIOS in CPU registers, and receives most information back the same way, but data too large to fit in registers, such as tables of control parameters or disk sector data for disk transfers, is passed by allocating a buffer (i.e. some space) in memory and passing the address of the buffer in registers. The interrupt number is specified as the parameter of the software interrupt instruction (in Intel assembly language, an "INT" instruction), and the function number is specified in the AH register; that is, the caller sets the AH register to the number of the desired In general, the BIOS services corresponding to each interrupt number operate independently of each other, but the functions within one interrupt service are handled by the same BIOS program and are not independent.
BIOS中断调用可以被认为是一种在BIOS和操作系统或其他BIOS客户端软件传递消息的一种机制。BIOS返回给调用者一些数据、状态信息或者是请求动作的结果。消息会通过中断号分类,大多数的类都会被分为若干个子类,我们把这些子类称为“函数”,这些函数通过“函数号”区分开。BIOS客户端通过CPU的寄存器传递大多数的信息给BIOS,同样的也是通过CPU的寄存器获取BIOS返回的信息。但是如果返回的信息太大的话以至于CPU的寄存器装不下,比如说控制参数表或者为磁盘传输磁盘扇区数据,这个时候就要在内存中开辟一块缓冲区然后把缓冲区的地址存放到寄存器中,通过这样来传递消息。中断号被指定为软中断的参数(Intel汇编语言中是INT指令),函数号放在AH寄存器中。也就是说,调用者设置所期望的号码到AH寄存器中,...但是一个中断服务里的各个函数都是通过一个BIOS程序处理的,彼此之间是不独立的。

The BIOS software usually returns to the caller with an error code if not successful, or with a status code and/or requested data if successful. The data itself can be as small as one bit or as large as 65536 bytes of whole raw disk sectors (the maximum that will fit into one real-mode memory segment).
如果调用不成功的话BIOS软中断通常会返回给调用者一个错误码,如果调用成功的话会返回给调用者一个状态码和/或者一个请求的数据。这个数据本身可以像1bit那么小,也可以像整个磁盘扇区的65536bytes那么大(最大由实模式段来决定)。

好了,上面说了这么多,我觉得总结起来就一句话:将中断号作为int指令的参数,如int 0x13,将函数号存入ax寄存器即可调用某个具体的服务。

举个官方给的例子

mov ah, 0x0e      ; function number = 0Eh : Display Character mov al, '!'             ; AL = code of character to display int 0x10                ; call INT 10h, BIOS video service

其中分号是注释,al寄存器存储的是参数,在此表示为要实现的字符。给大家看一部分官方给的BIOS软中断表于是我们就可以完成显示字符‘B’的功能了,只要把上面的代码中的‘!’改成‘B’就可以了。 

我们修改上一节的代码:

xor ax,ax
mov ds,ax
mov es,ax

mov ah, 0x0e      ; function number = 0Eh : Display Character
mov al, 'B'             ; AL = code of character to display
int 0x10                ; call INT 10h, BIOS video service
 
jmp $
 
times 510-($-$$) db 0
db 0x55,0xaa

编译方法:nasm 源文件 -o final.img

然后我们编译,重新运行,就会看到如下结果了:


方法二:直接写显存

在该模式下,显存的起始地址是0xb8000,有25行,每行有80列,如下图所示:



图中的每一个小格子里存放的是要显示的字符,每个要显示的字符用两个字节表示,低字节表示要显示的字符,高字节表示显示的属性。我们知道一个字节由8位组成,其中低4位用来设置前景色,高4位设置背景色。具体的属性表如下:

0 Black 黑色
1 Blue 蓝色
2 Green 绿色
3 Cyan 青色
4 Red 红色
5 Magenta 洋红
6 Brown 棕色
7 Light Gray 高亮灰色
8 Dark Gray 暗灰色
9 Light Blue 高亮蓝色
A Light Green 高亮绿色
B Light Cyan 高亮青色
C Light Red 高亮红色
D Light Magenta 高亮洋红
E Yellow 黄色
F White 白色

举个例子:

我想在第1行第3列的小格子内显示一个字符‘B’,显示属性为高亮样红,该如何做?

先计算第1行第3列的小格子所在的内存地址,因为显存起始地址为0xb8000,而且显示的一个字符占两个字节,所以第1行第3列的小格子所在的内存地址是0xb8000 + (3-1) * 2 = 0xb8004。所以最终的代码如下:

xor ax,axmov ds,axmov es,axmov ax,0xb800mov es,axmov ah,0xd   ;设置显示属性为高亮样红mov al,'B'       ;设置要显示的字符是‘B’mov [es:4],ax   ;设置好后,直接写入显存即可jmp $ times 510-($-$$) db 0db 0x55,0xaa

我们把他保存为bootsect.asm,然后用nasm bootsect.asm -o final.img编译生成final.img文件

然后用虚拟机运行,观察到的结果如下:


好了,这一节我们用两种方法实现了在屏幕上输出一个字符。

详细视频教程见:http://www.duobei.com/course/1574348473

0 0