Przenoszenie systemu Linux na inne wymagania dotyczące platformy [zamknięte]


28

Wiem, że Linux jest dostępny i został przeniesiony na wiele różnych platform, takich jak X86, ARM, PowerPC itp.

Jednak co do portowania jest dokładnie wymagane?

Rozumiem, że Linux jest oprogramowaniem napisanym w C. Dlatego, kiedy na przykład przenosisz Linuksa z X86 na ARM lub inne, czy nie jest to tylko kwestia ponownej kompilacji kodu z kompilatorem dla konkretnej architektury docelowej?

Odkładając na bok sterowniki urządzeń dla różnych urządzeń peryferyjnych, co jeszcze należałoby zrobić, przenosząc Linuksa na nową architekturę. Czy kompilator nie dba o nas za wszystko?


11
Czy możemy założyć, że sprawdziłeś źródła jądra specyficzne dla architektury? git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/…
Kusalananda

Odpowiedzi:


57

Mimo że większość kodu w jądrze Linuksa jest napisana w języku C, wciąż istnieje wiele jego części, które są bardzo specyficzne dla platformy, na której są uruchomione i należy to uwzględnić.

Jednym szczególnym przykładem tego jest pamięć wirtualna, która działa w podobny sposób na większości architektur (hierarchia tabel stron), ale ma określone szczegóły dla każdej architektury (takie jak liczba poziomów w każdej architekturze, i to wzrasta nawet na x86 z wprowadzenie nowych większych układów.) Kod jądra Linux wprowadza makra do obsługi przechodzenia przez te hierarchie, które mogą być pomijane przez kompilator w architekturach, które mają mniej poziomów tabel stron (tak, że kod jest napisany w C, ale uwzględnia szczegóły architektury w wynagrodzenie.)

Wiele innych obszarów jest bardzo specyficznych dla każdej architektury i musi być obsługiwanych za pomocą kodu specyficznego dla architektury. Większość z nich wymaga jednak kodu w języku asemblera. Przykładami są:

  • Przełączanie kontekstu : Przełączanie kontekstu polega na zapisaniu wartości wszystkich rejestrów wyłączanego procesu i przywróceniu rejestrów z zapisanego zestawu procesu zaplanowanego w CPU. Nawet liczba i zestaw rejestrów jest bardzo specyficzna dla każdej architektury. Ten kod jest zwykle implementowany w asemblerze, aby umożliwić pełny dostęp do rejestrów, a także upewnić się, że działa tak szybko, jak to możliwe, ponieważ wydajność przełączania kontekstu może być krytyczna dla systemu.

  • Wywołania systemowe : Mechanizm, za pomocą którego kod przestrzeni użytkownika może wywoływać wywołanie systemowe, jest zazwyczaj specyficzny dla architektury (a czasami nawet dla konkretnego modelu procesora, na przykład Intel i AMD wprowadziły różne instrukcje, starsze procesory mogą nie mieć tych instrukcji, więc szczegóły dla tych nadal będą wyjątkowe).

  • Programy obsługi przerwań : szczegółowe informacje na temat obsługi przerwań (przerwań sprzętowych) są zazwyczaj specyficzne dla platformy i zwykle wymagają kleju na poziomie zespołu do obsługi określonych konwencji wywoływania używanych dla platformy. Prymitywy do włączania / wyłączania przerwań są zazwyczaj specyficzne dla platformy i również wymagają kodu asemblera.

  • Inicjalizacja : szczegółowe informacje na temat tego, jak powinna się odbyć inicjalizacja, zwykle obejmują również szczegóły specyficzne dla platformy i często wymagają kodu instalacyjnego do obsługi punktu wejścia do jądra. Na platformach, które mają wiele procesorów (SMP), szczegółowe informacje na temat przełączania innych procesorów w tryb online są również zależne od platformy.

  • Blokowanie prymitywów : Implementacja bloków prymitywnych (takich jak blokady) zwykle obejmuje również szczegóły specyficzne dla platformy, ponieważ niektóre architektury zapewniają (lub preferują) różne instrukcje procesora, aby skutecznie je wdrożyć. Niektóre zaimplementują operacje atomowe, niektóre zapewnią cmpxchg, który może atomowo testować / aktualizować (ale nie powiedzie się, jeśli inny program zapisujący wszedł pierwszy), inne będą zawierać modyfikator „blokowania” instrukcji procesora. Często wymagają one również napisania kodu asemblera.

Prawdopodobnie istnieją inne obszary wymagające od platformy kod lub specyficzne dla architektury w jądrze (a konkretnie w jądrze Linux.) Patrząc na drzewie źródłowym jądra, istnieje architektura specyficzne poddrzewa poniżej arch/i pod include/arch/którym można znaleźć więcej przykłady tego.

Niektóre są w rzeczywistości zaskakujące, na przykład zobaczysz, że liczba wywołań systemowych dostępnych w każdej architekturze jest osobna, a niektóre wywołania systemowe będą istnieć w niektórych architekturach, a inne nie. (Nawet na x86 lista wywołań systemowych różni się między jądrem 32-bitowym a 64-bitowym.)

Krótko mówiąc, istnieje wiele przypadków, o których jądro musi wiedzieć, które są specyficzne dla platformy. Jądro Linux próbuje wyodrębnić większość z nich, więc algorytmy wyższego poziomu (takie jak zarządzanie pamięcią i planowanie) mogą być zaimplementowane w C i działają tak samo (lub przeważnie tak samo) na wszystkich architekturach.


7
Bardzo fajny opis! Różnice w liczbie wywołań systemowych są głównie związane z historią: nowe porty zawierają ważne wywołania systemowe w momencie portu, nie zawracają sobie głowy historycznym bagażem obecnym w starszych portach, więc przestarzałe wywołania systemowe zwykle nie są obecne w portach nowszy niż wycofanie. (To nie obejmuje wszystkich scenariuszy ...)
Stephen Kitt

10

Oprócz portowania jądra Linux musisz zdefiniować binarny interfejs aplikacji (ABI) dla programów „przestrzeni użytkownika” i przenieść najniższe warstwy stosu oprogramowania przestrzeni użytkownika. Linux jest zwykle używany z niskopoziomowymi komponentami przestrzeni użytkownika z projektu GNU, z których najbardziej krytyczne to:

  • Kompilator, asembler i linker C: GCC i GNU Binutils . Aby uzyskać zupełnie nową architekturę procesora, musisz przenieść to oprogramowanie, zanim jeszcze zaczniesz portować jądro, ponieważ samo jądro jest programem typu C i musi zostać skompilowane. Jeśli procesor Twojej platformy obsługuje już funkcję „zaplecza”, ale nie w przypadku Linuksa jako jądra systemu operacyjnego, masz znacznie mniej pracy do wykonania i możesz nie być w stanie odłożyć jej na później, dopóki jądro nie uruchomi się i bieganie.
  • Biblioteka środowiska wykonawczego C: „ GNU libc ”. Ta biblioteka zawiera kod, który wykonuje wywołania systemowe i w inny sposób współdziała bezpośrednio z jądrem.
  • Biblioteka „interfejsu funkcji obcych”, libffi , która jest niezbędnym składnikiem wielu interpreterów wysokiego poziomu i wykonuje jedno z niewielu pozostałych zadań, które wymaga niewielkiej ilości ręcznie napisanego języka asemblera.

Wiele innych programów ma opcjonalne komponenty zależne od platformy; na przykład przeglądanie sieci Web będzie znacznie szybsze, jeśli napiszesz ręcznie zoptymalizowane operacje kryptograficzne dla NSS i OpenSSL dla nowej architektury procesora oraz back-endy kompilacji just-in-time dla IonMonkey i V8 . Ale nie są one niezbędne do stworzenia nowej platformy.


1

Musisz poinformować jądro o sprzęcie, na który się przenosisz. Zadaniem jądra jest bezpośrednie połączenie ze sprzętem, więc aby działało poprawnie, jądro musi wiedzieć o procesorze, oscylatorach (zegarach) i wszelkich urządzeniach peryferyjnych, takich jak różne rodzaje portów szeregowych (SPI, CAN, I2C itp.).

W dawnych czasach robiłbyś to, pisząc kod specyficzny dla platformy, którego następnie użyliby sterowniki. Obecnie odbywa się to poprzez napisanie definicji drzewa urządzeń .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.