-
-
Notifications
You must be signed in to change notification settings - Fork 816
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
116 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# 教程06 - UART链加载器 | ||
|
||
## tl;dr | ||
|
||
- 从SD卡上运行是一次不错的体验,但是每次都为每个新的二进制文件这样做将非常繁琐。 | ||
因此,让我们编写一个[chainloader]。 | ||
- 这将是您需要放在SD卡上的最后一个二进制文件。 | ||
每个后续的教程都将在`Makefile`中提供一个`chainboot`,让您方便地通过`UART`加载内核。 | ||
|
||
[chainloader]: https://en.wikipedia.org/wiki/Chain_loading | ||
|
||
|
||
## 注意 | ||
|
||
请注意,这个教程中有一些内容仅通过查看源代码很难理解。 | ||
|
||
大致的意思是,在`boot.s`中,我们编写了一段[position independent code]代码, | ||
它会自动确定固件加载二进制文件的位置(`0x8_0000`),以及链接到的位置(`0x200_0000`,参见 `kernel.ld`)。 | ||
然后,二进制文件将自身从加载地址复制到链接地址(也就是"重定位"自身),然后跳转到`_start_rust()`的重定位版本。 | ||
|
||
由于链加载程序现在已经"脱离了路径",它现在可以从`UART`接收另一个内核二进制文件,并将其复制到RPi固件的标准加载地址`0x8_0000`。 | ||
最后,它跳转到`0x8_0000`,新加载的二进制文件会透明地执行,就好像它一直从SD卡加载一样。 | ||
|
||
在我有时间详细写下这些内容之前,请耐心等待。目前,请将这个教程视为一种便利功能的启用程序,它允许快速启动以下教程。 | ||
_对于那些渴望深入了解的人,可以直接跳到第[15章](../15_virtual_mem_part3_precomputed_tables),阅读README的前半部分, | ||
其中讨论了`Load Address != Link Address`的问题_。 | ||
|
||
[position independent code]: https://en.wikipedia.org/wiki/Position-independent_code | ||
|
||
## 安装并测试它 | ||
|
||
我们的链加载程序称为`MiniLoad`,受到了[raspbootin]的启发。 | ||
|
||
您可以按照以下教程尝试它: | ||
1. 根据您的目标硬件运行命令:`make`或`BSP=rpi4 make`。 | ||
1. 将`kernel8.img`复制到SD卡中,并将SD卡重新插入您的RPi。 | ||
1. 运行命令`make chainboot`或`BSP=rpi4 make chainboot`。 | ||
1. 将USB串口连接到您的主机PC上。 | ||
- 请参考[top-level README](../README.md#-usb-serial-output)中的接线图。 | ||
- 确保您**没有**连接USB串口的电源引脚,只连接RX/TX和GND。 | ||
1. 将RPi连接到(USB)电源线。 | ||
1. 观察加载程序通过`UART`获取内核: | ||
|
||
> ❗ **注意**: `make chainboot`假设默认的串行设备名称为`/dev/ttyUSB0`。根据您的主机操作系统,设备名称可能会有所不同。 | ||
> 例如,在`macOS`上,它可能是类似于`/dev/tty.usbserial-0001`的名称。 | ||
> 在这种情况下,请明确给出设备名称: | ||
|
||
```console | ||
$ DEV_SERIAL=/dev/tty.usbserial-0001 make chainboot | ||
``` | ||
|
||
[raspbootin]: https://github.com/mrvn/raspbootin | ||
|
||
```console | ||
$ make chainboot | ||
[...] | ||
Minipush 1.0 | ||
|
||
[MP] ⏳ Waiting for /dev/ttyUSB0 | ||
[MP] ✅ Serial connected | ||
[MP] 🔌 Please power the target now | ||
|
||
__ __ _ _ _ _ | ||
| \/ (_)_ _ (_) | ___ __ _ __| | | ||
| |\/| | | ' \| | |__/ _ \/ _` / _` | | ||
|_| |_|_|_||_|_|____\___/\__,_\__,_| | ||
|
||
Raspberry Pi 3 | ||
|
||
[ML] Requesting binary | ||
[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 | ||
[ML] Loaded! Executing the payload now | ||
|
||
[0] mingo version 0.5.0 | ||
[1] Booting on: Raspberry Pi 3 | ||
[2] Drivers loaded: | ||
1. BCM PL011 UART | ||
2. BCM GPIO | ||
[3] Chars written: 117 | ||
[4] Echoing input now | ||
``` | ||
|
||
在这个教程中,为了演示目的,加载了上一个教程中的内核版本。在后续的教程中,将使用工作目录的内核。 | ||
|
||
## 测试它 | ||
|
||
这个教程中的`Makefile`有一个额外的目标`qemuasm`,它可以让你很好地观察到内核在重新定位后如何从加载地址区域(`0x80_XXX`) | ||
跳转到重新定位的代码(`0x0200_0XXX`): | ||
|
||
```console | ||
$ make qemuasm | ||
[...] | ||
N: | ||
0x00080030: 58000140 ldr x0, #0x80058 | ||
0x00080034: 9100001f mov sp, x0 | ||
0x00080038: 58000141 ldr x1, #0x80060 | ||
0x0008003c: d61f0020 br x1 | ||
|
||
---------------- | ||
IN: | ||
0x02000070: 9400044c bl #0x20011a0 | ||
|
||
---------------- | ||
IN: | ||
0x020011a0: 90000008 adrp x8, #0x2001000 | ||
0x020011a4: 90000009 adrp x9, #0x2001000 | ||
0x020011a8: f9446508 ldr x8, [x8, #0x8c8] | ||
0x020011ac: f9446929 ldr x9, [x9, #0x8d0] | ||
0x020011b0: eb08013f cmp x9, x8 | ||
0x020011b4: 54000109 b.ls #0x20011d4 | ||
[...] | ||
``` | ||
|
||
## 相比之前的变化(diff) | ||
请检查[英文版本](README.md#diff-to-previous),这是最新的。 |