Яка різниця між режимами користувача та ядра в операційних системах?


104

Які відмінності між режимом користувача та режимом ядра, чому і як ви активуєте будь-який із них та які випадки їх використання?



1
@ CiroSantilli709 大 抓捕 六四 事件 法轮功 питання, яке було задано 7 років тому, не може бути закритим як дублікат на запитання, яке було задано 6 років тому. Якщо вони справді копії, закриття повинно бути навпаки.
Сальвадор Далі

2
@SalvadorDali Привіт, поточний консенсус - це закриття на "якість": meta.stackexchange.com/questions/147643/… Оскільки "якість" не піддається вимірюванню, я просто переходжу до рейтингів. ;-) Ймовірно, зводиться до того, яке питання потрапило у найкращі нові ключові слова Google у назві. Я закликаю вас просто скопіювати туди свою відповідь із застереженням, доданим внизу, та посилатись на цю, якщо вона закриється.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Відповіді:


143
  1. Режим ядра

    У режимі ядра виконуючий код має повний і необмежений доступ до базового обладнання. Він може виконати будь-яку інструкцію ЦП та посилатися на будь-яку адресу пам'яті. Режим ядра, як правило, зарезервований для найнижчих, найбільш надійних функцій операційної системи. Збої в режимі ядра катастрофічні; вони зупинять весь ПК.

  2. Режим користувача

    У режимі користувача виконавчий код не має можливості безпосередньо отримувати доступ до апаратної або довідкової пам'яті. Код, що працює в режимі користувача, повинен делегувати системні API для доступу до апаратного забезпечення або пам'яті. Завдяки захисту, що забезпечується таким видом ізоляції, збої в режимі користувача завжди підлягають відновленню. Більша частина коду, що працює на вашому комп’ютері, буде виконуватися в режимі користувача.

Детальніше

Розуміння режиму користувача та ядра


Цікаво, коли в процесорі працює код операційної системи, в якому режимі знаходиться процесор?
JackieLam

2
@JackieLam: Це повинно бути в режимі ядра.
kadina

Отже, щоби запустити процес простору користувача , його потрібно відобразити в просторі ядра ?
roottraveller

@rahul Я сумніваюся, що опорну пам'ять можна отримати в режимі користувача або що найпростіші маніпулювання даними призведе до зміни дорогого режиму в такій мові, як java.
maki XIE

48

Це два різних режими, в яких ваш комп'ютер може працювати. До цього, коли комп’ютери були як велика кімната, якщо щось виходить з ладу - це зупиняє весь комп'ютер. Тож комп'ютерні архітектори вирішують її змінити. Сучасні мікропроцесори реалізують в апараті щонайменше 2 різних стани.

Режим користувача:

  • режим, у якому виконуються всі користувацькі програми. Він не має доступу до оперативної пам’яті та обладнання. Причина цього полягає в тому, що якби всі програми працювали в режимі ядра, вони змогли б перезаписати пам'ять один одного. Якщо йому потрібно отримати доступ до будь-якої з цих функцій - він здійснює виклик до базового API. Кожен процес, запущений Windows, за винятком системного процесу, працює в режимі користувача.

Режим ядра:

  • режим, в якому виконуються всі програми ядра (різні драйвери). Він має доступ до кожного ресурсу та базового обладнання. Будь-яка інструкція з процесора може бути виконана і доступ до кожної адреси пам'яті. Цей режим зарезервований для водіїв, які працюють на найнижчому рівні

Як відбувається перемикання.

Перемикання з режиму користувача на режим ядра не відбувається автоматично процесором. Процесор переривається перериваннями (таймери, клавіатура, введення / виведення). Коли відбувається переривання, ЦП припиняє виконання поточної запущеної програми, переходить у режим ядра, виконує обробник переривання. Цей обробник зберігає стан процесора, виконує його операції, відновлює стан і повертається в режим користувача.

http://en.wikibooks.org/wiki/Windows_Programming/User_Mode_vs_Kernel_Mode

http://tldp.org/HOWTO/KernelAnalysis-HOWTO-3.html

http://en.wikipedia.org/wiki/Direct_memory_access

http://en.wikipedia.org/wiki/Interrupt_request


Цікаво, коли в процесорі працює код операційної системи, в якому режимі знаходиться процесор?
JackieLam

1
@JackieLam: режим ядра
Apurv Nerlekar

10

Процесор у комп’ютері під управлінням Windows має два різних режими: режим користувача та режим ядра. Процесор перемикається між двома режимами залежно від того, який тип коду працює на процесорі. Програми запускаються в режимі користувача, а основні компоненти операційної системи працюють у режимі ядра. Хоча багато драйверів працюють у режимі ядра, деякі драйвери можуть працювати в режимі користувача.

Коли ви запускаєте програму в режимі користувача, Windows створює процес для програми. Процес надає додатку приватний віртуальний адресний простір та приватну таблицю обробки. Оскільки віртуальний адресний простір програми приватний, одна програма не може змінювати дані, що належать іншій програмі. Кожна програма працює ізольовано, і якщо програма виходить з ладу, збій обмежений лише однією програмою. Інші програми та операційна система не впливають на збій.

Крім приватних, віртуальний адресний простір додатка в режимі користувача обмежений. Процесор, що працює в режимі користувача, не може отримати доступ до віртуальних адрес, зарезервованих для операційної системи. Обмеження віртуального адресного простору програми в режимі користувача не дозволяє додатку змінювати та, можливо, пошкоджувати критичні дані операційної системи.

Весь код, який працює в режимі ядра, розділяє один віртуальний адресний простір. Це означає, що драйвер режиму ядра не ізольований від інших драйверів та самої операційної системи. Якщо драйвер у режимі ядра випадково записується на неправильну віртуальну адресу, дані, що належать операційній системі або іншому драйверу, можуть бути порушені. Якщо драйвер у режимі ядра виходить з ладу, вся операційна система виходить з ладу.

Якщо ви є користувачем Windows один раз, перейшовши через це посилання, ви отримаєте більше.

Зв'язок між режимом користувача та режимом ядра


6

Кільця процесора - це найяскравіша відмінність

У захищеному режимі 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.

    • не може виконувати інструкції IO, як inі out, і, таким чином, мати довільний апаратний доступ.

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

      Точніше завдяки Майклу Петчу : насправді ОС може дозволити вказівки вводу-виводу на кільце 3, це фактично контролюється сегментом стану завдань .

      Що неможливо, це те, щоб кільце 3 давало собі дозвіл на це, якщо б його не було в першу чергу.

      Linux завжди забороняє це. Дивіться також: Чому Linux не використовує апаратний контекстний комутатор через TSS?

Як програми та операційні системи переходять між кільцями?

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

  • коли процес userland хоче, щоб ядро ​​щось для нього зробило, наприклад, записати у файл, воно використовує інструкцію, яка генерує переривання, наприклад, int 0x80абоsyscall для сигналізації ядра. Приклад світу syscall Linux x86-64 привіт:

    .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 вище за течією .

    Коли це відбувається, процесор викликає обробник зворотного виклику переривань, який ядро ​​зареєструвало під час завантаження. Ось конкретний бареметальний приклад, який реєструє обробник і використовує його .

    Цей обробник працює в кільці 0, яке вирішує, чи дозволить ядро ​​дозволити цю дію, зробіть дію та перезапустіть програмуlandland в кільці 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, і тому добре підходять для імені "негативне кільце".

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

Детальнішу інформацію див.

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 вище за течією .

    Перевірте це за допомогою 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інструкцією (безпечний виклик)

ARMv8 Architecture Reference Model DDI 0487C.a - Глава D1 - У AArch64 рівневої системи програміст Модель - Малюнок D1-1 ілюструє це красиво:

введіть тут опис зображення

Ситуація з ARM трохи змінилася з появою розширень хостів для віртуалізації ARMv8.1 (VHE) . Це розширення дозволяє ядру ефективно працювати в EL2:

введіть тут опис зображення

VHE був створений тому, що рішення для віртуалізації в ядрі Linux, такі як KVM, отримали позицію над Xen (див., Наприклад, перехід AWS до KVM, згаданий вище), тому що більшість клієнтів потребують лише VM Linux, і як ви можете собі уявити, будучи все в одному Проект, KVM простіший і потенційно ефективніший, ніж Xen. Тож тепер ядро ​​Linux 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.


1
Оскільки це запитання не характерне для будь-якої ОС, inі outвоно доступне для дзвінка 3. TSS може вказати на таблицю дозволів вводу-виводу в поточному завданні, що надає доступ для читання / запису на всі або конкретні порти.
Майкл Петч

Звичайно, ви встановлюєте біти IOPL значення 3, тоді програма ring 3 має повний доступ до порту, і дозволи на IOS TSS не застосовуються.
Майкл Петч

@MichaelPetch дякую, я цього не знав. Я оновив відповідь.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

5

Я збираюся зробити темний удар в темряві і здогадуюсь, що ви говорите про Windows. У двох словах, режим ядра має повний доступ до апаратного забезпечення, але користувальницький режим не робить. Наприклад, багато, якщо не більшість драйверів пристроїв написані в режимі ядра, оскільки їм потрібно контролювати більш детальні деталі свого обладнання.

Дивіться також цю вікі-книгу .


2
Це важливо для вас, як програміста, тому що помилки ядра, як правило, сприймають набагато гірші наслідки, ніж ви, можливо, звикли. Однією з причин розрізнення ядра / користувача є те, що ядро ​​може контролювати / контролювати критичні системні ресурси та захищати кожного користувача від інших. Це трохи спрощено, але все ж корисно, щоб нагадати собі, що помилки користувачів часто дратують, але помилки ядра, як правило, збивають всю машину.
Адам Лісс

3

Інші відповіді вже пояснювали різницю між режимом користувача та ядра. Якщо ви дійсно хочете детальніше ознайомитись, вам слід отримати копію Windows Internals , відмінну книгу, яку написали Марк Русинович та Девід Соломон, що описує архітектуру та внутрішні деталі різних операційних систем Windows.


2

Що

В основному різниця між режимами ядра та користувачем не залежить від ОС і досягається лише обмеженням деяких інструкцій, які можна виконувати лише в режимі ядра за допомогою апаратного проектування. Усі інші цілі, такі як захист пам’яті, можна виконати лише цим обмеженням.

Як

Це означає, що процесор живе або в режимі ядра, або в режимі користувача. Використовуючи деякі механізми, архітектура може гарантувати, що кожен раз, коли він перейде в режим ядра, код ОС буде завантажений для запуску.

Чому?

Маючи цю апаратну інфраструктуру, цього можна досягти в загальних ОС:

  • Захист програм користувача від доступу до всієї пам’яті, щоб не дозволяти програмам перезаписувати ОС, наприклад,
  • запобігання програмам користувачів виконувати чутливі інструкції, такі як ті, що змінюють межі вказівника на процесор, наприклад, не дозволяють програмам порушувати межі своєї пам'яті.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.