Więcej o firmie ELESOFTROM

Firma ELESOFTROM specjalizuje się w wykonywaniu i naprawianiu oprogramowania dla sterowników mikroprocesorowych.

Posiadamy ponad 10-letnie doświadczenie w tej dziedzinie.

W realizowanych projektach stawiamy na niezawodność i wydajność programów.

Naprawa oprogramowania

Oprogramowanie na zamówienie


Strona główna

Pełna oferta

Doświadczenie

O firmie

Kontakt


DioneOS - RTOS dla urządzeń embedded

Firma ELESOFTROM opracowała system RTOS dla procesorów ARM Cortex-M3 oraz msp430.

System jest zoptymalizowany pod względem wydajności, dzięki czemu uzyskano krótki czas przełączania pomiędzy wątkami.
System dostarcza elementy (np. semafory, mutexy, timery, kolejki itp.) niezbędne do tworzenia wielowątkowego firmware'u.

Wersja dla Cortexa została całkowicie przetestowana przy pomocy środowiska do automatycznego testowania.

Przeczytaj więcej:

Strona o systemie DioneOS

Niezawodność

Wydajność

Dokumentacja DioneOSa

Prezentacje n.t. DioneOS


^ Blog index    << Jak zbudować własny toolchain    >> Dokumentowanie kodu źródłowego

Jak zbudować własny firmware?

2012-05-08    dr inż. Piotr Romaniuk

Spis treści

Wstęp
Buildroot - system do budowania firmware'u
Drzewo katalogów Buildroota
Konfiguracja Buildroota
Jak umieścić obraz na urządzeniu?
Typowe problemy
Materiały na temat Buildroota

Wstęp
W odróżnieniu od komputerów ogólnego przeznaczenia (np. typu PC), urządzenia typu embedded charakteryzują się ściśle wyznaczoną funkcją użytkową (np. router WiFi, sterownik frezarki numerycznej, itp.). Takie systemy zintegrowane zawierają w sobie wbudowane oprogramowanie nazywane firmwarem. Oprogramowanie to nie podlega częstym zmianom i zazwyczaj jest "zaszyte" w urządzeniu, na którym pracuje. Często zdarza się, że użytkownik nie ma możliwości ingerencji w to oprogramowanie i może je używać jedynie w taki sposób, w jaki jest to wymagane do korzystania z urządzenia.
Firmware jest umieszczony w pamięci urządzenia, która przechowuje jego treść po wyłączeniu. Przykładowo w zależności od konkretnego rozwiązania może to być:

Zarówno w procesie produkcyjnym, jak i podczas przesyłania uaktualnień (niektóre urzadzenia pozwalaja na wgrywanie uaktualnień firmware'u), firmware jest dostępny w postaci pojedynczego pliku lub kilku plików. W takim pliku (nazywanym często obrazem [ang. image]) znajdują się wszystkie elementy systemu, to jest:

  • główny system plików (zawiera aplikacje oraz sterowniki niezbędne do pracy urządzenia),
  • jądro systemu operacyjnego [ang. kernel],
  • ustawienia konfiguracyjne (niekiedy ustawienia konfiguracyjne przechowuje się oddzielnie, aby ich nie utracić podczas aktualizacji).

Z punktu widzenia programisty i konstruktora takiego systemu, niezbędne jest posiadanie metod i narzędzi do budowania obrazu firmware'u na podstawie plików źródłowych. Oczywiście ręczne przygotowywanie byłoby bardzo żmudne i czasochłonne. Na szczęście istnieją narzędzia przeznaczone do wykonywania tych czynności. Ich wykorzystanie sprowadza się do przygotowania konfiguracji, a następnie do uruchomienia procesu automatycznego budowania firmware'u. W wyniku działania takich narzędzi powstają pliki obrazu, które należy umieścić na docelowym urządzeniu.

Buildroot - system do budowania firmware'u
Godnym polecenia systemem do budowania obrazu firmware'u jest
Buildroot. Jest on w stanie wykonać wszystkie potrzebne czynności, niezbędne do utworzenia obrazu, czyli:

  • ściąga pliki źródłowe odpowiednich pakietów z internetu,
  • aplikuje poprawki na źródłach (patche),
  • buduje toolchain (w tym kross-kompilator, niezbędny gdyż docelowy procesor może posiadać inną architekturę niż ten, na którym buduje się firmware),
  • przygotowuje główny system plików (rootfs),
  • kompiluje jądro [ang. kernel] systemu (w tym przypadku Linuxa),
  • buduje bootloader,
  • przygotowuje skompresowane pliki obrazu, gotowe to 'wrzucenia' na urządzenie.

Działania programisty sprowadzają się do określenia konfiguracji, w tym wyboru pakietów, które mają znaleźć się na docelowym urządzeniu. Następnie uruchamiany jest proces budowania, który przebiega dalej automatycznie. Buildroot jest napisany w makefile'ach oraz skryptach powłoki, dzięki czemu możliwa jest ingerencja w proces budowania i zmodyfikowanie go w celu dopasowania do nietypowych potrzeb. Ponadto, wykorzystując zdefiniowane funkcje w Buildroocie można opisać własne pakiety, określić jak mają być kompilowane, czy nakładać na nie poprawki oraz w jaki sposób i gdzie mają być instalowane.
Trzeba pamiętać, że Buildroot jest przeznaczony do budowania obrazów firmware'u, nie posiada on mechanizmów zarządzania i dystrybuowania pakietów na docelowe urządzenia. Do aktualizacji firmware'u przyjęto filozofię podmiany całego obrazu. Chociaż Buildroot śledzi wykonane etapy na kolejnych pakietach (tzn. ściągnięcie, konfiguracja, kompilacja, instalacja), to nie sprawdza czy nie zmodyfikowano źródeł pakietu. Z tego powodu niebędne jest czasem wyczyszczenie i wykonanie budowania od początku. Niestety pociąga to za sobą również budowanie toolchaina, co staje się uciążliwe, ponieważ wydłuża całą procedurę. Na szczęście, Buildroot umożliwia 'podczepienie' gotowego, zewnętrznego toolchaina. Można więc skorzystać z jednej z poniższych opcji:

Użycie zewnętrznego toolchaina poza oszczędnością czasu daje dodatkowe korzyści. Toolchain budowany przez Buildroota jest ściśle związany z biblioteką C w postaci uClibc, która może okazać się zbyt uproszczona w niektórych zastosowaniach (w szczególności pojawią się problem gdy potrzebne jest C++). Z powyższego powodu podczas budowania własnego toolchaina uzyskuje się więcej możliwości i swobody. Jednocześnie, nie stanowi to dużo większego nakładu pracy, gdyż toolchain przygotowuje się zwykle raz, na samym początku a potem już tylko używa.
Trzeba pamiętać, że jeśli nie określono tego inaczej w konfiguracji, Buildroot umieszcza w docelowym systemie Busybox - program obsługujący zestaw poleceń powłoki w uproszczonej, kompaktowej formie. Może się więc okazać, że dla niektórych poleceń dostępna jest tylko część funkcjonalności lub wystepują drobne niezgodności w opcjach. Warto w takim przypadku zajrzeć do konfiguracji samego BusyBoxa (make busybox-menuconfig), co ustawia się oddzielnie od konfiguracji Buildroota.

Drzewo katalogów w Buildroocie
Po sciągnięciu i rozpakowaniu pakietu Buildroot widoczne są nastepujące katalogi, zawierające odpowiednio:

+ board - zawiera pliki specyficzne dla platformy
+ boot - zawiera opcje konfiguracji dla różnych bootloaderów
+ configs - zawiera domyślne konfiguracje Buildroota dla znanych platform, po skonfigurowaniu można zapisać tam własną
+ docs - dokumentacja Buildroota (format HTML oraz PDF)
+ fs - konfiguracje do generacji różnych systemów plików
   + skeleton - szkielet głównego systemu plików (rootfs)
+ linux - konfiguracja oraz makefile do generacji kernela Linuxa (również rozszeżeń RT, takich jak RTAI, Xenomai)
+ package - konfiguracje i makefile wielu pakietów userspace'owych
+ support - różne elementy niezbędne do budowania (skrypty, kconfig - obsługa menu konfiguracyjnego)
+ target - katalog prawie nieużywany, zawiera tylko domyślną tabelę urządzeń (device table)
+ toolchain - konfiguracje do budowania lub importowania zewnętrznego toolchaina

Po rozpoczęciu budowania obrazu pojawią się podkatalogi:

+ dl - gdzie są ściągane wszelkie pliki zewnętrzne (zwykle spakowane pakiety w postaci źródłowej),
+ output - katalog, w którym są rozpakowywane źródła, budowane pakiety oraz gdzie znajdą się pliki wynikowe i obrazy

Patrząc na drzewo Buildroota, warto zwrócić uwagę na oddzielenie opisu pakietu (konfiguracja i makefile określajace jak należy postępować z pakietem aby go zbudować) od treści pakietów (źródeł, makefile'i i plików wynikowych). Z tego powodu konfiguracje pakietów w Buildrootcie mogą być traktowane jako meta-opis.


Buildroot drzewo katalogów
Drzewo katalogów: z lewej - główny katalog Buildroota, z prawej - zawartość katalogu output

W podkatalogu output można znaleźć następujące katalogi:

+ build - zawiera podkatalogi pakietów, a w nich źródła; w tych podkatalogach będzie następowało budowanie,
+ host - zawiera narzędzia używane na hoście do budowania,
   + host/usr/<nazwa>/sysroot - podkatalog zawierający sysroot dla toolchaina, biblioteki i nagłówki nięzbędne do budowania aplikacji na docelową platformę (*),
+ images - wynikowe, końcowe pliki obrazów (firmware, bootloader, itp.),
+ staging - link do [*] - sysroot (patrz powyżej w katalogu host),
+ stamps - pliki-stemple czasowe do określania co zostało zrobione,
+ target - docelowy, główny system plików bez tablicy urządzeń,
+ toolchain - katalog, w którym jest budowany toolchain (źródła kompilatora, biblioteki C, nagłówki Linuxa).

Trzeba pamiętać, że wszelkie zmiany w katalogu output są tracone po wykonaniu

make clean

Jest to szczególnie ważne, jeśli dokonuje się poprawek (tuningu) docelowego systemu plików w katalogu output/target. Może to być np. dodanie opisu interfejsów sieciowych (plik /etc/network/interfaces), nadania hasła poprzez wpis do /etc/shadow czy włączenia konsoli na porcie szeregowym ttyS0 (plik /etc/inittab).
Po skasowaniu i rozpoczęciu ponownego budowania, Buildroot wykorzystuje szkielet fs/skeleton, który (i) można zmodyfikować dopasowując do własnych potrzeb, (ii) stworzyć własny szkielet albo (iii) skorzystać ze skryptu uruchamianego po zakończeniu tworzenia głównego systemu plików (ta trzecia opcja jest wygodna gdy zmian jest niewiele). Użycie własnego szkieletu, utworzonego np. przez skopiowanie fs/skeleton może spowodować niepodziankę: po uruchomieniu docelowego systemu, bootuje się on ale nie pojawia się konsola - nie ma możliwości zalogowania się. Powodem takiego zachowania jest zakomentowana konsola w /etc/inittab:

# Put a getty on the serial port
# ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL

A dlaczego działało przy użyciu domyślnego szkieletu? Przecież nowy szkielet został utworzony jako kopia? Okazuje się, że gdy wybrany jest domyślny szkielet, wykonywane jest automatyczne odkomentowanie tej linii poprzez jeden ze skryptów na podstawie opcji w konfiguracji. Z resztą, wystarczy zaobserwować, że wybranie własnego szkieletu w konfiguracji powoduje ukrycie opcji dotyczących konsoli na ttyS0.

Konfiguracja Buildroota
Buildroot jest konfigurowany za pośrednictwem dobrze znanego interfejsu z konfiguracji kernela, po wydaniu polecenia:

make menuconfig

pojawia się okno konfiguracji:

Konfigruacja Buildroota

Pierwsze dwa podmenu służą do wybrania rodziny oraz odmiany architektury procesora na docelowej platformie. Dalsze pozycje menu zostały opisane poniżej (podany został tylko opis ważniejszych opcji):

1. Build options

Number of jobs to run simultaneously - określa zrównoleglenie procesu budowania (szybkość vs. obciążenie komputera). Nie należy używać opcji make -jN, tylko w tym miejscu podać liczbę zadań (próba użycia make -jN może doprowadzić do błedów).

strip - określa czy usuwać z plików wykonywalnych sekcje zawierające informacje dla debugera, głównie symbole, powiązania nr. linii źródeł i kodu binarnego. Stripując można znacznie zmniejszyć rozmiar plików wykonywalnych.

gcc optimization level - stopień i typ optymalizacji kodu generowanego przez kompilator GCC

2. Toolchain

Toolchain type - pozwala wybrać czy Buildroot ma budować toolchain samodzielnie czy używać zewnętrzny toolchain

Kernel Headers - ustala wersję nagłówków Linuxa z jakimi ma być budowany toolchain, jeśli nie ma na liście wersji, którą używamy, trzeba wybrać "Linux 2.6 (manually specified version)" i w "linux version" wpisać numer wymaganej wersji. Nie należy się przejmować numerem 2.6 na liście, istotny będzie wpisany przez nas numer.

Enable C++ - włącza obsługę C++ (uwaga uClibc nie zawiera standardowej biblioteki stdlibc++, aby budować prorgamy C++ należy użyć zewnętrznego toolchaina zbudowanego z inną biblioteką (np. glibc).

3. System configuration

System hostname - nazwa komputera (docelowej platformy), domyślnie buildroot

System banner - teskt powitalny na konsoli

/dev management - sposób tworzenia tablicy urządzeń (może być statyczna wkompilowana w obraz albo tworzona przez udev)

Root FS skeleton - szkielet systemu plików, domyślny to fs/skeleton

Port to run a getty (login prompt) on - port, na którym pojawi się konsola, domyślnie ttyS0, opcja dostępna tylko dla domyślnego szkieletu

Baudrate to use - szybkość transmisji portu szeregowego, domyślnie ustawione na 115200

Custom script to run before creating filesystem images - skrypt, który będzie uruchamiany przed tworzeniem końcowego pliku obrazu, można go używać do wprowadzania zmian w głównym systemie plików (dopasowanie).

4. Package selection for the target - pakiety, które mają być zbudowane i zainstalowane w obrazie dla docelowej platformy.

5. Filesystem images - określenie w jakich formatach ma być wygenerowany obraz (np. .tag.gz, jffs2, itd.)

6. Bootloaders - wybór bootloadera (Barebox, grub, syslinux, U-Boot) i ustawienie jego opcji

7. Kernel

Linux Kernel - należy zaznaczyć jeśli ma być budowany

Kernel Version - określenie wersji kernela, dobrze żeby był zgodny z wersją określoną do budowy toolchaina

Custom kernel patches - patche nakładane na kernel, można podać katalog, wtedy patche będą nakładane w kolejnosci nazw - jest to przydatne gdy patche są wygenerowane przez gita, wtedy ich nazwy rozpoczynają się od kolejnych liczb, np. 0001-, 0002-, itd.).

kernel configuration/configuration file path - określa konfigurację kernela, która ma być użyta do budowania.

Uwaga
a. Jeśli używana jest konfiguracja domyślna (defconfig) należy podać jej nazwę (np. i386, jeśli chce się użyć konfiguracji z pakietu kernela arch/x86/configs/i386_defconfig), w przeciwnym przypadku pojawi się błąd:

linux/linux.mk:228 *** No kernel defconfig name specified. check your BR2_LINUX_KERNEL_DEFCONFIG setting. Stop.

b. Można jednak utworzyć własną konfigurację w oddzielnym katalogu (również poprzez make menuconfig, po rozpakowaniu źródeł kernela), a następnie wybrać w konfiguracji Buildroota konfigurację nietypową (custom) i wskazać plik .config z katalogu kernela. Trzeba pamiętać aby konfiguracja była poza katalogiem output, inaczej zostanie skasowana przy czyszceniu buildroota (wykonanie make clean).

Install kernel image to /boot in target - pozwala umieścić kernel w obrazie rootfs w katalogu /boot. Wykorzystanie tej opcji zależy od wybranej struktury systemu, czasem kernel jest w odrębnej partycji niż rootfs.

Ten sam interfejs konfiguracji jest wykorzystywany do ustawienia parametów innych głównych elementów Buildroota, odpowiednio Busyboxa, kernela Linuxa oraz biblioteki C typu uClibc:

make busybox-menuconfig
make linux-menuconfig
make uclibc-menuconfig

Więcej opcji można wyświetlić uruchamiając:

make help

a także uzyskać wiecej informacji przeglądając manual Buildroota.

Jak umieścić obraz na urządzeniu?
Gotowy plik obrazu firmware'u, który jest wynikiem budowania pod Buildrootem należy umieścić na docelowym urządzeniu. W zależności od przyjętego rozwiązania konstrukcyjnego docelowej platformy, firmware może być tam przechowywany:

  • we wlutowanym na płytce układzie pamięci FLASH,
  • na karcie pamięci nieulotnej (np. Compact Flash), którą można wyjąć z urządzenia i zaprogramować w zewnętrznym czytniku, podłączonym do innego komputera
  • na twardym dysku, który można "przepiąć" do działającego systemu jako dysk dodatkowy (niesystemowy).

Urządzenie może też być w różnym stanie wynikającym z procesu produkcyjnego, np.:

  • może nie mieć żadnego bootloadera, w takim przypadku konieczny jest sprzętowy JTAG (alternatywą może być też uruchomienie pomocniczego systemu z pendrive'a usb czy dystrybucji LiveCD, jeśli tylko platforma pozwala na boot z takich lokalizacji - będzie tak dla urządzeń z procesorami x86 posiadającymi BIOS),
  • urządzenie posiada bootloader, wtedy pozwala on na 'wciągnięcie' i zapisanie nowego obrazu przez łacze szeregowe lub sieć,
  • urządzenie posiada działający system z programem do uaktualniania obrazu.

Typowe problemy

1. po zaznaczeniu budowania kernela, proces budowania zatrzymuje się i pojawia się bład:

linux/linux.mk:228 *** No kernel defconfig name specified. check your BR2_LINUX_KERNEL_DEFCONFIG setting. Stop.

Oznacza to, że nie wskazano konfiguracji kernela. Należy wskazać nazwę konfiguracji standardowej z pakietu kernela albo własny plik .config gdy jest to konfiguracja nietypowa. Konfiguracji standardowych można szukać w arch/<arch&gr/configs/, przykładowo dla arch/x86/configs/i386_defconfig należy w konfiguracji buildroota podać i386.

2. po zakończeniu bootowania urządzenia nie pojawia się tekst zachęcający do zalogowania, nie można zalogować się na konsolę po porcie szeregowym.
Trzeba sprawdzić czy konsola ttyS0 jest włączona (i czy nie jest zakomentowana) w pliku /etc/inittab:

# Put a getty on the serial port
ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL

3. po uruchomieniu nie ma interfejsu sieciowego eth0
Należy dodać odpowiedni opis w pliku /etc/network/interfaces, np.:

auto eth0
iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1

Pierwsza linijka odpowiada za automatyczne podniesienie interfejsu po uruchomieniu systemu. Jeśli nie chce się tego robić automatycznie trzeba ją usunąć i korzystać z ifconfig.

4. zmiany wprowadzone w plikach w katalogu target zniknęły
Jest to naturalne, stało się tak zapewne w wyniku wyczyszczenia buildroota (przez make clean), wtedy system plików jest budowany ponownie.

5. zmiany wprowadzone w fs/skeleton nie przeniosły się do docelowego obrazu plików
Zmiany przeniosą się (do katalogu target i obrazu rootfs) podczas następnego budowania systemu plików. Należy wykonać make clean Buildroota.

6. Nie można zalogować się przez SSH do urządzenia, chociaż pakiet dropbear został dodany
Trzeba sprawdzić czy użytkownik ma nadane hasło. Domyslnie buildroot posiada użytkownika root bez hasła a pakiet dropbear odrzuca logowanie użytkowników bez hasła. Należy nadać mu hasło przez passwd.

Materiały na temat Buildroota

Na zakończenie warto dodać, że Buildroot jest wykorzystywany w innym projekcie: OpenWRT, który z kolei jest przeznaczony do tworzenia firmware'u dla routerów.