Передача большого количества двоичных данных из u-boot в ядро Linux
Возникли проблемы с передачей большого объема данных (3 МБ) из uboot в ядро linux 2.6.35.3 на плате imx50 ARM. Эти данные требуются в функции проверки драйвера устройства ядра, а затем должны быть освобождены. Сначала загрузите данные из флэш-памяти в ОЗУ, а затем передайте физический адрес для ядра Linux с помощью загрузочных утилит. В ядре я пытаюсь зарезервировать определенный объем памяти с помощью reserve_resource() в файле arch/arm/kernel/setup.c:
--- a/arch/arm/kernel/setup.c Tue Jul 17 11:22:39 2012 +0300
+++ b/arch/arm/kernel/setup.c Fri Jul 20 14:17:16 2012 +0300
struct resource my_mem_res = {
.name = "My_Region",
.start = 0x77c00000,
.end = 0x77ffffff,
.flags = IORESOURCE_MEM | IORESOURCE_BUSY,
};
@@ -477,6 +479,10 @@
kernel_code.end = virt_to_phys(_etext - 1);
kernel_data.start = virt_to_phys(_data);
kernel_data.end = virt_to_phys(_end - 1);
+ my_mem_res.start = mi->bank[i].start + mi->bank[i].size - 0x400000;
+ my_mem_res.end = mi->bank[i].start + mi->bank[i].size - 1;
for (i = 0; i < mi->nr_banks; i++) {
if (mi->bank[i].size == 0)
@@ -496,6 +502,8 @@
if (kernel_data.start >= res->start &&
kernel_data.end <= res->end)
request_resource(res, &kernel_data);
+
+ request_resource(res, &my_mem_res);
}
if (mdesc->video_start) {
Этим я пытаюсь сказать ядру, что эта область памяти зарезервирована и эти данные не должны быть изменены ядром.
70000000-77ffffff : System RAM
70027000-7056ffff : Kernel text
70588000-7062094f : Kernel data
77c00000-77ffffff : My_Region
В водитель ioremap(0x77c00000, AREA_SIZE)
используется для получения адреса памяти ядра. Но когда я сбрасываю содержимое памяти, появляются только нули. Если загрузить ядро с mem=120M
(всего доступно 128 МБ ОЗУ), затем мои данные находятся выше области оперативной памяти ядра, затем я получаю ожидаемые данные.
Итак, мои вопросы:
Почему я получаю нули и как передать большой объем двоичных данных из Uboot в ядро Linux?
1 ответ
Вы можете использовать пользовательский ATAG для передачи блока данных или для адреса и длины данных. Обратите внимание, что "A" в ATAG обозначает ARM, поэтому это решение не переносимо на другие архитектуры. ATAG предпочтительнее командной строки IMO, так как вы не хотите, чтобы пользователь хранил адреса физической памяти. Также ядро Linux будет обрабатывать список ATAG до того, как MMU (то есть виртуальная память) будет включен.
В U-Boot посмотрите на lib_arm/armlinux.c
или же arch/arm/lib/bootm.c
для подпрограмм, которые создают список тегов ARM. Напишите свою собственную подпрограмму для вашего нового тега (ов), а затем вызовите ее в do_bootm_linux ().
В ядре Linux ATAG обрабатываются в arch/arm/kernel/setup.c
когда виртуальная память еще не была включена. Если вы просто передаете значения адреса и длины из U-Boot, тогда указатель и длина могут быть назначены глобальным переменным, которые экспортируются,
void *my_data;
unsigned int my_dlen;
EXPORT_SYMBOL(my_data);
EXPORT_SYMBOL(my_dlen);
и тогда водитель может получить его.
extern void *my_data;
extern unsigned int my_dlen;
request_mem_region(my_data, my_dlen, DRV_NAME);
md_map = ioremap(my_data, my_dlen);
Я использовал подобный код для поиска SRAM в U-Boot, а затем передал начальный адрес и количество найденных килобайт ядру в пользовательском ATAG. Драйвер ядра получает эти значения и, если они ненулевые и имеют нормальные значения, создает блочное устройство из SRAM. Основное отличие от вашей ситуации заключается в том, что SRAM находится в совершенно другом диапазоне физических адресов, чем SDRAM.
ПРИМЕЧАНИЕ. U-Boot создает ATAG для физической памяти, которую может использовать ядро, так что именно здесь вам нужно определить и исключить зарезервированную оперативную память. Вероятно, уже слишком поздно делать это в ядре.