Да, ядро имеет свой собственный стек, кучу, структуры данных и код, отдельный от каждого пользовательского процесса.
Код, работающий в ядре, сам по себе не рассматривается как «процесс». Код является привилегированным , что означает, что он может изменять любые данные в ядре, устанавливать привилегированные биты в регистрах процессора, отправлять прерывания, взаимодействовать с устройствами, выполнять привилегированные инструкции и т. Д. Он не ограничен, как код пользователя процесс.
Вся память ядра и пользовательская память процесса хранятся в физической памяти компьютера (или, возможно, на диске, если данные были выгружены из памяти).
Ключом к ответу на остальные вопросы является понимание разницы между физической памятью и виртуальной памятью. Помните, что если вы используете адрес виртуальной памяти для доступа к данным, этот виртуальный адрес преобразуется в физический адрес до того, как данные будут получены по определенному физическому адресу.
Каждый процесс имеет свое собственное виртуальное адресное пространство. Это означает, что некоторый виртуальный адрес a в одном процессе может отображаться на физический адрес, отличный от того же виртуального адреса a в другом процессе. Виртуальная память имеет много важных применений, но я не буду вдаваться в них здесь. Важным моментом является то, что виртуальная память обеспечивает изоляцию памяти . Это означает, что процесс A не может получить доступ к памяти процесса B. Все виртуальные адреса процесса A отображаются на некоторый набор физических адресов, а все виртуальные адреса процесса B отображаются на другой набор физических адресов. Пока два набора физических адресов не перекрываются, процессы не могут видеть или изменять память друг друга. Пользовательские процессы не могут обращаться к физическим адресам памяти напрямую - они могут осуществлять доступ к памяти только с виртуальными адресами.
Бывают случаи, когда два процесса могут иметь несколько виртуальных адресов, которые отображаются на одинаковые физические адреса, например, если они оба отображают один и тот же файл, оба используют общую библиотеку и т. Д.
Теперь ответим на ваш вопрос об адресных пространствах ядра и адресных пространствах пользователей.
Ядро может иметь отдельное виртуальное адресное пространство от каждого пользовательского процесса. Это так же просто, как изменение указателя каталога страниц в регистре cr3
(в процессоре x86) при каждом переключении контекста. Поскольку ядро имеет другое виртуальное адресное пространство, ни один пользовательский процесс не может получить доступ к памяти ядра, если ни один из адресов виртуальной памяти ядра не сопоставляется с теми же физическими адресами, что и любой из виртуальных адресов в любом адресном пространстве для пользовательского процесса.
Это может привести к незначительной проблеме. Если пользовательский процесс выполняет системный вызов и передает указатель в качестве параметра (например, указатель на буфер в системном вызове read
), как ядро узнает, какой физический адрес соответствует этому буферу? Виртуальный адрес в указателе отображается на другой физический адрес в пространстве ядра, поэтому ядро не может просто разыменовать указатель. Есть два варианта:
Ядро может просматривать каталог / таблицы страниц пользовательского процесса, чтобы найти физический адрес, который соответствует буферу. Затем ядро может выполнять чтение / запись с / на этот физический адрес.
Ядро может вместо этого включить все свои отображения в адресное пространство пользователя (в верхней части адресного пространства пользователя, как вы упомянули). Теперь, когда ядро получает указатель через системный вызов, оно может просто получить доступ к указателю напрямую, поскольку оно разделяет адресное пространство с процессом.
Ядра обычно идут со вторым вариантом, так как он более удобен и эффективен. Вариант 1 менее эффективен, потому что каждый раз, когда происходит переключение контекста, изменяется адресное пространство, поэтому необходимо сбросить TLB, и теперь вы потеряете все свои кэшированные отображения. Здесь я немного упростил ситуацию, поскольку ядра начали работать по-другому, учитывая недавно обнаруженную уязвимость Meltdown.
Это приводит к другой проблеме. Если ядро включает свои отображения в адресное пространство пользовательских процессов, что мешает пользовательскому процессу получить доступ к памяти ядра? Ядро устанавливает защитные биты в таблице страниц, которые заставляют процессор запрещать пользовательскому процессу доступ к виртуальным адресам, которые сопоставляются с физическими адресами, содержащими память ядра.
Посмотрите эти слайды для получения дополнительной информации.