0

我正在制作一个能够使用 UART 接收和发送字符的简单设备驱动程序。

我的读写函数如下:

unsigned char UART_read(void){
     unsigned int buf;
     while( ( ( inb(UART_LSR + UART) ) & UART_LSR_DR ) == 0 ){
             schedule();
     }
     buf = inb(UART);
     return (char)buf;
}

ssize_t serp_read(struct file *filep, char __user *buf, size_t count, loff_t *offp){
        ssize_t cnt, ret;
        char *buffer;
        unsigned char data;
        int i;

        buffer = kmalloc(count * sizeof(char), GFP_KERNEL);

        printk("\nTHIS IS KERNEL, read was called and count is %zd\n", count);

        while(1){        
           buffer[i] = UART_read();
           if(buffer[i] == '\n') break;
           i++;
        }

        buffer[strlen(buffer) - 1] = '\0';

        if( (cnt = (copy_to_user(buf, buffer, strlen(buffer)))) != 0 )
               printk("Error in copy_to_user() cnt is %d\n", cnt);

        ret = strlen(buffer);

        printk("\nTHIS IS KERNEL, read is going away and buf is %s\n", buf);

        return ret; 
}

void UART_send(unsigned char data){
       while( ( ( inb(UART_LSR + UART) ) & UART_LSR_THRE ) == 0 ){
             schedule();
       }
       outb(data, (UART + UART_TX));
}

ssize_t serp_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){
        ssize_t cnt, ret;
        int i;
        char *buffer;

        buffer = kmalloc(count * sizeof(char), GFP_KERNEL);

        if( (cnt = (copy_from_user(buffer, buf, count))) != 0 ) printk("Error in     copy_from_user()\n");
        buffer[count] = '\0';

        for(i = 0; i < strlen(buffer); i++){
            UART_send(buffer[i]);
        }

        ret = strlen(buffer);

        return ret; 
}

我用来测试的部分程序是:

    char *str = "HELLO MY NAME IS";
    strcpy(buffer, str);
    printf("\nThe message is [ %s ]\n", buffer);
    if ( (write(fd, buffer, strlen(buffer))) < 0) perror("Error");

    buffer[0] = '\0';

    if ( (read(fd, buffer, sizeof(buffer))) < 0) perror("Error");

    //buffer[strlen(buffer)] = '\0';

    printf("\nThe content of buffer after read() is [ %s ]\n", buffer);

有了我所拥有的,我写“HELLO,MY NAME IS”字符串没有问题,但是当我从UART读取“hey”时,读取函数中的buf显示为“heyLO,MY NAME IS”,而且我不明白为什么会发生这种覆盖。我现在最好的猜测是,首先我写入内核访问的用户空间,然后我读到同一个用户空间,最后覆盖了已经存在的内容。

4

2 回答 2

1

read返回读取的字节数,并且不终止。此外,这一行:

buffer[strlen(buffer)] = '\0';

什么都不做,因为strlen缓冲区是第一个的偏移量'\0'!尝试

ssize_t rb = read(fd, buffer, sizeof(buffer));
if ( rb < 0)
    perror("Error");
else {
    buffer[rb] = '\0';
    ...

再读serp_read一遍,我发现这种破碎的使用strlen无处不在。如果您还没有以 nul 结尾的 C 字符串,则不能使用strlen. 它只是寻找 nul!

ssize_t serp_read(struct file *filep,
                  char __user *buf, size_t count, loff_t *offp) {
    ssize_t cnt, i;
    char *buffer;

    buffer = kmalloc(count, GFP_KERNEL);
    printk("\nTHIS IS KERNEL, read was called and count is %zd\n", count);

    /* your while loop started with i uninitialized,
     * and didn't check for overflow */
    for (i = 0; i != count; ++i) {
        buffer[i] = UART_read();
        if(buffer[i] == '\n')
            break;
    }
    /* this is incorrect because:
     * 1. strlen isn't useable unless the buffer is already nul-terminated
     * 2. the read(2) system call isn't expected to nul-terminate buffers anyway
    buffer[strlen(buffer) - 1] = '\0';
     */

    /* Use i+1 as the length if you want to include the newline */
    cnt = copy_to_user(buf, buffer, i);
    kfree(buffer);
    if(cnt) {
        printk("Error in copy_to_user() cnt is %d\n", cnt);
        i -= cnt; /* bytes successfully copied */
    }

    printk("\nTHIS IS KERNEL, read is going away and buf is %.*s\n", i, buf);
    /* this is how to print non-nul-terminated variable-length strings */

    return i; /* NB. should return an error above, as well as printing */ 
}
于 2013-05-14T11:29:37.647 回答
0

使用 memset,你没有清除内存

char *str = "HELLO MY NAME IS";

strcpy(buffer, str);
printf("\nThe message is [ %s ]\n", buffer);

if ( (write(fd, buffer, strlen(buffer))) < 0) perror("Error");

buffer[0] = '\0'; // this is clearing only single character
memset( buffer , 0 , sizeof(buffer)); // clear the entire buffer here

if ( (read(fd, buffer, sizeof(buffer))) < 0) perror("Error");

//buffer[strlen(buffer)] = '\0';

printf("\nThe content of buffer after read() is [ %s ]\n", buffer);
于 2013-05-14T12:27:01.687 回答