device driver (1)
今日からこつこつ進めます。一旦仕切り直してリトライします。色々参考にしつつ。
雑多な情報から
昨日まで色々調べつつ中途半端に終わっているナニを控えておく。
errno
まず errno から。どういった仕掛けなのかは不明ですが、ワシ環境では include/asm は include/asm-i386 への symlink になっている模様。
- include/asm/errno.h は include/asm-generic/errno.h を include してるのみ
- include/asm-generic/errno.h は errno-base.h を include しつつ 35 から 131 までの errrno が定義
- include/asm-generic/errno-base.h では 1 から 34 までの errno が定義
でも errno 戻すナニで asm/errno.h を直接 include ではないはず。で探してみたら include/linux/errno.h というソレがある。これを include しておけば良いのでしょうか。
カーネル空間とユーザ空間のやりとり
- copy_{from, to}_user とか strncpy_{from, to}_user とかを使う模様
asm/uaccess.h でのプロトタイプ定義は以下
unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n); unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n); long __must_check strncpy_from_user(char *dst, const char __user *src, long count); long __must_check __strncpy_from_user(char *dst, const char __user *src, long count);
verify_area
この関数で_指定されたアクセスが許可されている_かどうかを判断するとの事。ただし、現在見ている 2.6.20 では rw_verify_area に変更されている模様。プロトタイプ定義は以下。
extern int rw_verify_area(int, struct file *, loff_t *, size_t);
実体は fs/read_write.c な模様。しかし用途がなんか微妙な気が。ってやっぱりそうか。ここによると verify_area は access_ok というナニになっている模様。linux/asm/uaccess.h にて define されている。
/** * access_ok: - Checks if a user space pointer is valid * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe * to write to a block, it is always safe to read from it. * @addr: User space pointer to start of block to check * @size: Size of block to check * * Context: User context only. This function may sleep. * * Checks if a pointer to a block of memory in user space is valid. * * Returns true (nonzero) if the memory block may be valid, false (zero) * if it is definitely invalid. * * Note that, depending on architecture, this function probably just * checks that the pointer is in the user space range - after calling * this function, memory access functions may still return -EFAULT. */ #define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
コメントによればビンゴな模様。使い方的には例えば以下??
access_ok(VERIFY_WRITE, dst, len)
VERIFY_READ とか VERIFY_WRITE とかも include/asm/uaccess.h にて define されている。
open あたりから動作を見てみる
とりあえずイチから、という事でディレクトリを掘って、既存な Makefile をコピッておいて修正。
obj-m := yamanetoshi.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: # $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules $(MAKE) -C $(KDIR) M=$(PWD) modules clean: @rm -rf *~ *.o *.ko Module.symvers *.mod.c
で、最初はシンプルに、で以下。
#include <linux/module.h> // required by all modules #include <linux/kernel.h> // required by printk() #include <linux/init.h> #include <linux/fs.h> #include <linux/sched.h> #include <asm/uaccess.h> // required by copy_{to_user, from_user} MODULE_LICENSE("GPL"); #define EOF (-1) #define TRUE 1 #define FALSE 0 #define DRIVERNAME "yamanetoshi" static int fifo_major = 130; static int yamanetoshi_open(struct inode *inode, struct file *file) { printk("yamanetoshi_open\n"); printk(" MINOR(inode->i_rdev): %d\n", MINOR(inode->i_rdev)); return 0; } static int yamanetoshi_release(struct inode *inode, struct file *file) { printk("yamanetoshi_close\n"); return 0; } struct file_operations fifo_fops = { .owner = THIS_MODULE, .read = NULL, .write = NULL, .ioctl = NULL, .open = yamanetoshi_open, .release = yamanetoshi_release, }; // Start/Init function static int yamanetoshi_init(void) { int ret; printk("initialize the fifo device\n"); ret = register_chrdev(fifo_major, DRIVERNAME, &fifo_fops); if(ret < 0) return ret; if(fifo_major == 0) fifo_major = ret; return 0; } // End/Cleanup function static void yamanetoshi_exit(void) { printk("cleanup the fifo device\n"); unregister_chrdev(fifo_major, DRIVERNAME); } module_init(yamanetoshi_init); module_exit(yamanetoshi_exit);
これだと open/close だけなんで vmware でなくても良いな。とりあえず insmod/rmmod の正常動作は確認。よく考えたら device 作ってない。
# mknod ./fifo100130 c 130 100 # mknod ./fifo101130 c 130 101 # ls total 24 -rw-r--r-- 1 rms rms 232 Aug 21 23:01 Makefile -rw-r--r-- 1 rms rms 0 Aug 21 23:01 Module.symvers crw-r--r-- 1 root root 130, 100 Aug 21 23:14 fifo100130 crw-r--r-- 1 root root 130, 101 Aug 21 23:15 fifo101130 -rw-r--r-- 1 rms rms 1474 Aug 21 23:00 yamanetoshi.c -rw-r--r-- 1 rms rms 3248 Aug 21 23:01 yamanetoshi.ko -rw-r--r-- 1 rms rms 681 Aug 21 23:01 yamanetoshi.mod.c -rw-r--r-- 1 rms rms 2072 Aug 21 23:01 yamanetoshi.mod.o -rw-r--r-- 1 rms rms 1888 Aug 21 23:01 yamanetoshi.o #
で、
# cat >fifo100130
してみたら
Aug 21 23:15:43 debian kernel: yamanetoshi_open Aug 21 23:15:43 debian kernel: MINOR(inode->i_rdev): 100 Aug 21 23:15:46 debian kernel: yamanetoshi_close
との事。一般ユーザだとどうか
$ cat >fifo100130 bash: fifo100130: 許可がありません $
ぬ。一般ユーザからだと書き込みできない?
ええと、ls -l してみたら確かに権限無いな。とほほ。権限 666 にしたら大丈夫でした。とりあえずハードル一つ越えました。とりあえず今日はこれで終了。