|
Запрещение и разрешение прерываний |
|
|
|
Jan 25 2016, 02:55
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Я сгенерировал кубом код для STM32F429 и добавляю в него необходимые мне функции. Обнаружил, что вопреки ожиданиям не запрещались прерывания когда следовало их запретить. На 100 процентов не уверен, что это так, но другого обюяснения поведения найти не могу. Вот так определены функции управления запрещением прерывания. Код /** \brief Enable IRQ Interrupts
This function enables IRQ interrupts by clearing the I-bit in the CPSR. Can only be executed in Privileged modes. */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) { __ASM volatile ("cpsie i" : : : "memory"); }
/** \brief Disable IRQ Interrupts
This function disables IRQ interrupts by setting the I-bit in the CPSR. Can only be executed in Privileged modes. */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); } В дисассемблерном коде я не вижу ничего похожего на них. Или я чего-то не разглядел? Посмотрите пожалуйста свежим взглядом.
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 31)
|
Jan 25 2016, 07:32
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 25-09-08
Пользователь №: 40 477

|
Регулярно наблюдаю такие приколы у кокосовского дебаггера (там вроде GDB). Добавьте в "after build" Код "${gcc.home}/arm-none-eabi-objdump -d -S ${project.bin}/${output.name}.elf > ${project.bin}/${output.name}.lst" получите .lst и в нем посмотрите
Сообщение отредактировал johnshadow - Jan 25 2016, 07:32
|
|
|
|
|
Jan 25 2016, 12:19
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Отожмите иконку "Show Source" на рамке окна дизассемблера. Пропавшие команды появятся. Правда исчезнут вкрапления исходного текста в дизассемблер. Цитата(Tarbal @ Jan 25 2016, 13:47)  Картинку я залил воспользовавшись кнопкой в диалоге для сообщения в форуме. Не делал этого раньше. Наверное чтоьто сделал не так. Не, это у нас движок на форуме такой. В следующий раз нажимайте "расширенная форма" и там будет возможность прикрепить файл прямо в сообщение, без внешних файлохранилищ. После выбора и загрузки файла появится возможность вставить его в нужное место сообщения, разберетесь.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 25 2016, 15:25
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Кстати, еще вопрос по той же теме. Нужна функция запрета прерываний, которая при последующем разрешении прерываний сможет точно восстановить предыдущее состояние разрешения прерываний ( I-bit CPSR) для кортекса М3 (stm32f207).
Проблема в том, что если я ручками задвину регистр CPSR в стек и, затем, запрещу прерывания, то при возникновении прерывания между этими двумя командами (а оно может изменить параметры прерываний), я получу не то состояние и не смогу восстановить реальное исходное состояние параметров прерываний.
Может есть команда, которая сразу и запомнит текущее состояние разрешения прерываний в стеке и запретит их? Ну, хотя бы, сохранит регистр CPSR или только его I-bit?
|
|
|
|
|
Jan 25 2016, 19:01
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(rudy_b @ Jan 25 2016, 19:25)  Кстати, еще вопрос по той же теме. Нужна функция запрета прерываний, которая при последующем разрешении прерываний сможет точно восстановить предыдущее состояние разрешения прерываний ( I-bit CPSR) для кортекса М3 (stm32f207).
Проблема в том, что если я ручками задвину регистр CPSR в стек и, затем, запрещу прерывания, то при возникновении прерывания между этими двумя командами (а оно может изменить параметры прерываний), я получу не то состояние и не смогу восстановить реальное исходное состояние параметров прерываний.
Может есть команда, которая сразу и запомнит текущее состояние разрешения прерываний в стеке и запретит их? Ну, хотя бы, сохранит регистр CPSR или только его I-bit? http://stm32f4-discovery.com/2015/06/how-t...n-arm-cortex-m/Цитата(Сергей Борщ @ Jan 25 2016, 16:19)  Отожмите иконку "Show Source" на рамке окна дизассемблера. Пропавшие команды появятся. Правда исчезнут вкрапления исходного текста в дизассемблер. Не, это у нас движок на форуме такой. В следующий раз нажимайте "расширенная форма" и там будет возможность прикрепить файл прямо в сообщение, без внешних файлохранилищ. После выбора и загрузки файла появится возможность вставить его в нужное место сообщения, разберетесь. Спасибо
|
|
|
|
|
Jan 25 2016, 21:22
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Цитата(smalcom @ Jan 25 2016, 21:04)  __disable_irq() оно? Нет, не оно. Эта функция сначала считывает CPSR в регистр, меняет биты в регистре, потом заносит регистр в CPSR. Если в это время произойдет прерываие и CPSR будет изменен - будет плохо. Нужно, чтобы одна ассемблерная команда одновременно и записала CPSR в стек и установила в нем запрет прерывания. И обратная операция - восстановиление CPSR из стека без всяких промежуточных операций в регистрах. Иными словами нужна атомарная операция сохранения старого CPSR в стек с одновременной записью указанного бита в CPSR. Ну и обратная операция - восстановление CPSR из стека. Честно сказать, совершенно не понимаю, как всякие функции HAL работают без этого - они обязательно должны глючить. Там все время пользуют общее разрешение и запрет прерываний. Если при этом нет возможности честно (атомарно, чтобы никто не мог перебить) сохранить исходное состояние бита разрешения прерываний, то это полный песец. Цитата(Tarbal @ Jan 25 2016, 22:01)  Именно так я и делаю, но это не снимает проблемы прерывания между считыванием CPSR и запретом прерываний. Для кортекса определены странные макро типа CFI_ARM_BLOCK_start и CFI_ARM_BLOCK_end, но что это и как этим пользоваться не нашел.
|
|
|
|
|
Jan 26 2016, 00:24
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(rudy_b @ Jan 25 2016, 19:25)  Проблема в том, что если я ручками задвину регистр CPSR в стек и, затем, запрещу прерывания, то при возникновении прерывания между этими двумя командами (а оно может изменить параметры прерываний), я получу не то состояние и не смогу восстановить реальное исходное состояние параметров прерываний. Какие параметры? Какое состояние? Цитата(Сергей Борщ @ Jan 26 2016, 03:11)  Интересно, зачем такое может понадобиться? Общие функции, вызываемые из прерываний и извне прерываний.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 26 2016, 03:42
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Цитата(GetSmart @ Jan 26 2016, 03:24)  Какие параметры? Какое состояние? В данный момент - состояние бита разрешения прерываний в CPSR. Ну а если это получится сделать корректно, то все остальное - дело техники.
|
|
|
|
|
Jan 26 2016, 05:37
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(rudy_b @ Jan 26 2016, 00:22)  Нет, не оно. Эта функция сначала считывает CPSR в регистр, меняет биты в регистре, потом заносит регистр в CPSR. Если в это время произойдет прерываие и CPSR будет изменен - будет плохо.
Нужно, чтобы одна ассемблерная команда одновременно и записала CPSR в стек и установила в нем запрет прерывания. И обратная операция - восстановиление CPSR из стека без всяких промежуточных операций в регистрах.
Иными словами нужна атомарная операция сохранения старого CPSR в стек с одновременной записью указанного бита в CPSR. Ну и обратная операция - восстановление CPSR из стека.
Честно сказать, совершенно не понимаю, как всякие функции HAL работают без этого - они обязательно должны глючить. Там все время пользуют общее разрешение и запрет прерываний. Если при этом нет возможности честно (атомарно, чтобы никто не мог перебить) сохранить исходное состояние бита разрешения прерываний, то это полный песец. Имхо, у вас странная исходная посылка. Ваши функции, в т.ч. обработчики прерываний, должны или не менять разрешение прерываний или менять и восстанавливать его обратно. Как я понимаю, HAL устроен именно так А если хотите странного, то можно например так Код __set_FAULTMASK(1); // не уверен, что она так называется, но какой-то инстринсик для записи в фаултмаск точно есть prim = __get_PRIMASK(); __disable_irq(); __set_FAULTMASK(0);
some_func();
if (!prim) __enable_irq();
|
|
|
|
|
Jan 26 2016, 13:28
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Цитата(Непомнящий Евгений @ Jan 26 2016, 08:37)  А если хотите странного, то можно например так Код __set_FAULTMASK(1); // не уверен, что она так называется, но какой-то инстринсик для записи в фаултмаск точно есть prim = __get_PRIMASK(); __disable_irq(); Это уже было. Прерывание между этими двумя командами может изменить CPSR Цитата(GetSmart @ Jan 26 2016, 09:37)  Суслика не видно. Опишите по шагам суть возникновения бага в такой последовательности действий. Аналогично багу с глобальным запретом IRQ+FIQ у ARM7. Долго описывать, эта проблема часто встречается, сталкиваюсь с ней не в первый раз. Особенно актальна при использовании чужих стеков. Цитата(GetSmart @ Jan 26 2016, 09:37)  А флаг глобального разрешений/запрета прерываний у кортекса в другом месте. Код /** \brief Disable IRQ Interrupts This function disables IRQ interrupts by setting the I-bit in the CPSR. Can only be executed in Privileged modes. */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); } Но, кажется, я понял как можно сделать правильно - использовать программное прерывание. При этом исходное значение CPSR пишется в стек. Поиграюсь.
|
|
|
|
|
Jan 26 2016, 20:00
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Цитата(Непомнящий Евгений @ Jan 26 2016, 16:32)  Между какими командами? После FAULTMASK=1 прерываний не будет... Зато между prim = __get_PRIMASK(); и __disable_irq(); вполне могут быть.
|
|
|
|
|
Jan 26 2016, 21:02
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(rudy_b @ Jan 26 2016, 17:28)  Код prim = __get_PRIMASK(); __disable_irq(); Это уже было. Прерывание между этими двумя командами может изменить CPSR Цитата ..то при возникновении прерывания между этими двумя командами (а оно может изменить параметры прерываний) Может быть PSR? Судя по мануалам, первая команда не обращается к PSR, а вторая здесь не ясна. Если она сделана через cpsid i, то тоже не обращается. У СМ3/CM4 (и возможно в CM7) в PSR есть поля, относящиеся к обработке условного префикса IT. Если они меняются, то так и пишите, т.к. это не "параметры прерываний". Из прерываний/исключений можно выйти с намеренно искажённым PSR. И после выхода там будет не то, что было на точке прерывания предыдущего уровня. Только это не должно влиять на правила осторожности предыдущего уровня. Цитата Долго описывать, эта проблема часто встречается, сталкиваюсь с ней не в первый раз. Особенно актальна при использовании чужих стеков. Пока описана только гипотеза. Некорректное поведение процессора не описано.
Сообщение отредактировал GetSmart - Jan 26 2016, 22:35
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 27 2016, 05:02
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(rudy_b @ Jan 26 2016, 23:00)  Зато между prim = __get_PRIMASK(); и __disable_irq(); вполне могут быть. Откуда они возьмутся, если FAULTMASK=1: Prevents the activation of all exceptions except for NMI? Цитата(GetSmart @ Jan 27 2016, 00:02)  Из прерываний/исключений можно выйти с намеренно искажённым PSR. И после выхода там будет не то, что было на точке прерывания предыдущего уровня. Только это не должно влиять на правила осторожности предыдущего уровня. А зачем так делать? Из прерывания можно к примеру стек расстрелять, тоже беда будет... Что б защититься от всего, надо писать для виртуальной машины
|
|
|
|
|
Jan 27 2016, 10:07
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(GetSmart @ Jan 27 2016, 10:50)  то при выходе можно переключить прерванный тред. Если есть гарантия, что был прерван именно тред. Соответственно PSR на выходе из прерывания будет абсолютно другой. Но и вернемся мы из такого переключателя в другое место, в то место, где прервали другую нить, а не туда где только что переключалось разрешение прерываний. А вот когда после какого-то следующего переключения вернемся в первое место, в PSR снова будет то же самое содержимое, которое было в момент возникновения прерывания в этом месте. Цитата(GetSmart @ Jan 26 2016, 02:24)  Общие функции, вызываемые из прерываний и извне прерываний. И что? Они точно так же сохранят в себе текущее состояние прерываний и восстановят перед выходом. А иначе ну глупо же получится - работала-работала себе программа, вдруг в производьном ее месте происходит внешнее событие (вызывающее прерывание) и после его обработки дальше программа вдруг дальше (со случайного места!) работает уже с запрещенными прерываниями. Бред какой-то.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 27 2016, 14:11
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Мы говорим о разных вещах. Попробую более узко сформулировать задачу.
Есть функция с критической секцией (запрет и разрешение прерываний), которая может вызываться как с разрешенными, так и с запрещенными прерываниями. Естественно, она должна восстановить исходное значение разрешения прерываний.
Но функция работает в кривой среде, в которой возможно возникновение другого прерывания, которое вполне может изменить разрешение прерываний. Т.е., если прерывания разрешены, то, после возврата они могут оказаться запрещенными. Вот такой бред.
Отсюда и возникает та проблема, о которой я говорю.
Посмотрел SVC (SWI). На его основе вполне можно сделать корректную функции запрета и разрешения прерываний с восстановлением исходного состояния разрешения прерываний. SVC имеет более высокий приоритет чем пользовательские прерывания, поэтому все должно быть корректно.
|
|
|
|
|
Jan 27 2016, 14:20
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(Сергей Борщ @ Jan 26 2016, 02:11)  Может потому, что они не пытаются разрешать/запрещать прерывания из обработчиков этих самых прерываний? Интересно, зачем такое может понадобиться? Разрешать прерывания изнури обработчика плохая идея. Цитата(rudy_b @ Jan 26 2016, 00:22)  Нет, не оно. Эта функция сначала считывает CPSR в регистр, меняет биты в регистре, потом заносит регистр в CPSR. Если в это время произойдет прерываие и CPSR будет изменен - будет плохо. Почему будет плохо? Ну сходит в прерывание между командами и вернется в том же виде (того кто напишет прерывание, что изменяет CPSR надо канделябром по фаберже), а затем запретит прерывание и продолжит работу.
|
|
|
|
|
Jan 27 2016, 18:59
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(Tarbal @ Jan 25 2016, 09:55)  Я сгенерировал кубом код для STM32F429 и добавляю в него необходимые мне функции. В этом и есть основная проблема. Код для прерывания необходимо писать самому, с минимальным использованием внешних данных. Сами функции в такой системе делятся на два типа - имеющие зависимости и без них. В случае когда в функции есть хотя-бы одна внутренняя или внешняя статическая переменная - последняя считается зависимой. У такой функции есть ограничения при работе в составе ос, и на использование последней в прерываниях. Точнее: применять можно - но только в одном месте. Функции без зависимостей - можно применять бесконечное количество раз одновременно, в том числе и в прерываниях. И неважно сколько у неё входных/выходных параметров, и сколько она в себе несёт вторичных вызовов. Всё аккуратно посчитается и вернётся на свои места. Так-что считаю ошибкой сам код прерывания, а не грабли вокруг него.
|
|
|
|
|
Jan 27 2016, 22:52
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(rudy_b @ Jan 27 2016, 18:11)  Но функция работает в кривой среде, в которой возможно возникновение другого прерывания, которое вполне может изменить разрешение прерываний. Т.е., если прерывания разрешены, то, после возврата они могут оказаться запрещенными. Вот такой бред.
Отсюда и возникает та проблема, о которой я говорю. Это кривой код обработчика прерываний, или код, оттуда вызывающийся. Который должен быть исправлен ТАМ ЖЕ. А не в другом месте программы. Или хитрая (но ничего не гарантирующая) задумка воздействия на обработку прерываний всей системы. От самого простого предположения: остановить приём всех прерываний до того, как тред не разрешит их снова. Общие критические секции (вставки) в этом случае не должны меняться.
Сообщение отредактировал GetSmart - Jan 28 2016, 00:11
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 28 2016, 04:51
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(rudy_b @ Jan 28 2016, 08:00)  Да и подобная проблема встает не впервые, уж лучше решить ее раз и навсегда. Problem: в девайсе что-то глобально запрещает прерывания в абсолютно случайном месте кода. Workaround: если не известна логика, по которой это происходит, то нет "прямого" решения. Или совсем кривое решение: расставить во множество мест своей программы глобальное разрешение прерываний. Везде, где они должны быть разрешёнными. Это если точно обозначена проблема. Критические секции тут ни при чём.
Сообщение отредактировал GetSmart - Jan 28 2016, 05:19
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|