操作系统实践-BIOS
- 基本概念: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相关推荐
- MIT6828操作系统实践记录(一)
MIT6828操作系统实践记录(一) 最近经常感受到被大佬碾压,想想自己写了几年代码但对操作系统的理解似乎仍然停留在课本上-OTZ,特开此篇来进行实践.总结.感谢大佬们,大佬们的碾压就是我前进的动力. ...
- 添加简单的linux内核模块,操作系统实践 第12章-添加最简单的Linux内核模块.ppt
操作系统实践 第12章-添加最简单的Linux内核模块.ppt 文档编号:310662 文档页数:16 上传时间: 2018-07-21 文档级别: 文档类型:ppt 文档大小:2.00MB 第12章 ...
- 泛在操作系统实践案例
本文字数:1399字 阅读时间:3 分钟 文章来源:<泛在操作系统实践与展望研究报告> 虽然泛在操作系统的概念是在 2018 年才正式由梅宏院士提出,但是与泛在操作系统相关的研究工作已经有 ...
- 操作系统实践 linux命令期末汇总
操作系统实践 linux命令 Linux 1 简介 linux介绍 GPL linux发行版 linux系统标准化 登入与登出 常用快捷键 补充内容 Linux 2 Shell Shell 环境变量 ...
- Linux操作系统实践——Samba服务器搭建
文章目录 Linux操作系统实践--Samba服务器搭建 一.实验目的 二.实验内容 ② 学生教师服务 三. 题目分析及基本设计过程分析 ② 学生教师服务 1) 整体思路 2) 系统用户和组分配设计说 ...
- TI 实时操作系统SYS/BIOS使用总结
1:概述: SYS/BIOS 是一个可扩展的实时的操作系统.具有非常快速的响应时间(在中断和任务切换时达到较短的延迟),响应时间的确定性,强壮的抢占系统,优化的内存分配和堆栈管理(尽量少的消耗和碎片) ...
- 一步步编写操作系统 08 bios跳转到神奇的内存地址0x7c00
为什么是0x7c00 计算机执行到这份上,bios也即将完成自己的历史使命了,完成之后,它又将睡去.想到这里,心中不免一丝忧伤,甚至有些许挽留它的想法.可是,这就是它的命,它生来被设计成这样,在它短暂 ...
- 【操作系统】BIOS篇
在之前的文章中我们说过,BIOS除了开机自检和加载引导扇区之外,还提供了很多有用的中断程序,这些程序是我们在真正启动操作系统之前的阶段和硬件交互的利器.既然叫基本I/O软件,那么我们就来看看其中比较重 ...
- 计算机从bios到操作系统,高手进!!计算机开机后在进入操作系统前BIOS在进行什么检测工作?...
满意答案 rhthtyyy 2015.09.24 采纳率:51% 等级:5 已帮助:257人 主板(BIOS)启动的顺序 1 .BIOS 的管理内容 BIOS ROM 芯片对于主板的意义就在于全 ...
最新文章
- 《C++面向对象高效编程(第2版)》——3.11 类名、成员函数名、参数类型和文档...
- Django连接数据mysql
- java.util.ResourceBundle使用详解
- (转载)Linux信息资源
- Django----缓存
- Java黑皮书课后题第6章:*6.2(求一个整数各位数字之和)编写一个方法,计算一个整数各位数字之和。使用下面的方法头:public static int sumDigits(long n)
- 论一个程序员的自我修养-从一张图片说起
- python 小说爬虫_从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载
- oracle删除数据释放表空间流程
- IE7下JSON不能有多余的逗号,IE8下创建IMG节点的BUG
- Google 开源下一代高安全性机密运算开发框架 Asylo
- 最短路径之迪杰斯特拉算法
- 多种嵌入式文件系统移植集合
- 机械设备行业经销商管理系统细致化经销商管理,让渠道管理更可控
- Kali Linux 软件源和软件更新(留着自己看)
- 使用浏览器检查工具下载网页视频
- HTML 合并单元格(学生成绩管理表格)
- su的2019面试准备
- EasyUI datagrid editor 中用filebox上传图片失败问题
- pytest-捕获告警信息
热门文章
- matlab 打开xml文件怎么打开方式,导入 XML 文档
- spss pro网络挑战赛A题:人群疏散模拟代码
- 七牛云测试域名过期了,全部图片下载方法
- golang: 密码中允许出现数字、大写字母、小写字母、特殊字符,但至少包含其中2种且长度在8-16之间(四种符号任意满足三种即可)
- 红外成像光电探测器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- 目前使用计算机的内存和外存,简述计算机内存和外存区别及常用外存有哪些
- 这些操作技巧能够让你的公众号迅速增粉
- [HTML5点滴]客户端存储那些事
- 自定义函数处理excel单元格列序数
- 测试工具:adb+perfdog+charles+tidevice+Monkey