小默

盖楼

恩,RT

posted on 2010-11-09 22:18 小默 阅读(2092) 评论(25)  编辑 收藏 引用 所属分类: Linux

评论

# re: 盖楼 2010-11-09 22:26 小默

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~~  回复  更多评论   

# 接一楼,UML安装 2010-11-10 10:06 小默

之前做毕设时也见过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 ]

到这儿就不动了,我是等等呢,还是等等呢。。。  回复  更多评论   

# 接,UML安装 2010-11-10 11:04 小默

吃了点瓜子儿垫把肚子,继续。。。
官网上的解释:
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




  回复  更多评论   

# re: 盖楼 2010-11-13 18:49 小默

下了个2.6.36重新编译了。编译前还确认了没有启用CONFIG_COMPAT_VDSO,依旧到上面的地方就停了。。。。逗我玩儿么?  回复  更多评论   

# re: 盖楼 2010-11-14 00:12 小默

insight+skyeye调试kernel
恩,明天试试O(∩_∩)O~~  回复  更多评论   

# Package xxx.rpm is not signed 2010-11-14 13:53 小默

装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.rpm
It shows a long list of dependences needed to install.

If I run
yum install xxx.rpm

I’ve got an error message
Package xxx.rpm is not signed

Solution:

Edit /etc/yum.conf

replace gpgcheck=1 to gpgcheck=0  回复  更多评论   

# cannot restore segment prot after reloc: Permission denied 2010-11-14 16:02 小默

[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.conf
SkyEye 1.3.1
SkyEye 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
保存,关闭  回复  更多评论   

# 一个驱动程序的角色是提供机制,而不是策略 2010-11-15 09:26 小默

“一个驱动程序的角色是提供机制,而不是策略。”--ldd3

机制:提供什么能力
策略:如何使用这些能力
机制和策略由软件不同部分,或完全不同的软件实现。

比如第一次实习时:
我们这边负责写驱动,只关注实现什么功能,怎么实现这样功能,这是机制。我们可以直接在设备管理器中安装卸载,或者用命令行安装卸载使用等,随意,也就是开发过程完全不考虑策略。
等开发进行到了一定阶段,又招了另外一名同学负责界面,这是策略。用户怎么使用这个驱动,操作界面是怎样的,是由他来负责的。

不知道是不是这个意思O(∩_∩)O~~  回复  更多评论   

# makefile写法 2010-11-15 17:14 小默

对于单个.c文件的hello world例子:
obj-m := hello.o
从目标文件hello.o简历一个模块hello.ko

如果模块来自两个源文件file1.c和file2.c:
obj-m := module.o
module-objs := file1.o file2.o

上面的命令,必须在内核系统上下建立文中被调用

-----

在任意当前工作目录中,需要在makefile中指明源码树的路径。

ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build //TODO 不是在源码树中么/(ㄒoㄒ)/~~
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

创建一个模块需要调用两次上面的makefile
第一次:没有设置变量KERNELRELEASE,通过已安装模块目录中的符号链接指回内核建立树;然后运行default中的make命令,第二次使用makefile
第二次:已经设置了变量KERNELRELEASE,直接obj-m := hello.o创建模块  回复  更多评论   

# 加载和卸载模块 2010-11-15 17:57 小默

modprobe实现和insmod一样加载模块到内核的功能
不同的是,加载前会检查模块中是否有当前内核中没有定义的symbol,如果有,在模块搜索路径中寻找其它模块是否含有上面的symbol,有的话,自动加载关联模块
insmod对于这种情况,会报错unresolved symbols

查看当前加载模块:
lsmod
cat /proc/modules
  回复  更多评论   

# 如果你的模块需要输出符号给其他模块使用 2010-11-15 18:12 小默

EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);  回复  更多评论   

# 模块参数 2010-11-15 18:40 小默

说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);   回复  更多评论   

# 设备主次编号 2010-11-16 13:24 小默

$ ls -l /dev
...
crw-rw---- 1 vcsa tty 7, 132 Nov 15 17:16 vcsa4
crw-rw---- 1 vcsa tty 7, 133 Nov 15 17:16 vcsa5
crw-rw---- 1 vcsa tty 7, 134 Nov 15 17:16 vcsa6
crw-rw---- 1 root root 10, 63 Nov 15 17:16 vga_arbiter
drwxr-xr-x 2 root root 80 Nov 15 17:16 vg_colorfulgreen
crw-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安装脚本 2010-11-16 13:57 小默

脚本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
  回复  更多评论   

# file_operations结构 2010-11-16 15:24 小默

一些处理文件的回调函数

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 };  回复  更多评论   

# 注册字符设备 2010-11-16 15:25 小默

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 2010-11-27 02:54 小默

system-config-selinux
什么时候改了,汗 //TODO  回复  更多评论   

# read & write 2010-11-30 22:12 小默

// 表示每个设备
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长
};
  回复  更多评论   

# 重定向控制台消息 2010-11-30 22:44 小默

// 重定向控制台消息
// 使用一个参数指定接收消息的控制台的编号
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);
}
  回复  更多评论   

# Implementing files in /proc 2010-12-04 00:42 小默

// 在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时,它们没有区别。。。悲剧。。。  回复  更多评论   

# The seq_file interface 2010-12-04 10:56 小默

// 创建一个虚拟文件,遍历一串数据,这些数据必须返回用户空间。
// 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和puts
int 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);  回复  更多评论   

# strace命令 - debug 2010-12-04 14:12 小默

略 O(∩_∩)O~~  回复  更多评论   

# ldd3_4.5_Debugging System Faults 2010-12-05 14:46 小默

讲了两部分

一、system opps
空指针引用,或者局部变量赋值覆盖了原eip,导致页错误

二、系统挂起 // TODO 看得云里雾里的
死循环等引起
假挂起:鼠标键盘等外设没有响应了,系统实际正常。可以看时间。。。
插入schedule调用防止死循环,作用是允许其他进程从当前进程窃取时间。讲了些弊端,没看懂
sysrq:没看懂
  回复  更多评论   

# re: 盖楼 2010-12-26 06:13 小默

所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。
原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。

原子类型定义:
typedef struct
{
volatile int counter;
}
atomic_t;

volatile修饰字段告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。  回复  更多评论   

# spinlock_t 2010-12-26 16:24 小默

17 typedef struct {
18 volatile unsigned int lock;
19 #ifdef CONFIG_DEBUG_SPINLOCK
20 unsigned magic;
21 #endif
22 } spinlock_t;  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

留言簿(13)

随笔分类(287)

随笔档案(289)

漏洞

搜索

积分与排名

最新评论

阅读排行榜