U-Boot porting: Difference between revisions
Dsankouski (talk | contribs) No edit summary |
Dsankouski (talk | contribs) m Add page categories |
||
Line 1: | Line 1: | ||
[[Category:low-level]] | |||
[[Category:guide]] | |||
It is possible to port u-boot on your phone, even if there is no SOC support in uboot tree (because stock bootloader initialized hardware for us). | It is possible to port u-boot on your phone, even if there is no SOC support in uboot tree (because stock bootloader initialized hardware for us). | ||
First thing to focus on should be getting u-boot shell prompt. | First thing to focus on should be getting u-boot shell prompt. |
Revision as of 09:24, 11 October 2020
It is possible to port u-boot on your phone, even if there is no SOC support in uboot tree (because stock bootloader initialized hardware for us).
First thing to focus on should be getting u-boot shell prompt.
Preparation
- Find uboot code
- Before starting uboot porting, you should get access to the stock bootloader uart port. Make sure you can see stock bootloader logs.
- Search uboot code for a uart driver, compatible with your SOC. It is good, if it support debug(i.e. include debug_uart.h)
- Get familiar with you phone RAM map
- Some useful links:
- bring up process
- configuration process
Create basic configuration and build
Add board files
Use guide from Free Electrons pdf or video version
Examples
Configure
U-boot configuration system comes from linux kernel. Put config options not supposed to be changed by user in /include/configs/.*.h
files, in *_defconfig
otherwise
Options, you DO NOT need
- All SPL related options. SPL(Secondary Program Loader) splits u-boot in two parts. You don't need this, since stock bootloader will load whole u-boot image into RAM.
- CONFIG_BOARD_EARLY_INIT_F
Options, you need
- CONFIG_SYS_MALLOC_LEN - size of early C runtime environment heap
- CONFIG_SYS_INIT_SP_ADDR - address of early C runtime environment stack (should in RAM address space, but NOT at the bottom, because stack is growing DOWN. see u-boot readme memory management section)
- CONFIG_SYS_TEXT_BASE - u-boot base address. See instructions below, how to find it.
- CONFIG_DEBUG_UART=y
- CONFIG_DEBUG_UART_SKIP_INIT=y - make sure to comment
_debug_uart_init
function code in you serial driver with that option - CONFIG_DEBUG_UART_BASE=0x13820000 // your uart address from downstream device tree
- CONFIG_LOGLEVEL=8 // log all
Building
Make u-boot
Install arm cross compiler Build:
export CROSS_COMPILE=aarch64-linux-gnu- make <$board_name>_defconfig make
Create android boot image
mkbootimg --base 0x40000000 --kernel_offset 0x00008000 --ramdisk_offset 0x01000000 --tags_offset 0x00000100 --pagesize 2048 --second_offset 0x00f00000 --kernel {path to u-boot.bin} -o {output file}
Replace offsets to your offsets, found from downstream boot.img.
Getting uart debug output
Raw
This may be useful, when no C runtime environment set up yet. You should find uart address to write
C
*(volatile unsigned char *)(0x13820020/*uart register to write characters*/) = 0x48; // print H letter
Assembly
mov x26, #0x20 // move 0x13820020 low 16 bit to x26 register movk x26, #0x1382, lsl #16 // move 0x13820020 high 16 bit to x26 register mov x27, #0x48 // H letter ascii code str x27, [x26] // move H to uart register
Using debug() function
You can get debug output from particular *.c file by adding #define DEBUG
at the top of file, and calling debug("debug output");
where you need.
Finding base address
You should tell u-boot base address, i.e. address in RAM, where stock bootloader load u-boot. Keep in mind, that stock bootloader may ignore offsets, set in boot.img. This section describes, how to find it.
Without the knowledge of base address u-boot will fail on /common/board_f.c
file when calling functions from init_sequence_f
. This is a list of initcall addresses, and if CONFIG_SYS_TEXT_BASE does not match with address u-boot resides, you CPU will jump in wrong address and execute irrelevant code, leaving you with unpredictable uart output and results.
To find u-boot base address, you should dump RAM, where u-boot presumably resides, and find(hex search), at what address uboot image starts.
Enable debug
- put #define DEBUG
at the top of /common/board_f.c
file
Narrow down RAM range u-boot resides in
- read PC(program counter) or LR(link register) at board_init_f function
uint64_t pc; asm volatile ("ADR %0, ." : "=r"(pc) ::); debug("pc reg at board_init_f is: %p", pc);
Here we are reading pc reg from C
Once you have PC register value, u-boot base address 100% in range PC-uboot_size - PC+uboot_size.
How to dump ram
- put ram dump code at the beginning of board_init_f
function.
Ram dump code example:
char *val; val = 0x40001000; // dump start address debug("0x40001000 - 0x40101000 \n"); for(int i=0 ; i < 0x100000 /* dump size*/; i++) { if ((i & 0xf) == 0) {// new line every 16 symbols debug("\n%.8x: ", val + i); // current address stamp } debug("%.2x ", *(val + i)); } debug("\n");
Find uboot start address in dump
Find first few bytes of compiled u-boot image in RAM dump. Result will be u-boot base address.
Creating basic device tree
Will contain node for uart driver, fixed clock and chosen.
a5y17lte device tree example
exynos7880.dtsi:
// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; #include "skeleton.dtsi" / { compatible = "samsung,exynos7880"; fin_pll: xxti { compatible = "fixed-clock"; clock-output-names = "fin_pll"; u-boot,dm-pre-reloc; #clock-cells = <0>; }; uart2: serial@13820000 { compatible = "samsung,exynos4210-uart"; reg = <0x13820000 0x100>; u-boot,dm-pre-reloc; }; };
a5y17lte.dts:
// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; #include "exynos7880.dtsi" / { compatible = "samsung,exynos7880"; aliases { console = &uart2; }; chosen { stdout-path = &uart2; }; }; &fin_pll { clock-frequency = <26000000>; };
Final changes
You may need to comment some serial driver initialization code, as it may not work properly without clock and pinctrl drivers.
Congrats! You should now get a u-boot console prompt!
Testing future u-boot builds
Once you entered in u-boot console, you may upload new u-boot build in RAM via uart and run it
Upload a file into RAM
- on u-boot console:
loadb <address>
. If no address specified, file will be loaded at CONFIG_SYS_LOAD_ADDR - exit u-boot console to release tty device
- install ckermit
- send file:
$kermit kermit> set port /dev/ttyUSB0 kermit> set speed 115200 kermit> set carrier-watch off kermit> set flow-control none kermit> set prefixing all
TODO: Figure out, how to transfer files from picocom with ymodem or xmodem or gkermit |
Run uboot test version
On u-boot console: go <address of loaded file>