Como desenvolver um sistema Linux do zero para a Raspberry Pi

- por Sergio Prado

Categorias: Linux, Raspberry Pi Tags: , , , ,

A Raspberry Pi já possui diversas distribuições Linux disponíveis, para diversos gostos e preferências, dentre elas Rasp­bian, Raspbmc, Debian “wheezy” e Arch Linux (eu escrevi sobre algumas delas no meu artigo introdutório sobre a Raspberry Pi).

E o uso de uma distribuição Linux facilita bastante o trabalho, principalmente para quem esta começando seus estudos. Mas junto com a facilidade de uso, vem a falta de flexibilidade. E se você quiser um tempo de boot menor? E se você quiser apenas um conjunto específico de aplicações? E se você quiser ter controle sobre os pacotes open source usados na distribuição e suas respectivas licenças (atividade essencial em um produto comercial)?

Tudo isso fica mais difícil de atingir quando usamos uma distribuição Linux pronta. Neste caso, o ideal é construir um sistema Linux customizado para as necessidades do projeto. E é isso que faremos neste artigo.

Todos os testes foram realizados em um PC com a distribuição Ubuntu 12.04 rodando nativamente. Se necessário, adapte os comandos utilizados à sua distribuição.

Então, vamos começar?

UM SISTEMA LINUX

Você precisa basicamente de 4 componentes para construir um sistema Linux completo (para qualquer plataforma de hardware):

  1. Toolchain
  2. Bootloader
  3. Kernel
  4. Rootfs

Vamos então estudar estes componentes mais detalhadamente.

TOOLCHAIN

Já escrevi bastante sobre toolchains, incluindo os artigos “Desmistificando toolchains em Linux embarcado” e “Gerando e usando toolchains em Linux embarcado“. Se você não souber ou quiser conhecer mais sobre o que é um toolchain e o seu uso em Linux embarcado, dê uma olhada nestes artigos.

Nossa plataforma de hardware é um ARM11 com suporte à ponto flutuante. Portanto, precisamos de um toolchain com estas características para trabalhar com Linux. E não precisamos ir muito longe. O projeto da Raspberry Pi já fornece um toolchain pronto para usarmos, baseado no toolchain da Linaro. Este toolchain esta disponível no repositório tools da Raspberry Pi no github.

Antes de começar, vamos criar um diretório de trabalho:

$ mkdir ~/raspberrypi

Agora vamos baixar o toolchain:

$ cd ~/raspberrypi
$ git clone https://github.com/raspberrypi/tools.git

E instalar em um diretório na máquina de desenvolvimento:

$ sudo mkdir -p /opt/toolchain
$ sudo chown $USER:$USER /opt/toolchain/
$ cp -a tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian /opt/toolchain/

Antes de usá-lo, vamos adicionar o diretório dos binários do toolchain no PATH:

$ echo -e '\nexport PATH="/opt/toolchain/gcc-linaro-arm-linux-gnueabihf-raspbian/bin:$PATH"\n' >> ~/.bashrc
$ source ~/.bashrc

Se sua máquina for de 64 bits, você precisa instalar os bibliotecas de 32 bits:

$ sudo apt-get install ia32-libs libc6-dev-i386

Se você estiver usando uma versão mais nova do Ubuntu, o comando acima pode não funcionar. Tente então instalar as bibliotecas de 32 bits com o comando abaixo:

$ sudo apt-get install lib32stdc++6 libc6-dev-i386

Agora teste o toolchain:

$ arm-linux-gnueabihf-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabihf-gcc
COLLECT_LTO_WRAPPER=/opt/toolchain/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/../libexec/gcc/arm-linux-gnueabihf/4.7.2/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: /cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/src/gcc-linaro-4.7-2012.08/configure --build=i686-build_pc-linux-gnu --host=i686-build_pc-linux-gnu --target=arm-linux-gnueabihf --prefix=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/install --with-sysroot=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/install/arm-linux-gnueabihf/libc --enable-languages=c,c++,fortran --disable-multilib --with-arch=armv6 --with-tune=arm1176jz-s --with-fpu=vfp --with-float=hard --with-pkgversion='crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08' --with-bugurl=https://bugs.launchpad.net/gcc-linaro --enable-__cxa_atexit --enable-libmudflap --enable-libgomp --enable-libssp --with-gmp=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-mpfr=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-mpc=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-ppl=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-cloog=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-libelf=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-host-libstdcxx='-L/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static/lib -lpwl' --enable-threads=posix --disable-libstdcxx-pch --enable-linker-build-id --enable-plugin --enable-gold --with-local-prefix=/cbuild/slaves/oort61/crosstool-ng/builds/arm-linux-gnueabihf-raspbian-linux/install/arm-linux-gnueabihf/libc --enable-c99 --enable-long-long
Thread model: posix
gcc version 4.7.2 20120731 (prerelease) (crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08)

Com as ferramentas de desenvolvimento instaladas, podemos começar a desenvolver o nosso sistema Linux.

BOOTLOADER

O processo de boot da Raspberry Pi é um pouco diferente quando comparada à outras plataformas ARM disponíveis no mercado. Quando você energiza a placa, quem assume o controle é a GPU do SoC (o núcleo ARM11 esta desabilitado neste momento). A GPU procura na primeira partição do cartão SD um código de boot, e com mais alguns passo adicionais, irá carregar e executar o kernel Linux. Para uma descrição mais completa do processo de boot da Raspberry Pi , leia o artigo “Raspberry Pi e o processo de boot“.

Precisamos então preparar um cartão SD com 2 partições:

  • Partição 1 (FAT32): partição de 64M para armazenar o código de boot, arquivos de configuração da GPU e a imagem do kernel Linux.
  • Partição 2 (EXT2): partição para armazenar o sistema de arquivos (aqui você pode usar o resto do espaço disponível no cartão SD).

Para formatar o cartão SD você pode usar o gparted, conforme abaixo (altere o sdX pelo nome do arquivo de dispositivo do seu cartão SD):

$ sudo gparted /dev/sdX

O particionamento do cartão SD deve ficar assim:

Perceba que criamos a primeira partição após os primeiros 2MB do cartão SD. Aparentemente isso é essencial para que a GPU consiga carregar o código de boot da primeira partição do cartão (as distros que testei gravam o cartão assim, e sem esta configuração não funcionou nos meus testes).

Com o cartão formatado, é só baixar os binários do bootloader e gravá-los na primeira partição do cartão (altere o ponto de montagem do cartão SD se necessário):

$ cd ~/raspberrypi
$ git clone git://github.com/raspberrypi/firmware.git
$ cd firmware/boot
$ cp bootcode.bin start.elf fixup.dat /media/BOOT/
$ echo "gpu_mem=32" > /media/BOOT/config.txt

KERNEL

No momento em que escrevo este artigo, o kernel da Raspberry Pi esta disponível no repositório linux do projeto no github.

Baixe então os fontes para sua máquina de desenvolvimento:

$ cd ~/raspberrypi
$ git clone git://github.com/raspberrypi/linux.git -b rpi-3.2.27
$ cd linux

Vamos configurar o kernel para ser compilado para a Raspberry Pi:

$ make ARCH=arm bcmrpi_cutdown_defconfig

Antes de compilar, abra o menu de configuração:

$ make ARCH=arm menuconfig

E habilite o sistema de arquivos ext2:

File systems  --->
    <*> Second extended fs support

Agora compile:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

E grave no cartão SD (altere o ponto de montagem do cartão SD se necessário):

$ cp -av arch/arm/boot/zImage /media/BOOT/kernel.img
$ echo "console=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext2 rootwait" > /media/BOOT/cmdline.txt

ROOTFS

Este é o nosso último passo. Vamos construir um sistema de arquivos simples baseado no Busybox. E para esta tarefa, usaremos o Buildroot.

O Buildroot é um sistema de build completo, capaz de gerar o toolchain, bootloader, kernel e rootfs. Mas para nossos testes, usaremos ele apenas para gerar o rootfs.

Baixe então o Buildroot para a sua máquina:

$ cd ~/raspberrypi
$ wget http://buildroot.net/downloads/buildroot-2012.08.tar.bz2
$ tar xjfv buildroot-2012.08.tar.bz2
$ cd buildroot-2012.08/

E inicie o processo de configuração:

$ make menuconfig

Primeiro configure a arquitetura:

Target Architecture (ARM (little endian))
Target Architecture Variant (arm1176jzf-s)

Depois configure o toolchain (apesar do Buildroot ter a capacidade de gerar seu próprio toolchain, vamos configurá-lo para usar o toolchain que instalamos no começo deste artigo):

Toolchain  --->
        Toolchain type (External toolchain)
        Toolchain (Custom toolchain)
        Toolchain origin (Pre-installed toolchain)
    (/opt/toolchain/gcc-linaro-arm-linux-gnueabihf-raspbian) Toolchain path
    ($(ARCH)-linux-gnueabihf) Toolchain prefix
        External toolchain C library (glibc)
    [*] Toolchain has C++ support?

Configure o sistema a ser gerado:

System configuration  --->
    (My Raspberry Pi is alive!) System banner
        /dev management (Dynamic using devtmpfs only)
    (ttyAMA0) Port to run a getty (login prompt) on

Sinta-se livre para acessar o menu “Package Selection for the target” e habilitar as aplicações que achar interessante. Minha sugestão é que você não habilite muitos pacotes neste primeiro teste, nem nada muito grande ou complexo como o X11. Você evitará eventuais problemas ou um tempo de compilação muito grande. E de qualquer forma, depois dos primeiros testes você poderá habilitar outras aplicações e bibliotecas e recompilar o Buildroot.

Agora é só iniciar o processo de compilação:

$ make

No fim da compilação, o Buildroot irá gerar a imagem do rootfs no diretório abaixo:

$ ls -l output/images/
-rw-rw-r-- 1 sprado sprado 4843520 Nov 3 20:20 rootfs.tar

Por último, é só extrair a imagem para a partição do rootfs no cartão SD (altere o ponto de montagem do cartão SD se necessário):

$ sudo cp -av output/images/rootfs.tar /media/ROOTFS/
$ cd /media/ROOTFS/
$ sudo tar xfv rootfs.tar && sudo rm rootfs.tar

TESTANDO

Para testar, você vai precisar de uma conexão com a console da Raspberry Pi. Na dúvida, dê uma olhada no artigo “Acessando a console serial na Raspberry Pi“.

Depois é só curtir o boot do sistema (para o login, o usuário é “root” e não tem senha):

Uncompressing Linux... done, booting the kernel.
Initializing cgroup subsys cpu
Linux version 3.2.27-cutdown+ (sprado@sergio-office-notebook) (gcc version 4.7.2 20120731 (prerelease) (crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08) ) #1 PREEMPT Sat Nov 3 16:23:41 BRST 2012
CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: BCM2708
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 56896
Kernel command line: dma.dmachans=0x7f35 bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=1024 bcm2708.boardrev=0x2 bcm2708.serial=0xff0782fa smsc95xx.macaddr=B8:27:EB:07:82:FA sdhci-bcm2708.emmc_clock_freq=10t
PID hash table entries: 1024 (order: 0, 4096 bytes)
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 224MB = 224MB total
Memory: 222856k/222856k available, 6520k reserved, 0K highmem
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    vmalloc : 0xce800000 - 0xe8000000   ( 408 MB)
    lowmem  : 0xc0000000 - 0xce000000   ( 224 MB)
    modules : 0xbf000000 - 0xc0000000   (  16 MB)
      .text : 0xc0008000 - 0xc03cc000   (3856 kB)
      .init : 0xc03cc000 - 0xc03eac80   ( 124 kB)
      .data : 0xc03ec000 - 0xc04121e0   ( 153 kB)
       .bss : 0xc0412204 - 0xc045f8cc   ( 310 kB)
NR_IRQS:330
sched_clock: 32 bits at 1000kHz, resolution 1000ns, wraps every 4294967ms
timer_set_mode: unhandled mode:1
timer_set_mode: unhandled mode:3
Console: colour dummy device 80x30
Calibrating delay loop... 697.95 BogoMIPS (lpj=3489792)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
devtmpfs: initialized
NET: Registered protocol family 16
bcm2708.uart_clock = 0
mailbox: Broadcom VideoCore Mailbox driver
bcm2708_vcio: mailbox at f200b880
bcm_power: Broadcom power driver
bcm_power_open() -> 0
bcm_power_request(0, 8)
bcm_mailbox_read -> 00000080, 0
bcm_power_request -> 0
Serial: AMBA PL011 UART driver
dev:f1: ttyAMA0 at MMIO 0x20201000 (irq = 83) is a PL011 rev3
console [ttyAMA0] enabled
bio: create slab  at 0
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Switching to clocksource stc
FS-Cache: Loaded
CacheFiles: Loaded
NET: Registered protocol family 2
IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
TCP established hash table entries: 8192 (order: 4, 65536 bytes)
TCP bind hash table entries: 8192 (order: 3, 32768 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP reno registered
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
bcm2708_dma: DMA manager at ce808000
bcm2708_gpio: bcm2708_gpio_probe c03f1a78
vc-mem: phys_addr:0x00000000 mem_base=0x0e000000 mem_size:0x10000000(256 MiB)
VFS: Disk quotas dquot_6.5.2
Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
FS-Cache: Netfs 'nfs' registered for caching
msgmni has been set to 435
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
Console: switching to colour frame buffer device 160x64
brd: module loaded
loop: module loaded
vcos: [1]: vchiq_init_state: slot_zero = 0xffd80000, is_master = 0
vcos: [1]: vchiq_init_state: called
vcos: [1]: vchiq: initialised - version 2 (min 2), device 253.0
usbcore: registered new interface driver smsc95xx
cdc_ncm: 04-Aug-2011
usbcore: registered new interface driver cdc_ncm
dwc_otg: version 3.00a 10-AUG-2012 (platform bus)
Core Release: 2.80a
Setting default values for core params
Finished setting default values for core params
Using Buffer DMA mode
Periodic Transfer Interrupt Enhancement - disabled
Multiprocessor Interrupt Enhancement - disabled
OTG VER PARAM: 0, OTG VER FLAG: 0
Dedicated Tx FIFOs mode
dwc_otg bcm2708_usb: DWC OTG Controller
dwc_otg bcm2708_usb: new USB bus registered, assigned bus number 1
dwc_otg bcm2708_usb: irq 32, io mem 0x00000000
Init: Port Power? op_state=1
Init: Power Port (0)
usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: DWC OTG Controller
usb usb1: Manufacturer: Linux 3.2.27-cutdown+ dwc_otg_hcd
usb usb1: SerialNumber: bcm2708_usb
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver uas
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
usbcore: registered new interface driver libusual
mousedev: PS/2 mouse device common for all mice
cpuidle: using governor ladder
cpuidle: using governor menu
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
sdhci: Enable low-latency mode
bcm_power_open() -> 1
mmc0: SDHCI controller on BCM2708_Arasan [platform] using platform's DMA
mmc0: BCM2708 SDHC host at 0x20300000 DMA 2 IRQ 77
sdhci-pltfm: SDHCI platform and OF driver helper
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
TCP cubic registered
Initializing XFRM netlink socket
NET: Registered protocol family 17
Registering the dns_resolver key type
VFP support v0.3: implementor 41 architecture 1 part 20 variant b rev 5
Waiting for root device /dev/mmcblk0p2...
mmc0: problem reading SD Status register.
mmc0: new high speed SD card at address 0007
mmcblk0: mmc0:0007 SD2GB 1.84 GiB 
 mmcblk0: p1 p2
EXT2-fs (mmcblk0p2): warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem) on device 179:2.
devtmpfs: mounted
Freeing init memory: 120K
Starting logging: OK
Initializing random number generator... done.
Starting network...
 
My Raspberry Pi is alive!
buildroot login: root
#

Para ter acesso completo à todos os recursos da Raspberry Pi, só faltou incluir no nosso sistema as bibliotecas de acesso à GPU. Estas bibliotecas possibilitam a utilização da GPU para tarefas pesadas como decodificação de vídeo e execução de aplicações 3D. Este será o foco do nosso próximo artigo.

Happy Pi hacking!

Sergio Prado

para

Faça um Comentário

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.