- В чем разница между стеком ядра и пользовательским стеком?
Короче говоря, ничего - кроме использования другого места в памяти (и, следовательно, другого значения для регистра указателя стека) и, как правило, различных средств защиты доступа к памяти. Т.е. при выполнении в пользовательском режиме память ядра (часть которой является стеком ядра) не будет доступна даже при отображении. И наоборот, без явного запроса кода ядра (в Linux с помощью таких функций copy_from_user()
) пользовательская память (включая пользовательский стек) обычно напрямую не доступна.
- Почему используется [отдельный] стек ядра?
Разделение привилегий и безопасности. Во-первых, программы пользовательского пространства могут делать свой стек (указатель) чем угодно, и обычно нет архитектурных требований, чтобы даже иметь действующий стек. Таким образом, ядро не может доверять указателю стека пользовательского пространства как действительному или пригодному к использованию, и поэтому ему потребуется один набор под собственным контролем. В разных архитектурах ЦП это реализовано по-разному; Процессоры x86 автоматически переключают указатели стека при переключении режима привилегий, а значения, которые будут использоваться для различных уровней привилегий, настраиваются с помощью привилегированного кода (т.е. только ядра).
- Если в ISR объявлена локальная переменная, где она будет храниться?
В стеке ядра. Ядро (то есть ядро Linux) не подключает обработчики прерываний напрямую к воротам прерывания архитектуры x86, а вместо этого делегирует отправку прерывания общему механизму входа / выхода прерывания ядра, который сохраняет состояние регистра до прерывания перед вызовом зарегистрированного обработчика (ов) . Сам ЦП при отправке прерывания может выполнять переключатель привилегий и / или стека, и это используется / настраивается ядром, так что общий код записи прерывания уже может полагаться на наличие стека ядра.
Тем не менее, прерывания, возникающие во время выполнения кода ядра, будут просто (продолжать) использовать стек ядра на месте в этот момент. Это может, если обработчики прерываний имеют глубоко вложенные пути вызовов, привести к переполнению стека (если путь глубокого вызова ядра прерывается и обработчик вызывает другой глубокий путь; в Linux код файловой системы / программного обеспечения RAID, прерываемый сетевым кодом с активными iptables, является известно, что такое срабатывает в ненастроенных старых ядрах ... решение состоит в увеличении размера стека ядра для таких рабочих нагрузок).
- Есть ли у каждого процесса собственный стек ядра?
Не только каждый процесс - каждый поток имеет свой собственный стек ядра (и, фактически, свой собственный стек пользователя). Помните, что единственная разница между процессами и потоками (для Linux) заключается в том, что несколько потоков могут совместно использовать адресное пространство (формируя процесс).
- Как координируется процесс между этими двумя стеками?
Вовсе нет - в этом нет необходимости. Планирование (как / когда выполняются разные потоки, как их состояние сохраняется и восстанавливается) - это задача операционной системы, и процессам не нужно этим заниматься. По мере создания потоков (и у каждого процесса должен быть хотя бы один поток) ядро создает для них стеки ядра, в то время как стеки пользовательского пространства либо явно создаются / предоставляются любым механизмом, который используется для создания потока (например, функции makecontext()
или pthread_create()
позволяют вызывающему указать область памяти, которая будет использоваться для стека «дочернего» потока) или унаследована (путем клонирования памяти при доступе, обычно называемого «копирование при записи» / COW, при создании нового процесса).
Тем не менее,(состояние, среди которых указатель стека потока). Есть несколько способов для этого: сигналов UNIX, setcontext()
, pthread_yield()
/ pthread_cancel()
, ... - но это disgressing немного от первоначального вопроса.
Мой ответ собран из других вопросов SO с моими материалами.
Как программист ядра вы знаете, что ядро должно быть ограничено от ошибочных пользовательских программ. Предположим, вы сохраняете один и тот же стек как для ядра, так и для пользовательского пространства, тогда простой segfault в пользовательском приложении вызывает сбой ядра и требует перезапуска.
Существует один «стек ядра» на процессор, такой как стек ISR, и один «стек ядра» на процесс. Для каждого процесса существует один «пользовательский стек», хотя каждый поток имеет свой собственный стек, включающий как пользовательские потоки, так и потоки ядра.
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Поэтому, когда мы находимся в режиме ядра, для обработки вызовов функций необходим стековый механизм, локальные переменные, подобные пользовательскому пространству.
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
Он будет храниться в стеке ISR (IRQSTACKSIZE). ISR работает в отдельном стеке прерываний, только если оборудование поддерживает его. В противном случае кадры стека ISR помещаются в стек прерванного потока.
Пользовательское пространство не знает и, откровенно говоря, не заботится о том, обслуживается ли прерывание в стеке ядра текущего процесса или в отдельном стеке ISR. Поскольку прерывания приходятся на процессор, поэтому стек ISR должен быть на процессор.
Да. У каждого процесса есть свой стек ядра.
Ответ @FrankH мне нравится.
источник
Ссылаясь на статью Роберта Лава о разработке ядра Linux, основное различие заключается в размере:
Также стек ядра содержит указатель на структуру thread_info, содержащую информацию о потоке.
источник