• 基本概念:https://wiki.osdev.org/BIOS
  • 所有中断列表:http://www.ctyme.com/intr/int.htm
  • IBM PC 介绍:http://classiccomputers.info/down/IBM_PS2/documents/PS2_and_PC_BIOS_Interface_Technical_Reference_Apr87.pdf
  • x86 汇编手册:
    • https://www.felixcloutier.com/x86/
    • https://en.wikibooks.org/wiki/X86_Assembly
  • x86 官方文档:https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf

BIOS 固化在主板上,通过中断进行调用,可以进行一些基本操作,例如输出字符串、获取键盘输入等。开机后首先执行 BIOS。

常用的 BIOS 指令

在调用 BIOS 函数之前,需要先设置 AH 或 AX(或 EAX) 寄存器,然后执行对应的 INT 指令。例如 INT 0x13, AH=0 用于重置硬盘或软盘。

INT 0x10 显示类指令

INT 0x10, AH = 1 -- set up the cursor
INT 0x10, AH = 3 -- 获取光标位置
INT 0x10, AH = 0xE -- 显示字符
INT 0x10, AH = 0xF -- get video page and mode
INT 0x10, AH = 0x11 -- set 8x8 font
INT 0x10, AH = 0x12 -- detect EGA/VGA
INT 0x10, AH = 0x13 -- 显示字符串,具体寄存器设置可以参考:http://www.ctyme.com/intr/rb-0210.htm
INT 0x10, AH = 0x1200 -- Alternate print screen
INT 0x10, AH = 0x1201 -- turn off cursor emulation
INT 0x10, AX = 0x4F00 -- video memory size
INT 0x10, AX = 0x4F01 -- VESA get mode information call
INT 0x10, AX = 0x4F02 -- select VESA video modes
INT 0x10, AX = 0x4F0A -- VESA 2.0 protected mode interface

INT 0x13 外存类指令

INT 0x13, AH = 0 -- reset floppy/hard disk
INT 0x13, AH = 2 -- read floppy/hard disk in CHS mode
INT 0x13, AH = 3 -- write floppy/hard disk in CHS mode
INT 0x13, AH = 0x15 -- detect second disk
INT 0x13, AH = 0x41 -- test existence of INT 13 extensions
INT 0x13, AH = 0x42 -- read hard disk in LBA mode
INT 0x13, AH = 0x43 -- write hard disk in LBA mode

INT 0x15 内存类指令

INT 0x12 -- get low memory size
INT 0x15, EAX = 0xE820 -- get complete memory map
INT 0x15, AX = 0xE801 -- get contiguous memory size
INT 0x15, AX = 0xE881 -- get contiguous memory size
INT 0x15, AH = 0x88 -- get contiguous memory sizeINT 0x15, AH = 0xC0 -- Detect MCA bus
INT 0x15, AX = 0x0530 -- Detect APM BIOS
INT 0x15, AH = 0x5300 -- APM detect
INT 0x15, AX = 0x5303 -- APM connect using 32 bit
INT 0x15, AX = 0x5304 -- APM disconnect

INT 0x16 键盘类指令

INT 0x16, AH = 0 -- read keyboard scancode (blocking)
INT 0x16, AH = 1 -- read keyboard scancode (non-blocking)
INT 0x16, AH = 3 -- keyboard repeat rate

示例

基本概念

X86 系列在 16 位实模式下,地址转换格式是:SEG:OFFSET,通过段地址左移4位加上偏移量得到物理地址。例如,0x07c0:0x0000 对应的就是 0x07c0 << 4 + 0x0 = 0x7c00

AT&T 语法中,句点开头的是伪指令。X86 汇编基本语法:

  • .global:声明全局符号,可被其他文件引用
  • .code16:16位模式
  • .equ:定义常量
  • .=:从当前位置对应机器码字节数开始,填充到指定字节数
  • .word:定义一个字
  • ljmp:第一个参数设置 CS 寄存器,第二个参数设置 EIP 寄存器。然后跳转执行。可以清理之前的 CPU 流水线缓存。

MBR 主引导扇区最后一个字节必须是 0xaa,倒数第二个字节必须是 0x55。X86 是小端模式,低字节在低地址。
下面例子在 MBR 的512字节中,显示开机的字符串。
通过 BIOS 显示字符串参考这里:http://www.ctyme.com/intr/rb-0210.htm

示例一:读取并执行磁盘第一个扇区的代码

这个例子把可执行文件中的二进制部分提取到第一个扇区,并在扇区最后两个字节填充 0xaa55,其他地方填0。最终在屏幕上打印字符串。

start.S

.code16
.global _start.equ BOOTSEG, 0x07c0
ljmp $BOOTSEG, $_start_start:mov $0x03, %ahint $0x10mov $BOOTSEG, %axmov %ax, %esmov $_string, %bpmov $0x1301, %axmov $0x0007, %bxmov $9, %cxint $0x10
loop:jmp loop_string:.ascii "hello los".=510signature:.word 0xaa55

Makefile

先用汇编器 as 把汇编代码转为可重定位目标文件,然后通过链接器,根据链接脚本得到 ELF 可执行目标文件。最后,把 ELF 中的二进制部分复制出来即可。

all: start.binstart.bin: start.S start.ldas --32 start.S -o start.old -T start.ld start.o -o start.elfobjcopy -O binary start.elf start.bin.PHONY= clean
clean:rm -f *.o *.bin *.elf

start.ld

在使用 LD 链接器时,通过 -T script_name 指定自定义的链接脚本。通过链接脚本,可以指定每个目标文件的段的信息,例如起始地址,排列顺序等。

  • *(.text):提取所有目标文件的代码段
  • /DISCARD/:要忽略的段
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386)SECTIONS {.text 0x0000 : {*(.text)}/DISCARD/ : {}
}

编译,并通过 QEMU 执行

make
qemu-system-i386 -boot a -fda start.bin

执行成功的话,会在屏幕上看到打印的字符串。

示例二:加载并执行更多扇区的代码

操作系统无法在一个扇区内放下。通常在软盘的第一个扇区放置 IPL(Initial program loader,启动程序加载器)。

BIOS 把第一个扇区的数据加载到内存后,把控制权交给扇区的第一条指令。然后这个扇区负责把操作系统加载到内存并跳转执行(仍然需要借助 BIOS 的函数)。

软盘概念

  • 磁头 header:每个盘面对应一个磁头,上面的是 0 号,下面的是 1 号
  • 柱面 cylinder:每个盘面分成多个同心圆环,每个圆环就是一个柱面,最外层是 0 号,最内层是 79 号,共 80 个
  • 扇区 sector:每个柱面分成 18 个扇区,编号 1-18。每个扇区 512Byte
  • 软盘总容量:2 个磁头 * 80 个柱面 * 18 个扇区 * 512Byte = 1440KB

BIOS 默认加载的是 0 号磁头、0 号柱面、1 号扇区。

x86 实模式的可用地址

x86寄存器分类:

  • 8个通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP
  • 1个标志寄存器:EFLAGS
  • 6个段寄存器:CS、DS、ES、FS、GS、SS
  • 5个控制寄存器:CR0、CR1、CR2、CR3、CR4
  • 8个调试寄存器:DR0、DR1、DR2、DR3、DR4、DR5、DR6、DR7
  • 4个系统地址寄存器:GDTR、IDTR、LDTR、TR
  • 其他寄存器:EIP、TSC等。

其中,通用寄存器在不同模式下可以用的不一样:

32位 16位 8位
EAX AX AH、AL
EBX BX BH、BL
ECX CX CH、CL
EDX DX DH、DL
ESI SI
EDI DI
ESP SP
EBP BP

实模式下通过 ES * 16 + BX 表示地址。因为 ES 和 BX 两个寄存器都是 16bit 的,所以最大可用地址是 1MB。

开机后,BIOS 会把第一个扇区 512B 的内容加载到内存的 0x7c00 地址处,即 0x7c00 ~ 0x7dff。从 0x7d00 开始直到 0x9fbff (1MB 处)都可以给操作系统用。

代码

除了上一个例子的 start.S,还有个 main.S。

start.S

.code16
.global _bootstart.equ BOOTSEG, 0x07c0
ljmp $BOOTSEG, $_bootstart_bootstart:mov $0x03, %ahint $0x10mov $BOOTSEG, %axmov %ax, %esmov $_string, %bpmov $0x1301, %axmov $0x0007, %bxmov $9, %cxint $0x10jmp readDiskreadDisk:mov $0x0800, %axmov %ax, %esmov $0x02, %ahmov $1, %almov $0, %chmov $2, %clmov $0, %dhmov $0, %dlint $0x13jc errorjmp _starterror:
loop:jmp loop_string:.ascii "hello los".=510signature:.word 0xaa55

main.S

.code16.global _start_start:mov $0x06, %ahmov $0, %almov $0, %cxmov $2479, %dxmov $0x07, %bhint $0x10mov $0x03, %ahint $0x10mov $0x800, %axmov %ax, %esmov $_string, %axmov %ax, %bpmov $0x13, %ahmov $0x1, %almov $0, %bhmov $07, %blmov $13, %cxint $0x10osloop:jmp osloop_osstring:.ascii "\n main os boot"

Makefile

COBJS +=
ASOBJS += start.S main.Sall: los.imglos.img: los.elfobjcopy -O binary los.elf los.imglos.elf: *.old -T start.ld %@ -o los.elf%.o: %.Sas -g --32 $(ASOBJS) -o %@.PHONY= clean run
clean:rm -f *.o *.bin *.elfrun:qemu-system-i386 -boot a -fda los.img

start.ld

COBJS +=
ASOBJS += start.S main.Sall: los.imglos.img: los.elfobjcopy -O binary los.elf los.imglos.elf: *.old -T start.ld %@ -o los.elf%.o: %.Sas -g --32 $(ASOBJS) -o %@.PHONY= clean run
clean:rm -f *.o *.bin *.elfrun:qemu-system-i386 -boot a -fda los.img

通过 GDB 配合 QEMU 进行调试

通过 QEMU 启动内核

启动时,必须指定调试参数。此时 QEMU 会等待 GDB 指令。

qemu-system-i386 -s -S -boot a -fda los.img --nographic
  • -S 表示“freeze CPU at start up”
  • -gdb tcp::1234表示启动gdbserver,默认开启

打开 GDB 链接 QEMU

  • 打开 gdb,不带任何参数
  • 关联要调试的内核对应的 elf 文件,注意需要在编译时通过 -g 参数指定调试信息
  • 设置断点
  • 启动
root@osboxes:~# gdb
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
For help, type "help".
Type "apropos word" to search for commands related to "word".(gdb) file  test/x86/bios-disk/los.elf
Reading symbols from test/x86/bios-disk/los.elf...done.(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()(gdb) break _start
Breakpoint 1 at 0x200: file main.S, line 5.(gdb) c
Continuing.
q
^C
Program received signal SIGINT, Interrupt.
loop () at start.S:34
34      jmp loop
  • target remote localhost:1234:连接 QEMU 远程调试
  • break *0x7c00:设置内存地址上的断点

操作系统实践-BIOS相关推荐

  1. MIT6828操作系统实践记录(一)

    MIT6828操作系统实践记录(一) 最近经常感受到被大佬碾压,想想自己写了几年代码但对操作系统的理解似乎仍然停留在课本上-OTZ,特开此篇来进行实践.总结.感谢大佬们,大佬们的碾压就是我前进的动力. ...

  2. 添加简单的linux内核模块,操作系统实践 第12章-添加最简单的Linux内核模块.ppt

    操作系统实践 第12章-添加最简单的Linux内核模块.ppt 文档编号:310662 文档页数:16 上传时间: 2018-07-21 文档级别: 文档类型:ppt 文档大小:2.00MB 第12章 ...

  3. 泛在操作系统实践案例

    本文字数:1399字 阅读时间:3 分钟 文章来源:<泛在操作系统实践与展望研究报告> 虽然泛在操作系统的概念是在 2018 年才正式由梅宏院士提出,但是与泛在操作系统相关的研究工作已经有 ...

  4. 操作系统实践 linux命令期末汇总

    操作系统实践 linux命令 Linux 1 简介 linux介绍 GPL linux发行版 linux系统标准化 登入与登出 常用快捷键 补充内容 Linux 2 Shell Shell 环境变量 ...

  5. Linux操作系统实践——Samba服务器搭建

    文章目录 Linux操作系统实践--Samba服务器搭建 一.实验目的 二.实验内容 ② 学生教师服务 三. 题目分析及基本设计过程分析 ② 学生教师服务 1) 整体思路 2) 系统用户和组分配设计说 ...

  6. TI 实时操作系统SYS/BIOS使用总结

    1:概述: SYS/BIOS 是一个可扩展的实时的操作系统.具有非常快速的响应时间(在中断和任务切换时达到较短的延迟),响应时间的确定性,强壮的抢占系统,优化的内存分配和堆栈管理(尽量少的消耗和碎片) ...

  7. 一步步编写操作系统 08 bios跳转到神奇的内存地址0x7c00

    为什么是0x7c00 计算机执行到这份上,bios也即将完成自己的历史使命了,完成之后,它又将睡去.想到这里,心中不免一丝忧伤,甚至有些许挽留它的想法.可是,这就是它的命,它生来被设计成这样,在它短暂 ...

  8. 【操作系统】BIOS篇

    在之前的文章中我们说过,BIOS除了开机自检和加载引导扇区之外,还提供了很多有用的中断程序,这些程序是我们在真正启动操作系统之前的阶段和硬件交互的利器.既然叫基本I/O软件,那么我们就来看看其中比较重 ...

  9. 计算机从bios到操作系统,高手进!!计算机开机后在进入操作系统前BIOS在进行什么检测工作?...

    满意答案 rhthtyyy 2015.09.24 采纳率:51%    等级:5 已帮助:257人 主板(BIOS)启动的顺序 1 .BIOS 的管理内容 BIOS ROM 芯片对于主板的意义就在于全 ...

最新文章

  1. 《C++面向对象高效编程(第2版)》——3.11 类名、成员函数名、参数类型和文档...
  2. Django连接数据mysql
  3. java.util.ResourceBundle使用详解
  4. (转载)Linux信息资源
  5. Django----缓存
  6. Java黑皮书课后题第6章:*6.2(求一个整数各位数字之和)编写一个方法,计算一个整数各位数字之和。使用下面的方法头:public static int sumDigits(long n)
  7. 论一个程序员的自我修养-从一张图片说起
  8. python 小说爬虫_从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载
  9. oracle删除数据释放表空间流程
  10. IE7下JSON不能有多余的逗号,IE8下创建IMG节点的BUG
  11. Google 开源下一代高安全性机密运算开发框架 Asylo
  12. 最短路径之迪杰斯特拉算法
  13. 多种嵌入式文件系统移植集合
  14. 机械设备行业经销商管理系统细致化经销商管理,让渠道管理更可控
  15. Kali Linux 软件源和软件更新(留着自己看)
  16. 使用浏览器检查工具下载网页视频
  17. HTML 合并单元格(学生成绩管理表格)
  18. su的2019面试准备
  19. EasyUI datagrid editor 中用filebox上传图片失败问题
  20. pytest-捕获告警信息

热门文章

  1. matlab 打开xml文件怎么打开方式,导入 XML 文档
  2. spss pro网络挑战赛A题:人群疏散模拟代码
  3. 七牛云测试域名过期了,全部图片下载方法
  4. golang: 密码中允许出现数字、大写字母、小写字母、特殊字符,但至少包含其中2种且长度在8-16之间(四种符号任意满足三种即可)
  5. 红外成像光电探测器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  6. 目前使用计算机的内存和外存,简述计算机内存和外存区别及常用外存有哪些
  7. 这些操作技巧能够让你的公众号迅速增粉
  8. [HTML5点滴]客户端存储那些事
  9. 自定义函数处理excel单元格列序数
  10. 测试工具:adb+perfdog+charles+tidevice+Monkey