免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1717 | 回复: 0
打印 上一主题 下一主题

FreeBSD核心入门 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-05-02 12:10 |只看该作者 |倒序浏览

              
                          
                          
                          
翻译    :Liangvy  JU6Linux联盟
E-mail  : liangvy@bigfoot.com  JU6Linux联盟
原著    :FreeBSD核心入门(日文版) 大木敦雄  JU6Linux联盟
JU6Linux联盟
1.1概述  JU6Linux联盟
         FreeBSD可以在PC/AT兼容机器上运行。CPU是i386,i486,Pentium,  JU6Linux联盟
Pentium Pro以及其兼容芯片等。  JU6Linux联盟
1.1.1(略)  JU6Linux联盟
         1,理论地址: 2个13 bit 长+32 bit 长  JU6Linux联盟
         2,线形地址:32 bit 长的空间  JU6Linux联盟
         3,物理地址:32 bit 长的空间  JU6Linux联盟
1.1.2进程的虚拟空间  JU6Linux联盟
         1,text部分  JU6Linux联盟
                 这部分是执行文件的的text领域,也就是机器语言部分,对于这个  JU6Linux联盟
             部分的空间在机器上的物理内存页是共有的,还有,这部分最后的变量  JU6Linux联盟
             地址是etext。  JU6Linux联盟
         2,data和bss部分  JU6Linux联盟
                 执行文件的data部分,也就是初始化的数据段和执行文件指定的内  JU6Linux联盟
             存变量。内存变量在开始的时候以0填充。这一段空间可以读写。它的  JU6Linux联盟
             边界也是以edata和end的地址做结尾。进程的malloc()等内存分配的  JU6Linux联盟
             操作的时候,地址的增加方向向bss空间进行。  JU6Linux联盟
         3,stack部分  JU6Linux联盟
                 也就是进程执行的时候的stack空间,这部分空间(从地址的最高位  JU6Linux联盟
             开始可以伸缩),其对于物理内存,伸缩程度由核心自动执行。  JU6Linux联盟
1.2 kernel的configure  JU6Linux联盟
         freebsd的kernel构成文件在/usr/src/sys的目录下面。下面的子目录做一个  JU6Linux联盟
     介绍。  JU6Linux联盟
         compile 编译核心的目录。  JU6Linux联盟
         conf    configure的目录。  JU6Linux联盟
         ddb     核心调试的sounre code的目录。  JU6Linux联盟
         dev     一部分的drivers的source code的目录。  JU6Linux联盟
         gnu     浮点运算的仿真以及ex2fs文件系统的source code目录。  JU6Linux联盟
         i386    依赖于pc/at机器的目录,以下介绍它的字目录。  JU6Linux联盟
                 apm     suspend一些节电程序。  JU6Linux联盟
                 boot    不是kernel本身的东西,只是一些怎么从开机到读入kernel  JU6Linux联盟
                         的boot program的source code。  JU6Linux联盟
                 conf    config的一些依赖data。  JU6Linux联盟
                 isa     isa bus的驱动程序类的source code。  JU6Linux联盟
                 eisa    eisa bus的驱动程序类的source code。  JU6Linux联盟
                 include 对pc/at的一些include files  JU6Linux联盟
                 i386    对pc/at的一些核心code  JU6Linux联盟
                 ibcs2,linux 使各类的os的执行文件在freebsd上执行的code  JU6Linux联盟
         isofs/cd9660  JU6Linux联盟
                 cd-rom在unix文件系统上操作的的有关code  JU6Linux联盟
         kern    核心code  JU6Linux联盟
         libkern 核心库的source code  JU6Linux联盟
         miscfs  实现unix文件系统的code  JU6Linux联盟
         msdosfs 在unix上操作ms-dos文件系统的有关code  JU6Linux联盟
         net     实现network功能的基本部分code  JU6Linux联盟
         netatalk  JU6Linux联盟
                 实现appletalk network功能code  JU6Linux联盟
         netinet 实现internet network功能的code  JU6Linux联盟
         netipx  实现ipx功能的code  JU6Linux联盟
         netns   实现ns network的code  JU6Linux联盟
         netkey  实现网络加密部分的功能的code  JU6Linux联盟
         nfs     实现nfs服务  JU6Linux联盟
         pc98    对于pc98的支持  JU6Linux联盟
         pccard  对pcmcia的支持  JU6Linux联盟
         pci     对pci bus的驱动程序的source code  JU6Linux联盟
         scsi    对cd-rom,hard disk,tape 等的scsi驱动程序的source code  JU6Linux联盟
         sys     独立于机器体系结构的一部分code  JU6Linux联盟
         ufs     unix file system 的支持code  JU6Linux联盟
         vm      虚拟内存管理的部分  JU6Linux联盟
1.2.1配置的操作----config command  JU6Linux联盟
         在root权限下,config,make实行后,可以得到简单的kernel。  JU6Linux联盟
         *configure file  JU6Linux联盟
         移动到/usr/src/sys/i386/config看看。  JU6Linux联盟
                 GENERIC 从cd-rom等安装freebsd的时候对应于defaule kernel  JU6Linux联盟
                         的配置file  JU6Linux联盟
                 LINT    kernel组合功能的网罗的的配置file  JU6Linux联盟
         下面4个是对配置很有必要的的依赖data file  JU6Linux联盟
                 Makefile.386    config生成的Makefile file的template.  JU6Linux联盟
                 devices.i386    对于unix filesystem可能的block型的device  JU6Linux联盟
                                 名字和major号的对照表  JU6Linux联盟
                 files.i386      记录kernel功能组合的基础上,依赖于pc/at  JU6Linux联盟
                                 机器的功能名称和各种功能实现的source code   JU6Linux联盟
                                 file的名字表。  JU6Linux联盟
                 options.i386    记录配置项目的表。  JU6Linux联盟
         还有,majors.i386是记录对应驱动器的I/O表和major号的一个文件。  JU6Linux联盟
         于核心配置没关系。  JU6Linux联盟
         对于新的i/o设备,如果要做device driver,对pc/at,要在files.i386(没  JU6Linux联盟
         有的话在/usr/src/sys/conf/files)追加相应的行,不然就不能把它加入  JU6Linux联盟
         到核心里面。  JU6Linux联盟
         追加的格式为  JU6Linux联盟
                 相对path名      optional        device-name device-driver  JU6Linux联盟
JU6Linux联盟
         对于配置文件,首先,要设置cpu,bus,i/o设备,多少用户等。例如对于GENERIC  JU6Linux联盟
                 machine "i386"  JU6Linux联盟
                 cpu     "I386_CPU"  JU6Linux联盟
                 cpu     "I486_CPU"  JU6Linux联盟
                 cpu     "I586_CPU"  JU6Linux联盟
                 cpu     "I686_COU"  JU6Linux联盟
                 ident   GENERIC  JU6Linux联盟
                 maxusers 10  JU6Linux联盟
         当作为server时候,应该把最大user设置大一点,以提高系统性能。  JU6Linux联盟
         下一步,指定options,对于GENERIC  JU6Linux联盟
                 options MATH_EMULATE    #support for x87 emulation  JU6Linux联盟
                 options INET            #interNETworing  JU6Linux联盟
                 options FFS             #Berkeley Fast Filesystem  JU6Linux联盟
                 options NFS             #Network Filesystem  JU6Linux联盟
                 ......  JU6Linux联盟
         options指定的名字xxx等,如果在/usr/src/sys/conf/options或者在  JU6Linux联盟
         /usr/src/sys/i386/conf/options.i386中记载的时候,应在对应的opt_XXX.h中写入  JU6Linux联盟
         。没有的话,作为cc命令行的参数定义"-D"在Makefile里面追加。对于XXX的格式应该  JU6Linux联盟
         是  JU6Linux联盟
                 相对path名      optional xxx  JU6Linux联盟
         下一步,对于config  JU6Linux联盟
                 config  kernel  root    on wd0  JU6Linux联盟
                 (略)  JU6Linux联盟
         配置文件剩下的部分应该是bus,i/o等一些硬件配置,一般有controller,device,  JU6Linux联盟
         disk,tape四类。例如  JU6Linux联盟
                 controller      isa0  JU6Linux联盟
                 controller      eisa0  JU6Linux联盟
                 controller      pci0  JU6Linux联盟
         等。  JU6Linux联盟
         第二层的device和controller,记录了一些bus设备的连接。ISA的情况是  JU6Linux联盟
                 device          device_name     at isa? 参数  JU6Linux联盟
                 controller      controller_name at isa? 参数  JU6Linux联盟
         EISA和PCI就相对简单一点:  JU6Linux联盟
                 device          device_name  JU6Linux联盟
                 controller      controller_name  JU6Linux联盟
         device_name里指定的设备名是,串口,并口,网络等装置。  JU6Linux联盟
         第三层的disk和tape为  JU6Linux联盟
                 disk    disk_name at 控制设备名 drive 号  JU6Linux联盟
                 tape    tape_name at 控制设备名 drive 号  JU6Linux联盟
         SCSI接口卡作为第二层的控制装置记录的同时  JU6Linux联盟
                 controller      scbus0  JU6Linux联盟
         作为通用的scsi控制设备。因此,对于它的hard disk,tape,cd-rom,mo设备,有  JU6Linux联盟
                 device  sd0  JU6Linux联盟
                 device  st0  JU6Linux联盟
                 device  cd0  JU6Linux联盟
                 device  od0  JU6Linux联盟
         等,它可以自动识别和分配号码。  JU6Linux联盟
         对于其他的scsi设备,有  JU6Linux联盟
                 device  pt0     at scbus?  JU6Linux联盟
         这些东西(bus,scsi,i/o),在生成的ioconf.c以及相应的include中有反映。  JU6Linux联盟
         configure的最后,不是一些物理设备,而是kernel内部的一些软设置  JU6Linux联盟
                 pseudo-device   理论设备名  JU6Linux联盟
         首先,要考虑以下两个设备:  JU6Linux联盟
                 pseudo-device   pty     16      #ttys - can go as high as 256  JU6Linux联盟
                 pseudo-device   log             #syslog interface (/dev/klog)  JU6Linux联盟
         network使用的场合,应该有下面两个  JU6Linux联盟
                 pseudo-device   loop  JU6Linux联盟
                 pseudo-device   ether  JU6Linux联盟
         这种情况下,最好有  JU6Linux联盟
                 pseudo-device   bpfilter 4      #berkeley packet filter  JU6Linux联盟
                 pseudo-device   tun      1      #Tunnel driver ( PPP)  JU6Linux联盟
         想做floppy的时候,要  JU6Linux联盟
                 pseudo-device   vn      #Vnode driver ( turns a file into a device)  JU6Linux联盟
         (代续) JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨(翻译)2 JU6Linux联盟
JU6Linux联盟
1.3  FreeBSD boot之前的工作  JU6Linux联盟
1.3.1pc/at机器的boot顺序  JU6Linux联盟
             hard disk的最前面的一个block(512byte),叫做master boot recorder(MBR).这  JU6Linux联盟
         里有启动限定的program和分区的信息。分区信息是指对于一个区是16byte长,最多  JU6Linux联盟
         只能有4个区。16byte的内容是,分区哪里开始,哪里结束。哪种os,能否启动等。对  JU6Linux联盟
         于freebsd,安装的时候向MBR写入了boot easy.  JU6Linux联盟
         磁盘的结构如下图表示:  JU6Linux联盟
                 block Number  JU6Linux联盟
           #0    #1      #2      ...     #14     #15     #16     #17  JU6Linux联盟
         -------------------------------------------------------------  JU6Linux联盟
                 disk                            no used   JU6Linux联盟
                 label  JU6Linux联盟
         -------------------------------------------------------------  JU6Linux联盟
         ;|;|       |JU6Linux联盟
JU6Linux联盟
         FreeBSD用的block#0--#14的15个block里面,含有读入freebsd的程序,bootease  JU6Linux联盟
         只在block#0里面,在15个block中并没有。它的作用  JU6Linux联盟
                 。读入mbr,找freebsd的分区  JU6Linux联盟
                 。读入最初的15个block,到物理内存中0x0001000  JU6Linux联盟
                 。跳转到相当于block#2的内存位置  JU6Linux联盟
         然后,屏幕表示为:  JU6Linux联盟
                 。。。  JU6Linux联盟
                 。。。  JU6Linux联盟
                 boot:  JU6Linux联盟
         (参数说明略)  JU6Linux联盟
         它的source是/usr/src/sys/i386/boot/biosboot,make之后,生成两个文件:  JU6Linux联盟
         boot1,boot2分别写入block#1,block#2--#14中。  JU6Linux联盟
         一般,一个物理的unix分区理论上可以有8个,比如swap,unix system等。  JU6Linux联盟
         boot2部分是boot program,它读入kernel的文件名和option。然后  JU6Linux联盟
                 。找boot label指定的分区。  JU6Linux联盟
                 。构造unix filesystem,找指定的kernel  JU6Linux联盟
                 。从开始执行文件,text,data的顺序向物理内存读入。对bss清零。  JU6Linux联盟
                 。以option的选择,向开始位置跳转。  JU6Linux联盟
1.3.2  kernel的初始化动作  JU6Linux联盟
             boot program执行之后,转向kernel的text段开始进行初始化,即先执行  JU6Linux联盟
         locore.s的text段。因此是虚拟内存还没有发生作用,locore.s的开始部分必  JU6Linux联盟
         须对offset进行补正。locore.s的作用是  JU6Linux联盟
                 。保存从boot program过来的option  JU6Linux联盟
                 。设定虚拟的stacker  JU6Linux联盟
                 。检测cpu的module  JU6Linux联盟
                 。对自己的bss空间进行0初始化  JU6Linux联盟
                 。为使虚拟内存工作,要保证最少的管理信息。然后是虚拟空间动作。  JU6Linux联盟
         也就是,调用cpu有强的依赖关系的过程init386()(@i386/i386/machdep.c),  JU6Linux联盟
         然后进行kernel内的管理信息初始化,i/o设备的登记,生成4个kernel process  JU6Linux联盟
         ,再调用main()(@kern/init_main.c)。当main()返回locore.s时,应该有如下  JU6Linux联盟
         5个进程:  JU6Linux联盟
                 PID     TT      STAT    TIME    COMMAND  JU6Linux联盟
                 0       ??      DLs     0:00.17 (swapper)  JU6Linux联盟
                 1       ??      Is      0:00.19 /sbin/init --  JU6Linux联盟
                 2       ??      DL      0:56.60 (pagedaemon)  JU6Linux联盟
                 3       ??      DL      0:00.06 (vmdaemon)  JU6Linux联盟
                 4       ??      DL      6:07.65 (updata)  JU6Linux联盟
         从locore.s返回到process #1,/sbin/init开始动作,然后转向freebsd的普通  JU6Linux联盟
         动作。  JU6Linux联盟
         init386()和main()的处理大致如下:  JU6Linux联盟
                 。init386()  JU6Linux联盟
                 GDT和LDT,IDT,task stages处理的初始化,例外处理等locore.s没做的  JU6Linux联盟
                 事情,虚拟内存初始化。然后,根据boot program的参数,增加物理内  JU6Linux联盟
                 存page数。然后,作成process #0的雏形。  JU6Linux联盟
                 。main()  JU6Linux联盟
                 逐步调用构成kernel模块的的初始化部分。 JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨(翻译)3 JU6Linux联盟
JU6Linux联盟
(续上,liangvy.icewolf.leon翻译)  JU6Linux联盟
JU6Linux联盟
但是,kernel构成的各个模块的初始化子程序一个个的列举出来运行很显然是  JU6Linux联盟
不行的。通常是利用时间连表的技能来运行它(ld command)。也就是,程序  JU6Linux联盟
是以很多个source分开编译和联结。相同的模块名字就对应于相同的地址来进  JU6Linux联盟
行调用。它在时间链表里面自动调节执行。  JU6Linux联盟
初始化时候,main()函数要call的模块利用在sys/kernel.h里面定义的宏  JU6Linux联盟
SYSINIT()和SYSINIT_KT()进行登记。这样,kernel在link的时候,ld命令就  JU6Linux联盟
能够得到那些信息和进行配置列表。这个列表就是kernel的组成模块的初始化  JU6Linux联盟
routine的登记。检查source,  JU6Linux联盟
就可以找到初始化routine的部分。  JU6Linux联盟
         如表:  JU6Linux联盟
         print_caddr_t(copyright)                kern/init_main.c  JU6Linux联盟
         vm_men_init(NULL)                       vm/vm_init.c  JU6Linux联盟
         syctl_order(&sysctl_)                   kern/kern_sysctl.c  JU6Linux联盟
         kmemnit(NULL)                           kern/kern_malloc.c  JU6Linux联盟
         fpu_init(NULL)                          i386/i386/math_emulate.c  JU6Linux联盟
         cpu_startup(NULL)                       i386/i386/machdep.c  JU6Linux联盟
         gnufpu_init(NULL)                       miscfs/devfs/devfs_tree.c  JU6Linux联盟
         ...  JU6Linux联盟
         各个device的major号与处理routine的登记  (major循序号)  JU6Linux联盟
         ...  JU6Linux联盟
         configure(NULL)                         i386/i386/autoconf.c  JU6Linux联盟
         proc0_init(NULL)                        kern/init_main.c  JU6Linux联盟
         rqinit(NULL)                            kern/kern_synch.c  JU6Linux联盟
         vm_init_limits(&proc0)                  vm/vm_glue.c  JU6Linux联盟
         vfsinit(NULL)                           kern/vfs_init.c  JU6Linux联盟
         elf_insert_brand_entry(&linux_brand)    i386/linux/linux_sysvec.c  JU6Linux联盟
         initclocks(NULL)                        kern/kern_clock.c  JU6Linux联盟
         mbinit(NULL)                            kern/uipc_mbuf.c  JU6Linux联盟
         clst_init(NULL)                         kern/tty_subr.c  JU6Linux联盟
         shmnit(NULL)                            kern/sysv_shm.c  JU6Linux联盟
         seminit(NULL)                           kern/sysv_sem.c  JU6Linux联盟
         msginit(NULL)                           kern/sysc_msg.c  JU6Linux联盟
         kludge_splimp(&x_save_spl)              kern/uipc_domain.c  JU6Linux联盟
         ifinit(NULL)                            net/if.c  JU6Linux联盟
         domaininit(NULL)                        kern/uipc_domain.c  JU6Linux联盟
         kludge_splx(&x_save_spl)                kern/uipc_domain.c  JU6Linux联盟
         kmstartup(NULL)                         kern/subr_prof.c  JU6Linux联盟
         sched_setup(NULL)                       kern/init_main.c  JU6Linux联盟
         xxx_vfs_mountroot(NULL)                 kern/init_main.c  JU6Linux联盟
         xxx_vfs_root_fdtab(NULL)                kern/init_main.c  JU6Linux联盟
         swapinit(NULL)                          kern/init_main.c  JU6Linux联盟
         proc0_post(NULL)                        kern/init_main.c  JU6Linux联盟
         kthread_init(NULL)                      kern/init_main.c||  JU6Linux联盟
         kproc_start(&page_kp)                   vm/vm_pageout.c||  JU6Linux联盟
         kproc_start(&vm_kp)                     vm/vm_pageout.c||  JU6Linux联盟
         kproc_start(&up_kp)                     kern/vfs_bio.c||  JU6Linux联盟
         scheduler(NULL)                         vm/vm_glue.c  JU6Linux联盟
(||表示有多个程序)  JU6Linux联盟
proc-post()被呼叫后,main()就是在对应process 0 的kernel的虚拟  JU6Linux联盟
内存里动作。kthread_init(),kproc_start(&page_kp),kproc_start(&vm_kp)  JU6Linux联盟
,kproc_start(&up_kp)等这几个进程,在fork()后相继被调用。它就是相  JU6Linux联盟
应的进程1,2,3,4等。  JU6Linux联盟
除process 1 以外,其他的进程调用并不返回调用的地址。(也就是,main()  JU6Linux联盟
的跟随执行后,并不返回locore.s)。对于process #1的kernel的虚拟内存,  JU6Linux联盟
在kthread_init()返回后,main()的跟随就完了,回到locore.s后,process #1  JU6Linux联盟
的进程空间的配置文件/sbin/init就被执行。  JU6Linux联盟
main()在process #0对应的kernel虚拟内存运行后,进入时间链表scheduler()。  JU6Linux联盟
这个并不返回。那现在就有五个进程了。  JU6Linux联盟
然后,fork() 的调用在下面说明。  JU6Linux联盟
         1,分配process ID,保证struct proc()用的空间。  JU6Linux联盟
         2,复制父亲的process的虚拟内存空间,作成物理内存的变换表。对  JU6Linux联盟
            应两个进程,采用相对应的物理内存表。  JU6Linux联盟
         3,给回父亲的struct proc和struct user,然后对子进程的struct和  JU6Linux联盟
            struct user进行初始化。  JU6Linux联盟
         4,kernel的stacker也进行复制。  JU6Linux联盟
         5,返回父进程后,标记生成的子进程。完成处理。  JU6Linux联盟
但是,process #0 -- 4 这五个进程的虚拟内存里面什么都没有。这些是核心  JU6Linux联盟
进程的特殊部分。进程0,2,3是调节系统存在的进程的执行优先级,监视物理  JU6Linux联盟
内存的不足,如果不够就使用swap区进行交换。进程4的作用就是定期调查核心  JU6Linux联盟
的unix文件系统的管理信息与驱动程序的管理信息的一致性,使它的信息一直  JU6Linux联盟
是最新的。  JU6Linux联盟
JU6Linux联盟
1.3.3 /sbin/init  JU6Linux联盟
从kernel里面看,/sbin/init就是单一的进程空间里动作,与一般的  JU6Linux联盟
user program一样,提供user使用的unix文件系统的环境的服务。  JU6Linux联盟
核心启动后最初的动作就是/sbin/init。作用如下:  JU6Linux联盟
         。确保file system的一致性,进行mount。  JU6Linux联盟
         。之后,network的设定和各种daemon的启动。  JU6Linux联盟
         。监视终端的login的配置和动作状态。这个动作完了后(logout),  JU6Linux联盟
           修改和配置 login。  JU6Linux联盟
也就是说,如果没有它,用户就不能使用unix文件系统。还有就是,如果boot   JU6Linux联盟
progam参数指定-s的话,它就过渡到单一的用户模式。相对来说,普通的用户  JU6Linux联盟
模式也就是multi模式。为了使普通用户能够使用系统,/sbin/init的参考文件  JU6Linux联盟
主要在/etc目录里放着。主要就是运行/etc/rc文件对系统进行初始化。  JU6Linux联盟
/etc/rc文件的主要内容和作用如下:  JU6Linux联盟
         。使系统能够使用swap区  JU6Linux联盟
         。检查/etc/fstab,检查它的连贯性,如果有问题就转到单一的用户模式  JU6Linux联盟
         。mount nfs以外的文件系统  JU6Linux联盟
         。读入network 的设定和各种daemon进程的设定情况的记录文件  JU6Linux联盟
           /etc/c.conf,这个内容作为shell script的变量设定,以下的就是  JU6Linux联盟
           各个shell的动作调整  JU6Linux联盟
         。serial的初始化(/etc/rc.serial)  JU6Linux联盟
         。运行PCMCIA卡的插拔监控守护进程(/etc/rc.pccard)  JU6Linux联盟
         。network的部分初始化(/etc/rc.network)  JU6Linux联盟
         。如果有nfs的时候就进行mount操作  JU6Linux联盟
         。network的最终初始化(/etc/rc.network:启动和entwork有关的daemon)  JU6Linux联盟
         。共有库的有关信息的初始化  JU6Linux联盟
         。intd,lpd,sendmail的启动  JU6Linux联盟
         。依赖系统的一些初始化进程  JU6Linux联盟
/etc/rc的处理完了后,/sbin/init就对/etc/ttys等记述的一些终端的用户login进行  JU6Linux联盟
监视。对于这个,/etc/ttys里指定的终端,fork()后的进程里:  JU6Linux联盟
         。exec()指定的程序(普通的情况是/usr/libexec/getty)  JU6Linux联盟
         。/usr/libexec/getty进行终端速度等的设定。提示login:,等待用户输入  JU6Linux联盟
         。用户输入后,名字作为参数exec() /etc/bin/login  JU6Linux联盟
         。/usr/bin/login就提示出passwd:,等待用户的输入  JU6Linux联盟
         。准备user名和passwd,对输入的用户名进行确定,正确的话就exec()用户  JU6Linux联盟
           shell  JU6Linux联盟
                   JU6Linux联盟
下图就是/sbin/init的监视进程图:  JU6Linux联盟
JU6Linux联盟
process #1  JU6Linux联盟
           -------------------------------------------------------->;  JU6Linux联盟
/sbin/init |                                         ^       \  JU6Linux联盟
            | fork()                                  |        | fork()  JU6Linux联盟
            + exec()  exec()     exec()               |        | exec()  JU6Linux联盟
process #n |---------->;+--------->;+------------------*+--------  JU6Linux联盟
               getty   login      user的login shell       process #m  JU6Linux联盟
JU6Linux联盟
(第一章完,下一章介绍文件系统和驱动程序,liangvy) JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨.4.驱动程序篇 JU6Linux联盟
JU6Linux联盟
翻译:liangvy           liangvy@bigfoot.com     icewolf.leon :-)  JU6Linux联盟
版权所有,可以转贴  JU6Linux联盟
JU6Linux联盟
                         第二章  文件系统和设备驱动程序  JU6Linux联盟
JU6Linux联盟
     这章主要介绍文件系统和特殊的设备文件以及它们的对应关系。  JU6Linux联盟
JU6Linux联盟
2..1 disk上的 unix file system 的基本知识  JU6Linux联盟
     首先介绍一下经典的unix file system的思维方法。  JU6Linux联盟
     disk 的 partition就是从0到512byte的连续长度的block的东西。这里有  JU6Linux联盟
         1.file/directory有关的固定长度的信息,i-node  JU6Linux联盟
         2.file/directory的本体,data block  JU6Linux联盟
     的两样不同的东西。partition的前面的附近块(block#16 ,1--15用于boot   JU6Linux联盟
     program :-))就是i-node,data block用的领域等等的开始位置(block号)  JU6Linux联盟
     和长度(block数量)等的记录,叫做super-block。一个block可能的容量只  JU6Linux联盟
     能有固定数目的i-node,所以如果分配了固定的i-node,收录了节点号和节  JU6Linux联盟
     点的块号和块的位置就可以计算出来。  JU6Linux联盟
         i-node就是  JU6Linux联盟
             。表明i-node的种类(file ,direstory,device等)  JU6Linux联盟
             。这个节点参考的次数(目录数)  JU6Linux联盟
             。参考,作成,变化的时间  JU6Linux联盟
             。权限  JU6Linux联盟
             。所有者的user id / group id  JU6Linux联盟
             。本体的长度  JU6Linux联盟
             。收集本体的data block的block号码的固定长度的对应表  JU6Linux联盟
               的一些记录。因为data block的对应表是固定的关系,比  JU6Linux联盟
               如10个,最长就能够作出512*10=5k为止的file。  JU6Linux联盟
JU6Linux联盟
    当文件比块大的时候,unix就采用成组联结的方式对它们进行管理。就是  JU6Linux联盟
    把所有的空闲块以一定数目为一组的方法作成单向空闲块stacker。  JU6Linux联盟
    特别地,文件的从先头的byte位置开始和i-node内的对应表有着密切的关系。  JU6Linux联盟
    而且,对于i-node的输入输出,可以对应指定位置的数据块进行读写。重要  JU6Linux联盟
    的是,核心可以依照这个管理表对io装置进行管理。  JU6Linux联盟
         unix对io设备的操作也是作为(特殊)文件进行的。对于用i-node进行  JU6Linux联盟
    描述的io设备,data block数据块的对应表就没必要了。这个部分的io设备  JU6Linux联盟
    的识别就通过device号码来进行。向这些对i-node进行输入输出处理的,  JU6Linux联盟
    就又设备驱动号区别,来进行device driver驱动。  JU6Linux联盟
         那么,节点怎么的进行查找呢?partition的最初的目录(根目录)就是,  JU6Linux联盟
    从第二个i-node开始,一个一个顺着节点进行查找。  JU6Linux联盟
         比如,对于目录/uuu/vvv/.../yyy/zzz的查找方式,有这种关系:  JU6Linux联盟
         。i-node #2 所存放的是root directory。读入它的本体,就可以找到  JU6Linux联盟
           相应的uuu所对应的i-node。  JU6Linux联盟
         。读入这个i-node所存放的directory的i-node本体,找到相应的vvv节点。  JU6Linux联盟
           ......  JU6Linux联盟
           查找对应yyy的节点  JU6Linux联盟
         。读入这个节点的本体信息,这里包含目录本题的内容,这样就可以找到  JU6Linux联盟
           zzz所对应的i-node。  JU6Linux联盟
         目录里面由于记录了对应文件名的节点号,所以,也有可能同一个节点号  JU6Linux联盟
     根据文件名不一样,就可以找到不同的目录名。这就是硬连接(hard link).  JU6Linux联盟
     但是,节点号有只存在于节点所在的分区的含义,所以,不同的分区,  JU6Linux联盟
     这种硬连接就不具有存在的可能性。为了解决这个矛盾,就有了符号连接  JU6Linux联盟
     (symble link)的说法。当节点是输入符号连接的时候,符号连接就包含  JU6Linux联盟
     了这个节点的data block所指定的路径名。但是,空连接和loop连接这种  JU6Linux联盟
     情况也是允许的,所以核心要指定循环连接的最大次数。具体由参数  JU6Linux联盟
     MAXSYMLINKS(@sys/param.h)指定。  JU6Linux联盟
         这样,多个分区建立一个文件系统就有可能了。启动核心的分区作为一个  JU6Linux联盟
    已存的文件系统,其他的分区就嫁接到目录层上面。这个操作过程就是mount。  JU6Linux联盟
    利用mount指令,就可以实现上面的操作。但是,mount之前的目录,在mount后  JU6Linux联盟
    就给屏蔽了,直到mount结束,那些目录就可以再现。  JU6Linux联盟
         以上就是经典的unix文件系统理论。但是,对于读入了i-node,就去读  JU6Linux联盟
    data block ,这种情况,对于一个比较大的分区,硬盘磁头向disk head的距  JU6Linux联盟
    离就太大了。总的来说,访问时间就会变长。在这里有一些指导思想:  JU6Linux联盟
         。分区要比较小,多分小区  JU6Linux联盟
         。了解超级块的地位,超级块记录了分区的信息,考虑由于介质的原因而  JU6Linux联盟
           使这个超级块造成损害,所以,在分区内部就必须为它准备多几个拷贝。  JU6Linux联盟
         。目录和它下层的文件,要在相同的领域内放置。  JU6Linux联盟
         。确保单位data block要比磁盘的block大。  JU6Linux联盟
         考虑了一些东西后,经过改良标准,freebsd就采用一个叫做FFS的文件系  JU6Linux联盟
    统(Fast File System),但这只是i-node领域/data领域的配置方法的变化,基  JU6Linux联盟
    本的考虑方法并没有变。对磁盘分区进行文件系统的构造的初始化由命令newfs  JU6Linux联盟
    提供。看看它的source就知道怎么配置的了。其他的构造(......)对应于kernel  JU6Linux联盟
    的source,对于构成boot program的文件disk.c和sys.c(@i386/boot/biosboot)  JU6Linux联盟
    比较简单易懂(单纯性)。  JU6Linux联盟
         上面讲述的i-node对disk的partition的记录形式,详细的(source)在  JU6Linux联盟
    struct dinode(@ufs/ufs/dinode.h)里面有。在核心内部使用的,包含这个东西  JU6Linux联盟
    的是struct inode(@ufs/ufs.inode.h)。  JU6Linux联盟
JU6Linux联盟
         描述io设备的文件叫特殊文件(special file),他对应的i-node有两个种  JU6Linux联盟
    类:  JU6Linux联盟
         。块型(block)  JU6Linux联盟
           和装置的固有的数据记录的单位(大多数的情况是512byte)无关。读写  JU6Linux联盟
           的最小单位是1byte,可以在任意的场所里任意长度的data。核心对各个  JU6Linux联盟
           block型的特殊文件进行固定的记录单位长度(倍数)进行缓冲(buffer)  JU6Linux联盟
           管理,这样就可以处理任意长度的读写了.  JU6Linux联盟
         。文字型(char)  JU6Linux联盟
           读写的基本单位是,受到装置固有的date记录单位长的限定。没有block  JU6Linux联盟
           型的缓冲管理,对应于装置的物理特性,读写属于专用。或者说,是读写  JU6Linux联盟
           两用。  JU6Linux联盟
         除了网络接口之外,io装置可以全部分为文字型和块型两个大类。总的来说,  JU6Linux联盟
    磁盘操作的两样都用,但其他的io装置只有文字型。还有就是一些没对应物理设  JU6Linux联盟
    备的kernel modules提供的虚拟设备也有,它们对应着文字型的特殊文件。特殊  JU6Linux联盟
    文件习惯放在目录/dev里面。  JU6Linux联盟
JU6Linux联盟
         对于特殊设备文件的i-node有block和chat两个类,设备通过驱动号进行记录  JU6Linux联盟
    。通过这些,就可以识别device driver。device 号就是major号(8bit)(主设备  JU6Linux联盟
   号)和minor号(24bit)(辅助设备号),device driver的识别就是由major的不  JU6Linux联盟
   一样而区别。而且呢,block型,char型的等等可能存在最大数目是256种类。一般的  JU6Linux联盟
   情况,同种类的设备不同数目的区别就是通过辅助设备号进行识别。实际上,对于  JU6Linux联盟
   disk的特殊文件,有disk/slide/partition表示法,而且,文字型,块型等的特殊  JU6Linux联盟
   设备文件也存在。以下就是一个ide硬盘的的文字型特殊设备文件的例子:  JU6Linux联盟
         /dev/rwd0               1台ide的硬盘  JU6Linux联盟
         /dev/rwd0s1             1台ide的硬盘的slide #1  JU6Linux联盟
         /dev/rwd0s2             1台ide的硬盘的slide #2  JU6Linux联盟
         /dev/rwd0s2a            slide #2的partition a  JU6Linux联盟
         /dev/rwd0s2b            slide #2的partition b  JU6Linux联盟
         ...  JU6Linux联盟
         /dev/rwd0s3             1台的ide的硬盘的slide #3  JU6Linux联盟
JU6Linux联盟
         如果把rwd换成wd,对应的就是block型的特殊设备文件了。  JU6Linux联盟
         对于磁盘,有如下的使用方法:  JU6Linux联盟
         。对于slide的文字型特殊文件  JU6Linux联盟
                 读写disk label时候使用(disklabel command)  JU6Linux联盟
         。对于对应的partition的文字型特殊文件  JU6Linux联盟
                 在分区上建立unix文件系统时候(newfs command),文件系统修复,  JU6Linux联盟
                 检查(fsck)时候使用  JU6Linux联盟
         。对于partition的block型的特殊文件  JU6Linux联盟
                 作为mount命令的参数使用  JU6Linux联盟
         (下一节介绍虚拟文件系统和v-node,要休息了:-) ) JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨.5.驱动程序篇 JU6Linux联盟
JU6Linux联盟
2.2    虚拟文件系统和v-node  JU6Linux联盟
         FreeBSD在disk上的除了ffs以外还可以操作各种各样的文件系统。主要的如  JU6Linux联盟
下:  JU6Linux联盟
         。cd9660  JU6Linux联盟
           可以对ISO9660形式的cd-rom的目录/文件构造的文件系统进行mount,  JU6Linux联盟
           locate等目录层的操作  JU6Linux联盟
         。ms-dos  JU6Linux联盟
           对ms-dos文件系统进行目录层次的mount,定位等操作  JU6Linux联盟
         。mfs  JU6Linux联盟
           通过使用虚拟内存对swap区的一部分进行unix文件系统的构造,定位  JU6Linux联盟
           作为目录的一部分进行读写  JU6Linux联盟
         。nfs  JU6Linux联盟
           由nfs server提供的remote目录级进行mount,定位的目录层操作。  JU6Linux联盟
         。null  JU6Linux联盟
           对已经存在的目录层的使用别名  JU6Linux联盟
         。union  JU6Linux联盟
           对已有的目录A(上层)在下层目录B上进行重叠 (不大理解这的意思  JU6Linux联盟
           ,大概是在下层目录里面又嫁接了上层目录的意思:译者)。文件名的查  JU6Linux联盟
           找由上层优先进行。没有的话就转道下层。如果对下层的文件进行写操作  JU6Linux联盟
           ,它的拷贝就在上层上进行。举例说明,作业目录在上层,但cd-rom的源  JU6Linux联盟
           在下层,两个目录重叠,那么编译source的时候,就相当方便了。  JU6Linux联盟
         。procfs  JU6Linux联盟
           对于进程号的目录作成mount point。通过文件名对各个目录的进程进行  JU6Linux联盟
           控制。  JU6Linux联盟
         。kernfs  JU6Linux联盟
           为了对动作中的kernel有关的信息进行参考,而作成的mount  point  JU6Linux联盟
         。fdesc  JU6Linux联盟
           对于各个进程,用它所打开的文件柄对应的文件作成的mount point  JU6Linux联盟
           JU6Linux联盟
         实际上,在核心内部,为了对它们进行统一操作,就对文件系统和v-node  JU6Linux联盟
进行抽象化,实际的处理过程就是调用各类的文件系统的模块进行处理。  JU6Linux联盟
JU6Linux联盟
2.2.1对虚拟文件系统的操作  JU6Linux联盟
         各个文件系统可以提供的操作的一览如下,它在struct vfsops  JU6Linux联盟
(@sys/mount.h)里面定义:  JU6Linux联盟
         。对文件系统进行mount的操作  JU6Linux联盟
         。本文件系统的开始动作的操作  JU6Linux联盟
         。本文件系统的umount操作  JU6Linux联盟
         。表达文件系统的根的v-node的查找操作  JU6Linux联盟
         。对一般用户的权限控制  JU6Linux联盟
         。取得文件系统的状态  JU6Linux联盟
         。内存内的管理信息写入介质中  JU6Linux联盟
         。从i-node到v-node的取得操作  JU6Linux联盟
         。v-node和nfs的文件柄的相互变换的操作  JU6Linux联盟
         。文件系统实际的模块的初始化  JU6Linux联盟
JU6Linux联盟
对于文件系统,各个实际的操作routine在vfsops的形式提供准备工作。各个文件系  JU6Linux联盟
统的vfsops,在以下的表里的source进行定义:  JU6Linux联盟
JU6Linux联盟
--------------------------------------------------------------  JU6Linux联盟
file system     vfsops的定义    source  JU6Linux联盟
--------------------------------------------------------------  JU6Linux联盟
ufs             ufs_vfsops      ufs/ffs/ffs_vfsops.c  JU6Linux联盟
cd9660          cd9660_vfsops   isofs/cd9660/cd9660_vfsops.c  JU6Linux联盟
msdos           msdosfs_vfsops  msdosfs/msdosfs_vfsops.c  JU6Linux联盟
mfs             mfs_vfsops      ufs/mfs/mfs_vfops.c  JU6Linux联盟
nfs             nfs_vfsops      nfs/nfs_vfsops.c  JU6Linux联盟
null            null_vfsops     miscfs/nullfs/null_vfsops.c  JU6Linux联盟
nuion           union_vfsops    miscfs/union/union_vfsops.c  JU6Linux联盟
procfs          procfs_vfsops   miscfs/procfs/procfs_vfsops.c  JU6Linux联盟
kernfs          kernfs_vfsops   miscfs/kernfs/kernfs_vfsops.c  JU6Linux联盟
fdesc           fdesc_vfsops    miscfs/fdesc/fdesc_vfsops.c  JU6Linux联盟
devfs           devfs_vfsops    miscfs/devfs/devfs_vfsops.c  JU6Linux联盟
ext2fs          ext2fs_vfsops   gnu/ext2fs/ext2_vfsops.c  JU6Linux联盟
lfs             lfs_vfsops      ufs/lfs/lfs_vfsops.c  JU6Linux联盟
portal          portal_vfsops   miscfs/portal.portal_vfsops.c  JU6Linux联盟
umap            umap_vfsops     miscfs/umapfs/umap_vfsops.c  JU6Linux联盟
---------------------------------------------------------------  JU6Linux联盟
这些就是文件系统的实际模块(*_vfsops.c),文件系统名称,文件系统号等等  JU6Linux联盟
在struct vfsconf(@sys/mount.h)里面汇总,各个模块里用宏VFS_SET()进入核  JU6Linux联盟
心。  JU6Linux联盟
         根据main()(@kern/init_main.c),在kernel初始化的过程中,vfsinit()  JU6Linux联盟
(@kern/vfs_init.c)里面有  JU6Linux联盟
         struct vfsconf  *vfsconf[MOUNT_MAXTYPE+1];  JU6Linux联盟
         struct vfsops   *vfssw[MOUNT_MAXTYPE+1];  JU6Linux联盟
各种东西的设定,这些是,管理mount信息的struct mount(@sys/mount.h)的成员  JU6Linux联盟
mnt_vfc和mnt_op要指定所对应的文件系统的vfsconf,vfssw。还有宏VFS_操作名  JU6Linux联盟
(struct mount *,..)里,可以各个操作的调用。  JU6Linux联盟
JU6Linux联盟
2.2.2对v-node的操作  JU6Linux联盟
虚拟文件系统就是通过对i-node的抽象化之后的v-node的文件/目录进行io处理。  JU6Linux联盟
为了这个目的,作为对v-node的适用处理,有  JU6Linux联盟
         。从v-node到文件名的查找,返回v-node  JU6Linux联盟
         。打开/关闭v-node  JU6Linux联盟
         。检查是否可能访问v-node  JU6Linux联盟
         。得到-v-node的属性  JU6Linux联盟
         。设定v-node的属性  JU6Linux联盟
         。对v-node的输入/输出  JU6Linux联盟
         。扩展v-node的硬连接和符号连接  JU6Linux联盟
         。对v-node进行目录的作成和删除  JU6Linux联盟
         。。。。  JU6Linux联盟
由这里开始,一共定义了41个。  JU6Linux联盟
         v-node由struct vnode(@sys/vnode.h)里定义,作为类别在enum vtype  JU6Linux联盟
里面表示出来,一共是9种类。它包含着在各个文件系统上对各个的文件/目录(包  JU6Linux联盟
括特殊)文件进行统一识别的信息。为了实现这样,v-node一连串的操作就是在各  JU6Linux联盟
模块里通过宏VNODEOP_SET()和核心通讯。这些操作名和实现的routine只需要必要  JU6Linux联盟
的几个对应。在核心初始化里,vfs_opv_init()(@kern/vfs_init.c)就使从数据得  JU6Linux联盟
到的号码一一对应,收集了routine的地址的同一size的配列再进行组合。各个  JU6Linux联盟
v-node就一个一个指向这些配列。对v-node的操作在vnode_if.h里定义:  JU6Linux联盟
它以  JU6Linux联盟
         VOP_操作名(v-node,...)  JU6Linux联盟
的统一形式记述。  JU6Linux联盟
JU6Linux联盟
         下面是对v-node的操作的定义source:  JU6Linux联盟
------------------------------------------------------------------------  JU6Linux联盟
各个v-node操作(vnodeopv)      source  JU6Linux联盟
------------------------------------------------------------------------  JU6Linux联盟
cd9660_fifoop_opv_desc          isofs/cd9660/cd9660_vnops.c  JU6Linux联盟
cd9660_specop_opv_desc          isofs/cd9660/cd9660_vnops.c  JU6Linux联盟
cd9660_vnodeop_opv_desc         isofs/cd9660/cd9660_vnops.c  JU6Linux联盟
dead_vnodop_opv_desc            miscfs/deadfs/dead_devfs_vnops.c  JU6Linux联盟
devfs_vnodeop_desc              miscfs/devfs/devfs_vnops.c  JU6Linux联盟
ext2fs_fifoop_opv_desc          gnu/ext2fs/ext2fs_vnops.c  JU6Linux联盟
ext2fs_specop_opv_desc          gnu/ext2fs/ext2fs_vnops.c  JU6Linux联盟
ext2fs_vnodeop_opv_desc         gnu/ext2fs/ext2fs_vnops.c  JU6Linux联盟
fdesc_vnodeop_opv_desc          miscfs/fdesc/fdesc_vnops.c  JU6Linux联盟
ffs_fifoop_opv_desc             ufs/ffs/ffs_vnops.c  JU6Linux联盟
ffs_specop_opv_desc             ufs/ffs/ffs_vnops.c  JU6Linux联盟
ffs_vnodeop_opv_desc            ufs/ffs/ffs_vnops.c  JU6Linux联盟
fifo_nfsv2nodeop_opv_desc       nfs/nfs_vnops.c  JU6Linux联盟
fifo_vnodeop_opv_desc           miscfs/fifofs/fifo_vnops.c  JU6Linux联盟
kernfs_vnodeop_opv_desc         miscfs/kernfs/kernfs_vnops.c  JU6Linux联盟
lfs_fifoop_opv_desc             ufs/lfs/lfs_vnops.c  JU6Linux联盟
lfs_specop_opv_desc             ufs/lfs/lfs_vnops.c  JU6Linux联盟
lfs_vnodeop_opv_desc            ufs/lfs/lfs_vnops.c  JU6Linux联盟
mfs_vnodeop_opv_desc            ufs/mfs/mfs_vnops.c  JU6Linux联盟
msdosfs_vnodeop_opv_desc        msdosfs/msdosfs_vnops.c  JU6Linux联盟
nfsv2_vnodeop_opv_desc          nfs/nfs_vnops.c  JU6Linux联盟
null_vnodeop_opv_desc           miscfs/nullfs/null_vnops.c  JU6Linux联盟
portal_vnodeop_opv_desc         miscfs/portal/portal_vnops.c  JU6Linux联盟
procfs_vnodeop_opv_desc         miscfs/procfs/procfs_vnops.c  JU6Linux联盟
spec_nfsv2nodeop_opv_desc       nfs/nfs_vnops.c  JU6Linux联盟
spec_vnodeop_opv_desc           miscfs/specfs/spec_vnops.c  JU6Linux联盟
umap_vnodeop_opv_desc           miscfs/umapfs/umap_vnops.c  JU6Linux联盟
union_vnodeop_opv_desc          miscfs/union/union_vnops.c  JU6Linux联盟
------------------------------------------------------------------------  JU6Linux联盟
这个基础上,spec_vnodeop_opv_spec里描述的操作群就是device driver   JU6Linux联盟
interface的东西!!  JU6Linux联盟
JU6Linux联盟
( 本小节完,待本岛主有空再继续:-) ) JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨.6.驱动程序篇 JU6Linux联盟
JU6Linux联盟
2.3 mount根目录之前的处理概要 JU6Linux联盟
mount根目录的时候,main()(@kern/init_main.c)的初始化的过程从xxx_vfs_mountroot() JU6Linux联盟
(@kern/init_mail.c)被调用开始。如果处理过程正常,就对rootvp设定包含了root的 JU6Linux联盟
v-node。 JU6Linux联盟
        。main()的初始化过程中,configure()(@autoconf.c)被调用。在这个,io设备 JU6Linux联盟
初始化完了后,就转移到如下两个变量的地址:一个是mountroot,是处理mount的routine, JU6Linux联盟
另一个是mountrootvfsops,是处理虚拟文件系统的routine。在本机磁盘中,就进入变量 JU6Linux联盟
rootdev所指定的disk号中。这里就是,假定本机磁盘 JU6Linux联盟
        mountroot       vfs_mountroot JU6Linux联盟
        mountrootvfsop  &ufs_vfsops JU6Linux联盟
        rootdev         boot disk number JU6Linux联盟
JU6Linux联盟
        。xxx_vfs_mountroot()(@kern/init_main.c) JU6Linux联盟
          运行(*mountroot)(mountrootvfsops)后,就指明了root file system的mount. JU6Linux联盟
        。vfs_mountroot()(@kern/vfs_conf.c) JU6Linux联盟
          管理mount的了文件系统的信息的struct mount(@sys/mount.h),对它进行确认 JU6Linux联盟
          ,然后设定传递过来的对虚拟文件系统的操作群(&ufs_vfsops),才进行"root" JU6Linux联盟
          标记。根据VFS_MOUNT(mp,...)进行mount这个虚拟文件系统。mount成功后,就 JU6Linux联盟
          追加file system的list。这里,由于传递了&ufs_vfsops,就可以调用 JU6Linux联盟
          ffs_mount()(@ufs/ffs/ffs_vfsops.c) JU6Linux联盟
        。ffs_mount() JU6Linux联盟
          首先调用bdevvp()(@kern/vfs_subr.c),进行VBLK类别,spec_vnodeop_p JU6Linux联盟
          (@misc/specfs/spec_vnops.c) v-node操作,保证设定了驱动号的rootdev的 JU6Linux联盟
          v-node的最新信息,然后设定rootvp。最后,通过ffs_mountfs()调用进行实际 JU6Linux联盟
          的mount rootvp操作。 JU6Linux联盟
        。ffs_mountfs() JU6Linux联盟
          各种各样的检查完了后,调用VOP_OPEN(),打开rootvp的v-node。在这里,如果 JU6Linux联盟
          v-node的v_op成员在spec_vnodeop_p存在的话,就调用spec_open()(@misc/ JU6Linux联盟
          specfs/spec_vnops.c)。 JU6Linux联盟
                .spec_open JU6Linux联盟
                 由于VBLK里包含v-node的种类,从v-node指定的device号取得major的 JU6Linux联盟
                 号,调用对应driver的XXopen() routine JU6Linux联盟
JU6Linux联盟
          续上,由VOP_IOCTL()(还是的通过spec_ioctl()(@misc/specfs/spec_vnops.c)) JU6Linux联盟
          可以得到partition信息,然后该检查super block的内容。正确的话,就在struct  JU6Linux联盟
          ufsmount(@ufs/ufs/ufsmount.h)设定unix file system,这样处理过程就完了。 JU6Linux联盟
JU6Linux联盟
2.2.4 struct buf 和block的输入输出routine JU6Linux联盟
        前节的ffs_mountfs()提到使用bread()(@kern/vfs_bio.c)读出partition的 JU6Linux联盟
        super block。这个接口函数很快就会解释。它主要用于读取block型的device到 JU6Linux联盟
        kernel内部的buffer中。 JU6Linux联盟
                bread(struct vnode *vp, /*(in)输入对象的v-node*/ JU6Linux联盟
                      daddr_t blkno,    /*(in)block号*/ JU6Linux联盟
                      int size,         /*(in)读出的byte数量,block长的倍数*/ JU6Linux联盟
                      struct ucred * cred,/*(in)权限信息*/ JU6Linux联盟
                      struct buf ** bpp)/*(out)存储读来的data*/ JU6Linux联盟
        同样的buffer link后的block输出的子程序是bwrite()。 JU6Linux联盟
                bwrite(struct buf *bp)  /*(out)可以输出的struct buf*/ JU6Linux联盟
        两者之间共同的地方就是struct buf(@/sys/buf.h),它用于io处理中给device driver JU6Linux联盟
        做桥梁作用的数据结构。它记录了v-node,io的区别,可以io的block位置/byte数,存 JU6Linux联盟
        储实际data buffer的address,io处理的进展情况等。 JU6Linux联盟
         JU6Linux联盟
        bread则通过getblk()对block输入的结构struct buf进行操作。getblk()调用在核心 JU6Linux联盟
        管理buffer link和返回指定大小的block的struct buf。这个(缓冲区)内容在目的 JU6Linux联盟
        block是否存在与指定v-node的指定位置block是否已经构成缓冲环有关。struct buf JU6Linux联盟
        里面有一个标志位,当缓冲环内容变化是,这个标志位就会改变。bread()根据这个 JU6Linux联盟
        flag判断block是否已经缓冲,如果已经完成,它就终止退出。如果不是这样,则在 JU6Linux联盟
        struct buf的mark里面标志,然后调用VOP_STRATEGY()。在v-node登记的strategy  JU6Linux联盟
        routine记录了io处理的过程,所以bread()当实际的处理完了后,就调用biowait() JU6Linux联盟
        进入等待状态。然后,就转移到别的进程A。io处理完了后,调用biodone(),进程A JU6Linux联盟
        也可以继续进行。还有,调用bread()的一边,当完成操作后,就调用brelse(),在 JU6Linux联盟
        里面对struct buf的flag重新设置,让它对别的程序开放。 JU6Linux联盟
         JU6Linux联盟
        bwrite也是同样的通过VOP_STRATEGY()对io处理要求进行登记,同时也调用biowait() JU6Linux联盟
        进入等待状态,同样,当实际操作完了后,也设置flag进行复位,使得其他程序可以 JU6Linux联盟
        使用io,当空闲的时候,io就挂起,转向其他进程处理。 JU6Linux联盟
        进程等待进入的时候,当然不限于只是调用biowait()。在bread()或者bwrite()之前, JU6Linux联盟
        系统必须分配足够的资源供它使用,比如一些缓冲区等。当进行实际io时候,1个block JU6Linux联盟
        也可以,多个block也可以,而且这样可以获得更高的效率,这样看起来,就象实际上 JU6Linux联盟
        是连续操作了。 JU6Linux联盟
        (代续) JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨.7.驱动程序篇 JU6Linux联盟
JU6Linux联盟
2.2.5系统调用open()的处理概要 JU6Linux联盟
        进程通过系统调用read()/write()进行io处理,它由文件描述符指定对哪里进 JU6Linux联盟
行i/o,文件描述符是0以上的整数,它在各个进程的struct proc的成员 JU6Linux联盟
struct filedesc *p_fd(struct filedesc(@sys/filedesc.h))保留的struct file JU6Linux联盟
((@sys/file.h)进行选择添加。对struct file,它含有从文件的头的输入输出的byte JU6Linux联盟
位置,输入操作,输出操作,输入输出控制,输入输出的准备状态的检查,执行close JU6Linux联盟
的routine,以及描述io处理对象的信息(v-node,socket,pipe) 。系统调用open() JU6Linux联盟
(@kern/vfs_syscalls.c)就是把包含路径信息的v-node找寻出来,为了对它进行io处理, JU6Linux联盟
先要对struct file进行初始化,然后返回文件描述符。 JU6Linux联盟
        从路径名查找v-nodehe和io准备操作由vn_open()(@kern/vfs_vnops.c)承担。 JU6Linux联盟
vn_open()通过namei()(@kern/vfs_lookup.c)查找路径对应的v-node名,由VOP_OPEN() JU6Linux联盟
调用不同的v-node定义的准备过程routine。例如,有如下的处理方法。 JU6Linux联盟
        。普通的file/directory JU6Linux联盟
          调用ufs_open()(@ufs/ufs/ufs_vnops.c),检查open的mode JU6Linux联盟
        。特殊设备文件 JU6Linux联盟
          调用spec_open()(@miscfs/specfs/spec_vnops.c) JU6Linux联盟
          文字型        调用device driver的open routine JU6Linux联盟
          快型          mount的时候出错。如果不是这样,就调用device driver的 JU6Linux联盟
                        open routine。 JU6Linux联盟
JU6Linux联盟
        回过头来,namei()的任务是就是,对于指定的路径名,对应于跟目录或者当 JU6Linux联盟
前目录的v-node作为起点,通过lookup()(@kern/vfs_lookup.c)进行v-node查找。 JU6Linux联盟
lookup()从路径名开始的v-node(VDIR)开始查找。找到了的v-node作为新的起点继续进行 JU6Linux联盟
查找下一步的要素名,然后得到目的的v-node。这个时候,根据v-node的不同,目录的检 JU6Linux联盟
索方法也就不同。各个要素的实际检索由VOP_LOOKUP()来做。 JU6Linux联盟
JU6Linux联盟
2.2.6系统调用read()的处理概要 JU6Linux联盟
        open()取得文件描述符后,对它的输入处理,有如下的流程。指定的文件描述符 JU6Linux联盟
的struct file内登记的处理routine有vn_read()(@kern/vfs_vnops.c),vn_write(), JU6Linux联盟
vn_ioctl(),vn_select(),vn_closefile(),v_node JU6Linux联盟
登记的操作routine不能分开使用。vn_*()里,只有在合适的前缀操作下,才能正确调用。 JU6Linux联盟
        read()首先在struct uio(@sys/uio.h)登记进程指定的buffer的位置和长度。 JU6Linux联盟
执行read()后,vn_read()向struct file设定登记的文件的读写位置,然后调用VOP_READ()。 JU6Linux联盟
根据读出来的byte数,读写位置相应增加。 JU6Linux联盟
        VOP_READ()的call routine则是与v-node有关,就象下图一样。 JU6Linux联盟
JU6Linux联盟
                                        vn_read() JU6Linux联盟
                        文字型/块型       | JU6Linux联盟
                        /------------------ JU6Linux联盟
                        |                 | file/directory JU6Linux联盟
                  spec_read() ---------ffs_read()-------VOP_READ() JU6Linux联盟
        block型         |                 | JU6Linux联盟
        /---------------|char型           | JU6Linux联盟
        bread()       device driver    bread() JU6Linux联盟
        |                                 | JU6Linux联盟
        spec_strategy() ---------------ufs_strategy() --VOP_STRATEGY() JU6Linux联盟
        |                                 |                         | JU6Linux联盟
        |                                 |                         | JU6Linux联盟
        device driver                  spec_strategy() -------------/ JU6Linux联盟
                                          | JU6Linux联盟
                                          | JU6Linux联盟
                                       device driver JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
        。普通的file/directory JU6Linux联盟
          调用ffs_read()(@ufs/ufs/ufs_readwrite.c)。对应指定的读写位置,计算block JU6Linux联盟
          的位置,然后用bread()读出来。读出来的数据送到进程所准备的缓冲区。从bread() JU6Linux联盟
          传递过来的block并不是物理block的位置,而是把file作为block列的一个理论值。 JU6Linux联盟
          从理论块到物理块的变换由VOP_STARATEGY()完成。也就是说,ufs_strategy()先把 JU6Linux联盟
          文件内位置转化为物理block位置,然后从v-node记录的i-node把表示物理设备的 JU6Linux联盟
          v-node 去出来,这个VOP_STRATEGY就调用spec()(@miscfs/specfs/spec_vnops.c) JU6Linux联盟
          让它进行输入要求。 JU6Linux联盟
        。特殊设备文件 JU6Linux联盟
          通过调用spec_read()(@miscfs/specfs/spec_vnops.c),把它分为文字型和块型两类。 JU6Linux联盟
          文字型        调用device driver的输入routine JU6Linux联盟
          块型          通过bread()进行输入处理 JU6Linux联盟
JU6Linux联盟
        对文件的系统调用write()的场合也是类似的处理流程(ufs_write()->;bwrite()), JU6Linux联盟
ufs_write()则要考虑到文件大小的延伸。 JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨.8.驱动程序篇 JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
2.3  Device Driver JU6Linux联盟
进程的io要求到这里说的差不多了。上面也解说了对于文字型,块型的驱动程序接口,就 JU6Linux联盟
是dev_spec_vnodeop_opv_desc里定义的子函数那些。参考设备驱动程序,在sys/conf.h JU6Linux联盟
里定义的结构体。block型是 JU6Linux联盟
        struct bdevsw{ JU6Linux联盟
                d_open_t        *d_open; JU6Linux联盟
                d_close_t       *d_close; JU6Linux联盟
                d_strategy_t    *d_strategy; JU6Linux联盟
                d_ioctl_t       *d_ioctl; JU6Linux联盟
                d_dump_t        *d_dump; JU6Linux联盟
                d_psize_t       *d_psize;       /*得到容量*/ JU6Linux联盟
                int             *d_flags;        JU6Linux联盟
                char            *d_name;        /*device 名*/ JU6Linux联盟
                struct cdesw    *d_cdev;        /*对应的文字型*/ JU6Linux联盟
                int             d_maj;          /*major号*/ JU6Linux联盟
        } JU6Linux联盟
        文字型的则是 JU6Linux联盟
        struct cdevsw{ JU6Linux联盟
                d_open_t        *d_open; JU6Linux联盟
                d_close_t       *d_close; JU6Linux联盟
                d_read_t        *d_read;        /* rawread() */ JU6Linux联盟
                d_write_t       *d_write;       /* rawwrite()*/ JU6Linux联盟
                d_ioctl_t       *d_ioctl; JU6Linux联盟
                d_stop_t        *d_stop;        /* nostop()*/ JU6Linux联盟
                d_reset_t       *d_reset;       /* nullreset()*/ JU6Linux联盟
                d_devtotty_t    *d_devtotty;    /* nodevtotty*/ JU6Linux联盟
                d_select_t      *d_select;      /* deltrue*/ JU6Linux联盟
                d_mmap_t        *d_mmap;        /* nommap*/ JU6Linux联盟
                d_strategy_t    *d_strategy JU6Linux联盟
                char            *d_name;        /*device名*/ JU6Linux联盟
                struct bdevsw   *d_bdev;        /*对应block型*/ JU6Linux联盟
                int             d_may;          /*major号*/ JU6Linux联盟
        } JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
两方面共同的部分有 JU6Linux联盟
        xx_open(dev_t dev,int oflags,int devtype,struct proc *p) JU6Linux联盟
        xx_close(dev_t dev,int fflag,int devtype,struct proc *p) JU6Linux联盟
        xx_ioctl(dev_t dev,int cmd,caddr_t data,int fflag,struct proc *p) JU6Linux联盟
xx_open()用于打开device号的设备。xx_close()则用于关闭它。xx_ioctl()则对设备的 JU6Linux联盟
动作状态,机能的取得,设置等进行控制,它通过int cmd命令和参数caddr_t data对之 JU6Linux联盟
进行处理。xx_open()的oflags则是系统调用open()里指定的标志。xx_close()和 JU6Linux联盟
xx_ioctl()的fflag是每个文件描述符设定的标志。int devtype用来区别设备类型是文 JU6Linux联盟
字型的还是块型的。struct proc *p是本次要求的进程号。 JU6Linux联盟
JU6Linux联盟
        在文字型的操作里,有这三个函数 JU6Linux联盟
        xx_read(dev_t dev,struct uio *uio,int ioflag) JU6Linux联盟
        xx_write(dev_t dev,struct uio *uio,int ioflag) JU6Linux联盟
        xx_select(dev_t dev,int which, struct proc *p) JU6Linux联盟
xx_read()/xx_write()是对device号的io,struct uio *uio 是io的buffer,int ioflag JU6Linux联盟
标志io动作的option。例如,输入data没准备好的场合不用进入等待状态也可以。 JU6Linux联盟
xx_select()检查是否可以进行io要求。 JU6Linux联盟
        在块设备的操作中,有一个函数 JU6Linux联盟
        xx_strategy(struct buf *bp) JU6Linux联盟
它处理io要求。struct buf *bp里面包含着device号,输入还是输出,io的buffer等。 JU6Linux联盟
JU6Linux联盟
        device号中的major号,对文字型的struct cdevsw *cdevsw[],对块型的struct  JU6Linux联盟
bdevsw *bdevsw[],作为配列的添加字使用。向这些配列登记,就可以调出device driver JU6Linux联盟
的登记routine。 JU6Linux联盟
        对cdevsw[]登记的过程在kern/kern_conf.c,它使用 JU6Linux联盟
        int cdevsw_add( JU6Linux联盟
                dev_t *descrip,         /*收集device号的变量的指针*/ JU6Linux联盟
                struct cdevsw *newentry,/*设置struct cdevsw的指针*/ JU6Linux联盟
                struct cdevsw **oldentry,/*旧的设定内容的返回领域*/ JU6Linux联盟
        ) JU6Linux联盟
        另一方面,对bdevsw[]的登记过程则使用 JU6Linux联盟
        int bdevsw_add_generic( JU6Linux联盟
                int bdev,               /*block型的major号*/ JU6Linux联盟
                int cdev,               /*文字型的major浩*/ JU6Linux联盟
                struct bdevsw *bdevsw,  /*设定struct bdevsw的指针,对应d_cdev*/ JU6Linux联盟
        ) JU6Linux联盟
        block型的device和char型的device有着一定的对应关系。这些结构体相互参考。 JU6Linux联盟
bdevsw_add_generic()从block的结构体开始,对作为char型的device的结构体进行初始化。 JU6Linux联盟
还有,network interface的devive driver,并没有向cdevsw[]和bdevsw[]登记。而且也没有 JU6Linux联盟
device号。网络间的package流,和进程间与网络间的package流也没有特别指明。 JU6Linux联盟
        调用登记routine的时候,可以把文件系统的modules作为特殊设备文件参考。登记 JU6Linux联盟
routine在什么地方都可以调用。 JU6Linux联盟
        。main()(@kern/init_mail.c)的初始化过程中登记的routine调用的时候,各个 JU6Linux联盟
          device driver的modules里由宏SYSINIT()准备进行。 JU6Linux联盟
        。确认device driver里的io设备的存在的时候,调用登记routine。 JU6Linux联盟
        当调用登记程序段的时候,如果major号和/dev/MAKEDEV的major号有冲突的时候, JU6Linux联盟
就调用全部无关性device file的处理routine,也可能没有预期的的灾难事情。还有别的 JU6Linux联盟
以外事情,就是当/dev里没有对应的特殊设备文件的时候,也就不能从进程进行参考。 JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
FreeBSD核心探讨.9.驱动程序篇 JU6Linux联盟
JU6Linux联盟
JU6Linux联盟
2.3.1驱动程序初始化 JU6Linux联盟
        从文件系统的模块可以看出来,如果要对驱动程序的物理设备进行io,必须 JU6Linux联盟
先对它们进行初始化,否则不能处理process的io。核心初始化的过程里,一共登记 JU6Linux联盟
了两个基本的操作过程。 JU6Linux联盟
        1.probe         确认io设备 JU6Linux联盟
        2.attach        设置device driver内部的数据结构,使它能够对io设备 JU6Linux联盟
                        进行操作。登记中断子程序。 JU6Linux联盟
        在device driver中的处理过程有: JU6Linux联盟
        1.i/o地址 JU6Linux联盟
          i/o命令使用的地址,使io设备的控制硬件和数据交换。 JU6Linux联盟
        2.中断号 JU6Linux联盟
          io设备的状态变化的时候,向cpu发出通知。 JU6Linux联盟
        3.共有内存地址 JU6Linux联盟
          根据设备的不同,使用一部分内存空间进行cpu和数据的交换。 JU6Linux联盟
        4.DMA通道 JU6Linux联盟
          不用通过cpu做中介,设备和内存直接交换数据时候采用的通道的识别号。 JU6Linux联盟
          cpu可以在数据传送的时候同时执行它的机器语言。 JU6Linux联盟
        前两种是必须有的。设备根据他连接的总线设备不一样,处理过程也就不同。 JU6Linux联盟
这个在核心的configure中反映出来。 JU6Linux联盟
JU6Linux联盟
    各种总线设备的device driver的初始化 JU6Linux联盟
        驱动程序的初始化在main()初始化的过程中调用configure() JU6Linux联盟
        (@i386/i386autoconf.c). JU6Linux联盟
JU6Linux联盟
EISA    bus JU6Linux联盟
        连接EISA bus的io设备用的device driver的初始化在eisa_configure() JU6Linux联盟
(@i386/eisa/eisaconf.c)。各个device driver在module里对struct eisa_driver  JU6Linux联盟
XXX(@i386/eisa/eisaconf.h)进行probe,attach等的设置,准备在宏DATA_SET JU6Linux联盟
(eisadriver_set,XXX)进行登记。 JU6Linux联盟
        eisa_configure()(@i386/eisa/eisaconf.c)对连接EISA bus的全部io设备 JU6Linux联盟
标志和i/o地址进行检测。之后便调用登记的probe子程序。在probe子程序中,通过 JU6Linux联盟
eisa_match_dev()(@i386/eisa/eisaconf.c)对自身检测,查找io设备,检测i/o中断 JU6Linux联盟
号,然后进行使用预定,之后用eisa_registerdev()(@i386/eisa/eisaconf.c)在 JU6Linux联盟
struct eisa_driver XXX对这个设备操作,作为device driver登记。全部的io设备 JU6Linux联盟
的控制device driver登记完毕后,eisa_configure()就调用device driver的attach JU6Linux联盟
子程序。attach子程序则进行中断处理程序的登记和device driver的数据的初始化。 JU6Linux联盟
JU6Linux联盟
        核心的configure文件登记了以下的一些device driver: JU6Linux联盟
-------------------------------------------------------------------------- JU6Linux联盟
device  device driver的情报     source                  参考 JU6Linux联盟
-------------------------------------------------------------------------- JU6Linux联盟
        mainboard_drv           i386/eisa/eisaconf.c     JU6Linux联盟
ahb     ahb_eisa_driver         i386/eisa/aha1742.c     scsi adapt JU6Linux联盟
ahc     ahc_eisa_driver         i386/eisa/aic7770.c     scsi adapt JU6Linux联盟
bt      bt_eisa_driver          i386/eisa/bt74x.c       scsi adapt JU6Linux联盟
ep      ep_eisa_driver          i386/eisa/3c5x9.c       network interface JU6Linux联盟
fea     pdq_eisa_driver         i386/eisa/if_fea.c      network interface JU6Linux联盟
vx      vx_eisa_driver          i386/eida/if_vx_eisa.c  network interface JU6Linux联盟
-------------------------------------------------------------------------- JU6Linux联盟
JU6Linux联盟
PCI     bus JU6Linux联盟
        连接pci bus的设备的初始化在pci_configure()(@pci/pci.c)进行。各个 JU6Linux联盟
device driver在module内的struct pci_device XXX(@pci/pcivar.h)设置probe和 JU6Linux联盟
attach,在通过宏DATA_SET(pcidevice_est,XXX)进行登记。 JU6Linux联盟
        DATA_SET(pcibus_set,i386pci)(@i386/isa/pcibus.c)登记的子程序可以 JU6Linux联盟
得到有关pci bus的一些信息。之后和eisa bus处理过程一样进行各种各样的调用。 JU6Linux联盟
        核心的configure文件登记了以下的一些device driver: JU6Linux联盟
-------------------------------------------------------------------------- JU6Linux联盟
device  device driver的情报     source                  参考 JU6Linux联盟
-------------------------------------------------------------------------- JU6Linux联盟
ahc     ahc_pci_driver          pci/aic7870.c           scsi adapt JU6Linux联盟
bt      bt_pci_driver           pci/bt9xx.c             scsi adapt JU6Linux联盟
ncr     ncr_device              pci/ncr.c               scsi adapt JU6Linux联盟
amd     trmamd_device           pci/tek390.c            scsi adapt JU6Linux联盟
cy      cy_device               pci/cy_pci.c            serial port JU6Linux联盟
meteor  met_device              pci/meteor.c            meteor通道 JU6Linux联盟
stl     stlpcidriver            i386/isa/stallion.c     serial port JU6Linux联盟
wdc     wdc_pci_driver          pci/wdc_p.c             ide control JU6Linux联盟
de      dedevice                pci/if_de.c             network interface JU6Linux联盟
ed      ed_pci_driver           pci/if_ed_p.c           network interface JU6Linux联盟
fpa     pfadevice               pci/if_pfa.c            network interface JU6Linux联盟
fxp     fxp_device              pci/if_pxp.c            network interface JU6Linux联盟
lnc     lnc_pci_driver          pci/if_lnc_p.c          network interface JU6Linux联盟
sr      sr_pci_driver           pci/if_sr_p.c           network interface JU6Linux联盟
vx      vxdevice                pci/if_vx_pci.c         network interface JU6Linux联盟
------------------------------------------------------------------------- JU6Linux联盟
JU6Linux联盟
ISA     bus JU6Linux联盟
        连接ISA bus的io设备的device driver的初始化在isa_configure()(@i386/ JU6Linux联盟
isa/isa.c)进行。和EISA,PCI很大的一个区别就是,在核心的配置文件中,要指定所 JU6Linux联盟
有的io地址等。 JU6Linux联盟
        configure文件中,有象如下的记录 JU6Linux联盟
                controller      控制设备名      at isa?... JU6Linux联盟
                device          device名        at isa?... JU6Linux联盟
        这些内容在编译核心的目录下作为ioconf.c的struct isa_device  JU6Linux联盟
isa_devtab_XXX[]的初始值由config命令写进去。在struct isa_device(@i386/isa JU6Linux联盟
/isa_device.h)的上,其次的成员变量由configure文件的记录内容进行设定。但是 JU6Linux联盟
,“名字”是控制设备名/device名的数字除外的部分。 JU6Linux联盟
------------------------------------------------------------------------- JU6Linux联盟
member名                configure的记述内容 JU6Linux联盟
------------------------------------------------------------------------- JU6Linux联盟
id_driver               名字drvier JU6Linux联盟
id_iobase               prot I/O address JU6Linux联盟
id_irq                  irq号 JU6Linux联盟
id_drq                  drq DMA通道号 JU6Linux联盟
id_maddr                iomem共有memory address JU6Linux联盟
id_msize                iosiz共有memory长度 JU6Linux联盟
id_intr                 vector device driver的中断处理程序名 JU6Linux联盟
id_unit                 名字的后的数字(?) JU6Linux联盟
id_flags                flags JU6Linux联盟
------------------------------------------------------------------------- JU6Linux联盟
JU6Linux联盟
        但是,和控制设备/device名有关的一些东西如bio,net,tty出现的场合,这 JU6Linux联盟
些一般成为isa_devtab_bio[],isa_devtab_net[],isa_devtab_tty[]数组的初始值。 JU6Linux联盟
没有的情况,则成为isa_tab_null[]的初始值。还有一个就是名字driver,它是各个 JU6Linux联盟
device driver的module内部的struct isa_driver(@i386/isa/isa_device.h)一个东 JU6Linux联盟
西。对isa bus设备的device driver,这个是一个固定值。 JU6Linux联盟
象这样的记录: JU6Linux联盟
------------------------------------------------------------ JU6Linux联盟
disk    device名        at      控制设备名      driver  数字 JU6Linux联盟
tape    device名        at      控制设备名      driver  数字 JU6Linux联盟
------------------------------------------------------------ JU6Linux联盟
每个数字除外控制设备名(wdc或者fdc),总结起来就是写进一个叫做 JU6Linux联盟
isa_biotab_控制设备名[]的数组的某个元素的初始设定值。但对unit成员填入数字 JU6Linux联盟
外,其他的也就和isa_devtab_bio[]的内容一样。 JU6Linux联盟
        isa_configure()依照isa_devtab_bio[],isa_devtab_net[], JU6Linux联盟
isa_devtab_tty[]的设定值调用probe子程序对设备的有无进行确认。有的话就继续 JU6Linux联盟
调用attach子程序。 JU6Linux联盟
        probe子程序对设备进行确认,不同的probe子程序也有可能对同样的io地址 JU6Linux联盟
进行操作。所以为了防止这个问题,isa_configure()对已经确认过的的io地址不再 JU6Linux联盟
给别的probe进行动作。 JU6Linux联盟
        同样,错认的可能性也有的。必要的时候没连接的设备的probe要禁止使用, JU6Linux联盟
(在boot的参数的时候)。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/63316/showart_654840.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP