Czytam „Linux Kernel Development” Roberta Love'a i natknąłem się na następujący fragment:
Brak (łatwego) użycia zmiennoprzecinkowego punktu
Kiedy proces przestrzeni użytkownika używa instrukcji zmiennoprzecinkowych, jądro zarządza przejściem z trybu liczb całkowitych do trybu zmiennoprzecinkowego. To, co jądro musi zrobić podczas używania instrukcji zmiennoprzecinkowych, różni się w zależności od architektury, ale jądro zwykle łapie pułapkę, a następnie inicjuje przejście z trybu liczb całkowitych do trybu zmiennoprzecinkowego.
W przeciwieństwie do przestrzeni użytkownika, jądro nie ma luksusu płynnej obsługi zmiennoprzecinkowej, ponieważ nie może łatwo przechwytywać siebie. Używanie zmiennoprzecinkowych wewnątrz jądra wymaga, między innymi, ręcznego zapisywania i przywracania rejestrów zmiennoprzecinkowych. Krótka odpowiedź brzmi: nie rób tego! Z wyjątkiem rzadkich przypadków, w jądrze nie ma operacji zmiennoprzecinkowych.
Nigdy nie słyszałem o tych trybach „całkowitych” i „zmiennoprzecinkowych”. Czym dokładnie są i dlaczego są potrzebne? Czy to rozróżnienie istnieje w głównych architekturach sprzętowych (takich jak x86), czy też jest specyficzne dla bardziej egzotycznych środowisk? Co dokładnie oznacza przejście z trybu liczb całkowitych do trybu zmiennoprzecinkowego, zarówno z punktu widzenia procesu, jak i jądra?
kernel_fpu_begin()
/kernel_fpu_end()
przed / po kodzie, aby upewnić się, że stan FPU przestrzeni użytkownika nie jest uszkodzony. To właśniemd
robi kod Linuksa dla RAID5 / RAID6.Odpowiedzi:
Dlatego...
... jądro systemu operacyjnego może po prostu wyłączyć FPU. Presto, brak stanu do zapisania i przywrócenia, a zatem szybsze przełączanie kontekstów. (To oznaczał tryb, oznaczał tylko, że FPU jest włączony.)
Jeśli program spróbuje wykonać operację FPU, program wpadnie do jądra, jądro włączy FPU, przywróci każdy zapisany stan, który może już istnieć, a następnie powróci do ponownego wykonania operacji FPU.
W czasie przełączania kontekstu wie, że faktycznie przechodzi przez logikę zapisywania stanu. (A następnie może ponownie wyłączyć FPU.)
Nawiasem mówiąc, uważam, że wyjaśnienie w książce, dla którego jądra (i nie tylko Linux) unikają operacji FPU, jest ... nie do końca dokładne. 1
Jądro może uwięzić się w sobie i robi to w wielu sytuacjach. (Zegary, błędy stron, przerwania urządzeń, inne). Prawdziwym powodem jest to, że jądro nie potrzebuje szczególnie operacji FPU, a także musi w ogóle działać na architekturach bez FPU. Dlatego po prostu unika złożoności i czasu wykonywania wymaganego do zarządzania własnym kontekstem FPU, nie wykonując operacji, dla których zawsze istnieją inne rozwiązania programowe.
Warto zauważyć, jak często stan FPU musiałby być zapisywany, gdyby jądro chciał użyć FP . . . każde wywołanie systemowe, każde przerwanie, każde przełączenie między wątkami jądra. Nawet gdyby okazjonalnie istniała potrzeba jądra FP, 2 , prawdopodobnie byłoby szybciej zrobić to w oprogramowaniu.
1. To znaczy bardzo źle.
2. Jest kilka przypadków, które znam, w których oprogramowanie jądra zawiera implementację arytmetyki zmiennoprzecinkowej . Niektóre architektury implementują tradycyjne operacje FPU w sprzęcie, ale pozostawiają skomplikowane operacje IEEE FP oprogramowaniu. (Pomyśl: arytmetyka denormalna.) Kiedy zdarza się jakiś dziwny przypadek narożny IEEE, pułapka na oprogramowanie, które zawiera pedantycznie poprawną emulację operacji, które mogą pułapki.
źródło
W niektórych projektach jądra rejestry zmiennoprzecinkowe nie są zapisywane, gdy zadanie „jądra” lub „systemu” jest przełączane. (Dzieje się tak, ponieważ rejestry FP są duże, a ich zapisanie zajmuje zarówno czas, jak i miejsce). Jeśli więc spróbujesz użyć FP, wartości będą losowo zmieniane na „poof”.
Ponadto, niektóre sprzętowe schematy zmiennoprzecinkowe polegają na jądrze do obsługi "dziwnych" sytuacji (np. Dzielenia przez zero) poprzez pułapkę, a wymagany mechanizm pułapki może być na wyższym "poziomie" niż zadanie jądra aktualnie uruchomione.
Z tych powodów (i kilku innych) niektóre sprzętowe schematy FP będą pułapki, gdy użyjesz instrukcji FP po raz pierwszy w zadaniu. Jeśli masz pozwolenie na użycie FP, to w zadaniu zostanie włączona flaga zmiennoprzecinkowa, jeśli nie, zostaniesz ostrzelany przez pluton egzekucyjny.
źródło
kernel_fpu_begin()
/kernel_fpu_end()
przed / po kodzie, aby wyzwolić zapisywanie / przywracanie stanu FPU przestrzeni użytkownika (i domyślam się, że stan FPU jądra jest przeciwny wywłaszczaniu).