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?
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?
Odpowiedzi:
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.
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
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 jądra:
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
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.
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:
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, Privl
któ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 = 0
oznacza, ż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 in
i 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 0x80
lub,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
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 exec
uż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:
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 svc
instrukcją (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
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 hvc
instrukcją (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 smc
instrukcją (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:
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:
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ą MRS
instrukcji: 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.
in
i out
jest 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.
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 .
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.
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: