7

Zabawy z Raspbianem, czyli jak to zrobić bez malinki

Ponieważ tytuł cyklu to Malinowe Przepisy, zaczniemy oczywiście od komputerka Raspberry Pi. Zaczniemy jednak nie od sprzętu a od oprogramowania. Spróbujemy poddać emulacji nasz komputerek, wystartować oprogramowanie systemowe (w tym przykładzie Raspbian) tak aby móc zaznajomić się z nim nawet bez zakupionej malinki. Autorem wpisu jest Rafał Świętonowski. Później ta umiejętność może być przydatna, np. przy przygotowaniu naszego […]

Ponieważ tytuł cyklu to Malinowe Przepisy, zaczniemy oczywiście od komputerka Raspberry Pi. Zaczniemy jednak nie od sprzętu a od oprogramowania. Spróbujemy poddać emulacji nasz komputerek, wystartować oprogramowanie systemowe (w tym przykładzie Raspbian) tak aby móc zaznajomić się z nim nawet bez zakupionej malinki.

Autorem wpisu jest Rafał Świętonowski.

Później ta umiejętność może być przydatna, np. przy przygotowaniu naszego obrazu systemu lub testowaniu wybranych rozwiązań bez konieczności każdorazowego nadpisywania karty SD, z której startujemy RPI. Jak wiadomo karty SD nie żyją wiecznie :)

Pragnę nadmienić, że wszelkie opisy dotyczą systemu GNU/Linux. Do zabawy wykorzystałem maszynę wirtualną z zainstalowanym systemem Ubuntu w wersji 14.04 32 bit, uruchomionym w Virtualboxie oraz emulator qemu. Oczywiście, co będzie miało znaczenie dla wydajności, możemy pominąć wirtualizację i uruchamiać emulator qemu bezpośrednio na naszym systemie ponieważ ten sposób nie powoduje wielkiego bałaganu i zamieszania.

Uwaga: Miłośników systemu Windows proszę o zaglądnięcie na koniec artykułu.

Jednym ze sposobów aby uruchomić emulację „malinki” jest użycie emulatora qemu. Posiada on tę właściwość, że potrafi emulować różne architektury sprzętowe co w naszym wypadku jest istotne ponieważ chcemy uruchomić oprogramowanie przeznaczone dla architektury ARM na procesorze z rodziny x86. Będąc dokładnym należy napisać, że uruchomimy wirtualny komputer o architekturze ARM na komputerze z rodziny x86.

Czego więc potrzebujemy:

  1. Systemu operacyjnego, na którym zainstalujemy emulator qemu (w moim przypadku jest to maszyna wirtualna Ubuntu 14.04). Ważne! Emulator qemu musi być w wersji obsługującej procesor ARM1176. W przypadku używania Ubuntu (przynajmniej od wersji 12.04), odpowiednia wersja emulatora jest dostępna w repozytoriach oprogramowania.
  2. Specjalnie przygotowany kernel dla naszej emulacji – kernel dla RPI nie obsługuje emulowanej przez qemu architektury. Gotowy kernel jest pod tym adresem. Oczywiście możemy pokusić się o samodzielne skompilowanie takiego kernela (wskazówki na ten temat są także dostępne pod powyższym adresem) ale na potrzeby tego artykułu skorzystamy z już przygotowanego z uwagi na to, że ten sposób emulacji ma być prosty :) 
  3. Obraz dysku z systemem Raspbian, pod tym adresem.

Zaczynamy od przygotowania środowiska ze wszystkimi elementami (zakładam, że mamy już zainstalowany systemem operacyjny):

  1. Zakładamy katalog na wszystkie składniki przepisu :)
    rafal@ubuntu-rpi-vm:~$ mkdir target
    rafal@ubuntu-rpi-vm:~$ cd target
    rafal@ubuntu-rpi-vm:~/target$
  2. Pobieramy gotowy kernel dla qemu
    rafal@ubuntu-rpi-vm:~/target$ wget http://xecdesign.com/downloads/linux-qemu/kernel-qemu
  3. Pobieramy najnowszą wersję Rasbiana 
    rafal@ubuntu-rpi-vm:~/target$ wget http://downloads.raspberrypi.org/raspbian_latest 
    (w momencie wykonywania tej czynności najnowszą wersją był raspbian – 2014-09-12/2014-09-09-wheezy-raspbian.zip). Oczywiście ściągnięty plik musimy rozpakować za pomocą komendy unzip.

Kolejną czynnością jest zainstalowanie emulatora qemu wraz z niezbędnymi elementami dodatkowymi (w większości przypadków instalowanymi automatycznie jako zależności pakietowe do qemu).

  1. rafal@ubuntu-rpi-vm:~/target$ sudo apt-get install qemu qemu-kvm qemu-user qemu utils kvm-ipxe

    Dla porządku podaję poniżej listę pakietów, która została zainstalowana u mnie:

    • ipxe-qemu 1.0.0
    • qemu 2.0.0
    • qemu-keymaps 2.0.0
    • qemu-kvm 2.0.0
    • qemu-system 2.0.0
    • qemu-system-arm 2.0.0
    • qemu-system-common 2.0.0
    • qemu-system-mips 2.0.0
    • qemu-system-misc 2.0.0
    • qemu-system-ppc 2.0.0
    • qemu-system-sparc 2.0.0
    • qemu-system-x86 2.0.0
    • qemu-user 2.0.0
    • qemu-user-static 2.0.0
    • qemu-utils 2.0.0
    • kvm-ipxe 1.0.0
    • qemu-kvm 2.0.0

Część tych programów nie będzie nam potrzebna w tym ćwiczeniu, zostały one jednak zainstalowane jako zależności pakietowe. Ponieważ od przybytku głowa nie boli to np. qemu-user-static przyda nam się przy następnej okazji.

  1. rafal@ubuntu-rpi-vm:~/target$ qemu-arm -cpu ?
    Sprawdzamy czy nasz emulator obsługuje procesor ARM1176JZFS. Wynik powyższego polecenia powinien zawierać wartość arm1176.
  2. Aby wszystko działało prawidłowo, musimy poddać edycji pewien plik, który zawarty jest w obrazie systemu Raspbian. Można tego dokonać podczas pierwszego uruchomienia systemu Raspbian w emulatorze qemu, z podanym parametrem init=/bin/bash

Uruchomienie wstępne maszyny qemu:

rafal@ubuntu-rpi-vm:~/target$ qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append „root=/dev/sda2 panic=1 rootfstype=ext4 rw init=/bin/bash” -hda rasbian.img

Opis parametrów:

  • qemu-system-arm (komenda do emulowania architektury arm)
  • -kernel (kernel, którego używamy dla emulowanego systemu operacyjnego)
  • -cpu arm1176 (procesor, który chcemy emulować)
  • -m 256 (wartość pamięci RAM dla emulowanej maszyny)
  • -M versatilepb (urządzenie, które będziemy emulowali dla procesora arm)
  • -no-reboot -serial stdio -append „root=/dev/sda2 panic=1 rootfstype=ext4 rw (parametry definiujące zamontowany główny system plików do urządzenia /dev/sda2 w emulowanej maszynie qemu)
  • init=/bin/bash (parametr dla pierwszego uruchomienia emulowanej maszyny, umożliwiający edycję plików, przed pełnym uruchomieniem systemu operacyjnego)
  • -hda rasbian.img (plik zawierający obraz systemu Raspbian)

Poniżej jak to wszystko powinno wyglądać:

proxy

W oknie qemu wykonujemy następujące polecenia:
root@(none):/# nano /etc/ld.so.preload (edycja pliku ld.so.preload)

Na początku linii /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so wstawiamy znak #. Wciskamy ctrl-x, następnie y i enter – nastąpi zapisanie zmian i wyjść z edycji pliku.

Dodatkowo możemy utworzyć wpisy dla utworzenia odpowiednich linków dla dysków. Podczas uruchamiania qemu, kernel widzi dysk emulowanej maszyny jako /dev/sda, rzeczywiste RPI widzi dysk (kartę SD) jako urządzenie /dev/mmcblk0. Poniższe wpisy pozwolą np. w prosty sposób zmienić później wielkość głównego systemu plików (o tym w dalszej części artykułu). Tworzymy plik z regułami:

root@(none):/# nano /etc/udev/rules.d/90-qemu.rules

i wpisujemy poniższe wartości:

KERNEL==”sda”, SYMLINK+=”mmcblk0″
KERNEL==”sda?”, SYMLINK+=”mmcblk0p%n”
KERNEL==”sda2″, SYMLINK+=”root”

Zapisujemy plik i zamykamy maszynę qemu.

Teraz możemy już wykonać właściwe uruchomienie naszego wirtualnego RPI :)

rafal@ubuntu-rpi-vm:~/target$ qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append „root=/dev/sda2 panic=1 rootfstype=ext4 rw ” -hda rasbian.img

Jak widać jedyna różnica polega na braku opcji init=/bin/bash.
 
Po odczekaniu dłuższej chwili (emulacja nie jest zbyt szybka) powinniśmy zobaczyć następujący stan naszej maszyny:

proxy2

Po lewej stronie widać terminal, z którego uruchamiałem maszynę qemu z oczekującą konsolą (uruchomiona podczas startu maszyny qemu za pomocą opcji -serial stdio), po prawej stronie okno maszyny qemu z uruchomionym Raspbianem oraz oknem początkowej konfiguracji polecenia raspi-config.

To co możemy wykonać na początku, to ustawić wartości dla menu nr 4 czyli parametry dotyczące lokalizacji (ustawienie parametrów właściwych dla naszego kraju). Po wybraniu tego menu będziemy mogli ustawić:

proxy3

Locale – przewijamy listę możliwych wartości dla różnych języków, wybieramy pl_PL.UTF-8 UTF-8 i wciskamy OK. Następnie zostaniemy zapytani o default’owe ustawienie, wybieramy wartość pl_PL.UTF-8 UTF-8 (musi być podświetlona) i wciskamy OK. Proces generowania koniecznych wartości trwa chwilę.

Kiedy się zakończy zostaniemy „przeniesieni” do głównego menu. Następnie możemy jeszcze przez dokonywanie wyboru menu nr 4 ustawić strefę czasową i kolejno układ klawiatury (odpowiednie dla Polski). Ponieważ sprawa jest prosta nie będę już tego opisywał. Pozostałe menu możemy sobie darować w tym momencie. Ciekawskim polecam oczywiście przeglądnięcie pozostałych możliwości programu raspi-config (jeszcze jednej z opcji raspi-config użyjemy w tym artykule).

Po zamknięciu programu raspi-config powinniśmy mieć widok podobny do poniższego:

proxy4

Jak widać jesteśmy zalogowani na użytkownika pi. Możemy teraz przyjrzeć się naszemu systemowi (kilku parametrom – pokażę je na obrazkach):

Schowek

Zwróćmy uwagę na informację dotyczące procesora. Jak widać wartość BogoMIPS jest na dużo niższym poziomie niż w prawdziwym RPI. Wynika to z ograniczeń emulacji. W moim przypadku uruchamiam emulację w środowisku wirtualnym co dodatkowo obniża wydajność.  U każdego może się ta wartość zmieniać w zależności od tego w jak szybkim środowisku uruchamia maszynę qemu.

Poniżej informację o dostępnej pamięci…

Schowek2

…oraz zamontowanych zasobach…

proxy7

…możemy także zauważyć, że nasza maszyna dostała automatycznie adres ip. Na nasze potrzeby (a właściwie na potrzeby tego artykułu) taka konfiguracja sieciowa jest wystarczająca.

proxy8

Poniżej zamieściłem jeszcze podsumowanie wartości dla poszczególnych systemów plików. Nas interesuje wartość dla systemu plików rootfs (urządzenie /dev/sda2). Jest do niecałe 3 GB z czego wolnej przestrzeni mamy jedynie 467 MB.  Jest to wartość ustalona przez plik z obrazem naszego Raspbiana. Gdybyśmy nasz obraz systemu Raspbian przenieśli na kartę SD i uruchomili RPI, uzyskalibyśmy podobną wartość dla partycji rootfs. Przy założeniu, że używalibyśmy  kart SD o maksymalnej pojemności np. 8 GB to oczywistym jest, że trochę powierzchni byłoby zmarnowane. Do poprawienia takiego stanu rzeczy służy jedna z opcji programu raspi-config.

Schowek3

Przed dalszymi czynnościami spróbujmy zmienić ten stan rzeczy i powiększmy nasz system plików. Oczywiście w naszym wypadku kartą SD jest plik z obrazem i ma on właśnie wielkość trochę ponad 3 GB. Aby zyskać trochę więcej miejsca oraz zasymulować rozszerzenie systemu plików, powiększymy najpierw nasz plik z obrazem systemu (naszą „kartę SD”) o 2 GB.

W tym celu wykonujemy polecenie:
pi@raspberrypi~$ sudo shutdown -h now

Kiedy pojawi się komunikat System halted, możemy zamknąć okno qemu. Przed kolejnym uruchomieniem maszyny qemu powiększamy nasz obraz .img.

rafal@ubuntu-rpi-vm:~/target$ qemu-img resize raspbian.img +2G

Zobaczmy jak teraz wygląda plik .img. Poniżej jego nowy rozmiar:

proxy10

Jak widać mamy teraz „kartę SD” o wielkości 5 GB. Następnym krokiem jest rozszerzenie systemu plików dla rootfs. Dlaczego? Zaraz sami sprawdzicie.

Startujemy ponownie naszą maszynę qemu, polecenie jak poprzednio i czekamy… Teraz powita nas ekran logowania – zarówno w oknie terminala, z którego uruchamialiśmy maszynę qemu (opcja -serial stdio jak poprzednio) jak i w oknie qemu.

Proponuję tym razem dla odmiany użyć okno połączenia -serial.

Default’owe parametry logowania:
login: pi
password: raspberry

Zobaczmy teraz czy coś się zmieniło z naszym systemem plików rootfs:

Schowek4

Widać powyżej, że system plików rootfs ma tę samą wartość jak poprzednio. Zmieniliśmy tylko wielkość naszej „karty SD”. Aby rozszerzyć system plików dla rootfs do maksymalnego rozmiaru naszej „karty SD” piszemy:

pi@raspberrypi:~$ sudo ln -snf mmcblk0p2 /dev/root 
(pamiętacie jeszcze wcześniejsze zapisy SYMLINK? Teraz możemy to wykorzystać i zlinkować urządzenie /dev/root na mmcblk0p2)
 
uruchamiamy raspi-config
pi@raspberrypi: ~$ sudo raspi-config

i wybieramy menu nr 1. Po chwili (i kilku komunikatach na terminalu) powinniśmy otrzymać poniższy obrazek:

Schowek54

Potwierdzamy Enterem i kończymy pracę z programem raspi-config.

Zostaniemy zapytani o to czy chcemy zrestartować system. Oczywiście żeby zmiany odniosły skutek musimy to zrobić wcześniej czy później. System qemu nie wystartuje nam w tym przypadku automatycznie a jedynie zamknie nasze emulowane RPI. Musimy więc wykonać ponownie komendę uruchomienia qemu z tymi samymi parametrami co poprzednio i … tak, znowu czekamy…:)

Logujemy się i patrzymy jak teraz wygląda nasza przestrzeń dyskowa:

saaa

Jak widać udało się, rootfs jest większy a my zyskaliśmy trochę miejsca na dalsze zabawy.
Na zakończenie tej części zróbmy jeszcze kilka rzeczy aby nasz system był aktualny i uruchamiał środowisko graficzne w trochę większym okienku.

Zacznijmy od aktualizacji informacji o dostępnych pakietach w repozytoriach (oczywiście nasz główny host, z którego uruchamiamy maszynę qemu musi mieć połączenie z internetem):

pi@raspberrypi:~$ sudo apt-get update
pi@raspberrypi:~$ sudo apt-get dist-upgrade 
(zatwierdzamy aktualizacje – jeżeli są) i …  wszyscy chórem: „znowu czekamy” :)

Zajmijmy się jeszcze kernelem i firmware – one też podlegają aktualizacji. Do tego celu służy program rpi-update:

pi@raspberrypi:~$ sudo rpi-update

Oczywiście w naszym przypadku ostatnia komenda niewiele zmieni ponieważ w procesie uruchamiania naszej maszyny qemu używamy cały czas tego samego kernela, specjalnie przygotowanego do tego celu. Gdybyśmy jednak chcieli zapisać teraz nasz obraz systemu Raspbian na karcie SD, będziemy mieli już uaktualniony kernel oraz firmware.

Zróbmy jeszcze jedną rzecz. Zwiększmy okienko qemu dla sesji graficznej Xorg.

W tym celu utworzymy plik xorg.conf:

pi@raspberrypi:~$ sudo nano /etc/X11/xorg.conf

i wpisujemy:

Section „Screen”
Identifier „Default Screen”
SubSection „Display”
Depth 16
Modes „800×600” „640×480”
EndSubSection
EndSection

Zapisujemy plik i w oknie emulatora qemu (oczywiście musimy być zalogowani – uwaga dla tych, którzy wykonywali wszelkie prace w oknie terminala z połączeniem -serial) wpisujemy:

pi@raspberrypi:~$  startx

proxy345

Po dłuższej chwili powinniśmy mieć uruchomione środowisko graficzne w rozdzielczości 800×600. 

Przy pomocy programu raspi-config możemy ustawić także aby środowisko graficzne startowało automatycznie podczas startu maszyny qemu.

Aby postawić „kropkę nad i” można dopisać na końcu polecenia qemu-system-arm jeszcze jedną opcję: -redir tcp:2222::22. To pozwoli na połączenie się z serwerem ssh emulowanej malinki. Działa to w ten sposób, że qemu pozwoli na połączenie ssh na porcie 2222, następnie przekieruje połączenie na port 22 emulowanego systemu.

W systemie, na którym uruchamiamy maszynę qemu wykonujemy polecenie:

rafal@ubuntu-rpi-vm:~/target$ ssh pi@localhost -p 2222

Emulacja RPI za pomocą qemu posiada wiele ograniczeń, głównie dotyczących wydajności, przydzielania wielkości pamięci czy rozdzielczości środowiska graficznego. Pozwala jednak na zaznajomienie się z systemem dla RPI (nie tylko z Raspbianem), wykonaniem uaktualnień dla docelowego środowiska, doinstalowania aplikacji czy przetestowanie usług sieciowych.

Oczywiście parametrów przekazywanych do qemu może być znacznie więcej, związanych z bardziej zaawansowanymi konfiguracjami sieciowymi czy z urządzeniami takimi jak karty dźwiękowe oraz urządzenia usb. Istnieje także wersja qemu dla emulacji RPI rozwijana pod tym adresem, która poprawia kilka powyższych niedoskonałości. To jednak temat do rozwinięcia na inną okazję.

Osoby, które nie używają jako głównego systemu operacyjnego rozwiązań z pingwinem w tle, też mogą pobawić się w emulację RPI pod swoim ulubionym systemem operacyjnym. Pierwsza możliwość to oczywiście wirtualizacja, np. taka jak opisana w tym artykule – zapraszam więc na początek :)

Druga możliwość to ściągnięcie środowiska piqemu w wersji dla Windows, które można znaleźć pod adresem.

W paczce znajdziemy wszystko co potrzebne aby uruchomić emulowane RPI. Zasada uruchamiania jest bardzo podobna jak w przytoczonym powyżej przykładzie.

Istnieje jeszcze inny sposób aby uruchamiać elementy środowiska RPI na komputerze x86. Przy wykorzystaniu mechanizmu chroot możemy wykonywać podobne rzeczy a nawet więcej bez ograniczeń związanych z wydajnością. To właśnie będzie głównym tematem następnego artykułu.