Oficina
Seguir essa página em paralelo com o tutorial.
Dica: caso você tenha interesse em guardar as atividades realizadas em cada etapa desse processo
você pode realizar um commit a cada etapa do processo. Ao finalizar a oficina, você pode juntar todos
os commits em um patchset (seção 5.2 do tutorial 2)
e enviar para você mesme por e-mail. Só tenha a certeza de conferir que no --dry-run
você não
enviará para mais ninguém. Com isso, você poderá recuperar facilmente suas alterações utilizando:
git am <patch>
ou git apply <patch>
.
Linux kernel - um projeto modular
Agora vamos começar a modularizar o projeto Linux kernel. Primeiramente, vamos dividir o kernel em 3 espaços:
- syscall: chamadas de sistemas, são funções que servem para que aplicações do espaço de usuário se comuniquem com os drivers de dentro do kernel;
- core: serviços genéricos de um sistema operacional: escalonamento, gerenciamento de memórias;
- device drivers: módulos que representam como cada hardware (dispositivo) deverá ser configurado, lido e alterado.
Nessa oficina vamos entender melhor os device drivers (ou drivers de dispositivo).
Talvez você já escutou que 'tudo no kernel é um arquivo'. Mas o que isso significa?
Vamos considerar que cada hardware pode ser (pelo menos): aberto/iniciado
, fechado/finalizado
, lido
e modificado
.
Com isso fazemos essa analogia, de que com essas 4 funções conseguimos nos comunicar com a maioria de nossos hardwares.
Por exemplo:
- um arquivo:
- ao abrir (
init
): acessamos a memória em que ele está localizado; - ao ler (
read
): lemos o conteúdo que está escrito nele; - ao escrever (
write
): modificamos o conteúdo desse arquivo; - ao fechar (
exit
): apenas paramos de nos comunicar com ele.
- ao abrir (
- um driver de áudio:
init
: inicia o driver, começa a comunicação;read
: ler o conteúdo que pode ser, por exemplo: volume atual;write
: modificar, que pode ser o volume, pode ser o que deve reproduzir, etc;exit
: fechar a conexão, enquanto fechada a conexão nada será modificado ou enviado a esse driver
Como essas 4 funções são bem diretas para um arquivo de texto, fazemos essa simplificação para melhor compreender como o kernel trata cada hardware de uma máquina.
Para essa oficina criaremos um módulo que não é conectado a um hardware, apenas para compreendimento
do conceito de drivers de dispositivo
.
Construindo um driver de dispositivo simples
Primeiramente, as funções essenciais para um device são as funções de inicialização e de finalização. Como o kernel deve agir quando o módulo é inicializado e fechado. Para cada dispositivo essas funções serão mais simples ou mais complexas, dependerá das particularidades de cada dispositivo.
No nosso driver simples, essas funções apenas printarão mensagens no log do kernel. Intruções para esse driver estão na seção 2 do tutorial.
Também devemos incluir nesse módulo sua licensa (GPL). Além disso incluimos também o autor e descrição do módulo (essas últimas duas informações não são exigidas, porém fortemente aconselhadas).
As funções de inicialização e finalização são definidas por init_module
e cleanup_module
, porém
desde a versão 2.4 do Linux, usa-se macros para essas funções, essa opção pode ser encontrada no
tutorial.
Primeiramente criaremos esse módulo 'out-tree': fora da árvore do kernel. Isso significa que o
módulo pode ser criado fora da pasta linux, em qualquer lugar do seu computador e ser 'carregado'
na árvore através de funções básicas do linux insmod
e rmmod
.
Geralmente utilizado para testar novos módulos ou módulos temporários que não há o interesse de ser incluído no projeto, apenas será testado localmente.
Assim que decidido que deverá ser incluído em árvore: 'in-tree', devemos realizar algumas alterações
nos arquivos: Makefile
e Kconfig
da pasta parent
em que o módulo será incluído.
Lembre-se que a função make
e *config
fazem uma busca recorrente dentro das pastas a partir da
raiz em que a função foi chamada. Então precisamos informar a pasta imediatamente acima da pasta
incluída que seu Makefile
e Kconfig
devem ser considerados.
Aqui sinta-se convidade a olhar os Makefile
e Kconfig
de pastas diversas para tentar entender os
padrões de cada pasta.
Próximos passos
Na seção 3 do tutorial veremos mais implementações possíveis do módulo.
Primeiramente como passar um argumento pela linha de comando na inicialização de um módulo. No
tutorial é apresentado como fazê-lo com um int
, mas você pode conferir em:
https://tldp.org/LDP/lkmpg/2.6/html/x323.html para saber como utilizar parâmetros de outros tipos.
Na seção 3.2
estudaremos um módulo que implementa a função read
e write
. O código nesse exercício é entregue
pronto, mas você pode e deve dar uma olhada nas funções implementadas. Além disso, você pode testar
colocá-lo in-tree, seja em uma pasta nova, seja dentro de uma pasta já existente. Teste também se
um patch dessas alterações passa no chackpatch, se não, faça as alterações necessárias para fazer um
commit que respeite o coding style do Linux kernel.
Referências
Nessa oficina, nós vimos apenas um pequena parte da superficie do que são device drivers
. Você
pode encontrar mais sobre, em referências oficiais do Linux: https://lwn.net/Kernel/LDD3/.