您的位置:首页 > 运维架构

从用户态的open到内核驱动实现流程

2015-07-27 17:04 429 查看
从用户态的open到内核驱动实现流程

作者:李老师, 华清远见嵌入式学院讲师。

问题来源:

在讲授Linux初级驱动的时候,我发现困惑很多同学的是不真正理解从应用层到我们自己所写的驱动层的调用过程,所以写此文章来大概描述。

首先我们知道,在我们目前的Linux系统中,我们大概共约300左右个系统调用,其中linux/arch/arm/kernel/calls.S列出了所有的系统调用表。

在本文件中记录了所有当前平台系统中所提供的系统调用表,其中第五项就包括:

.long sys_open /* 5 */

---------------------------- -
查看sys_open() 函数,我们看到里面所完成的工作为:
1、查看打开的是否是大文件,如果是的话,置大文件标志位:O_LARGEFILE
2、做do_sys_open()函数调用。
3、检查2的调用返回值ret是否有效。
---------------------------- -

---------------------------- -
查看do_sys_open()函数所完成的工作为:
调用getname() ,getname函数主要功能是在使用文件名之前将其拷贝到内核数据区,正常结束时返回内核分配的空间首地址,出错时返回错误代码。
取得系统中可用的文件描述符fd。
调用do_filp_open()函数,此函数使用了一个数据结构nameidata来描述与文件相关的文件操作。

struct nameidata {
struct dentry *dentry; // 目录数据
struct vfsmount *mnt; // 虚拟文件挂载点数据
struct qstr last; // hash值
unsigned int flags; // 文件操作标识
int last_type; // 类型
unsigned depth;
char *saved_names[MAX_NESTED_LINKS + 1];
union {
struct open_intent open;
} intent; // 专用数据
};
---------------------------- -

---------------------------- -
struct file *do_filp_open(const char * filename, int flags, int mode){
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags + 1) & O_ACCMODE)
namei_flags++; // 如果flags有O_WRONLY,则增加O_RDONLY

error = open_namei(filename, namei_flags, mode, &nd);
// open_namei函数主要执行文件操作的inode部分的打开等操作。
if (!error)
return nameidata_to_filp(nd, flags);
// 把文件的inod相关信息转换成文件结构。
return ERR_PTR(error); // 返回错误代码
}
---------------------------- -

---------------------------- -
我们下面来看这个比较关键的函数:nameidata_to_filp() :
struct file * nameidata_to_filp(struct nameidata *nd, int flags)
{
struct file *filp;

/* Pick up the filp from the open intent */
filp = nd->intent.open.file;
// 把相关 file结构的指针赋予 filp。
/* Has the filesystem initialised the file for us? */
if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
// ***** 关键函数 ***** //
else
path_release(nd);
return filp;
}
---------------------------- -

---------------------------- -
关键函数:__dentry_open() :
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
int flags, struct file *f,
int(*open)(struct inode *, struct file *))
{
......
f->f_pos = 0;
f->f_op = fops_get(inode->i_fop);
// 在这里进行赋值,f->f_op = &def_chr_fops,注意上文inode->i_fop中的赋值。
file_move(f, &inode->i_sb->s_files);

if (!open && f->f_op)
// 在调用__dentry_open时open赋值为空,所以!open为真。
open = f->f_op->open;
// 在这里将open赋为chrdev_open。
if (open) {
error = open(inode, f);
// 这里调用chrdev_open, 参照下文。
if (error)
goto cleanup_all;
......
}
---------------------------- -

---------------------------- -
在函数chrdev_open中(/ fs / char_dev.v) :
int chrdev_open(struct inode * inode, struct file * filp)
{
......
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
// 执行kobj_lookup函数,在cdev_map里寻找相应的inode->i_rdev设备。
// cdev_map是一个256个probe结构组成的数组,用于查找具有相应设备号的设备。
// inode->i_rdev为设备号。

new = container_of(kobj, struct cdev, kobj);
//从kobj的位置倒算出cdev的内存地址,获得包含相应kobj的cdev。

inode->i_cdev = p = new;
// 到这里p已经为我们要的设备cdev了。

filp->f_op = fops_get(p->ops);
/ / 拿到 cdev操作集。
// 至此以后read,write操作都通过file->f_op直接与我们要的设备操作集挂钩了。
......
}
---------------------------- -

到此,系统通过file->f_op 就与我们在设备驱动里面的定义的相关操作联系起来了,我们之前在写驱动实现的功能操作就被系统通过应用层的open 一步一步的调用到我们自己的open跟相关其他的操作了。

这里是用的open系统调用,是linux内核接口函数,不是库函数,返回fd,详细请google, 这个open最终会调用驱动中的open函数(代码流程是这样的open()->sys_open()->filp_open()->dentry_open()->驱动open)

/*
*  linux/arch/arm/kernel/calls.S
*
*  Copyright (C) 1995-2005 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*  This file is included thrice in entry-common.S
*/
/* 0 */		CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */		CALL(sys_open)
CALL(sys_close)
CALL(sys_ni_syscall)		/* was sys_waitpid */
CALL(sys_creat)
CALL(sys_link)
/* 10 */	CALL(sys_unlink)
CALL(sys_execve_wrapper)
CALL(sys_chdir)
CALL(OBSOLETE(sys_time))	/* used by libc4 */
CALL(sys_mknod)
/* 15 */	CALL(sys_chmod)
CALL(sys_lchown16)
CALL(sys_ni_syscall)		/* was sys_break */
CALL(sys_ni_syscall)		/* was sys_stat */
CALL(sys_lseek)
/* 20 */	CALL(sys_getpid)
CALL(sys_mount)
CALL(OBSOLETE(sys_oldumount))	/* used by libc4 */
CALL(sys_setuid16)
CALL(sys_getuid16)
/* 25 */	CALL(OBSOLETE(sys_stime))
CALL(sys_ptrace)
CALL(OBSOLETE(sys_alarm))	/* used by libc4 */
CALL(sys_ni_syscall)		/* was sys_fstat */
CALL(sys_pause)
/* 30 */	CALL(OBSOLETE(sys_utime))	/* used by libc4 */
CALL(sys_ni_syscall)		/* was sys_stty */
CALL(sys_ni_syscall)		/* was sys_getty */
CALL(sys_access)
CALL(sys_nice)
/* 35 */	CALL(sys_ni_syscall)		/* was sys_ftime */
CALL(sys_sync)
CALL(sys_kill)
CALL(sys_rename)
CALL(sys_mkdir)
/* 40 */	CALL(sys_rmdir)
CALL(sys_dup)
CALL(sys_pipe)
CALL(sys_times)
CALL(sys_ni_syscall)		/* was sys_prof */
/* 45 */	CALL(sys_brk)
CALL(sys_setgid16)
CALL(sys_getgid16)
CALL(sys_ni_syscall)		/* was sys_signal */
CALL(sys_geteuid16)
/* 50 */	CALL(sys_getegid16)
CALL(sys_acct)
CALL(sys_umount)
CALL(sys_ni_syscall)		/* was sys_lock */
CALL(sys_ioctl)
/* 55 */	CALL(sys_fcntl)
CALL(sys_ni_syscall)		/* was sys_mpx */
CALL(sys_setpgid)
CALL(sys_ni_syscall)		/* was sys_ulimit */
CALL(sys_ni_syscall)		/* was sys_olduname */
/* 60 */	CALL(sys_umask)
CALL(sys_chroot)
CALL(sys_ustat)
CALL(sys_dup2)
CALL(sys_getppid)
/* 65 */	CALL(sys_getpgrp)
CALL(sys_setsid)
CALL(sys_sigaction)
CALL(sys_ni_syscall)		/* was sys_sgetmask */
CALL(sys_ni_syscall)		/* was sys_ssetmask */
/* 70 */	CALL(sys_setreuid16)
CALL(sys_setregid16)
CALL(sys_sigsuspend)
CALL(sys_sigpending)
CALL(sys_sethostname)
/* 75 */	CALL(sys_setrlimit)
CALL(OBSOLETE(sys_old_getrlimit)) /* used by libc4 */
CALL(sys_getrusage)
CALL(sys_gettimeofday)
CALL(sys_settimeofday)
/* 80 */	CALL(sys_getgroups16)
CALL(sys_setgroups16)
CALL(OBSOLETE(sys_old_select))	/* used by libc4 */
CALL(sys_symlink)
CALL(sys_ni_syscall)		/* was sys_lstat */
/* 85 */	CALL(sys_readlink)
CALL(sys_uselib)
CALL(sys_swapon)
CALL(sys_reboot)
CALL(OBSOLETE(sys_old_readdir))	/* used by libc4 */
/* 90 */	CALL(OBSOLETE(sys_old_mmap))	/* used by libc4 */
CALL(sys_munmap)
CALL(sys_truncate)
CALL(sys_ftruncate)
CALL(sys_fchmod)
/* 95 */	CALL(sys_fchown16)
CALL(sys_getpriority)
CALL(sys_setpriority)
CALL(sys_ni_syscall)		/* was sys_profil */
CALL(sys_statfs)
/* 100 */	CALL(sys_fstatfs)
CALL(sys_ni_syscall)		/* sys_ioperm */
CALL(OBSOLETE(ABI(sys_socketcall, sys_oabi_socketcall)))
CALL(sys_syslog)
CALL(sys_setitimer)
/* 105 */	CALL(sys_getitimer)
CALL(sys_newstat)
CALL(sys_newlstat)
CALL(sys_newfstat)
CALL(sys_ni_syscall)		/* was sys_uname */
/* 110 */	CALL(sys_ni_syscall)		/* was sys_iopl */
CALL(sys_vhangup)
CALL(sys_ni_syscall)
CALL(OBSOLETE(sys_syscall))	/* call a syscall */
CALL(sys_wait4)
/* 115 */	CALL(sys_swapoff)
CALL(sys_sysinfo)
CALL(OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)))
CALL(sys_fsync)
CALL(sys_sigreturn_wrapper)
/* 120 */	CALL(sys_clone_wrapper)
CALL(sys_setdomainname)
CALL(sys_newuname)
CALL(sys_ni_syscall)		/* modify_ldt */
CALL(sys_adjtimex)
/* 125 */	CALL(sys_mprotect)
CALL(sys_sigprocmask)
CALL(sys_ni_syscall)		/* was sys_create_module */
CALL(sys_init_module)
CALL(sys_delete_module)
/* 130 */	CALL(sys_ni_syscall)		/* was sys_get_kernel_syms */
CALL(sys_quotactl)
CALL(sys_getpgid)
CALL(sys_fchdir)
CALL(sys_bdflush)
/* 135 */	CALL(sys_sysfs)
CALL(sys_personality)
CALL(sys_ni_syscall)		/* reserved for afs_syscall */
CALL(sys_setfsuid16)
CALL(sys_setfsgid16)
/* 140 */	CALL(sys_llseek)
CALL(sys_getdents)
CALL(sys_select)
CALL(sys_flock)
CALL(sys_msync)
/* 145 */	CALL(sys_readv)
CALL(sys_writev)
CALL(sys_getsid)
CALL(sys_fdatasync)
CALL(sys_sysctl)
/* 150 */	CALL(sys_mlock)
CALL(sys_munlock)
CALL(sys_mlockall)
CALL(sys_munlockall)
CALL(sys_sched_setparam)
/* 155 */	CALL(sys_sched_getparam)
CALL(sys_sched_setscheduler)
CALL(sys_sched_getscheduler)
CALL(sys_sched_yield)
CALL(sys_sched_get_priority_max)
/* 160 */	CALL(sys_sched_get_priority_min)
CALL(sys_sched_rr_get_interval)
CALL(sys_nanosleep)
CALL(sys_mremap)
CALL(sys_setresuid16)
/* 165 */	CALL(sys_getresuid16)
CALL(sys_ni_syscall)		/* vm86 */
CALL(sys_ni_syscall)		/* was sys_query_module */
CALL(sys_poll)
CALL(sys_ni_syscall)		/* was nfsservctl */
/* 170 */	CALL(sys_setresgid16)
CALL(sys_getresgid16)
CALL(sys_prctl)
CALL(sys_rt_sigreturn_wrapper)
CALL(sys_rt_sigaction)
/* 175 */	CALL(sys_rt_sigprocmask)
CALL(sys_rt_sigpending)
CALL(sys_rt_sigtimedwait)
CALL(sys_rt_sigqueueinfo)
CALL(sys_rt_sigsuspend)
/* 180 */	CALL(ABI(sys_pread64, sys_oabi_pread64))
CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))
CALL(sys_chown16)
CALL(sys_getcwd)
CALL(sys_capget)
/* 185 */	CALL(sys_capset)
CALL(sys_sigaltstack_wrapper)
CALL(sys_sendfile)
CALL(sys_ni_syscall)		/* getpmsg */
CALL(sys_ni_syscall)		/* putpmsg */
/* 190 */	CALL(sys_vfork_wrapper)
CALL(sys_getrlimit)
CALL(sys_mmap2)
CALL(ABI(sys_truncate64, sys_oabi_truncate64))
CALL(ABI(sys_ftruncate64, sys_oabi_ftruncate64))
/* 195 */	CALL(ABI(sys_stat64, sys_oabi_stat64))
CALL(ABI(sys_lstat64, sys_oabi_lstat64))
CALL(ABI(sys_fstat64, sys_oabi_fstat64))
CALL(sys_lchown)
CALL(sys_getuid)
/* 200 */	CALL(sys_getgid)
CALL(sys_geteuid)
CALL(sys_getegid)
CALL(sys_setreuid)
CALL(sys_setregid)
/* 205 */	CALL(sys_getgroups)
CALL(sys_setgroups)
CALL(sys_fchown)
CALL(sys_setresuid)
CALL(sys_getresuid)
/* 210 */	CALL(sys_setresgid)
CALL(sys_getresgid)
CALL(sys_chown)
CALL(sys_setuid)
CALL(sys_setgid)
/* 215 */	CALL(sys_setfsuid)
CALL(sys_setfsgid)
CALL(sys_getdents64)
CALL(sys_pivot_root)
CALL(sys_mincore)
/* 220 */	CALL(sys_madvise)
CALL(ABI(sys_fcntl64, sys_oabi_fcntl64))
CALL(sys_ni_syscall) /* TUX */
CALL(sys_ni_syscall)
CALL(sys_gettid)
/* 225 */	CALL(ABI(sys_readahead, sys_oabi_readahead))
CALL(sys_setxattr)
CALL(sys_lsetxattr)
CALL(sys_fsetxattr)
CALL(sys_getxattr)
/* 230 */	CALL(sys_lgetxattr)
CALL(sys_fgetxattr)
CALL(sys_listxattr)
CALL(sys_llistxattr)
CALL(sys_flistxattr)
/* 235 */	CALL(sys_removexattr)
CALL(sys_lremovexattr)
CALL(sys_fremovexattr)
CALL(sys_tkill)
CALL(sys_sendfile64)
/* 240 */	CALL(sys_futex)
CALL(sys_sched_setaffinity)
CALL(sys_sched_getaffinity)
CALL(sys_io_setup)
CALL(sys_io_destroy)
/* 245 */	CALL(sys_io_getevents)
CALL(sys_io_submit)
CALL(sys_io_cancel)
CALL(sys_exit_group)
CALL(sys_lookup_dcookie)
/* 250 */	CALL(sys_epoll_create)
CALL(ABI(sys_epoll_ctl, sys_oabi_epoll_ctl))
CALL(ABI(sys_epoll_wait, sys_oabi_epoll_wait))
CALL(sys_remap_file_pages)
CALL(sys_ni_syscall)	/* sys_set_thread_area */
/* 255 */	CALL(sys_ni_syscall)	/* sys_get_thread_area */
CALL(sys_set_tid_address)
CALL(sys_timer_create)
CALL(sys_timer_settime)
CALL(sys_timer_gettime)
/* 260 */	CALL(sys_timer_getoverrun)
CALL(sys_timer_delete)
CALL(sys_clock_settime)
CALL(sys_clock_gettime)
CALL(sys_clock_getres)
/* 265 */	CALL(sys_clock_nanosleep)
CALL(sys_statfs64_wrapper)
CALL(sys_fstatfs64_wrapper)
CALL(sys_tgkill)
CALL(sys_utimes)
/* 270 */	CALL(sys_arm_fadvise64_64)
CALL(sys_pciconfig_iobase)
CALL(sys_pciconfig_read)
CALL(sys_pciconfig_write)
CALL(sys_mq_open)
/* 275 */	CALL(sys_mq_unlink)
CALL(sys_mq_timedsend)
CALL(sys_mq_timedreceive)
CALL(sys_mq_notify)
CALL(sys_mq_getsetattr)
/* 280 */	CALL(sys_waitid)
CALL(sys_socket)
CALL(ABI(sys_bind, sys_oabi_bind))
CALL(ABI(sys_connect, sys_oabi_connect))
CALL(sys_listen)
/* 285 */	CALL(sys_accept)
CALL(sys_getsockname)
CALL(sys_getpeername)
CALL(sys_socketpair)
CALL(sys_send)
/* 290 */	CALL(ABI(sys_sendto, sys_oabi_sendto))
CALL(sys_recv)
CALL(sys_recvfrom)
CALL(sys_shutdown)
CALL(sys_setsockopt)
/* 295 */	CALL(sys_getsockopt)
CALL(ABI(sys_sendmsg, sys_oabi_sendmsg))
CALL(sys_recvmsg)
CALL(ABI(sys_semop, sys_oabi_semop))
CALL(sys_semget)
/* 300 */	CALL(sys_semctl)
CALL(sys_msgsnd)
CALL(sys_msgrcv)
CALL(sys_msgget)
CALL(sys_msgctl)
/* 305 */	CALL(sys_shmat)
CALL(sys_shmdt)
CALL(sys_shmget)
CALL(sys_shmctl)
CALL(sys_add_key)
/* 310 */	CALL(sys_request_key)
CALL(sys_keyctl)
CALL(ABI(sys_semtimedop, sys_oabi_semtimedop))
/* vserver */	CALL(sys_ni_syscall)
CALL(sys_ioprio_set)
/* 315 */	CALL(sys_ioprio_get)
CALL(sys_inotify_init)
CALL(sys_inotify_add_watch)
CALL(sys_inotify_rm_watch)
CALL(sys_mbind)
/* 320 */	CALL(sys_get_mempolicy)
CALL(sys_set_mempolicy)
CALL(sys_openat)
CALL(sys_mkdirat)
CALL(sys_mknodat)
/* 325 */	CALL(sys_fchownat)
CALL(sys_futimesat)
CALL(ABI(sys_fstatat64,  sys_oabi_fstatat64))
CALL(sys_unlinkat)
CALL(sys_renameat)
/* 330 */	CALL(sys_linkat)
CALL(sys_symlinkat)
CALL(sys_readlinkat)
CALL(sys_fchmodat)
CALL(sys_faccessat)
/* 335 */	CALL(sys_pselect6)
CALL(sys_ppoll)
CALL(sys_unshare)
CALL(sys_set_robust_list)
CALL(sys_get_robust_list)
/* 340 */	CALL(sys_splice)
CALL(sys_sync_file_range2)
CALL(sys_tee)
CALL(sys_vmsplice)
CALL(sys_move_pages)
/* 345 */	CALL(sys_getcpu)
CALL(sys_epoll_pwait)
CALL(sys_kexec_load)
CALL(sys_utimensat)
CALL(sys_signalfd)
/* 350 */	CALL(sys_timerfd_create)
CALL(sys_eventfd)
CALL(sys_fallocate)
CALL(sys_timerfd_settime)
CALL(sys_timerfd_gettime)
/* 355 */	CALL(sys_signalfd4)
CALL(sys_eventfd2)
CALL(sys_epoll_create1)
CALL(sys_dup3)
CALL(sys_pipe2)
/* 360 */	CALL(sys_inotify_init1)
CALL(sys_preadv)
CALL(sys_pwritev)
CALL(sys_rt_tgsigqueueinfo)
CALL(sys_perf_event_open)
/* 365 */	CALL(sys_recvmmsg)
CALL(sys_accept4)
CALL(sys_fanotify_init)
CALL(sys_fanotify_mark)
CALL(sys_prlimit64)
/* 370 */	CALL(sys_name_to_handle_at)
CALL(sys_open_by_handle_at)
CALL(sys_clock_adjtime)
CALL(sys_syncfs)
CALL(sys_sendmmsg)
/* 375 */	CALL(sys_setns)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
#endif
.rept syscalls_padding
CALL(sys_ni_syscall)
.endr



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: