gpt4 book ai didi

linux - 退出 DRAM 中的 Linux 以在 SRAM 中运行裸机代码

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:45:07 24 4
gpt4 key购买 nike

没有细节的问题:

是否可以从 Linux 复制裸机可执行文件,从 DDR 运行到处理器内部 SRAM 中并运行它?此应用程序将暂停 DDR 并禁用电源轨以修复硬件问题。

详细信息:

我正在开发一款使用 ARM 处理器并运行嵌入式 Linux 的定制嵌入式产品。处理器是 Atmel ATSAMA5D36。我们使用以下辅助引导加载程序和内核:

目前的开机流程大概是这样的:

  • Atmel 有一个 ROM 引导加载程序,可以在 NOR 闪存上找到我们的引导加载程序并将其复制到 SAMA5 的内部 SRAM
  • 第二级引导加载程序初始化硬件并从 LPDDR 中的 NOR 闪存复制/解压缩我们的内核
  • 我们跳入内核并从 LPDDR 运行 linux

该设备以两种模式运行:连接到主电源或由电池备份。当连接到主​​电源时,可以发出一条命令来挂起 linux,这会将我们的 LPDDR 内存置于自刷新模式。一旦 LPDDR 处于自刷新状态,就可以移除主电源,并且 LPDDR 将持续到下一个上电周期。板上有一个小型辅助 ARM Cortex-M0 微 Controller ,它一直运行并执行 IO 处理和其他一些与时间相关的任务。

问题:

当主电源从电路板上移除时,电池切换为 LPDDR、辅助 ARM 微 Controller 供电,并且主 SAMA5 电源关闭。当 SAMA5 断电且电源电容放电时,处理器会短暂 (100uS) 掉电并强制 IO 进入复位状态,然后再永久关闭。不幸的是,电源中的这个“信号”将 LPDDR CKE 线拉高到足以使 LPDDR 退出自刷新模式。这会导致 LPDDR 上的内存损坏。

显示主电源电压和 DDR_CKE 信号的示波器图:

Scope Plot

要解决此问题,我们需要暂停 LPDDR,然后告诉 PMIC 禁用处理器上的 DDR_IO 电源(DDR 的 IO 电源和主电源是独立的稳压器)。这将防止使 LPDDR 退出自刷新的电源故障。不幸的是,这是先有鸡还是先有蛋的问题。如果我们暂停 LPDDR,我们将无法运行任何代码来与 PMIC 通信并禁用特定电源。如果我们禁用电源,我们将无法再与 LPDDR 通信以使其进入自刷新状态。

当前的解决方法:

当发出暂停主处理器的命令时,它会将其转发给辅助微 Controller ,然后暂停 LPDDR 以进行 self 刷新。辅助微 Controller 然后重置主处理器并等待辅助引导加载程序启动。当引导加载程序启动时,它会检查微 Controller 以查看是否发出了暂停。如果是,它将 LPDDR 置于自刷新状态,告诉 PMIC(通过 I2C)禁用 DDR_IO 电源,并等待一段时间 (1) 等待电源被移除。

问题在于启动时间——从重置到 DDR 初始化和挂起需要 120 毫秒。 LPDDR 的刷新周期为 16-64 毫秒,因此我们至少缺少一个 DDR 的刷新周期。到目前为止,在测试中我们还没有看到由于这种延迟而导致的内存损坏,但这显然不是一个理想的解决方案(但比硬件修订要好)。

最佳答案

只是绕回来回答这个问题。实际上,可以将代码从 DRAM 加载到 SRAM 中并执行。经过进一步调查,我们发现许多嵌入式平台使用这种方法来处理电源管理功能,尤其是挂起/恢复——这与我在这里试图解决的问题完全一样。

以下是 linux 在 at91 平台上处理进入挂起的方式:http://lxr.free-electrons.com/source/arch/arm/mach-at91/pm.c#L416

我们需要对此进行自定义实现,并最终创建了一个使用相同方法的内核模块。然后我们从用户空间插入内核模块,它为我们提供了一种从 SRAM 运行代码以执行电源管理功能的方法。

示例内核模块代码:

#include <linux/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#define VIRT_BASE 0xFEF78000 //for AT91

static void (*sram_fn)(void) = NULL;

unsigned char buf[] = {
//your complied ARM byte code
};

static void __init init_sram_fn (void)
{
sram_fn = (void *) (VIRT_BASE – sizeof(buf));
memcpy(sram_fn, &buf, sizeof(buf));
sram_fn();
}

static void __exit cleanup_sram_fn (void){}

module_init(init_sram_fn);
module_exit(cleanup_sram_fn);

从用户空间调用

system("insmod custom_pm_module.ko");

关于linux - 退出 DRAM 中的 Linux 以在 SRAM 中运行裸机代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38082488/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com