深入探究Linux下int86 BIOS操作 (linux int86 bios)

在计算机领域,BIOS(基本输入输出系统)是指固化在计算机主板上的一组程序,用于在计算机启动期间执行硬件初始化和自主检查,以确保计算机硬件能够正常工作。在PC架构中,BIOS通常具有访问低级硬件和设置计算机配置的能力。在Linux操作系统下,我们可以通过int86函数来调用BIOS的功能,从而实现对硬件的访问和配置。

int86函数的定义如下:

“`c

int int86(int intno, union REGS *in, union REGS *out);

“`

其中,intno为BIOS的中断号;in为输入参数的寄存器,包括AX、BX、CX、DX等;out为输出参数的寄存器。

在Linux下使用int86函数需要注意以下几点:

1. int86函数需要使用内核支持的__KERNEL__宏定义来编译,否则会出现编译错误。

2. int86函数的寄存器结构体REGS定义在linux/a/syscalls.h头文件中。

3. 在Linux下,BIOS的中断号需要加上0x80来调用,即INT 0x80。

下面我们将针对常见的BIOS操作进行深入探究。

1.显示字符串

在BIOS中,显示字符串的中断号为0x10,我们可以通过int86函数调用BIOS来显示字符串。

下面是显示字符串的代码实现:

“`c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

typedef unsigned char byte;

typedef unsigned short word;

struct videoinfo {

byte mode;

byte page;

word col;

word row;

byte attr;

byte ch;

};

struct videoinfo SavePara2[2];

struct videoinfo SavePara[1];

int mn()

{

char *str = “Hello World!”; // 要显示的字符串

int str_len = strlen(str); // 字符串长度

__a__ __volatile__(

“movw $0x0003,%%ax\n\t”

“int $0x10\n\t”

:

:

: “%eax”

); // 将显示模式设置为80×25,00为文本模式,02和03为CGA模式

__a__ __volatile__(

“movw $0x0000,%%ax\n\t”

“movw $0x0000,%%bx\n\t”

“movw $0x0007,%%cx\n\t”

“movw $0x0000,%%dx\n\t”

“int $0x10\n\t”

:

:

: “%eax”,”%ebx”,”%ecx”,”%edx”

); // 保存当前显示参数

__a__ __volatile__(

“movw $0x0000,%%ax\n\t”

“movw %%ax,%%es\n\t”

“movw $0x0000,%%bx\n\t”

“movw $0x0000,%%dx\n\t”

“movw %2,%%cx\n\t”

“movw $0x0009,%%ah\n\t”

“int $0x10\n\t”

:

: “a” (0x0e00), “b” (0x0000), “c” (str_len), “d” ((int)str)

:

); // 在文本模式下,将字符串输出到屏幕

__a__ __volatile__(

“movw $0x0000,%%ax\n\t”

“movw $0x0000,%%bx\n\t”

“movw $0x0007,%%cx\n\t”

“movw $0x0000,%%dx\n\t”

“int $0x10\n\t”

:

:

: “%eax”,”%ebx”,”%ecx”,”%edx”

); // 恢复原来的显示参数

}

“`

上述代码中,我们首先将显示模式设置为文本模式(80×25),然后保存当前的显示参数,接着在屏幕上显示字符串,最后恢复原来的显示参数。

2.读写磁盘

BIOS提供了读写磁盘的功能,其中读磁盘操作的中断号为0x13,写磁盘操作的中断号为0x19。

下面是读写磁盘的代码实现:

“`c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

typedef unsigned char byte;

typedef unsigned short word;

struct diskinfo {

byte head;

byte sect_cyl;

byte cyl;

byte sect;

void *buf;

};

struct diskinfo SavePara[1];

struct diskinfo SavePara2[1];

int mn()

{

short count = 1; // 读取扇区的个数

byte sector = 1; // 起始扇区

byte head = 0; // 磁头号

byte cyl = 0; // 柱面号

byte feature = 0x80; // 定义控制字节,指定使用LBA模式

byte read_cmd = 0x42; // 定义读取命令号

byte drive_id = 0x80; // 定义磁盘驱动器号,80h表示0号磁盘驱动器

char buf[512]; // 存放读取到的数据

__a__ __volatile__(

“movw $0x0000,%%bx\n\t”

“movw $0x0000,%%es\n\t”

“movw $0x0000,%%di\n\t”

“int $0x13\n\t”

:

:

:”%eax”,”%ebx”

); // 保存磁盘参数

__a__ __volatile__(

“movw $0x0000,%%di\n\t”

“movw $0x0000,%%es\n\t”

“movw $0x0000,%%bx\n\t”

“movw %4,%%cx\n\t”

“movb %3,%%cl\n\t”

“movb %2,%%dh\n\t”

“movb %1,%%ch\n\t”

“movb %0,%%ah\n\t”

“movb %5,%%dl\n\t”

“int $0x13\n\t”

:

:”m”(read_cmd), “m”(feature),”m”(head),”m”(sector),”m”(count),”m”(drive_id),”d”((int)buf)

:”%eax”,”%ebx”

); // 读取磁盘

__a__ __volatile__(

“movw $0x0000,%%bx\n\t”

“movw $0x0000,%%es\n\t”

“movw $0x0000,%%di\n\t”

“int $0x13\n\t”

:

:

:”%eax”,”%ebx”

); // 恢复原来的磁盘参数

}

“`

上述代码中,我们首先保存当前的磁盘参数,然后通过int86函数调用BIOS,读取指定位置的磁盘数据,最后恢复原来的磁盘参数。

3.设置中断向量

BIOS为每个中断提供了一个中断向量,其中每个中断向量的寻址方式为中断号*4,比如中断号为0x10,那么对应的中断向量地址就是0x40。

下面是设置中断向量的代码实现:

“`c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

typedef unsigned char byte;

typedef unsigned short word;

void set_intvect(byte intno, void (*handler)(void));

void int_timer(void);

void set_intvect(byte intno, void (*handler)(void))

{

word offset = (word)handler; // 中断处理程序的段内偏移

word segment = (word)handler >> 16; // 中断处理程序的段地址

*(word *)(intno * 4) = offset;

*(word *)(intno * 4 + 2) = segment; // 设置中断向量

}

void int_timer(void)

{

printf(“Timer Interrupt!\n”);

__a__ __volatile__(

“pushl %eax\n\t”

“pushl %ebx\n\t”

“movw $0x0028,%%ax\n\t”

“movw %%ax,%%ds\n\t”

“movw %%ax,%%es\n\t”

“movw $0x0000,%%bx\n\t”

“movb $0x20,%%al\n\t”

“outb %%al,$0x20\n\t”

“popl %ebx\n\t”

“popl %eax\n\t”

“iret\n\t”

:

:

:

); // 定义中断处理程序

}

int mn()

{

set_intvect(0x08, int_timer); // 设置中断向量

while(1)

{

__a__ __volatile__(

“hlt\n\t”

:

:

:

); // 等待中断

}

}

“`

上述代码中,我们首先定义了一个中断处理程序,用于处理时钟中断。然后通过set_intvect函数设置中断向量,即将中断号为0x08的中断向量设置为int_timer函数。最后我们无限循环等待时钟中断的到来,以确保中断处理程序能够被正确地执行。

相关问题拓展阅读:

可以通过BIOS把显示模式改为VGA图形模式吗

可以。中断10H,即Video BIOS,负责处理文本模式和图形模式之间的转换。当你所运行的程序要进行文本模式和图形模式之间的相互转换时(即使该程序是Microsoft Windows),就需要通过Video BIOS来实现这种转换。每一种不同的设置都被称作一种显示模式。

要改变显示模式,你必须通过int 10H服务来调用Video BIOS。这就是说,你必须向中断10H的中断处理程序发出中断请求。除中断号不同之外,这与实现DOS调用(int 21H)没有什么区别。下面的一段程序通过调用Video BIOS函数0,先从标准文本模式(模式3)切换到一个由命令行输入的模式号,然后再切换回来:

# include

# include

main(int argc, char * * argv)

{

union REGS regs;

int mode;

/ * accept Mode number in hex * /

sscanf (argv , ” %x” , &mode) ;

regs. h. ah = 0;/* AH = 0 means “change display mode” */

regs.h.al = (char)mode; /* AL = ??, where ?? is the Mode number *

regs. x. bx = 0;/* Page number, usually zero */

int86(0xl0, ®s, ®s); /* Call the BIOS (intlO) * /

printf(“Mode 0x%X now active\n” , mode);

printf (“Press any key to return. . . “) ;

getch();

regs. h. al = 3;/ * return to Mode 3 * /

int86(0xl0, ®s, ®s);

}

有一个有趣的特点并没有在这个程序中表现出来,即该程序可以在不清屏的情况下改变显示模式。在某些场合,这一特点极为有用。要想改变显示模式,而又不影响屏幕内容,只需把存放在AI.寄存器中的显示模式值和80H或一下。例如,如果你要切换到模式13H,你只需把93H存入AL中,而程序中其余的代码可以保持不变。

今天,在VESA Video BIOS标准中已经加入了VGA卡对扩充显示模式(见下文中的补充说明)的支持。然而,需要有一个新的“改变显示模式”函数来支持这些扩充模式。按照VESA标准,在切换VESA模式时,应该使用函数4FH,而不是前文例子中的函数O。下面的程序改进了前文中的例子,以切换VESA模式:

# include

#include

main(int argc, char * * argv)

{

union REGS regs;

int mode;

/ * accept Mode number in hex * /

sscanf (argv, ” %x” , &mode);

regs. x. ax = 0x4F02;/* change display mode * /

regs. x. bx = (short )mode; / * three-digit mode number * /

int86(0x10, ®s, ®s); /* Call the BIOS (intlO) * /

if(regs.h.al !=0x4F){

printf(“VESA modes NOT supported! \n” );

}

else {

printf(“Mode Ox%X now active\n” , mode);

printf (“Press any key to return. . . ” ) ;

getch() ;

}

regs. h. al = 3;/ * return to Mode 3 * /

int86(0x10,®s, ®s) ;

}

注意,在切换VESA模式时,不能通过把模式号和80H或一下来达到不清屏的目的。但是。只要把原来两位的(十六进制)模式号的更高位往前移一位,就得到了VESA模式号(所有VESA模式号的长度都是三位(十六进制),见下文中的补充说明)。因此,为了切换到VESA模式101H并且保留屏幕上的内容,你只需把VESA模式号换为901H。

关于显示模式的补充说明:

IBM推出了一种显示模式标准,该标准试图定义所有可能会用到的显示模式,其中包括所有可能的像素层次(颜色的数目)。因此,IBM创建了19种显示模式(从OH到13H)。表14.8a给出了这种显示模式标准。

14.8a 标准显示模式

模式(H)分辨率图形/文本颜色

X 文本 单色

X 文本 16

X 文本 单色

X 文本 16

X 图形 4

X 图形 4级灰度

X 图形 单色

X 文本 单色

X 图形 16

X 图形 16

Ax图形 4

B 保留给EC-A BIOS使用

C 保留给EGA BIOS使用

D×图形 16

E×图形 16

F×图形 单色

×图形 4

×图形 单色

×图形 16

×图形 256

那么,你见过其中的某些模式吗?模式3是80×25彩色文本模式,也就是PC机上电时你所看到的模式。当你把”VGA”(随Windows提供的一个驱动程序)选为Microsoft Windows3.x的驱动程序时,你所看到的就是模式12(H)。注意,上表中并没有一种颜色多于256色或分辨率高于640×480的模式。多年以来,模式4,9和D一直是DOS游戏开发者喜欢用的模式,它们拥有“高”达320×200的分辨率和足够的颜色(4或16种),足以显示一些“象样”的图形。所有流行的动画游戏几乎都使用模式13,例如DOOM(一代和二代),id软件公司的new Heretic,Apogee公司的Rise of the Triad,Interplay公司的Descent,等等。实际上,许多动画游戏在VGA卡上耍了个小花招,即把模式13的分辨率改为320×这种模式被称为模式x,它有更多的内存页。可以提高图形质量和显示速度。

那么,其它一些常见的显示模式又是从哪里来的呢?它们是由VGA卡的制造商提供的。这些你可能已经熟悉的显示模式来自各种各样的渠道,但不管它们来自何处,VGA卡的制造商们都把它们加到了自己的VGA卡中,以增加这些VGA卡的价值。这些模式通常被称为扩充显示模式(extended display mode)。由于竞争和资本积累的原因,VGA卡的制造商们逐步转向了这些更高级的显示模式。有人还试过其它一些显示模式(听说过1152×900吗?),但并不象上述模式那样受欢迎。

那么。什么是VESA呢?它与VGA卡有什么关系呢?尽管VGA卡的制造商们都选择了支持同样的一组显示模式(包括扩充模式),但他们都按自己的专用方式去实现其中的扩充模式,而游戏厂商和其它软件厂商不得不去支持市场上每一种VGA卡的每一种专用方式。因此,一些制造商和其它方面的一些代表一起组成了一个委员会,以尽可能地使这些卡的设置和编程标准化,这个委员会就是VESA(Video Electronic Standards Association)。VESA委员会采用了一种扩充显示模式的标准,从而使软件可以通过普通的BIOS调用来设置和初始化所有符合该标准的VGA卡。基本上可以这样说,在美国出售的所有的VGA卡都支持某种VESA标准。

所有的VESA模式(即VESA标准所包含的那些显示模式)都采用宽度为9位(bit)的模式号,而不是标准模式的8位(hit)模式号。使用了9位(bit)的模式号后,就可以用三位十六进制数来表示VESA模式了,而IBM标准模式只能用两位十六进制数(在表14.8a中,从0到13H)来表示,这样就避免了模式号的冲突。因此,所有的VESA模式号都大于100H。VESA模式是这样起作用的:假设你想让你的VGA卡以1024×768和256色这样的模式显示,而这种模式就是VESA模式105,因此你要用模式号105作一次BIOS调用。Video BIOS(有时叫做VESA BIOS)会把VESA模式号翻译成内部专用号,以完成实际的模式切换工作。VGA卡的制造商们在每一块VGA卡上都提供了一种可以完成上述翻译工作的Video BIOS,因此你只需要搞清楚VESA模式号就行了。表14.8b列出了最新的VESA显示模式(VESA是一个不断发展的标准。)

表14.8b VESA显示模式

——

分辨率 颜色VESA模式

——

640X 100

640X 101

640X 110

640X 111

640X 16. 7M

800X 102

800X 103

800X 113

800X 114

800X 16. 7M

1024X 104

1024X 105

1024X 116

1024X 117

1024X 16. 7M

1280X 106

1280X 107

1280X 119

1280X 11A

1280X 16. 7MB

linux int86 bios的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux int86 bios,深入探究Linux下int86 BIOS操作,可以通过BIOS把显示模式改为VGA图形模式吗的信息别忘了在本站进行查找喔。


数据运维技术 » 深入探究Linux下int86 BIOS操作 (linux int86 bios)