从u-boot传递大量二进制数据到Linux内核

10

在imx50 ARM板上从uboot传递大量数据(3 MB)到Linux内核2.6.35.3时遇到了一些问题。该数据在内核设备驱动程序探测功能中是必需的,然后应该被释放。首先,uboot从flash加载数据到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可用)启动内核,那么我的数据就位于内核系统RAM区域之上,然后我就得到了期望的数据。

所以,我的问题是:

为什么我得到的都是零值,如何将大量二进制数据从uboot传递到Linux内核?


我已经有一段时间没有使用ARM进行工作了...但是看看boot/compressed/head.S。简而言之,当Linux启动时,它会清除RAM。这有点复杂,因为在Linux内核引导之前,u-boot会准备实际的内存大小。查找bootm.c do_bootm_linux(),那里有一个调用setup_memory_tags()。这些文章可能有点旧,但基本的概念仍然有效 [1] (http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html)和[2](http://amitshah.bizhat.com/arm/arm_linux_boot-1.html)。希望对你有所帮助。 - sessyargc.jp
确保启动加载程序在启动序列开始之前不进行内存测试。这可能解释了为什么您看到了零。 - Eli Rosencruft
1个回答

8
您可以使用自定义的ATAG来传递数据块或者传递数据的地址和长度。需要注意的是,ATAG中的"A"代表ARM,因此这种解决方案无法移植到其他体系结构。相较于命令行bootarg,我认为ATAG更可取,因为您不希望用户干扰物理内存地址。而且,在启用MMU(即虚拟内存)之前,Linux内核将处理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,然后将起始地址和发现的KBytes数量传递给内核中的自定义ATAG。内核驱动程序获取这些值,如果它们不为零并且具有合理的值,则会从SRAM创建块设备。与您的情况相比,主要区别是SRAM位于与SDRAM完全不同的物理地址范围内。

注意 ATAG由U-Boot为内核可以使用的物理内存构建,因此这是您需要定义和排除保留RAM的地方。可能太晚在内核中进行操作。


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