利用BIOS的硬件信息编程(1)
2016-12-30 23:40
246 查看
1.为什么要有BIOS这个东西
BIOS实际就是ROM里面的一段小程序(芯片总容量大概就是几M),在主板通电时候会硬件加载执行。基本功能就是进行硬件检测,检查没问题就引导bootloader和系统。
为什么需要这个?
第一个原因,即使只有一块主板,什么外部连接的存储介质(磁盘,U盘等存储)都没有(更别说操作系统),这种情况下,一个主板其实也应该能进行一些硬件检查( 甚至是设置),这就是BIOS存在并且嵌入到主板的一个原因。再者,不同主板不一样的硬件配置,对应的bios代码也不一样。不过两个不同bios,对外提供统一的一些统一的操作硬件的接口,他们遵循bios规范【http://blog.chinaunix.net/uid-27033491-id-3239348.html】,以前的操一些操作系统例如DOS就是直接使用bios提供的硬件接口访问硬件,现在的linux访问硬件就是绕过bios访问硬件,下面我们会测试通过bios去访问硬件。
2.bios加载MBR扇区
首先主板通电,硬件自动加载bios程序。bios程序检查硬件,初始化和设置硬件,然后加载磁盘(启动盘)的MBR扇区到0x7c00,然后跳到0x7c00执行。为什么是0x7c00?可以看【http://www.ruanyifeng.com/blog/2015/09/0x7c00.html】。主要是兼容历史的原因。
3.什么是启动扇区?
一个磁盘分为多个磁面,一个磁面一个head(读写磁头),一个磁面多个磁道(track),一个磁道多个扇区(sector),一个扇区512字节。其中0磁头0磁盘第一个扇区称为这个磁盘的第一个扇区。如果这个扇区(512字节)最后两个字节是0xaa55.识别这个扇区是MBR主启动扇区。
现在我们就来测试一下bios去加载MBR扇区的流程。
我们这里使用redhat7.2的qemu虚拟化来做实验最为简单。
首先新建一块1G的虚拟磁盘:
使用已有磁盘新建一台虚拟机,启动虚拟机,查看屏幕输出信息:
现在设置磁盘的第一个扇区为启动扇区MBR.
#vim mbr.asm
编译:nasm mbr.asm -o mbr
这个文件现在我们的磁盘的第一个扇区:
由于qcow2是一个虚拟磁盘文件。我们需要通过nbd把虚拟磁盘文件挂在为真正可以访问的磁盘的。默认centos是没有nbd 安装nbd驱动。
这里需要编译一下内核的nbd驱动:
查看内核版本:
# uname -a
Linux bogon 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
#wget http://vault.centos.org/7.2.1511/os/Source/SPackages/kernel-3.10.0-327.el7.src.rpm
#rpm2cpio kernel-3.10.0-327.el7.src.rpm |cpio -imd
#tar xvf linux-3.10.0-327.el7.tar.xz
增加内核编译选项
重启启动虚拟机,虚拟机的屏幕输出:
这说明bios已经识别到磁盘的MBR分区并且已经把MBR分区加载到了0x7c00地址执行。
3.利用执行MBR扇区的代码实现键盘操作功能。
现在处理器的控制权已经在mbr扇区代码的手里。现在我们就可以通过mbr扇区的代码去控制我们的处理器,进而操作我们的主板。
现在我们就实现键盘的操作功能,其实bios已经有相关的键盘的接口提供。但是我们目前先不用它的接口。我们直接操作我
4000
们的键盘。
目前我的键盘是ps2接口的键盘, 使用的ps2控制器是Intel的8042.
所以我们先链接一下ps2接口,以及连接的电路图。
键盘链接ps2插头:
电脑ps2控制器连接图:
上面两个图整合为一个整体就是:
我们cpu可以控制ps2控制器8042进而控制我们的键盘。所以我们需要了解一下ps2的协议以及8042的芯片资料。其中ps2协议可以了解一下时钟信号和数据信号(电信号)的一些传输协议,当然这些信号我们只需要了解就行,因为这些信号ps2控制器可以帮我们处理,我们只要操作ps2控制器。ps2协议可以自己百度,这里只提供一下数据传输的信号:
电信号采集数据要不就是高电平(二进制1),要不就是低电平(二进制0),上面8个数据刚好可以组成一个字节的数据。控制器就是通过这些信号和键盘进行通信的。当然,这是控制器的工作,我们可以重点不放在这里【有兴趣可以自己百度一下"ps2协议"或者"ps2 protocol"】。我们重点看如何操作ps2控制器。现在我们看一下8042控制器的操作:
这里有一篇不错的介绍文章:http://blog.chinaunix.net/uid-25099259-id-3409632.html
8042控制器的寄存器有四个:状态寄存器,输出缓存控制器,输入缓冲控制器,控制寄存器。我们通过处理器操作端口就可以控制8042寄存器:
关于寄存器的 每一个位的意思,可以看一下这个文章【http://wiki.osdev.org/%228042%22_PS/2_Controller】,里面有详细的寄存器信息介绍,还有如何初始化和使用控制器。我们就参考这边文章来操作的我们的寄存器。由于汇编不好,代码可能写的有点不精简。
开始之前我们需要先要调试工具。例如读取到数据我们如何知道数据是什么?
通过显示是最直观的。显示暂时没有去研究,我们可以直接使用bios提供的显示接口。例如打印0xaa,怎么打印?代码如下
代码写的有点挫,熟悉的人可以修改一下:
有了这个我们就可以打印出控制器端口读出来的数据了。下面开始真正编码操作ps2控制器:
上面就是键盘输入:bear和ctl+alt的扫描码输出。
各个按键的扫描码可以查看:http://wiki.osdev.org/PS/2_Keyboard
BIOS实际就是ROM里面的一段小程序(芯片总容量大概就是几M),在主板通电时候会硬件加载执行。基本功能就是进行硬件检测,检查没问题就引导bootloader和系统。
为什么需要这个?
第一个原因,即使只有一块主板,什么外部连接的存储介质(磁盘,U盘等存储)都没有(更别说操作系统),这种情况下,一个主板其实也应该能进行一些硬件检查( 甚至是设置),这就是BIOS存在并且嵌入到主板的一个原因。再者,不同主板不一样的硬件配置,对应的bios代码也不一样。不过两个不同bios,对外提供统一的一些统一的操作硬件的接口,他们遵循bios规范【http://blog.chinaunix.net/uid-27033491-id-3239348.html】,以前的操一些操作系统例如DOS就是直接使用bios提供的硬件接口访问硬件,现在的linux访问硬件就是绕过bios访问硬件,下面我们会测试通过bios去访问硬件。
2.bios加载MBR扇区
首先主板通电,硬件自动加载bios程序。bios程序检查硬件,初始化和设置硬件,然后加载磁盘(启动盘)的MBR扇区到0x7c00,然后跳到0x7c00执行。为什么是0x7c00?可以看【http://www.ruanyifeng.com/blog/2015/09/0x7c00.html】。主要是兼容历史的原因。
3.什么是启动扇区?
一个磁盘分为多个磁面,一个磁面一个head(读写磁头),一个磁面多个磁道(track),一个磁道多个扇区(sector),一个扇区512字节。其中0磁头0磁盘第一个扇区称为这个磁盘的第一个扇区。如果这个扇区(512字节)最后两个字节是0xaa55.识别这个扇区是MBR主启动扇区。
现在我们就来测试一下bios去加载MBR扇区的流程。
我们这里使用redhat7.2的qemu虚拟化来做实验最为简单。
首先新建一块1G的虚拟磁盘:
qemu-img create -f qcow2 /home/disk.qcow2 2G
使用已有磁盘新建一台虚拟机,启动虚拟机,查看屏幕输出信息:
现在设置磁盘的第一个扇区为启动扇区MBR.
#vim mbr.asm
start: times (510-($-$$)) db 0 ;510字节前面都设置为0,$表示当前地址,$$表示起始地址 dw 0xaa55 ;511和512字节设置为AA55,表示启动扇区
编译:nasm mbr.asm -o mbr
这个文件现在我们的磁盘的第一个扇区:
由于qcow2是一个虚拟磁盘文件。我们需要通过nbd把虚拟磁盘文件挂在为真正可以访问的磁盘的。默认centos是没有nbd 安装nbd驱动。
这里需要编译一下内核的nbd驱动:
查看内核版本:
# uname -a
Linux bogon 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
#wget http://vault.centos.org/7.2.1511/os/Source/SPackages/kernel-3.10.0-327.el7.src.rpm
#rpm2cpio kernel-3.10.0-327.el7.src.rpm |cpio -imd
#tar xvf linux-3.10.0-327.el7.tar.xz
增加内核编译选项
Device Drivers ---> [*] Block devices ---> <M> Network block device support # make #insmod drivers/block/nbd.ko max_part=8 # qemu-nbd -c /dev/nbd0 /home/disk.qcow2 ----------------虚拟磁盘文件挂在为真正的磁盘设备 # dd if=./mbr of=/dev/nbd0 bs=1 count=512 ----------------把上面的程序mbr写入磁盘的头512字节,也就是第一个扇区 #qemu-nbd -d /dev/nbd0
重启启动虚拟机,虚拟机的屏幕输出:
这说明bios已经识别到磁盘的MBR分区并且已经把MBR分区加载到了0x7c00地址执行。
3.利用执行MBR扇区的代码实现键盘操作功能。
现在处理器的控制权已经在mbr扇区代码的手里。现在我们就可以通过mbr扇区的代码去控制我们的处理器,进而操作我们的主板。
现在我们就实现键盘的操作功能,其实bios已经有相关的键盘的接口提供。但是我们目前先不用它的接口。我们直接操作我
4000
们的键盘。
目前我的键盘是ps2接口的键盘, 使用的ps2控制器是Intel的8042.
所以我们先链接一下ps2接口,以及连接的电路图。
键盘链接ps2插头:
电脑ps2控制器连接图:
上面两个图整合为一个整体就是:
我们cpu可以控制ps2控制器8042进而控制我们的键盘。所以我们需要了解一下ps2的协议以及8042的芯片资料。其中ps2协议可以了解一下时钟信号和数据信号(电信号)的一些传输协议,当然这些信号我们只需要了解就行,因为这些信号ps2控制器可以帮我们处理,我们只要操作ps2控制器。ps2协议可以自己百度,这里只提供一下数据传输的信号:
电信号采集数据要不就是高电平(二进制1),要不就是低电平(二进制0),上面8个数据刚好可以组成一个字节的数据。控制器就是通过这些信号和键盘进行通信的。当然,这是控制器的工作,我们可以重点不放在这里【有兴趣可以自己百度一下"ps2协议"或者"ps2 protocol"】。我们重点看如何操作ps2控制器。现在我们看一下8042控制器的操作:
这里有一篇不错的介绍文章:http://blog.chinaunix.net/uid-25099259-id-3409632.html
8042控制器的寄存器有四个:状态寄存器,输出缓存控制器,输入缓冲控制器,控制寄存器。我们通过处理器操作端口就可以控制8042寄存器:
IO Port | Access Type | Purpose |
---|---|---|
0x60 | Read/Write | Data Port |
0x64 | Read | Status Register |
0x64 | Write | Command Register |
开始之前我们需要先要调试工具。例如读取到数据我们如何知道数据是什么?
通过显示是最直观的。显示暂时没有去研究,我们可以直接使用bios提供的显示接口。例如打印0xaa,怎么打印?代码如下
代码写的有点挫,熟悉的人可以修改一下:
start: jmp run tran_ascii:;数字转为对应的ASCII cmp al,9 jle add_30h jmp add_57h add_30h: add al,0x30;eg:0的ASCII 0x30 ret add_57h: add al,0x57;eg:a的ASCII 0x61 ret print_8bit:;dl has data need print,eg:0xAB push ax push bx push cx push dx xor ax,ax ;clear xor bx,bx mov al,dl ;被除数 mov bl,16 ;除数 div bl;AL存储除法操作的商,AH存储除法操作的余数 ;把要打印的数据先保存起来 mov di,need_print stosw ;显示高四位 mov ah,0x09 mov bh,0 ;显示页码 mov cx,1 ;重复输出字符的次数 call tran_ascii int 0x10;功能描述:在当前光标处按指定属性显示字符 ;移动光标到下一处 mov ah,0x03;读取当前光标位置 int 0x10 add dl,1;移动光标到下一处 mov ah,0x02 mov bh,0 int 0x10 ;显示低四位 mov si,need_print lodsw mov al,ah mov ah,0x09 mov cx,1 ; call tran_ascii int 0x10 pop dx pop cx pop bx pop ax ret need_print: DW 0x00 run: mov dl,0x1b call print_8bit times (510-($-$$)) db 0
有了这个我们就可以打印出控制器端口读出来的数据了。下面开始真正编码操作ps2控制器:
start: jmp run ; ;数字转为对应的ASCII tran_ascii: cmp al,9 jle add_30h jmp add_57h add_30h: add al,0x30;eg:0的ASCII 0x30 ret add_57h: add al,0x57;eg:a的ASCII 0x61 ret print_8bit: push ax push bx push cx push dx ;dl has data need print,eg:0xAB xor ax,ax ;clear xor bx,bx mov al,dl ;被除数 mov bl,16 ;除数 div bl;AL存储除法操作的商,AH存储除法操作的余数 ;save mov di,need_print stosw ;移动光标到下一处 mov ah,0x03;读取当前光标位置 int 0x10 add dl,1;移动光标到下一处 mov ah,0x02 mov bh,0 int 0x10 ;显示high四位 mov si,need_print lodsw mov ah,0x09 mov bh,0 ;显示页码 mov cx,1 ;重复输出字符的次数 call tran_ascii int 0x10;功能描述:在当前光标处按指定属性显示字符 ;移动光标到下一处 mov ah,0x03;读取当前光标位置 int 0x10 add dl,1;移动光标到下一处 mov ah,0x02 mov bh,0 int 0x10 ;显示low四位 mov si,need_print lodsw mov al,ah mov ah,0x09 mov cx,1 ; call tran_ascii int 0x10 pop dx pop cx pop bx pop ax ret wait_data: in al,0x64 and al,1b jz wait_data in al,0x60 ret need_print: DW 0x00 run: cli ;Disable Devices mov al,0xad out 0x64,al ;Flush The Output Buffer flush_data: in al,0x64 and al,0x01 jz flush_ok in al,0x60 jmp flush_data flush_ok: ;Set the Controller Configuration Byte mov al,0x20;read configure out 0x64,al in al,0x60 mov dl,al add dl,11101100b;disabled interrupt,use poll mode mov al,0x60;set configure out 0x64,al mov al,dl out 0x60,al ;Perform Controller Self Test mov al,0xaa out 0x64,al call wait_data cmp al,0x55 jne err ;Enable Devices mov al,0xae ;first port for keyboard out 0x64,al test_port_1: mov al,0xAB out 0x64,al call wait_data cmp al,0x00 jne err read_input: call wait_data mov dl,al call print_8bit jmp read_input err: times (510-($-$$)) db 0 dw 0xaa55
上面就是键盘输入:bear和ctl+alt的扫描码输出。
各个按键的扫描码可以查看:http://wiki.osdev.org/PS/2_Keyboard
0x30 | B pressed |
0xB0 | B released |
0x12 | E pressed |
0x92 | E released |
0x1E | A pressed |
0x9E | A released |
0x13 | R pressed |
0x93 | R released |
0x1D | left control pressed |
0x38 | left alt pressed |
0xB8 | left alt released |
0x9D | left control released |
相关文章推荐
- [Windows编程] 利用dxdiag获取用户机器硬件及OS信息
- [Windows编程] 利用dxdiag获取用户机器硬件及OS信息
- [Windows编程] 利用dxdiag获取用户机器硬件及OS信息
- 转:C#编程中如何获得硬件的信息
- 获取PC硬件信息方法一:利用Java Applet
- Atitit.获取主板与bios序列号获取硬件设备信息 Wmi wmic 的作用
- Atitit.获取主板与bios序列号获取硬件设备信息 Wmi wmic 的作用
- Delphi 利用注册表和API取WIN系统下硬件信息
- 利用汇编语言编程实现在屏幕上显示问候信息
- Windows下获取硬件信息的编程(CPU、硬盘、内存和启动时间等)
- 编程实战——电影管理器之利用MediaInfo获取高清视频文件的相关信息
- 利用shell脚本“综合、集中”查看linux server常用软硬件信息 推荐
- 利用EVEREST Corporate Edition网络统计硬件配置信息 推荐
- linux下查看BIOS提供的硬件信息:dmidecode
- WMI获取硬件信息封装函数方法(联想台式机出厂编号 CPUID BIOS序列号 硬盘信息 显卡信息 MAC地址)
- VisualC++利用CRegKey和WIN32 API获取系统硬件信息
- 利用JavaScript获取客户端的硬件信息
- 利用硬件信息实现共享软件的安全注册
- 在VC里实现WMI编程取硬件信息
- 利用WMI获取系统的软硬件信息的学习与总结