Когда происходит прерывание, процессор прерывает текущий процесс и вызывает код ядра для обработки прерывания. Как процессор знает, куда войти в ядро?
Я понимаю, что есть обработчики прерываний, которые могут быть установлены для каждой линии прерывания. Но поскольку процессор выполняет только «аппаратную логику», должно существовать некоторое предопределенное место, которое указывает либо на сам обработчик прерываний, либо на некоторый код, который выполняется перед обработчиком (поскольку для одной строки прерывания может быть несколько обработчиков, я предполагаю, что последний).
источник
Да, есть предопределенное место, которое содержит адрес кода для перехода: вектор прерывания . В зависимости от процессора это может быть конкретное место в физической памяти (8088), конкретное место в виртуальной памяти, регистр процессора, место в памяти, указанное регистром (ARM, 386),…
Детали различаются для разных процессоров, но основными общими элементами обработки прерываний в процессоре являются:
источник
Два других ответа (на момент написания) говорят о прерываниях и IDT. Это верно, однако, на современном процессоре Intel-esque существует не менее трех способов вызова ядра.
Метод № 1: Прерывания.
Это объяснено выше. Вы устанавливаете запись в таблице дескрипторов прерываний / векторе прерываний, а затем выполняете программное прерывание для входа в ядро.
Основным преимуществом этого метода является то, что типичное ядро должно быть способным обрабатывать прерывания в любом случае, и оно работает на устаревшем оборудовании.
Способ № 2: вызов ворот.
Шлюз вызова - это особый тип селектора сегмента. Цель вызова должна быть загружена в глобальную или локальную таблицу дескрипторов сегментов (GDT и LDT соответственно). Если затем выполнить инструкцию дальнего вызова с использованием шлюза вызова в качестве сегмента (смещение вызова игнорируется), это позволяет вам вызывать более привилегированный код. Ворота вызова чрезвычайно гибки; архитектура IA-32 имеет четыре уровня привилегий, а шлюзы вызовов позволяют вызывать любой уровень.
Я не верю, что в Linux когда-либо использовались шлюзы вызовов, а в Windows 95 - нет. Службы ядра Win95 (
krnl386.exe
иkernel.dll
) фактически работали в пользовательском режиме (кольцо 3). Самый высокий уровень привилегий (кольцо 0) использовался только для драйверов и микроядра, которое выполняло только переключение процессов. Звонок в водителей был сделан с помощью ворот вызова. Это позволило старому 16-битному коду (которых было много!) Использовать драйверы Win95, просто используя стандартный дальний вызов, как они всегда это делали.Неадекватная защита таблицы глобальных дескрипторов была причиной нескольких эксплойтов Windows 95, которым удалось установить собственные шлюзы вызовов путем перезаписи памяти.
Метод № 3: SYSCALL / SYSRET и SYSENTER / SYSEXIT
Это два набора инструкций, независимо придуманных AMD и Intel, но по сути они делают то же самое. SYSCALL / SYSRET был первым и был только для AMD, SYSENTER / SYSEXIT был Intel, но AMD реализует его сейчас. Итак, я собираюсь описать SYSENTER / SYSEXIT.
В отличие от шлюзов вызовов, SYSENTER может использоваться только для передачи на кольцо 0 и может быть переведен только в одно место. Однако его преимущество заключается в чрезвычайно низкой задержке, поскольку в отличие от вызова или прерывания он не затрагивает стек.
Местоположение передачи устанавливается с использованием трех регистров, специфичных для модели: один для информации о сегменте, а другой - для указателя инструкций и указателя стека кода ядра. Поскольку ничто не «помещается» в стек, код пользовательского режима отвечает за указание ядру, куда возвращаться, путем передачи указателя инструкции возврата и указателя стека в регистрах. Ядро отвечает за восстановление указателя стека, а инструкция SYSEXIT восстанавливает указатель инструкции.
Дополнительная информация об инструкциях SYSENTER и SYSEXIT.
источник