stos jądra i stos przestrzeni użytkownika

110

Jaka jest różnica między stosem jądra a stosem użytkownika? Dlaczego używany jest stos jądra? Jeśli zmienna lokalna jest zadeklarowana w ISR, gdzie będzie przechowywana? Czy każdy proces ma własny stos jądra? Jak więc koordynuje się proces między tymi dwoma stosami?

jkv
źródło

Odpowiedzi:

188
  1. Jaka jest różnica między stosem jądra a stosem użytkownika?

Krótko mówiąc, nic - poza wykorzystaniem innej lokalizacji w pamięci (a co za tym idzie innej wartości dla rejestru stackpointer) i zwykle różnych zabezpieczeń dostępu do pamięci. Oznacza to, że podczas wykonywania w trybie użytkownika pamięć jądra (której częścią jest stos jądra) nie będzie dostępna, nawet jeśli zostanie zmapowana. I odwrotnie, bez wyraźnego żądania przez kod jądra (w Linuksie poprzez funkcje takie jak copy_from_user()), pamięć użytkownika (w tym stos użytkownika) zwykle nie jest bezpośrednio dostępna.

  1. Dlaczego używany jest [oddzielny] stos jądra?

Rozdział uprawnień i bezpieczeństwa. Po pierwsze, programy działające w przestrzeni użytkownika mogą dowolnie zmieniać stos (wskaźnik) i zwykle nie ma wymagań architektonicznych, aby mieć nawet poprawny. W związku z tym jądro nie może ufać, że wskaźnik stosu w przestrzeni użytkownika jest prawidłowy ani użyteczny, a zatem będzie wymagał jednego zestawu pod własną kontrolą. Różne architektury procesorów implementują to na różne sposoby; Procesory x86 automatycznie przełączają punkty stosu, gdy występują przełączenia trybu uprzywilejowania, a wartości, które mają być używane dla różnych poziomów uprawnień, są konfigurowalne - za pomocą kodu uprzywilejowanego (tj. tylko jądra).

  1. Jeśli zmienna lokalna jest zadeklarowana w ISR, gdzie będzie przechowywana?

Na stosie jądra. Jądro (Linux kernel, to jest) ma nie zahaczyć ISR bezpośrednio do X86 Architecture przerwań bram ale zamiast delegaci przerwanie wysyłka do wspólnego jądra przerwania mechanizmu wejścia / wyjścia, która oszczędza sprzed przerwania Państwowego Rejestru przed wywołaniem zarejestrowaną obsługę (s) . Procesor sam podczas wysyłania przerwania może wykonać przywilej i / lub przełącznik stosu, a to jest używane / ustawiane przez jądro tak, że wspólny kod wejściowy przerwania może już polegać na obecnym stosie jądra.
To powiedziawszy, przerwania, które występują podczas wykonywania kodu jądra, po prostu (nadal będą) używały stosu jądra na miejscu w tym momencie. Może to, jeśli procedury obsługi przerwań mają głęboko zagnieżdżone ścieżki wywołań, prowadzić do przepełnienia stosu (jeśli głęboka ścieżka wywołania jądra zostanie przerwana, a program obsługi spowoduje inną głęboką ścieżkę; w Linuksie kod RAID systemu plików / oprogramowania jest przerywany przez kod sieciowy z aktywnym iptables jest wiadomo, że wyzwala takie w niestrojonych starszych jądrach ... rozwiązaniem jest zwiększenie rozmiaru stosu jądra dla takich obciążeń).

  1. Czy każdy proces ma własny stos jądra?

Nie tylko każdy proces - każdy wątek ma swój własny stos jądra (i właściwie również swój własny stos użytkowników). Pamiętaj, że jedyną różnicą między procesami i wątkami (do Linuksa) jest fakt, że wiele wątków może współdzielić przestrzeń adresową (tworząc proces).

  1. Jak koordynuje się proces między tymi dwoma stosami?

Wcale nie - nie musi. Planowanie (jak / kiedy są uruchamiane różne wątki, jak ich stan jest zapisywany i przywracany) jest zadaniem systemu operacyjnego i procesy nie muszą się tym przejmować. W miarę tworzenia wątków (a każdy proces musi mieć co najmniej jeden wątek), jądro tworzy dla nich stosy jądra, podczas gdy stosy przestrzeni użytkownika są albo jawnie tworzone / dostarczane przez dowolny mechanizm używany do tworzenia wątku (funkcje takie jak makecontext()lub pthread_create()pozwalają wywołującemu określ region pamięci, który ma być używany dla stosu wątku „potomnego”) lub dziedziczony (przez klonowanie pamięci przy dostępie, zwykle nazywane „kopiuj przy zapisie” / COW, podczas tworzenia nowego procesu).
To mówi,(między innymi stan stosu wątku). Istnieje wiele sposobów na to: sygnały UNIX setcontext(), pthread_yield()/ pthread_cancel()... - ale to jest disgressing nieco od pierwotnego pytania.

FrankH.
źródło
Doskonałe odpowiedzi FrankH. Dzięki.
kumar
1
@FrankH Doskonała odpowiedź… ale mam małe pytania z tym związane, ale w architekturze ARM… Jak ten stos jądra jest powiązany z różnymi trybami procesora?
Rahul,
2
@Rahul: "Margines komentarza SO jest zbyt mały, aby zawierał taką odpowiedź". Jak stosy / rejestry stosu działają w różnych trybach procesora ARM (które z nich implementują zbankowane SP) jest dobrym pytaniem, ale wymaga więcej miejsca na odpowiedź, niż może dać komentarz. To samo dotyczy rzeczy takich jak bramki zadań x86 lub IST - nie ma czegoś takiego jak „pojedynczy” wskaźnik stosu jądra (tak samo jak nie ma „pojedynczego” wskaźnika stosu użytkownika), i jakie wsparcie sprzętowe / mandat jest dla oddzielne wskaźniki stosu w różnych trybach pracy są ... bardzo zależne od sprzętu.
FrankH.
@FrankH. Utworzyłem nowe pytanie dla tego samego ... stackoverflow.com/q/22601165/769260 Mam nadzieję, że teraz możesz mi pomóc bez dbania o przestrzeń :)
Rahul
1
@FrankH. Czy możesz przedstawić diagram pokazujący, gdzie należy stos jądra w układzie pamięci procesu?
Jithin Pavithran
19

Moja odpowiedź jest zbierana z innych pytań SO dotyczących moich rzeczy.

What's the difference between kernel stack and user stack?

Jako programista jądra wiesz, że jądro powinno być ograniczone do błędnych programów użytkownika. Załóżmy, że masz ten sam stos zarówno dla jądra, jak i przestrzeni użytkownika, a następnie prosty błąd w aplikacji użytkownika powoduje awarię jądra i wymaga ponownego uruchomienia.

Istnieje jeden „stos jądra” na procesor, taki jak stos ISR i jeden „stos jądra” na proces. Dla każdego procesu istnieje jeden „stos użytkownika”, chociaż każdy wątek ma swój własny stos, obejmujący zarówno wątki użytkownika, jak i wątki jądra.

http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html

Why kernel stack is used?

Więc kiedy jesteśmy w trybie jądra, mechanizm stosu jest niezbędny do obsługi wywołań funkcji, zmiennych lokalnych podobnych do przestrzeni użytkownika.

http://www.kernel.org/doc/Documentation/x86/kernel-stacks

If a local variable is declared in an ISR, where it will be stored?

Będzie przechowywany w stosie ISR (IRQSTACKSIZE). ISR działa na oddzielnym stosie przerwań tylko wtedy, gdy obsługuje go sprzęt. W przeciwnym razie ramki stosu ISR są wpychane na stos przerywanego wątku.

Przestrzeń użytkownika nie wie i szczerze mówiąc nie dba o to, czy przerwanie jest obsługiwane w stosie jądra bieżącego procesu, czy w oddzielnym stosie ISR. Ponieważ przerwania przypadają na procesor, stos ISR musi być przypisany do procesora.

 Does each process has its own kernel stack ?

Tak. Każdy proces ma własny stos jądra.

 Then how the process coordinates between both these stacks?

@ Odpowiedź FrankH wygląda świetnie.

Jeyaram
źródło
4
  1. Jaka jest różnica między stosem jądra a stosem użytkownika

Biorąc pod uwagę rozwój jądra Linuksa Roberta Love'a, główną różnicą jest rozmiar:

Przestrzeń użytkownika może uciec dzięki statycznemu przydzielaniu wielu zmiennych na stosie, w tym ogromnych struktur i tablic tysiąca elementów.
To zachowanie jest legalne, ponieważ przestrzeń użytkownika ma duży stos, który może dynamicznie rosnąć.
Stos jądra nie jest ani duży, ani dynamiczny; jest mały i ma stały rozmiar.
Dokładny rozmiar stosu jądra zależy od architektury.
Na platformie x86 rozmiar stosu można konfigurować w czasie kompilacji i może wynosić 4 KB lub 8 KB.
Historycznie, stos jądra składa się z dwóch stron, co ogólnie oznacza, że ​​ma 8 KB na architekturach 32-bitowych i 16 KB na architekturach 64-bitowych - ten rozmiar jest stały i bezwzględny.
Każdy proces otrzymuje własny stos.

Również stos jądra zawiera wskaźnik do struktury thread_info przechowującej informacje o wątku.

arenard
źródło