深入探究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函数。最后我们无限循环等待时钟中断的到来,以确保中断处理程序能够被正确地执行。


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