Как работает segmentation fault (kernel / оборудование)?

В общем, мне интересно, как kernel ​​(или ЦП) знает, что процесс попытался получить доступ к ячейке памяти, для которой ему не хватает разрешения, и как таинственная часть аппаратного обеспечения, называемая MMU, помогает в этом.

В частности: мне кажется, что MMU агностически относится к модели управления памятью ядра ОС (подкачки, зоны памяти, пространства адресов процессов …) (я бы предположил, что страницы Linux и Windows не совсем то же самое, для пример. Поправьте меня, если я ошибаюсь). Но тогда, как мой CPU узнает, может ли текущий код получить доступ к местоположению x ? И как это сигнализирует об этом ядру?

    Это, вероятно, слишком большая тема, чтобы полностью удовлетворительно ответить на этот вопрос; вам лучше искать некоторые статьи / статьи / книги, в которых обсуждаются аппаратные средства, используемые для реализации виртуальной памяти (возможно, начиная с конкретной архитектуры, поскольку существуют значительные различия между, например, x86, x86_64, sparc и т. д.).

    Короткий ответ, однако, заключается в том, что аппаратное обеспечение обрабатывает это через таблицы страниц. Каждый доступ к памяти, к которому обращается MMU, проверяется через структуры таблицы страниц. Если запись в таблице страниц, описывающая страницу, содержащую запрашиваемый адрес, не помечена, чтобы разрешить запрашиваемый тип доступа (чтение / запись / выполнение / …), аппаратное обеспечение создает ловушку, которую Linux в конечном итоге вызывает «ошибку сегментации», , Другие ОС называют их по-разному (например, общая ошибка защиты, …). Затем kernel ​​ОС должно выяснить причину ошибки и можно ли что-либо сделать с ней (многие ловушки обрабатываются kernelм для обмена новыми страницами с диска, отображения новой пустой страницы и т. Д., Но некоторые, например, null-pointer dereferences, лучшее, что может сделать kernel, это бросить его в приложение, чтобы сказать «вы сделали что-то плохое»).

    MMU сконфигурирован (по своей логике и / или битам опций, установленным kernelм), чтобы быть аппаратной частью реализации модели поискового вызова.

    MMU должен обычно переводить логические адреса на отображаемые физические адреса; когда он не может этого сделать, потому что не существует соответствующего физического адреса для запрошенного логического адреса, он генерирует ошибку (часто как тип прерывания), которая запускает код обработчика в ядре.

    Если ошибка была попыткой запросить то, что теоретически существует – скажем, часть отображаемого файла – но в настоящее время нет в физическом RAM, реализация виртуальной памяти операционной системы может решить проблему путем выделения некоторого физического топа и копирования соответствующих блоков диска внутрь.

    Однако, если это запрос на то, чего не существует, он не может быть удовлетворен и должен быть обработан как ошибка программы.

    Требование написать что-то, где письмо не разрешено, будет обрабатываться аналогичным образом.

    В верхней части моей головы я не уверен, что попытки выполнить неисполняемую информацию обнаруживаются в MMU или больше в самом CPU; как кэш команд, если он присутствует, может также усложнить ситуацию. Однако конечный результат был бы аналогичным – условие отказа для ядра, что была предпринята попытка незаконного выполнения, которую kernel ​​обычно рассматривало бы как ошибку программы.

    Таким образом, модель состоит в том, что более простые аппаратные уровни сообщают ядру, что произошло что-то необычное, которое аппаратное обеспечение не может решить само по себе, используя свою текущую конфигурацию. Затем операционная система решает, может ли и когда должно произойти то, что было предпринято, – если это так, то обновляет конфигурацию оборудования, чтобы сделать это возможным. Или, если попытка не должна быть разрешена, объявляется ошибка программы. И есть и дополнительные возможности, например, уровень виртуализации может решить эмулировать запрошенную операцию, а не буквально ее выполнять, сохраняя некоторую изоляцию от аппаратного обеспечения.