了解U-Boot的内存占用情况

15

我不理解在加载U-Boot时RAM中发生了什么。我正在使用Xilinx Zynq ZC702评估套件,并尝试使用U-Boot将Linux内核加载到其中。因此,我使用Xilinx工具Vivado和SDK逐步生成写入SD卡的BOOT.bin文件:

  • 使用Vivado创建HW项目,
  • 使用SDK生成FSBL和FPGA位流,
  • 创建包含FSBL + 位流 + U-Boot的引导映像(我从xilinx Git存储库下载了U-Boot源代码)。

简而言之,我遵循了Xilinx用户指南上描述的所有步骤。

但是现在,在加载内核之前,我想了解发生了什么,但我无法理解。根据文档,如果从闪存加载,U-Boot会将自身复制到RAM中,并从那里执行自己,但是在哪里?

我在网上搜索并发现U-Boot提取自身的地址定义在include/configs/zynq-common.h中的CONFIG_SYS_TEXT_BASE中,似乎为0x400_0000。

但是在另一个网站上,我看到我们可以在调试模式下打印重定位地址,因此我修改了文件common/board_r.c并覆盖了函数“initr_announce”以打印“gd->relocaddr”字段。这次它显示U-Boot使用偏移地址0x3FF3_7000。

当我使用U-Boot命令“md”检查内存时,我看到两个偏移都被使用,并且我在两个位置都看到了一种类似于“be00_00ea”的魔术数字:

Xilinx First Stage Boot Loader 
Release 2014.4  Feb  8 2016-14:53:56
Devcfg driver initialized 
Silicon Version 3.1
Boot mode is SD
SD: rc= 0
SD Init Done 
Flash Base Address: 0xE0100000
Reboot status register: 0x60400000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 3
Partition Number: 1
Header Dump
Image Word Len: 0x000F6EC0
Data Word Len: 0x000F6EC0
Partition Word Len:0x000F6EC0
Load Addr: 0x00000000
Exec Addr: 0x00000000
Partition Start: 0x000065D0
Partition Attr: 0x00000020
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFD14B7E
Bitstream
In FsblHookBeforeBitstreamDload function 
PCAP:StatusReg = 0x40000A30
PCAP:device ready
PCAP:Clear done
Level Shifter Value = 0xA 
Devcfg Status register = 0x40000A30 
PCAP:Fabric is Initialized done
PCAP register dump:
PCAP CTRL 0xF8007000: 0x4C00E07F
PCAP LOCK 0xF8007004: 0x0000001A
PCAP CONFIG 0xF8007008: 0x00000508
PCAP ISR 0xF800700C: 0x0802000B
PCAP IMR 0xF8007010: 0xFFFFFFFF
PCAP STATUS 0xF8007014: 0x00000A30
PCAP DMA SRC ADDR 0xF8007018: 0x00100001
PCAP DMA DEST ADDR 0xF800701C: 0xFFFFFFFF
PCAP DMA SRC LEN 0xF8007020: 0x000F6EC0
PCAP DMA DEST LEN 0xF8007024: 0x000F6EC0
PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF
PCAP MBOOT 0xF800702C: 0x0000C000
PCAP SW ID 0xF8007030: 0x00000000
PCAP UNLOCK 0xF8007034: 0x757BDF0D
PCAP MCTRL 0xF8007080: 0x30800100

DMA Done ! 

FPGA Done ! 
In FsblHookAfterBitstreamDload function 
Partition Number: 2
Header Dump
Image Word Len: 0x0001BA12
Data Word Len: 0x0001BA12
Partition Word Len:0x0001BA12
Load Addr: 0x04000000
Exec Addr: 0x04000000
Partition Start: 0x000FD490
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xF7EAFAC8
Application
Handoff Address: 0x04000000
In FsblHookBeforeHandoff function 
SUCCESSFUL_HANDOFF
FSBL Status = 0x1


U-Boot 2015.07 (Feb 11 2016 - 10:24:28 +0100)

Model: Zynq ZC702 Development Board
I2C:   ready
DRAM:  ECC disabled 1 GiB
MMC:   zynq_sdhci: 0
SF: Detected N25Q128A with page size 256 Bytes, erase size 64 KiB, total 16 MiB
In:    serial
Out:   serial
Err:   serial
Model: Zynq ZC702 Development Board
Net:   Gem.e000b000
Hit any key to stop autoboot:  0 
zynq-uboot> md 0x4000000
04000000: ea0000be e59ff014 e59ff014 e59ff014    ................
04000010: e59ff014 e59ff014 e59ff014 e59ff014    ................
04000020: 04000060 040000c0 04000120 04000180    `....... .......
04000030: 040001e0 04000240 040002a0 deadbeef    ....@...........
04000040: 0badc0de e320f000 e320f000 e320f000    ...... ... ... .
04000050: e320f000 e320f000 e320f000 e320f000    .. ... ... ... .
04000060: e51fd028 e58de000 e14fe000 e58de004    (.........O.....
04000070: e3a0d013 e169f00d e1a0e00f e1b0f00e    ......i.........
04000080: e24dd048 e88d1fff e51f2050 e892000c    H.M.....P ......
04000090: e28d0048 e28d5034 e1a0100e e885000f    H...4P..........
040000a0: e1a0000d eb0005dc e320f000 e320f000    .......... ... .
040000b0: e320f000 e320f000 e320f000 e320f000    .. ... ... ... .
040000c0: e51fd088 e58de000 e14fe000 e58de004    ..........O.....
040000d0: e3a0d013 e169f00d e1a0e00f e1b0f00e    ......i.........
040000e0: e24dd048 e88d1fff e51f20b0 e892000c    H.M...... ......
040000f0: e28d0048 e28d5034 e1a0100e e885000f    H...4P..........
zynq-uboot> md 0x3ff37000
3ff37000: ea0000be e59ff014 e59ff014 e59ff014    ................
3ff37010: e59ff014 e59ff014 e59ff014 e59ff014    ................
3ff37020: 3ff37060 3ff370c0 3ff37120 3ff37180    `p.?.p.? q.?.q.?
3ff37030: 3ff371e0 3ff37240 3ff372a0 deadbeef    .q.?@r.?.r.?....
3ff37040: 3f312628 e320f000 e320f000 e320f000    (&1?.. ... ... .
3ff37050: e320f000 e320f000 e320f000 e320f000    .. ... ... ... .
3ff37060: e51fd028 e58de000 e14fe000 e58de004    (.........O.....
3ff37070: e3a0d013 e169f00d e1a0e00f e1b0f00e    ......i.........
3ff37080: e24dd048 e88d1fff e51f2050 e892000c    H.M.....P ......
3ff37090: e28d0048 e28d5034 e1a0100e e885000f    H...4P..........
3ff370a0: e1a0000d eb0005dc e320f000 e320f000    .......... ... .
3ff370b0: e320f000 e320f000 e320f000 e320f000    .. ... ... ... .
3ff370c0: e51fd088 e58de000 e14fe000 e58de004    ..........O.....
3ff370d0: e3a0d013 e169f00d e1a0e00f e1b0f00e    ......i.........
3ff370e0: e24dd048 e88d1fff e51f20b0 e892000c    H.M...... ......
3ff370f0: e28d0048 e28d5034 e1a0100e e885000f    H...4P..........
zynq-uboot> 

U-Boot为什么需要这两个偏移量?U-Boot的实际内存占用情况是什么?更一般地说,我应该把我的内核放在哪里,以确保它不会覆盖任何东西?

1个回答

35

ARM架构上的u-boot重定位

下面是两阶段引导过程的完整序列:

  1. ROM代码将SPL(从SD卡上的MLO文件)读取到CONFIG_SPL_TEXT_BASE地址。此地址通常位于SRAM中,不需要初始化即可正常运行(与RAM相反)。 ROM代码跳转到SPL代码。
  2. SPL配置RAM,然后将u-boot(从SD卡上的u-boot.img文件)读取到CONFIG_SYS_TEXT_BASE RAM地址(通常在RAM的开头),并运行它
  3. u-boot将自己重定位到gd->relocaddr RAM地址(通常在RAM末尾),然后跳转到重定位的代码
  4. 现在我们准备启动内核

对于单级引导,您没有SPL,通常只使用u-boot.bin文件。 在这种情况下,您只有步骤3和4。

关于重定位有两种情况(如doc/README.arm-relocation中所述):

  1. CONFIG_SYS_TEXT_BASE!= gd->relocaddr:将执行重定位
  2. CONFIG_SYS_TEXT_BASE == gd->relocaddr:不会执行重定位

在您的情况下,您可以看到已执行重定位(因为CONFIG_SYS_TEXT_BASE!= gd->relocaddr)。

因此,回答您的问题:

为什么U-Boot需要这两个偏移量?

该重定位背后的原因在u-boot ARM relocation task中描述:

...我们可以测量板上实际存在的内存大小,然后将U-Boot重定位到RAM的最末尾,使几乎整个RAM可用作一个大的连续区域,用于“应用程序”,如加载Linux内核、ramdisk等。

实际上,如果您查看代码,可以看到gd->relocaddr是RAM末尾减去监视器代码(U-Boot)大小:

gd->relocaddr = gd->ram_top;
...
gd->relocaddr -= gd->mon_len;

还可以进行一些额外的内存预留。例如,在我的平台(TI DRA7XX EVM)上,我可以看到调用了以下函数:

setup_dest_addr()
reserve_round_4k()
reserve_mmu()
reserve_uboot()

实际的重定位是在board_init_f()调用之后进行的。

arch/arm/lib/crt0.S:

bl board_init_f
...
b relocate_code

arch/arm/lib/relocate.S:

ENTRY(relocate_code)

现在回答你的下一个问题很容易:

U-Boot 的实际内存占用是多少?

在重定位之前,U-Boot 位于 CONFIG_SYS_TEXT_BASE。重定位后,U-Boot 位于 gs->relocaddr

关于你的最后一个问题:

我应该把我的内核放在哪里,以确保它不会覆盖任何内容?

由于 U-Boot 已经被重定位到 RAM 的末尾,理论上可以使用任何 RAM 地址来放置内核。但是请查看 include/configs/zynq-common.h 中的 CONFIG_EXTRA_ENV_SETTINGS 定义:

"sdboot=if mmcinfo; then " \
        "run uenvboot; " \
        "echo Copying Linux from SD to RAM... && " \
        "load mmc 0 ${kernel_load_address} ${kernel_image} && " \
        "load mmc 0 ${devicetree_load_address} ${devicetree_image} && " \
        "load mmc 0 ${ramdisk_load_address} ${ramdisk_image} && " \
        "bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}; " \
    "fi\0" \

从这里你可以看到,你应该加载内核到${kernel_load_address},即0x2080000

"kernel_load_address=0x2080000\0" \

其他常量请参见该定义的其余部分。

bdinfo命令

您可以找到bdinfo命令有用:可以使用bdinfo命令从U-Boot shell中找到重定位地址以及其他有用信息。例如,对于DRA7XX EVM:

=> bdinfo

DRAM bank   = 0x00000000
-> start    = 0x80000000
-> size     = 0x60000000
TLB addr    = 0xDFFF0000
relocaddr   = 0xDFF5D000
reloc off   = 0x5F75D000
irq_sp      = 0xDEF3CEE0
sp start    = 0xDEF3CED0

从这里您可以看出:

  • RAM起始地址是0x80000000
  • RAM大小为0x60000000
  • ...因此RAM结束(gd->ram_top)是0x80000000 + 0x60000000 = 0xE0000000
  • 重定位地址是0xDFF5D000
  • 用于重定位的保留内存为0xE0000000 - 0xDFF5D000 = 652 KB
  • 监视器(U-Boot)大小约为TLB addr - relocaddr = 0xDFFF0000 - 0xDFF5D000 = 588 KB

另请参见:

[1] u-boot:重定位

[2] 什么是SPL(辅助程序加载程序)的用途

[3] 添加ARM重定位支持到u-boot的提交


0x02080000 是您的板子地址。对于 DRA7XX EVM 来说,它是 0x80800000。请查看您的 include/configs/zynq-common.h 文件中的 CONFIG_EXTRA_ENV_SETTINGS 定义以获取所有地址(内核、设备树、RAM 磁盘)。 - Sam Protsenko
如果您将 CONFIG_SYS_TEXT_BASE 设置为重定位地址,将不会执行重定位。您可以在 doc/README.arm-relocation 中找到此行为的说明。此功能是在汇编程序例程 relocate_code 中实现的,请查看此行:beq relocate_done /* skip relocation */ - Sam Protsenko
好的,谢谢,这只是为了理解过程;)但仍然存在一个问题,如果我将设备树加载到地址0x200_0000(如zynq-common.h文件中指定的那样),我会收到“image is not a fdt,FDT creation failed!”的错误提示... - AwaX
1
尝试从 U-Boot shell 运行 run sdboot 命令,而不是手动执行所有步骤。根据 CONFIG_EXTRA_ENV_SETTINGS,你的 SD 卡上应该有 uImagedevicetree.dtburamdisk.image.gz 文件。如果问题仍然存在 - 你应该创建一个新的问题,并提供关于该特定问题的详细信息。 - Sam Protsenko
2
如果您不必向bootm命令提供ramdisk地址,则语义应为bootm 1-3,其中1是内核地址,3是设备树地址。如在bootm帮助中所述:“要在没有initrd映像的情况下引导该内核,请使用'-'作为第二个参数”。如果bootm语义和设备树地址都正确,并且设备树blob本身合法,则一切都应该正常工作。 - Sam Protsenko
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接