Атмег 0 10 августа, 2010 Опубликовано 10 августа, 2010 · Жалоба Тупой вопрос, но уже месяц не могу найти концов. Спецы, помогите! Имеется отладочная плата 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 Буду благодарен любым соображениям! Подскажите хоть что нибудь. Может кто натолкнет на мысль. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 10 августа, 2010 Опубликовано 10 августа, 2010 · Жалоба 1. SWI (software, не spurious), случайно возникает, хотя нигде в коде не используется - непонятно, как? Возникает по той же причине, что и undefined instruction. Просто этой инструкцией иногда случайно оказывается SWI. 2. В gcc был (есть?) баг, касающийся генерации прологов/эпилогов в прерываниях, но у меня обработчики взяты из атмеловских примеров, ниже приведу их. Там и вложенность поддерживается и общий стек используется, переполнения быть не должно. Тут вроде как все норм должно быть? Или я еще какой то тонкости не понимаю? Т.к. пролог и эпилог заключены в стартапе, то проблем быть не должно. Если, конечно, не продублировать их в C-обработчиках. 3. Программа попадает в прерывание, я отладчиком вижу конечное состояние и стек, но это мало чего дает, может есть еще какие то способы получить информацию о предыстории? Как минимум можно посмотреть LR_irq (или другого режима, в котором оказались) и узнать, откуда программа попала в исключение. В большинстве случаев адреса и содержимого регистров достаточно для локализации проблемы. Если не помогает, то можно посмотреть и стек, только убедитесь, что он принадлежит исходному режиму. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 10 августа, 2010 Опубликовано 10 августа, 2010 · Жалоба 3. Программа попадает в прерывание, я отладчиком вижу конечное состояние и стек, но это мало чего дает, может есть еще какие то способы получить информацию о предыстории? Что значит "мало"? В этом все есть и откуда вылетели, соответственно команда, текст, по стеку и листингу раскручивается и история вызовов, если нужно идти вглубь. Все, как на ладошке. Ну а по простому ошибка "номер раз" приводящая к необъяснимым явлениям это проблемы с размером стека. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Атмег 0 11 августа, 2010 Опубликовано 11 августа, 2010 · Жалоба Вот смотрю 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 отведена под буферы и не кэшируется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sergeeff 1 11 августа, 2010 Опубликовано 11 августа, 2010 · Жалоба Обычно места под стеки резервируются в startup'e. Посмотрите там внимательно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Атмег 0 11 августа, 2010 Опубликовано 11 августа, 2010 · Жалоба Стартап я в первом посте привел, уже много раз все пересмотрел - не пойму что не так. Объясните, как может получиться такая ситуация backtrace #0 0x0000 0004 #1 0x2000 20A4 at main.c.... #2 0xE24E E004 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 11 августа, 2010 Опубликовано 11 августа, 2010 · Жалоба Но под стек места полно и непонятно Вопрос на засыпку, сколько стеков у Вашего 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 И можно о чем-то рассуждать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sergeeff 1 11 августа, 2010 Опубликовано 11 августа, 2010 · Жалоба Проверьте, правильно ли заполнена таблица векторов прерываний с адреса 0х00000000. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
defunct 0 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба Вот, например, распечатка вылета на 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 памяти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба но по вашей распечатке не ясно содержание какого SP выведено. Поскольку SP, Abort режима, как Вы правильно заметили, бессмысленен с точки зрения локализации проблемы, то выводить его мне было-бы ОЧЕНЬ странно. Посему совершено очевидно какой стек распечатан. Это точно так-же очевидно по содержимому CPSR, он ведь не Exception Mode показывает, а вполне себе System Mode не правда-ли :)? Кстати, по нему-же видно, что вывалились не из обработчика прерывания или секции с закрытыми прерываниями - тоже информация. И для именно для того, что-бы понять куда (чего как-раз не видно по распечатке) попали, и есть специальный индикатор Abort:[D] - значение которого я специально в посте и расшифровал - "Data Abort". Так-что никаких непоняток в распечатке нет. В случае же Undef / Swi найти тот LR, что нужно очень не просто т.к. проц выполняет уже совсем не код программы, а просто какой-то мусор со случайного адреса. Тем не менее, он далеко не обязательно попал туда через МНОЖЕСТВЕНЫЕ call. Ну в моем случае, распечатка состояния производится уже в отладочной консоли загрузчика - гипотетически можно и мусор по которому бежали порасшифровывать, благо PC есть (замечу, что тоже "тот" :) ). В свое время для некоторых процессоров в консоли у меня и дизассемблер был. Ну в случае НЕ мусора, несколько вызовов обычно уже видны в стеке и вычисляются по листингу. P.S. Приведенная распечатка вылета, кстати, была прислана из-за границы за несколько часов до этого заказчиком ведущими проверку софта с добавленной функциональностью на железе которого у меня вообще нет :). Проблема с различием структур данных была по этой распечатке решена минут за 20. Случай был практически (в структурах было совсем не то) такой: 4. Непроинициализированные поля / переменные. - очень сложная ситуация... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Атмег 0 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба Вопрос на засыпку, сколько стеков у Вашего 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-й... Плата - отладка Атмеловская. Могут на такой плате быть проблемы из-за плохой разводки? Или это больше относится к своим платам? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба backtrace выдает не знаю что.. Я тоже не знаю :( :) Как от gdb получить подробную распечатку, как у Вас приведено? Не пинайте, я с gdb знаком недавно :) Не знаю, эта моя собственная распечатка при вылете, как уже писал, в аварийную консоль. Отладчиками пользуюсь крайне редко, ибо самое интересное случается за тысячи километров на объектах, а там никаких подключенных JTAG адаптеров, отладчиков, компиляторов и т.д. просто нет не было и не будет. Стеки организованы так: по 0х2200 0000 лежит стек FIQ, ниже стек IRQ, ниже стек Supervisor. "Полно" - это неск Мб, судя по мэпу. Какие такие "Mб", если стеки FIQ и IRQ черным по белому записаны у Вас по 24 слова!!! Да и инициализированы только три стека. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sergeeff 1 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба Вы бы взяли и прислали свой проект, если он не сов.секретный? Дистанционно вас пытать, что к чему, не очень продуктивно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Атмег 0 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба Какие такие "Mб", если стеки FIQ и IRQ черным по белому записаны у Вас по 24 слова! Да и инициализированы только три стека. Ну я же описал, как работает обработчик прерывания. Сам код прерывания выполняется в SVC. Посему и стеки по 24 слова, а Мб - это стек SVC. Инициализированы только три стека, потому что обработчики остальных исключений отсутствуют backtrace выдает не знаю что.. Неправда, я привел то, что выдает backtrace. Проанализировать не могу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба Посему и стеки по 24 слова, а Мб - это стек SVC. Инициализированы только три стека, потому что обработчики остальных исключений отсутствуют По этой причине будем парить мозги и себе, и людям, и отладчику, но не проинициализируем все (вылетать в них будем, но инициализировать ни за что) стеки и не сделаем при наличии мегабайтов тот-же IRQ/FIQ в десяток-другой раз больше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться