Перейти к содержанию
    

Undefined instruction, Data Abort, SWI - помогите локализовать проблему!

Тупой вопрос, но уже месяц не могу найти концов. Спецы, помогите!

 

Имеется отладочная плата at91sam9263-ek (то есть железо как мне кажется рабочее). Приложение работает, вроде бы все нормально. Но. Периодически возникают прерывания Undefined instruction, Prefetch abort, Data abort и Software interrupt. Возникают в произвольный момент времени. То есть иногда программа идет по одной и той же ветке нормально, иногда в какой то момент возникает прерывание.

Я могу понять причины Undefined instruction, ну скажем не туда что то записал (код из SDRAM исполняется), но SWI почему тогда возникает?

Смотрю отладчиком:

 

backtrace

#0 0x0000000c in ?? () // исключение по prefetch abort

#1 0xdfff9f36 in ?? () // предыдущее значение PC - из неиспользуемого диапазона, такое обращение и должно вызвать abort

 

Притом что никакой динамической памяти, передачи функции в качестве параметра и т.п. у меня не используется, все структуры статические.

 

Проект слинкован под SDRAM, собирается gcc-4.2.2, newlib-1.16.0.

 

Более конкретно вопросы:

 

1. SWI (software, не spurious), случайно возникает, хотя нигде в коде не используется - непонятно, как?

 

2. В gcc был (есть?) баг, касающийся генерации прологов/эпилогов в прерываниях, но у меня обработчики взяты из атмеловских примеров, ниже приведу их. Там и вложенность поддерживается и общий стек используется, переполнения быть не должно.

Тут вроде как все норм должно быть? Или я еще какой то тонкости не понимаю?

 

3. Программа попадает в прерывание, я отладчиком вижу конечное состояние и стек, но это мало чего дает, может есть еще какие то способы получить информацию о предыстории?

 

Вот мой стартап, обработчик FIQ скопирован с IRQ, выкидывать лишнее не стал для уверенности что не в нем проблема.

#define FIQ_STACK_SIZE   8*3*4
#define IRQ_STACK_SIZE   8*3*4

#define ARM_MODE_ABT     0x17
#define ARM_MODE_FIQ     0x11
#define ARM_MODE_IRQ     0x12
#define ARM_MODE_SVC     0x13

#define I_BIT            0x80
#define F_BIT            0x40

//------------------------------------------------------------------------------
//         Startup routine
//------------------------------------------------------------------------------

           .align      4
           .arm

/* Exception vectors
*******************/
           .section    .vectors, "a", %progbits

resetVector:
       ldr     pc, =resetHandler       /* Reset */
undefVector:
       b       undefVector             /* Undefined instruction */
swiVector:
       b       swiVector               /* Software interrupt */
prefetchAbortVector:
       b       prefetchAbortVector     /* Prefetch abort */
dataAbortVector:
       b       dataAbortVector         /* Data abort */
reservedVector:
       b       reservedVector          /* Reserved for future use */
irqVector:
       b       irqHandler              /* Interrupt */
fiqVector:
//      b       fiqHandler              /* Fast interrupt */
//------------------------------------------------------------------------------
/// Handles a fast interrupt request by branching to the address defined in the
/// AIC.
//------------------------------------------------------------------------------
fiqHandler:

/* Save interrupt context on the stack to allow nesting */
       sub     lr, lr, #4
       stmfd   sp!, {lr}
       mrs     lr, SPSR
       stmfd   sp!, {r0, lr}

/* Write in the FVR to support Protect Mode */
       ldr     lr, =AT91C_BASE_AIC
       ldr     r0, [lr, #AIC_FVR]
       str     lr, [lr, #AIC_FVR]

/* Branch to interrupt handler in Supervisor mode */
       msr     CPSR_c, #ARM_MODE_SVC | F_BIT | I_BIT
       stmfd   sp!, {r1-r3, r4, r12, lr}
       blx     r0

/* Restore scratch/used registers and LR from User Stack */
/* Disable Interrupt and switch back in FIQ mode */
       ldmia   sp!, {r1-r3, r4, r12, lr}
       msr     CPSR_c, #ARM_MODE_FIQ | F_BIT | I_BIT

/* Acknowledge interrupt */
       ldr     lr, =AT91C_BASE_AIC
       str     lr, [lr, #AIC_EOICR]

/* Restore interrupt context and branch back to calling code */
       ldmia   sp!, {r0, lr}
       msr     SPSR_cxsf, lr
       ldmia   sp!, {pc}^

//------------------------------------------------------------------------------
/// Handles incoming interrupt requests by branching to the corresponding
/// handler, as defined in the AIC. Supports interrupt nesting.
//------------------------------------------------------------------------------
irqHandler:

/* Save interrupt context on the stack to allow nesting */
       sub     lr, lr, #4
       stmfd   sp!, {lr}
       mrs     lr, SPSR
       stmfd   sp!, {r0, lr}

/* Write in the IVR to support Protect Mode */
       ldr     lr, =AT91C_BASE_AIC
       ldr     r0, [lr, #AIC_IVR]
       str     lr, [lr, #AIC_IVR]

/* Branch to interrupt handler in Supervisor mode */
       msr     CPSR_c, #ARM_MODE_SVC
       stmfd   sp!, {r1-r3, r4, r12, lr}
       blx     r0

/* Restore scratch/used registers and LR from User Stack */
/* Disable Interrupt and switch back in IRQ mode */      
       ldmia   sp!, {r1-r3, r4, r12, lr}
       msr     CPSR_c, #ARM_MODE_IRQ | F_BIT | I_BIT

/* Acknowledge interrupt */
       ldr     lr, =AT91C_BASE_AIC
       str     lr, [lr, #AIC_EOICR]

/* Restore interrupt context and branch back to calling code */
       ldmia   sp!, {r0, lr}
       msr     SPSR_cxsf, lr
       ldmia   sp!, {pc}^

//------------------------------------------------------------------------------
/// Initializes the chip and branches to the main() function.
//------------------------------------------------------------------------------
           .section    .text
           .global     entry

entry:
resetHandler:

/* Useless instruction for referencing the .vectors section */
       ldr     r0, =resetVector

/* Set pc to actual code location (i.e. not in remap zone) */
    ldr     pc, =1f

/* Initialize the prerelocate segment */
1:
       ldr     r0, =_efixed
       ldr     r1, =_sprerelocate
       ldr     r2, =_eprerelocate
1:
       cmp     r1, r2
       ldrcc   r3, [r0], #4
       strcc   r3, [r1], #4
       bcc     1b

/* Perform low-level initialization of the chip using LowLevelInit() */
       ldr     sp, =_sstack
       stmfd   sp!, {r0}
    ldr     r0, =LowLevelInit
       blx     r0

/* Initialize the postrelocate segment */

       ldmfd   sp!, {r0}
       ldr     r1, =_spostrelocate
       ldr     r2, =_epostrelocate
1:
       cmp     r1, r2
       ldrcc   r3, [r0], #4
       strcc   r3, [r1], #4
       bcc     1b

/* Clear the zero segment */
    ldr     r0, =_szero
       ldr     r1, =_ezero
       mov     r2, #0
1:
       cmp     r0, r1
       strcc   r2, [r0], #4
       bcc     1b

/* Setup stacks
**************/
/* FIQ mode */
       msr     CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
       ldr     sp, =_sstack
       sub     r4, sp, #FIQ_STACK_SIZE

/* IRQ mode */
       msr     CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
       mov     sp, r4
       sub     r4, sp, #IRQ_STACK_SIZE

/* Supervisor mode (interrupts enabled) */
       msr     CPSR_c, #ARM_MODE_SVC
       mov     sp, r4

/* Branch to main()
******************/
       ldr     r0, =main
       blx     r0

/* Loop indefinitely when program is finished */
1:
       b       1b

 

 

Буду благодарен любым соображениям! Подскажите хоть что нибудь. Может кто натолкнет на мысль.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. SWI (software, не spurious), случайно возникает, хотя нигде в коде не используется - непонятно, как?

Возникает по той же причине, что и undefined instruction. Просто этой инструкцией иногда случайно оказывается SWI.

 

2. В gcc был (есть?) баг, касающийся генерации прологов/эпилогов в прерываниях, но у меня обработчики взяты из атмеловских примеров, ниже приведу их. Там и вложенность поддерживается и общий стек используется, переполнения быть не должно.

Тут вроде как все норм должно быть? Или я еще какой то тонкости не понимаю?

Т.к. пролог и эпилог заключены в стартапе, то проблем быть не должно. Если, конечно, не продублировать их в C-обработчиках.

 

3. Программа попадает в прерывание, я отладчиком вижу конечное состояние и стек, но это мало чего дает, может есть еще какие то способы получить информацию о предыстории?

Как минимум можно посмотреть LR_irq (или другого режима, в котором оказались) и узнать, откуда программа попала в исключение.

В большинстве случаев адреса и содержимого регистров достаточно для локализации проблемы. Если не помогает, то можно посмотреть и

стек, только убедитесь, что он принадлежит исходному режиму.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3. Программа попадает в прерывание, я отладчиком вижу конечное состояние и стек, но это мало чего дает, может есть еще какие то способы получить информацию о предыстории?

Что значит "мало"? В этом все есть и откуда вылетели, соответственно команда, текст, по стеку и листингу раскручивается и история вызовов, если нужно идти вглубь. Все, как на ладошке.

Ну а по простому ошибка "номер раз" приводящая к необъяснимым явлениям это проблемы с размером стека.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот смотрю LR:

 

#0 0x0000 0004

#1 0x2000 20A4 at main.c....

#2 0xE24E E004

 

В LR не могло оказаться 0xE24E E004, там вообще нет кода, это зарезервированный диапазон адресов.

То есть действительно стек запорчен? Но под стек места полно и непонятно как туда что то попало.

 

Вот мой линкер-скрипт, может я тут чего накосячил?

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(entry)

MEMORY
{
   sram (W!RX)  : ORIGIN = 0x300000, LENGTH = 0x10000
   sdram (W!RX) : ORIGIN = 0x20000000, LENGTH = 32M
   sdram_nocache (W!RX) : ORIGIN = 0x22000000, LENGTH = 32M
}

SECTIONS
{  
   .fixed :
   {
       . = ALIGN(4);
       _sfixed = .;
       *(.text*)
       *(.glue_7)
       *(.glue_7t)
       *(.rodata*)
       *(.data)
       . = ALIGN(4);
       _efixed = .;
   } > sdram

   .prerelocate : AT (_efixed)
   {
       . = ALIGN(4);
       _sprerelocate = .;
       . = ALIGN(4);
       _eprerelocate = .;
   }

   .postrelocate : AT (_efixed + SIZEOF(.prerelocate))
   {
       . = ALIGN(4);
       _spostrelocate = .;
       *(.vectors)
       *(.ramfunc)
       . = ALIGN(4);

       _epostrelocate = .;
   } > sram

   .bss (NOLOAD) : 
   {
       _szero = .;
       *(.bss)
       _ezero = .;
   } > sdram

   .nocache (NOLOAD) : 
   {
       *(.nocache)
   } > sdram_nocache

   _sstack = 0x22000000;
}
end = .;

 

Область 0x22000000 - 0x24000000 отведена под буферы и не кэшируется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Стартап я в первом посте привел, уже много раз все пересмотрел - не пойму что не так.

 

Объясните, как может получиться такая ситуация

backtrace

#0 0x0000 0004

#1 0x2000 20A4 at main.c....

#2 0xE24E E004

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но под стек места полно и непонятно

Вопрос на засыпку, сколько стеков у Вашего ARM? В каком режиме работаете? Из какого режима вылетели в Аборт? А "полно", это достаточно для работы?

 

Объясните, как может получиться такая ситуация

Без понятия, что значат всякие приведенные Вами цифири и как Вы их получали, посему ответа не будет.

Вот, например, распечатка вылета на Data Abort, по которой видно текущее состояние:

Abort:[D] PC:00016AF0 Op:E5D00020 CPSR:6000001F
   LR:00014BF4 SP:400059C0
SP[0]:00000022->00014BF4->00000016->0001381C->
SP[4]:40000EBC->40000E70->00000004->40002D4C
R0:00430001 R1:00000000 R2:00027190 R3:00000000  R4:40002D4C  R5:00026D40
R6:00000000 R7:40001698 R8:00000001 R9:00000004 R10:00000FFF R11:400034D4
R12:00000000

И можно о чем-то рассуждать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверьте, правильно ли заполнена таблица векторов прерываний с адреса 0х00000000.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот, например, распечатка вылета на Data Abort, по которой видно текущее состояние:

Data Abort это наиболее простая проблема, но по вашей распечатке не ясно содержание какого SP выведено. Тот что "DAbt SP" - смотреть бессмыслено, надо смотреть SP и стек контекст предыдущего режима, из которого ввалились в Abort. Prefetch Abort тоже относительно прост, LR SYS/SVSR режима будет содержать то место откуда прыгнули в недоступную область памяти.

 

В случае же Undef / Swi найти тот LR, что нужно очень не просто т.к. проц выполняет уже совсем не код программы, а просто какой-то мусор со случайного адреса.

если вдобавок еще и SYS / SVSR SP подпорчен, то практически нереально будет найти то место из которого осуществлен прыжек... Здесь нужен более глубойкий анализ дампа нежели только значения регистров.

 

как причина вышеописанного поведения из наиболее часто встечающихся в порядке убывания такие:

 

1. Перетирание стека упомянутое выше, по причине нехватки стека - решение: не жлобитесь, на железках с 32/64MB памяти отведите 1-2MB под стек (напр 64KB под задачу) и забудьте что такое проблемы со стеком навсегда.

2. Перетирание стека по причине выхода за границу массива, если есть массивы объявленные в стеке самое время посмотреть а все ли с ними в порядке.

3. NULL pointer в результате которого перетирается таблица векторов, тут имеет смысл анализировать дампы только с Data/Prefetch Abort'ами - их анализ будет самым эффективным.

4. Непроинициализированные поля / переменные. - очень сложная ситуация...

5. сбоит SDRAM - портится значение бита ячейки содержащей какой-нить callback. или что еще хуже - corruption непосредственно в секции кода. Здесь главное убедиться что в некой ячейке изменяется строго один бит, ну а дальше выявить регулярность и найти соотв. проблемную линию / попробовать изменить параметры SDRAM контроллера, если не поможет, - фиксить аппартный баг, вплоть до замены м/c памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но по вашей распечатке не ясно содержание какого SP выведено.

Поскольку SP, Abort режима, как Вы правильно заметили, бессмысленен с точки зрения локализации проблемы, то выводить его мне было-бы ОЧЕНЬ странно. Посему совершено очевидно какой стек распечатан. Это точно так-же очевидно по содержимому CPSR, он ведь не Exception Mode показывает, а вполне себе System Mode не правда-ли :)? Кстати, по нему-же видно, что вывалились не из обработчика прерывания или секции с закрытыми прерываниями - тоже информация.

И для именно для того, что-бы понять куда (чего как-раз не видно по распечатке) попали, и есть специальный индикатор Abort:[D] - значение которого я специально в посте и расшифровал - "Data Abort". Так-что никаких непоняток в распечатке нет.

В случае же Undef / Swi найти тот LR, что нужно очень не просто т.к. проц выполняет уже совсем не код программы, а просто какой-то мусор со случайного адреса.

Тем не менее, он далеко не обязательно попал туда через МНОЖЕСТВЕНЫЕ call. Ну в моем случае, распечатка состояния производится уже в отладочной консоли загрузчика - гипотетически можно и мусор по которому бежали порасшифровывать, благо PC есть (замечу, что тоже "тот" :) ). В свое время для некоторых процессоров в консоли у меня и дизассемблер был. Ну в случае НЕ мусора, несколько вызовов обычно уже видны в стеке и вычисляются по листингу.

P.S.

Приведенная распечатка вылета, кстати, была прислана из-за границы за несколько часов до этого заказчиком ведущими проверку софта с добавленной функциональностью на железе которого у меня вообще нет :). Проблема с различием структур данных была по этой распечатке решена минут за 20. Случай был практически (в структурах было совсем не то) такой:

4. Непроинициализированные поля / переменные. - очень сложная ситуация...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос на засыпку, сколько стеков у Вашего ARM? В каком режиме работаете? Из какого режима вылетели в Аборт? А "полно", это достаточно для работы?

 

Стеки организованы так: по 0х2200 0000 лежит стек FIQ, ниже стек IRQ, ниже стек Supervisor. "Полно" - это неск Мб, судя по мэпу. Программа все время сидит в SVC, обработчик прерываний организован так: сохраняем в стек IRQ, потом переключаемся в SVC и выполняем прерывание в нем, по завершении обратно в IRQ, подтверждаем и выходим в SVC. Соответственно стек IRQ небольшой, а стека SVC большой, его должно хватить.

Нормально ли, что стек у меня в середине памяти, а над ним и до конца памяти еще отдельная секция под буферы? Просто мне показалось так удобней сделать для некэшируемых буферов.

 

что значат всякие приведенные Вами цифири

 

Это результат выданный мне командой backtrace. В нормальном состоянии программы я по этим строчкам вижу цепочку вызовов, то есть это вроде как значения LR? Когда возникает глюк, backtrace выдает не знаю что, может он как то неправильно разбивает стек на фреймы и не может понять откуда был вызов? Но в любом случае видно что 0xe24ee004 - адрес из которого код не мог быть исполнен и не мог оттуда вызов быть.

Как от gdb получить подробную распечатку, как у Вас приведено? Не пинайте, я с gdb знаком недавно :)

 

Проверьте, правильно ли заполнена таблица векторов прерываний с адреса 0х00000000.

 

Правильно.

 

Вот типичный случай как выглядит:

 

"$cpsr" = 0x2000009b - Undefined instruction

sp 0x00000000 - sp для Undef не инициализирован, вместо обработчика беск цикл

"$lr" = 0x200020f8

"$pc" = 0x00000004

 

 

backtrace дает вот что:

 

#0 0x00000004 in ?? ()

#1 0x200020f8 in ISR_SPI1 () at main.c:1069

#2 0xe24ee004 in ?? ()

Backtrace stopped: frame did not save the PC

 

То есть из main.c:1069 как то попали в exceiption...

Как непонятно..

Dump of assembler code from 0x200020f0 to 0x20002100:

0x200020f0 <ISR_SPI1+272>: add lr, r12, #1 ; 0x1

0x200020f4 <ISR_SPI1+276>: add r2, lr, #1 ; 0x1

0x200020f8 <ISR_SPI1+280>: ldr r3, [pc, #1424] ; 0x20002690 <ISR_SPI1+1712>

0x200020fc <ISR_SPI1+284>: str r2, [r6]

End of assembler dump.

 

Глюк происходит редко, поэтому поставил в main.c:1069 брейкпоинт и посмотрел как оно в норме, вот так:

bt

#0 ISR_SPI1 () at main.c:1069

#1 0x00000088 in ?? ()

#2 0x20003b24 in AIC_ConfigureIT (source=<value optimized out>, mode=8, handler=0xffff) at at91lib/peripherals/aic/aic.c:61

#3 0x000007fe in ?? ()

#4 0xcc33cc32 in ?? ()

Backtrace stopped: frame did not save the PC

 

Тут похоже backtrace путается из-за обработчика прерываний, поэтому строчки #1-4 какие то бессмысленные. AIC_ConfigureIT из второй строки здесь вообще не вызывается, проверял, брейкпойнт на ней ставил.

 

Это наиболее частый случай я тут привел, а вообще то глюки возникают иногда еще до разрешения прерываний.

 

1. Перетирание стека...

 

Смотрю по мар-файлу, неск Мб от последней переменной до начала стека

 

2. Перетирание стека по причине выхода за границу массива, если есть массивы объявленные в стеке самое время посмотреть а все ли с ними в порядке.

 

Структуры объявлены, но обращаюсь к полям стандартным образом, без особых хитростей...

 

3. NULL pointer в результате которого перетирается таблица векторов, тут имеет смысл анализировать дампы только с Data/Prefetch Abort'ами - их анализ будет самым эффективным.

 

malloc/calloc не использую, вроде не должно...

 

4. Непроинициализированные поля / переменные. - очень сложная ситуация...

 

Можете подробнее, что имеется в виду? Кроме обращения по указателю который равен 0.

 

5. сбоит SDRAM

 

Ситуация слабоповторяемая, то сбоит, то не сбоит. То есть запускаю определенную функцию в программе, может на 3-й раз посыпаться, может на 10-й... Плата - отладка Атмеловская. Могут на такой плате быть проблемы из-за плохой разводки? Или это больше относится к своим платам?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

backtrace выдает не знаю что..

Я тоже не знаю :( :)

Как от gdb получить подробную распечатку, как у Вас приведено? Не пинайте, я с gdb знаком недавно :)

Не знаю, эта моя собственная распечатка при вылете, как уже писал, в аварийную консоль. Отладчиками пользуюсь крайне редко, ибо самое интересное случается за тысячи километров на объектах, а там никаких подключенных JTAG адаптеров, отладчиков, компиляторов и т.д. просто нет не было и не будет.

Стеки организованы так: по 0х2200 0000 лежит стек FIQ, ниже стек IRQ, ниже стек Supervisor. "Полно" - это неск Мб, судя по мэпу.

Какие такие "Mб", если стеки FIQ и IRQ черным по белому записаны у Вас по 24 слова!!! Да и инициализированы только три стека.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы бы взяли и прислали свой проект, если он не сов.секретный? Дистанционно вас пытать, что к чему, не очень продуктивно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Какие такие "Mб", если стеки FIQ и IRQ черным по белому записаны у Вас по 24 слова! Да и инициализированы только три стека.

 

Ну я же описал, как работает обработчик прерывания. Сам код прерывания выполняется в SVC. Посему и стеки по 24 слова, а Мб - это стек SVC. Инициализированы только три стека, потому что обработчики остальных исключений отсутствуют

 

backtrace выдает не знаю что..

 

Неправда, я привел то, что выдает backtrace. Проанализировать не могу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посему и стеки по 24 слова, а Мб - это стек SVC. Инициализированы только три стека, потому что обработчики остальных исключений отсутствуют

По этой причине будем парить мозги и себе, и людям, и отладчику, но не проинициализируем все (вылетать в них будем, но инициализировать ни за что) стеки и не сделаем при наличии мегабайтов тот-же IRQ/FIQ в десяток-другой раз больше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...