| Just Joined!
Join Date: May 2006
Posts: 3
| TTY Driver "driving" me crazy. Ok. So I have the task of writing a driver that is a tty on the top and interfaces to our proprietary system on the bottom. No problem. Simple. I'm thinking. So, I wrote it as a module.
When I run it with minicom it was crashing the app. It looked like it was doing some writes (minicom modem initialization) and then doing a select() and crashing.
Then I ran in with minicom --noinit. I thought the write()s were doing something bad maybe. But no. It still crashes. Then I wrote a small app to open it and do a select(), which is essentially what minicom --noinit does.
My little app worked, but I noticed that minicom includes fd 0 1 and 2 (stdin, stdout, stderr) in the select() list. And thats the magic that makes the select() crash. I'm perplexed.
I have no idea what is wrong. I stripped down the driver to the ridiculously small module that I have shown below and I can still make it crash by doing an open() and do a select() on it along with fd 0 1 and 2. I am running kernel 2.6.23.8
I have also included the output of the crash.
Can anybody help. Maybe shed some light on this. Thanks so much for the help.
- Mike
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/capability.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/sysrq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#ifdef CONFIG_KDB
# include <linux/kdb.h>
#endif
static struct tty_driver *my_tty_driver;
static int my_open(struct tty_struct *tty, struct file * filp)
{
tty->driver_data = NULL;
return 0;
}
static void my_close(struct tty_struct *tty, struct file * filp)
{
}
static int my_write(struct tty_struct * tty, const unsigned char *buf, int count)
{
return count;
}
static int my_write_room(struct tty_struct *tty)
{
return 1000;
}
static const struct tty_operations my_ops = {
.open = my_open,
.close = my_close,
.write = my_write,
.write_room = my_write_room,
};
MODULE_AUTHOR("Me");
MODULE_DESCRIPTION("TTY driver");
MODULE_LICENSE("GPL");
static int __init my_init (void)
{
int i;
my_tty_driver = alloc_tty_driver(4);
if (!my_tty_driver)
return -ENOMEM;
/* Initialize the tty_driver structure */
my_tty_driver->owner = THIS_MODULE;
my_tty_driver->driver_name = "/dev/my";
my_tty_driver->name = "my";
my_tty_driver->major = 99;
my_tty_driver->minor_start = 0;
my_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
my_tty_driver->subtype = SERIAL_TYPE_NORMAL;
my_tty_driver->init_termios = tty_std_termios;
my_tty_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
my_tty_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(my_tty_driver, &my_ops);
if((i = tty_register_driver(my_tty_driver)))
{
printk(KERN_INFO "tty_register_driver returned 0x%x\n", i);
}
return 0;
}
static void __exit my_exit(void)
{
}
module_init(my_init);
module_exit(my_exit);
---------------------------------------------------------------------
Crash output:
BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000
printing eip:
00000000
*pde = 00000000
Oops: 0000 [#1]
PREEMPT
Modules linked in: cygnus_lic cygnus_sys cygnus_local cygnus_pcm cygnus_serial_dma cygnus_reg cygnus_dma
CPU: 0
EIP: 0060:[<00000000>] Not tainted VLI
EFLAGS: 00010246 (2.6.23.8 #7)
EIP is at _stext+0x3fefff50/0x19
eax: cdbf1400 ebx: cdbf1400 ecx: 00000000 edx: ce43b600
esi: 00000000 edi: cdb28440 ebp: cd4d3b60 esp: cd4d3b4c
ds: 007b es: 007b fs: 0000 gs: 0033 ss: 0068
Process select (pid: 2256, ti=cd4d2000 task=c1242570 task.ti=cd4d2000)
Stack: c021c66c 0021846f cdbf1400 c021c579 cdb28440 cd4d3b80 c021905d 00000000
cdbf140c 00000000 00000100 cdb28440 00000003 cd4d3e2c c01597fc cd4d3f9c
cd4d3f48 00000000 cd4d3e54 cd4d3e58 cd4d3e5c cd4d3e48 cd4d3e4c cd4d3e50
Call Trace:
[<c01034fa>] show_trace_log_lvl+0x1a/0x2f
[<c01035aa>] show_stack_log_lvl+0x9b/0xa3
[<c0103799>] show_registers+0x1e7/0x328
[<c01039d7>] die+0xfd/0x1e0
[<c011022e>] do_page_fault+0x495/0x563
[<c03417d2>] error_code+0x6a/0x70
[<c021905d>] tty_poll+0x4a/0x62
[<c01597fc>] do_select+0x2d5/0x4c3
[<c0159c80>] core_sys_select+0x296/0x2b3
[<c0159fc6>] sys_select+0x95/0x165
[<c0102652>] syscall_call+0x7/0xb
=======================
Code: Bad EIP value.
EIP: [<00000000>] _stext+0x3fefff50/0x19 SS:ESP 0068:cd4d3b4c
----------------------------------------------------------------------
Strace output of my little select() app:
execve("./select", ["./select"], [/* 24 vars */]) = 0
brk(0) = 0x804a000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f82000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=9582, ...}) = 0
mmap2(NULL, 9582, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f7f000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0 `\1\000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1216808, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7e000
mmap2(NULL, 1226148, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e52000
mmap2(0xb7f78000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x125) = 0xb7f78000
mmap2(0xb7f7b000, 9636, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f7b000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e51000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e516c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7f78000, 4096, PROT_READ) = 0
munmap(0xb7f7f000, 9582) = 0
open("/dev/my", O_RDWR) = 3
select(4, [0 1 2 3], NULL, NULL, {5, 0} |