新唐MCU技术
直播中

甘满盛

8年用户 1360经验值
擅长:386660
私信 关注
[问答]

Linux 中的FAQ_MA35D1_RAM大小与硬件不同是怎么回事?

Linux 中的FAQ_MA35D1_RAM大小与硬件不同

回帖(2)

李磊

2025-9-3 17:21:41
Linux 中的 RAM 大小与硬件不同,因为 VC8000 解码器和显示驱动程序保留了一些内存
您可以从 U-Boot 和 Linux 设备树中检查它
例如,您可以在下面看到 Linux 内核设备树
显示驱动程序预留 48 MB,VC8K 预留 24 MB,因此 Linux 无法看到系统中的所有内存空间
而且,OP-TEE还预留了一些内存

MA35D1.DTSIreserved-memory {        #address-cells = <2>;        #size-cells = <2>;        ranges;        display_buf: display_buf@0 {            reg = <0x0 0x8C800000 0x0 0x3000000>; /* 48MiB */            no-map;        };        vc8k_buf: vc8k_buf@0 {            reg = <0x0 0x8B000000 0x0 0x1800000>; /* 24MiB */            no-map;        };        rproc_buf: rproc_buf@0 {            reg = <0x0 0x80020000 0x0 0x60000>; /* 384KB */            no-map;        };    };#MA35D1 #DDR Size #Memory
举报

张辉

2025-9-8 17:49:41

这个问题的核心在于 U-Boot 配置或设备树(Device Tree)中对内存的描述与物理硬件配置不匹配,导致 Linux 内核启动时只识别了部分内存,通常表现为 Linux 报告的 Total RAM 远小于实际安装的 RAM(例如,物理装了 512MB 或 1GB,Linux 只显示 256MB 或更少)。


为什么会出现这种情况?


这通常是由以下原因造成的:




  1. U-Boot 加载位置与内存映射限制冲突: MA35D1 芯片的物理地址空间起始于 0x8000_0000,并且默认情况下,它的 DDR 内存控制器映射了整个 1GB 的空间(0x8000_00000xC000_0000)。然而:



    • XIP(Execute-In-Place)内核加载: MA35D1 默认推荐使用 XIP 方式启动 Linux 内核,即直接将压缩的内核镜像(uImage) 加载到 DDR 内存中由 CONFIG_SYS_LOAD_ADDR 定义的位置(例如 0x8000_80000x8020_0000)并解压执行。

    • 限制: MA35D1 的 DDR 内存控制器初始设置有一个默认值 DRAM_SIZE = 0x10000000(即 256MB)。这意味着,在 U-Boot 初始阶段,硬件只认为有 256MB 物理地址空间(0x8000_00000x9000_0000)是有效的。 即使物理上安装了更大的 RAM(如 512MB、1GB),这个初始化大小也不会自动改变。

    • 问题发生: 如果 U-Boot 尝试将 Linux 内核加载到 0x8000_0000 + 256MB (0x9000_0000) 之后的地址(比如 0xA000_0000),而此时硬件初始化只认前 256MB,那么内核加载就会失败。U-Boot 会退而求其次,把内核加载到当前有效内存范围之内的另一个地址(例如 0x8800_00000x8020_0000),这个地址是安全的。

    • 传递给内核的错误信息: U-Boot 启动内核时,会将一块连续的内存范围通过 bootargs 中的 mem= 参数传递给内核(例如 mem=256M)。这是因为 U-Boot 在加载内核时就“认为”只有加载地址以下的内存是安全的(即它自己初始化时的 256MB),而加载地址之上的内存(超过 256MB 的部分)被它认为是尚未验证或未初始化的潜在危险区域。内核只能接受并运行在这个受限的范围内。




  2. 设备树内存节点描述不完整: 设备树中的 /memory 节点精确地告诉 Linux 内核系统中有多少、哪些内存区域是可用的。



    • 如果设备树中只定义了一个较小的内存范围(例如 reg = <0x80000000 0x10000000>; // 256MB @ 0x80000000),那么内核自然只使用这部分内存。

    • 对于物理上包含多个 DRAM bank 的系统(比如 bank0 512MB @ 0x80000000, bank1 512MB @ 0xA0000000),如果设备树只描述了 bank0,或者 bank1 的地址超出了 MA35D1 DDR 控制器的默认 1GB 映射范围而没有正确描述整个映射,那么内核就无法访问 bank1 的内存。




  3. 内存保留区过大/位置不正确: 设备树中的 reserved-memory 节点可能会保留大块内存给特定功能(如 CMA, VPU, GPU, 安全 TA 等)。如果保留区域定义得过大,或者错误地覆盖了大部分内存区域,也会导致内核可用的有效内存减少。




如何解决这个问题?


解决方案集中在正确配置 U-Boot 和 设备树,确保它们能识别并传递完整的内存信息给 Linux:




  1. 检查并确认内核启动信息:



    • 在系统启动的早期,查看 U-Boot 传递给内核的命令行参数(bootargs),特别注意是否有 mem= 参数限制了大小。控制台输出通常包含类似 "Kernel command line: ..." 的信息。

    • 在 Linux 启动日志(dmesg)中,寻找包含 "Memory:" 的行,这会显示内核解析到的内存节点信息。例如:Memory: 255868K/262144K available ...。这能明确看到内核认为的总内存和 U-Boot 传递的限制(如果有)。




  2. 检查并修改 MA35D1 的 U-Boot 配置:



    • 这是最常见和关键的解决方法。你需要修改 U-Boot 源代码中针对 MA35D1 的配置文件(通常是 include/configs/ma35d1.hconfigs/ma35d1_xxx_defconfig)。

    • 关键参数:

      • CONFIG_SYS_SDRAM_BASE: 物理内存起始地址,通常是 0x80000000

      • CONFIG_SYS_SDRAM_SIZE: 必须设置为物理安装的实际 RAM 总大小(以字节为单位)。例如,对于 512MB,设置为 0x20000000;对于 1GB,设置为 0x40000000这是告诉 U-Boot 硬件实际有多少内存的核心设置。

      • CONFIG_SYS_LOAD_ADDR: (可选但推荐) 检查此值,确保内核加载地址 (CONFIG_SYS_LOAD_ADDR) 位于 CONFIG_SYS_SDRAM_BASECONFIG_SYS_SDRAM_BASE + CONFIG_SYS_SDRAM_SIZE 范围内一个合理的位置(例如 0x80200000)。如果之前使用的是超过 256MB 的地址导致加载失败回退,正确设置总大小后,默认加载地址通常就能正常工作。避免手动设置过高的地址。


    • 修改 RAMDISK_STARTKERNEL_STARTma35d1.h 中,找到定义 RAMDISK_STARTKERNEL_START 的地方。RAMDISK_START 的值需要大于内核结束地址。KERNEL_START 应该等于 CONFIG_SYS_LOAD_ADDR。它们的差值 (RAMDISK_START - KERNEL_START) 至少需要足够存放解压后的内核镜像。

    • 重新编译和部署 U-Boot: 修改后,重新编译 U-Boot 并将新的 U-Boot 镜像烧录到设备上。




  3. 检查并修改设备树(DTS/DTSI):



    • 找到内存节点 /memory。它应该类似:
      memory {
          device_type = "memory";
          reg = <0x80000000 0x40000000>; // 例如 1GB: 0x40000000 = 1073741824 bytes
      };


      • 确认 reg 属性的第二个值(size)是否等于或大于物理安装的总内存大小


    • 检查 reserved-memory 节点:
      reserved-memory {
          #address-cells = <1>;
          #size-cells = <1>;
          ranges;
          /* Example reserved region */
          cma_reserved: linux,cma {
              compatible = "shared-dma-pool";
              reusable;
              size = <0x2000000>; // 32MB
              alignment = <0x1000>;
              linux,cma-default;
          };
          /* Check other reservations (vpu, gpu, sec, etc.) if applicable */
      };


      • 计算所有 reserved-memory 区域的总和,确保它们没有过度侵占可用的物理内存空间。

      • 如果内存不连续(多个 bank),确保设备树包含了所有有效的 bank 范围。MA35D1 DDR 最大支持 2GB (0x80000000 - 0xC00000000x100000000 - 0x140000000),但需要驱动程序支持。单个物理地址空间描述通常是连续的。





  4. 验证解决方案:



    • 更新 U-Boot 和设备树后,重新启动系统。

    • 在 Linux 命令行运行 free -hcat /proc/meminfo | grep MemTotal

    • 检查 dmesg | grep Memory: 的输出。

    • 这些命令报告的总内存 (MemTotal) 应该非常接近物理安装的 RAM 大小(会略少一些,因为内核本身、保留区、页表等会占用少量空间)。




总结:


FAQ_MA35D1_RAM 大小不符的问题,几乎总是由于 U-Boot 配置中 CONFIG_SYS_SDRAM_SIZE 未设置为实际硬件大小 导致的。该设置不正确会使 U-Boot 在启动内核时传递错误的内存限制参数或使用错误的加载地址。同时,确保设备树中的 /memory 节点正确描述了完整且连续的物理内存范围,并检查预留内存是否合理。按照上述步骤检查和修改 U-Boot 和设备树配置,几乎总能解决此问题。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分