Mudanças entre as edições de "LKMPG"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
(Criou página com 'Uma rápida compilação de materiais sobre o [http://www.kernel.org/ kernel Linux] e seus device drivers. = Tutoriais sobre programação de módulos do kernel = * [http://der...')
 
Linha 23: Linha 23:
 
== Etapa 2 ==
 
== Etapa 2 ==
  
Nesse novo exercício, o dispositivo virtual guarda os dados nele escritos, e possibilita que sejam lidos por processos que o abram e façam chamadas ''read''. Note o seguinte:
+
Nesse novo exercício, o dispositivo virtual da etapa 1 guarda os dados nele escritos, e possibilita que sejam lidos por processos que o abram e façam chamadas ''read''. Note o seguinte:
  
 
# A capacidade de armazenamento do dispositivo deve ser limitada .... se ele ficar cheio, uma nova tentativa de escrita deve falhar com algum código de erro (ex: EAGAIN).
 
# A capacidade de armazenamento do dispositivo deve ser limitada .... se ele ficar cheio, uma nova tentativa de escrita deve falhar com algum código de erro (ex: EAGAIN).
Linha 36: Linha 36:
 
== Etapa 3 ==
 
== Etapa 3 ==
  
Quando concluir esse segundo exercício, modifique-o para que:
+
Nesta nova versão, o dispositivo feito na etapa 2 deve ter estas extensões:
 
 
 
# Se uma escrita for realizada e a memória estiver cheia, então o processo que tentou a escrita deve ser bloqueado. Quando houver espaço na memória, o processo deve ser desbloqueado para terminar a operação de escrita.
 
# Se uma escrita for realizada e a memória estiver cheia, então o processo que tentou a escrita deve ser bloqueado. Quando houver espaço na memória, o processo deve ser desbloqueado para terminar a operação de escrita.
 
# Mesma coisa quando se tentar ler e a memória do dispositivo estiver vazia
 
# Mesma coisa quando se tentar ler e a memória do dispositivo estiver vazia
Linha 59: Linha 58:
 
'''Dica''': usar ''kfifo'' seria uma boa. No livro ''Linux Kernel Development'' tem uma seção que explica como funciona kfifo, e como se pode usá-la - ver Queues no capítulo 6.
 
'''Dica''': usar ''kfifo'' seria uma boa. No livro ''Linux Kernel Development'' tem uma seção que explica como funciona kfifo, e como se pode usá-la - ver Queues no capítulo 6.
  
A próxima capacidade do driver que pedi é que seja capaz de bloquear
+
== Etapa 4 ==
um processo que tente ler o dispositivo, mas não existam dados para
 
ler. E o mesmo deve ocorrer se um processo tentar escrever no
 
dispositivo, mas ele estiver cheio. Lembrem que a ideia é que o
 
dispositivo represente um named pipe, o que implica haver uma fila.
 
  
Este tutorial explica de forma bastante clara como fazer com que
+
A próxima capacidade do driver é torná-lo capaz de bloquear um processo que tente ler o dispositivo, mas não existam dados para ler. E o mesmo deve ocorrer se um processo tentar escrever no dispositivo, mas ele estiver cheio. Lembre que a ideia é que o dispositivo represente um [https://en.wikipedia.org/wiki/Named_pipe named pipe], o que implica haver uma fila.
processos esperem por alguma condição dentro de um driver:
+
 
 +
Este tutorial explica de forma bastante clara como fazer com que processos esperem por alguma condição dentro de um driver:
  
 
https://sysplay.in/blog/linux-kernel-internals/2015/10/waiting-blocking-in-linux-driver/
 
https://sysplay.in/blog/linux-kernel-internals/2015/10/waiting-blocking-in-linux-driver/
  
Caros, o próximo passo envolve entender a temporização de tarefas
+
== Etapa 5 ==
dentro do kernel. O kernel fornece facilidades para medição de tmpo
 
decorrido (jiffies), espera ocupada ou bloqueada (timeout), execução
 
de uma ação em momento específico (timer), e execução de ação em
 
momento oportuno (tasklet e workqueue). Cada mecanismo tem sua
 
aplicação e suas limitações, como se pode ler no capítulo 7 do livro
 
Linux Device Drivers:
 
 
 
https://www.oreilly.com/library/view/linux-device-drivers/0596005903/ch07.html
 
  
 +
O próximo passo envolve entender a temporização de tarefas dentro do kernel. O kernel fornece facilidades para medição de tempo decorrido (jiffies), espera ocupada ou bloqueada (timeout), execução de uma ação em momento específico (timer), e execução de ação em momento oportuno (tasklet e workqueue). Cada mecanismo tem sua aplicação e suas limitações, como se pode ler no [ttps://www.oreilly.com/library/view/linux-device-drivers/0596005903/ch07.html capítulo 7 do livro ''Linux Device Drivers'']:
  
A próxima tarefa envolve modificar o seu device driver para que as
+
Entendo-se os mecanismos de temporização, a próxima tarefa envolve modificar o seu device driver para que as informações gravadas na fila tenham um certo tempo de vida ... Cada conjunto de bytes gravados na fila deve lá permanecer por, no máximo, algum tempo predefinido (ex: 5 segundos). Se esse tempo passar e aqueles bytes ainda estiverem na fila, eles devem ser retirados e descartados. Notem que o controle de tempo decorrido deve ser feito
informações gravadas na fila tenham um certo tempo de vida ... Cada
+
com base no instante em que os dados entraram na fila: se um processo gravar 4 bytes no dispositivo no instante 0, depois 7 bytes no instante 2, e finalmente 3 bytes no instante 4, os primeiros 4 bytes devem ser descartados no instante 5, os 7 bytes no instante 7, e os 2 bytes finais no instante 9 (caso não tenham sido lidos do dispositivo).
conjunto de bytes gravados na fila deve lá permanecer por, no máximo,
 
algum tempo predefinido (ex: 5 segundos). Se esse tempo passar e
 
aqueles bytes ainda estiverem na fila, eles devem ser retirados e
 
descartados. Notem que o controle de tempo decorrido deve ser feito
 
com base no instante em que os dados entraram na fila: se um processo
 
gravar 4 bytes no dispositivo no instante 0, depois 7 bytes no
 
instante 2, e finalmente 3 bytes no instante 4, os primeiros 4 bytes
 
devem ser descartados no instante 5, os 7 bytes no instante 7, e os 2
 
bytes finais no instante 9 (caso não tenham sido lidos do
 
dispositivo).
 

Edição das 13h57min de 19 de dezembro de 2019

Uma rápida compilação de materiais sobre o kernel Linux e seus device drivers.

Tutoriais sobre programação de módulos do kernel

Introdução

Para começarem a entender como desenvolver módulos e drivers para o kernel Linux, podem se basear neste livro:

Ele não é recente, e se baseia no kernel 2.6.x, mas muito do que ali está ainda é válido.

Vocês podem iniciar o estudo usando o próprio kernel do sistema operacional que está em seus laptops. Se for Ubuntu ou Debian, instalem o pacote linux-headers para poderem criarem seus módulos.

Etapa 1

Como primeiro módulo, experimentem criar um módulo que implemente um device driver para dispositivo orientado a caractere (ex: serial), que é o tipo mais simples de driver. Os livros inclusive usam como primeiro exemplo um driver desse tipo.

  • Arquivo:Lkm.zip: exemplo de módulo apresentado nas partes 1 e 2 do livro Linux Device Drivers.

Etapa 2

Nesse novo exercício, o dispositivo virtual da etapa 1 guarda os dados nele escritos, e possibilita que sejam lidos por processos que o abram e façam chamadas read. Note o seguinte:

  1. A capacidade de armazenamento do dispositivo deve ser limitada .... se ele ficar cheio, uma nova tentativa de escrita deve falhar com algum código de erro (ex: EAGAIN).
  2. Quando um processo lê do dispositivo, a quantidade de bytes lidos deve ser retirada da memória.
  3. Cada novo read deve iniciar a partir da posição onde o read anterior terminou
  4. Se não houver dados para ler, read deve falhar com algum erro (ex: EAGAIN)

Note que, pela descrição acima, a memória do dispositivo deve funcionar como uma fila circular.

OBS: Códigos de erro estão em /usr/include/asm-generic/errno-base.h

Etapa 3

Nesta nova versão, o dispositivo feito na etapa 2 deve ter estas extensões:

  1. Se uma escrita for realizada e a memória estiver cheia, então o processo que tentou a escrita deve ser bloqueado. Quando houver espaço na memória, o processo deve ser desbloqueado para terminar a operação de escrita.
  2. Mesma coisa quando se tentar ler e a memória do dispositivo estiver vazia


A cópia de valores entre buffers do driver e do processo que o acessa deve levar em conta que:

  • o buffer do driver está em espaço de kernel, que usa endereçamento real
  • o buffer do processo está em espaço de usuário, que usa endereçamento virtual

Por isso a cópia não pode ser feita diretamente com memcpy, strncpy, ou funções similares. A cópia precisa ser feita com funções da API do kernel, as quais traduzem os endereços virtuais do processo para reais (para isso elas usam a tabela de páginas do processo em questão). As funções são:


Existem outras, que podem ser vistas nestas documentações:

Dica: usar kfifo seria uma boa. No livro Linux Kernel Development tem uma seção que explica como funciona kfifo, e como se pode usá-la - ver Queues no capítulo 6.

Etapa 4

A próxima capacidade do driver é torná-lo capaz de bloquear um processo que tente ler o dispositivo, mas não existam dados para ler. E o mesmo deve ocorrer se um processo tentar escrever no dispositivo, mas ele estiver cheio. Lembre que a ideia é que o dispositivo represente um named pipe, o que implica haver uma fila.

Este tutorial explica de forma bastante clara como fazer com que processos esperem por alguma condição dentro de um driver:

https://sysplay.in/blog/linux-kernel-internals/2015/10/waiting-blocking-in-linux-driver/

Etapa 5

O próximo passo envolve entender a temporização de tarefas dentro do kernel. O kernel fornece facilidades para medição de tempo decorrido (jiffies), espera ocupada ou bloqueada (timeout), execução de uma ação em momento específico (timer), e execução de ação em momento oportuno (tasklet e workqueue). Cada mecanismo tem sua aplicação e suas limitações, como se pode ler no [ttps://www.oreilly.com/library/view/linux-device-drivers/0596005903/ch07.html capítulo 7 do livro Linux Device Drivers]:

Entendo-se os mecanismos de temporização, a próxima tarefa envolve modificar o seu device driver para que as informações gravadas na fila tenham um certo tempo de vida ... Cada conjunto de bytes gravados na fila deve lá permanecer por, no máximo, algum tempo predefinido (ex: 5 segundos). Se esse tempo passar e aqueles bytes ainda estiverem na fila, eles devem ser retirados e descartados. Notem que o controle de tempo decorrido deve ser feito com base no instante em que os dados entraram na fila: se um processo gravar 4 bytes no dispositivo no instante 0, depois 7 bytes no instante 2, e finalmente 3 bytes no instante 4, os primeiros 4 bytes devem ser descartados no instante 5, os 7 bytes no instante 7, e os 2 bytes finais no instante 9 (caso não tenham sido lidos do dispositivo).