Skip to content

Commit 7769558

Browse files
committed
add 2024秋冬季开源操作系统训练营第四阶段总结-hbuxiaofei
Signed-off-by: rayylee <[email protected]>
1 parent d678ab9 commit 7769558

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
---
2+
title: 2024秋冬季开源操作系统训练营第四阶段总结-hbuxiaofei
3+
date: 2024-12-21 22:00:35
4+
tags:
5+
---
6+
7+
8+
## x86 架构 hypervisor SeaBIOS 引导与 Linux 启动实现
9+
10+
### 1. seabios 工作流程
11+
```
12+
(1) POST( Power On Self Test):上电自检,BIOS 对计算机硬件(CPU、主板、内存等)的检测。
13+
(2) POST 之后的初始化与启动相关硬件(磁盘、键盘控制器等)。
14+
(3) 为 OS 创建一些参数,如 ACPI、E820 表等。
15+
(4) 选择引导设备,从设备中加载 BootLoader,进而启动操作系统。
16+
```
17+
18+
### 2. qemu 加载seabios过程
19+
```
20+
(1) qemu加载 seabios 在地址的 4G 最顶端的 LOW_MMIO 区,以及低 1M 区域各有一份。
21+
(2) cpu 的第一条取指地址为 0xFFFFFFF0,该地址指向贴近 4G 的 BIOS 的最后 16 个字节,这也是 BIOS 的第一条指令。
22+
(3) BIOS 最后 16 个字节处,是一个长跳转指令,目的就是换到低 1M 段空间去执行 entry_post ( ORG 0xe05b )
23+
```
24+
25+
### 3. kbuild 使用方法
26+
```
27+
参考: https://github.com/Starry-OS/Starry
28+
29+
# To download the tool
30+
$ cargo install kbuild
31+
$ mkdir crates
32+
$ kbuild patch add axstarry
33+
$ kbuild patch remove axstarry
34+
$ kbuild patch list
35+
```
36+
37+
### 4. seabios 编译方法
38+
```
39+
cat > .config << EOF
40+
# for qemu machine types 2.0 + newer
41+
CONFIG_QEMU=y
42+
CONFIG_ROM_SIZE=256
43+
CONFIG_ATA_DMA=n
44+
45+
CONFIG_XEN=n
46+
47+
CONFIG_DEBUG_LEVEL=9
48+
CONFIG_DEBUG_SERIAL=y
49+
EOF
50+
echo "CONFIG_DEBUG_LEVEL=9" >> .config
51+
52+
make PYTHON=python3 oldnoconfig
53+
make
54+
55+
```
56+
57+
### 5. seabios 反汇编
58+
59+
```
60+
objdump -D -b binary -m i8086 bios.bin
61+
objdump -D -b binary -m i8086 romlayout.o
62+
63+
-M intel : 指定intel格式
64+
```
65+
66+
### 6. kvm 中所有 port IO
67+
所谓端口Port IO, x86上使用in out指令进行访问, 和内存的地址空间完全隔离.(ARM上没有PIO) Guest以Linux为例: `cat /proc/ioports`查看当前OS的所有的ioports :
68+
69+
```
70+
0000-0cf7 : PCI Bus 0000:00
71+
0000-001f : dma1
72+
0020-0021 : pic1
73+
0040-0043 : timer0
74+
0050-0053 : timer1
75+
0060-0060 : keyboard
76+
0064-0064 : keyboard
77+
0070-0077 : rtc0
78+
0080-008f : dma page reg
79+
00a0-00a1 : pic2
80+
00c0-00df : dma2
81+
00f0-00ff : fpu
82+
03c0-03df : vga+
83+
03f8-03ff : serial
84+
0510-051b : QEMU0002:00
85+
0510-051b : fw_cfg_io
86+
0600-067f : 0000:00:1f.0
87+
0600-0603 : ACPI PM1a_EVT_BLK
88+
0604-0605 : ACPI PM1a_CNT_BLK
89+
0608-060b : ACPI PM_TMR
90+
0620-062f : ACPI GPE0_BLK
91+
0630-0633 : iTCO_wdt.0.auto
92+
0630-0633 : iTCO_wdt
93+
0660-067f : iTCO_wdt.0.auto
94+
0660-067f : iTCO_wdt
95+
0700-073f : 0000:00:1f.3
96+
0700-073f : i801_smbus
97+
0cf8-0cff : PCI conf1
98+
0d00-ffff : PCI Bus 0000:00
99+
1000-1fff : PCI Bus 0000:01
100+
2000-2fff : PCI Bus 0000:02
101+
3000-3fff : PCI Bus 0000:03
102+
4000-4fff : PCI Bus 0000:04
103+
5000-5fff : PCI Bus 0000:05
104+
6000-6fff : PCI Bus 0000:06
105+
7000-7fff : PCI Bus 0000:07
106+
c040-c05f : 0000:00:1f.2
107+
c040-c05f : ahci
108+
109+
```
110+
111+
### 7. 项目实现总结
112+
113+
项目刚开始, 我把seabios当作 kernel,写了个简单的 bios 来引导 seabios ,seabios成功运行
114+
```asm
115+
.section .text
116+
.code16
117+
.global entry16
118+
entry16:
119+
cli
120+
cld
121+
122+
xor ax, ax
123+
mov ds, ax
124+
mov es, ax
125+
126+
ljmp 0xf000, 0xe05b
127+
```
128+
129+
后面通过学习vmcs的使用方法,增加了CS寄存器的设置后,seabios 可以自启动成功。
130+
```rust
131+
VmcsGuestNW::RIP.write(entry.as_usize() & 0xffff)?;
132+
VmcsGuest16::CS_SELECTOR.write(((entry.as_usize() >> 4) & 0xf000) as u16)?;
133+
// On Intel requires 'base' to be 'selector * 16' in real mode.
134+
VmcsGuestNW::CS_BASE.write(entry.as_usize() & 0xf0000)?;
135+
```
136+
对应的linux.tmol修改为
137+
```toml
138+
cpu_num = 1
139+
phys_cpu_sets = [1]
140+
entry_point = 0xf_e05b
141+
bios_path = "bios-256k.bin"
142+
bios_load_addr = 0xc_0000
143+
kernel_path = "arceos-x86_64.bin"
144+
kernel_load_addr = 0x100_0000
145+
# ramdisk_path = ""
146+
# ramdisk_load_addr = 0
147+
# disk_path = "disk.img"
148+
# Memory regions with format (`base_paddr`, `size`, `flags`).
149+
memory_regions = [
150+
[0x0000_0000, 0x1_0000, 0x13], # IO Port 64K 0b10011
151+
[0x0001_0000, 0x400_0000, 0x7], # Low RAM 64M 0b111
152+
[0xfec0_0000, 0x1000, 0x17], # IO APIC 4K 0b10111
153+
[0xfee0_0000, 0x1000, 0x17], # Local APIC 4K 0b10111
154+
[0xfed0_0000, 0x1000, 0x17], # HPET 4K 0b10111
155+
]
156+
# Emu_devices
157+
# Name Base-Ipa Ipa_len Alloc-Irq Emu-Type EmuConfig
158+
emu_devices = [
159+
]
160+
```
161+
162+
Seabios 加载内核流程,seabios加载内核是通过 fw_cfg 的 file 接口,读取 multiboo.bin 当作 rom 来加载的,这个 multiboo.bin是linux内核封装过的带有 0x55aa 标记的可以引导的 rom,seabios读取到 rom后,加载到内存中然后执行。整理需要实现内容如下(“对号” 为截至此笔记已完成的):
163+
164+
- [x] 1. seabios第一条指令地址为: 0xf000:0xe05b, 支持设置primary vcpu第一条指令地址 entry_point.
165+
166+
167+
```
168+
1. 目前实模式下还不支设置超过0xffff的地址
169+
2. 考虑设置代码段 CS 寄存器
170+
```
171+
172+
- [x] 2. 设置虚拟化需要截获的io端口
173+
174+
```
175+
有些端口需要进行截获, 否则会透传到宿主机, 获取宿主机的信息, 例如pci信息, 内存大小信息等
176+
```
177+
178+
- [ ] 3. dma 实现支持
179+
180+
```
181+
很多数据的传输需要通过 dma 传输
182+
```
183+
184+
185+
- [ ] 4. 实现fw_cfg设备模拟
186+
187+
188+
- [x] fw_cfg 实现 pio, 设备地址 [0x510, 0x511]
189+
```
190+
告诉seabios, 虚拟化环境为 “QEMU”
191+
192+
```
193+
194+
- [ ] fw_cfg 实现 dma, 设备地址 [0x514]
195+
```
196+
用于传输数据, 例如内核data数据等
197+
```
198+
199+
- [x] 5. 实现rtc设备模拟, 设备地址 [0x70, 0x71]
200+
201+
202+
```
203+
在虚拟化环境中, seabios 通过 rtc 几个保留的寄存器获取内存大小信息
204+
```
205+
206+
- [ ] 6. multiboot 实现
207+
208+
```
209+
seabios通过内核启动是通过multiboot协议启动的, 需要将内核文件进行重新封装
210+
```
211+
212+
213+
- [ ] 其他 ...
214+
215+
216+
**修改链接如下:**
217+
218+
https://github.com/hbuxiaofei/arceos-umhv/tree/support-seabios
219+
https://github.com/hbuxiaofei/axvcpu/tree/support-seabios
220+
https://github.com/hbuxiaofei/x86_vcpu/tree/support-seabios
221+
https://github.com/hbuxiaofei/axvm/tree/support-seabios
222+
https://github.com/hbuxiaofei/axdevice/tree/support-seabios
223+
224+
225+
**运行日志:**
226+
```
227+
[ 0.307806 0:2 axvm::vm:230] Booting VM[1]
228+
[ 0.308076 0:2 arceos_vmm::vmm:40] VM[1] boot success
229+
[ 0.308390 0:2 axtask::run_queue:393] task block: Task(2, "main")
230+
[ 0.308757 0:3 axtask::task:471] task drop: Task(4, "")
231+
[ 0.309079 0:3 axtask::run_queue:393] task block: Task(3, "gc")
232+
[ 0.309436 0:5 arceos_vmm::vmm::vcpus:240] VM[1] Vcpu[0] waiting for running
233+
[ 0.309852 0:5 arceos_vmm::vmm::vcpus:243] VM[1] Vcpu[0] running...
234+
[ 0.310227 0:5 x86_vcpu::vmx::vcpu:118] VmxVcpu bind to current processor vmcs @ PA:0x5b2000
235+
[ 0.310751 0:5 axvm::vm:258] >>>>> exit_reason IoWrite {
236+
port: 0x70,
237+
width: Byte,
238+
data: 0x8f,
239+
}
240+
241+
[ 0.311332 0:5 axvm::vm:289] IoWrite: 0x70 Byte 0x8f
242+
[ 0.311646 0:5 axdevice::device:96] emu: GPA:0x70..GPA:0x72 handler write port:GPA:0x70 width:1 val:0x8f
243+
[ 0.312180 0:5 axdevice::rtc:54] Rtc select 0xf
244+
245+
[ 0.312482 0:5 axvm::vm:258] >>>>> exit_reason IoRead {
246+
port: 0x71,
247+
width: Byte,
248+
}
249+
250+
[ 0.312984 0:5 axvm::vm:278] IoRead: 0x71 Byte
251+
[ 0.313268 0:5 axdevice::device:79] emu: GPA:0x70..GPA:0x72 handler read port:GPA:0x71 width:1
252+
[ 0.313758 0:5 axdevice::rtc:81] Rtc read addr: GPA:0x71 GPA:0x71
253+
254+
[ 0.314130 0:5 axdevice::rtc:62] Rtc get index: 0xf
255+
256+
[ 0.314454 0:5 axvm::vm:258] >>>>> exit_reason Nothing
257+
258+
[ 0.314787 0:5 x86_vcpu::vmx::vcpu:131] VmxVcpu unbind from current processor vmcs @ PA:0x5b2000
259+
[ 0.315285 0:5 x86_vcpu::vmx::vcpu:118] VmxVcpu bind to current processor vmcs @ PA:0x5b2000
260+
SeaBIOS (version 1.16.0-20241104_115553-centos83-dev)
261+
BUILD: gcc: (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) binutils: version 2.30-108.el8_5.1
262+
enabling shadow ram
263+
[ 0.316631 0:5 axvm::vm:258] >>>>> exit_reason IoWrite {
264+
port: 0xcf8,
265+
width: Dword,
266+
data: 0x80000000,
267+
}
268+
269+
[ 0.317243 0:5 axvm::vm:289] IoWrite: 0xcf8 Dword 0x80000000
270+
[ 0.317586 0:5 axdevice::device:96] emu: GPA:0xcf8..GPA:0xd00 handler write port:GPA:0xcf8 width:4 val:0x80000000
271+
[ 0.318159 0:5 axdevice::pci:210] >>> axdevice pci write GPA:0xcf8 0x80000000...
272+
273+
[ 0.318592 0:5 axdevice::pci:87] >>> set address 0x0 : device:0x0 : 0x0 : 0x0
274+
275+
[ 0.319020 0:5 axvm::vm:258] >>>>> exit_reason IoRead {
276+
port: 0xcfc,
277+
width: Word,
278+
}
279+
read QEMU_CFG_SIGNATURE 85(U)
280+
Found QEMU fw_cfg
281+
>>> qemu_cfg_read_entry start ...
282+
>>> cfg read qemu_cfg_read over
283+
>>> qemu_cfg_read_entry over ...
284+
QEMU fw_cfg: 956659(0xe98f3) 0x2
285+
QEMU fw_cfg DMA interface supported
286+
>>> qemu_early_e820 call qemu_cfg_read_entry, port:0x19
287+
>>> qemu_cfg_read_entry start ...
288+
>>> cfg read qemu_cfg_dma_transfer 0x6f80 4
289+
>>> dma outl: 0x518 0x806f000000000000
290+
[ 0.508528 0:5 axvm::vm:258] >>>>> exit_reason IoWrite {
291+
port: 0x518,
292+
width: Dword,
293+
data: 0x206f0000,
294+
}
295+
296+
[ 0.509263 0:5 axvm::vm:289] IoWrite: 0x518 Dword 0x206f0000
297+
[ 0.509671 0:5 axdevice::device:96] emu: GPA:0x510..GPA:0x522 handler write port:GPA:0x518 width:4 val:0x206f0000
298+
[ 0.510356 0:5 axdevice::fwcfg:238] >>> do_write GPA:0x518 4 0x206f0000
299+
300+
[ 0.510837 0:5 axdevice::fwcfg:226] dma_write: GPA:0x518 0x206f0000
301+
302+
>>> dma outl over: 0x518 0x806f000000000000
303+
QEMU: Terminated
304+
```
305+
306+
---
307+
308+
**参考文档:**
309+
310+
[SeaBIOS实现简单分析](https://www.cnblogs.com/gnuemacs/p/14287120.html)
311+
[浅度剖析 SeaBIOS 之 QEMU 初始化](https://zhuanlan.zhihu.com/p/678576761)
312+
<<Qemu/kvm源码解析与应用>> - 李强

0 commit comments

Comments
 (0)