免费注册 查看新帖 |

Chinaunix

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

[FreeBSD] [转贴]FreeBSD核心入门 作者:(日)大木敦雄 译:Liangvy [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-01-15 00:40 |只看该作者 |倒序浏览
翻译    :Liangvy
E-mail  : liangvy@bigfoot.com
原著    :FreeBSD核心入门(日文版) 大木敦雄

1.1概述
         FreeBSD可以在PC/AT兼容机器上运行。CPU是i386,i486,Pentium,
Pentium Pro以及其兼容芯片等。
1.1.1(略)
         1,理论地址: 2个13 bit 长+32 bit 长
         2,线形地址:32 bit 长的空间
         3,物理地址:32 bit 长的空间
1.1.2进程的虚拟空间
         1,text部分
                 这部分是执行文件的的text领域,也就是机器语言部分,对于这个
             部分的空间在机器上的物理内存页是共有的,还有,这部分最后的变量
             地址是etext。
         2,data和bss部分
                 执行文件的data部分,也就是初始化的数据段和执行文件指定的内
             存变量。内存变量在开始的时候以0填充。这一段空间可以读写。它的
             边界也是以edata和end的地址做结尾。进程的malloc()等内存分配的
             操作的时候,地址的增加方向向bss空间进行。
         3,stack部分
                 也就是进程执行的时候的stack空间,这部分空间(从地址的最高位
             开始可以伸缩),其对于物理内存,伸缩程度由核心自动执行。
1.2 kernel的configure
         freebsd的kernel构成文件在/usr/src/sys的目录下面。下面的子目录做一个
     介绍。
         compile 编译核心的目录。
         conf    configure的目录。
         ddb     核心调试的sounre code的目录。
         dev     一部分的drivers的source code的目录。
         gnu     浮点运算的仿真以及ex2fs文件系统的source code目录。
         i386    依赖于pc/at机器的目录,以下介绍它的字目录。
                 apm     suspend一些节电程序。
                 boot    不是kernel本身的东西,只是一些怎么从开机到读入kernel
                         的boot program的source code。
                 conf    config的一些依赖data。
                 isa     isa bus的驱动程序类的source code。
                 eisa    eisa bus的驱动程序类的source code。
                 include 对pc/at的一些include files
                 i386    对pc/at的一些核心code
                 ibcs2,linux 使各类的os的执行文件在freebsd上执行的code
         isofs/cd9660
                 cd-rom在unix文件系统上操作的的有关code
         kern    核心code
         libkern 核心库的source code
         miscfs  实现unix文件系统的code
         msdosfs 在unix上操作ms-dos文件系统的有关code
         net     实现network功能的基本部分code
         netatalk
                 实现appletalk network功能code
         netinet 实现internet network功能的code
         netipx  实现ipx功能的code
         netns   实现ns network的code
         netkey  实现网络加密部分的功能的code
         nfs     实现nfs服务
         pc98    对于pc98的支持
         pccard  对pcmcia的支持
         pci     对pci bus的驱动程序的source code
         scsi    对cd-rom,hard disk,tape 等的scsi驱动程序的source code
         sys     独立于机器体系结构的一部分code
         ufs     unix file system 的支持code
         vm      虚拟内存管理的部分
1.2.1配置的操作----config command
         在root权限下,config,make实行后,可以得到简单的kernel。
         *configure file
         移动到/usr/src/sys/i386/config看看。
                 GENERIC 从cd-rom等安装freebsd的时候对应于defaule kernel
                         的配置file
                 LINT    kernel组合功能的网罗的的配置file
         下面4个是对配置很有必要的的依赖data file
                 Makefile.386    config生成的Makefile file的template.
                 devices.i386    对于unix filesystem可能的block型的device
                                 名字和major号的对照表
                 files.i386      记录kernel功能组合的基础上,依赖于pc/at
                                 机器的功能名称和各种功能实现的source code  
                                 file的名字表。
                 options.i386    记录配置项目的表。
         还有,majors.i386是记录对应驱动器的I/O表和major号的一个文件。
         于核心配置没关系。
         对于新的i/o设备,如果要做device driver,对pc/at,要在files.i386(没
         有的话在/usr/src/sys/conf/files)追加相应的行,不然就不能把它加入
         到核心里面。
         追加的格式为
                 相对path名      optional        device-name device-driver

         对于配置文件,首先,要设置cpu,bus,i/o设备,多少用户等。例如对于GENERIC
                 machine "i386"
                 cpu     "I386_CPU"
                 cpu     "I486_CPU"
                 cpu     "I586_CPU"
                 cpu     "I686_COU"
                 ident   GENERIC
                 maxusers 10
         当作为server时候,应该把最大user设置大一点,以提高系统性能。
         下一步,指定options,对于GENERIC
                 options MATH_EMULATE    #support for x87 emulation
                 options INET            #interNETworing
                 options FFS             #Berkeley Fast Filesystem
                 options NFS             #Network Filesystem
                 ......
         options指定的名字xxx等,如果在/usr/src/sys/conf/options或者在
         /usr/src/sys/i386/conf/options.i386中记载的时候,应在对应的opt_XXX.h中写入
         。没有的话,作为cc命令行的参数定义"-D"在Makefile里面追加。对于XXX的格式应该
         是
                 相对path名      optional xxx
         下一步,对于config
                 config  kernel  root    on wd0
                 (略)
         配置文件剩下的部分应该是bus,i/o等一些硬件配置,一般有controller,device,
         disk,tape四类。例如
                 controller      isa0
                 controller      eisa0
                 controller      pci0
         等。
         第二层的device和controller,记录了一些bus设备的连接。ISA的情况是
                 device          device_name     at isa? 参数
                 controller      controller_name at isa? 参数
         EISA和PCI就相对简单一点:
                 device          device_name
                 controller      controller_name
         device_name里指定的设备名是,串口,并口,网络等装置。
         第三层的disk和tape为
                 disk    disk_name at 控制设备名 drive 号
                 tape    tape_name at 控制设备名 drive 号
         SCSI接口卡作为第二层的控制装置记录的同时
                 controller      scbus0
         作为通用的scsi控制设备。因此,对于它的hard disk,tape,cd-rom,mo设备,有
                 device  sd0
                 device  st0
                 device  cd0
                 device  od0
         等,它可以自动识别和分配号码。
         对于其他的scsi设备,有
                 device  pt0     at scbus?
         这些东西(bus,scsi,i/o),在生成的ioconf.c以及相应的include中有反映。
         configure的最后,不是一些物理设备,而是kernel内部的一些软设置
                 pseudo-device   理论设备名
         首先,要考虑以下两个设备:
                 pseudo-device   pty     16      #ttys - can go as high as 256
                 pseudo-device   log             #syslog interface (/dev/klog)
         network使用的场合,应该有下面两个
                 pseudo-device   loop
                 pseudo-device   ether
         这种情况下,最好有
                 pseudo-device   bpfilter 4      #berkeley packet filter
                 pseudo-device   tun      1      #Tunnel driver ( PPP)
         想做floppy的时候,要
                 pseudo-device   vn      #Vnode driver ( turns a file into a device)
         (代续)



FreeBSD核心探讨(翻译)2

1.3  FreeBSD boot之前的工作
1.3.1pc/at机器的boot顺序
             hard disk的最前面的一个block(512byte),叫做master boot recorder(MBR).这
         里有启动限定的program和分区的信息。分区信息是指对于一个区是16byte长,最多
         只能有4个区。16byte的内容是,分区哪里开始,哪里结束。哪种os,能否启动等。对
         于freebsd,安装的时候向MBR写入了boot easy.
         磁盘的结构如下图表示:
                 block Number
           #0    #1      #2      ...     #14     #15     #16     #17
         -------------------------------------------------------------
                 disk                            no used  
                 label
         -------------------------------------------------------------
         <-boot->;|<---------boot2-------------->;|       |<--unix file system--

         FreeBSD用的block#0--#14的15个block里面,含有读入freebsd的程序,bootease
         只在block#0里面,在15个block中并没有。它的作用
                 。读入mbr,找freebsd的分区
                 。读入最初的15个block,到物理内存中0x0001000
                 。跳转到相当于block#2的内存位置
         然后,屏幕表示为:
                 。。。
                 。。。
                 boot:
         (参数说明略)
         它的source是/usr/src/sys/i386/boot/biosboot,make之后,生成两个文件:
         boot1,boot2分别写入block#1,block#2--#14中。
         一般,一个物理的unix分区理论上可以有8个,比如swap,unix system等。
         boot2部分是boot program,它读入kernel的文件名和option。然后
                 。找boot label指定的分区。
                 。构造unix filesystem,找指定的kernel
                 。从开始执行文件,text,data的顺序向物理内存读入。对bss清零。
                 。以option的选择,向开始位置跳转。
1.3.2  kernel的初始化动作
             boot program执行之后,转向kernel的text段开始进行初始化,即先执行
         locore.s的text段。因此是虚拟内存还没有发生作用,locore.s的开始部分必
         须对offset进行补正。locore.s的作用是
                 。保存从boot program过来的option
                 。设定虚拟的stacker
                 。检测cpu的module
                 。对自己的bss空间进行0初始化
                 。为使虚拟内存工作,要保证最少的管理信息。然后是虚拟空间动作。
         也就是,调用cpu有强的依赖关系的过程init386()(@i386/i386/machdep.c),
         然后进行kernel内的管理信息初始化,i/o设备的登记,生成4个kernel process
         ,再调用main()(@kern/init_main.c)。当main()返回locore.s时,应该有如下
         5个进程:
                 PID     TT      STAT    TIME    COMMAND
                 0       ??      DLs     0:00.17 (swapper)
                 1       ??      Is      0:00.19 /sbin/init --
                 2       ??      DL      0:56.60 (pagedaemon)
                 3       ??      DL      0:00.06 (vmdaemon)
                 4       ??      DL      6:07.65 (updata)
         从locore.s返回到process #1,/sbin/init开始动作,然后转向freebsd的普通
         动作。
         init386()和main()的处理大致如下:
                 。init386()
                 GDT和LDT,IDT,task stages处理的初始化,例外处理等locore.s没做的
                 事情,虚拟内存初始化。然后,根据boot program的参数,增加物理内
                 存page数。然后,作成process #0的雏形。
                 。main()
                 逐步调用构成kernel模块的的初始化部分。


FreeBSD核心探讨(翻译)3

(续上,liangvy.icewolf.leon翻译)

但是,kernel构成的各个模块的初始化子程序一个个的列举出来运行很显然是
不行的。通常是利用时间连表的技能来运行它(ld command)。也就是,程序
是以很多个source分开编译和联结。相同的模块名字就对应于相同的地址来进
行调用。它在时间链表里面自动调节执行。
初始化时候,main()函数要call的模块利用在sys/kernel.h里面定义的宏
SYSINIT()和SYSINIT_KT()进行登记。这样,kernel在link的时候,ld命令就
能够得到那些信息和进行配置列表。这个列表就是kernel的组成模块的初始化
routine的登记。检查source,
就可以找到初始化routine的部分。
         如表:
         print_caddr_t(copyright)                kern/init_main.c
         vm_men_init(NULL)                       vm/vm_init.c
         syctl_order(&amp;sysctl_)                   kern/kern_sysctl.c
         kmemnit(NULL)                           kern/kern_malloc.c
         fpu_init(NULL)                          i386/i386/math_emulate.c
         cpu_startup(NULL)                       i386/i386/machdep.c
         gnufpu_init(NULL)                       miscfs/devfs/devfs_tree.c
         ...
         各个device的major号与处理routine的登记  (major循序号)
         ...
         configure(NULL)                         i386/i386/autoconf.c
         proc0_init(NULL)                        kern/init_main.c
         rqinit(NULL)                            kern/kern_synch.c
         vm_init_limits(&amp;proc0)                  vm/vm_glue.c
         vfsinit(NULL)                           kern/vfs_init.c
         elf_insert_brand_entry(&amp;linux_brand)    i386/linux/linux_sysvec.c
         initclocks(NULL)                        kern/kern_clock.c
         mbinit(NULL)                            kern/uipc_mbuf.c
         clst_init(NULL)                         kern/tty_subr.c
         shmnit(NULL)                            kern/sysv_shm.c
         seminit(NULL)                           kern/sysv_sem.c
         msginit(NULL)                           kern/sysc_msg.c
         kludge_splimp(&amp;x_save_spl)              kern/uipc_domain.c
         ifinit(NULL)                            net/if.c
         domaininit(NULL)                        kern/uipc_domain.c
         kludge_splx(&amp;x_save_spl)                kern/uipc_domain.c
         kmstartup(NULL)                         kern/subr_prof.c
         sched_setup(NULL)                       kern/init_main.c
         xxx_vfs_mountroot(NULL)                 kern/init_main.c
         xxx_vfs_root_fdtab(NULL)                kern/init_main.c
         swapinit(NULL)                          kern/init_main.c
         proc0_post(NULL)                        kern/init_main.c
         kthread_init(NULL)                      kern/init_main.c||
         kproc_start(&amp;page_kp)                   vm/vm_pageout.c||
         kproc_start(&amp;vm_kp)                     vm/vm_pageout.c||
         kproc_start(&amp;up_kp)                     kern/vfs_bio.c||
         scheduler(NULL)                         vm/vm_glue.c
(||表示有多个程序)
proc-post()被呼叫后,main()就是在对应process 0 的kernel的虚拟
内存里动作。kthread_init(),kproc_start(&amp;page_kp),kproc_start(&amp;vm_kp)
,kproc_start(&amp;up_kp)等这几个进程,在fork()后相继被调用。它就是相
应的进程1,2,3,4等。
除process 1 以外,其他的进程调用并不返回调用的地址。(也就是,main()
的跟随执行后,并不返回locore.s)。对于process #1的kernel的虚拟内存,
在kthread_init()返回后,main()的跟随就完了,回到locore.s后,process #1
的进程空间的配置文件/sbin/init就被执行。
main()在process #0对应的kernel虚拟内存运行后,进入时间链表scheduler()。
这个并不返回。那现在就有五个进程了。
然后,fork() 的调用在下面说明。
         1,分配process ID,保证struct proc()用的空间。
         2,复制父亲的process的虚拟内存空间,作成物理内存的变换表。对
            应两个进程,采用相对应的物理内存表。
         3,给回父亲的struct proc和struct user,然后对子进程的struct和
            struct user进行初始化。
         4,kernel的stacker也进行复制。
         5,返回父进程后,标记生成的子进程。完成处理。
但是,process #0 -- 4 这五个进程的虚拟内存里面什么都没有。这些是核心
进程的特殊部分。进程0,2,3是调节系统存在的进程的执行优先级,监视物理
内存的不足,如果不够就使用swap区进行交换。进程4的作用就是定期调查核心
的unix文件系统的管理信息与驱动程序的管理信息的一致性,使它的信息一直
是最新的。

1.3.3 /sbin/init
从kernel里面看,/sbin/init就是单一的进程空间里动作,与一般的
user program一样,提供user使用的unix文件系统的环境的服务。
核心启动后最初的动作就是/sbin/init。作用如下:
         。确保file system的一致性,进行mount。
         。之后,network的设定和各种daemon的启动。
         。监视终端的login的配置和动作状态。这个动作完了后(logout),
           修改和配置 login。
也就是说,如果没有它,用户就不能使用unix文件系统。还有就是,如果boot  
progam参数指定-s的话,它就过渡到单一的用户模式。相对来说,普通的用户
模式也就是multi模式。为了使普通用户能够使用系统,/sbin/init的参考文件
主要在/etc目录里放着。主要就是运行/etc/rc文件对系统进行初始化。
/etc/rc文件的主要内容和作用如下:
         。使系统能够使用swap区
         。检查/etc/fstab,检查它的连贯性,如果有问题就转到单一的用户模式
         。mount nfs以外的文件系统
         。读入network 的设定和各种daemon进程的设定情况的记录文件
           /etc/c.conf,这个内容作为shell script的变量设定,以下的就是
           各个shell的动作调整
         。serial的初始化(/etc/rc.serial)
         。运行PCMCIA卡的插拔监控守护进程(/etc/rc.pccard)
         。network的部分初始化(/etc/rc.network)
         。如果有nfs的时候就进行mount操作
         。network的最终初始化(/etc/rc.network:启动和entwork有关的daemon)
         。共有库的有关信息的初始化
         。intd,lpd,sendmail的启动
         。依赖系统的一些初始化进程
/etc/rc的处理完了后,/sbin/init就对/etc/ttys等记述的一些终端的用户login进行
监视。对于这个,/etc/ttys里指定的终端,fork()后的进程里:
         。exec()指定的程序(普通的情况是/usr/libexec/getty)
         。/usr/libexec/getty进行终端速度等的设定。提示login:,等待用户输入
         。用户输入后,名字作为参数exec() /etc/bin/login
         。/usr/bin/login就提示出passwd:,等待用户的输入
         。准备user名和passwd,对输入的用户名进行确定,正确的话就exec()用户
           shell
                  
下图就是/sbin/init的监视进程图:

process #1
           -------------------------------------------------------->;
/sbin/init |                                         ^       \
            | fork()                                  |        | fork()
            + exec()  exec()     exec()               |        | exec()
process #n |---------->;+--------->;+------------------*+--------
               getty   login      user的login shell       process #m

(第一章完,下一章介绍文件系统和驱动程序,liangvy)



FreeBSD核心探讨.4.驱动程序篇

翻译:liangvy           liangvy@bigfoot.com     icewolf.leon
版权所有,可以转贴

                         第二章  文件系统和设备驱动程序

     这章主要介绍文件系统和特殊的设备文件以及它们的对应关系。

2..1 disk上的 unix file system 的基本知识
     首先介绍一下经典的unix file system的思维方法。
     disk 的 partition就是从0到512byte的连续长度的block的东西。这里有
         1.file/directory有关的固定长度的信息,i-node
         2.file/directory的本体,data block
     的两样不同的东西。partition的前面的附近块(block#16 ,1--15用于boot  
     program )就是i-node,data block用的领域等等的开始位置(block号)
     和长度(block数量)等的记录,叫做super-block。一个block可能的容量只
     能有固定数目的i-node,所以如果分配了固定的i-node,收录了节点号和节
     点的块号和块的位置就可以计算出来。
         i-node就是
             。表明i-node的种类(file ,direstory,device等)
             。这个节点参考的次数(目录数)
             。参考,作成,变化的时间
             。权限
             。所有者的user id / group id
             。本体的长度
             。收集本体的data block的block号码的固定长度的对应表
               的一些记录。因为data block的对应表是固定的关系,比
               如10个,最长就能够作出512*10=5k为止的file。

    当文件比块大的时候,unix就采用成组联结的方式对它们进行管理。就是
    把所有的空闲块以一定数目为一组的方法作成单向空闲块stacker。
    特别地,文件的从先头的byte位置开始和i-node内的对应表有着密切的关系。
    而且,对于i-node的输入输出,可以对应指定位置的数据块进行读写。重要
    的是,核心可以依照这个管理表对io装置进行管理。
         unix对io设备的操作也是作为(特殊)文件进行的。对于用i-node进行
    描述的io设备,data block数据块的对应表就没必要了。这个部分的io设备
    的识别就通过device号码来进行。向这些对i-node进行输入输出处理的,
    就又设备驱动号区别,来进行device driver驱动。
         那么,节点怎么的进行查找呢?partition的最初的目录(根目录)就是,
    从第二个i-node开始,一个一个顺着节点进行查找。
         比如,对于目录/uuu/vvv/.../yyy/zzz的查找方式,有这种关系:
         。i-node #2 所存放的是root directory。读入它的本体,就可以找到
           相应的uuu所对应的i-node。
         。读入这个i-node所存放的directory的i-node本体,找到相应的vvv节点。
           ......
           查找对应yyy的节点
         。读入这个节点的本体信息,这里包含目录本题的内容,这样就可以找到
           zzz所对应的i-node。
         目录里面由于记录了对应文件名的节点号,所以,也有可能同一个节点号
     根据文件名不一样,就可以找到不同的目录名。这就是硬连接(hard link).
     但是,节点号有只存在于节点所在的分区的含义,所以,不同的分区,
     这种硬连接就不具有存在的可能性。为了解决这个矛盾,就有了符号连接
     (symble link)的说法。当节点是输入符号连接的时候,符号连接就包含
     了这个节点的data block所指定的路径名。但是,空连接和loop连接这种
     情况也是允许的,所以核心要指定循环连接的最大次数。具体由参数
     MAXSYMLINKS(@sys/param.h)指定。
         这样,多个分区建立一个文件系统就有可能了。启动核心的分区作为一个
    已存的文件系统,其他的分区就嫁接到目录层上面。这个操作过程就是mount。
    利用mount指令,就可以实现上面的操作。但是,mount之前的目录,在mount后
    就给屏蔽了,直到mount结束,那些目录就可以再现。
         以上就是经典的unix文件系统理论。但是,对于读入了i-node,就去读
    data block ,这种情况,对于一个比较大的分区,硬盘磁头向disk head的距
    离就太大了。总的来说,访问时间就会变长。在这里有一些指导思想:
         。分区要比较小,多分小区
         。了解超级块的地位,超级块记录了分区的信息,考虑由于介质的原因而
           使这个超级块造成损害,所以,在分区内部就必须为它准备多几个拷贝。
         。目录和它下层的文件,要在相同的领域内放置。
         。确保单位data block要比磁盘的block大。
         考虑了一些东西后,经过改良标准,freebsd就采用一个叫做FFS的文件系
    统(Fast File System),但这只是i-node领域/data领域的配置方法的变化,基
    本的考虑方法并没有变。对磁盘分区进行文件系统的构造的初始化由命令newfs
    提供。看看它的source就知道怎么配置的了。其他的构造(......)对应于kernel
    的source,对于构成boot program的文件disk.c和sys.c(@i386/boot/biosboot)
    比较简单易懂(单纯性)。
         上面讲述的i-node对disk的partition的记录形式,详细的(source)在
    struct dinode(@ufs/ufs/dinode.h)里面有。在核心内部使用的,包含这个东西
    的是struct inode(@ufs/ufs.inode.h)。

         描述io设备的文件叫特殊文件(special file),他对应的i-node有两个种
    类:
         。块型(block)
           和装置的固有的数据记录的单位(大多数的情况是512byte)无关。读写
           的最小单位是1byte,可以在任意的场所里任意长度的data。核心对各个
           block型的特殊文件进行固定的记录单位长度(倍数)进行缓冲(buffer)
           管理,这样就可以处理任意长度的读写了.
         。文字型(char)
           读写的基本单位是,受到装置固有的date记录单位长的限定。没有block
           型的缓冲管理,对应于装置的物理特性,读写属于专用。或者说,是读写
           两用。
         除了网络接口之外,io装置可以全部分为文字型和块型两个大类。总的来说,
    磁盘操作的两样都用,但其他的io装置只有文字型。还有就是一些没对应物理设
    备的kernel modules提供的虚拟设备也有,它们对应着文字型的特殊文件。特殊
    文件习惯放在目录/dev里面。

         对于特殊设备文件的i-node有block和chat两个类,设备通过驱动号进行记录
    。通过这些,就可以识别device driver。device 号就是major号(8bit)(主设备
   号)和minor号(24bit)(辅助设备号),device driver的识别就是由major的不
   一样而区别。而且呢,block型,char型的等等可能存在最大数目是256种类。一般的
   情况,同种类的设备不同数目的区别就是通过辅助设备号进行识别。实际上,对于
   disk的特殊文件,有disk/slide/partition表示法,而且,文字型,块型等的特殊
   设备文件也存在。以下就是一个ide硬盘的的文字型特殊设备文件的例子:
         /dev/rwd0               1台ide的硬盘
         /dev/rwd0s1             1台ide的硬盘的slide #1
         /dev/rwd0s2             1台ide的硬盘的slide #2
         /dev/rwd0s2a            slide #2的partition a
         /dev/rwd0s2b            slide #2的partition b
         ...
         /dev/rwd0s3             1台的ide的硬盘的slide #3

         如果把rwd换成wd,对应的就是block型的特殊设备文件了。
         对于磁盘,有如下的使用方法:
         。对于slide的文字型特殊文件
                 读写disk label时候使用(disklabel command)
         。对于对应的partition的文字型特殊文件
                 在分区上建立unix文件系统时候(newfs command),文件系统修复,
                 检查(fsck)时候使用
         。对于partition的block型的特殊文件
                 作为mount命令的参数使用
         (下一节介绍虚拟文件系统和v-node,要休息了 )



FreeBSD核心探讨.5.驱动程序篇

2.2    虚拟文件系统和v-node
         FreeBSD在disk上的除了ffs以外还可以操作各种各样的文件系统。主要的如
下:
         。cd9660
           可以对ISO9660形式的cd-rom的目录/文件构造的文件系统进行mount,
           locate等目录层的操作
         。ms-dos
           对ms-dos文件系统进行目录层次的mount,定位等操作
         。mfs
           通过使用虚拟内存对swap区的一部分进行unix文件系统的构造,定位
           作为目录的一部分进行读写
         。nfs
           由nfs server提供的remote目录级进行mount,定位的目录层操作。
         。null
           对已经存在的目录层的使用别名
         。union
           对已有的目录A(上层)在下层目录B上进行重叠 (不大理解这的意思
           ,大概是在下层目录里面又嫁接了上层目录的意思:译者)。文件名的查
           找由上层优先进行。没有的话就转道下层。如果对下层的文件进行写操作
           ,它的拷贝就在上层上进行。举例说明,作业目录在上层,但cd-rom的源
           在下层,两个目录重叠,那么编译source的时候,就相当方便了。
         。procfs
           对于进程号的目录作成mount point。通过文件名对各个目录的进程进行
           控制。
         。kernfs
           为了对动作中的kernel有关的信息进行参考,而作成的mount  point
         。fdesc
           对于各个进程,用它所打开的文件柄对应的文件作成的mount point
         
         实际上,在核心内部,为了对它们进行统一操作,就对文件系统和v-node
进行抽象化,实际的处理过程就是调用各类的文件系统的模块进行处理。

2.2.1对虚拟文件系统的操作
         各个文件系统可以提供的操作的一览如下,它在struct vfsops
(@sys/mount.h)里面定义:
         。对文件系统进行mount的操作
         。本文件系统的开始动作的操作
         。本文件系统的umount操作
         。表达文件系统的根的v-node的查找操作
         。对一般用户的权限控制
         。取得文件系统的状态
         。内存内的管理信息写入介质中
         。从i-node到v-node的取得操作
         。v-node和nfs的文件柄的相互变换的操作
         。文件系统实际的模块的初始化

对于文件系统,各个实际的操作routine在vfsops的形式提供准备工作。各个文件系
统的vfsops,在以下的表里的source进行定义:

--------------------------------------------------------------
file system     vfsops的定义    source
--------------------------------------------------------------
ufs             ufs_vfsops      ufs/ffs/ffs_vfsops.c
cd9660          cd9660_vfsops   isofs/cd9660/cd9660_vfsops.c
msdos           msdosfs_vfsops  msdosfs/msdosfs_vfsops.c
mfs             mfs_vfsops      ufs/mfs/mfs_vfops.c
nfs             nfs_vfsops      nfs/nfs_vfsops.c
null            null_vfsops     miscfs/nullfs/null_vfsops.c
nuion           union_vfsops    miscfs/union/union_vfsops.c
procfs          procfs_vfsops   miscfs/procfs/procfs_vfsops.c
kernfs          kernfs_vfsops   miscfs/kernfs/kernfs_vfsops.c
fdesc           fdesc_vfsops    miscfs/fdesc/fdesc_vfsops.c
devfs           devfs_vfsops    miscfs/devfs/devfs_vfsops.c
ext2fs          ext2fs_vfsops   gnu/ext2fs/ext2_vfsops.c
lfs             lfs_vfsops      ufs/lfs/lfs_vfsops.c
portal          portal_vfsops   miscfs/portal.portal_vfsops.c
umap            umap_vfsops     miscfs/umapfs/umap_vfsops.c
---------------------------------------------------------------
这些就是文件系统的实际模块(*_vfsops.c),文件系统名称,文件系统号等等
在struct vfsconf(@sys/mount.h)里面汇总,各个模块里用宏VFS_SET()进入核
心。
         根据main()(@kern/init_main.c),在kernel初始化的过程中,vfsinit()
(@kern/vfs_init.c)里面有
         struct vfsconf  *vfsconf[MOUNT_MAXTYPE+1];
         struct vfsops   *vfssw[MOUNT_MAXTYPE+1];
各种东西的设定,这些是,管理mount信息的struct mount(@sys/mount.h)的成员
mnt_vfc和mnt_op要指定所对应的文件系统的vfsconf,vfssw。还有宏VFS_操作名
(struct mount *,..)里,可以各个操作的调用。

2.2.2对v-node的操作
虚拟文件系统就是通过对i-node的抽象化之后的v-node的文件/目录进行io处理。
为了这个目的,作为对v-node的适用处理,有
         。从v-node到文件名的查找,返回v-node
         。打开/关闭v-node
         。检查是否可能访问v-node
         。得到-v-node的属性
         。设定v-node的属性
         。对v-node的输入/输出
         。扩展v-node的硬连接和符号连接
         。对v-node进行目录的作成和删除
         。。。。
由这里开始,一共定义了41个。
         v-node由struct vnode(@sys/vnode.h)里定义,作为类别在enum vtype
里面表示出来,一共是9种类。它包含着在各个文件系统上对各个的文件/目录(包
括特殊)文件进行统一识别的信息。为了实现这样,v-node一连串的操作就是在各
模块里通过宏VNODEOP_SET()和核心通讯。这些操作名和实现的routine只需要必要
的几个对应。在核心初始化里,vfs_opv_init()(@kern/vfs_init.c)就使从数据得
到的号码一一对应,收集了routine的地址的同一size的配列再进行组合。各个
v-node就一个一个指向这些配列。对v-node的操作在vnode_if.h里定义:
它以
         VOP_操作名(v-node,...)
的统一形式记述。

         下面是对v-node的操作的定义source:
------------------------------------------------------------------------
各个v-node操作(vnodeopv)      source
------------------------------------------------------------------------
cd9660_fifoop_opv_desc          isofs/cd9660/cd9660_vnops.c
cd9660_specop_opv_desc          isofs/cd9660/cd9660_vnops.c
cd9660_vnodeop_opv_desc         isofs/cd9660/cd9660_vnops.c
dead_vnodop_opv_desc            miscfs/deadfs/dead_devfs_vnops.c
devfs_vnodeop_desc              miscfs/devfs/devfs_vnops.c
ext2fs_fifoop_opv_desc          gnu/ext2fs/ext2fs_vnops.c
ext2fs_specop_opv_desc          gnu/ext2fs/ext2fs_vnops.c
ext2fs_vnodeop_opv_desc         gnu/ext2fs/ext2fs_vnops.c
fdesc_vnodeop_opv_desc          miscfs/fdesc/fdesc_vnops.c
ffs_fifoop_opv_desc             ufs/ffs/ffs_vnops.c
ffs_specop_opv_desc             ufs/ffs/ffs_vnops.c
ffs_vnodeop_opv_desc            ufs/ffs/ffs_vnops.c
fifo_nfsv2nodeop_opv_desc       nfs/nfs_vnops.c
fifo_vnodeop_opv_desc           miscfs/fifofs/fifo_vnops.c
kernfs_vnodeop_opv_desc         miscfs/kernfs/kernfs_vnops.c
lfs_fifoop_opv_desc             ufs/lfs/lfs_vnops.c
lfs_specop_opv_desc             ufs/lfs/lfs_vnops.c
lfs_vnodeop_opv_desc            ufs/lfs/lfs_vnops.c
mfs_vnodeop_opv_desc            ufs/mfs/mfs_vnops.c
msdosfs_vnodeop_opv_desc        msdosfs/msdosfs_vnops.c
nfsv2_vnodeop_opv_desc          nfs/nfs_vnops.c
null_vnodeop_opv_desc           miscfs/nullfs/null_vnops.c
portal_vnodeop_opv_desc         miscfs/portal/portal_vnops.c
procfs_vnodeop_opv_desc         miscfs/procfs/procfs_vnops.c
spec_nfsv2nodeop_opv_desc       nfs/nfs_vnops.c
spec_vnodeop_opv_desc           miscfs/specfs/spec_vnops.c
umap_vnodeop_opv_desc           miscfs/umapfs/umap_vnops.c
union_vnodeop_opv_desc          miscfs/union/union_vnops.c
------------------------------------------------------------------------
这个基础上,spec_vnodeop_opv_spec里描述的操作群就是device driver  
interface的东西!!

( 本小节完,待本岛主有空再继续 )



FreeBSD核心探讨.6.驱动程序篇

2.3 mount根目录之前的处理概要
mount根目录的时候,main()(@kern/init_main.c)的初始化的过程从xxx_vfs_mountroot()
(@kern/init_mail.c)被调用开始。如果处理过程正常,就对rootvp设定包含了root的
v-node。
        。main()的初始化过程中,configure()(@autoconf.c)被调用。在这个,io设备
初始化完了后,就转移到如下两个变量的地址:一个是mountroot,是处理mount的routine,
另一个是mountrootvfsops,是处理虚拟文件系统的routine。在本机磁盘中,就进入变量
rootdev所指定的disk号中。这里就是,假定本机磁盘
        mountroot       vfs_mountroot
        mountrootvfsop  &amp;ufs_vfsops
        rootdev         boot disk number

        。xxx_vfs_mountroot()(@kern/init_main.c)
          运行(*mountroot)(mountrootvfsops)后,就指明了root file system的mount.
        。vfs_mountroot()(@kern/vfs_conf.c)
          管理mount的了文件系统的信息的struct mount(@sys/mount.h),对它进行确认
          ,然后设定传递过来的对虚拟文件系统的操作群(&amp;ufs_vfsops),才进行"root"
          标记。根据VFS_MOUNT(mp,...)进行mount这个虚拟文件系统。mount成功后,就
          追加file system的list。这里,由于传递了&amp;ufs_vfsops,就可以调用
          ffs_mount()(@ufs/ffs/ffs_vfsops.c)
        。ffs_mount()
          首先调用bdevvp()(@kern/vfs_subr.c),进行VBLK类别,spec_vnodeop_p
          (@misc/specfs/spec_vnops.c) v-node操作,保证设定了驱动号的rootdev的
          v-node的最新信息,然后设定rootvp。最后,通过ffs_mountfs()调用进行实际
          的mount rootvp操作。
        。ffs_mountfs()
          各种各样的检查完了后,调用VOP_OPEN(),打开rootvp的v-node。在这里,如果
          v-node的v_op成员在spec_vnodeop_p存在的话,就调用spec_open()(@misc/
          specfs/spec_vnops.c)。
                .spec_open
                 由于VBLK里包含v-node的种类,从v-node指定的device号取得major的
                 号,调用对应driver的XXopen() routine

          续上,由VOP_IOCTL()(还是的通过spec_ioctl()(@misc/specfs/spec_vnops.c))
          可以得到partition信息,然后该检查super block的内容。正确的话,就在struct
          ufsmount(@ufs/ufs/ufsmount.h)设定unix file system,这样处理过程就完了。

2.2.4 struct buf 和block的输入输出routine
        前节的ffs_mountfs()提到使用bread()(@kern/vfs_bio.c)读出partition的
        super block。这个接口函数很快就会解释。它主要用于读取block型的device到
        kernel内部的buffer中。
                bread(struct vnode *vp, /*(in)输入对象的v-node*/
                      daddr_t blkno,    /*(in)block号*/
                      int size,         /*(in)读出的byte数量,block长的倍数*/
                      struct ucred * cred,/*(in)权限信息*/
                      struct buf ** bpp)/*(out)存储读来的data*/
        同样的buffer link后的block输出的子程序是bwrite()。
                bwrite(struct buf *bp)  /*(out)可以输出的struct buf*/
        两者之间共同的地方就是struct buf(@/sys/buf.h),它用于io处理中给device driver
        做桥梁作用的数据结构。它记录了v-node,io的区别,可以io的block位置/byte数,存
        储实际data buffer的address,io处理的进展情况等。
        
        bread则通过getblk()对block输入的结构struct buf进行操作。getblk()调用在核心
        管理buffer link和返回指定大小的block的struct buf。这个(缓冲区)内容在目的
        block是否存在与指定v-node的指定位置block是否已经构成缓冲环有关。struct buf
        里面有一个标志位,当缓冲环内容变化是,这个标志位就会改变。bread()根据这个
        flag判断block是否已经缓冲,如果已经完成,它就终止退出。如果不是这样,则在
        struct buf的mark里面标志,然后调用VOP_STRATEGY()。在v-node登记的strategy
        routine记录了io处理的过程,所以bread()当实际的处理完了后,就调用biowait()
        进入等待状态。然后,就转移到别的进程A。io处理完了后,调用biodone(),进程A
        也可以继续进行。还有,调用bread()的一边,当完成操作后,就调用brelse(),在
        里面对struct buf的flag重新设置,让它对别的程序开放。
        
        bwrite也是同样的通过VOP_STRATEGY()对io处理要求进行登记,同时也调用biowait()
        进入等待状态,同样,当实际操作完了后,也设置flag进行复位,使得其他程序可以
        使用io,当空闲的时候,io就挂起,转向其他进程处理。
        进程等待进入的时候,当然不限于只是调用biowait()。在bread()或者bwrite()之前,
        系统必须分配足够的资源供它使用,比如一些缓冲区等。当进行实际io时候,1个block
        也可以,多个block也可以,而且这样可以获得更高的效率,这样看起来,就象实际上
        是连续操作了。
        (代续)



FreeBSD核心探讨.7.驱动程序篇

2.2.5系统调用open()的处理概要
        进程通过系统调用read()/write()进行io处理,它由文件描述符指定对哪里进
行i/o,文件描述符是0以上的整数,它在各个进程的struct proc的成员
struct filedesc *p_fd(struct filedesc(@sys/filedesc.h))保留的struct file
((@sys/file.h)进行选择添加。对struct file,它含有从文件的头的输入输出的byte
位置,输入操作,输出操作,输入输出控制,输入输出的准备状态的检查,执行close
的routine,以及描述io处理对象的信息(v-node,socket,pipe) 。系统调用open()
(@kern/vfs_syscalls.c)就是把包含路径信息的v-node找寻出来,为了对它进行io处理,
先要对struct file进行初始化,然后返回文件描述符。
        从路径名查找v-nodehe和io准备操作由vn_open()(@kern/vfs_vnops.c)承担。
vn_open()通过namei()(@kern/vfs_lookup.c)查找路径对应的v-node名,由VOP_OPEN()
调用不同的v-node定义的准备过程routine。例如,有如下的处理方法。
        。普通的file/directory
          调用ufs_open()(@ufs/ufs/ufs_vnops.c),检查open的mode
        。特殊设备文件
          调用spec_open()(@miscfs/specfs/spec_vnops.c)
          文字型        调用device driver的open routine
          快型          mount的时候出错。如果不是这样,就调用device driver的
                        open routine。

        回过头来,namei()的任务是就是,对于指定的路径名,对应于跟目录或者当
前目录的v-node作为起点,通过lookup()(@kern/vfs_lookup.c)进行v-node查找。
lookup()从路径名开始的v-node(VDIR)开始查找。找到了的v-node作为新的起点继续进行
查找下一步的要素名,然后得到目的的v-node。这个时候,根据v-node的不同,目录的检
索方法也就不同。各个要素的实际检索由VOP_LOOKUP()来做。

2.2.6系统调用read()的处理概要
        open()取得文件描述符后,对它的输入处理,有如下的流程。指定的文件描述符
的struct file内登记的处理routine有vn_read()(@kern/vfs_vnops.c),vn_write(),
vn_ioctl(),vn_select(),vn_closefile(),v_node
登记的操作routine不能分开使用。vn_*()里,只有在合适的前缀操作下,才能正确调用。
        read()首先在struct uio(@sys/uio.h)登记进程指定的buffer的位置和长度。
执行read()后,vn_read()向struct file设定登记的文件的读写位置,然后调用VOP_READ()。
根据读出来的byte数,读写位置相应增加。
        VOP_READ()的call routine则是与v-node有关,就象下图一样。

                                        vn_read()
                        文字型/块型       |
                        /------------------
                        |                 | file/directory
                  spec_read() ---------ffs_read()-------VOP_READ()
        block型         |                 |
        /---------------|char型           |
        bread()       device driver    bread()
        |                                 |
        spec_strategy() ---------------ufs_strategy() --VOP_STRATEGY()
        |                                 |                         |
        |                                 |                         |
        device driver                  spec_strategy() -------------/
                                          |
                                          |
                                       device driver


        。普通的file/directory
          调用ffs_read()(@ufs/ufs/ufs_readwrite.c)。对应指定的读写位置,计算block
          的位置,然后用bread()读出来。读出来的数据送到进程所准备的缓冲区。从bread()
          传递过来的block并不是物理block的位置,而是把file作为block列的一个理论值。
          从理论块到物理块的变换由VOP_STARATEGY()完成。也就是说,ufs_strategy()先把
          文件内位置转化为物理block位置,然后从v-node记录的i-node把表示物理设备的
          v-node 去出来,这个VOP_STRATEGY就调用spec()(@miscfs/specfs/spec_vnops.c)
          让它进行输入要求。
        。特殊设备文件
          通过调用spec_read()(@miscfs/specfs/spec_vnops.c),把它分为文字型和块型两类。
          文字型        调用device driver的输入routine
          块型          通过bread()进行输入处理

        对文件的系统调用write()的场合也是类似的处理流程(ufs_write()->;bwrite()),
ufs_write()则要考虑到文件大小的延伸。




FreeBSD核心探讨.8.驱动程序篇


2.3  Device Driver
进程的io要求到这里说的差不多了。上面也解说了对于文字型,块型的驱动程序接口,就
是dev_spec_vnodeop_opv_desc里定义的子函数那些。参考设备驱动程序,在sys/conf.h
里定义的结构体。block型是
        struct bdevsw{
                d_open_t        *d_open;
                d_close_t       *d_close;
                d_strategy_t    *d_strategy;
                d_ioctl_t       *d_ioctl;
                d_dump_t        *d_dump;
                d_psize_t       *d_psize;       /*得到容量*/
                int             *d_flags;      
                char            *d_name;        /*device 名*/
                struct cdesw    *d_cdev;        /*对应的文字型*/
                int             d_maj;          /*major号*/
        }
        文字型的则是
        struct cdevsw{
                d_open_t        *d_open;
                d_close_t       *d_close;
                d_read_t        *d_read;        /* rawread() */
                d_write_t       *d_write;       /* rawwrite()*/
                d_ioctl_t       *d_ioctl;
                d_stop_t        *d_stop;        /* nostop()*/
                d_reset_t       *d_reset;       /* nullreset()*/
                d_devtotty_t    *d_devtotty;    /* nodevtotty*/
                d_select_t      *d_select;      /* deltrue*/
                d_mmap_t        *d_mmap;        /* nommap*/
                d_strategy_t    *d_strategy
                char            *d_name;        /*device名*/
                struct bdevsw   *d_bdev;        /*对应block型*/
                int             d_may;          /*major号*/
        }


两方面共同的部分有
        xx_open(dev_t dev,int oflags,int devtype,struct proc *p)
        xx_close(dev_t dev,int fflag,int devtype,struct proc *p)
        xx_ioctl(dev_t dev,int cmd,caddr_t data,int fflag,struct proc *p)
xx_open()用于打开device号的设备。xx_close()则用于关闭它。xx_ioctl()则对设备的
动作状态,机能的取得,设置等进行控制,它通过int cmd命令和参数caddr_t data对之
进行处理。xx_open()的oflags则是系统调用open()里指定的标志。xx_close()和
xx_ioctl()的fflag是每个文件描述符设定的标志。int devtype用来区别设备类型是文
字型的还是块型的。struct proc *p是本次要求的进程号。

        在文字型的操作里,有这三个函数
        xx_read(dev_t dev,struct uio *uio,int ioflag)
        xx_write(dev_t dev,struct uio *uio,int ioflag)
        xx_select(dev_t dev,int which, struct proc *p)
xx_read()/xx_write()是对device号的io,struct uio *uio 是io的buffer,int ioflag
标志io动作的option。例如,输入data没准备好的场合不用进入等待状态也可以。
xx_select()检查是否可以进行io要求。
        在块设备的操作中,有一个函数
        xx_strategy(struct buf *bp)
它处理io要求。struct buf *bp里面包含着device号,输入还是输出,io的buffer等。

        device号中的major号,对文字型的struct cdevsw *cdevsw[],对块型的struct
bdevsw *bdevsw[],作为配列的添加字使用。向这些配列登记,就可以调出device driver
的登记routine。
        对cdevsw[]登记的过程在kern/kern_conf.c,它使用
        int cdevsw_add(
                dev_t *descrip,         /*收集device号的变量的指针*/
                struct cdevsw *newentry,/*设置struct cdevsw的指针*/
                struct cdevsw **oldentry,/*旧的设定内容的返回领域*/
        )
        另一方面,对bdevsw[]的登记过程则使用
        int bdevsw_add_generic(
                int bdev,               /*block型的major号*/
                int cdev,               /*文字型的major浩*/
                struct bdevsw *bdevsw,  /*设定struct bdevsw的指针,对应d_cdev*/
        )
        block型的device和char型的device有着一定的对应关系。这些结构体相互参考。
bdevsw_add_generic()从block的结构体开始,对作为char型的device的结构体进行初始化。
还有,network interface的devive driver,并没有向cdevsw[]和bdevsw[]登记。而且也没有
device号。网络间的package流,和进程间与网络间的package流也没有特别指明。
        调用登记routine的时候,可以把文件系统的modules作为特殊设备文件参考。登记
routine在什么地方都可以调用。
        。main()(@kern/init_mail.c)的初始化过程中登记的routine调用的时候,各个
          device driver的modules里由宏SYSINIT()准备进行。
        。确认device driver里的io设备的存在的时候,调用登记routine。
        当调用登记程序段的时候,如果major号和/dev/MAKEDEV的major号有冲突的时候,
就调用全部无关性device file的处理routine,也可能没有预期的的灾难事情。还有别的
以外事情,就是当/dev里没有对应的特殊设备文件的时候,也就不能从进程进行参考。



FreeBSD核心探讨.9.驱动程序篇


2.3.1驱动程序初始化
        从文件系统的模块可以看出来,如果要对驱动程序的物理设备进行io,必须
先对它们进行初始化,否则不能处理process的io。核心初始化的过程里,一共登记
了两个基本的操作过程。
        1.probe         确认io设备
        2.attach        设置device driver内部的数据结构,使它能够对io设备
                        进行操作。登记中断子程序。
        在device driver中的处理过程有:
        1.i/o地址
          i/o命令使用的地址,使io设备的控制硬件和数据交换。
        2.中断号
          io设备的状态变化的时候,向cpu发出通知。
        3.共有内存地址
          根据设备的不同,使用一部分内存空间进行cpu和数据的交换。
        4.DMA通道
          不用通过cpu做中介,设备和内存直接交换数据时候采用的通道的识别号。
          cpu可以在数据传送的时候同时执行它的机器语言。
        前两种是必须有的。设备根据他连接的总线设备不一样,处理过程也就不同。
这个在核心的configure中反映出来。

    各种总线设备的device driver的初始化
        驱动程序的初始化在main()初始化的过程中调用configure()
        (@i386/i386autoconf.c).

EISA    bus
        连接EISA bus的io设备用的device driver的初始化在eisa_configure()
(@i386/eisa/eisaconf.c)。各个device driver在module里对struct eisa_driver
XXX(@i386/eisa/eisaconf.h)进行probe,attach等的设置,准备在宏DATA_SET
(eisadriver_set,XXX)进行登记。
        eisa_configure()(@i386/eisa/eisaconf.c)对连接EISA bus的全部io设备
标志和i/o地址进行检测。之后便调用登记的probe子程序。在probe子程序中,通过
eisa_match_dev()(@i386/eisa/eisaconf.c)对自身检测,查找io设备,检测i/o中断
号,然后进行使用预定,之后用eisa_registerdev()(@i386/eisa/eisaconf.c)在
struct eisa_driver XXX对这个设备操作,作为device driver登记。全部的io设备
的控制device driver登记完毕后,eisa_configure()就调用device driver的attach
子程序。attach子程序则进行中断处理程序的登记和device driver的数据的初始化。

        核心的configure文件登记了以下的一些device driver:
--------------------------------------------------------------------------
device  device driver的情报     source                  参考
--------------------------------------------------------------------------
        mainboard_drv           i386/eisa/eisaconf.c   
ahb     ahb_eisa_driver         i386/eisa/aha1742.c     scsi adapt
ahc     ahc_eisa_driver         i386/eisa/aic7770.c     scsi adapt
bt      bt_eisa_driver          i386/eisa/bt74x.c       scsi adapt
ep      ep_eisa_driver          i386/eisa/3c5x9.c       network interface
fea     pdq_eisa_driver         i386/eisa/if_fea.c      network interface
vx      vx_eisa_driver          i386/eida/if_vx_eisa.c  network interface
--------------------------------------------------------------------------

PCI     bus
        连接pci bus的设备的初始化在pci_configure()(@pci/pci.c)进行。各个
device driver在module内的struct pci_device XXX(@pci/pcivar.h)设置probe和
attach,在通过宏DATA_SET(pcidevice_est,XXX)进行登记。
        DATA_SET(pcibus_set,i386pci)(@i386/isa/pcibus.c)登记的子程序可以
得到有关pci bus的一些信息。之后和eisa bus处理过程一样进行各种各样的调用。
        核心的configure文件登记了以下的一些device driver:
--------------------------------------------------------------------------
device  device driver的情报     source                  参考
--------------------------------------------------------------------------
ahc     ahc_pci_driver          pci/aic7870.c           scsi adapt
bt      bt_pci_driver           pci/bt9xx.c             scsi adapt
ncr     ncr_device              pci/ncr.c               scsi adapt
amd     trmamd_device           pci/tek390.c            scsi adapt
cy      cy_device               pci/cy_pci.c            serial port
meteor  met_device              pci/meteor.c            meteor通道
stl     stlpcidriver            i386/isa/stallion.c     serial port
wdc     wdc_pci_driver          pci/wdc_p.c             ide control
de      dedevice                pci/if_de.c             network interface
ed      ed_pci_driver           pci/if_ed_p.c           network interface
fpa     pfadevice               pci/if_pfa.c            network interface
fxp     fxp_device              pci/if_pxp.c            network interface
lnc     lnc_pci_driver          pci/if_lnc_p.c          network interface
sr      sr_pci_driver           pci/if_sr_p.c           network interface
vx      vxdevice                pci/if_vx_pci.c         network interface
-------------------------------------------------------------------------

ISA     bus
        连接ISA bus的io设备的device driver的初始化在isa_configure()(@i386/
isa/isa.c)进行。和EISA,PCI很大的一个区别就是,在核心的配置文件中,要指定所
有的io地址等。
        configure文件中,有象如下的记录
                controller      控制设备名      at isa?...
                device          device名        at isa?...
        这些内容在编译核心的目录下作为ioconf.c的struct isa_device
isa_devtab_XXX[]的初始值由config命令写进去。在struct isa_device(@i386/isa
/isa_device.h)的上,其次的成员变量由configure文件的记录内容进行设定。但是
,“名字”是控制设备名/device名的数字除外的部分。
-------------------------------------------------------------------------
member名                configure的记述内容
-------------------------------------------------------------------------
id_driver               名字drvier
id_iobase               prot I/O address
id_irq                  irq号
id_drq                  drq DMA通道号
id_maddr                iomem共有memory address
id_msize                iosiz共有memory长度
id_intr                 vector device driver的中断处理程序名
id_unit                 名字的后的数字(?)
id_flags                flags
-------------------------------------------------------------------------

        但是,和控制设备/device名有关的一些东西如bio,net,tty出现的场合,这
些一般成为isa_devtab_bio[],isa_devtab_net[],isa_devtab_tty[]数组的初始值。
没有的情况,则成为isa_tab_null[]的初始值。还有一个就是名字driver,它是各个
device driver的module内部的struct isa_driver(@i386/isa/isa_device.h)一个东
西。对isa bus设备的device driver,这个是一个固定值。
象这样的记录:
------------------------------------------------------------
disk    device名        at      控制设备名      driver  数字
tape    device名        at      控制设备名      driver  数字
------------------------------------------------------------
每个数字除外控制设备名(wdc或者fdc),总结起来就是写进一个叫做
isa_biotab_控制设备名[]的数组的某个元素的初始设定值。但对unit成员填入数字
外,其他的也就和isa_devtab_bio[]的内容一样。
        isa_configure()依照isa_devtab_bio[],isa_devtab_net[],
isa_devtab_tty[]的设定值调用probe子程序对设备的有无进行确认。有的话就继续
调用attach子程序。
        probe子程序对设备进行确认,不同的probe子程序也有可能对同样的io地址
进行操作。所以为了防止这个问题,isa_configure()对已经确认过的的io地址不再
给别的probe进行动作。
        同样,错认的可能性也有的。必要的时候没连接的设备的probe要禁止使用,
(在boot的参数的时候)。

论坛徽章:
0
2 [报告]
发表于 2003-01-15 13:38 |只看该作者

[转贴]FreeBSD核心入门 作者:(日)大木敦雄 译:Liangvy

加入精华!

论坛徽章:
20
CU大牛徽章
日期:2013-04-17 11:48:26羊年新春福章
日期:2015-03-10 22:39:202015年中国系统架构师大会
日期:2015-06-29 16:11:282015亚冠之平阳省
日期:2015-07-31 09:19:042015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-09-30 06:20:002015亚冠之柏太阳神
日期:2015-10-19 20:29:5915-16赛季CBA联赛之天津
日期:2016-11-29 14:03:4315-16赛季CBA联赛之北控
日期:2016-12-24 20:51:492015年辞旧岁徽章
日期:2015-03-03 16:54:15双鱼座
日期:2015-01-12 20:58:532014年中国系统架构师大会
日期:2014-10-14 15:59:00
3 [报告]
发表于 2010-07-13 11:14 |只看该作者
日本人在开源上面还是比较有研究的

论坛徽章:
2
技术图书徽章
日期:2013-09-04 15:21:51酉鸡
日期:2013-11-01 21:20:20
4 [报告]
发表于 2010-07-13 11:48 |只看该作者
本帖最后由 mirnshi 于 2010-07-13 11:49 编辑

4.x版本的分析。vn设备在现在的版本上已经没有了,只有md了。楼上考古?

论坛徽章:
0
5 [报告]
发表于 2010-07-14 09:15 |只看该作者
日本人在开源上面还是比较有研究的
beyondfly 发表于 2010-07-13 11:14

所以日本人能做出ruby, 而中国人什么也做不出

论坛徽章:
0
6 [报告]
发表于 2010-07-14 10:32 |只看该作者
FreeBSD就是日本人介绍给我的,要不可能我现在都还不知道有个BSD,老实说,日本人在东方LOCALE问题上解决了不少问题,中国人在这点上算是托了日本的福了。另外搂主有排版好的文字下载吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP