Jaka jest różnica między trybem użytkownika a trybem jądra w systemach operacyjnych?

105

Jakie są różnice między trybem użytkownika a trybem jądra, dlaczego i jak aktywujesz jeden z nich i jakie są ich przypadki użycia?

Alex
źródło
1
Możliwy duplikat Jaka jest różnica między przestrzenią jądra a przestrzenią użytkownika?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@ CiroSantilli709 大 抓捕 六四 事件 法轮功 pytanie zadane 7 lat temu nie może być zamknięte jako duplikat pytania zadanego 6 lat temu. Jeśli naprawdę są duplikatami, zamknięcie powinno być odwrotnie.
Salvador Dali
2
@SalvadorDali Cześć, obecny konsensus to „jakość”: meta.stackexchange.com/questions/147643/… Ponieważ „jakości” nie da się zmierzyć, po prostu przechodzę przez pozytywne głosy. ;-) Najprawdopodobniej sprowadza się to do tego, które pytanie trafiło w najlepsze nowe słowa kluczowe Google w tytule. Zachęcam do skopiowania tam swojej odpowiedzi z zastrzeżeniem dodanym na dole i linkiem z tego, na wypadek gdyby się zamykał.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

144
  1. Tryb jądra

    W trybie jądra wykonywany kod ma pełny i nieograniczony dostęp do podstawowego sprzętu. Może wykonać dowolną instrukcję procesora i odwołać się do dowolnego adresu pamięci. Tryb jądra jest zwykle zarezerwowany dla najniższego poziomu, najbardziej zaufanych funkcji systemu operacyjnego. Awarie w trybie jądra są katastrofalne; zatrzymają cały komputer.

  2. Tryb użytkownika

    W trybie użytkownika kod wykonawczy nie ma możliwości bezpośredniego dostępu do sprzętu lub pamięci odniesienia. Kod działający w trybie użytkownika musi przekazywać do systemowych interfejsów API dostęp do sprzętu lub pamięci. Ze względu na ochronę zapewnianą przez ten rodzaj izolacji awarie w trybie użytkownika są zawsze możliwe do odzyskania. Większość kodu działającego na komputerze zostanie wykonana w trybie użytkownika.

Czytaj więcej

Zrozumienie trybu użytkownika i jądra

rahul
źródło
Zastanawiam się, kiedy procesor uruchamia kod systemu operacyjnego, w którym trybie znajduje się procesor?
JackieLam
2
@JackieLam: Powinien być w trybie jądra.
kadina
Czyli per se, aby uruchomić proces przestrzeni użytkownika , musi on zostać zmapowany do przestrzeni jądra ?
roottraveller
@rahul Wątpię, czy pamięć referencyjną można uzyskać w trybie użytkownika lub czy najprostsza manipulacja danymi spowoduje kosztowną zmianę trybu w języku takim jak java.
maki XIE
48

Są to dwa różne tryby, w których może działać komputer. Wcześniej, gdy komputery były jak duży pokój, jeśli coś się zawiesza - zatrzymuje cały komputer. Architekci komputerów decydują się więc na zmianę. Nowoczesne mikroprocesory implementują sprzętowo co najmniej 2 różne stany.

Tryb użytkownika:

  • tryb, w którym wykonywane są wszystkie programy użytkownika. Nie ma dostępu do pamięci RAM i sprzętu. Powodem tego jest to, że gdyby wszystkie programy działały w trybie jądra, byłyby w stanie nadpisywać pamięć innych użytkowników. Jeśli potrzebuje dostępu do którejkolwiek z tych funkcji - wykonuje wywołanie do bazowego interfejsu API. Każdy proces uruchamiany przez system Windows, z wyjątkiem procesu systemowego, działa w trybie użytkownika.

Tryb jądra:

  • tryb, w którym wykonywane są wszystkie programy jądra (różne sterowniki). Ma dostęp do wszystkich zasobów i podstawowego sprzętu. Można wykonać dowolną instrukcję CPU i uzyskać dostęp do każdego adresu pamięci. Ten tryb jest zarezerwowany dla kierowców działających na najniższym poziomie

Jak następuje zmiana.

Przejście z trybu użytkownika do trybu jądra nie jest wykonywane automatycznie przez procesor. Procesor jest przerywany przez przerwania (timery, klawiatura, I / O). Kiedy wystąpi przerwanie, CPU przestaje wykonywać aktualnie działający program, przełącza się w tryb jądra, wykonuje obsługę przerwań. Ten program obsługi zapisuje stan procesora, wykonuje swoje operacje, przywraca stan i powraca do trybu użytkownika.

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

Salvador Dali
źródło
Zastanawiam się, kiedy procesor uruchamia kod systemu operacyjnego, w którym trybie znajduje się procesor?
JackieLam
1
@JackieLam: tryb jądra
Apurv Nerlekar
10

Procesor w komputerze z systemem Windows ma dwa różne tryby: tryb użytkownika i tryb jądra. Procesor przełącza się między tymi dwoma trybami w zależności od typu kodu uruchomionego na procesorze. Aplikacje działają w trybie użytkownika, a podstawowe składniki systemu operacyjnego działają w trybie jądra. Podczas gdy wiele sterowników działa w trybie jądra, niektóre sterowniki mogą działać w trybie użytkownika.

Po uruchomieniu aplikacji w trybie użytkownika system Windows tworzy proces dla aplikacji. Proces zapewnia aplikacji prywatną wirtualną przestrzeń adresową i prywatną tablicę uchwytów. Ponieważ wirtualna przestrzeń adresowa aplikacji jest prywatna, jedna aplikacja nie może zmieniać danych należących do innej aplikacji. Każda aplikacja działa w izolacji, a jeśli aplikacja ulegnie awarii, awaria jest ograniczona do tej jednej aplikacji. Awaria nie ma wpływu na inne aplikacje i system operacyjny.

Oprócz tego, że jest prywatna, wirtualna przestrzeń adresowa aplikacji w trybie użytkownika jest ograniczona. Procesor działający w trybie użytkownika nie może uzyskać dostępu do adresów wirtualnych zarezerwowanych dla systemu operacyjnego. Ograniczenie wirtualnej przestrzeni adresowej aplikacji w trybie użytkownika uniemożliwia aplikacji zmianę i prawdopodobnie uszkodzenie krytycznych danych systemu operacyjnego.

Cały kod działający w trybie jądra korzysta z jednej wirtualnej przestrzeni adresowej. Oznacza to, że sterownik trybu jądra nie jest izolowany od innych sterowników i samego systemu operacyjnego. Jeśli sterownik trybu jądra przypadkowo zapisze pod nieprawidłowym adresem wirtualnym, dane należące do systemu operacyjnego lub innego sterownika mogą zostać naruszone. Awaria sterownika trybu jądra powoduje awarię całego systemu operacyjnego.

Jeśli jesteś użytkownikiem systemu Windows, po przejściu przez ten link otrzymasz więcej.

Komunikacja między trybem użytkownika a trybem jądra

Sangeen
źródło
6

Pierścienie procesora są najbardziej wyraźnym rozróżnieniem

W trybie chronionym x86 procesor jest zawsze w jednym z 4 pierścieni. Jądro Linuksa używa tylko 0 i 3:

  • 0 dla jądra
  • 3 dla użytkowników

Jest to najtrudniejsza i najszybsza definicja jądra i przestrzeni użytkownika.

Dlaczego Linux nie używa pierścieni 1 i 2: Pierścienie uprawnień procesora: Dlaczego pierścienie 1 i 2 nie są używane?

Jak jest określany obecny pierścień?

Bieżący dzwonek jest wybierany przez kombinację:

  • globalna tablica deskryptorów: tablica wpisów GDT w pamięci, a każdy wpis ma pole, Privlktóre koduje pierścień.

    Instrukcja LGDT ustawia adres na bieżącą tablicę deskryptorów.

    Zobacz także: http://wiki.osdev.org/Global_Descriptor_Table

  • rejestry segmentu CS, DS itp., które wskazują na indeks wpisu w GDT.

    Na przykład CS = 0oznacza, że ​​pierwszy wpis GDT jest obecnie aktywny dla kodu wykonawczego.

Co może zrobić każdy pierścionek?

Układ procesora jest fizycznie zbudowany tak, że:

  • ring 0 może zrobić wszystko

  • pierścień 3 nie może uruchomić kilku instrukcji i zapisać do kilku rejestrów, w szczególności:

    • nie może zmienić własnego pierścienia! W przeciwnym razie może ustawić się na dzwonek 0, a pierścienie byłyby bezużyteczne.

      Innymi słowy, nie może modyfikować deskryptora bieżącego segmentu , który określa bieżący pierścień.

    • nie można modyfikować tabel stron: Jak działa stronicowanie x86?

      Innymi słowy, nie może modyfikować rejestru CR3, a samo stronicowanie zapobiega modyfikowaniu tabel stron.

      Dzięki temu jeden proces nie widzi pamięci innych procesów ze względów bezpieczeństwa / łatwości programowania.

    • nie można zarejestrować programów obsługi przerwań. Są one konfigurowane przez zapisywanie w lokalizacjach pamięci, czemu zapobiega również stronicowanie.

      Programy obsługi działają w pierścieniu 0 i złamałyby model zabezpieczeń.

      Innymi słowy, nie może korzystać z instrukcji LGDT i LIDT.

    • nie mogą wykonywać instrukcji IO, takich jak ini out, a zatem mają dowolny dostęp do sprzętu.

      W przeciwnym razie, na przykład, uprawnienia do plików byłyby bezużyteczne, gdyby jakikolwiek program mógł bezpośrednio czytać z dysku.

      Dokładniej dzięki Michaelowi Petchowi : w rzeczywistości system operacyjny może zezwolić na instrukcje IO na pierścieniu 3, jest to faktycznie kontrolowane przez segment stanu zadania .

      Nie jest możliwe, aby pierścień 3 udzielił sobie na to pozwolenia, jeśli w ogóle go nie miał.

      Linux zawsze tego zabrania. Zobacz też: Dlaczego Linux nie używa sprzętowego przełączania kontekstu za pośrednictwem TSS?

W jaki sposób programy i systemy operacyjne przechodzą między pierścieniami?

  • gdy procesor jest włączony, zaczyna uruchamiać program początkowy w pierścieniu 0 (no cóż, ale jest to dobre przybliżenie). Możesz myśleć, że ten program początkowy jest jądrem (ale zwykle jest to program ładujący, który następnie wywołuje jądro wciąż w pierścieniu 0 ).

  • kiedy proces użytkownika chce, aby jądro zrobiło coś dla niego, na przykład zapis do pliku, używa instrukcji, która generuje przerwanie, takie jak int 0x80lub,syscall aby zasygnalizować jądro. x86-64 Linux syscall hello world przykład:

    .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
    

    skompiluj i uruchom:

    as -o hello_world.o hello_world.S
    ld -o hello_world.out hello_world.o
    ./hello_world.out
    

    GitHub upstream .

    Kiedy tak się dzieje, CPU wywołuje procedurę obsługi wywołania zwrotnego przerwania, którą jądro zarejestrowało podczas uruchamiania. Oto konkretny przykład baremetalu, który rejestruje program obsługi i używa go .

    Ten program obsługi działa w pierścieniu 0, który decyduje, czy jądro zezwoli na to działanie, wykona akcję i zrestartuje program przestrzeni użytkownika w pierścieniu 3. x86_64

  • gdy execużywane jest wywołanie systemowe (lub gdy jądro się uruchamia/init ), jądro przygotowuje rejestry i pamięć nowego procesu użytkownika, a następnie przeskakuje do punktu wejścia i przełącza procesor na pierścień 3

  • Jeśli program próbuje zrobić coś niegrzecznego, jak zapis do zabronionego rejestru lub adresu pamięci (z powodu stronicowania), procesor wywołuje również program obsługi wywołań zwrotnych jądra w pierścieniu 0.

    Ale ponieważ obszar użytkownika był niegrzeczny, jądro może tym razem zabić proces lub dać mu ostrzeżenie za pomocą sygnału.

  • Kiedy jądro uruchamia się, ustawia zegar sprzętowy z pewną stałą częstotliwością, która okresowo generuje przerwania.

    Ten zegar sprzętowy generuje przerwania, które uruchamiają pierścień 0 i pozwalają mu zaplanować, które procesy użytkownika mają się wybudzić.

    W ten sposób planowanie może mieć miejsce nawet wtedy, gdy procesy nie wykonują żadnych wywołań systemowych.

Jaki jest sens posiadania wielu dzwonków?

Istnieją dwie główne zalety oddzielenia jądra od obszaru użytkownika:

  • tworzenie programów jest łatwiejsze, ponieważ masz większą pewność, że jeden z nich nie będzie kolidował z drugim. Np. Jeden proces w przestrzeni użytkownika nie musi martwić się o nadpisanie pamięci innego programu z powodu stronicowania, ani o wprowadzenie sprzętu w stan nieprawidłowy dla innego procesu.
  • jest bezpieczniejszy. Np. Uprawnienia do plików i separacja pamięci mogą uniemożliwić aplikacji hakerskiej odczyt danych bankowych. To oczywiście zakłada, że ​​ufasz jądru.

Jak się tym bawić?

Stworzyłem gotowy zestaw metalowy, który powinien być dobrym sposobem na bezpośrednie manipulowanie pierścieniami: https://github.com/cirosantilli/x86-bare-metal-examples

Niestety nie miałem cierpliwości, by stworzyć przykład przestrzeni użytkownika, ale posunąłem się do konfiguracji stronicowania, więc przestrzeń użytkownika powinna być wykonalna. Bardzo chciałbym zobaczyć prośbę o wycofanie.

Alternatywnie, moduły jądra Linuksa działają w pierścieniu 0, więc możesz ich użyć do wypróbowania uprzywilejowanych operacji, np. Odczytu rejestrów kontrolnych: Jak uzyskać dostęp do rejestrów kontrolnych cr0, cr2, cr3 z programu? Uzyskanie błędu segmentacji

Oto wygodna konfiguracja QEMU + Buildroot, aby wypróbować ją bez zabijania hosta.

Wadą modułów jądra jest to, że inne k-wątki działają i mogą zakłócać twoje eksperymenty. Ale teoretycznie możesz przejąć wszystkie programy obsługi przerwań swoim modułem jądra i posiadać system, to byłby właściwie interesujący projekt.

Pierścienie ujemne

Chociaż w podręczniku Intela nie ma odniesień do pierścieni ujemnych, w rzeczywistości istnieją tryby procesora, które mają większe możliwości niż sam pierścień 0, a zatem dobrze pasują do nazwy „pierścień ujemny”.

Jednym z przykładów jest tryb hiperwizora używany w wirtualizacji.

Więcej informacji:

RAMIĘ

W ARM pierścienie nazywane są zamiast tego poziomami wyjątków, ale główne pomysły pozostają takie same.

Istnieją 4 poziomy wyjątków w ARMv8, powszechnie używane jako:

  • EL0: obszar użytkownika

  • EL1: jądro („nadzorca” w terminologii ARM).

    Wprowadzono z svcinstrukcją (wywołanie SuperVisor), wcześniej znaną jako swi przed ujednoliconym asemblacją , która jest instrukcją używaną do wykonywania wywołań systemu Linux. Przykład Hello world ARMv8:

    przywitania

    .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 .

    Przetestuj z QEMU na 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
    

    Oto konkretny przykład baremetal, który rejestruje program obsługi SVC i wywołuje SVC .

  • EL2: hiperwizory , na przykład Xen .

    Wprowadzono z hvcinstrukcją (połączenie HyperVisor).

    Hiperwizor jest dla systemu operacyjnego, czym system operacyjny dla obszaru użytkownika.

    Na przykład Xen pozwala na jednoczesne uruchamianie wielu systemów operacyjnych, takich jak Linux lub Windows w tym samym systemie, i izoluje systemy operacyjne od siebie w celu zapewnienia bezpieczeństwa i łatwości debugowania, tak jak Linux robi to w programach użytkownika.

    Hiperwizory są kluczową częścią dzisiejszej infrastruktury chmurowej: umożliwiają działanie wielu serwerów na jednym sprzęcie, utrzymując wykorzystanie sprzętu na poziomie bliskim 100% i oszczędzając dużo pieniędzy.

    Na przykład AWS używał Xena do 2017 roku, kiedy jego przejście na KVM pojawiło się w wiadomościach .

  • EL3: kolejny poziom. Przykład TODO.

    Wprowadzono z smcinstrukcją (połączenie w trybie bezpiecznym)

ARMv8 Architektura Model referencyjny DDI 0487C.a - Rozdział D1 - na poziomie systemu AArch64 programisty Model - Rysunek D1-1 ilustruje to pięknie:

wprowadź opis obrazu tutaj

Sytuacja ARM zmieniła się nieco wraz z pojawieniem się rozszerzeń hosta wirtualizacji ARMv8.1 (VHE) . To rozszerzenie umożliwia wydajne działanie jądra w EL2:

wprowadź opis obrazu tutaj

VHE zostało stworzone, ponieważ rozwiązania wirtualizacji w jądrze Linuksa, takie jak KVM, zyskały przewagę nad Xen (patrz np. Przejście AWS na KVM wspomniane powyżej), ponieważ większość klientów potrzebuje tylko maszyn wirtualnych z systemem Linux i, jak możesz sobie wyobrazić, wszystko w jednym projekt KVM jest prostszy i potencjalnie bardziej wydajny niż Xen. Więc teraz jądro Linuksa-hosta działa w takich przypadkach jako hiperwizor.

Zwróć uwagę, że ARM, być może z perspektywy czasu, ma lepszą konwencję nazewnictwa poziomów uprawnień niż x86, bez potrzeby stosowania poziomów ujemnych: 0 oznacza niższy, a 3 najwyższy. Wyższe poziomy są zwykle tworzone częściej niż niższe.

Bieżący EL można zapytać za pomocą MRSinstrukcji: jaki jest bieżący tryb wykonywania / poziom wyjątku itp.?

ARM nie wymaga obecności wszystkich poziomów wyjątków, aby umożliwić implementacje, które nie wymagają funkcji oszczędzania obszaru chipa. ARMv8 „Poziomy wyjątków” mówi:

Implementacja może nie obejmować wszystkich poziomów wyjątków. Wszystkie implementacje muszą zawierać EL0 i EL1. EL2 i EL3 są opcjonalne.

Na przykład QEMU domyślnie ustawia się na EL1, ale EL2 i EL3 można włączyć za pomocą opcji wiersza poleceń: qemu-system-aarch64 wpisuje el1 podczas emulacji zasilania a53

Fragmenty kodu przetestowane na Ubuntu 18.10.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
1
Ponieważ to pytanie nie jest specyficzne dla żadnego systemu operacyjnego ini outjest dostępne dla dzwonka 3. TSS może wskazywać na tabelę uprawnień we / wy w bieżącym zadaniu, przyznając dostęp do odczytu / zapisu do wszystkich lub określonych portów.
Michael Petch,
Oczywiście ustawiasz bity IOPL na wartość 3, wtedy program ring 3 ma pełny dostęp do portu, a uprawnienia TSS IO nie mają zastosowania.
Michael Petch,
@MichaelPetch dzięki, nie wiedziałem tego. Zaktualizowałem odpowiedź.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
5

Zamierzam zaryzykować w ciemności i chyba mówisz o systemie Windows. W skrócie, tryb jądra ma pełny dostęp do sprzętu, ale tryb użytkownika nie. Na przykład wiele, jeśli nie większość sterowników urządzeń jest napisanych w trybie jądra, ponieważ muszą kontrolować dokładniejsze szczegóły swojego sprzętu.

Zobacz także ten wikibook .

Mark Rushakoff
źródło
2
Jest to ważne dla Ciebie jako programisty, ponieważ błędy jądra sieją znacznie większe spustoszenie, niż możesz być przyzwyczajony. Jednym z powodów odróżnienia jądra od użytkownika jest to, że jądro może monitorować / kontrolować krytyczne zasoby systemowe i chronić każdego użytkownika przed innymi. Jest to nieco uproszczone, ale nadal pomocne, aby przypomnieć sobie, że błędy użytkowników są często irytujące, ale błędy jądra mają tendencję do wyłączania całej maszyny.
Adam Liss
3

Inne odpowiedzi już wyjaśniły różnicę między trybem użytkownika a trybem jądra. Jeśli naprawdę chcesz zagłębić się w szczegóły, powinieneś otrzymać kopię Windows Internals , doskonałej książki napisanej przez Marka Russinovicha i Davida Solomona, opisującej architekturę i szczegóły wewnętrzne różnych systemów operacyjnych Windows.

Dirk Vollmar
źródło
2

Co

Zasadniczo różnica między trybem jądra a trybem użytkownika nie jest zależna od systemu operacyjnego i można ją osiągnąć jedynie poprzez ograniczenie niektórych instrukcji do uruchamiania tylko w trybie jądra za pomocą projektu sprzętowego. Wszystkie inne cele, takie jak ochrona pamięci, można osiągnąć tylko przez to ograniczenie.

W jaki sposób

Oznacza to, że procesor działa albo w trybie jądra, albo w trybie użytkownika. Korzystając z pewnych mechanizmów, architektura może zagwarantować, że za każdym razem, gdy zostanie przełączona w tryb jądra, kod systemu operacyjnego zostanie pobrany do uruchomienia.

Czemu

Mając taką infrastrukturę sprzętową, można to osiągnąć w typowych systemach operacyjnych:

  • Ochrona programów użytkownika przed dostępem do całej pamięci, aby na przykład nie pozwolić programom nadpisać systemu operacyjnego,
  • zapobieganie wykonywaniu przez programy użytkownika wrażliwych instrukcji, takich jak te, które zmieniają granice wskaźnika pamięci procesora, aby na przykład nie pozwolić programom łamać granic pamięci.
Ali Asgari
źródło