You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.5 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 教程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),这是最新的。