Instituto de Computação - UNICAMP

MC504 - Sistemas Operacionais

Implementação de um driver com caracteres

Islene Calciolari Garcia

Após implementar um null driver seguindo os exemplos disponibilizados na série Linux Device Drivers do site Open Source forU, vamos implementar um driver de caracteres com caracteres.

No arquivo newdrivers.tar.xz você encontrará os arquivos referentes aos drivers deste experimento. No arquivo apps.tar.xz você encontrará um diretório com arquivos de teste para os drivers. Para cada arquivo .c há um executável gerado para arquitetura 386. Caso queira gerar novo executável utilize o site ccplusplus.

Objetivos

Primeira tentativa com crash

Na parte 6 da série, Shweta tenta armazenar o último caractere da seguinte maneira:
static char c;

static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
    printk(KERN_INFO "Driver: read()\n");
    buf[0] = c;
    return 1;
}
static ssize_t my_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
    printk(KERN_INFO "Driver: write()\n");
    c = buf[len - 1];
    return len;
}
Esta abordagem está codificada no arquivo ofcd-lastchar-bug.c. Você pode testar com as aplicações teste-lastchar e teste-lastchar-invalid-buffer.

ofcd-lastchar: copy_to_user e copy_from_user

Ainda na parte 6 da série, Shweta descobre as funções copy_to_user e copy_from_user.
static char c;

static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
    printk(KERN_INFO "Driver: read()\n");
    if (copy_to_user(buf, &c, 1) != 0)
        return -EFAULT;
    else
        return 1;
}
static ssize_t my_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
    printk(KERN_INFO "Driver: write()\n");
    if (copy_from_user(&c, buf + len - 1, 1) != 0)
        return -EFAULT;
    else
        return len;
}

Refaça os testes teste-lastchar e teste-lastchar-invalid-buffer com o driver ofcd-lastchar.

Se você procurar a documentação sobre copy_to_user e copy_from_user verá que estas funções podem dormir. Por quê?

Sugestão: tente implementar uma versão deste driver que armazene a última escrita com kmalloc e kfree.

ioctl

Na parte 9 da série, o autor ilustra o uso da função ioctl (i/o control) para controle dos dispositivos. O driver query_iocl tem três variáveis (status, dignity, ego) que são controladas a partir de chamadas da aplicação query_app.
./query_app      to display the driver variables
./query_app -c   to clear the driver variables
./query_app -g   to display the driver variables
./query_app -s   to set the driver variables
Você deve rodar este exemplo e entender o funcionamento de ioctl. Como posso alterar o tipo de argumento passado para ioctl? Esta função permite grande flexibilidade?

No capítulo 4 do Kernel Hacking: ioctls: Not writing a new system call podemos encontrar a seguinte informação:


A system call generally looks like this

asmlinkage long sys_mycall(int arg)
{
        return 0;
}

First, in most cases you don't want to create a new system call. You
create a character device and implement an appropriate ioctl for
it. This is much more flexible than system calls, doesn't have to be
entered in every architecture's include/asm/unistd.h and
arch/kernel/entry.S file, and is much more likely to be accepted by
Linus.
No entanto, nem todos amam este design. Você consegue dizer algumas desvantagens?