2013-09-20 5 views
2

Я играю с микроконтроллером Atmel AT91SAM7S, и похоже, что обработчики IRQ должны выполняться в режиме супервизора, а основной код цикла - в системном режиме. Кроме того, я должен зарезервировать определенную часть ОЗУ, которая будет использоваться как стек по коду режима супервизора. Код начальной загрузки, который я получил из демонстрационной программы, по умолчанию резервирует 128 байтов.Почему режим супервизора ARM имеет свой собственный стек?

Почему я должен резервировать отдельное пространство стека для режима супервизора; почему он не может использовать тот же стек, что и системный режим (основной)? В чем преимущество кода обработки прерываний, имеющего совершенно другой стек, чем основной код цикла? Я вижу, что текущий код сборки для обработки IRQ переключается из режима IRQ в режим супервизора до перехода к обработчику прерываний. Было бы целесообразно выполнить обработчик прерываний в пользовательском режиме? Если да, то с чем мне нужно быть осторожным?

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

Единственное, что я могу придумать, это то, что наличие отдельного стека было бы полезно, если вы реализуете операционную систему с какой-либо защитой памяти; но поскольку я этого не делаю, это имеет значение?

P.S. Я знаком с AVR и их обработкой прерываний.

Разъяснение

Оказывается, прерывание обработки начинается, когда процессор переходит на адрес 0x18, который содержит команду перехода к AT91F_Irq_Handler ниже. Из того, что я могу сказать, процессор автоматически вводит прерывание режим; эта сборка переключается на диспетчер до перехода на функцию (C) в зависимости от того, какая линия прерывания была запущена. Он получает адрес филиала от Advanced Interrupt Controller (AIC).

AT91F_Irq_Handler: 
/* Manage Exception Entry    */ 
/* Adjust and save LR_irq in IRQ stack */ 
       sub   lr, lr, #4 
       stmfd  sp!, {lr} 
/* Save r0 and SPSR (need to be saved for nested interrupt) */ 
       mrs   r14, SPSR 
       stmfd  sp!, {r0,r14} 
/* Write in the IVR to support Protect Mode     */ 
/* No effect in Normal Mode        */ 
/* De-assert the NIRQ and clear the source in Protect Mode */ 
       ldr   r14, =AT91C_BASE_AIC 
       ldr   r0 , [r14, #AIC_IVR] 
       str   r14, [r14, #AIC_IVR] 

/* Enable Interrupt and Switch in Supervisor Mode */ 
       msr   CPSR_c, #ARM_MODE_SVC 

/* Save scratch/used registers and LR in User Stack */ 
       stmfd  sp!, { r1-r3, r12, r14} 

/* Branch to the routine pointed by the AIC_IVR */ 
       mov   r14, pc 
       bx   r0 
/* Manage Exception Exit         */ 
/* Restore scratch/used registers and LR from User Stack */ 
       ldmia  sp!, { r1-r3, r12, r14} 

/* Disable Interrupt and switch back in IRQ mode */ 
       msr   CPSR_c, #I_BIT | ARM_MODE_IRQ 
/* Mark the End of Interrupt on the AIC */ 
       ldr   r14, =AT91C_BASE_AIC 
       str   r14, [r14, #AIC_EOICR] 
/* Restore SPSR_irq and r0 from IRQ stack */ 
       ldmia  sp!, {r0,r14} 
       msr   SPSR_cxsf, r14 
/* Restore adjusted LR_irq from IRQ stack directly in the PC */ 
       ldmia  sp!, {pc}^ 
+0

Переполнение стека - очень неприятная ошибка, причина для названия этого веб-сайта. Если супервайзер использовал один и тот же стек, тогда не было бы способа восстановить из SO в пользовательском режиме. Или иметь дело с SO, генерируемым IRQ или исключением. –

+0

@HansPassant Не должно быть переполнения стека в любом месте; если вы можете это сделать, вам не нужно заботиться о восстановлении в первую очередь. Но с (например) только 128 байтов стека для прерываний, легко случайно получить переполнение (поскольку стек прерываний переполняется в стек пользователя, по крайней мере, в моем случае). Не было бы проблем, если бы прерывания продолжались только с стеком, где заканчивается пользовательский стек. –

+0

Я думал, что у нас [аналогичный вопрос] (http://stackoverflow.com/questions/18638711/why-is-cpsr-not-a-banked-register); речь идет о 'cpsr', который может быть интересен людям, рассматривающим этот вопрос. –

ответ

3

Вы не должны использовать супервизора r13 как стек. Вы можете использовать его как регистр общего назначения, чтобы что-то сохранить, а затем перейти на системный режим и запустить остальную часть ISR в этом режиме. Он является гибким, и вы можете иметь другой стек, если хотите; вы не ручная, как другие архитектуры. Вы можете набрать супервизор r13 с некоторым указателем области сохранения или обычно указателем (или двойным указателем) на выполняемую в настоящее время задачу. Вам нужно сохранить lr, spsr и любые другие регистры, которые будут сбиты, если вы ожидаете возвращения ISR. Я думаю, что изначально нормальный ARM будет в режиме прерывания; возможно, у вас есть другой обработчик, который уже переходит на режим супервизора? Часто системный режим имеет блок управления стеклом/задачами ядра и он включает в себя многозадачность. Режим супервизора является общим режимом для обработки исключений .

Если у вас есть только одна задача, и вы хотите использовать ее, вы можете использовать следующее. После сохранения контекста в руководитель, перейдите на системный режим и выполните оставшуюся часть ISR. Просто верните регистры, включая lr и cpsr, чтобы вернуться в правильный режим, счетчик программ и коды условий.

Вы делаете конечно есть вариант использовать супервизора r13 как стек исключений, который многие люди могут понравиться с ограниченным поведением и быстрее IRQ латентности в стек предустановка и готов к использованию по основным ISR корпус.

+0

Самое главное убедиться, что вы исправили стек 'pop'ing, прежде чем вы вернетесь в прерванный код пользователя. Для вашего кода пользователя могут потребоваться некоторые параметры. Например, когда-то «C» использует пространство [выше и ниже указателя стека] (http://stackoverflow.com/questions/15752188/arm-link-register-and-frame-pointer). Он настраивается только на вызов функции. Если вы просто используете память, вы можете наступить на локальные переменные прерванных кодов. –

+0

Да, я понимаю опасность, хотя в AVR используется тот же метод стека, и, предположительно, нет проблем с переписыванием пользовательских данных, поскольку он был написан до того, как указатель стека был увеличен. Считаете ли вы, что компиляторы ARM (gcc) не так осторожны в этом отношении? –

+0

Я бы предположил, что 'gcc' имеет некоторую возможность заставить его работать и другой вариант, который его сломает. Это может даже зависеть от версии 'gcc'; Вам нужно посмотреть руководство и, возможно, сгенерированный код. Я думаю, что местные жители ссылаются на 'fp' и, вероятно, это безопасно, но я бы (и имел) выделил еще один стек; обработчики прерываний обычно не так сложны. Просто измените 128 байтов, чтобы они соответствовали вашим требованиям ISR; вам нужно, чтобы требования к стеку ISR были высокими, а системная память была низкой, чтобы это не имело смысла. –

Смежные вопросы