В чем разница между пользовательским режимом и режимом ядра, почему и как вы активируете любой из них и каковы их варианты использования?
В чем разница между пользовательским режимом и режимом ядра, почему и как вы активируете любой из них и каковы их варианты использования?
Ответы:
Режим ядра
В режиме ядра исполняемый код имеет полный и неограниченный доступ к базовому оборудованию. Он может выполнять любую инструкцию ЦП и ссылаться на любой адрес памяти. Режим ядра обычно зарезервирован для самых низкоуровневых и наиболее надежных функций операционной системы. Сбои в режиме ядра катастрофичны; они остановят весь компьютер.
Пользовательский режим
В пользовательском режиме исполняемый код не имеет возможности напрямую обращаться к оборудованию или справочной памяти. Код, работающий в пользовательском режиме, должен делегировать системные API-интерфейсы для доступа к оборудованию или памяти. Благодаря защите, обеспечиваемой такой изоляцией, сбои в пользовательском режиме всегда можно исправить. Большая часть кода, запущенного на вашем компьютере, будет выполняться в пользовательском режиме.
Читать далее
Это два разных режима, в которых может работать ваш компьютер. До этого, когда компьютеры были похожи на большую комнату, если что-то выходит из строя - останавливает весь компьютер. Поэтому компьютерные архитекторы решили изменить это. Современные микропроцессоры аппаратно реализуют как минимум 2 различных состояния.
Пользовательский режим:
Режим ядра:
Как происходит переключение.
Переключение из пользовательского режима в режим ядра не выполняется процессором автоматически. CPU прерывается прерываниями (таймеры, клавиатура, ввод / вывод). При возникновении прерывания ЦП прекращает выполнение текущей запущенной программы, переключается в режим ядра, выполняет обработчик прерывания. Этот обработчик сохраняет состояние процессора, выполняет его операции, восстанавливает состояние и возвращается в пользовательский режим.
http://en.wikibooks.org/wiki/Windows_Programming/User_Mode_vs_Kernel_Mode
http://tldp.org/HOWTO/KernelAnalysis-HOWTO-3.html
Процессор на компьютере под управлением Windows имеет два разных режима: пользовательский режим и режим ядра. Процессор переключается между двумя режимами в зависимости от того, какой тип кода выполняется на процессоре. Приложения работают в пользовательском режиме, а основные компоненты операционной системы - в режиме ядра. Хотя многие драйверы работают в режиме ядра, некоторые драйверы могут работать в пользовательском режиме.
Когда вы запускаете приложение в пользовательском режиме, Windows создает процесс для этого приложения. Процесс предоставляет приложению частное виртуальное адресное пространство и частную таблицу дескрипторов. Поскольку виртуальное адресное пространство приложения является частным, одно приложение не может изменять данные, принадлежащие другому приложению. Каждое приложение работает изолированно, и в случае сбоя приложения сбой ограничивается только этим приложением. На другие приложения и операционную систему сбой не влияет.
Помимо того, что виртуальное адресное пространство приложения пользовательского режима является частным, оно ограничено. Процессор, работающий в пользовательском режиме, не может получить доступ к виртуальным адресам, зарезервированным для операционной системы. Ограничение виртуального адресного пространства приложения пользовательского режима предотвращает изменение и возможное повреждение критически важных данных операционной системы приложением.
Весь код, работающий в режиме ядра, использует единое виртуальное адресное пространство. Это означает, что драйвер режима ядра не изолирован от других драйверов и самой операционной системы. Если драйвер режима ядра случайно записывает неправильный виртуальный адрес, данные, принадлежащие операционной системе или другому драйверу, могут быть скомпрометированы. В случае отказа драйвера режима ядра происходит сбой всей операционной системы.
Если вы являетесь пользователем Windows, пройдя по этой ссылке, вы получите больше.
Кольца процессора - самое четкое различие
В защищенном режиме x86 ЦП всегда находится в одном из 4-х колец. Ядро Linux использует только 0 и 3:
Это наиболее четкое и быстрое определение отношения ядра к пользовательской среде.
Почему Linux не использует кольца 1 и 2: Кольца привилегий ЦП: Почему кольца 1 и 2 не используются?
Как определяется текущее кольцо?
Текущее кольцо выбирается комбинацией:
глобальная таблица дескрипторов: таблица записей GDT в памяти, и каждая запись имеет поле, Privl
которое кодирует кольцо.
Инструкция LGDT устанавливает адрес текущей таблицы дескрипторов.
сегментные регистры CS, DS и т. д. указывают на индекс записи в GDT.
Например, CS = 0
означает, что первая запись GDT в настоящее время активна для исполняемого кода.
Что может делать каждое кольцо?
Чип ЦП физически построен так, чтобы:
кольцо 0 может все
кольцо 3 не может запускать несколько инструкций и записывать в несколько регистров, в первую очередь:
не может изменить свое собственное кольцо! В противном случае он мог бы установить для себя 0 звонков, и звонки были бы бесполезны.
Другими словами, нельзя изменить дескриптор текущего сегмента , который определяет текущее кольцо.
Невозможно изменить таблицы страниц: как работает подкачка x86?
Другими словами, невозможно изменить регистр CR3, а сама подкачка предотвращает изменение таблиц страниц.
Это предотвращает просмотр одним процессом памяти других процессов по причинам безопасности / простоты программирования.
не может регистрировать обработчики прерываний. Они настраиваются путем записи в ячейки памяти, что также предотвращается подкачкой.
Обработчики работают в кольце 0 и нарушают модель безопасности.
Другими словами, нельзя использовать инструкции LGDT и LIDT.
не может выполнять инструкции ввода-вывода, такие как in
и out
, и, следовательно, иметь произвольный доступ к оборудованию.
В противном случае, например, права доступа к файлам были бы бесполезны, если бы какая-либо программа могла напрямую читать с диска.
Точнее, спасибо Майклу Петчу : на самом деле ОС может разрешить инструкции ввода-вывода на кольце 3, это фактически контролируется сегментом состояния задачи .
Кольцо 3 не может дать себе на это разрешение, если оно изначально не имело.
Linux всегда это запрещает. См. Также: Почему Linux не использует аппаратное переключение контекста через TSS?
Как программы и операционные системы переходят между кольцами?
когда ЦП включен, он запускает начальную программу в кольце 0 (ну, вроде как, но это хорошее приближение). Вы можете считать эту начальную программу ядром (но обычно это загрузчик, который затем вызывает ядро, все еще находящееся в кольце 0 ).
когда процесс пользовательской среды хочет, чтобы ядро что-то сделало для него, например, запись в файл, он использует инструкцию, которая генерирует прерывание, например int 0x80
или,syscall
чтобы сигнализировать ядру. Пример системного вызова Linux x86-64 hello world:
.data
hello_world:
.ascii "hello world\n"
hello_world_len = . - hello_world
.text
.global _start
_start:
/* write */
mov $1, %rax
mov $1, %rdi
mov $hello_world, %rsi
mov $hello_world_len, %rdx
syscall
/* exit */
mov $60, %rax
mov $0, %rdi
syscall
скомпилировать и запустить:
as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out
Когда это происходит, ЦП вызывает обработчик обратного вызова прерывания, который ядро зарегистрировало во время загрузки. Вот конкретный пример baremetal, который регистрирует обработчик и использует его .
Этот обработчик работает в кольце 0, которое решает, разрешит ли ядро это действие, выполняет действие и перезапускает программу пользовательского пространства в кольце 3. x86_64
когда используется exec
системный вызов (или когда ядро запускается/init
), ядро подготавливает регистры и память для нового пользовательского процесса, затем переходит к точке входа и переключает ЦП на кольцо 3
Если программа пытается сделать что-то непослушное, например запись в запрещенный регистр или адрес памяти (из-за разбиения на страницы), CPU также вызывает некоторый обработчик обратного вызова ядра в кольце 0.
Но поскольку пользовательская среда была непослушной, ядро могло на этот раз убить процесс или выдать ему предупреждение с сигналом.
Когда ядро загружается, оно устанавливает аппаратные часы с некоторой фиксированной частотой, которые периодически генерируют прерывания.
Эти аппаратные часы генерируют прерывания, которые запускают кольцо 0, и позволяют ему планировать, какие процессы пользовательского пространства должны пробудиться.
Таким образом, планирование может выполняться, даже если процессы не выполняют никаких системных вызовов.
Какой смысл иметь несколько колец?
Разделение ядра и пользовательской среды дает два основных преимущества:
Как с этим поиграться?
Я создал "голый металл", который должен быть хорошим способом прямого управления кольцами: https://github.com/cirosantilli/x86-bare-metal-examples
К сожалению, у меня не хватило терпения сделать пример пользовательского пространства, но я дошел до настройки разбиения на страницы, так что пользовательское пространство должно быть возможным. Я бы хотел увидеть запрос на перенос.
В качестве альтернативы модули ядра Linux работают в кольце 0, поэтому вы можете использовать их для опробования привилегированных операций, например, чтения регистров управления: Как получить доступ к регистрам управления cr0, cr2, cr3 из программы? Получение ошибки сегментации
Вот удобная установка QEMU + Buildroot, чтобы попробовать ее, не убивая хоста.
Обратной стороной модулей ядра является то, что работают другие потоки kthread, которые могут помешать вашим экспериментам. Но теоретически вы можете взять на себя все обработчики прерываний с вашим модулем ядра и владеть системой, что на самом деле было бы интересным проектом.
Отрицательные кольца
Хотя отрицательные кольца фактически не упоминаются в руководстве Intel, на самом деле существуют режимы ЦП, которые имеют дополнительные возможности, чем само кольцо 0, и поэтому хорошо подходят для названия «отрицательное кольцо».
Одним из примеров является режим гипервизора, используемый в виртуализации.
Подробнее см .:
РУКА
В ARM вместо этого кольца называются уровнями исключений, но основные идеи остаются прежними.
В ARMv8 существует 4 уровня исключений, которые обычно используются как:
EL0: пользовательское пространство
EL1: ядро («супервизор» в терминологии ARM).
Вводится с помощью svc
инструкции (SuperVisor Call), ранее известной как swi
до унифицированной сборки , которая используется для выполнения системных вызовов Linux. Привет, мир, пример ARMv8:
привет.
.text
.global _start
_start:
/* write */
mov x0, 1
ldr x1, =msg
ldr x2, =len
mov x8, 64
svc 0
/* exit */
mov x0, 0
mov x8, 93
svc 0
msg:
.ascii "hello syscall v8\n"
len = . - msg
Протестируйте это с помощью QEMU на Ubuntu 16.04:
sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
arm-linux-gnueabihf-as -o hello.o hello.S
arm-linux-gnueabihf-ld -o hello hello.o
qemu-arm hello
Вот конкретный пример «голого металла», который регистрирует обработчик SVC и выполняет вызов SVC .
EL2: гипервизоры , например Xen .
Вступил с hvc
инструкцией (HyperVisor Call).
Гипервизор для ОС - то же самое, что ОС для пользователя.
Например, Xen позволяет одновременно запускать несколько операционных систем, таких как Linux или Windows, в одной и той же системе, и он изолирует операционные системы друг от друга для обеспечения безопасности и простоты отладки, как это делает Linux для программ пользовательского уровня.
Гипервизоры являются ключевой частью сегодняшней облачной инфраструктуры: они позволяют нескольким серверам работать на одном оборудовании, поддерживая использование оборудования почти на 100% и экономя много денег.
AWS, например, использовала Xen до 2017 года, когда о его переходе на KVM стало известно в новостях .
EL3: еще один уровень. Пример TODO.
Вошел с smc
инструкцией (Secure Mode Call)
ARMv8 Architecture Reference Model DDI 0487C.a - Глава D1 - В AArch64 уровневой системы программист Модель - Рисунок D1-1 иллюстрирует это красиво:
Ситуация с ARM немного изменилась с появлением расширений хоста виртуализации ARMv8.1 (VHE) . Это расширение позволяет ядру эффективно работать в EL2:
VHE был создан, потому что решения виртуализации в ядре Linux, такие как KVM, завоевали популярность по сравнению с Xen (см., Например, переход AWS на KVM, упомянутый выше), потому что большинству клиентов нужны только виртуальные машины Linux, и, как вы можете себе представить, все в одном В проекте KVM проще и потенциально более эффективно, чем Xen. Итак, теперь ядро хоста Linux действует как гипервизор в этих случаях.
Обратите внимание на то, что ARM, возможно, благодаря преимуществу ретроспективного анализа, имеет лучшее соглашение об именах для уровней привилегий, чем x86, без необходимости в отрицательных уровнях: 0 является нижним и 3 высшим. Более высокие уровни, как правило, создаются чаще, чем более низкие.
Текущий EL можно запросить с помощью MRS
инструкции: каков текущий режим выполнения / уровень исключения и т. Д.?
ARM не требует наличия всех уровней исключений, чтобы позволить реализациям, которым не нужна функция для экономии области чипа. ARMv8 «Уровни исключения» говорит:
Реализация может не включать все уровни исключений. Все реализации должны включать EL0 и EL1. EL2 и EL3 не являются обязательными.
QEMU, например, по умолчанию имеет значение EL1, но EL2 и EL3 можно включить с помощью параметров командной строки: qemu-system-aarch64, ввод el1 при эмуляции включения питания a53
Фрагменты кода протестированы на Ubuntu 18.10.
in
и out
доступен для звонка 3. TSS может указывать на таблицу разрешений ввода-вывода в текущей задаче, предоставляя доступ для чтения / записи ко всем или определенным портам.
Я собираюсь нанести удар в темноте и предположить, что вы говорите о Windows. Короче говоря, режим ядра имеет полный доступ к оборудованию, а пользовательский режим - нет. Например, многие, если не большинство драйверов устройств, написаны в режиме ядра, потому что им нужно контролировать более тонкие детали своего оборудования.
См. Также эту вики-книгу .
Другие ответы уже объясняли разницу между пользовательским режимом и режимом ядра. Если вы действительно хотите вдаваться в подробности, вы должны получить копию Windows Internals , отличную книгу, написанную Марком Руссиновичем и Дэвидом Соломоном, в которой описывается архитектура и внутренние детали различных операционных систем Windows.
какой
По сути, разница между режимами ядра и пользователя не зависит от ОС и достигается только путем ограничения выполнения некоторых инструкций только в режиме ядра с помощью аппаратной конструкции. Все другие цели, такие как защита памяти, могут быть выполнены только с помощью этого ограничения.
Как
Это означает, что процессор живет либо в режиме ядра, либо в пользовательском режиме. Используя некоторые механизмы, архитектура может гарантировать, что всякий раз, когда она переключается в режим ядра, код ОС выбирается для запуска.
Зачем
Имея эту аппаратную инфраструктуру, они могут быть достигнуты в обычных ОС: