前言
在使用 uboot 升级的时候,有个疑问:
通过 tftp 下载的 bin 文件,我该暂存在哪段内存空间?换句话说,哪段内存空间可供我存放临时数据?
带着这个疑问,开启今天的 uboot 和 内存地址 研究之旅。
环境
硬件:OrangePi PC(H3)
bdinfo
在 uboot 命令行中,使用 bdinfo 命令查看板子信息
=> bdinfo
boot_params = 0x40000100
DRAM bank = 0x00000000
-> start = 0x40000000
-> size = 0x40000000
memstart = 0x40000000
memsize = 0x40000000
flashstart = 0x00000000
flashsize = 0x00000000
flashoffset = 0x00000000
baudrate = 115200 bps
relocaddr = 0x7df96000
reloc off = 0x33f96000
Build = 32-bit
current eth = ethernet@1c30000
ethaddr = 02:81:e6:56:d9:1f
IP addr = <NULL>
fdt_blob = 0x79f6ef30
new_fdt = 0x79f6ef30
fdt_size = 0x00006fa0
FB base = 0x7e000000
lmb_dump_all:
memory.cnt = 0x1
memory.size = 0x0
memory.reg[0x0].base = 0x40000000
.size = 0x40000000
reserved.cnt = 0x1
reserved.size = 0x0
reserved.reg[0x0].base = 0x79f6dd24
.size = 0x60922dc
arch_number = 0x00000000
TLB addr = 0x7fff0000
irq_sp = 0x79f6ef20
sp start = 0x79f6ef10
Early malloc usage: 2b8 / 400
可以看到,内存起始地址为 0x40000000,大小为 0x40000000,所以范围是 0x40000000~0x7FFFFFFF,这和我们在内核中查看 /proc/iomem
得到的内存范围一致
# cat /proc/iomem
...
40000000-7fffffff : System RAM
40008000-40afffff : Kernel code
40c00000-40d268d7 : Kernel data
内存起始地址
又冒出一个疑问,内存起始地址 0x40000000 是谁规定的?
这个通常是在 SoC 数据手册中 Memory mapping 这一节规定的,查看 H3 芯片的数据手册
看到 DRAM 使用的物理地址范围为 0x40000000-0xBFFFFFFF,共 2G 范围,这也决定了 H3 最大支持 2GB 内存。
我们板子上焊接的是两片 512MB 的 DDR 颗粒,共 1GB,所以内存地址范围是 0x40000000~0x7FFFFFFF。
uboot 起始地址
讲了那么多,uboot 会被加载到内存的哪个地址呢?是内存的起始地址 0x40000000?还是中间位置 0x60000000?
这得从 uboot 源码和链接脚本中找寻。
uboot 是没有使用虚拟内存地址的,直接跑在物理内存上,所以 uboot 在被编译链接时,肯定指定了代码的入口地址,这个地址肯定落在 0x40000000~0x7FFFFFFF 这个范围内
CONFIG_SYS_TEXT_BASE
在 uboot 的 .config 和 Makefile 文件中,使用 CONFIG_SYS_TEXT_BASE 宏来指定代码的入口地址
.config
CONFIG_SYS_TEXT_BASE=0x4a000000
Makefile
LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
验证
liyongjun@Box:~/project/board/buildroot$ OrangePiPC/host/bin/arm-linux-readelf -h OrangePiPC/build/uboot-2020.10/u-boot
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x4a000000
Start of program headers: 52 (bytes into file)
Start of section headers: 3872012 (bytes into file)
Flags: 0x5000200, Version5 EABI, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 4
Size of section headers: 40 (bytes)
Number of section headers: 37
Section header string table index: 36
可以看到 uboot 的入口地址确实是 0x4a000000
uboot 验证
uboot 读取 0x4a000000
u-boot.bin 二进制内容
可以看到,uboot 使用命令从 0x4a000000 处读到的内容就是 u-boot.bin 的内容。
这也充分证实了:SPL 已经将 uboot 程序加载到了内存地址 0x4a000000 处。
空闲内存
那么 0x40000000 ~ 0x4a000000 这段内存空间(160MB),uboot 没有使用,我们可以用这段内存来暂存 tftp 下载的文件。
=> tftp 42000000 u-boot-sunxi-with-spl.bin
Using ethernet@1c30000 device
TFTP from server 192.168.31.223; our IP address is 192.168.31.32
Filename 'u-boot-sunxi-with-spl.bin'.
Load address: 0x42000000
Loading: ##################################
1.4 MiB/s
done
Bytes transferred = 498944 (79d00 hex)
使用 tftp 命令,从 server 下载 u-boot-sunxi-with-spl.bin,存放在内存 0x42000000 处,大小共 498944B。
写入 SD 卡
=> mmc write 42000000 10 3ce
MMC write: dev # 0, block # 16, count 974 ... 974 blocks written: OK
将暂存在内存的 u-boot-sunxi-with-spl.bin 文件写入 SD 卡来完成升级操作。
0x42000000 为内存地址
0x10 为 SD 卡的块号,一个块为 512 字节,我们需要从 SD 卡偏移 8KB 的位置开始写入
0x3ce 为写入的块数,0x3ce = 974 = 498944 / 512
写入 SD 卡后,重启就行了
=> reset
resetting ...
U-Boot SPL 2020.10 (Nov 08 2023 - 22:15:30 +0800)
DRAM: 1024 MiB
Trying to boot from MMC1
U-Boot 2020.10 (Nov 08 2023 - 22:15:30 +0800) Allwinner Technology
CPU: Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi PC
DRAM: 1 GiB
MMC: mmc@1c0f000: 0
检查编译日期,可以看到升级成功了。
uboot 升级到内存
为了快速验证 uboot 功能,我们可以直接将 uboot 升级到内存,无需写入 SD 卡
以下两组命令都是可以的,使用 u-boot-sunxi-with-spl.bin 的话,要注意计算好 uboot 在该文件中的偏移,使得 uboot 的起始落在 0x4a000000 处就可以了。
setenv serverip 192.168.31.223
setenv ipaddr 192.168.31.32
tftp 0x4a000000 u-boot.bin
go 4a000000
setenv serverip 192.168.31.223
setenv ipaddr 192.168.31.32
tftp 0x49FF7FC0 u-boot-sunxi-with-spl.bin
go 4a000000