O Kernel

Introdução

A princípio pode parecer uma tarefa quase impossível entender e configurar o Kernel para uma nova arquitetura. São mais de 20.000 arquivos e 6 milhões de linhas, sem contar as ferramentas de compilação, sistema de arquivos raiz e aplicações. É importante entender como o kernel funciona, e como suas fontes estão organizadas.

Estrutura do Kernel

Diversos arquivos e diretórios compõem os fontes do Kernel. O diretório …/drivers, por exemplo, contém a implementação dos drivers dos diversos periféricos do sistema, como portas USB, Ethernet, serial, etc. O diretório …/arch contém os arquivos que são suporte a diversas arquiteturas de computadores. O diretório fonte do Kernel 2.6 do uClinux, após o build, é listado abaixo:

uderman@udermanlp:~/uClinux/uClinux-dist/linux-2.6.x$ ls
arch     Documentation  ipc     MAINTAINERS     README          System.map
block    drivers        Kbuild  Makefile        REPORTING-BUGS  teste.config
COPYING  fs             kernel  mm              scripts         usr
CREDITS  include        lib     Module.symvers  security        vmlinux
crypto   init           linux   net             sound

Dois dos arquivos importantes gerados pelo build são System.map e vmlinux. System.map é um arquivo que contém uma lista de símbolos do Kernel, e seus respectivos endereços. Estas informações são úteis para depurar o Kernel. O arquivo vmlinux é um arquivo executável no formato ELF (Executable and Linking Format), gerado após a compilação do Kernel. Este arquivo é uma imagem binária do Kernel.

Analisando as partes que compõem o arquivo vmlinux, pode-se ter uma visão de alto nível do Kernel. Os três principais componentes da imagem binária do Kernel são o sistema de arquivos, drivers de dispositivos e rede. O Kernel em si, junto com os drivers de dispositivos, também ocupa uma parcela significativa do arquivo. Poucas plataformas fazem o boot diretamente com esta imagem. Normalmente, esta imagem está comprimida e um bootloader é utilizado para descomprimir e carregar a imagem do Kernel. A figura abaixo ilustra os componentes típicos de vmlinux:

Add Figura e Tabela

Processo de configuração e compilação do Kernel

O processo de compilação do Kernel é bastante complexo, entretanto, boa parte da complexidade é encapsulada pelas ferramentas disponíveis. Diversos sub-diretórios do Kernel possuem arquivos Makefile e Kconfig, utilizados na configuração e compilação do Kernel. A listagem abaixo mostra o do diretório referente a uma determinada família de processadores ARM, um subdiretório do Kernel. Caso o Kernel do linux seja configurado para esta família, os arquivos Kconfig e Makefile serão utilizado no processo de configuração e compilação do Kernel, respectivamente:

uderman@udermanlp:~/uClinux/uClinux-dist/linux-2.6.x$ ls -l arch/arm/mach-ixp4xx/
-rw-rw-r-- 1 500 500  8845 2006-11-29 23:03 common.c
-rw-rw-r-- 1 500 500 13029 2006-11-13 22:42 common-pci.c
-rw-rw-r-- 1 500 500  1610 2006-11-29 23:03 coyote-pci.c
-rw-rw-r-- 1 500 500  3158 2006-05-25 00:36 coyote-setup.c
-rw-rw-r-- 1 500 500  1782 2006-11-29 23:39 ess710-pci.c
-rw-rw-r-- 1 500 500  2759 2005-10-28 01:39 gtwx5715-pci.c
-rw-rw-r-- 1 500 500  3939 2006-10-08 21:01 gtwx5715-setup.c
-rw-rw-r-- 1 500 500  1750 2006-10-11 04:07 ixdp425-pci.c
-rw-rw-r-- 1 500 500  4532 2006-03-21 04:07 ixdp425-setup.c
-rw-rw-r-- 1 500 500  1505 2006-11-29 20:28 ixdpg425-pci.c
-rw-rw-r-- 1 500 500  6641 2006-10-11 04:07 Kconfig
-rw-rw-r-- 1 500 500  1461 2006-10-11 04:07 Makefile
-rw-rw-r-- 1 500 500    57 2005-01-04 08:59 Makefile.boot
-rw-rw-r-- 1 500 500  1701 2006-10-08 21:01 nas100d-pci.c
-rw-rw-r-- 1 500 500  1522 2006-11-29 20:28 nas100d-power.c
-rw-rw-r-- 1 500 500  4173 2006-10-08 21:01 nas100d-setup.c
-rw-rw-r-- 1 500 500  1531 2006-10-08 21:01 nslu2-pci.c
-rw-rw-r-- 1 500 500  2037 2006-11-29 20:28 nslu2-power.c
-rw-rw-r-- 1 500 500  4468 2006-11-29 20:28 nslu2-setup.c
-rw-rw-r-- 1 500 500  1450 2006-10-15 23:10 sg5xx-pci.c
-rw-rw-r-- 1 500 500  2427 2007-01-17 03:05 sg720-pci.c
-rw-rw-r-- 1 500 500  6452 2006-11-13 05:42 sg-setup.c

Configuração

Existem algumas maneiras diferentes de configurar o Kernel, desde editar manualmente o arquivo .config até editores por linha de comando e gráficos. Os editores geram menus e textos de ajuda que guiam o processo de configuração do Kernel. Os arquivos Kconfig estão presentes em diversos subdiretórios do Kernel e são responsáveis por armazenar as informações que alimentam os editores. Arquivos Kconfig podem acessar outros arquivos Kconfig, e este recurso é utilizado par compor as diversas sessões e sub-sessões que compõem os editores. Estes menus são invocados como alvos de configuração do comando make. A listagem abaixo mostra parte do help do make, que lista estes alvos. Os quatro primeiros alvos permitem a configuração manual do Kernel, por linha de comando, editores baseados em menus ou gráficos. O comando make menuconfig, por exemplo, inicializa a configuração do Kernel através de um editor baseado em menus:

uderman@udermanlp:~/uClinux/uClinux-dist/linux-2.6.x$ make help

Configuration targets:
  config          - Update current config utilising a line-oriented program
  menuconfig      - Update current config utilising a menu based program
  xconfig         - Update current config utilising a QT based front-end
  gconfig         - Update current config utilising a GTK based front-end

  oldconfig       - Update current config utilising a provided .config as base
  silentoldconfig - Same as oldconfig, but quietly

  randconfig      - New config with random answer to all options
  defconfig       - New config with default answer to all options
  allmodconfig    - New config selecting modules when possible
  allyesconfig    - New config where all options are accepted with yes
  allnoconfig     - New config where all options are answered with no

Todo o resultado da configuração é armazenado no arquivo .config (Dot-config file). Construir um arquivo .config para uma arquitetura específica pode ser trabalhoso, portanto é altamente recomendável fazer cópias de backup destes arquivos. Existem opções do comando make que podem apagar este arquivo sem aviso prévio. As informações contidas no arquivo .config são processadas em um arquivo de cabeçalho C, chamado autoconf.h. Este arquivo está localizado no diretório …/include/lnux. Diversos fontes do Kernel referenciam este arquivo diretamente. É através deste arquivo, autoconf.h, que as modificações realizadas no processo de configuração são implementadas.

O Kernel do Linux é compilado como um único executável linkado estaticamente. Entretanto, é possível compilar e linkar de forma incremental um conjunto de fontes em um único módulo objeto que pode ser dinamicamente inserido em um Kernel Linux em execução. Em linux isto é chamado de módulos carregáveis (loadable modules), ou de forma mais geral, drivers de dispositivos (device drivers). No arquivo .config é possível setar, por exemplo, que o suporte a USB deve ser carregado como um módulo:

# USB support
#
CONFIG_USB=m

Outras linhas de código são necessárias para configurar os drivers da interface USB, mas A linha CONFIG_USB=m especifica que o sub-sistema USB deve ser carregado como um módulo, que poderá ser carregado depois do boot do Kernel. CONFIG_USB=y faria com que este subsistema fosse compilado como parte integrante do Kernel. Através deste recurso pode-se montar uma estrutura baseada no Kernel e nos drivers de dipositivos, que podem ser carregados, removidos, modificados, de forma a atender as mais variadas configurações de hardware e cenários de operação.

Compilação

Depois da configuração, é preciso compilar o Kernel. Executar o comando make no diretório raiz das fontes do Kernel inicia a compilação do Kernel. Durante o processo de compilação, os arquivos Makefile d Kernel decidem quais subdiretórios serão acessados e quais arquivos fontes serão compilados. O uso mais comum do make para compilação é sem especificar parâmetro algum, o que compila o Kernel para os alvos padrões.

Abaixo é mostrada a listagem completa do help do comando make para a arquitetura ARM (é possível exibir o help as diversas arquiteturas suportadas). Os alvos de configuração são mostrados no inicio da listagem. Os alvos (targets) marcados com o* são gerador por padrão, quando se invoca o make sem parâmetros. Observe também a existência de diversas famílias de processadores ARM como possíveis alvos, na parte final da listagem:

uderman@udermanlp:~/uClinux/uClinux-dist/linux-2.6.x$ make ARCH=arm help
Cleaning targets:
  clean           - remove most generated files but keep the config and
                    enough build support to build external modules
  mrproper        - remove all generated files + config + various backup files
  distclean       - mrproper + remove editor backup and patch files

Configuration targets:
  config          - Update current config utilising a line-oriented program
  menuconfig      - Update current config utilising a menu based program
  xconfig         - Update current config utilising a QT based front-end
  gconfig         - Update current config utilising a GTK based front-end
  oldconfig       - Update current config utilising a provided .config as base
  silentoldconfig - Same as oldconfig, but quietly
  randconfig      - New config with random answer to all options
  defconfig       - New config with default answer to all options
  allmodconfig    - New config selecting modules when possible
  allyesconfig    - New config where all options are accepted with yes
  allnoconfig     - New config where all options are answered with no

Other generic targets:
  all             - Build all targets marked with [*]
* vmlinux         - Build the bare kernel
* modules         - Build all modules
  modules_install - Install all modules to INSTALL_MOD_PATH (default: /)
  dir/            - Build all files in dir and below
  dir/file.[ois]  - Build specified target only
  dir/file.ko     - Build module including final link
  rpm             - Build a kernel as an RPM package
  tags/TAGS       - Generate tags file for editors
  cscope          - Generate cscope index
  kernelrelease   - Output the release version string
  kernelversion   - Output the version stored in Makefile
  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH
                    (default: /home/uderman/uClinux/uClinux-dist/linux-2.6.x/usr)

Static analysers
  checkstack      - Generate a list of stack hogs
  namespacecheck  - Name space analysis on compiled kernel
  headers_check   - Sanity check on exported headers

Kernel packaging:
  rpm-pkg         - Build the kernel as an RPM package
  binrpm-pkg      - Build an rpm package containing the compiled kernel
                    and modules
  deb-pkg         - Build the kernel as an deb package
  tar-pkg         - Build the kernel as an uncompressed tarball
  targz-pkg       - Build the kernel as a gzip compressed tarball
  tarbz2-pkg      - Build the kernel as a bzip2 compressed tarball

Documentation targets:
  Linux kernel internal documentation in different formats:
  xmldocs (XML DocBook), psdocs (Postscript), pdfdocs (PDF)
  htmldocs (HTML), mandocs (man pages, use installmandocs to install)

Architecture specific targets (arm):
* zImage        - Compressed kernel image (arch/arm/boot/zImage)
  Image         - Uncompressed kernel image (arch/arm/boot/Image)
* xipImage      - XIP kernel image, if configured (arch/arm/boot/xipImage)
  bootpImage    - Combined zImage and initial RAM disk
                  (supply initrd image via make variable INITRD=<path>)
  install       - Install uncompressed kernel
  zinstall      - Install compressed kernel
                  Install using (your) ~/bin/installkernel or
                  (distribution) /sbin/installkernel or
                  install to $(INSTALL_PATH) and run lilo

  assabet_defconfig        - Build for assabet
  at91rm9200dk_defconfig   - Build for at91rm9200dk
  at91rm9200ek_defconfig   - Build for at91rm9200ek
  ateb9200_defconfig       - Build for ateb9200
  atmel_defconfig          - Build for atmel
  badge4_defconfig         - Build for badge4
  carmeva_defconfig        - Build for carmeva
  cerfcube_defconfig       - Build for cerfcube
  clps7500_defconfig       - Build for clps7500
  collie_defconfig         - Build for collie
  corgi_defconfig          - Build for corgi
  csb337_defconfig         - Build for csb337
  csb637_defconfig         - Build for csb637
  ebsa110_defconfig        - Build for ebsa110
  edb7211_defconfig        - Build for edb7211
  ep93xx_defconfig         - Build for ep93xx
  espd_4510b_defconfig     - Build for espd_4510b
  footbridge_defconfig     - Build for footbridge
  fortunet_defconfig       - Build for fortunet
  GDB_ARMulator_defconfig  - Build for GDB_ARMulator
  h3600_defconfig          - Build for h3600
  h7201_defconfig          - Build for h7201
  h7202_defconfig          - Build for h7202
  hackkit_defconfig        - Build for hackkit
  integrator_defconfig     - Build for integrator
  iop32x_defconfig         - Build for iop32x
  iop33x_defconfig         - Build for iop33x
  ixp2000_defconfig        - Build for ixp2000
  ixp23xx_defconfig        - Build for ixp23xx
  ixp4xx_defconfig         - Build for ixp4xx
  jornada720_defconfig     - Build for jornada720
  kafa_defconfig           - Build for kafa
  kb9202_defconfig         - Build for kb9202
  lart_defconfig           - Build for lart
  lpc22xx_defconfig        - Build for lpc22xx
  lpd270_defconfig         - Build for lpd270
  lpd7a400_defconfig       - Build for lpd7a400
  lpd7a404_defconfig       - Build for lpd7a404
  lubbock_defconfig        - Build for lubbock
  lusl7200_defconfig       - Build for lusl7200
  mainstone_defconfig      - Build for mainstone
  mx1ads_defconfig         - Build for mx1ads
  neponset_defconfig       - Build for neponset
  netwinder_defconfig      - Build for netwinder
  netx_defconfig           - Build for netx
  omap_h2_1610_defconfig   - Build for omap_h2_1610
  onearm_defconfig         - Build for onearm
  p2001_defconfig          - Build for p2001
  pleb_defconfig           - Build for pleb
  pnx4008_defconfig        - Build for pnx4008
  pxa255-idp_defconfig     - Build for pxa255-idp
  realview_defconfig       - Build for realview
  realview-smp_defconfig   - Build for realview-smp
  rpc_defconfig            - Build for rpc
  s3c2410_defconfig        - Build for s3c2410
  s3c24a0_mmu_defconfig    - Build for s3c24a0_mmu
  s3c24a0_nommu_defconfig  - Build for s3c24a0_nommu
  s3c3410_defconfig        - Build for s3c3410
  s3c44b0x_defconfig       - Build for s3c44b0x
  s5c7375_defconfig        - Build for s5c7375
  shannon_defconfig        - Build for shannon
  shark_defconfig          - Build for shark
  simpad_defconfig         - Build for simpad
  spitz_defconfig          - Build for spitz
  trizeps4_defconfig       - Build for trizeps4
  versatile_defconfig      - Build for versatile

  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
  make V=2   [targets] 2 => give reason for rebuild of target
  make O=dir [targets] Locate all output files in "dir", including .config
  make C=1   [targets] Check all c source with $CHECK (sparse by default)
  make C=2   [targets] Force check of all c source with $CHECK

Execute "make" or "make all" to build all targets marked with [*] 
For further info see the ./README file

Suporte a componentes de hardware customizados

Para adicionar suporte a novos componentes de hardware, é preciso escrever os códigos dos drivers destes dispositivos, além de editar os arquivos Kconfig e Makefile correspondentes. Isto permitiria configurar esta nova funcionalidade com um dos editores disponíveis (Kconfig) e também incluir os drivers no processo de compilação (Makelife). Por exemplo, para o suporte de novas funcionalidades em um sistema ARM IXP4xx, os arquivos Kconfig e Makefile editados seriam o do diretório …/arch/arm/machixp4xx/. O processo de adicionar suporte a uma nova funcionalidade de hardware para um sistema é relativamente simples, pois grande parte da complexidade é encapsulada de forma que a maioria dos desenvolvedores de novas plataformas não precisem se preocupar com todos os detalhes do processo de configuração e compilação do Kernel.

Documentação do Kernel

Uma grande quantidade de informação está disponível no próprio diretório fonte do Kernel, no subdiretório …/Documentation. São mais de 650 arquivos em 42 subdiretórios. É importante ter em mente que nem sempre a documentação reflete o último status do Kernel, pois provavelmente as últimas modificações feitas ainda não estão documentadas. A listagem abaixo mostra o conteúdo do diretório …/Documentation/kbuild, que possui informações sobre o processo de edição de arquivos Kconfig e configuração do Kernel:

uderman@udermanlp:~/uClinux/uClinux-dist/linux-2.6.x$ ls -l Documentation/kbuild/
total 76
-rw-rw-r-- 1 500 500   270 2003-09-30 23:20 00-INDEX
-rw-rw-r-- 1 500 500  9629 2006-11-29 20:28 kconfig-language.txt
-rw-rw-r-- 1 500 500 39845 2006-11-29 20:28 makefiles.txt
-rw-rw-r-- 1 500 500 18756 2006-11-29 20:28 modules.txt
uderman@udermanlp:~/uClinux/uClinux-dist/linux-2.6.x$

Outra boa fonte de informação é o projeto de documentação do Linux (Linux Documentation project). É possível encontrar neste endereço as versões mais atualizadas dos arquivos de documentação. No mais, é possível encontrar muitas outras fontes (blogs, wikis, lista de discussões, forums, websites, etc) em sites de busca na internet, como o google.

Como obter o Kernel do Linux

Existem basicamente três maneiras de se obter o Kernel do linux para uma determinada plataforma de hardware. Comprar uma distribuição comercial, baixar uma distribuição gratuita compatível com seu hardware (caso exista), ou baixar uma distribuição gratuita compatível com um hardware semelhante ao seu e realizar as modificações necessárias (porting). Esta última opção pode ser uma tarefa complicada, a depender do cenário em questão. Através do site Kernel.org é possível baixar a versão mais atual do Kernel do Linux, ou versões anteriores. O [www.uclinux.org uClinux] é um port do Linux com suporte a arquiteturas sem MMU (Memory Management Unit).

O que mais é necessário?

O kernel do linux é apenas um dos componentes necessários para desenvolvimento de sistemas baseados em Linux embarcado. Adicionalmente, estes outros componentes são necessários:

  • Bootloader portado e configurado para a plataforma de hardware
  • Cadeia de desenvolvimento cruzada (Cross-Compilling Toolchain)
  • Sistema de arquivos contendo pastas, arquivos binários executáveis e bibliotecas compilados para o sistema alvo
  • Drivers de dispositivos (Device Drivers) para os dispositivos customizados da plataforma de hardware

Referências

1. Hallinan, C. Embedded Linux Primer - A Practical Real-World Approach. Prentice Hall. ISBN: 0-13-167984-8.
2. tldp.org . Website do projeto TLDP.
3. kernel.org. Repositório do Kernel Linux.
4. uClinux.org. Site do uClinux.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License