В чем разница между пространством ядра и пространством пользователя? - PullRequest
129 голосов
/ 11 мая 2011

В чем разница между пространством ядра и пространством пользователя? Означает ли пространство ядра, потоки ядра, процессы ядра и стек ядра одно и то же? Кроме того, зачем нам эта дифференциация?

Ответы [ 16 ]

110 голосов
/ 11 мая 2011

Упрощенный ответ действительно заключается в том, что ядро ​​работает в пространстве ядра, а обычные программы - в пространстве пользователя.Пространство пользователя в основном является формой песочницы - оно ограничивает пользовательские программы, чтобы они не могли связываться с памятью (и другими ресурсами), принадлежащими другим программам или ядру ОС.Это ограничивает (но обычно не полностью исключает) их способность совершать плохие вещи, такие как сбой машины.

Ядро - это ядро ​​операционной системы.Обычно он имеет полный доступ ко всей памяти и оборудованию машины (и всему остальному на машине).Чтобы обеспечить максимальную стабильность машины, обычно требуется, чтобы в режиме ядра / пространстве ядра выполнялся только самый проверенный и хорошо протестированный код.

Стек - это просто другая часть памяти, поэтому, естественно, он разделен правильновместе с остальной памятью.

61 голосов
/ 26 марта 2012

Память с произвольным доступом 1002 * (RAM) может быть логически разделена на две отдельные области, а именно - пространство ядра и пространство пользователя. ( Физические адреса RAM)фактически не разделены только виртуальные адреса , все это реализовано MMU )

Ядро работает в той части памяти, которая ему предоставлена.Эта часть памяти не может быть доступна напрямую процессам обычных пользователей, поскольку ядро ​​может получить доступ ко всем частям памяти.Чтобы получить доступ к некоторой части ядра, пользовательские процессы должны использовать предопределенные системные вызовы, например open, read, write и т. Д. Кроме того, функции библиотеки C, такие как printf, вызывают системный вызов * 1018.* в очереди.

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

Таким образом, когда происходит системный вызов, в ядро ​​отправляется программное прерывание.ЦПУ может временно передать управление соответствующей подпрограмме обработки прерывания.Процесс ядра, который был остановлен прерываниями, возобновляется после того, как подпрограмма обработчика прерываний завершает свою работу.

22 голосов
/ 31 августа 2014

Пространство ядра и виртуальное пространство - это понятия виртуальной памяти .... это не означает, что Ram (ваша фактическая память) разделен на ядро ​​и пространство пользователя.Каждому процессу предоставляется виртуальная память, которая разделена на ядро ​​и пространство пользователя.

Скажем так: «Оперативная память (RAM) может быть разделена на две отдельные области, а именно - пространство ядра и пространство пользователя«.не так.

и что касается понятия "пространство ядра или пространство пользователя"

Когда процесс создается и его виртуальная память делится на пространство пользователя и пространство ядра, где область пространства пользователясодержит данные, код, стек, кучу процесса и пространство ядра. Содержит такие вещи, как таблица страниц процесса, структуры данных ядра, код ядра и т. д. Для запуска кода пространства ядра управление должно перейти в режим ядра (с использованием программного обеспечения 0x80прерывание для системных вызовов) и стек ядра в основном распределяется между всеми процессами, выполняемыми в настоящее время в пространстве ядра.

12 голосов

Кольца процессора - самое четкое различие

В защищенном режиме x86 процессор всегда находится в одном из 4 звонков. Ядро Linux использует только 0 и 3:

  • 0 для ядра
  • 3 для пользователей

Это наиболее сложное и быстрое определение ядра и пользовательского пространства.

Почему Linux не использует кольца 1 и 2: Кольца привилегий ЦП: почему кольца 1 и 2 не используются?

Как определяется текущее кольцо?

Текущее кольцо выбирается комбинацией:

  • таблица глобальных дескрипторов: таблица в памяти записей GDT, и каждая запись имеет поле Privl, которое кодирует кольцо.

    Инструкция LGDT устанавливает адрес для текущей таблицы дескрипторов.

    Смотри также: http://wiki.osdev.org/Global_Descriptor_Table

  • регистры сегментов CS, DS и т. Д., Которые указывают на индекс записи в GDT.

    Например, CS = 0 означает, что первая запись GDT в данный момент активна для исполняемого кода.

Что может делать каждое кольцо?

Чип процессора физически построен так, что:

  • кольцо 0 может делать что угодно

  • кольцо 3 не может выполнить несколько инструкций и записать в несколько регистров, в частности:

    • не может изменить свое собственное кольцо! В противном случае он мог бы установить себе кольцо 0, и кольца были бы бесполезны.

      Другими словами, нельзя изменить текущий дескриптор сегмента , который определяет текущее кольцо.

    • не может изменить таблицы страниц: Как работает подкачка x86?

      Другими словами, невозможно изменить регистр CR3, а само разбиение на страницы предотвращает изменение таблиц страниц.

      Это препятствует тому, чтобы один процесс видел память других процессов из соображений безопасности / простоты программирования.

    • не может зарегистрировать обработчики прерываний. Они настраиваются путем записи в ячейки памяти, что также предотвращается подкачкой.

      Обработчики работают в кольце 0 и нарушают модель безопасности.

      Другими словами, нельзя использовать инструкции LGDT и LIDT.

    • не может выполнять команды ввода-вывода, такие как in и out, и, следовательно, имеет произвольный доступ к оборудованию.

      В противном случае, например, права доступа к файлам будут бесполезны, если какая-либо программа сможет напрямую читать с диска.

      Точнее, благодаря Michael Petch : на самом деле ОС может разрешить инструкции ввода-вывода на кольце 3, это фактически контролируется сегментом состояния задачи .

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

      Linux всегда запрещает это. См. Также: Почему Linux не использует аппаратный переключатель контекста через TSS?

Как программы и операционные системы переходят между кольцами?

  • когда процессор включен, он запускает начальную программу в кольце 0 (что-то вроде, но это хорошее приближение). Вы можете считать эту исходную программу ядром (но обычно это загрузчик, который затем вызывает ядро ​​все еще в кольце 0).

  • когда пользовательский процесс хочет, чтобы ядро ​​сделало что-то для него, например, запись в файл, он использует инструкцию, которая генерирует прерывание, например int 0x80 или syscall, чтобы сигнализировать ядро. x86-64 Linux syscall 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
    

    GitHub upstream .

    Когда это происходит, ЦП вызывает обработчик обратного вызова прерывания, который ядро ​​зарегистрировало во время загрузки. Вот конкретный пример baremetal, который регистрирует обработчик и использует его .

    Этот обработчик работает в кольце 0, который решает, разрешит ли ядро ​​это действие, выполняет действие и перезапускает программу пользователя в кольце 3. x86_64

  • когда используется системный вызов exec (или когда запускается ядро ​​ /init), ядро ​​ подготавливает регистры и память нового пользовательского пространства процесс, затем он переходит к точке входа и переключает ЦП на звонок 3

  • Если программа пытается сделать что-то непослушное, например запись в запрещенный регистр или адрес памяти (из-за подкачки), ЦП также вызывает некоторый обработчик обратного вызова ядра в кольце 0.

    Но поскольку пользовательская область была непослушной, ядро ​​на этот раз может завершить процесс или выдать ему предупреждение с сигналом.

  • Когда ядро ​​загружается, оно устанавливает аппаратные часы с некоторой фиксированной частотой, которая периодически генерирует прерывания.

    Эти аппаратные часы генерируют прерывания, которые запускают кольцо 0, и позволяют ему планировать, какие пользовательские процессы должны активизироваться.

    Таким образом, планирование может происходить, даже если процессы не выполняют никаких системных вызовов.

Какой смысл иметь несколько колец?

Существует два основных преимущества разделения ядра и пользовательского пространства:

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

Как с этим поиграться?

Я создал голую металлическую установку, которая должна быть хорошим способом для непосредственного управления кольцами: https://github.com/cirosantilli/x86-bare-metal-examples

К сожалению, у меня не хватило терпения сделать пример пользовательского пространства, но я дошел до настройки пейджинга, поэтому пользовательское пространство должно быть выполнимым. Я хотел бы увидеть запрос на получение разрешения.

В качестве альтернативы модули ядра Linux работают в кольце 0, так что вы можете использовать их для проверки привилегированных операций, например, прочитайте управляющие регистры: Как получить доступ к управляющим регистрам cr0, cr2, cr3 из программы? Получение ошибки сегментации

Вот удобная настройка QEMU + Buildroot , чтобы попробовать его, не убивая ваш хост.

Недостатком модулей ядра является то, что другие kthreads работают и могут мешать вашим экспериментам. Но в теории вы можете взять на себя все обработчики прерываний с вашим модулем ядра и владеть системой, на самом деле это был бы интересный проект.

отрицательные кольца

Хотя отрицательные кольца фактически не упоминаются в руководстве Intel, на самом деле существуют режимы ЦП, которые имеют более широкие возможности, чем само кольцо 0, и поэтому хорошо подходят для имени «отрицательного кольца».

Одним из примеров является режим гипервизора, используемый в виртуализации.

Подробнее см .: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1

ARM

В 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
    

    GitHub upstream .

    Протестируйте его с 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).

    Гипервизор для ОС, то же самое, что ОС для пользовательского пространства.

    Например, Xen позволяет вам запускать несколько ОС, таких как Linux или Windows, в одной и той же системе одновременно, и он изолирует ОС друг от друга для обеспечения безопасности и простоты отладки, как это делает Linux для пользовательских программ.

    Гипервизоры являются ключевой частью современной облачной инфраструктуры: они позволяют нескольким серверам работать на одном оборудовании, поддерживая аппаратное использование всегда близким к 100% и экономя большие деньги.

    AWS дляВ примере использовался Xen до 2017 года, когда его переход на KVM сделал новостью .

  • EL3: еще один уровень.Пример TODO.

    Введено с помощью инструкции smc (вызов в безопасном режиме)

Справочная модель архитектуры ARMv8 DDI 0487C.a - ГлаваD1 - Модель программиста на уровне системы AArch64 - Рисунок D1-1 прекрасно иллюстрирует это:

enter image description here

Обратите внимание, как ARM, возможно, благодаря ретроспективному анализу,имеет лучшее соглашение об именах для уровней привилегий, чем x86, без необходимости использования отрицательных уровней: 0 - самый низкий, а 3 - самый высокий.Более высокие уровни, как правило, создаются чаще, чем более низкие.

Текущий EL может быть запрошен с помощью инструкции MRS: Каков текущий режим выполнения / уровень исключения и т. Д.?

ARM не требует наличия всех уровней исключений, чтобы обеспечить реализации, которым не требуется эта функция для сохранения площади микросхемы.ARMv8 «Уровни исключений» гласит:

Реализация может включать не все уровни исключений.Все реализации должны включать EL0 и EL1.EL2 и EL3 являются необязательными.

Например, QEMU по умолчанию имеет значение EL1, но EL2 и EL3 можно включить с помощью параметров командной строки: qemu-system-aarch64 вводит el1 при эмуляции включения питания a53

Фрагменты кода, протестированные в Ubuntu 18.10.

10 голосов
/ 11 мая 2011

Пространство ядра и пространство пользователя - это разделение функций привилегированной операционной системы и ограниченных пользовательских приложений. Разделение необходимо для того, чтобы пользовательские приложения не могли обыскать ваш компьютер. Было бы плохо, если бы любая старая пользовательская программа могла начать запись случайных данных на ваш жесткий диск или считывать память из пространства памяти другой пользовательской программы.

Программы пространства пользователя не могут обращаться к системным ресурсам напрямую, поэтому доступ осуществляется от имени программы ядром операционной системы. Программы пользовательского пространства обычно делают такие запросы операционной системы через системные вызовы.

Потоки ядра, процессы, стек не означают одно и то же. Они являются аналогичными конструкциями для пространства ядра и их аналогами в пространстве пользователя.

7 голосов
/ 02 июня 2011

Каждый процесс имеет 4 ГБ виртуальной памяти, которая отображается на физическую память через таблицы страниц. Виртуальная память в основном разделена на две части: 3 ГБ для использования процесса и 1 ГБ для использования ядра. Большинство переменных, которые вы создаете, находятся в первой части адресного пространства. Эта часть называется пользовательским пространством. В последней части находится ядро, общее для всех процессов. Это называется пространством ядра, и большая часть этого пространства отображается на начальные места физической памяти, куда загружается образ ядра во время загрузки.

5 голосов
/ 25 марта 2016

Максимальный размер адресного пространства зависит от длины адресного регистра в ЦП.

В системах с 32-разрядными адресными регистрами максимальный размер адресного пространства составляет 2 32 * 1004.* байтов или 4 ГиБ.Аналогично, в 64-разрядных системах можно адресовать 2 64 байтов.

Такое адресное пространство называется виртуальная память или виртуальное адресное пространство ,На самом деле он не связан с физическим размером ОЗУ.

На платформах Linux виртуальное адресное пространство делится на пространство ядра и пространство пользователя.

Константа для конкретной архитектуры, называемая ограничение размера задачи или TASK_SIZE отмечает позицию, в которой происходит разделение:

  • диапазон адресов от 0 до TASK_SIZE -1 выделен для пространства пользователя;

  • остаток от TASK_SIZE до 2 32 -1 (или 2 64 -1) выделяется для пространства ядра.

Например, в конкретной 32-разрядной системе 3 ГБ могут быть заняты для пространства пользователя и 1 ГБ для пространства ядра.

Каждое приложение / программа в Unix-подобной операционной системеэто процесс;каждый из них имеет уникальный идентификатор, называемый Идентификатор процесса (или просто Идентификатор процесса , то есть PID).Linux предоставляет два механизма для создания процесса: 1. системный вызов fork() или 2. вызов exec().

Поток ядра - это легкий процесс, а также исполняемая программа.Один процесс может состоять из нескольких потоков, совместно использующих одни и те же данные и ресурсы, но проходящих разные пути через программный код.Linux обеспечивает системный вызов clone() для генерации потоков.

Примеры использования потоков ядра: синхронизация данных в ОЗУ, помощь планировщику в распределении процессов между процессорами и т. Д.

4 голосов
/ 04 августа 2013

Вкратце: ядро ​​работает в пространстве ядра, пространство ядра имеет полный доступ ко всей памяти и ресурсам, можно сказать, что память делится на две части, часть для ядра и часть для собственного процесса пользователя (пространство пользователя) работает нормальнопрограммы, пользовательское пространство не может получить прямой доступ к пространству ядра, поэтому оно запрашивает у ядра использование ресурсов.по syscall (предопределенный системный вызов в glibc)

есть оператор, упрощающий различные " пространство пользователя - это просто тестовая загрузка для ядра " ...

Чтобы быть очень ясным: архитектура процессора позволяет процессору работать в двух режимах, Режим ядра и Пользовательский режим , инструкция Аппаратного обеспечения позволяет переключаться из одного режима в другой.

память может быть помечена как часть пространства пользователя или пространства ядра.

Когда процессор работает в пользовательском режиме, процессор может обращаться только к памяти, находящейся в пространстве пользователя, в то время как процессор пытается получить доступ к памяти в пространстве ядра.В результате получается «аппаратное исключение», когда ЦП работает в режиме ядра, ЦП может напрямую обращаться как к пространству ядра, так и к пространству пользователя ...

2 голосов
/ 09 августа 2014

Пространство ядра означает, что пространство памяти может быть затронуто только ядром.В 32-битном Linux это 1G (от 0xC0000000 до 0xffffffff в качестве адреса виртуальной памяти). Каждый процесс, созданный ядром, также является потоком ядра, поэтому для одного процесса существует два стека: один стек в пространстве пользователя для этого процесса и другой в ядрепространство для потока ядра.

стек ядра занимает 2 страницы (8k в 32-битном linux), включает task_struct (около 1k) и реальный стек (около 7k).Последний используется для хранения некоторых автоматических переменных или параметров вызова функции или адреса функции в функциях ядра.Вот код (Processor.h (linux \ include \ asm-i386)):

#define THREAD_SIZE (2*PAGE_SIZE)
#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
#define free_task_struct(p) free_pages((unsigned long) (p), 1)

__ get_free_pages (GFP_KERNEL, 1)) означает выделение памяти как 2 ^ 1 = 2 страницы.

Но стек процессов - это другое дело, его адрес просто ниже 0xC0000000 (32-битный linux), его размер может быть значительно больше, используется для вызовов функций из пространства пользователя.

Итак, вот вопросдля системного вызова он выполняется в пространстве ядра, но был вызван процессом в пространстве пользователя, как он работает?Положит ли linux свои параметры и адрес функции в стек ядра или в стек процессов?Решение Linux: все системные вызовы запускаются программным прерыванием INT 0x80.Определено в entry.S (linux \ arch \ i386 \ kernel), вот несколько строк, например:

ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall)   /* 0  -  old "setup()" system call*/
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork)
.long SYMBOL_NAME(sys_read)
.long SYMBOL_NAME(sys_write)
.long SYMBOL_NAME(sys_open)     /* 5 */
.long SYMBOL_NAME(sys_close)
2 голосов
/ 09 марта 2014

IN короткое пространство ядра - это часть памяти, в которой работает ядро ​​linux (верхнее 1 ГБ виртуального пространства в случае linux), а пространство пользователя - это часть памяти, в которой запускается пользовательское приложение (нижние 3 ГБ виртуальной памяти в случае LinuxЕсли вы хотите узнать больше, см. Ссылку ниже:)

http://learnlinuxconcepts.blogspot.in/2014/02/kernel-space-and-user-space.html

...