Adaptação e Compilação do Kernel Linux 5.2 em Hardware S3C2440

Introdução à Portabilidade do Bootloader

A configuração do ambiente de inicialização é fundamental para o funcionamento do sistema embarcado. Após estabelecer a rotina de arranque via bootloader, o próximo passo envolve ajustar este software para suportar uma versão específica do núcleo, neste caso o Linux 5.2.8. A portabilidade de kernel consiste na modificação dos trechos de código que são específicos da arquitetura de hardware, visando compatibilizar o sistema operativo com as características físicas da placa.

No ecossistema Linux, os códigos sensíveis ao hardware residem principalmente nas pastas arch (onde estão definidos os arquiteturas e configurações de placas específicas) e drivers (contendo os controladores de dispositivos). Dependendo da posição na cadeia de produção, as responsabilidades variam:

  • Fabricantes de Núcleos (IP Core): Responsáveis por fornecer as instruções base e os blocos lógicos do processador, desenvolvendo as rotinas assembly iniciais de inicialização.
  • Fabricantes de SOC: Ao integrar núcleos de CPU com periféricos, estes fabricantes criam placas de desenvolvimento genéricas. O trabalho deles envolve fornecer drivers de periféricos integrados (on-board) e códigos de suporte de placa (BSP).
  • Fabricantes de Periféricos: Fornecem os drivers necessários para sensores ou controladores externos (como conversores ADC), facilitando a integração pelo cliente final.
  • Fabricantes de Produtos Finais: Geralmente utilizam o código de suporte fornecido pelos fabricantes de SOC, adaptando apenas a definição de dispositivo (device tree) para seus circuitos impressos personalizados.

Configuração Avançada do U-Boot

Para garantir a compatibilidade com a nova versão do kernel, copia-se o diretório do bootlaoder antigo para um novo ambiente de trabalho. Alterações estruturais devem ser aplicadas nos arquivos de cabeçalho de configuração e lógica de controle.

Definição de Parâmetros de Inicialização

O arquivo smdk2440.h, locailzado em include/configs/, deve conter os argumentos de inicialização (bootargs). Estes parâmetros informam ao kernel onde encontrar o sistema de arquivos raiz e qual processo iniciar:


#define CONFIG_BOOTARGS "root=/dev/mtdblock3 console=ttySAC0,115200 init=/linuxrc"

Nesta definição:
- root: Define o bloco de memória correspondente ao sistema de arquivos raiz (NAND partição 3).
- init: Especifica o binário de iniciação.
- console: Redireciona a saída padrão para a porta serial 0 (UART).

Habilitação do Suporte a Sistemas YAFFS2

Versões antigas do U-Boot frequentemente incluíam suporte nativo a sistemas de arquivos YAFFS, mas versões mais recentes podem necessitar de implementação manual no comando de gravação da NAND. Dentro da rotina do_nand no arquivo cmd/nand.c, adiciona-se tratamento específico para sufixos ".yaffs2":


#ifdef CONFIG_CMD_NAND_YAFFS
} else if (!strcmp(s, ".yaffs2")) {
    if (read) {
        printf("Comando 'nand' desconhecido: %s\n", s);
        return 1;
    }
    // Lógica de escrita preservando a área OOB (Out-of-Band)
    ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, 
                              (u_char *)addr, WITH_YAFFS_OOB);
#endif

Além disso, registros auxiliares na array nand_help_text devem ser atualizados para documentar o novo comando nand write.yaffs2. No driver principal de utilitários NAND (drivers/mtd/nand/nand_util.c), a função nand_write_skip_bad precisa identificar se o flag WITH_YAFFS_OOB está ativo para calcular corretamente o tamanho do bloco baseado na página e dados fora da página (OOB):


if (flags & WITH_YAFFS_OOB) {
    if (flags & ~WITH_YAFFS_OOB) return -EINVAL;
    int pages = nand->erasesize / nand->writesize;
    blocksize = (pages * nand->oobsize) + nand->erasesize;
    // Validação de alinhamento de página
    if (*length % (nand->writesize + nand->oobsize)) {
        printf("Erro: Tentativa de escrever página incompleta em modo YAFFS\n");
        return -EINVAL;
    }
}
// ... restante do fluxo de escrita ...

Por fim, o macro WITH_YAFFS_OOB deve ser declarado em include/nand.h e a opção CONFIG_CMD_NAND_YAFFS ativada no arquivo de configuração da placa.

Definição da Máquina (Machine ID)

Para que o kernel identifique corretamente a placa durante a carga de imagens, o U-Boot deve passar o número de identificação correto através do registro r1. No código de inicialização da placa (board_init em board/samsung/smdk2440/smdk2440.c), alteramos o valor para o identificador correto da SMDK2440, garantindo consistência entre o bootloader e o kernel.

Solução de Problemas na Leitura NAND

Erros como "Failed -74" durante a leitura indicam falhas de校验 (verificação de integridade) ECD (Error Correction Code). Este erro decorre frequentemente de uma incompatibilidade entre a configuração de ECC do hardware e o driver utilizado pelo bootloader.

Análise do Erro ECC

O retorno negativo -74 corresponde à constante -EBADMSG, indicando que a correção de erros falhou repetidamente após tentativas de recuperação (retry). A causa raiz está na função nand_do_read_ops dentro de drivers/mtd/nand/nand_base.c, onde a lógica verifica falhas de ECC acumuladas. Se o contador exceder o limite permitido, a flag ecc_fail é setada true.

Desabilitação de ECC para Desenvolvimento

Em casos onde a qualidade da mídia não permite correção robusta, ou durante fases de teste, pode-se desabilitar a verificação de ECC no driver da placa. Isso envolve modificar a estrutura de inicialização da NAND (board_nand_init) para usar o modo NAND_ECC_NONE:


// Comentar linha habilitadora de ECC Soft
// nand->ecc.mode = NAND_ECC_SOFT; 
// A configuração herdará o valor padrão NONE

Com o modo definido como NONE, a função nand_read_page_raw será chamada, ignorando cálculos de checksum e permitindo leitura direta dos dados brutos, eliminando o erro de boot pendular (stuck) causados por falsos positivos de bad block.

Preparação e Compilação do Kernel

O processo de obtenção dos fontes do núcleo Linux envolve download de repositórios confiáveis. É crucial verificar versões antigas (como 5.2.x) pois versões muito recentes podem ter removido suporte a plataformas ARM legadas.

Estrutura de Projetos

Diretórios principais incluem:

  • arch/arm: Código específico da arquitetura ARM.
  • drivers/mtd: Controladores de armazenamento (MTD).
  • init: Roteiros de inicialização do sistema (start_kernel).

Configuração do Makefile

No nível raiz, o arquivo Makefile define o alvo da arquitetura compilada. Deve-se configurar explicitamente o compilador de cruzamento:


ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabi-

Geração de Configuração (Defconfig)

A ferramenta make menuconfig facilita a seleção de recursos. Para esta plataforma, utiliza-se uma configuração base próxima, como a s3c2410_defconfig, já que a arquitetura é semelhante. Opções críticas incluem habilitar suporte ao filesystem de memória e definir a máquina correta.

Patch no Código do Kernel

São necessárias edições manuais para sincronizar perfeitamente com o hardware específico da placa Mini2440:

  1. Cronometrista (Clock): Definir a frequência correta do cristal (ex: 12MHz) no arquivo mach-smdk2440.c.
  2. Partições NAND: Em common-smdk.c, redifinir a tabela de partições (smdk_default_nand_part) para refletir o uso real da memória Flash (U-Boot, Parametros, Kernel, RootFS).
  3. Mach-ID: O identificador da máquina no arquivo mach-types deve corresponder ao valor informado pelo U-Boot. Verificar o valor hexadecimal no terminal U-Boot usando bdinfo.

Instalação do Ambiente de Compilação

Compiladores modernos do GNU Toolchain podem apresentar incompatibilidades com kernels antigos se não configurados corretamente. A escolha da versão da ferramenta (arm-none-linux-gnueabi-gcc) depende da arquitetura alvo (EABI vs ABI clássico).

O caminho ideal é instalar ferramentas de compilação como u-boot-tools para gerar a imagem do kernel (mkimage) e configurar linkes simbólicos para manter a compatibilidade com nomes antigos de comandos de compilação (ex: gcc, ld).

Testes de Boot e Transferência

Após a compilação gerada a imagem uImage, o processo de carregamento pode ocorrer via rede (TFTP) ou programação direta da Flash.

O U-Boot deve receber os argumentos de inicialização e apontar para o endereço de memória correto onde a imagem reside. Exemplo de sequência de comandos via TFTP:


tftp 30000000 uImage
nand erase.part kernel
nand write 30000000 kernel
bootm 30000000

Análise de Logs de Boot

Em caso de falha ao iniciar o kernel, observam-se mensagens claras sobre IDs de máquina divergentes ou erros de E/S no disco. Um erro comum é "unrecognized machine ID", o que indica que o U-Boot passou um valor numérico diferente daquele esperado pelo Kernel.

Sistemas de arquivos montados como "yaffs" ou "jffs2" confirmam sucesso parcial na inicialização. O término ideal seria a mensagem "Starting kernel..." seguida pelas linhas de inicialização de drivers. Erros no sistema de arquivos raiz (VFS) geralmente indicam que o particionamento ou a própria imagem do rootfs não corresponde aos argumentos bootargs passados.

Limpando Bad Blocks Virtuais

Fenômenos onde muitos blocos aparecem como defeituosos logo após a limpeza podem indicar marcas de firmware residual. O comando nand scrub.chip realiza uma limpeza profunda, removendo essas marcações falsas.

Otimização do Kernel

Imagens de kernel podem ser excessivamente grandes dependendo das configurações padrão. Utilizando o make menuconfig novamente, é possível remover drivers de periféricos não utilizados e sistemas de arquivos obsoletos no projeto específico (ex: remover suporte a EXT3 ou ISO9660 se não houver CD-ROM no hardware). Essa redução diminui o consumo de RAM e acelera o tempo de boot.

Tags: Embedded-Linux ARM-S3C2440 U-Boot NAND-Flash Kernel-Compiling

Publicado em 9-18 02:28