gpt4 book ai didi

linux - PCI 枚举 hack 以数据中止异常结束

转载 作者:太空狗 更新时间:2023-10-29 12:33:02 28 4
gpt4 key购买 nike

我正在开发一个带有几个 PCI 插槽的 arm-linux 板。

我想检查 UBoot 中 PCI 模块的供应商 ID/设备 ID。所以我将 PCI 驱动程序的初始化部分从 linux 移植到 UBoot。

黑客:由于我板上的 PCI 拓扑是固定的,我冒昧地在 UBoot 中硬编码了总线编号(主要、次要、从属),所以我不必将枚举代码移植到 UBoot。为了获取总线编号,我编写了一个小型可加载内核模块,一旦内核完成 PCI 总线上的枚举设备,它就会为我获取 device 总线编号。

问题:现在,如果模块存在于 PCI 插槽中,我就可以成功读取它们的 ID。但是,如果某个模块不存在并且我尝试读取它的 ID,我就会被 ARM 的数据中止处理程序击中。

是否有解决此数据中止异常的方法,或者在尝试读取 ID 之前提前知道插槽是否已填充。


更新 1:我根据auselen的输入修改了UBoot源码如下:

开始.S

//添加了以下宏

     .macro  irq_restore_user_regs_mod
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
mov pc, lr @ return & move spsr_svc into cpsr
.endm

修改data_abort代码如下

data_abort:
get_bad_stack
irq_save_user_regs
bl do_data_abort
irq_restore_user_regs_mod

中断.c修改 do_data_abort 为

void do_data_abort (struct pt_regs *pt_regs)
{
if (flag == 1)
{
flag = 0;
return;
}
printf ("data abort handler\n");
printf ("Originally installed by U-Boot\n");
show_regs (pt_regs);
bad_mode ();
}

mypcie.c 尝试读取可能无效地址的代码部分

    printf("Trying possibly invalid address\n");
flag = 1;
data = *((volatile unsigned int *)(0xbe200000)) ;
if (flag == 0) printf("Bad address \n");
flag = 1;

UBoot日志关注部分:

Trying possibly invalid address
data abort handler
Originally installed by U-Boot
pc : [<00012150>] lr : [<00012144>]
sp : 46069a00 ip : 78000000 fp : 00000000
r10: 07f7eca4 r9 : 00000000 r8 : 07f7efdc
r7 : 00000000 r6 : 000000f8 r5 : 00000001 r4 : bb000000
r3 : be200000 r2 : 00020b28 r1 : 00000020 r0 : 07f7ea49
Flags: nzcv IRQs on FIQs on Mode USER_32
U-Boot::Resetting CPU ...

我怀疑 *irq_restore_user_regs_mod* 正在将 UBoot 发送回 *do_data_abort*。所以第一次do_data_abort执行时flag为1,do_data_abort将flag改为0,irq_restore_user_regs_mod将UBoot发回给do_data_abort。由于标志为 0,UBoot 进入错误模式。

请告诉我是否应该使用

MOVS PC, LR

MOV PC, LR

irq_restore_user_regs_mod(代码段中的命令与文本不同)。

另外请详细说明为什么您使用MOV(S) PC, LR 而不是SUBS PC, LR, #4


更新 2:(根据 auselen 的评论)

i) 将标志从简单的 int 更改为 volatileii) 在 interrupts.c 中添加了 printf(s) 用于调试目的如下:

printf("flag = %d\n",flag);
if (flag == 1)
{
flag = 0;
printf("FLAG = %d\n",flag);
return;
}

iii) 在文件 mypcie.c 中添加了 asm volatile(""::::"memory");

flag = 1;
asm volatile("" ::: "memory");
data = *((volatile unsigned int *)(0xbe200000)) ;
asm volatile("" ::: "memory");
if (flag == 0) printf("Bad address \n");

结果

UBoot 日志 1:

Trying possibly invalid address
flag = 1
FLAG = 0
flag = 1
FLAG = 0
(continues forever)

似乎控制一直回到flag=1; mypcie.c 中的说明如果我注释掉这条指令,并在这个函数之外将标志初始化为 1,那么我会得到以下日志:

UBoot日志2:

Trying possibly invalid address
flag = 1
FLAG = 0
flag = 0
data abort handler
Originally installed by U-Boot
pc : [<00012174>] lr : [<5306b01e>]
sp : c6a69a08 ip : 78000000 fp : 00000000
r10: 07f7eca1 r9 : 00000000 r8 : 07f7efdc
r7 : 00000000 r6 : 000000fb r5 : 00000001 r4 : bb000000
r3 : be200000 r2 : 00000000 r1 : 00000020 r0 : 07f7ea4d
Flags: nzcv IRQs on FIQs on Mode USER_32
U-Boot::Resetting CPU ...

现在看起来好像下面的指令执行了两次:

data = *((volatile unsigned int *)(0xbe200000))  ;

在第二次执行中,标志为 0,因此我们命中了数据中止。


更新 3(根据 auselen 关于 MOV、MOVS 和 SUBS 的评论)从 UBoot 目录中的 config.mk 文件中删除了 -O2 标志。

UBoot 日志

使用 subs pc, lr, #4

Trying possibly invalid address
flag = 1
FLAG = 0
prefetch abort handler
Originally installed by U-Boot
pc : [<90000004>] lr : [<00012174>]
sp : 07f7eb80 ip : 78000000 fp : 00000000
r10: 00000000 r9 : 00000000 r8 : 07f7efdc
r7 : 00000000 r6 : 00000000 r5 : 00000000 r4 : 00008e00
r3 : 00000000 r2 : c6a68e1c r1 : 00010001 r0 : 00000003
Flags: nZCv IRQs on FIQs on Mode USER_32
U-Boot::Resetting CPU ...

使用 subs pc, lr, #8

Trying possibly invalid address
flag = 1
FLAG = 0
flag = 0
data abort handler
Originally installed by U-Boot
pc : [<00012174>] lr : [<00008e7c>]
sp : c6a68cf4 ip : 78000000 fp : 00000000
r10: 07f7eca1 r9 : 00000000 r8 : 07f7efdc
r7 : 00000000 r6 : 000000fb r5 : 00000001 r4 : bb000000
r3 : be200000 r2 : 00000000 r1 : 00000020 r0 : 07f7ea4d
Flags: nzcv IRQs on FIQs on Mode USER_32
U-Boot::Resetting CPU ...

最佳答案

我自己还没有尝试过,但应该能够修改 u-boot 以处理某些地址访问期间的数据中止。

arch/arm/cpu/armv7/start.S包含

data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort

从代码看来,bad_save_user_regs 需要更改为 irq_save_user_regs/irq_restore_user_regs* 对,就像处理 IRQ/FIQ 一样。使 data_abort 读起来像

data_abort:
get_bad_stack
irq_save_user_regs
bl do_data_abort
irq_restore_user_regs*

do_data_abort 位于 arch/arm/lib/interrupts.c

  void do_data_abort (struct pt_regs *pt_regs)
{
printf ("data abort\n\n MAYBE you should read doc/README.arm-unaligned-accesses\n\n");
show_regs (pt_regs);
bad_mode ();
}

bad_mode 重置 cpu。

一种方法可能是在尝试可能的中止地址之前升起标志,然后在 do_data_abort 中检查标志而不是 bad_mode 如果是这种情况,则降低标志并继续下一条指令,它应该检查标志是否被降低。

[*]返回到下一条指令可以通过 subs PC, LR, #4irq_restore_user_regs 的修改副本中处理。让它读作

          .macro  irq_restore_user_regs_mod
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs PC, LR, #4 @ return & move spsr_svc into
@ cpsr
.endm

关于linux - PCI 枚举 hack 以数据中止异常结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21235303/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com