I am working on an arm-linux board that has a couple of PCI slots on it.
I wanted to check the vendor IDs / device IDs of the PCI modules in UBoot. So I ported the initialization portion of the PCI driver from linux to UBoot.
The Hack:
Since the PCI topology on my board is fixed, I took the liberty of hardcoding the bus numbers(pirmary, secondary, subordinate) in UBoot, so I dont have to port the enumeration code to UBoot. To get the bus numbers I had written a small loadable kernel module that gets me the device bus numbers once the kernel is done with enumerating devices on the PCI bus.
Problem: Now, if the modules are present in PCI slots, I am able to read their IDs successfully. But if a module is not present and I try to read its IDs, I get hit by ARM's data abort handler.
Is the are a way around to this data abort exception, or knowing in advance if the slot is populated or not before trying to read the IDs.
Update 1: I modified UBoot source according to auselen's input as follows:
start.S
//Added following macro
.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
Changed data_abort code as follows
data_abort:
get_bad_stack
irq_save_user_regs
bl do_data_abort
irq_restore_user_regs_mod
interrupts.c Modified do_data_abort to
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 Portion of code that attempts to read possibly invalid address
printf("Trying possibly invalid address\n");
flag = 1;
data = *((volatile unsigned int *)(0xbe200000)) ;
if (flag == 0) printf("Bad address \n");
flag = 1;
Concerned Portion of UBoot Log:
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 ...
What I suspect is that *irq_restore_user_regs_mod* is sending UBoot back to *do_data_abort*. So 1st time when do_data_abort executes the flag is 1, do_data_abort changes the flag to 0, irq_restore_user_regs_mod sends the UBoot back to do_data_abort. Since the flag is 0 UBoot enters into bad mode.
Kindly tell me whether I should use
MOVS PC, LR
or
MOV PC, LR
in irq_restore_user_regs_mod (command in code snippet is different from the text).
Also please elaborate why you used MOV(S) PC, LR instead of SUBS PC, LR, #4 .
Update 2: (in light of auselen's comments)
i) Changed flag from simple int to volatile ii) Added printf(s) in interrupts.c for debugging purposes as follows:
printf("flag = %d\n",flag);
if (flag == 1)
{
flag = 0;
printf("FLAG = %d\n",flag);
return;
}
iii) Added asm volatile("" ::: "memory");
before and after making data abortable access, in file mypcie.c
flag = 1;
asm volatile("" ::: "memory");
data = *((volatile unsigned int *)(0xbe200000)) ;
asm volatile("" ::: "memory");
if (flag == 0) printf("Bad address \n");
Results
UBoot Log 1:
Trying possibly invalid address
flag = 1
FLAG = 0
flag = 1
FLAG = 0
(continues forever)
It seems that control kept returning to flag=1; instruction in mypcie.c If I comment out this instruction, and initialize flag to 1 outside of this function, then I get the following log:
UBoot Log 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 ...
Now It looks as if following instruction executed twice:
data = *((volatile unsigned int *)(0xbe200000)) ;
In 2nd execution flag was 0, so we hit the data abort.
Update 3 (In light of auselen's comment regarding MOV, MOVS and SUBS) removed -O2 flag from config.mk file in UBoot Directory.
UBoot Logs
Using 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 ...
Using 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 ...