posted on 2010-11-09 22:18 小默 阅读(2135) 评论(25) 编辑 收藏 引用 所属分类: Linux
User-Mode Linux 允许多个系统彼此独立的工作,同时独立于硬件。 一、 安装UML kernel RPM 下载user_mode_linux-2.4.19.5um-0.i386.rpm 安装: # rpm -ivh user_mode_linux-2.4.19.5um-0.i386.rpm 测试是否安装成功: # /usr/bin/linux 这时UML会运行,然后报段错误崩溃。OK,传说中就是这样滴! 因为没有文件系统。。。。 二、 安装文件系统 从http://fs.devloop.org.uk/下载文件系统 我下的是Fedora14-x86-root_fs.bz2 建立uml目录 # mkdir /usr/local/share/uml 把下载的文件系统拷到新建的uml目录下,解压缩 # bunzip2 Fedora14-x86-root_fs.bz2 (bunzip2会删除掉bz2压缩包,只保留解压缩后的文件) 在uml目录下给/usr/bin/linux建一个soft link # ln -s /usr/bin/linux /usr/local/share/uml 恩,安装到此结束,请看uml目录 [root@colorfulgreen uml]# ls -lhs total 1.1G 1.1G -rw-------. 1 root root 1.0G Nov 7 14:05 Fedora14-x86-root_fs 0 lrwxrwxrwx. 1 root root 14 Nov 8 20:39 linux -> /usr/bin/linux 传说中,要启动一个新的闪闪的UML,到这里就万事俱备,只欠启动了。我来试下: [root@colorfulgreen uml]# ./linux Segmentation fault (core dumped) 泪奔,哭着睡觉了T_T~~ 回复 更多评论
之前做毕设时也见过Segmentation fault (core dumped) 貌似是因为内存访问错误,当时就是一个数组越界导致的。 不过现在我这水平,肯定是分析不了了。 先把环境搭好才是真的。 上user-mode-linux.sourceforge.net,首页下面Getting started中kernel是linux-2.6.24-rc7.bz2 我倒!估计是之前用的user_mode_linux-2.4.19.5um-0.i386.rpm太老了。。 Tips1:新接触一样东西的话,和什么乱七八糟的教程比起来,官网似乎是更好的选择。官网会实时更新,而且东西一般都很全。 下载linux-2.6.24-rc7.bz2,bunzip2到/usr/local/share/uml下 # chmod 755 linux-2.6.24-rc7 # ./linux-2.6.24-rc7 ubda=Fedora14-x86-root_fs mem=400M ... No filesystem could mount root, tried: reiserfs ext3 ext2 Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(98,0) ... Segmentation fault (core dumped) 和上面一样是段错误,不过显示的有错误原因,文件系统没有挂上。 上http://fs.devloop.org.uk/看了下,Fedora14-x86-root_fs.bz2是ext4格式的。 ext4最初的开发版本包含在2.6.19中,稳定版本第一次包含在2.6.28中[http://en.wikipedia.org/wiki/Ext4] 猜测可能是这儿的内核不支持ext4 重新下了个ext3格式的Fedora13-x86-root_fs.bz2,拷贝到uml目录下,bunzip2 [green@colorfulgreen uml]$ ls -lns total 1071204 1048580 -rw-r--r--. 1 0 0 1073741824 Nov 8 23:52 Fedora13-x86-root_fs 22624 -rwxr-xr-x. 1 0 0 23166750 Nov 8 22:30 linux-2.6.24-rc7 [root@colorfulgreen uml]# ./linux-2.6.24-rc7 ubda=Fedora13-x86-root_fs mem=400M Core dump limits : soft - 0 hard - NONE Checking that ptrace can change system call numbers...OK Checking syscall emulation patch for ptrace...OK Checking advanced syscall emulation patch for ptrace...OK Checking for tmpfs mount on /dev/shm...OK Checking PROT_EXEC mmap in /dev/shm/...OK Checking for the skas3 patch in the host: - /proc/mm...not found: No such file or directory - PTRACE_FAULTINFO...not found - PTRACE_LDT...not found UML running in SKAS0 mode Adding 18673664 bytes to physical memory to account for exec-shield gap Linux version 2.6.24-rc7-dirty (jdike@tp.user-mode-linux.org) (gcc version 4.1.2 20070925 (Red Hat 4.1.2-27)) #97 Mon Jan 7 11:18:24 EST 2008 Built 1 zonelists in Zone order, mobility grouping on. Total pages: 106124 Kernel command line: ubda=Fedora13-x86-root_fs mem=400M root=98:0 PID hash table entries: 2048 (order: 11, 8192 bytes) Dentry cache hash table entries: 65536 (order: 6, 262144 bytes) Inode-cache hash table entries: 32768 (order: 5, 131072 bytes) Memory: 400256k available Mount-cache hash table entries: 512 Checking for host processor cmov support...Yes Checking for host processor xmm support...No Checking that host ptys support output SIGIO...Yes Checking that host ptys support SIGIO on close...No, enabling workaround net_namespace: 64 bytes Using 2.6 host AIO NET: Registered protocol family 16 NET: Registered protocol family 2 Time: itimer clocksource has been installed. IP route cache hash table entries: 4096 (order: 2, 16384 bytes) TCP established hash table entries: 16384 (order: 5, 131072 bytes) TCP bind hash table entries: 16384 (order: 4, 65536 bytes) TCP: Hash tables configured (established 16384 bind 16384) TCP reno registered Checking host MADV_REMOVE support...OK mconsole (version 2) initialized on /root/.uml/HJNlpW/mconsole Host TLS support detected Detected host type: i386 VFS: Disk quotas dquot_6.5.1 Dquot-cache hash table entries: 1024 (order 0, 4096 bytes) io scheduler noop registered io scheduler anticipatory registered (default) io scheduler deadline registered io scheduler cfq registered TCP cubic registered NET: Registered protocol family 1 NET: Registered protocol family 17 Initialized stdio console driver Console initialized on /dev/tty0 console [tty0] enabled Initializing software serial port version 1 console [mc-1] enabled ubda: unknown partition table kjournald starting. Commit interval 5 seconds EXT3-fs: mounted filesystem with ordered data mode. VFS: Mounted root (ext3 filesystem) readonly. Welcome to Fedora Press 'I' to enter interactive startup. Starting udev: modprobe: FATAL: Could not load /lib/modules/2.6.24-rc7-dirty/modules.dep: No such file or directory error initializing netlink socket error sending message: Connection refused error sending message: Connection refused error sending message: Connection refused [ OK ] Setting hostname localhost: [ OK ] Checking filesystems Checking all file systems. [ OK ] Remounting root filesystem in read-write mode: [ OK ] Mounting local filesystems: [ OK ] Enabling /etc/fstab swaps: [ OK ] 到这儿就不动了,我是等等呢,还是等等呢。。。 回复 更多评论
吃了点瓜子儿垫把肚子,继续。。。 官网上的解释: Hang after 'VFS: Mounted root...' The VDSOs provided by the host kernel are confusing UML. Until this is fixed in UML, a workaround to to disable CONFIG_COMPAT_VDSO on the host. 可恶阿,又要编译内核了么,T_T 回复 更多评论
下了个2.6.36重新编译了。编译前还确认了没有启用CONFIG_COMPAT_VDSO,依旧到上面的地方就停了。。。。逗我玩儿么? 回复 更多评论
insight+skyeye调试kernel恩,明天试试O(∩_∩)O~~ 回复 更多评论
装skyeye时遇到的问题,参考下面文章搞定。记一下。http://www.mysidenotes.com/2007/08/26/package-xxxrpm-is-not-signed/------------I downloaded an .rpm package but if I run# rpm -ivh xxx.rpmIt shows a long list of dependences needed to install.If I runyum install xxx.rpmI’ve got an error messagePackage xxx.rpm is not signedSolution:Edit /etc/yum.confreplace gpgcheck=1 to gpgcheck=0 回复 更多评论
[root@colorfulgreen arm_hello]# skyeye -e arm_hello -c skyeye.conf skyeye: error while loading shared libraries: /opt/skyeye/lib/skyeye/libcommon.so.0: cannot restore segment prot after reloc: Permission denied[root@colorfulgreen arm_hello]# vim /etc/sysconfig/selinux [root@colorfulgreen arm_hello]# chcon -t texrel_shlib_t /opt/skyeye/lib/skyeye/libcommon.so.0[root@colorfulgreen arm_hello]# skyeye -e arm_hello -c skyeye.conf Non-option argument skyeye.confSkyEye 1.3.1SkyEye is an Open Source project under GPL. All rights of different parts or modules are reserved by their author. Any modification or redistributions of SkyEye should not remove or modify the annoucement of SkyEye copyright. Get more information about it, please visit the homepage http://www.skyeye.org.Type "help" to get command list. (skyeye)其中编辑/etc/sysconfig/selinux:注释掉SELINUX=enforcing,新加一行SELINUX=disabled保存,关闭 回复 更多评论
“一个驱动程序的角色是提供机制,而不是策略。”--ldd3机制:提供什么能力策略:如何使用这些能力机制和策略由软件不同部分,或完全不同的软件实现。比如第一次实习时:我们这边负责写驱动,只关注实现什么功能,怎么实现这样功能,这是机制。我们可以直接在设备管理器中安装卸载,或者用命令行安装卸载使用等,随意,也就是开发过程完全不考虑策略。等开发进行到了一定阶段,又招了另外一名同学负责界面,这是策略。用户怎么使用这个驱动,操作界面是怎样的,是由他来负责的。不知道是不是这个意思O(∩_∩)O~~ 回复 更多评论
对于单个.c文件的hello world例子:obj-m := hello.o从目标文件hello.o简历一个模块hello.ko如果模块来自两个源文件file1.c和file2.c:obj-m := module.omodule-objs := file1.o file2.o上面的命令,必须在内核系统上下建立文中被调用-----在任意当前工作目录中,需要在makefile中指明源码树的路径。ifneq ($(KERNELRELEASE),) obj-m := hello.oelse KERNELDIR ?= /lib/modules/$(shell uname -r)/build //TODO 不是在源码树中么/(ㄒoㄒ)/~~ PWD := $(shell pwd)default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendif创建一个模块需要调用两次上面的makefile第一次:没有设置变量KERNELRELEASE,通过已安装模块目录中的符号链接指回内核建立树;然后运行default中的make命令,第二次使用makefile第二次:已经设置了变量KERNELRELEASE,直接obj-m := hello.o创建模块 回复 更多评论
modprobe实现和insmod一样加载模块到内核的功能不同的是,加载前会检查模块中是否有当前内核中没有定义的symbol,如果有,在模块搜索路径中寻找其它模块是否含有上面的symbol,有的话,自动加载关联模块insmod对于这种情况,会报错unresolved symbols查看当前加载模块:lsmodcat /proc/modules 回复 更多评论
EXPORT_SYMBOL(name);EXPORT_SYMBOL_GPL(name); 回复 更多评论
说10次hello,Mom# insmod hellop howmany=10 whom="Mom"--static char *whom = "world"; //必须给默认值static int howmany = 1;module_param(howmany, int, S_IRUGO);module_param(whom, charp, S_IRUGO);--S_IRUGO 允许所有人读S_IRUGO | S_IWUSR 允许所有人读,允许root改变参数如果参数被sysfs修改,不会通知模块。不要使参数可写,除非准备好检测参数改变。--数组参数:module_param_array(name, type, num, perm); 回复 更多评论
$ ls -l /dev...crw-rw---- 1 vcsa tty 7, 132 Nov 15 17:16 vcsa4crw-rw---- 1 vcsa tty 7, 133 Nov 15 17:16 vcsa5crw-rw---- 1 vcsa tty 7, 134 Nov 15 17:16 vcsa6crw-rw---- 1 root root 10, 63 Nov 15 17:16 vga_arbiterdrwxr-xr-x 2 root root 80 Nov 15 17:16 vg_colorfulgreencrw-rw-rw- 1 root root 1, 5 Nov 15 17:16 zero...输出第一列是c的是字符设备,第一列b块设备修改日期前的两个数字。第一个是主设备编号:标识设备相连的驱动第二个是次设备编号:决定引用哪个设备-------设备编号的内部表示dev_t 在<linux/types.h>中定义,32位,12位主编号,20位次编号。获得一个dev_t的主或次编号:<linux/kdev_t.h>MAJOR(dev_t dev);MINOR(dev_t dev);将主次编号转换成dev_t:MKDEV(int major, int minor);--------分配和释放设备编号建立一个字符驱动时,做的第一件事就是获取一个或多个设备编号使用:<linux/fs.h>int register_chrdev_region(dev_t first, unsigned int count, char *name);first要分配的起始设备编号count请求的连续设备编号的总数name连接到这个编号范围的设备的名字,会出现在/proc/devices和sysfs中成功返回0,出错返回负的错误码。如果事先不知道使用哪个设备编号,使用下面函数,内核会分配一个主设备编号:int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);dev是一个输出参数,返回分配范围的第一个数firstminor请求第一个要用的次编号,常是0设备编号的释放:void unregister_chrdev_region(dev_t first, unsigned int count); 回复 更多评论
脚本scull_load: 1 #!/bin/sh 2 module="scull" 3 device="scull" 4 mode="664" 5 6 # invoke insmod with all arguments we got 7 # and use a pathname, as newer modutils don't look in. by default 8 /sbin/insmod ./$module.ko $* || exit 1 # 插入模块,使用获取的所有参数($*) 9 10 # remove stale nodes删除无效的节点,不能删除device0,device1,device2...阿。。TODO 11 rm -f /dev/${device}[0-3] 12 13 major=$(awk "\\$2==\"$module\" {print \\$1}" /proc/devices) #TODO 没有搞明白 14 mknod /dev/${device}0 c $major 0 #创建4个虚拟设备 15 mknod /dev/${device}1 c $major 1 16 mknod /dev/${device}2 c $major 2 17 mknod /dev/${device}3 c $major 3 18 19 # give appropriate group/permissions, and change the group. 20 # Not all distributions have staff, some have "wheel" instead. #TODO 神马意思? 21 group="staff" 22 grep -q '^staff:' /etc/group || group="wheel" 23 # 改变设备的组和模式。脚本必须以root运行,但设备使用可能需要其它用户写。 24 chgrp $group /dev/${device}[0-3] 25 chmod $mode /dev/${device}[0-3] 26 回复 更多评论
一些处理文件的回调函数 1 // init file_operations 2 struct file_operations scull_fops = { 3 .owner = THIS_MODULE, 4 .llseek = scull_llseek, 5 .read = scull_read, 6 .write = scull_write, 7 .ioctl = scull_ioctl, 8 .open = scull_open, 9 .release = scull_release, 10 }; 回复 更多评论
12 // 使用struct scull_dev结构表示每个设备 13 // TODO 没有理解什么意思 14 struct scull_dev { 15 struct scull_qset *data; // pointer to first quantum set 16 int quantum; // the current quantum size 17 int qset; // the current array size 18 unsigned long sizee; //amount of data stored here 19 unsigned int access_key; // used by sculluid and scullpriv 20 struct semaphore sem; // matual exclusion semaphore 21 struct cdev cdev; // 字符设备结构 22 }; 23 24 // 初始化struct cdev,并添加到系统中 25 static void scull_setup_cdev(struct scull_dev *dev, int index) 26 { 27 int err, devno = MKDEV(scull_major, scull_minor + index); 28 29 // TODO 初始化已经分配的结构. 不是很理解 30 // cdev结构嵌套在struct scull_dev中,必须调用cdev_init()来初始化cdev结构 31 cdev_init(&dev->cdev, &scull_fops); 32 dev->cdev.owner = THIS_MODULE; 33 dev->cdev.ops = &scull_fops; 34 // 添加到系统中 35 err = cdev_add(&dev->cdev, devno, 1); 36 if(err) 37 printk(KERN_NOTICE "Error %d adding scull%d", err, index); 38 } 回复 更多评论
system-config-selinux什么时候改了,汗 //TODO 回复 更多评论
// 表示每个设备struct scull_dev{ struct scull_qset *data; // pointer to first quantum set int quantum; // the current quantum size - 当前量子和量子集大小 int qset; // the current array size - 每个内存区域为一个量子,数组为一个量子集 unsigned long size; // amount of data stored here unsigned int access_key; // used by sculluid and scullpriv struct semaphore sem; // mutual exclusion semaphore struct cdev cdev; // char device structure};// 量子集,即一个内存区域的数组struct scull_qset{ void **data; struct scull_qset *next;};ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){ struct scull_dev *dev = file->private_data; struct scull_qset *dptr; // 量子集中的第一个元素 int quantum = dev->quantum, qset = dev->qset; // 当前量子和量子集大小 int itemsize = quantum * qset; // listitem中的字节数=量子大小*量子集大小 int item, s_pos, q_pos, rset; ssize_t retval = 0; if(down_interruptible(&dev->sem)) // TODO return -ERESTARTSYS; if(*f_pos > dev->size) goto out; if(*f_pos + count > dev->size) count = dev->size - *f_pos; // 查找listitem, qset index, and 量子中的偏移量 item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; // 遍历list到右侧 dptr = scull_follow(dev, item); // 量子集中的第一个元素 if(dptr == NULL || !dptr->data || !dptr->data[s_pos]) goto out; // 只读取到这个量子的尾部 if(count > quantum - q_pos) count = quantum - q_pos; if(copy_to_user(buf, dptr->data[s_pos] + q_pos, count)){ retval = -EFAULT; goto out; } *f_pos += count; retval = count;out: up(&dev->sem); return retval;}// 一次处理单个量子ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){ struct scull_dev *dev = filp->private_data; struct scull_qset *dptr; int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum * qset; int item, s_pos, q_pos, rest; ssize_t retval = -ENOMEM; // value used in "goto out" statements if(down_interruptible(&dev->sem)) return -ERESTARTSYS; // 查找列表元素,qset index and 量子中的偏移量 item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; // 遍历list到右侧 dptr = scull_follow(dev, item); if(dptr == NULL): goto out; if(!dptr->data){ dptr->data = kmalloc(qset * sizeof(char), GPL_KERNEL); if(!dptr->data) goto out; memset(dptr->data, 0, qset * sizeof(char *)); } if(!dptr->data[s_pos]){ dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); if(!dptr->data[s_pos]) goto out; } // 只写到这个量子的结束 if(count > quantum-q_pos) count = quantum - q_pos; // 从用户空间拷贝一整段数据to from count if(copy_from_user(dptr->data[s_pos]+q_pos, buf, count)){ retval = -EFAULT; goto out; } *f_pos += count; retval = count; // 更新size if(dev->size < *f_pos) dev->size = *f_pos;out: up(&dev->sem); return retval;}//-------------------------------// read和write的"矢量"版本// readv轮流读取指示的数量到每个缓存;writev收集每个缓存的内容到一起并且作为单个写操作送出它们。// count参数告诉有多少iovec结构,这些结构由应用程序创建,但是内核在调用驱动之前拷贝它们到内核空间。ssize_t (*readv)(struct file *filp, const struct iovec *iov, unsigned long count, loff_t *ppos);ssize_t (*writev)(struct file *filp, const struct iovec *iov, unsigned long count, loff_t *ppos);// iovec描述了一块要传送的数据struct iovec{ void __user *iov_base; // 开始于iov_base(在用户空间) __kernel_size_t iov_len; // 并有iov_len长}; 回复 更多评论
// 重定向控制台消息// 使用一个参数指定接收消息的控制台的编号int main(int argc, char **argv){ char bytes[2] = {11, 0}; // 11 是 TIOCLINUX 的功能号 if(argc == 2) bytes[1] = atoi(argv[1]); // the chosen console else{ fprintf(stderr, "%s: need a single arg\n", argv[0]); exit(1); } // TIOCLINUX传递一个指向字节数组的指针作为参数,数组的第一个字节是一个数(需要指定的子命令)。 // 当子命令是11时,下一个字节指定虚拟控制台。 if(ioctl(STDIN_FILENO, TIOCLINUX, bytes)<0){ // use stdin fprintf(stderr, "%s: ioctl(stdin, TIOCLINUX): %s\n", argv[0], stderror(errno)); exit(1); } exit(0);} 回复 更多评论
// 在proc里实现文件,在文件被读时产生数据。// 当一个进程读你的/proc文件,内核分配了一页内存,驱动可以写入数据返回给用户空间。// buf 写数据的缓冲区;start有关数据写在页中哪里;eof必须被驱动设置,表示写数据结束;data用来传递私有数据。// 假定不会有必要产生超过一页的数据,并且因此忽略了start和offset值。int scull_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int i, j, len = 0; int limit = count - 80; // Don't print more than this for(i = 0; i < scull_nr_devs && len <= limit; i++){ // TODO scull_nr_devs ? struct scull_dev *d = &scull_devices[i]; struct scull_qset *qs = d->data; if(down_interruptible(&d->sem)) return -ERESTARTSYS; // 设备号,量子集大小,量子大小,存储的数据量 len += sprintf(buf+len, "\nDevice %i: qset %i, q %i, sz %li\n", i, d->qset, d->quantum, d->size); for(; qs && len <= limit; qs = qs->next){ //scan the list 遍历量子链表 // 元素地址、链表地址 len += sprintf(buf + len, " item at %p, qset at %p\n", qs, qs->data); // %p 显示一个指针 if(qs->data && !qs->next) // dump only the last item for(j = 0; j < d->qset, j++){ if(qs->data[j]) len += sprintf(buf+len, "%4i: %8p\n", j, qs->data[j]); } } up(&scull_devices[i]); } *eof = 1; return len; // 返回实际在页中写了多少数据}/// 移除entry的一些问题// 移除可能发生在文件正在被使用时。/proc入口没有owner,没有引用计数。// 内核不检查注册的名字是否已经存在,可能会有多个entry使用相同名称。而且在访问和remove_proc_entry时,它们没有区别。。。悲剧。。。 回复 更多评论
// 创建一个虚拟文件,遍历一串数据,这些数据必须返回用户空间。// start, next, stop, show// sfile 总被忽略;pos指从哪儿开始读,具体意义完全依赖于实现。// seq_file典型的实现是遍历一感兴趣的数据序列,pos就用来指示序列中的下一个元素。// 在scull中,pos简单地作为scull_array数组的索引。// 原型void *start(struct seq_file *sfile, loff_t *pos);// 在scull中的实现static void *scull_seq_start(struct seq_file *s, loff_t *pos){ if(*pos >= scull_nr_devs) return NULL; // no more to read return scull_devices + *pos; // 返回供迭代器使用的私有数据}// next把迭代器后挪一位,返回NULL表示没有更多数据了// v:上一次start/next调用返回的迭代器 TODO ???返回的不是私有数据么?// pos: 文件中的当前位置。void *next(struct seq_file *sfile, void *v, loff_t *pos);// scull的实现static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos){ (*pos)++; if(*pos >= scull_nr_devs) return NULL; return scull_devices + *pos;}// 内核完成迭代器,调用stop清理void stop(struct seq_file *sfile, void *v);// scull没有要清理的东西,stop方法是空的// start到stop期间不会有sleep或者非原子操作,可以放心的在start中获得信号量或自旋锁。整个调用序列都是原子的。天书啊 TODO ???// 在start和stop期间,内核调用show输出迭代器v生成的数据到用户空间int show(struct seq_file *sfile, void *v);// 输出,等效于用户空间的printf。返回非0值表示缓冲满,输出的数据会被丢弃。不过大多数实现都忽略返回值。int seq_sprintf(struct seq_file *sfile, const char *fmt, ...);// 等效于用户空间的putc和putsint seq_putc(struct seq_file *sfile, char c);int seq_puts(struct seq_file *sfile, const char *s);// 如果s中有esc中的数据,这些数据用8进制输出。常见的esc是"\t\n\\",用于保持空格,避免搞乱输出。int seq_escape(struct seq_file *m, const char *s, const char *esc);// scull中show实现static int scull_seq_show(struct seq_file *s, void *v){ struct scull_dev *dev = (struct scull_dev *)v; struct scull_qset *d; int i; if(down_interrutible(&dev->sem)) return -ERESTARTSYS; seq_printf(s, "\nDevice %i: qset %i, q %i, sz %li\n", (int)(dev - scull_devices), dev->qset, dev->quantum, dev->size); for(d = dev->data; d; d = d->next){ // 遍历链表 seq_printf(s, " item at %p, qset at %p\n", d, d->data); if(d->data && !d->next) // dump only the last item for(i = 0; i < dev->qset; i++){ if(d->data[i]) seq_printf(s, " %4i: %8p\n", i, d->data[i]); } } up(&dev->sem); return 0;}// 迭代器:指向scull_dev的一个指针,囧。。。// 迭代器操作集static struct seq_operations scull_seq_ops = { .start = scull_seq_start, .next = scull_seq_next, .stop = scull_seq_stop, .show = scull_seq_show};/// 用file_operations结构结构,实现内核read/seek文件的所有操作。// 创建一个open方法,连接文件和seq_file操作 TODO 没看懂static int scull_proc_open(struct inode *inode, struct file *file){ // seq_open 连接文件和上面定义的scull_seq_ops return seq_open(file, &scull_seq_ops);}// file_operations结构static struct fle_operations scull_proc_ops = { .owner = THIS_MODULE, .open = scull_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release};// 在/proc中创建设备entry = create_proc_entry("scullseq", 0, NULL);if(entry) entry->proc_fops = &scull_proc_ops;// create_proc_entry原型struct proc_dir_entry *create_proc_entry(const char *name, mode_t, mode, struct proc_dir_entry *parent); 回复 更多评论
略 O(∩_∩)O~~ 回复 更多评论
讲了两部分一、system opps空指针引用,或者局部变量赋值覆盖了原eip,导致页错误二、系统挂起 // TODO 看得云里雾里的死循环等引起假挂起:鼠标键盘等外设没有响应了,系统实际正常。可以看时间。。。插入schedule调用防止死循环,作用是允许其他进程从当前进程窃取时间。讲了些弊端,没看懂sysrq:没看懂 回复 更多评论
所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。原子类型定义:typedef struct { volatile int counter; } atomic_t; volatile修饰字段告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。 回复 更多评论
17 typedef struct { 18 volatile unsigned int lock; 19 #ifdef CONFIG_DEBUG_SPINLOCK 20 unsigned magic; 21 #endif 22 } spinlock_t; 回复 更多评论