Сбой ядра при загрузке данных на физический адрес Ram через модульLinux

Ответить Пред. темаСлед. тема
Anonymous
 Сбой ядра при загрузке данных на физический адрес Ram через модуль

Сообщение Anonymous »

Я пытаюсь загрузить файл прошивки по определенному физическому адресу в оперативной памяти устройства Arm64. В дереве устройств уже есть запись, которая определяет область памяти и использует no-map, чтобы Linux не мог сопоставить виртуальную память с этой областью:

Код: Выделить всё

.
.
.
reserved-memory {
#address-cells = ;
#size-cells = ;
ranges;

/* Reserved memory for COM.2 firmware */
reserved: memory@8000000 {
no-map;
reg = ;
};
};

xlnx-com2@8000000 {
compatible = "xlnx,reserved-memory";
memory-region = ;
};
};
};
};
Мой драйвер ядра успешно распознает указанную область как ресурс памяти, сопоставляет ее с помощью memremap(), принимает в качестве параметра модуля расположение файла прошивки для чтения битового потока, а затем записи его в область памяти.
Это мой код:

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define DRV_NAME "com2"

static char *fpgaupdate;
module_param(fpgaupdate, charp, 0444);

static int com2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np;
struct resource res;
phys_addr_t mem_paddr;
void __iomem *mem_vaddr;
size_t mem_size;
int ret = 0;

const struct firmware *fw;
size_t offset = 0;
size_t chunk_size;

if (fpgaupdate == NULL) {
dev_err(dev, "fpgaupdate parameter is missing\n");
return -EINVAL;
}

ret = request_firmware(&fw, fpgaupdate, dev);
if (ret) {
dev_err(dev, "failed to request firmware.  error: %d\n", ret);
return ret;
}

dev_info(dev, "firmware size: %ld bytes\n", fw->size);

np = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!np) {
dev_err(dev, "No %s specified\n", "memory-region");
ret = -EINVAL;
goto rel_fw;
}

ret = of_address_to_resource(np, 0, &res);
if (ret) {
dev_err(dev, "No memory address assigned to the region\n");
goto rel_fw;
}

mem_paddr = res.start;
mem_size = resource_size(&res);

if (fw->size > mem_size) {
dev_err(dev, "firmware size exceeds reserved memory size\n");
ret = -ENOMEM;
goto rel_fw;
}

while (offset < fw->size) {
dev_info(dev, "fw_size 0x%lx, offset 0x%lx\n", fw->size, offset);

chunk_size = min((size_t)PAGE_SIZE, fw->size - offset);

// if (!IS_ALIGNED(mem_paddr + offset, PAGE_SIZE)) {
//     dev_err(dev, "Memory access is not page aligned!\n");
//     ret = -EINVAL;
//     goto rel_fw;
// }
mem_vaddr = memremap(mem_paddr + offset, chunk_size, MEMREMAP_WB);
if (!mem_vaddr) {
dev_err(dev, "failed to remap reserved memory region\n");
ret = -ENOMEM;
goto rel_fw;
}
dev_info(dev, "vaddr received 0x%p, \n", mem_vaddr);

memcpy_toio(mem_vaddr, fw->data + offset, chunk_size);
dev_info(dev, "Copied %ld bytes to reserved memory at offset 0x%lx\n", chunk_size, offset);

memunmap(mem_vaddr);

offset += chunk_size;
}

rel_fw:
release_firmware(fw);

return ret;
}

static int com2_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "firmware loader module removed\n");
return 0;
}

static const struct of_device_id com2_of_match[] = {
{ .compatible = "xlnx,reserved-memory", },
{},
};
MODULE_DEVICE_TABLE(of, com2_of_match);

static struct platform_driver com2_driver = {
.probe = com2_probe,
.remove = com2_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = com2_of_match,
},
};

module_platform_driver(com2_driver);

MODULE_ALIAS("platform:" DRV_NAME);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("com2 driver");
Размер файла прошивки составляет около 3 МБ, а область, зарезервированная в оперативной памяти, — 16 МБ.
В идеале я хотел бы сопоставить весь регион один раз. а затем просто скопируйте полный битовый поток прошивки в область памяти, но во время memcpy() происходит сбой ядра. Вот почему я копирую данные частями по 4 КБ, чтобы сузить источник ошибки.
После успешного копирования некоторых фрагментов данных внезапно происходит сбой. Заметил, что не всегда крашится по одному и тому же физическому адресу. Иногда перед сбоем копируется 1/3 данных, а иногда всего несколько Кбайт.
Это вывод ошибки:

Код: Выделить всё

[  127.396751] com2 xlnx-com2@8000000: firmware size: 3652740 bytes
[  127.396801] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0x0
[  127.396819] com2 xlnx-com2@8000000: vaddr received 0x00000000e1ff176d,
[  127.396831] com2 xlnx-com2@8000000: Copied 4096 bytes to reserved memory at offset 0x0
[  127.396837] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0x1000
[  127.396844] com2 xlnx-com2@8000000: vaddr received 0x000000003e2c1ae9,
[  127.396854] com2 xlnx-com2@8000000: Copied 4096 bytes to reserved memory at offset 0x1000
[  127.396860] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0x2000
[  127.396866] com2 xlnx-com2@8000000: vaddr received 0x00000000edb34175,
[  127.396876] com2 xlnx-com2@8000000: Copied 4096 bytes to reserved memory at offset 0x2000
[  127.396957] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0x3000
.
.
(I removed some printlogs here to shorten the output...)
.
.
[  127.400867] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0xbe000
[  127.400873] com2 xlnx-com2@8000000: vaddr received 0x00000000a7c0dd17,
[  127.400881] com2 xlnx-com2@8000000: Copied 4096 bytes to reserved memory at offset 0xbe000
[  127.400887] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0xbf000
[  127.400893] com2 xlnx-com2@8000000: vaddr received 0x00000000c459ba52,
[  127.400901] com2 xlnx-com2@8000000: Copied 4096 bytes to reserved memory at offset 0xbf000
[  127.400906] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0xc0000
[  127.400913] com2 xlnx-com2@8000000: vaddr received 0x000000001477362a,
[  127.400921] com2 xlnx-com2@8000000: Copied 4096 bytes to reserved memory at offset 0xc0000
[  127.400927] com2 xlnx-com2@8000000: fw_size 0x37bc84, offset 0xc1000
[  127.400941] Unable to handle kernel paging request at virtual address 30a1001cb9f45354
[  127.409371] Mem abort info:
[  127.412169]   ESR = 0x0000000096000004
[  127.415917]   EC = 0x25: DABT (current EL), IL = 32 bits
[  127.421234]   SET = 0, FnV = 0
[  127.424283]   EA = 0, S1PTW = 0
[  127.427420]   FSC = 0x04: level 0 translation fault
[  127.432296] Data abort info:
[  127.435167]   ISV = 0, ISS = 0x00000004
[  127.439000]   CM = 0, WnR = 0
[  127.441965] [30a1001cb9f45354] address between user and kernel address ranges
[  127.449109] Internal error: Oops: 0000000096000004 [#1] PREEMPT_RT SMP
[  127.449117] Modules linked in: com2(OE+) - XXXXXXXX
[  127.449187] CPU: 2 PID: 1192 Comm: insmod Tainted: G           OE      6.1.33-rt11-31 #1
[  127.449195] Hardware name: XXXXXXXXXX
[  127.449199] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[  127.449206] pc : region_intersects+0x78/0xf8
[  127.449221] lr : region_intersects+0x40/0xf8
[  127.449229] sp : ffffff800839b820
[  127.449231] x29: ffffff800839b820 x28: ffffff80080c0000 x27: 0000000000001000
[  127.449241] x26: 0000000008000000 x25: ffffffc000a0c118 x24: ffffffc000a0c160
[  127.449249] x23: 0000000001000200 x22: 0000000000000000 x21: 00000000080c1000
[  127.449258] x20: ffffffc008fd1090 x19: 0000000000000000 x18: 0000000000000020
[  127.449267] x17: 000058d800005ce8 x16: 000061300000d160 x15: ffffff8004e93c90
[  127.449275] x14: 0000000000000000 x13: ffffffc009154542 x12: ffffffc00915453b
[  127.449284] x11: 6d656d2064657672 x10: 000000000000000a x9 : ffffffc0089dd534
[  127.449293] x8 : 000000000000000a x7 : 000000000000000f x6 : 00000000fffff40b
[  127.449301] x5 : ffffff807fe6c8d8 x4 : 30a1001cb9f4533c x3 : 30a0000330e00017
[  127.449310] x2 : 10d6000011130000 x1 : 00000000080c1fff x0 :  0000000000000001
[  127.449319] Call trace:
[  127.449321]  region_intersects+0x78/0xf8
[  127.449331]  memremap+0x38/0x238
[  127.449341]  com2_probe+0x1bc/0x25c [com2]
[  127.449359]  platform_probe+0x70/0xe0
[  127.449368]  really_probe+0xc4/0x2b0
[  127.449374]  __driver_probe_device+0x80/0x120
[  127.449380]  driver_probe_device+0x44/0x120
[  127.449385]  __driver_attach+0x7c/0x130
[  127.449391]  bus_for_each_dev+0x78/0xd0
[  127.449401]  driver_attach+0x2c/0x38
[  127.449410]  bus_add_driver+0x15c/0x210
[  127.449418]  driver_register+0x6c/0x128
[  127.449424]  __platform_driver_register+0x30/0x40
[  127.449431]  com2_driver_init+0x28/0x1000 [com2]
[  127.449445]  do_one_initcall+0x50/0x2e0
[  127.449453]  do_init_module+0x50/0x1f8
[  127.449462]  load_module+0x1828/0x1d50
[  127.449470]  __do_sys_finit_module+0xc0/0x118
[  127.449478]  __arm64_sys_finit_module+0x28/0x38
[  127.449485]  invoke_syscall+0x4c/0x110
[  127.449494]  el0_svc_common.constprop.0+0x4c/0xf8
[  127.449501]  do_el0_svc+0x24/0x30
[  127.449509]  el0_svc+0x20/0x60
[  127.449518]  el0t_64_sync_handler+0xb8/0xc0
[  127.449526]  el0t_64_sync+0x174/0x178
[  127.449536] Code: eb0202bf 1a938673 f9401884 b4000224 (f9400c83)
похоже на ошибку страницы или доступ к несуществующей виртуальной странице.
Будем очень благодарны за любую помощь или подсказку. Спасибо!
Я следовал документации xilinx по зарезервированной памяти: https://xilinx-wiki.atlassian.net/wiki/ ... d+Memory.Я также пытался удалить no-map, так что посмотрите, повлияет ли это... но я все равно получаю ту же ошибку.

Подробнее здесь: https://stackoverflow.com/questions/790 ... via-module
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Linux»