内核API获取物理RAM偏移量

时间:2017-04-03 17:54:48

标签: linux linux-kernel linux-device-driver

我正在编写一个设备驱动程序(用于Linux内核2.6.x),它使用物理地址直接与物理RAM交互。对于我的设备的内存布局(根据cat /proc/iomem的输出),系统RAM从物理地址0x80000000开始;但是,此代码可能在具有不同内存布局的其他设备上运行,因此我不想对该偏移进行硬编码。

我可以在设备驱动程序中使用函数,宏或常量,它给出了系统RAM第一个字节的物理地址吗?

3 个答案:

答案 0 :(得分:3)

  

我可以在设备驱动程序中使用函数,宏或常量,它给出了系统RAM第一个字节的物理地址吗?

没关系,因为你问XY question 您不应该在设备驱动程序中查找或尝试使用"系统RAM" 的第一个字节。
驱动程序只需要知道其寄存器块的地址(和长度)(这就是"内存"用于什么?不是吗?)。

在2.6内核中(即在设备树之前),此信息通常通过 board _devices.c文件中的struct resourcestruct platform_device定义传递给驱动程序。

IORESOURCE_MEM中的struct resource属性是将设备的内存块起始和结束地址传递给设备驱动程序的机制。
起始地址通常是硬编码的,直接取自SoC数据表或电路板的存储器映射。
如果更改SoC,则需要新的电路板文件。

例如,来自arch/arm/mach-at91/at91rm9200_devices.c的代码用于配置和设置评估板的MMC设备(AT91RM9200_BASE_MCI是该设备的寄存器块的物理存储器地址):

#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
static u64 mmc_dmamask = DMA_BIT_MASK(32);
static struct at91_mmc_data mmc_data;

static struct resource mmc_resources[] = {
    [0] = {
        .start  = AT91RM9200_BASE_MCI,
        .end    = AT91RM9200_BASE_MCI + SZ_16K - 1,
        .flags  = IORESOURCE_MEM,
    },
    [1] = {
        .start  = AT91RM9200_ID_MCI,
        .end    = AT91RM9200_ID_MCI,
        .flags  = IORESOURCE_IRQ,
    },
};

static struct platform_device at91rm9200_mmc_device = {
    .name       = "at91_mci",
    .id     = -1,
    .dev        = {
                .dma_mask       = &mmc_dmamask,
                .coherent_dma_mask  = DMA_BIT_MASK(32),
                .platform_data      = &mmc_data,
    },
    .resource   = mmc_resources,
    .num_resources  = ARRAY_SIZE(mmc_resources),
};

void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
{
    if (!data)
        return;

    /* input/irq */
    if (data->det_pin) {
        at91_set_gpio_input(data->det_pin, 1);
        at91_set_deglitch(data->det_pin, 1);
    }
    if (data->wp_pin)
        at91_set_gpio_input(data->wp_pin, 1);
    if (data->vcc_pin)
        at91_set_gpio_output(data->vcc_pin, 0);

    /* CLK */
    at91_set_A_periph(AT91_PIN_PA27, 0);

    if (data->slot_b) {
        /* CMD */
        at91_set_B_periph(AT91_PIN_PA8, 1);

        /* DAT0, maybe DAT1..DAT3 */
        at91_set_B_periph(AT91_PIN_PA9, 1);
        if (data->wire4) {
            at91_set_B_periph(AT91_PIN_PA10, 1);
            at91_set_B_periph(AT91_PIN_PA11, 1);
            at91_set_B_periph(AT91_PIN_PA12, 1);
        }
    } else {
        /* CMD */
        at91_set_A_periph(AT91_PIN_PA28, 1);

        /* DAT0, maybe DAT1..DAT3 */
        at91_set_A_periph(AT91_PIN_PA29, 1);
        if (data->wire4) {
            at91_set_B_periph(AT91_PIN_PB3, 1);
            at91_set_B_periph(AT91_PIN_PB4, 1);
            at91_set_B_periph(AT91_PIN_PB5, 1);
        }
    }

    mmc_data = *data;
    platform_device_register(&at91rm9200_mmc_device);
}
#else
void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
#endif

ADDENDUM

  

我还没有看到这是一个xy问题。

我认为这是一个XY问题,因为:

  • "系统RAM" 与物理内存地址空间混为一谈。
    " RAM"将是存在于地址空间中的实际(可读/可写)存储器 "系统内存"是Linux内核管理的RAM(参考your previous question) 外设可以在(物理)存储器地址空间中具有寄存器和/或器件存储器,但这不应该被称为"系统RAM"

  • 您尚未提供任何有关驱动程序"如何或为何使用物理地址直接与物理RAM进行交互的背景信息。" 的方式与其他方式不同Linux驱动程序。

  • 您认为某个功能是您的驱动程序的解决方案,但您不知道该功能的名称。这是XY问题的原型。

  

我可以调用像get_platform_device这样的函数(我刚刚编写)来获取struct platform_device,然后找到代表System RAM的struct资源吗?

设备驱动程序将调用platform_get_resource()(在其探测函数中)以检索其在板文件中定义的struct resource
要继续上面开始的示例,驱动程序的探测路由具有:

static int __init at91_mci_probe(struct platform_device *pdev)
{
    struct mmc_host *mmc;
    struct at91mci_host *host;
    struct resource *res;
    int ret;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res)
        return -ENXIO;

    if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
        return -EBUSY;

...  

    /*
     * Map I/O region
     */
    host->baseaddr = ioremap(res->start, resource_size(res));
    if (!host->baseaddr) {
        ret = -ENOMEM;
        goto fail1;
    }
  

这将允许我编写始终可以访问RAM的第n个字节的代码,而无需假设RAM如何相对于内存的其他部分进行排列。

这就像安全漏洞或潜在的错误 我挑战你在主线Linux内核中找到一个驱动程序,它使用"系统RAM的第一个字节的物理地址"

您的标题是"内核API以获取物理RAM偏移"
您正在寻找的API似乎是struct resource

您想要做的事情似乎是面对Linux内核约定。为了系统的完整性和安全性,驱动程序不会尝试访问内存的任何/每个部分 驱动程序将请求并可以独占访问其寄存器和/或设备存储器的地址空间 内核管理下的所有RAM只能通过定义良好的约定来访问,例如copy_to_user()的缓冲区地址或DMA API。 设备驱动程序根本没有自由的权重来访问它选择的任何内存部分 一旦内核启动了一个驱动程序,就绝对没有办法忽视"假设如何安排RAM"

答案 1 :(得分:0)

RAM内存映射与每个SOC或处理器相同。 Vendor usually provide their memory mapping related documents to the user. 您可能需要参考处理器数据表相关文档。 正如你所说,内存是硬编码的。在大多数情况下,内存映射是通过设备树或SDRAM驱动程序本身进行硬编码的。

答案 2 :(得分:0)

enter image description here

也许您可以查看memblock struct和memblock_start_of_DRAM()。

/ sys / kernel / debug / memblock / memory表示内存库。

0: 0x0000000940000000..0x0000000957bb5fff 
RAM bank 0: 0x0000000940000000 0x0000000017bb6000

1: 0x0000000980000000..0x00000009ffffffff 
RAM bank 1: 0x0000000980000000 0x0000000080000000