2014-01-20 41 views
2

我正在一個arm-linux板上有幾個PCI插槽。PCI枚舉黑客結束數據中止異常

我想檢查UBoot中PCI模塊的供應商ID /設備ID。 因此,我將PCI驅動程序的初始化部分從linux移植到UBoot。

的哈克: 由於我的船上的PCI拓撲結構是固定的,我把硬編碼的巴士號碼(pirmary,二次,下屬)在UBOOT的自由,所以我沒有端口枚舉代碼UBOOT 。爲了獲得總線編號,我編寫了一個小型可加載的內核模塊,一旦內核完成枚舉PCI總線上的設備,我就可以獲得總線編號 設備

問題: 現在,如果模塊存在於PCI插槽中,我可以成功讀取它們的ID。 但是,如果一個模塊不存在,並且我嘗試讀取它的ID,那麼我可以通過ARM的數據中止處理程序

是否解決此數據中止異常,或在嘗試讀取ID之前事先知道插槽是否已填充。


更新1: 我根據auselen的輸入改性UBOOT源如下:

start.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 

interrupts.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執行標誌時的第一次是1,do_data_abort將標誌更改爲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的評論光)

ⅰ)從簡單int改爲標誌在揮發性 ⅱ)增補的printf(S)interrupts.c用於調試目的如如下:

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

III)新增asm volatile("" ::: "memory");之前,使數據可中止訪問後,在文件mypcie.c

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) 

似乎控制保持返回標誌= 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評論的光) 取出-02在UBOOT目錄config.mk文件標誌。

UBOOT日誌

使用潛艇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 ... 

使用潛艇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 ... 
+1

您也可以更改數據中止處理程序以及跳轉到下一條指令。 – auselen

+0

感謝auselen,但不是最好不要在第一個地方得到例外嗎?就像是在進行交易之前檢查目標地址是否有效一樣。此外,處理器現在將處於中止模式。 – microMolvi

+1

與芯片/供應商專用於檢測板卡的根聯合體進行通話。你可能不需要做一個完整的枚舉(反正這個並不複雜),但足以不盲目地談論那些可能導致數據中止的東西。我假設pcie控制器正在導致中止,並且只要您嘗試與那裏沒有的東西交談就會繼續。 –

回答

1

我沒有試試這個我的自我,但應該能夠修改u-boot來處理數據中止durin g某些地址訪問。

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

data_abort: 
     get_bad_stack 
     bad_save_user_regs 
     bl  do_data_abort 

它從代碼與irq_save_user_regs/irq_restore_user_regs*對就像IRQ/FIQ的處理來改變bad_save_user_regs需求似乎。製作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 
+0

請看更新2 – microMolvi

+1

@microMolvi它看起來像(從文檔)我錯了關於mov/movs。您應該使用movs從異常中返回。看來我對使用subs也是錯誤的。 '子PC,LR,#4'似乎是回到下一條指令的正確方式,'子PC,LR,#8'將重新執行數據中止指令。 – auselen

+0

irq_restore_user_regs_mod = irq_restore_user_regs now? – microMolvi