Почему процессоры x86 используют только 2 из 4 звонков?

13

Поэтому системы x86 на базе Linux или Windows используют только кольцо 0 для режима ядра и кольцо 3 для режима пользователя. Почему процессоры даже различают четыре разных кольца, если они все равно используют только два из них? И изменилось ли это на архитектуре AMD64?

AdHominem
источник
Кстати, я бы предложил изменить название вопроса на «Почему в операционных системах x86 используется только 2 из 4 звонков?» или, может быть, «Почему ОС только на процессорах x86 ...». Процессор делает только то, что говорит операционная система.
Джейми Ханрахан
ПЕРЕСТАВЛЕНО: howtogeek.com/251081/…
rahuldottech

Ответы:

15

Есть две основные причины.

Первая причина в том, что, хотя процессоры x86 предлагают четыре кольца защиты памяти, степень защиты, предлагаемая таким образом, существует только на уровне сегмента. То есть каждый сегмент может быть установлен на определенное кольцо («уровень привилегий») от 0 до 3, наряду с другими средствами защиты, такими как отключение записи. Но не так много доступных дескрипторов сегментов. Большинство операционных систем хотели бы иметь более тонкую степень защиты памяти. Как ... для отдельных страниц.

Таким образом, введите защиту на основе записей таблицы страниц (PTE). Большинство, если не все современные операционные системы x86 более или менее игнорируют механизм сегментирования (во всяком случае, насколько это возможно) и полагаются на защиту на основе PTE. Это определяется битами флага, которые являются младшими 12 битами в каждом PTE - плюс бит 63 на процессорах, которые поддерживают no-execute. Существует один PTE для каждой страницы, который обычно составляет 4K.

Один из этих битов флага называется «привилегированным» битом. Этот бит определяет, должен ли процессор находиться на одном из «привилегированных» уровней для доступа к странице. «Привилегированными» уровнями являются PL 0, 1 и 2. Но это всего лишь один бит, поэтому на уровне постраничной защиты количество доступных «режимов» для защиты памяти равно двум: может быть доступен из непривилегированного режима или нет. Отсюда всего два кольца.

Чтобы иметь четыре возможных звонка для каждой страницы, они должны иметь два защитных бита в каждой записи таблицы страниц, чтобы кодировать одно из четырех возможных номеров звонков (так же, как и дескрипторы сегментов). Они не

Вторая причина - цель переносимости ОС. Дело не только в x86; Unix научил нас, что ОС может быть относительно переносимой для многопроцессорных архитектур, и это хорошо. А некоторые процессоры поддерживают только два кольца. Не зависящие от множества колец в архитектуре, разработчики ОС сделали ОС более переносимыми.

Третья причина связана с разработкой Windows NT. Дизайнеры NT (Дэвид Катлер и его команда, нанятые Microsoft из DEC Western Region Labs) имели большой опыт работы с VMS; Фактически, Катлер и некоторые другие были среди оригинальных дизайнеров VMS. А процессор VAX, для которого была разработана VMS (и наоборот), имеет четыре кольца. VMS использует четыре кольца. (На самом деле VAX имеет четыре защитных бита в PTE, что позволяет использовать такие комбинации, как «только чтение из пользовательского режима, но возможность записи из кольца 2 и изнутри.» Но я отвлекся.)

Но компоненты, которые работали в кольцах VMS 1 и 2 (Службы управления записями и CLI, соответственно), были оставлены вне дизайна NT. Кольцо 2 в VMS на самом деле было связано не с безопасностью ОС, а с сохранением среды CLI пользователя от одной программы к другой, а в Windows NT такой концепции просто не было; CLI работает как обычный процесс. Что касается кольца 1 VMS, то код RMS в кольце 1 должен был вызываться в кольцо 0 довольно часто, и переходы вызова являются дорогостоящими. Оказалось, что гораздо эффективнее просто перейти к кольцу 0 и покончить с ним, а не иметь много переходов кольца 0 в коде кольца 1. (Опять же - не то чтобы в NT все равно было что-то вроде RMS.)

Но почему они там? Что касается того, почему в x86 реализовано четыре кольца, а ОС их не использует - вы говорите об ОС гораздо более свежего дизайна, чем x86. Многие функции «системного программирования» в x86 были разработаны задолго до того, как на нем были внедрены NT или настоящие ядра Unix-ish, и они не знали, что будут использовать ОС. (Только когда мы получили пейджинг на x86 - который не появлялся до 80386 - мы могли реализовать настоящие ядра Unix или VMS-подобные без переосмысления управления памятью с нуля.)

Современные ОС x86 не только в значительной степени игнорируют сегментирование (они просто устанавливают сегменты C, D и S с базовым адресом 0 и размером 4 ГБ; сегменты F и G иногда используются для указания на ключевые структуры данных ОС), они также в значительной степени игнорировать такие вещи, как «сегменты состояния задачи». Механизм TSS был явно разработан для переключения контекста потока, но у него слишком много побочных эффектов, поэтому современные ОС x86 делают это «вручную». Например, единственное время, когда x86 NT меняет аппаратные задачи, - это некоторые действительно исключительные условия, такие как исключение двойной ошибки.

Что касается x64, многие из этих неиспользуемых функций были опущены. (К их чести, AMD фактически поговорила с командами ядра ОС и спросила, что им нужно от x86, что им не нужно или не нужно, и что они хотели бы добавить.) Сегменты на x64 существуют только в том, что может быть так называемая рудиментарная форма, переключение состояний задачи не существует и т. д. И ОС продолжают использовать только два кольца.

Джейми Ханрахан
источник
1
Благодарность! (Если вы не можете сказать, я потратил больше времени на ядро ​​VMS ...)
Джейми Ханрахан
Да, у меня сложилось такое впечатление ... :-) Мне нравится, когда кто-то вроде тебя с глубоким знанием чего-то пишет такой ответ, это история ИТ, и я люблю это знать. Ваш ответ вспомнил меня, когда я учился в школе 20 лет назад, и я купил «Справочное руководство для программистов Intel 80268», а затем справочное руководство 386. Я много читал о защитных кольцах ... но никогда ничего с ними не делал. Просто простое программирование на ассемблере x86 ... затем Turbo Pascal, затем C / C ++, Java ... и, наконец, .Net за последние 13 лет :-)
Макс