【问题标题】:Pass large amount of binary data from u-boot to linux kernel将大量二进制数据从 u-boot 传递到 linux 内核
【发布时间】:2012-07-19 18:51:01
【问题描述】:

在将大量数据 (3 MB) 从 uboot 传递到 imx50 ARM 板上的 linux 内核 2.6.35.3 时遇到一些问题。该数据在内核设备驱动探测函数中是必需的,然后应该被释放。首先 uboot 将数据从闪存加载到 RAM,然后使用 bootargs 为 linux 内核传递物理地址。在内核中,我尝试使用 arch/arm/kernel/setup.c 文件中的 reserve_resource() 保留一定数量的内存:

--- a/arch/arm/kernel/setup.c   Tue Jul 17 11:22:39 2012 +0300
+++ b/arch/arm/kernel/setup.c   Fri Jul 20 14:17:16 2012 +0300

struct resource my_mem_res = {
    .name = "My_Region",
    .start = 0x77c00000,
    .end = 0x77ffffff,
    .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
};

@@ -477,6 +479,10 @@
    kernel_code.end     = virt_to_phys(_etext - 1);
    kernel_data.start   = virt_to_phys(_data);
    kernel_data.end     = virt_to_phys(_end - 1);
+   my_mem_res.start    = mi->bank[i].start + mi->bank[i].size - 0x400000;
+   my_mem_res.end      = mi->bank[i].start + mi->bank[i].size - 1;

    for (i = 0; i < mi->nr_banks; i++) {
        if (mi->bank[i].size == 0)
@@ -496,6 +502,8 @@
        if (kernel_data.start >= res->start &&
            kernel_data.end <= res->end)
            request_resource(res, &kernel_data);
+
+       request_resource(res, &my_mem_res);
    }

    if (mdesc->video_start) {

通过这个我试图告诉内核它保留了这个内存区域并且这个数据不应该被内核修改。

70000000-77ffffff : System RAM
  70027000-7056ffff : Kernel text
  70588000-7062094f : Kernel data
  77c00000-77ffffff : My_Region

在驱动程序中ioremap(0x77c00000, AREA_SIZE) 用于获取内核内存地址。但是当我转储内存内容时,只有零。如果用mem=120M 启动内核(总共128MB RAM 可用),那么我的数据在内核系统内存区域之上,那么我得到了我期望的数据。

所以,我的问题:

为什么我得到零以及如何将大量二进制数据从 uboot 传递到 linux 内核?

【问题讨论】:

  • 我已经有一段时间没有使用 ARM 了……但是看看 boot/compressed/head.S。简而言之,当 Linux 启动时,它会清除 RAM。这有点复杂,因为 u-boot 在 Linux 内核启动之前准备好实际的内存大小。查找 bootm.c do_bootm_linux() 那里有一个调用 setup_memory_tags()。这些都是旧的,但要点仍然有效12。 HTH
  • 确保您的引导加载程序在启动引导序列之前没有进行内存测试。这可以解释为什么你会看到零。

标签: memory linux-kernel arm embedded-linux u-boot


【解决方案1】:

您可以使用自定义 ATAG 来传递数据块或传递数据的地址和长度。请注意,ATAG 中的“A”代表 ARM,因此该解决方案不能移植到其他架构。 ATAG 比命令行 bootarg IMO 更可取,因为您不希望用户弄乱物理内存地址。此外,Linux 内核将在启用 MMU(即虚拟内存)之前处理 ATAG 列表。

在 U-Boot 中,查看 lib_arm/armlinux.carch/arm/lib/bootm.c 以获取构建 ARM 标记列表的例程。为新标签编写自己的例程,然后在 do_bootm_linux() 中调用它。

在 Linux 内核中,ATAGs 在尚未启用虚拟内存时在 arch/arm/kernel/setup.c 中处理。如果您只是从 U-Boot 传递地址和长度值,则可以将指针和长度分配给导出的全局变量,

void          *my_data;
unsigned int  my_dlen;
EXPORT_SYMBOL(my_data);
EXPORT_SYMBOL(my_dlen);

然后驱动程序可以检索它。

extern void          *my_data;
extern unsigned int  my_dlen;

request_mem_region(my_data, my_dlen, DRV_NAME);
md_map = ioremap(my_data, my_dlen);

我已经使用类似的代码来探测 U-Boot 中的 SRAM,然后在自定义 ATAG 中将找到的起始地址和千字节数传递给内核。内核驱动程序获取这些值,如果它们不为零且具有合理的值,则从 SRAM 中创建块设备。与您的情况的主要区别在于 SRAM 与 SDRAM 的物理地址范围完全不同。

注意 ATAG 是由 U-Boot 为内核可以使用的物理内存构建的,因此这确实是您需要定义和排除保留 RAM 的地方。在内核中这样做可能为时已晚。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多