Módulo de kernel Linux com compilação cruzada: um guia prático
Bem -vindo ao meu primeiro dev.to post! Hoje, estamos mergulhando no mundo prático dos módulos de kernel Linux, uma habilidade essencial para o desenvolvimento de sistemas incorporados. Esteja você trabalhando com Raspberry Pi, placas de braço personalizadas ou ambientes virtualizados, entender esse processo é crucial. Antes de sujarmos as mãos com o código, vamos esclarecer alguns conceitos fundamentais. Se você trabalhou com o IDES, provavelmente compilou o código com um botão, pressione sem ver o processo subjacente. Os usuários do Linux podem estar mais familiarizados com ferramentas de linha de comando, como o GCC ou o Make. O processo de compilação consiste em transformar o código-fonte legível pelo homem em binários executáveis por máquina através de quatro estágios principais: pré-processamento: expande macros e alças inclui compilação: uma ferramenta chamada compilador pega a saída do pré-processador e o converte em linguagem de montagem. Assembléia: se traduz em código da máquina (arquivos de objeto) Linking: combina todo o código do objeto em binários executáveis Entendendo estratégias de compilação 1. Definição de compilação nativa: Consiste em compilar software na mesma arquitetura e sistema em que ele será executado. 2. Definição de compilação cruzada: Consiste em compilar o software em uma arquitetura diferente daquela em que será executada, usando uma cadeia de ferramentas de compilação cruzada. Portanto, a saída binária final será executada em diferentes máquina de destino. Por que compilação cruzada? Precisamos de compilação cruzada, pois não podemos compilar diretamente o próprio alvo devido a Ressources limitados e o próprio processo de compilação precisa de grandes resíduos. A cadeia de ferramentas de compilação cruzada Uma cadeia de ferramentas inclui compiladores, ligantes e bibliotecas necessários para a criação de software. Para o desenvolvimento do ARM64, usamos o AARCH64-Linux-Gnu Toolchain: Compilador: Binutils AARCH64-Linux-Gnu-GCC: AARCH64-Linux-Gnu-LD, AARCH64-LINUX-GNU-OBJCOPY … Bibliotecas: Arm64 Librtaries This Toolchain RunS runs on X8. Pronto para começar? vamos! 1. Configuração do ambiente Vamos começar configurando nosso ambiente de desenvolvimento. Primeiro, temos que garantir que tenhamos todas as ferramentas necessárias: sudo apt install -y \ qemu-system-arm \ gcc-aarch64-linux-gnu \ edifício-essencial \ libncurses fullcurSes-dev \ bison \ flex \ libbl-dev \ libelf-dev \ cpio \ cpio \ km \ km systems \ full \ kms \ km symemsl \ km symSSENSCENSEMSCENSESTEN \ KMOM \ KM \ KM \ LIBSSl-DEV \ LIBFL-DEV \ CPIO \ CPIO Ubuntu 22.04. Depois disso, precisamos fazer o download do projeto Github que contém a fonte de código do módulo Linux Kernel (hello_module.c + makelfile): clone Git Digite o modo de tela cheia de tela cheia Nota: É um repo do github onde coloco todo o código -fonte deste tutorial. 2. Download e preparação da fonte do kernel # download do kernel Linux 6.6 WGet Tar XF Linux-6.6.tar.xz CD Linux-6.6 Digite o modo de tela cheia de tela cheia: Exportar Modo de Modo FullScreen 3. Configuração e construção de configurações com configurações padrão: faça o DefConfig entrar no modo de saída de tela cheia de tela cheia, cria um arquivo de configuração padrão (.config) para nossa arquitetura de destino. Opcional: podemos personalizar as opções do kernel e este comando abre uma interface de menu baseada em texto para personalizar as opções do kernel: faça o Menuconfig entrar no modo de tela cheia de saída de tela cheia como navegar: as teclas de seta: movimentação entre as opções ENTER: SELECTIFIGET /Submenu y: Ativar opção n: desabilitar a opção: compilar como módulo /: hounshignel sliplature verification verification verification Qemu. Podemos verificar se algumas opções críticas estão ativadas: grep -e “config_serial_amba_pl011 | config_blk_dev_initrd | config_modules | config_devtmpfs | config_proc_fs | config_sysfs”. Config_sysfs_sysCall = y config_modules_use_elf_rela = y config_modules = y config_modules_tree_lookup = y config_devtmpfs = y config_devtmpfs_mount = y # config_devtmpmfsfsfsf. Config_serial_amba_pl011_console = y config_proc_fs = y config_sysfs = y Digite o modo de tela cheia Sair do modo de tela cheia de criação de kernel make -j $ (nProc) Modo de tela full) imagem make -j $ (nproc) modules Enter Archrot/tela de tela cheia) Imagem executável de inicialização do kernel ARM64. Este rootfs fornece o ambiente em que os processos do usuário são iniciados e os serviços do sistema começam. Para o nosso ambiente incorporado, criaremos um Rootfs mínimo usando o BusyBox, que empacota vários utilitários essenciais do Unix em um único binário compacto. Essa abordagem simplifica drasticamente nossa construção, criando um sistema estaticamente vinculado, eliminando a necessidade de dependências dinâmicas de vinculação ou biblioteca compartilhada. CD .. WGET TAR XF BUSYCHINGBOX-1.36.0.TAR.BZ2 CD BUSINCINGBOOKBOX-1.36.0 # Configure para vinculação estática Faça o Defconfig fazer com que o MENUCONFIG MENUCONFIG ENTIR MODO DE ESCRAÇÃO COMPLETA FILLEUT MODO FULLING Cross-Green Cross-Cross- Cross-ComCile → Build Binary (sem Libs-Libs-Libra-Libra-Libra-LOBSIM-Cross-Crossk Verifique o ARM64 Binário: Arquivo _install/Bin/BusyBox Digite Modo de tela cheia Modo de tela cheia 5. ROOT CDROTHSTRUÇÃO DE FERROS. MKNOD rootfs/dev/console c 5 1 sudo mknod rootfs/dev/null c 1 3 Digite o modo de saída de tela cheia de tela cheia. Existem várias maneiras de inicializar em um kernel Linux. O initramfs é comumente usado nas distribuições modernas do Linux. É um arquivo incorporado no kernel ou adjacente ao kernel. Ele é carregado completamente na memória volátil e seu objetivo é iniciar dispositivos e unidades de hardware necessários para o sistema. No nosso caso, vamos simplesmente usar o initramfs como um método para inicializar nosso sistema em um estado volátil. Dessa forma, todas as alterações que fizemos no ambiente serão limpadas na reinicialização 6. A criação de scripts init para o kernel passar o controle para o espaço dos usuários, ele tenta executar um processo init como o primeiro processo. Portanto, criaremos nosso próprio script de shell para ser executado como o primeiro processo. Criar Rootfs/Init Script: CD Rootfs Cat> Init< ‘EOF’
#!/bin/sh
# Mount essential filesystems
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
# Set up environment
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export SHELL=/bin/sh
echo “Minimal Linux environment ready”
exec /bin/sh
EOF
# Setup the script to be executable
chmod +x init
cd ..
Enter fullscreen mode
Exit fullscreen mode
7. Module Compilation and Integration
# Cross-compile the module
make KDIR=linux-6.6 cross-compile
# Verify ARM64 module
file hello_module.ko
# Add to rootfs and rebuild initramfs
cp hello_module.ko rootfs/
cd rootfs
find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz cd .. Enter fullscreen mode Exit fullscreen mode 8. QEMU Testing and Validation Now we can test our fully emulated system to see if it boots: qemu-system-aarch64 \ -M virt \ -cpu cortex-a53 \ -smp 2 \ -m 1G \ -kernel linux-6.6/arch/arm64/boot/Image \ -initrd initramfs.cpio.gz \ -append “console=ttyAMA0 earlycon=pl011,0x9000000 init=/init” \ -nographic \ -no-reboot Enter fullscreen mode Exit fullscreen mode This QEMU command launches a 64-bit ARM virtual machine using the generic virt board, emulating a Cortex-A53 CPU with 2 cores and 1 GB of RAM. Ele inicializa um kernel Linux 6.6 com um initramfs como o sistema de arquivos raiz, passa os parâmetros do kernel para usar o PL011 UART (TTYAMA0) para saída do console e inicia /init como o primeiro processo do usuário. A opção -nográfica direciona toda a entrada/saída para o terminal em vez de uma janela gráfica, e -no -reboot garante que o Qemu saia em vez de reiniciar o desligamento ou falha. 9. Runtime Teste do módulo # Carga e módulo de teste Insmod hello_module.ko dmesg | cauda -3 rmmod hello_module dmesg | Tail -3 Digite o modo de saída do modo de tela cheia, afinal, o modo de tela inteira, consulte o Linux incorporado, não é tão assustador! so what we have achieved today : Cross-compiled a Linux kernel for ARM64 Built a minimal root filesystem with BusyBox Created a working initramfs Wrote and cross-compiled a kernel module Booted a virtual ARM64 machine with QEMU Loaded and tested our custom kernel module 🌟 Remember All you have to do is start learning and implementing things you thought were hard or complex.🌟 And stay tuned for my next post! Ressources adicionais: Documentação do kernel LinuxBusyBox Documentação Official QURMU Sistema de braço EmulaçãoBuilding Módulos externos Guidethe Linux Kernel Module Programação do Módulo GCC Compilador cruzado
Fonte