我正在制作一个简单的设备驱动程序,能够使用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说“嘿”,读取功能中的buf显示为“heyLO,MY NAME” IS“,我不明白为什么会发生这种覆盖。我现在最好的猜测是,首先我写入内核访问的用户空间,然后我读到相同的用户空间,最后覆盖已经存在的内容。
答案 0 :(得分: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 */
}
答案 1 :(得分: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);