Skip to content

Commit 9fd529f

Browse files
authored
Translation Chapter 6 (#186)
1 parent daee880 commit 9fd529f

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

06_uart_chainloader/README.CN.md

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# 教程06 - UART链加载器
2+
3+
## tl;dr
4+
5+
- 从SD卡上运行是一次不错的体验,但是每次都为每个新的二进制文件这样做将非常繁琐。
6+
因此,让我们编写一个[chainloader]
7+
- 这将是您需要放在SD卡上的最后一个二进制文件。
8+
每个后续的教程都将在`Makefile`中提供一个`chainboot`,让您方便地通过`UART`加载内核。
9+
10+
[chainloader]: https://en.wikipedia.org/wiki/Chain_loading
11+
12+
13+
## 注意
14+
15+
请注意,这个教程中有一些内容仅通过查看源代码很难理解。
16+
17+
大致的意思是,在`boot.s`中,我们编写了一段[position independent code]代码,
18+
它会自动确定固件加载二进制文件的位置(`0x8_0000`),以及链接到的位置(`0x200_0000`,参见 `kernel.ld`)。
19+
然后,二进制文件将自身从加载地址复制到链接地址(也就是"重定位"自身),然后跳转到`_start_rust()`的重定位版本。
20+
21+
由于链加载程序现在已经"脱离了路径",它现在可以从`UART`接收另一个内核二进制文件,并将其复制到RPi固件的标准加载地址`0x8_0000`
22+
最后,它跳转到`0x8_0000`,新加载的二进制文件会透明地执行,就好像它一直从SD卡加载一样。
23+
24+
在我有时间详细写下这些内容之前,请耐心等待。目前,请将这个教程视为一种便利功能的启用程序,它允许快速启动以下教程。
25+
_对于那些渴望深入了解的人,可以直接跳到第[15章](../15_virtual_mem_part3_precomputed_tables),阅读README的前半部分,
26+
其中讨论了`Load Address != Link Address`的问题_
27+
28+
[position independent code]: https://en.wikipedia.org/wiki/Position-independent_code
29+
30+
## 安装并测试它
31+
32+
我们的链加载程序称为`MiniLoad`,受到了[raspbootin]的启发。
33+
34+
您可以按照以下教程尝试它:
35+
1. 根据您的目标硬件运行命令:`make``BSP=rpi4 make`
36+
1.`kernel8.img`复制到SD卡中,并将SD卡重新插入您的RPi。
37+
1. 运行命令`make chainboot``BSP=rpi4 make chainboot`
38+
1. 将USB串口连接到您的主机PC上。
39+
- 请参考[top-level README](../README.md#-usb-serial-output)中的接线图。
40+
- 确保您**没有**连接USB串口的电源引脚,只连接RX/TX和GND。
41+
1. 将RPi连接到(USB)电源线。
42+
1. 观察加载程序通过`UART`获取内核:
43+
44+
> **注意**: `make chainboot`假设默认的串行设备名称为`/dev/ttyUSB0`。根据您的主机操作系统,设备名称可能会有所不同。
45+
> 例如,在`macOS`上,它可能是类似于`/dev/tty.usbserial-0001`的名称。
46+
> 在这种情况下,请明确给出设备名称:
47+
48+
49+
```console
50+
$ DEV_SERIAL=/dev/tty.usbserial-0001 make chainboot
51+
```
52+
53+
[raspbootin]: https://github.com/mrvn/raspbootin
54+
55+
```console
56+
$ make chainboot
57+
[...]
58+
Minipush 1.0
59+
60+
[MP] ⏳ Waiting for /dev/ttyUSB0
61+
[MP] ✅ Serial connected
62+
[MP] 🔌 Please power the target now
63+
64+
__ __ _ _ _ _
65+
| \/ (_)_ _ (_) | ___ __ _ __| |
66+
| |\/| | | ' \| | |__/ _ \/ _` / _` |
67+
|_| |_|_|_||_|_|____\___/\__,_\__,_|
68+
69+
Raspberry Pi 3
70+
71+
[ML] Requesting binary
72+
[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00
73+
[ML] Loaded! Executing the payload now
74+
75+
[0] mingo version 0.5.0
76+
[1] Booting on: Raspberry Pi 3
77+
[2] Drivers loaded:
78+
1. BCM PL011 UART
79+
2. BCM GPIO
80+
[3] Chars written: 117
81+
[4] Echoing input now
82+
```
83+
84+
在这个教程中,为了演示目的,加载了上一个教程中的内核版本。在后续的教程中,将使用工作目录的内核。
85+
86+
## 测试它
87+
88+
这个教程中的`Makefile`有一个额外的目标`qemuasm`,它可以让你很好地观察到内核在重新定位后如何从加载地址区域(`0x80_XXX`
89+
跳转到重新定位的代码(`0x0200_0XXX`):
90+
91+
```console
92+
$ make qemuasm
93+
[...]
94+
N:
95+
0x00080030: 58000140 ldr x0, #0x80058
96+
0x00080034: 9100001f mov sp, x0
97+
0x00080038: 58000141 ldr x1, #0x80060
98+
0x0008003c: d61f0020 br x1
99+
100+
----------------
101+
IN:
102+
0x02000070: 9400044c bl #0x20011a0
103+
104+
----------------
105+
IN:
106+
0x020011a0: 90000008 adrp x8, #0x2001000
107+
0x020011a4: 90000009 adrp x9, #0x2001000
108+
0x020011a8: f9446508 ldr x8, [x8, #0x8c8]
109+
0x020011ac: f9446929 ldr x9, [x9, #0x8d0]
110+
0x020011b0: eb08013f cmp x9, x8
111+
0x020011b4: 54000109 b.ls #0x20011d4
112+
[...]
113+
```
114+
115+
## 相比之前的变化(diff)
116+
请检查[英文版本](README.md#diff-to-previous),这是最新的。

0 commit comments

Comments
 (0)