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

时间:2016-06-28 17:17:58

标签: linux embedded-linux

没有详细信息的问题:

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

详细信息:

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

当前启动过程大致如下:

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

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

问题:

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

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

Scope Plot

要解决此问题,我们需要暂停LPDDR,然后告诉PMIC禁用处理器上的DDR_IO电源(DDR的IO电源和主电源是独立的稳压器)。这样可以防止弹出LPDDR的电源短路自刷新。不幸的是,这是一个鸡蛋或鸡蛋问题。如果我们暂停LPDDR,我们就无法运行任何代码与PMIC通信并禁用特定供应。如果我们禁用电源,我们将无法再与LPDDR通信以使其自动刷新。

当前的解决方法:

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

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

2 个答案:

答案 0 :(得分:1)

回过头来回答这个问题。事实上,可以将代码从DRAM加载到SRAM中并执行它。经过进一步调查,我们发现许多嵌入式平台使用这种方法来处理电源管理功能,特别是暂停/恢复 - 就像我在这里试图解决的问题一样。

以下是linux如何在at91平台上处理暂停:http://lxr.free-electrons.com/source/arch/arm/mach-at91/pm.c#L416

我们需要对此进行自定义实现,最终创建了一个使用相同方法的内核模块。然后我们从user-land插入了内核模块,它为我们提供了一种从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);

从user-land调用

system("insmod custom_pm_module.ko");

答案 1 :(得分:0)

  

是否可以将从DDR运行的裸机可执行文件复制到处理器内部SRAM并运行它?

根据您的平台,这是非常难以实现的。 Linux内核本身是从DRAM运行的,所以当DRAM关闭时,你将没有实时Linux内核,也没有任何OS服务(没有系统调用,没有调度程序,没有irqs / irq处理程序;如果它在dram中没有irq向量?)。

你的芯片只有128 KB的SRAM:http://www.atmel.com/devices/ATsama5d36.aspx?tab=parameters - 它只是小到包含完整的Linux内核。

因此,您可以尝试创建一些可执行文件,将其优先级更改为RT(实时)以便能够忽略调度程序/ irqs ...您应该将此可执行文件完全放入SRAM(仅当SRAM可以用作直接寻址内存)...你还应该检查它是否需要它,它将被加载(或者你应该让可执行文件在核心上一直运行吗?它是多核芯片吗?)

写这个不是可执行文件,但作为内核的一部分可能更容易......但任务看起来仍然不可能......

在关闭DRAM之前DRAM和CPU运行的时间是什么时候?

DRAM可以保存数个刷新周期;它将保留大部分数据数秒(冷却时间更长 - https://en.wikipedia.org/wiki/Cold_boot_attack;热时更短)。您可能想要添加一些数据校验和...(您的芯片没有用于DRAM的ECC?)