搭建操作系统框架,输出hello world
知识点:
CPU的两种运行模式:实模式、保护模式(普遍)
- 操作系统或应用程序运行中用到的都是
真实的物理地址
,这种场景叫做实模式运行
;我们的操作系统刚开机的时候就是运行在实模式下;我们自己写的操作系统也是,先在实模式
下运行,载入内核,然后进入保护模式
。
如何向屏幕输出内容?
- BIOS中断?
- 在实模式下,我们写的OS内核想要访问硬件,就必须借助BIOS中断
实现微内核
运行起来一个简单的框架
重点理解:
- 汇编脚本怎么转换成内核?
- 内核存放在硬盘什么位置?
0
柱面0
磁道1
扇区(512字节 0x200
)- 硬盘哪里来的?
- 怎么写进硬盘?
- 内核如何运行起来?
BIOS
例程读取0
柱面0
磁道1
扇区- 读到
0x7c00
(为什么?) - 执行权限如何给微内核?
具体实现:
- 创建一个内核项目编写boot.asm脚本(使用clion)
;基本框架 [ORG 0x7c00] ;指定想对位置 物理地址 [SECTION .text] ;段 [BITS 16] ;指定16位寄存器 global _start ;声明全全局的开始 _start可以换成别的,但一般这么写 _start: xchg bx, bx ;断点调试 jmp $ times 510 - ($ - $$) db 0 ;times指定重复次数 $: 表示当前地址 $$: 表示当前节(section)的开始地址 db 0x55, 0xaa ;启动扇区的标准签名,表示这是一个有效的启动扇区
(1)使用bximage -q -hd=16 -func=create -sectsize=512 -imgmode=flat hd.img
命令生成hd.img硬盘
`bximage` 是一个用于创建硬盘或软盘映像文件的工具,该工具常用于`Bochs`模拟器。这个模拟器主要用于开发操作系统或运行旧的操作系统。 让我们分解你给出的命令: 1. **bximage**: 这是调用该工具的命令名。 2. **-q**: 这个选项使`bximage`在“快速模式”下运行,意思是它不会询问任何交互式问题,只会基于提供的参数来执行。 3. **-hd=16**: 指定创建的映像文件的大小为16MB。这里的`-hd`表示硬盘映像。 4. **-func=create**: 指定你要执行的功能是创建一个新的映像文件。 5. **-sectsize=512**: 设置每个扇区的大小为512字节。这是一个常见的扇区大小。 6. **-imgmode=flat**: 这指定映像文件的模式为`flat`。在这种模式下,映像文件就是一个简单的连续字节流,没有任何特殊的结构或格式。 7. **hd.img**: 这是你要创建的映像文件的文件名。 总结一下:这个命令告诉`bximage`快速地创建一个16MB的硬盘映像文件,名为`hd.img`,每个扇区大小为512字节,映像模式为`flat`。
(2) 使用nasm boot.asm
命令生成boot.o
文件;内存分布如下:
(3)使用 "dd if=boot of=hd.img bs=512 seek=0 count=1 conv=notrunc"
将内核程序(boot)
写入硬盘(hd.img)
当中;内存图如下:
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/af037a79425b4ba8aeaa596eb549af04.png) `dd` 是一个 Unix/Linux 下的命令行工具,用于在文件之间或者从文件和设备之间复制数据。它可以用于各种数据转换和复制任务,经常用于制作启动盘或拷贝整个硬盘或分区的数据。 让我们详细解释你给出的命令: 1. **dd**: 调用这个命令。 2. **if=boot**: 设置输入文件为`boot`。`if`代表 "input file"。 3. **of=hd.img**: 设置输出文件为`hd.img`。`of`代表 "output file"。 4. **bs=512**: 设置块大小为512字节。`bs`代表 "block size"。这意味着`dd`每次读取和写入512字节。 5. **seek=0**: 开始从输出文件的开始位置写入。`seek`用于指定输出文件中的起始位置。 6. **count=1**: 只复制一个块。因为`bs`是512字节,所以这个命令只会复制512字节。 7. **conv=notrunc**: 不截断输出文件。`conv`用于指定一些转换操作。`notrunc`意味着它不会截断(或者缩短)输出文件。如果输出文件已经存在并且比要复制的数据大,它不会被缩短,只会在指定的位置被新数据覆盖。 综上所述,这个命令的作用是将`boot`文件的前512字节复制到`hd.img`文件的开始位置,而不会截断或者改变`hd.img`文件的其他部分。
(4)利用 bochs
或 qemu
来运行
将命令汇总位makefile
文件:
# 汇总命令执行 BUILD:=./build HD_IMG_NAME:= "hd.img" all: ${BUILD}/boot/boot.o $(shell rm -rf $(HD_IMG_NAME)) bximage -q -hd=16 -func=create -sectsize=512 -imgmode=flat $(HD_IMG_NAME) dd if=${BUILD}/boot/boot.o of=hd.img bs=512 seek=0 count=1 conv=notrunc ${BUILD}/boot/%.o: %.asm $(shell mkdir -p ${BUILD}/boot) nasm $< -o $@ clean: $(shell rm -rf ${BUILD}) bochs: all bochs -q -f bochsrc qemu: all qemu-system-x86_64 -hda hd.img
运行起来的样子:
实战BIOS中断之屏幕输出
;基本框架 [ORG 0x7c00] ;指定想对位置 物理地址 [SECTION .text] ;段 [BITS 16] ;指定16位寄存器 global _start ;声明全全局的开始 _start可以换成别的,但一般这么写 _start: xchg bx, bx ;断点调试 jmp $ times 510 - ($ - $$) db 0 ;times指定重复次数 $: 表示当前地址 $$: 表示当前节(section)的开始地址 db 0x55, 0xaa ;启动扇区的标准签名,表示这是一个有效的启动扇区
输出hello world
[ORG 0x7c00] [SECTION .text] [BITS 16] global _start _start: ; 设置屏幕模式为文本模式,清除屏幕 mov ax, 3 int 0x10 mov si, msg call print jmp $ ; 如何调用 ; mov si, msg ; 1 传入字符串 ; call print ; 2 调用 print: mov ah, 0x0e mov bh, 0 mov bl, 0x01 .loop: mov al, [si] cmp al, 0 jz .done int 0x10 ;利用中断的方式打印出来 inc si jmp .loop .done: ret msg: db "hello, world", 10, 13, 0 times 510 - ($ - $$) db 0 db 0x55, 0xaa;
详细理解:
- 内核如何运行起来?
BIOS
例程读取0
柱面0
磁道1
扇区- 读到
0x7c00
(为什么?) - 执行权限如何给微内核?
实时模式下
,Intel的早期微处理器,例如8086,它确实有20位的地址总线
,这允许它访问1MB的物理内存
(2^20 = 1,048,576字节或1MB);- 考虑哪些内存可以用哪些不能用,参考实时模式下内存布局图。
3.BIOS
启动过程
在实时模式下的内存布局中可以看到在最后16字节
的内容时跳转指令jmp f000:e05b
实时模式下寻址方式为 段:段内偏移
,所有f000 << 4 + e05b = fe05b (真实物理地址)
。
跳转到fe05b
去执行BIOS启动过程
BIOS(Basic Input/Output System)是计算机启动时首先运行的固件。BIOS启动过程是相对固定的,负责初始化和测试系统硬件,然后加载并执行引导加载程序来启动操作系统。以下是BIOS启动过程的简要概述: 1. **上电自检(POST,Power-On Self Test)**:当计算机上电或重启时,BIOS首先执行POST。这是一系列的硬件测试,确保关键组件(如RAM、CPU、键盘和其他设备)功能正常。 2. **硬件初始化**:BIOS将初始化系统的所有硬件设备,包括内存控制器、显示卡、硬盘、光驱等。 3. **设备检查**:BIOS检查连接到计算机的所有设备,例如键盘、鼠标、硬盘、CD/DVD驱动器等。 4. **启动顺序**:根据BIOS设置中定义的启动顺序,BIOS会尝试从各种设备上加载操作系统。例如,通常的启动顺序可能是:光驱、USB驱动器、硬盘。但这可以在BIOS设置中自定义。 5. **引导扇区加载**:当BIOS找到一个有效的启动设备后,它会加载该设备的第一个扇区——称为引导扇区。引导扇区包含引导加载程序的代码,它的任务是开始加载操作系统。 6.**转交控制权限**:一旦引导扇区的内容被加载到内存中,BIOS就将控制权转交给这段代码。这通常发生在物理内存的0x7C00地址处,因为这是BIOS加载引导扇区内容的标准位置。 7. **引导加载程序执行**:引导加载程序接管后,它会继续加载操作系统的其余部分。在某些系统中,例如使用GRUB引导加载程序的Linux系统,用户可能会看到一个菜单,允许他们选择不同的操作系统或配置。 8. **操作系统加载**:引导加载程序加载并执行操作系统。操作系统接管后,它将完成其自己的初始化并最终显示用户界面,等待用户输入。 这只是BIOS启动过程的高级概述。具体的步骤和细节可能因计算机硬件和配置的不同而异。此外,现代计算机上也有一个BIOS的替代者,称为UEFI(统一的可扩展固件接口),它提供了更多的功能和安全性,并支持更大的硬盘驱动器和现代操作系统。
总结
- 创建一个微内核项目,编写
boot.asm
- 使用
nasm boot.asm
命令生成boot.o
文件。
- 如何生成一个硬盘?
- 使用
bximage -q -hd=16 -func=create -sectsize=512 -imgmode=flat hd.img
命令生成。hd.img硬盘
- 如何将内核写入硬盘?
- 使用
"dd if=boot of=hd.img bs=512 seek=0 count=1 conv=notrunc"
将内核程序(boot)
写入硬盘(hd.img)
当中。
- 如何运行起来?
- 利用
bochs
或qemu
来运行 。
- 为什么要读到
0x7c00
位置?
- 查看实时实时模式下内的存布局图可以发现
0x7c00
为BIOS例程
的入口。
- 为什么要调到
0xf000:e05b
处?
BIOS
例程的内存地址