Zadaniem LinuxBIOSa jest zastąpienie BIOSu dostarczonego przez producenta na płycie głównej. Normalny BIOS oraz program służący do konfiguracji urządzeń na płycie głównej jest zastępowany przez prostą sekwencję inicjującą oraz moduł rozpakowujący jądro Linuxa. Następnie jest uruchamiane jądro Linuxa i od tej pory proces bootowania przebiega już w normalny sposób. Dzięki wprowadzeniu takich zmian możliwe jest przejście do etapu montowania głównego systemu plików w czasie poniżej sekundy od momentu włączenia komputera.
LinuxBIOS w większości składa się z Linuxa, poprawionego, aby jądro było w stanie pracować na niezainicjalizowanym sprzęcie. Po wprowadzeniu dodatkowych poprawek do jądra używanego przez LinuxBIOS możliwe jest zbootowanie innego jądra (np. za pomocą mechanizmu LOBOS, omawianego poniżej), a także możliwe jest wykorzystanie protokołów sieciowych wspieranych przez Linuxa, aby pobrać właściwe jądro do zbootowania.
LinuxBIOS powstał głównie z myślą o dużych klastrach. Jego twórcy zauważyli mnóstwo ograniczeń związanych z BIOSami instalowanych przez producentów płyt głównych i postanowili usprawnić proces bootowania. Wady obecnie stosowanych programów bootujących to:
LinuxBIOS znalazł zastosowanie w wielu klastrach, oto ich lista (w kolejności powstawania):
Głównym założeniem twórców LinuxBIOSa jest to, aby ograniczyć do minimum kod inicjalizujący i pozwolić wszystko zrobić Linuxowi. Wszystkie procesory rodziny x86 uruchamiają się w trybie emulacji 8086 operując na 16-bitowych adresach i instrukcjach. Jest to problematyczne, ponieważ inicjalizacja niektórych urządzeń wymaga 32-bitowgo adresowania, np. ustawienie pamięci SDRAM wymaga zapisu do komórek, których adresacja wykracza daleko poza 16 bitów, co bardzo komplikuje sekwencje inicjalizacyjną. Dlatego twórcy LinuxBIOSa zdecydowali się od razu przejść do trybu 32-bitowego. Przejście jest dość proste: procesor musi załadować tablicę deskryptorów segmentów (Global Descriptor Table) i włączyć ochronę pamięci. Aby załadować GDT trzeba wywołać instrukcję LGDT podając wskaźnik do tablicy wewnątrz adresowalnej pamięci. To nie jest problem, ponieważ taką tablicę można umieścić w NVRAMie. Po przejściu do trybu 32-bitowego należy dokonać inicjalizacji układu. Kod w asemblerze jest potrzebny jedynie do uruchomienia DRAM, później można już wykorzystywać C, co pozwala na łatwą przenaszalność kodu.
Istnieje problem związany z tym, że LinuxBIOS działa na niezainicjowanym sprzęcie (nie można robić żadnych założeń związanych ze sprzętem), natomiast Linux zakłada, że sprzęt jest zainicjalizowany. Dlatego należy wprowadzić niewielkie zmiany do jądra. Na przykład Linux zakłada, że jeżeli kontroler dyskowy nie jest włączony, to dlatego że BIOS wyłączył go, natomiast na niezainicjalizowanym sprzęcie kontroler IDE nie jest włączony, bo nie ma BIOSu, który mógłby go włączyć. Dlatego to, że kontroler nie jest włączony ma zupełnie inne znaczenie i należy wprowadzić zmiany.
Pod LinuxBIOSem nie ma programu służącego do konfigurowania urządzeń na płycie głównej, jak to ma miejsce w przypadku zwykłego BIOSu. Ponieważ LinuxBIOS rozwijany jest z zgodnie z zasadą "pozwólmy to zrobić Linuxowi", dokonywana jest jedynie minimalna inicjalizacja sprzętu. Oznacza to, że jeżeli chcemy na przykład wyłączyć kartę sieciową zintegrowaną z płytą główną, wymaga to od nas poznania adresu pamięci (a dokładnie bitu), gdzie ustawia się tą opcję i ręcznego dodania instrukcji, która dokona odpowiedniej zmiany zawartości tej komórki pamięci.
Ten krok wymaga 17 instrukcji w asemblerze, aby ustawić znany stan dla segmentacji, stronicowania i sprzętu TLB a następnie przejść do trybu 32-bitowego.
0xffff0
jest skok do początku procedur startowych BIOSu. Jest to standardowa procedura resetująca na platformie x86.Ponieważ początkowo nie ma żadnego działającego sprzętu zarządzającego pamięcią, inicjalizacja odbywa się przy pomocy kodu asemblera. Jest to najbardziej złożona część procesu startowego i wymaga nawet kilkuset instrukcji, aby ją obsłużyć. Po włączeniu DRAM i ustawieniu stosu możliwe jest już korzystanie z kodu w języku C.
Przeprowadzenie dodatkowych ustawień jest realizowanie za pomocą kilkuset instrukcji w C.
0x100000
dla PC). Następnie wywoływana jest funkcja startup_32
, co powoduje pominięcie startowych procedur bootowalnych jądra, ponieważ tam dochodzi do rozpakowania dalszej części jądra, a to jest już zrobione przez LinuxBIOSa.
Po wystartowaniu jądra Linuxa możliwe jest korzystanie ze wszystkich dobrodziejstw dostarczanych przez nie. Twórcy LinuxBIOSa opisują kilka możliwości: bootowanie przez sieć, standardowe, bezdyskowe a także czynności związane ze zdalnym zarządzaniem.
Bootowanie przez sieć przy użyciu Linuxa daje o wiele więcej możliwości niż w przypadku standardowych protokołów takich jak bootp czy PXE, ponieważ można użyć biblioteki SSH i nawiązywać połączenia do serwera DHCP przy jej pomocy. Dzięki temu połączenia są realizowane po protokole TCP, który nie jest tak zawodny, jak UDP (używany przez bootp i PXE). Serwer DHCP może wskazać węzłowi w klastrze, które jądro zbootować a nawet przesłać je.
Możliwe jest także wykorzystanie sieci opartych o pamięć o wysokiej przepustowości (np. SCI Scalable Coherent Interface) w celu przekopiowania jądra a nawet całego obrazu RAMDISK w ciągu kilku sekund.
Termin LOBOS oznacza Linux Os Boots OS. Jest to funkcja systemowa zezwalająca działającemu jądru zbootować nowe jądro bez opuszczania trybu 32-bitowego i bez użycia BIOSu. Dzięki temu można stosować Linuxa jako protokół bootowania sieciowego a nawet jako BIOS (co ma miejsce w przypadku LinuxBIOSa). Realizacja funkcji składa się z kilku kroków:
0x100000
, czyli w miejsce starego.LinuxBIOS w pełni obsługuje Linuxa i to właśnie jemu powierza dalszą inicjalizację sprzętu. Natomiast inne systemy operacyjne takie jak BSD i Windows 2000/XP nie mogą bezpośrednio działać z LinuxBIOSem, ponieważ polegają na kilku usługach dostarczanych przez zwykłe BIOSy. Właśnie z myślą o nich powstała inicjatywa łącząca elementy projektu LinuxBIOS, emulatora Bochs (Bochs jest darmowym, w pełni funkcjonalnym emulatorem komputera PC z procesorem x86, napisanym w C++, a co najważniejsze zawiera darmowy BIOS, działający na emulowanym sprzęcie) oraz dodatkowego oprogramowania w celu stworzenia pierwszego w pełni darmowego BIOSu dla PC.
Z projektu LinuxBIOS została zaczerpnięta część odpowiadająca za start systemu (bez jądra). Następnie została dodana warstwa pośrednia między LinuxBIOSem a Bochs BIOSem nazwana ADLO (ADhesive LOader), przekazująca parametry z LinuxBIOSa do Bochs BIOSa, a także zmieniająca działanie pewnych funkcji w Bochs BIOSie bez konieczności modyfikowania go. Do tego dołączony jest Bochs BIOS czyli BIOS z emulatora Bochs. Zawiera on funkcjonalność potrzebną do uruchomienia systemów takich jak Windows przy pomocy GNU Grub Bootloadera. Połączenie LinuxBIOSa, ADLO i Bochs BIOSa jest szybkie oraz nie zajmuje dużo miejsca.
Windows 2000 |
Grub Bootloader |
Bochs BIOS |
ADLO |
LinuxBIOS |
Wykorzystanie BIOSu z darmowego emulatora Bochs było możliwe dzięki temu, w jaki sposób został napisany. Po pierwsze żadne urządzenie emulowane przez Bochs nie zostało zaimplementowane w warstwie BIOSu. BIOS został napisany tak jakby miał działać na prawdziwym sprzęcie. Po drugie skoro sprzęt w jest emulowany, to nie musi być włączony, a więc nie trzeba go inicjalizować (np. nie inicjalizuje pamięci podręcznej procesora, czy też kontrolera IDE). A tym właśnie zajmuje się LinuxBIOS. Jedyne zmiany wprowadzone do Bochs BIOSa polegały na bardziej prawidłowym zaimplementowaniu niektórych przerwań, co nie złamało jego kompatybilności z emulatorem.
Usługi BIOSu wymagane przez systemy operacyjne do poprawnej pracy są liczne. Większość z nich jest trywialna jak na przykład szukanie klawiatury czy korzystanie z przerwania zegarowego. Główne cztery usługi potrzebne to: funkcje ekranu, dysku twardego, pamięci oraz tabeli PCI. Wykorzystywane są także nowe usługi jednak są one opcjonalne (np. ACPI).
Usługa BIOSu | Standardowe jądro 2.4.x |
Zmienione jądro 2.4.x |
Windows 2000/XP |
FreeBSD |
---|---|---|---|---|
Przerwanie Int13 | tak | nie | tak | tak |
Przerwanie Int15 | tak | nie | tak | tak |
PnPBIOS | nie | nie | nie | nie |
Tablica PCI | tak | tak | tak | tak |
Video BIOS | nie | nie | nie | nie |
ACPI | nie | nie | nie | nie |
APM | nie | nie | nie | nie |
Funkcje BIOSu zajmujące się ekranem można pobrać z pamięci, spod adresu 0xC0000
(do 0xC7FFF
) w pamięci. Tam właśnie znajduje się BIOS producenta karty graficznej. Po przekopiowaniu go umieszczony jest on razem z LinuxBIOSem i Bochs BIOSem w EEPROMie. Dzięki temu mamy pełne wsparcie dla przerwania Int10. W celu realizacji przerwania Int13, czyli dostępu do dysku używana jest implementacja zawarta w Bochs BIOSie, dostosowana do prawdziwego sprzętu, jednak wszelkie zmiany wprowadzone są za pomocą ADLO. Wsparcie dla zwracania informacji o obszarach pamięci oraz tablicach PCI zawarte jest w Bochs BIOSie.
Proces bootowania odbywa się w następujący sposób:
Niestety projekt LinuxBIOS jest bardzo słabo udokumentowany i jedynie dostępne są szczątkowne informacje dotyczące jego stanu i sposobu korzystania z niego. Na szczęście w sieci można znaleźć kilka artykułów opisujących w dokładny sposób, krok po kroku, w jaki sposób zainstalować LinuxBIOSa na własnej płycie głównej. Zachęcony tym faktem stwierdziłem, że też spróbuję tego dokonać.
Pierwszą rzeczą, którą należy sprawdzić, jest to czy płyta, na której chce się zainstalować LinuxBIOS, jest wspierana. Do testów przeznaczyłem dwie płyty Asus P2B oraz Asus P3B-F, obie oparte o chipset Intel 440BX. Okazało się, że żadna nie jest bezpośrednio wspierana, jednak istniał szablon ustawień dla płyt opartych na BXie, a także kilka gotowych konfiguracji pod podobne płyty innych producentów. Uznałem to jako dobry znak i postanowiłem podjąć dalsze działania.
Drugi etap polega na zakupie chipowej pamięci flaszowej o zwiększonej pojemności oraz podstawki ZIF (Zero Insert Force). Potrzeba kości o większej pojemności bierze się stąd, że normalne BIOSy zajmują zazwyczaj 256 KB natomiast LinuxBIOS wraz z kernelem może zajmować nawet prawie półtora megabajta. Dlatego konieczny jest zakup tak zwanego DoC'a (Disc-On-Chip), czyli silikonowego dysku w postaci normalnej kości flaszowej, firmy M-Systems. Pojemności tych kości zaczynają się od 8 MB (czyli 32 razy więcej niż normalna kość mieszcząca BIOS) aż do 1 GB!!! Po drobnych poszukiwaniach okazało się, że jest w Polsce jeden dystrybutor firmy M-Systems. Niestety nie miał tych pamięci w magazynie, ale sprowadził je dla mnie w zaledwie 4 tygodnie... Drugą potrzebną częścią jest podstawka ZIF. Jest to podstawka wtykana w normalne złącze BIOSu na płycie głównej, umożliwiająca łatwe podmienianie wetkniętej w nią kości. Wykorzystuje się ją w fazie programowania pamięci flaszowej (gdzie przy włączonym prądzie podmieniamy kość BIOSu), aby uniknąć zakupu drogiego urządzenia zewnętrznego.
Uzbrojony we wszystkie potrzebne części przystąpiłem do działania. Zainstalowałem na płycie głównej podstawkę ZIF (nie było łatwo, bo nie mieściła się z powodu slotu PCI znajdującego się w pobliżu, ale się udało). Dodałem do aktualnie działającego jądra obsługę dla urządzenia DoC i przystąpiłem do budowania LinuxBIOSa. Po przeprowadzeniu odpowiednich zmian konfiguracyjnych, dostosowałem pakiet do mojej płyty głównej oraz zbudowałem nowe jądro, które miało być umieszczone razem z LinuxBIOSem w pamięci flaszowej, a następnie wywołałem program flaszujący. Tu spotkało mnie pierwsze rozczarowanie. Nie zadziałał, a raczej zadziałał tylko nie do końca. Zapisał do DoCa linuxbiosa oraz kernel, ale nie zapisał jednego pliku na samym początku pamięci flaszowej, bo go nie było. Okazało się, że plik ten istnieje tylko dla nielicznych chipsetów (nie dla BX) i odpowiada za start LinuxBIOSa z Disk-On-Chipa (tego dowiedziałem się po przejrzeniu listy dyskusyjnej poświęconej LinuxBIOSowi). Bez niego nie jest możliwe korzystanie z powiększonej pamięci flaszowej, czyli na przykład można używać LiunuxBIOSa do załadowania programu w formacie elf, jak np. etherboot czy memtest86, który pomieści się w normalnej kości EEPROM. Także na płycie Asus P3B-F okazało się, że nie działa standardowa metoda odblokowywania zabezpieczenia przed zapisem dla gniazda BIOSu.
Po krótkich testach, które okazały się być bardzo kształcące, doszedłem do następujących wniosków na temat LinuxBIOSa: