2021-03-20 09:47:39 +00:00
|
|
|
# Tutorial 06 - UART Chainloader
|
2019-10-17 07:33:42 +00:00
|
|
|
|
|
|
|
## tl;dr
|
|
|
|
|
2020-10-04 20:27:28 +00:00
|
|
|
- Running from an SD card was a nice experience, but it would be extremely tedious to do it for
|
2021-03-20 08:41:43 +00:00
|
|
|
every new binary. So let's write a [chainloader].
|
2020-10-04 20:27:28 +00:00
|
|
|
- This will be the last binary you need to put on the SD card. Each following tutorial will provide
|
|
|
|
a `chainboot` target in the `Makefile` that lets you conveniently load the kernel over `UART`.
|
2019-10-17 07:33:42 +00:00
|
|
|
|
|
|
|
[chainloader]: https://en.wikipedia.org/wiki/Chain_loading
|
2021-03-20 08:41:43 +00:00
|
|
|
|
2020-03-28 12:26:27 +00:00
|
|
|
|
2020-10-28 15:29:50 +00:00
|
|
|
## Note
|
|
|
|
|
2021-03-20 08:41:43 +00:00
|
|
|
Please note that there is stuff going on in this tutorial that is very hard to grasp by only looking
|
|
|
|
at the source code changes.
|
|
|
|
|
|
|
|
The gist of it is that in `boot.s`, we are writing a piece of [position independent code] which
|
|
|
|
automatically determines where the firmware has loaded the binary (`0x8_0000`), and where it was
|
|
|
|
linked to (`0x200_0000`, see `link.ld`). The binary then copies itself from loaded to linked address
|
|
|
|
(aka "relocating" itself), and then jumps to the relocated version of `_start_rust()`.
|
|
|
|
|
|
|
|
Since the chainloader has put itself "out of the way" now, it can now receive another kernel binary
|
|
|
|
from the `UART` and copy it to the standard load address of the RPi firmware at `0x8_0000`. Finally,
|
|
|
|
it jumps to `0x8_0000` and the newly loaded binary transparently executes as if it had been loaded
|
|
|
|
from SD card all along.
|
2020-10-28 15:29:50 +00:00
|
|
|
|
|
|
|
Please bear with me until I find the time to write it all down here elaborately. For the time being,
|
|
|
|
please see this tutorial as an enabler for a convenience feature that allows booting the following
|
|
|
|
tutorials in a quick manner.
|
|
|
|
|
2021-03-20 08:41:43 +00:00
|
|
|
[position independent code]: https://en.wikipedia.org/wiki/Position-independent_code
|
|
|
|
|
2020-03-28 12:26:27 +00:00
|
|
|
## Install and test it
|
|
|
|
|
|
|
|
Our chainloader is called `MiniLoad` and is inspired by [raspbootin].
|
2019-10-17 07:33:42 +00:00
|
|
|
|
|
|
|
You can try it with this tutorial already:
|
2021-01-23 21:43:59 +00:00
|
|
|
1. Depending on your target hardware, run:`make` or `BSP=rpi4 make`.
|
2021-03-27 19:44:50 +00:00
|
|
|
1. Copy `kernel8.img` to the SD card and put the SD card back into your RPi.
|
2021-01-23 21:43:59 +00:00
|
|
|
1. Run `make chainboot` or `BSP=rpi4 make chainboot`.
|
2020-12-26 22:59:16 +00:00
|
|
|
1. Connect the USB serial to your host PC.
|
|
|
|
- Wiring diagram at [top-level README](../README.md#-usb-serial-output).
|
|
|
|
- Make sure that you **DID NOT** connect the power pin of the USB serial. Only RX/TX and GND.
|
|
|
|
1. Connect the RPi to the (USB) power cable.
|
|
|
|
1. Observe the loader fetching a kernel over `UART`:
|
2019-10-21 20:11:52 +00:00
|
|
|
|
2021-01-23 21:43:59 +00:00
|
|
|
> ❗ **NOTE**: `make chainboot` assumes a default serial device name of `/dev/ttyUSB0`. Depending on
|
|
|
|
> your host operating system, the device name might differ. For example, on `macOS`, it might be
|
|
|
|
> something like `/dev/tty.usbserial-0001`. In this case, please give the name explicitly:
|
|
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
$ DEV_SERIAL=/dev/tty.usbserial-0001 make chainboot
|
|
|
|
```
|
2020-04-11 20:07:59 +00:00
|
|
|
|
2020-03-28 12:26:27 +00:00
|
|
|
[raspbootin]: https://github.com/mrvn/raspbootin
|
|
|
|
|
2019-10-21 20:11:52 +00:00
|
|
|
```console
|
2020-03-28 12:26:27 +00:00
|
|
|
$ make chainboot
|
2019-10-21 20:11:52 +00:00
|
|
|
[...]
|
2020-01-14 19:45:41 +00:00
|
|
|
Minipush 1.0
|
|
|
|
|
|
|
|
[MP] ⏳ Waiting for /dev/ttyUSB0
|
2020-12-26 22:59:16 +00:00
|
|
|
[MP] ✅ Serial connected
|
|
|
|
[MP] 🔌 Please power the target now
|
2019-12-30 23:00:09 +00:00
|
|
|
__ __ _ _ _ _
|
2019-10-21 20:11:52 +00:00
|
|
|
| \/ (_)_ _ (_) | ___ __ _ __| |
|
|
|
|
| |\/| | | ' \| | |__/ _ \/ _` / _` |
|
|
|
|
|_| |_|_|_||_|_|____\___/\__,_\__,_|
|
|
|
|
|
|
|
|
Raspberry Pi 3
|
|
|
|
|
2020-01-14 19:45:41 +00:00
|
|
|
[ML] Requesting binary
|
2020-12-26 22:59:16 +00:00
|
|
|
[MP] ⏩ Pushing 6 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00
|
2019-10-21 20:11:52 +00:00
|
|
|
[ML] Loaded! Executing the payload now
|
|
|
|
|
2021-04-04 20:30:40 +00:00
|
|
|
[0] mingo version 0.5.0
|
|
|
|
[1] Booting on: Raspberry Pi 3
|
|
|
|
[2] Drivers loaded:
|
2020-03-28 12:26:27 +00:00
|
|
|
1. BCM GPIO
|
|
|
|
2. BCM PL011 UART
|
2021-04-04 20:30:40 +00:00
|
|
|
[3] Chars written: 117
|
|
|
|
[4] Echoing input now
|
2019-10-21 20:11:52 +00:00
|
|
|
```
|
2019-10-17 07:33:42 +00:00
|
|
|
|
2021-03-20 08:41:43 +00:00
|
|
|
In this tutorial, a version of the kernel from the previous tutorial is loaded for demo purposes. In
|
|
|
|
subsequent tutorials, it will be the working directory's kernel.
|
2019-10-17 07:33:42 +00:00
|
|
|
|
2019-12-30 23:00:09 +00:00
|
|
|
## Test it
|
2019-10-17 07:33:42 +00:00
|
|
|
|
2021-03-20 08:41:43 +00:00
|
|
|
The `Makefile` in this tutorial has an additional target, `qemuasm`, that lets you nicely observe
|
|
|
|
how the kernel, after relocating itself, jumps the load address region (`0x80_XXX`) to the relocated
|
|
|
|
code at (`0x0200_0XXX`):
|
2019-10-17 07:33:42 +00:00
|
|
|
|
|
|
|
```console
|
2020-03-28 12:26:27 +00:00
|
|
|
$ make qemuasm
|
2019-10-17 07:33:42 +00:00
|
|
|
[...]
|
2021-03-20 08:41:43 +00:00
|
|
|
N:
|
|
|
|
0x00080030: 58000140 ldr x0, #0x80058
|
|
|
|
0x00080034: 9100001f mov sp, x0
|
|
|
|
0x00080038: 58000141 ldr x1, #0x80060
|
|
|
|
0x0008003c: d61f0020 br x1
|
|
|
|
|
|
|
|
----------------
|
2019-10-17 07:33:42 +00:00
|
|
|
IN:
|
2021-03-20 08:41:43 +00:00
|
|
|
0x02000070: 9400044c bl #0x20011a0
|
2019-10-17 07:33:42 +00:00
|
|
|
|
|
|
|
----------------
|
|
|
|
IN:
|
2021-03-20 08:41:43 +00:00
|
|
|
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
|
2019-10-17 07:33:42 +00:00
|
|
|
[...]
|
|
|
|
```
|
|
|
|
|
|
|
|
## Diff to previous
|
2020-03-28 14:42:42 +00:00
|
|
|
```diff
|
2021-04-04 20:30:40 +00:00
|
|
|
|
|
|
|
diff -uNr 05_drivers_gpio_uart/Cargo.toml 06_uart_chainloader/Cargo.toml
|
|
|
|
--- 05_drivers_gpio_uart/Cargo.toml
|
|
|
|
+++ 06_uart_chainloader/Cargo.toml
|
|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
[package]
|
|
|
|
name = "mingo"
|
|
|
|
-version = "0.5.0"
|
|
|
|
+version = "0.6.0"
|
|
|
|
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
|
|
|
|
edition = "2018"
|
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
Binary files 05_drivers_gpio_uart/demo_payload_rpi3.img and 06_uart_chainloader/demo_payload_rpi3.img differ
|
|
|
|
Binary files 05_drivers_gpio_uart/demo_payload_rpi4.img and 06_uart_chainloader/demo_payload_rpi4.img differ
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile
|
|
|
|
--- 05_drivers_gpio_uart/Makefile
|
|
|
|
+++ 06_uart_chainloader/Makefile
|
2021-03-20 08:41:43 +00:00
|
|
|
@@ -25,6 +25,7 @@
|
2021-03-12 22:44:10 +00:00
|
|
|
READELF_BINARY = aarch64-none-elf-readelf
|
2020-04-12 20:22:29 +00:00
|
|
|
LINKER_FILE = src/bsp/raspberrypi/link.ld
|
2021-03-20 08:41:43 +00:00
|
|
|
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
|
2020-04-12 20:22:29 +00:00
|
|
|
+ CHAINBOOT_DEMO_PAYLOAD = demo_payload_rpi3.img
|
2020-03-28 14:42:42 +00:00
|
|
|
else ifeq ($(BSP),rpi4)
|
2020-04-12 20:22:29 +00:00
|
|
|
TARGET = aarch64-unknown-none-softfloat
|
2020-04-16 20:46:11 +00:00
|
|
|
KERNEL_BIN = kernel8.img
|
2021-03-20 08:41:43 +00:00
|
|
|
@@ -36,6 +37,7 @@
|
2021-03-12 22:44:10 +00:00
|
|
|
READELF_BINARY = aarch64-none-elf-readelf
|
2020-04-12 20:22:29 +00:00
|
|
|
LINKER_FILE = src/bsp/raspberrypi/link.ld
|
2021-03-20 08:41:43 +00:00
|
|
|
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72
|
2020-04-12 20:22:29 +00:00
|
|
|
+ CHAINBOOT_DEMO_PAYLOAD = demo_payload_rpi4.img
|
2020-03-28 14:42:42 +00:00
|
|
|
endif
|
|
|
|
|
2020-04-14 21:16:35 +00:00
|
|
|
# Export for build.rs
|
2021-04-29 20:54:57 +00:00
|
|
|
@@ -68,19 +70,22 @@
|
|
|
|
DOCKER_ARG_DEV = --privileged -v /dev:/dev
|
|
|
|
|
|
|
|
DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE)
|
2021-04-29 22:03:55 +00:00
|
|
|
+DOCKER_TEST = $(DOCKER_CMD) -t $(DOCKER_ARG_DIR_UTILS) $(DOCKER_IMAGE)
|
2021-04-29 20:54:57 +00:00
|
|
|
DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE)
|
|
|
|
|
|
|
|
# Dockerize commands that require USB device passthrough only on Linux
|
2020-11-08 22:37:17 +00:00
|
|
|
ifeq ($(UNAME_S),Linux)
|
|
|
|
DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV)
|
|
|
|
|
|
|
|
- DOCKER_MINITERM = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_UTILS) $(DOCKER_IMAGE)
|
2020-04-12 20:22:29 +00:00
|
|
|
+ DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_UTILS) $(DOCKER_IMAGE)
|
2020-11-08 22:37:17 +00:00
|
|
|
endif
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-04-29 20:54:57 +00:00
|
|
|
-EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
|
2020-11-08 22:37:17 +00:00
|
|
|
-EXEC_MINITERM = ruby ../utils/miniterm.rb
|
2021-04-29 20:54:57 +00:00
|
|
|
+EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
|
|
|
|
+EXEC_MINIPUSH = ruby ../utils/minipush.rb
|
|
|
|
+EXEC_QEMU_MINIPUSH = ruby tests/qemu_minipush.rb
|
2020-11-08 22:37:17 +00:00
|
|
|
|
2020-11-08 22:43:56 +00:00
|
|
|
-.PHONY: all $(KERNEL_ELF) $(KERNEL_BIN) doc qemu miniterm clippy clean readelf objdump nm check
|
2020-04-16 20:46:11 +00:00
|
|
|
+.PHONY: all $(KERNEL_ELF) $(KERNEL_BIN) doc qemu qemuasm chainboot clippy clean readelf objdump nm \
|
|
|
|
+ check
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2020-04-16 20:46:11 +00:00
|
|
|
all: $(KERNEL_BIN)
|
|
|
|
|
2021-04-29 20:54:57 +00:00
|
|
|
@@ -96,16 +101,26 @@
|
|
|
|
@$(DOC_CMD) --document-private-items --open
|
|
|
|
|
|
|
|
ifeq ($(QEMU_MACHINE_TYPE),)
|
|
|
|
-qemu:
|
|
|
|
+qemu test:
|
|
|
|
$(call colorecho, "\n$(QEMU_MISSING_STRING)")
|
|
|
|
else
|
2020-04-16 20:46:11 +00:00
|
|
|
qemu: $(KERNEL_BIN)
|
2021-03-12 22:44:10 +00:00
|
|
|
$(call colorecho, "\nLaunching QEMU")
|
2020-04-16 20:46:11 +00:00
|
|
|
@$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
|
2020-03-28 14:42:42 +00:00
|
|
|
+
|
2020-04-16 20:46:11 +00:00
|
|
|
+qemuasm: $(KERNEL_BIN)
|
2021-03-12 22:44:10 +00:00
|
|
|
+ $(call colorecho, "\nLaunching QEMU with ASM output")
|
2020-04-16 20:46:11 +00:00
|
|
|
+ @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -d in_asm
|
2021-04-29 20:54:57 +00:00
|
|
|
+
|
|
|
|
+test: $(KERNEL_BIN)
|
|
|
|
+ $(call colorecho, "\nTesting chainloading - $(BSP)")
|
|
|
|
+ @$(DOCKER_TEST) $(EXEC_QEMU_MINIPUSH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) \
|
|
|
|
+ -kernel $(KERNEL_BIN) $(CHAINBOOT_DEMO_PAYLOAD)
|
|
|
|
+
|
2020-03-28 14:42:42 +00:00
|
|
|
endif
|
|
|
|
|
2020-11-08 22:37:17 +00:00
|
|
|
-miniterm:
|
|
|
|
- @$(DOCKER_MINITERM) $(EXEC_MINITERM) $(DEV_SERIAL)
|
2020-03-28 14:42:42 +00:00
|
|
|
+chainboot:
|
2020-04-11 10:22:52 +00:00
|
|
|
+ @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(CHAINBOOT_DEMO_PAYLOAD)
|
2020-11-08 22:37:17 +00:00
|
|
|
|
2020-03-28 14:42:42 +00:00
|
|
|
clippy:
|
2021-03-12 22:44:10 +00:00
|
|
|
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD)
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s
|
|
|
|
--- 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s
|
|
|
|
+++ 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s
|
2021-03-22 21:54:08 +00:00
|
|
|
@@ -18,6 +18,17 @@
|
|
|
|
add \register, \register, #:lo12:\symbol
|
|
|
|
.endm
|
|
|
|
|
|
|
|
+// Load the address of a symbol into a register, absolute.
|
|
|
|
+//
|
|
|
|
+// # Resources
|
|
|
|
+//
|
|
|
|
+// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html
|
|
|
|
+.macro ADR_ABS register, symbol
|
|
|
|
+ movz \register, #:abs_g2:\symbol
|
|
|
|
+ movk \register, #:abs_g1_nc:\symbol
|
|
|
|
+ movk \register, #:abs_g0_nc:\symbol
|
|
|
|
+.endm
|
|
|
|
+
|
|
|
|
.equ _core_id_mask, 0b11
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-07-02 21:04:18 +00:00
|
|
|
@@ -39,23 +50,35 @@
|
|
|
|
// If execution reaches here, it is the boot core.
|
|
|
|
|
|
|
|
// Initialize DRAM.
|
|
|
|
- ADR_REL x0, __bss_start
|
|
|
|
- ADR_REL x1, __bss_end_exclusive
|
|
|
|
+ ADR_ABS x0, __bss_start
|
|
|
|
+ ADR_ABS x1, __bss_end_exclusive
|
|
|
|
|
|
|
|
bss_init_loop:
|
|
|
|
cmp x0, x1
|
|
|
|
- b.eq prepare_rust
|
|
|
|
+ b.eq relocate_binary
|
|
|
|
stp xzr, xzr, [x0], #16
|
|
|
|
b bss_init_loop
|
2021-03-20 08:41:43 +00:00
|
|
|
|
|
|
|
+ // Next, relocate the binary.
|
2021-07-02 21:04:18 +00:00
|
|
|
+relocate_binary:
|
2021-03-22 21:54:08 +00:00
|
|
|
+ ADR_REL x0, __binary_nonzero_start // The address the binary got loaded to.
|
|
|
|
+ ADR_ABS x1, __binary_nonzero_start // The address the binary was linked to.
|
|
|
|
+ ADR_ABS x2, __binary_nonzero_end_exclusive
|
2020-10-28 22:10:01 +00:00
|
|
|
+
|
2021-07-02 21:04:18 +00:00
|
|
|
+copy_loop:
|
|
|
|
+ ldr x3, [x0], #8
|
2021-03-20 08:41:43 +00:00
|
|
|
+ str x3, [x1], #8
|
|
|
|
+ cmp x1, x2
|
2021-07-02 21:04:18 +00:00
|
|
|
+ b.lo copy_loop
|
|
|
|
+
|
|
|
|
// Prepare the jump to Rust code.
|
|
|
|
-prepare_rust:
|
2021-03-20 08:41:43 +00:00
|
|
|
// Set the stack pointer.
|
2021-03-22 21:54:08 +00:00
|
|
|
- ADR_REL x0, __boot_core_stack_end_exclusive
|
|
|
|
+ ADR_ABS x0, __boot_core_stack_end_exclusive
|
2021-03-20 08:41:43 +00:00
|
|
|
mov sp, x0
|
|
|
|
|
|
|
|
- // Jump to Rust code.
|
|
|
|
- b _start_rust
|
|
|
|
+ // Jump to the relocated Rust code.
|
2021-03-22 21:54:08 +00:00
|
|
|
+ ADR_ABS x1, _start_rust
|
2021-03-20 08:41:43 +00:00
|
|
|
+ br x1
|
|
|
|
|
|
|
|
// Infinitely wait for events (aka "park the core").
|
2021-07-02 21:04:18 +00:00
|
|
|
parking_loop:
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
|
|
|
|
--- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
|
|
|
|
+++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
|
2021-01-04 13:37:17 +00:00
|
|
|
@@ -144,7 +144,7 @@
|
|
|
|
// Make an educated guess for a good delay value (Sequence described in the BCM2837
|
|
|
|
// peripherals PDF).
|
|
|
|
//
|
|
|
|
- // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz.
|
|
|
|
+ // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz.
|
|
|
|
// - The Linux 2837 GPIO driver waits 1 µs between the steps.
|
|
|
|
//
|
|
|
|
// So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs
|
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
|
|
|
|
--- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
|
|
|
|
+++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
|
2021-01-28 22:25:57 +00:00
|
|
|
@@ -279,7 +279,7 @@
|
2020-03-28 14:42:42 +00:00
|
|
|
}
|
|
|
|
|
2021-01-04 13:37:17 +00:00
|
|
|
/// Retrieve a character.
|
|
|
|
- fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option<char> {
|
|
|
|
+ fn read_char(&mut self, blocking_mode: BlockingMode) -> Option<char> {
|
|
|
|
// If RX FIFO is empty,
|
|
|
|
if self.registers.FR.matches_all(FR::RXFE::SET) {
|
|
|
|
// immediately return in non-blocking mode.
|
2021-01-28 22:25:57 +00:00
|
|
|
@@ -294,12 +294,7 @@
|
2021-01-04 13:37:17 +00:00
|
|
|
}
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-01-04 13:37:17 +00:00
|
|
|
// Read one character.
|
|
|
|
- let mut ret = self.registers.DR.get() as u8 as char;
|
2020-03-28 14:42:42 +00:00
|
|
|
-
|
2021-01-04 13:37:17 +00:00
|
|
|
- // Convert carrige return to newline.
|
|
|
|
- if ret == '\r' {
|
|
|
|
- ret = '\n'
|
|
|
|
- }
|
|
|
|
+ let ret = self.registers.DR.get() as u8 as char;
|
|
|
|
|
|
|
|
// Update statistics.
|
|
|
|
self.chars_read += 1;
|
2021-01-28 22:25:57 +00:00
|
|
|
@@ -379,14 +374,14 @@
|
2021-01-04 13:37:17 +00:00
|
|
|
impl console::interface::Read for PL011Uart {
|
|
|
|
fn read_char(&self) -> char {
|
|
|
|
self.inner
|
|
|
|
- .lock(|inner| inner.read_char_converting(BlockingMode::Blocking).unwrap())
|
|
|
|
+ .lock(|inner| inner.read_char(BlockingMode::Blocking).unwrap())
|
|
|
|
}
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-01-04 13:37:17 +00:00
|
|
|
fn clear_rx(&self) {
|
|
|
|
// Read from the RX FIFO until it is indicating empty.
|
|
|
|
while self
|
|
|
|
.inner
|
|
|
|
- .lock(|inner| inner.read_char_converting(BlockingMode::NonBlocking))
|
|
|
|
+ .lock(|inner| inner.read_char(BlockingMode::NonBlocking))
|
|
|
|
.is_some()
|
|
|
|
{}
|
2020-03-28 14:42:42 +00:00
|
|
|
}
|
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/link.ld 06_uart_chainloader/src/bsp/raspberrypi/link.ld
|
|
|
|
--- 05_drivers_gpio_uart/src/bsp/raspberrypi/link.ld
|
|
|
|
+++ 06_uart_chainloader/src/bsp/raspberrypi/link.ld
|
2021-03-20 08:41:43 +00:00
|
|
|
@@ -16,7 +16,8 @@
|
2020-03-28 14:42:42 +00:00
|
|
|
|
|
|
|
SECTIONS
|
|
|
|
{
|
2021-03-16 21:36:06 +00:00
|
|
|
- . = __rpi_load_addr;
|
2020-04-11 09:27:50 +00:00
|
|
|
+ /* Set the link address to 32 MiB */
|
|
|
|
+ . = 0x2000000;
|
2021-03-20 08:41:43 +00:00
|
|
|
/* ^ */
|
|
|
|
/* | stack */
|
|
|
|
/* | growth */
|
|
|
|
@@ -26,6 +27,7 @@
|
2021-03-16 21:36:06 +00:00
|
|
|
/***********************************************************************************************
|
|
|
|
* Code + RO Data + Global Offset Table
|
|
|
|
***********************************************************************************************/
|
2021-03-20 08:41:43 +00:00
|
|
|
+ __binary_nonzero_start = .;
|
2020-03-28 14:42:42 +00:00
|
|
|
.text :
|
|
|
|
{
|
2021-03-16 21:36:06 +00:00
|
|
|
KEEP(*(.text._start))
|
2021-07-02 21:04:18 +00:00
|
|
|
@@ -42,6 +44,10 @@
|
2021-03-20 08:41:43 +00:00
|
|
|
***********************************************************************************************/
|
|
|
|
.data : { *(.data*) } :segment_rw
|
|
|
|
|
2020-03-28 14:42:42 +00:00
|
|
|
+ /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */
|
|
|
|
+ . = ALIGN(8);
|
2021-03-20 08:41:43 +00:00
|
|
|
+ __binary_nonzero_end_exclusive = .;
|
2020-10-29 16:28:33 +00:00
|
|
|
+
|
2021-07-02 21:04:18 +00:00
|
|
|
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
|
|
|
|
.bss : ALIGN(16)
|
2021-03-20 08:41:43 +00:00
|
|
|
{
|
2020-03-28 14:42:42 +00:00
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader/src/bsp/raspberrypi/memory.rs
|
|
|
|
--- 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs
|
|
|
|
+++ 06_uart_chainloader/src/bsp/raspberrypi/memory.rs
|
2021-07-02 21:04:18 +00:00
|
|
|
@@ -11,9 +11,10 @@
|
2021-03-16 21:36:06 +00:00
|
|
|
/// The board's physical memory map.
|
2020-07-30 20:59:24 +00:00
|
|
|
#[rustfmt::skip]
|
|
|
|
pub(super) mod map {
|
2021-03-16 21:36:06 +00:00
|
|
|
+ pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000;
|
2020-09-29 19:43:31 +00:00
|
|
|
|
2020-09-30 19:51:31 +00:00
|
|
|
- pub const GPIO_OFFSET: usize = 0x0020_0000;
|
|
|
|
- pub const UART_OFFSET: usize = 0x0020_1000;
|
2020-09-29 19:43:31 +00:00
|
|
|
+ pub const GPIO_OFFSET: usize = 0x0020_0000;
|
|
|
|
+ pub const UART_OFFSET: usize = 0x0020_1000;
|
|
|
|
|
|
|
|
/// Physical devices.
|
|
|
|
#[cfg(feature = "bsp_rpi3")]
|
2021-07-02 21:04:18 +00:00
|
|
|
@@ -35,3 +36,13 @@
|
|
|
|
pub const PL011_UART_START: usize = START + UART_OFFSET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
+// Public Code
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
+
|
2020-09-29 19:43:31 +00:00
|
|
|
+/// The address on which the Raspberry firmware loads every binary by default.
|
|
|
|
+#[inline(always)]
|
2020-10-28 15:29:50 +00:00
|
|
|
+pub fn board_default_load_addr() -> *const u64 {
|
|
|
|
+ map::BOARD_DEFAULT_LOAD_ADDRESS as _
|
|
|
|
+}
|
2021-01-23 21:43:59 +00:00
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs
|
|
|
|
--- 05_drivers_gpio_uart/src/main.rs
|
|
|
|
+++ 06_uart_chainloader/src/main.rs
|
2021-07-02 21:04:18 +00:00
|
|
|
@@ -105,6 +105,7 @@
|
|
|
|
//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
|
2020-10-28 22:10:01 +00:00
|
|
|
|
2021-04-29 21:08:49 +00:00
|
|
|
#![allow(clippy::upper_case_acronyms)]
|
2020-10-28 22:10:01 +00:00
|
|
|
+#![feature(asm)]
|
2020-11-19 21:53:43 +00:00
|
|
|
#![feature(const_fn_fn_ptr_basics)]
|
2020-10-28 22:10:01 +00:00
|
|
|
#![feature(format_args_nl)]
|
2021-03-20 08:41:43 +00:00
|
|
|
#![feature(global_asm)]
|
2021-07-02 21:04:18 +00:00
|
|
|
@@ -142,38 +143,56 @@
|
2021-03-31 20:48:02 +00:00
|
|
|
kernel_main()
|
|
|
|
}
|
|
|
|
|
|
|
|
+const MINILOAD_LOGO: &str = r#"
|
|
|
|
+ __ __ _ _ _ _
|
|
|
|
+| \/ (_)_ _ (_) | ___ __ _ __| |
|
|
|
|
+| |\/| | | ' \| | |__/ _ \/ _` / _` |
|
|
|
|
+|_| |_|_|_||_|_|____\___/\__,_\__,_|
|
|
|
|
+"#;
|
|
|
|
+
|
|
|
|
/// The main function running after the early init.
|
2020-03-28 14:42:42 +00:00
|
|
|
fn kernel_main() -> ! {
|
2021-01-04 13:37:17 +00:00
|
|
|
use bsp::console::console;
|
2020-03-28 14:42:42 +00:00
|
|
|
use console::interface::All;
|
|
|
|
- use driver::interface::DriverManager;
|
2021-04-04 20:30:40 +00:00
|
|
|
-
|
|
|
|
- println!(
|
|
|
|
- "[0] {} version {}",
|
|
|
|
- env!("CARGO_PKG_NAME"),
|
|
|
|
- env!("CARGO_PKG_VERSION")
|
|
|
|
- );
|
|
|
|
- println!("[1] Booting on: {}", bsp::board_name());
|
|
|
|
-
|
|
|
|
- println!("[2] Drivers loaded:");
|
2021-01-04 13:37:17 +00:00
|
|
|
- for (i, driver) in bsp::driver::driver_manager()
|
|
|
|
- .all_device_drivers()
|
|
|
|
- .iter()
|
|
|
|
- .enumerate()
|
|
|
|
- {
|
|
|
|
- println!(" {}. {}", i + 1, driver.compatible());
|
|
|
|
- }
|
2020-12-26 22:59:16 +00:00
|
|
|
|
|
|
|
- println!(
|
2021-04-04 20:30:40 +00:00
|
|
|
- "[3] Chars written: {}",
|
2020-12-26 22:59:16 +00:00
|
|
|
- bsp::console::console().chars_written()
|
|
|
|
- );
|
2021-04-04 20:30:40 +00:00
|
|
|
- println!("[4] Echoing input now");
|
|
|
|
+ println!("{}", MINILOAD_LOGO);
|
|
|
|
+ println!("{:^37}", bsp::board_name());
|
|
|
|
+ println!();
|
|
|
|
+ println!("[ML] Requesting binary");
|
|
|
|
+ console().flush();
|
2021-01-04 13:37:17 +00:00
|
|
|
|
|
|
|
- // Discard any spurious received characters before going into echo mode.
|
2021-04-04 20:30:40 +00:00
|
|
|
+ // Discard any spurious received characters before starting with the loader protocol.
|
|
|
|
console().clear_rx();
|
2020-12-26 22:59:16 +00:00
|
|
|
- loop {
|
|
|
|
- let c = bsp::console::console().read_char();
|
|
|
|
- bsp::console::console().write_char(c);
|
2021-04-04 20:30:40 +00:00
|
|
|
+
|
|
|
|
+ // Notify `Minipush` to send the binary.
|
|
|
|
+ for _ in 0..3 {
|
|
|
|
+ console().write_char(3 as char);
|
|
|
|
}
|
|
|
|
+
|
2020-03-28 14:42:42 +00:00
|
|
|
+ // Read the binary's size.
|
|
|
|
+ let mut size: u32 = u32::from(console().read_char() as u8);
|
|
|
|
+ size |= u32::from(console().read_char() as u8) << 8;
|
|
|
|
+ size |= u32::from(console().read_char() as u8) << 16;
|
|
|
|
+ size |= u32::from(console().read_char() as u8) << 24;
|
|
|
|
+
|
|
|
|
+ // Trust it's not too big.
|
|
|
|
+ console().write_char('O');
|
|
|
|
+ console().write_char('K');
|
|
|
|
+
|
2020-09-29 19:43:31 +00:00
|
|
|
+ let kernel_addr: *mut u8 = bsp::memory::board_default_load_addr() as *mut u8;
|
2020-03-28 14:42:42 +00:00
|
|
|
+ unsafe {
|
|
|
|
+ // Read the kernel byte by byte.
|
|
|
|
+ for i in 0..size {
|
2020-10-28 15:29:50 +00:00
|
|
|
+ core::ptr::write_volatile(kernel_addr.offset(i as isize), console().read_char() as u8)
|
2020-12-26 22:59:16 +00:00
|
|
|
+ }
|
2021-04-04 20:30:40 +00:00
|
|
|
+ }
|
2020-12-26 22:59:16 +00:00
|
|
|
+
|
2020-03-28 14:42:42 +00:00
|
|
|
+ println!("[ML] Loaded! Executing the payload now\n");
|
|
|
|
+ console().flush();
|
2020-12-26 22:59:16 +00:00
|
|
|
+
|
2021-01-23 21:43:59 +00:00
|
|
|
+ // Use black magic to create a function pointer.
|
2020-10-28 22:10:01 +00:00
|
|
|
+ let kernel: fn() -> ! = unsafe { core::mem::transmute(kernel_addr) };
|
2020-12-26 22:59:16 +00:00
|
|
|
+
|
2020-03-28 14:42:42 +00:00
|
|
|
+ // Jump to loaded kernel!
|
|
|
|
+ kernel()
|
|
|
|
}
|
|
|
|
|
2021-04-29 20:54:57 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/tests/qemu_minipush.rb 06_uart_chainloader/tests/qemu_minipush.rb
|
|
|
|
--- 05_drivers_gpio_uart/tests/qemu_minipush.rb
|
|
|
|
+++ 06_uart_chainloader/tests/qemu_minipush.rb
|
2021-04-29 21:01:22 +00:00
|
|
|
@@ -0,0 +1,80 @@
|
2021-04-29 20:54:57 +00:00
|
|
|
+# frozen_string_literal: true
|
|
|
|
+
|
|
|
|
+# SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
+#
|
|
|
|
+# Copyright (c) 2020-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
+
|
|
|
|
+require_relative '../../utils/minipush'
|
|
|
|
+require 'expect'
|
|
|
|
+require 'timeout'
|
|
|
|
+
|
|
|
|
+# Match for the last print that 'demo_payload_rpiX.img' produces.
|
|
|
|
+EXPECTED_PRINT = 'Echoing input now'
|
|
|
|
+
|
|
|
|
+# The main class
|
|
|
|
+class QEMUMiniPush < MiniPush
|
|
|
|
+ TIMEOUT_SECS = 3
|
|
|
|
+
|
|
|
|
+ # override
|
|
|
|
+ def initialize(qemu_cmd, binary_image_path)
|
|
|
|
+ super(nil, binary_image_path)
|
|
|
|
+
|
|
|
|
+ @qemu_cmd = qemu_cmd
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ private
|
|
|
|
+
|
|
|
|
+ def quit_qemu_graceful
|
|
|
|
+ Timeout.timeout(5) do
|
|
|
|
+ pid = @target_serial.pid
|
|
|
|
+ Process.kill('TERM', pid)
|
|
|
|
+ Process.wait(pid)
|
|
|
|
+ end
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ # override
|
|
|
|
+ def open_serial
|
|
|
|
+ @target_serial = IO.popen(@qemu_cmd, 'r+', err: '/dev/null')
|
|
|
|
+
|
|
|
|
+ # Ensure all output is immediately flushed to the device.
|
|
|
|
+ @target_serial.sync = true
|
|
|
|
+
|
|
|
|
+ puts "[#{@name_short}] ✅ Serial connected"
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ # override
|
|
|
|
+ def terminal
|
|
|
|
+ result = @target_serial.expect(EXPECTED_PRINT, TIMEOUT_SECS)
|
|
|
|
+ exit(1) if result.nil?
|
|
|
|
+
|
|
|
|
+ puts result
|
|
|
|
+
|
|
|
|
+ quit_qemu_graceful
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ # override
|
|
|
|
+ def connetion_reset; end
|
|
|
|
+
|
|
|
|
+ # override
|
|
|
|
+ def handle_reconnect(error)
|
|
|
|
+ handle_unexpected(error)
|
|
|
|
+ end
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+##--------------------------------------------------------------------------------------------------
|
|
|
|
+## Execution starts here
|
|
|
|
+##--------------------------------------------------------------------------------------------------
|
|
|
|
+puts
|
|
|
|
+puts 'QEMUMiniPush 1.0'.cyan
|
|
|
|
+puts
|
|
|
|
+
|
|
|
|
+# CTRL + C handler. Only here to suppress Ruby's default exception print.
|
|
|
|
+trap('INT') do
|
|
|
|
+ # The `ensure` block from `QEMUMiniPush::run` will run after exit, restoring console state.
|
|
|
|
+ exit
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+binary_image_path = ARGV.pop
|
|
|
|
+qemu_cmd = ARGV.join(' ')
|
|
|
|
+
|
|
|
|
+QEMUMiniPush.new(qemu_cmd, binary_image_path).run
|
|
|
|
|
2021-03-20 09:47:39 +00:00
|
|
|
diff -uNr 05_drivers_gpio_uart/update.sh 06_uart_chainloader/update.sh
|
|
|
|
--- 05_drivers_gpio_uart/update.sh
|
|
|
|
+++ 06_uart_chainloader/update.sh
|
2020-12-26 22:59:16 +00:00
|
|
|
@@ -0,0 +1,8 @@
|
|
|
|
+#!/usr/bin/env bash
|
|
|
|
+
|
2021-03-20 09:47:39 +00:00
|
|
|
+cd ../05_drivers_gpio_uart
|
2020-12-26 22:59:16 +00:00
|
|
|
+BSP=rpi4 make
|
2021-03-20 09:47:39 +00:00
|
|
|
+cp kernel8.img ../06_uart_chainloader/demo_payload_rpi4.img
|
2020-12-26 22:59:16 +00:00
|
|
|
+make
|
2021-03-20 09:47:39 +00:00
|
|
|
+cp kernel8.img ../06_uart_chainloader/demo_payload_rpi3.img
|
2020-12-26 22:59:16 +00:00
|
|
|
+rm kernel8.img
|
|
|
|
|
2020-03-28 14:42:42 +00:00
|
|
|
```
|