我正在编写一个设备驱动程序(用于Linux内核2.6.x),它使用物理地址直接与物理RAM交互。对于我的设备的内存布局(根据cat /proc/iomem
的输出),系统RAM从物理地址0x80000000
开始;但是,此代码可能在具有不同内存布局的其他设备上运行,因此我不想对该偏移进行硬编码。
我可以在设备驱动程序中使用函数,宏或常量,它给出了系统RAM第一个字节的物理地址吗?
答案 0 :(得分:3)
我可以在设备驱动程序中使用函数,宏或常量,它给出了系统RAM第一个字节的物理地址吗?
没关系,因为你问XY question
您不应该在设备驱动程序中查找或尝试使用"系统RAM" 的第一个字节。
驱动程序只需要知道其寄存器块的地址(和长度)(这就是"内存"用于什么?不是吗?)。
在2.6内核中(即在设备树之前),此信息通常通过 board _devices.c文件中的struct resource
和struct 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)