Inúmeras pessoas não sabem como adicionar alterações de kernel dentro do build system OpenEmbedded/Yocto. Apesar de ser uma ótima ferramenta para gerar sua imagem, usar o build system para compilar e testar pequenas alterações de pacotes independentes, apesar de possível, pode se tornar muito confuso. Minha sugestão para alteração de kernel é compilar o mesmo isoladamente, testar todas as alterações realizadas e no final do projeto, adicionar estas alterações ao build system. Este artigo irá apresentar como adicionar suas próprias alterações de kernel no OpenEmbedded. Para ilustrar o processo, iremos adicionar suporte ao acelerômetro mma8653 da NXP (antiga Freescale) ao kernel 4.4.14 utilizado pelo computador em módulo Toradex Colibri VF61.

Procedimento

A primeira coisa a fazer é ter o OpenEmbedded e seus pré-requisitos instalados. Você pode seguir as seções prerequisites e installation deste artigo para tal.

Para encontrar a localização e o kernel sendo utilizado pelo target, você pode começar procurando as receitas de kernel utilizadas pelos diferentes targets suportados:

cd stuff
find . -wholename "*recipes-kernel/linux*.bb"

Dentre os resultados, aqueles nos quais estamos interessados ficam dentro do diretório meta-toradex/recipes-kernel/linux/. Ao olhar dentro deste diretório, vemos o resultado apresentado na figura 1:

Olhando dentro do diretório meta-toradex/recipes-kernel/linux/
Figura 1: Olhando dentro do diretório meta-toradex/recipes-kernel/linux/

Observe que há diversas versões de kernel. Para descobrir quais targets utilizam quais versões do kernel, execute o seguinte comando dentro do diretório. O resultado é mostrado na figura 2:

grep -nre "COMPATIBLE_MACHINE" *
openembedded_compatible_machine

Observe que alguns targets podem utilizar mais de uma receita de kernel. Para saber rapidamente qual receita está sendo usada pelo target com o qual você está trabalhando, vá ao diretório de build e execute o bitbake da sua receita responsável pelo kernel, no nosso caso linux-toradex. Observe com atenção enquanto o comando é executado e você verá qual receita está sendo utilizada, conforme ilustrado na figura 3 (você também pode procurar pela variável PREFERRED_PROVIDER_virtual/kernel na receita para a sua machine):

bitbake linux-toradex
Verificando a versão do kernel sendo utilizada pelo bitbake, para o target em questão
Figura 3: Verificando a versão do kernel sendo utilizada pelo bitbake, para o target em questão

Agora que nós sabemos qual receita está sendo usada, vamos abrir o seu arquivo e dar uma olhada. Abaixo está o conteúdo do arquivo stuff/meta-toradex/recipes-kernel/linux/linux-toradex_4.4.bb:

require recipes-kernel/linux/linux-imx.inc
require recipes-kernel/linux/linux-dtb.inc


SUMMARY = "Linux kernel for Toradex Colibri VFxx Computer on Modules"


SRC_URI = "git://git.toradex.com/linux-toradex.git;protocol=git;branch=${SRCBRANCH} \
                      file://defconfig"


KERNEL_MODULE_AUTOLOAD += "${@bb.utils.contains('COMBINED_FEATURES', 'usbgadget', ' libcomposite', '',d)}"


LOCALVERSION = "-v2.6b2"
SRCBRANCH = "toradex_vf_4.4"
SRCREV = "efe965a5dad66bd14219cdc9474ea75eda783456"
DEPENDS += "lzop-native bc-native"
COMPATIBLE_MACHINE = "(vf)"

Nós estamos interessados nas variáveis SRC_URI, SRCBRANCH e SRCREV. SRC_URI indica de onde o código-fonte do kernel deve ser buscado e qual o arquivo de configuração a ser utilizado. SRCBRANCH indica o branch do repositório git apontado pela variável SRC_URI. SRCREV aponta qual é o commit sendo usado para este branch.

Vamos clonar o mesmo branch para a nossa máquina de desenvolvimento (host) e em seguida verificar os últimos 5 commits realizados. O resultado é apresentado na figura 4:

git clone -b 2015.04-toradex git://git.toradex.com/u-boot-toradex.git
git log -5 --pretty=oneline
Últimos 5 commits do código-fonte do kernel
Figura 4: Últimos 5 commits do código-fonte do kernel

Você pode observar que o último commit (que começa com efe…) é o mesmo que aquele apontado pela variável SRCREV da receita. Isto confirma que nós temos o mesmo código-fonte que está sendo utilizado pelo OpenEmbedded.

Realizando mudanças e adicionando ao OpenEmbedded

Para o exemplo deste artigo, o driver para o acelerômetro mma8653 será habilitado, assim como o dispositivo adicionado à device tree do target. Para isto é preciso ter instalada uma toolchain que permita a compilação cruzada para a arquitetura do target – que no caso é ARM. É possível baixar e instalar diretamente a toolchain Linaro, ou alternativamente fazer uma build do OpenEmbedded e depois usar a toolchain gerada durante a build. Mais informações sobre como executar ambas as abordagens podem ser encontradas neste artigo. Em resumo, para instalar a toolchain diretamente:

cd
wget -c https://releases.linaro.org/components/toolchain/binaries/5.2-2015.11-2/arm-linux-gnueabihf/gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf.tar.xz
tar xvf gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf.tar.xz
ln -s gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf gcc-linaro

E depois de instalada, exportar as variáveis no terminal e carregar as configurações padrão do kernel para o target desejado, como ponto de partida. Note que isto deve ser feito toda vez que for aberto um novo terminal.

export ARCH=arm
export PATH=~/gcc-linaro/bin/:$PATH
export CROSS_COMPILE=arm-linux-gnueabihf-
make colibri_vf_defconfig

Copie a configuração atual para outro arquivo. Não pule este passo, pois vamos usar os arquivos de backup a seguir:

cp .config .config_old
cp arch/arm/configs/colibri_vf_defconfig arch/arm/configs/colibri_vf_mma8653

Configure o kernel e modifique seu código-fonte de acordo com as suas necessidades. Para habilitar o driver do acelerômetro, será usada a ferramenta menuconfig, conforme ilustrado no comando abaixo e na figura 5:

make menuconfig
Habilitando o driver do kernel para o acelerômetro mma8452Q (compatível com mma8653)
Figura 5: Habilitando o driver do kernel para o acelerômetro mma8452Q (compatível com mma8653)

Para verificar o que mudou entre o antes e depois, vamos comparar o arquivo de configuração com o backup que fizemos anteriormente. O resultado é apresentado na figura 6:

meld .config .config_old
Diferença entre antes e depois de habilitar o driver do mma8452
Figura 6: Diferença entre antes e depois de habilitar o driver do mma8452

Observe que a única mudança é que CONFIG_MMA8452 agora está setado. Vamos simplesmente adicionar esta linha para o backup do defconfig que fizemos anteriormente:

echo "CONFIG_MMA8452=y" >> arch/arm/configs/colibri_vf_mma8653

A device tree também precisa de algumas mudanças. Abra o arquivo arch/arm/boot/dts/vf-colibri-eval-v3.dtsi e modifique o nó &i2c0 (linha 127) conforme apresentado abaixo. Observe que o nó mma8453fc@1d é o que foi adicionada ao arquivo:

&i2c0 {
        status = "okay";


        /* TouchRevolution Fusion 7 and 10 multi-touch controller */
        touch: touchrevf0710a@10 {
                compatible = "touchrevolution,fusion-f0710a";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpiotouch>;
                reg = <0x10>;
                gpios = <&gpio0 30 GPIO_ACTIVE_HIGH /* SO-DIMM 28, Pen down interrupt */
                                &gpio0 23 GPIO_ACTIVE_LOW /* SO-DIMM 30, Reset interrupt */
                                >;
                status = "disabled";
        };


        /* M41T0M6 real time clock on carrier board */
        rtc: m41t0m6@68 {
                compatible = "st,m41t00";
                reg = <0x68>;
        };


        mma8453fc@1d {
                compatible = "fsl,mma8653";
                reg = <0x1d>;
                pinctrl-0 = <&pinctrl_gpiokeys>;
                interrupt-parent = <&gpio1>;
                interrupts = <9 0>;
        };


};

Também modifique a porção de código abaixo. Ela está no nó &iomuxc, no final do arquivo. Observe que o valor hexadecimal foi modificado de 0x218d para 0x22ed:

pinctrl_gpiokeys: gpiokeys {
                        fsl,pins = <
                                VF610_PAD_PTB19__GPIO_41        0x22ed
                        >;
                };

Faça o commit das suas mudanças e crie um patch a partir deles:

git commit –m "mma8653 accelerometer"
git format-patch --signoff HEAD~1

Se você fez múltiplos commits, crie múltiplos arquivos mudando o número 1 acima conforme o número de commits que você fez.

Para adicionar as mudanças ao OpenEmbedded, copie o patch e o arquivo defconfig modificado para o diretório que corresponde à sua receita:

cp 0001-mma8653-accelerometer.patch /home/prjs/oe-core/stuff/meta-toradex/recipes-kernel/linux/linux-toradex-4.4/


cp arch/arm/configs/colibri_vf_mma8653 /home/prjs/oe-core/stuff/meta-toradex/recipes-kernel/linux/linux-toradex-4.4/defconfig

Edite a receita para aplicar o patch, adicionando seu arquivo à variável SRC_URI:

SRC_URI = "git://git.toradex.com/linux-toradex.git;protocol=git;branch=${SRCBRANCH} \
                      File://0001-mma8653-accelerometer.patch \
                      file://defconfig"

Por fim, compile o kernel:

bitbake -c clean linux-toradex
bitbake linux-toradex

A imagem do kernel e a device tree estarão no diretório out-glibc/deploy/images/colibri-vf/, conforme ilustrado pela figura 7. Você pode aplicar ambos ao target seguindo a seção kernel update deste artigo.

Imagem do kernel, módulos compilados e device tree
Figura 7: Imagem do kernel, módulos compilados e device tree

Conclusão

Conforme comentado na introdução, compilar o kernel dentro do build system é possível, mas um pouco confuso. Existem comandos que permitem fazer isso, porém é preciso conhecer muito bem OpenEmbedded/Yocto para ter certeza do que realmente está sendo feito.

A ideia deste artigo é mostrar que é possível isolar os problemas compilando e personalizando o kernel fora do build system. Espero que este artigo tenha sido útil e até a próxima!