pmon启动流程

来源:互联网 发布:windows命令行重启电脑 编辑:程序博客网 时间:2024/04/30 09:15
下面介绍的pmon流程,基于龙芯2c,计算所的北桥。

1 pmon的编译
1.1 pmon的配置
1)配置文件
总的配置文件在 :/usr/src/pmon-all/conf/files
开发板的配置文件: /usr/src/pmon-all/Target/bonito/conf/Bonito
其他配置文件还有 /usr/src/pmon-all/sys/dev/pci/files.pci
/usr/src/pmon-all/sys/dev/ata/files.ata
2)配置设置
我们这里最重要的是 /usr/src/pmon-all/Target/bonito/conf/Bonito文件
文件格式,#表示注释
include "conf/GENERIC_ALL1"
#包含/usr/src/pmon-all/conf/GENERIC_ALL1文件,其内容如下

#
# Module selection. Selects pmon features
#
select                mod_flash_amd                # AMD flash device programming
select                mod_flash_intel                # intel flash device programming
select                mod_flash_sst                # intel flash device programming
#目前pmon支持amd,inter和sst公司的flash的烧写,有两个作用,一是储存环境变量,二是在线更新bios
#
# Command selection. Selects pmon commands
#
#select                cmd_about                # Display info about PMON
select                cmd_boot                # Boot wrapper
select                cmd_cache                # Cache enabling
select                cmd_call                # Call a function command
select                cmd_mycfg
select                cmd_date                # Time of day command
select                cmd_env                        # Full blown environment command set
select                cmd_flash                # Flash programming cmds
select                cmd_hist                # Command history
select                cmd_ifaddr                # Interface address command
select                cmd_l                        # Disassemble
select                cmd_mem                        # Memory manipulation commands
select                cmd_more                # More paginator
select                cmd_mt                        # Simple memory test command
select                cmd_misc                # Reboot & Flush etc.
select                cmd_set                        # As cmd_env but not req. cmd_hist
select                cmd_stty                # TTY setings command
select                cmd_tr                        # Host port-through command
select                cmd_devls                # Device list
#
select                cmd_shell                # Shell commands, vers, help, eval
select                cmd_vers
select                cmd_help
select                cmd_eval
select      cmd_mycmd
select                cmd_newmt    #test86内层检测程序
select                cmd_setup     #条棒式配置程序
上面这些选项选择编译那些命令到pmon中
option      CONFIG_CACHE_64K_4WAY
#龙芯2c的cache设置4路,64k.
再返回到原配置文件中
# Platform options
#
option                BONITOEL        #平台北桥的类型,计算所binito结构北桥
option                MIPS
option                INET

select                mod_uart_ns16550        # Standard UART driver
option                CONS_BAUD=B115200
#串口的波特率设置
select                ext2
select                 iso9660
#pmon支持ext2,iso9660文件系统,可以从网络硬盘软驱光驱引导内核
select                mod_x86emu_int10
#显卡rom模拟程序
select                mod_vgacon
#显示器和键盘虚拟终端
option                 AUTOLOAD
#pmon起动后,自动引导内核
# Functional options.
#
option                HAVE_TOD                # Time-Of-Day clock
#实时钟
option                HAVE_NVENV                #  Platform has non-volatile env mem
#环境变量支持
option                 NVRAM_IN_FLASH       
#打开这个选项环境变量存储在flash中,关闭环境变量存在cmos中
option      HAVE_NB_SERIAL
#北桥有串口,在正式的电路板中北桥无串口
#下面是pmon的设备树的设置
#
#  Now the Machine specification
#
mainbus0        at root
localbus0        at mainbus0
fd0         at mainbus0
#软驱驱动
pcibr0                at mainbus0
pci*                at pcibr?
# fxp normally only used for debugging (enable/disable both)
fxp0            at pci? dev ? function ?        # Intel 82559 Device
inphy*          at mii? phy ?                   # Intel 82555 PHYs
#82559网卡驱动
##########82546
#82546 use a lot of memory so setup NKMEMCLUSTERS as bellow
#         #define NKMEMCLUSTERS   (16 * 1024 * 1024 / CLBYTES)        /* 0.5Mb */
em*            at pci? dev ? function ?        # Intel 82559 Device
#82546网卡驱动
#### IDE controllers
pciide*         at pci ? dev ? function ? flags 0x0000

#### IDE hard drives
wd*                at pciide? channel ? drive ? flags 0x0000
#硬盘驱动
ide_cd*         at pciide? channel ? drive ? flags 0x0001
#光驱驱动
1.2 pmon的编译

Cd /usr/src/pmon-all/zloader
Make cfg #根据配置文件重新产生makefile
Make tgt=rom #生成rom bin文件gzrom.bin
Make tgt=ram #生成网络加载文件gzram,通过网络tftp重新加载pmon在调pmon程序的时候很有用
也可以用老的编译方法
cd /usr/src/pmon-all/Targets/Bonito/conf
pmoncfg Bonito
cd /usr/src/pmon-all/Targets/Bonito/compile/Bonito
make
2.利用gdb来分析pmon
2.1.得到编译信息
要使生成的pmon带编译信息,改 Targets/Bonito/compile/Bonito/Makefile
直接将gcc 改成了gcc -ggdb -g3
将Makefile中的
STRIPFLAGS=     -g -S --strip-debug
LFLAGS+=        -S
注释掉。其中ld的参数 -S和--strip-debug的作用是去掉调试的信息。
STRIPFLAGS=     #-g -S --strip-debug
LFLAGS+=        #-S
make DEBUG=-g
2.使用gdb
mips-elf-gdb pmon
(gdb) target sim
load
(gdb) disassemble  0xffffffff80010000

0xffffffff80010030 <uncached>:  lui     $at,0xa000
0xffffffff80010034 <uncached+4>:        or      $ra,$ra,$at
0xffffffff80010038 <uncached+8>:        jr      $ra
反汇编出来的和原来的不一样
其他gdb使用方面的知识就不介绍了。
3.pmon的起动流程
Targets/Bonito是计算所北桥相关的代码位置,起动代码为Targets/Bonito/Bonito/start.S.
看代码的时候要注意pmon中的一些宏是定义在头文件中的,另一些则定义在Makefile中,通过gcc参数-D来定义。
3.1mips cpu和北桥的基本知识

    kseg0: 0x8000 0000 - 0x9FFF FFFF(512M): 只需要把最高位清零,这些地址就被转换(translate)为物理地址,
然后把它们连续地映射到物理内存中512M大小的低字段 (0x0000 0000 - 0x1FFF FFFF)内。这种转换是很简单的,
因此常常把这些地址称为“无需转换的“。一般情况下,都是通过快速缓存(cache),对这段区域内的地址进行访问。
因此在cache被正确地初始化之前,不要使用这些地址。通常,在没有MMU的系统中,这段区域用于存放大多数程序和数据。
至于有MMU的系统,操作系统的内核会存放在这个区域。
    kseg1: 0xA000 0000 - 0xBFFF FFFF(512M): 通过将最高3位清零的方法,把这些地址映射为相应的物理地址,然后象kseg0一样,
再映射到物理内存中512M大小的低字段。但要注意,kseg1是不通过cache存取的(uncached)。kseg1是唯一的在系统重启时能正常工作
的地址空间,这也是为什么重新启动时的入口向量0xBFC0 0000会在这个区域内。入口向量对应的物理地址是0x1FC0 0000――这个应该
告诉你的硬件工程师。
因此,你可以使用这段地址空间来访问你的初始化程序的ROM。还有大多数人把它用来访问I/O寄存器。如果你的硬件工程师要把这些东西
映射到非低段512M物理空间,那你应该试图说服他们修改。
kseg2: 0xC000 0000 - 0xFFFF FFFF (1GB): 这段地址空间只能在核心态下使用并且要经过MMU的转换。在MMU设置好之前,
不要对其进行访问。通常,除非你在写一个真正的操作系统,否则都不必使用这段地址空间。

maped指的是要经过TLB进行虚拟内存的翻译。cached指先从cache取,未命中才从内存中取。
从北桥的映射图上看其大部分区域映射在低512M物理内存上。省下三个段512M-2G maps 1-1 on pci access用处不大,2G-4G pci窗口,4G以上sdram。

3.2 代码分析
总的来说:
1)启动位置位于cpu的启动地址是0xbfc00000,这个地址对应的物理地址是0x1fc00000,北桥将这一地址影射到flash的0地址上.
因此准确的说pmon是从flash的0地址开设运行。编译的时候start.o正好是第一个被链接的obj文件,因此start.S的第一条指令是cpu运行的第一个指令,位于_start。
2)c代码的第一个入口是initmips,位于tgt_machdep.c中。最后程序到main函数中运行命令循环。
3)pmon开始应该是freebsd移植过来的,系统调用,设备驱动是unix风格的。
4)pmon中cpu运行于32位模式下,是关中断运行。pmon完全靠查询来完成整个系统,技巧是idle函数中调用scandevs来扫描设备驱动程序。驱动程序 中的中断也是通过被系统查询的时候不断调用来实现的。
5)在cpu的状态寄存器中有一个bev,设置异常向量从rom中取,还是重ram中取.
            bcopy(MipsException, (char *)TLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException);
            bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException);

下面具体介绍启动流程:

start.S中
_start:
start:
        .globl        stack
stack = start - 0x4000                /* Place PMON stack below PMON start in RAM */

/* NOTE!! Not more that 16 instructions here!!! Right now it's FULL! */
        mtc0        zero, COP_0_STATUS_REG
        mtc0        zero, COP_0_CAUSE_REG
        li        t0, SR_BOOT_EXC_VEC        /* Exception to Boostrap Location */
        mtc0        t0, COP_0_STATUS_REG
        la        sp, stack
        la        gp, _gp

        bal        uncached                /* Switch to uncached address space */
        nop

        bal        locate                        /* Get current execute address */
        nop
从pmon中反汇编得到
(gdb) disassemble 0xffffffff80010000
Dump of assembler code for function start:
0xffffffff80010000 <start>:     mtc0    $zero,$12
0xffffffff80010004 <start+4>:   mtc0    $zero,$13
0xffffffff80010008 <start+8>:   lui     $t0,0x40
0xffffffff8001000c <start+12>:  mtc0    $t0,$12
0xffffffff80010010 <start+16>:  lui     $sp,0x8001
0xffffffff80010014 <start+20>:  daddiu  $sp,$sp,-16384 #0xffffc000
0xffffffff80010018 <start+24>:  lui     $gp,0x8009
0xffffffff8001001c <start+28>:  daddiu  $gp,$gp,30800
0xffffffff80010020 <start+32>:  bal     0x80010030
0xffffffff80010024 <start+36>:  nop
0xffffffff80010028 <start+40>:  bal     0x80010638
0xffffffff8001002c <start+44>:  nop
可以看出sp的指向的位置,并不是指向flash,因此开始的堆栈用的就是sdram
bal uncached
nop
bal locate
nop
uncached:
or ra, UNCACHED_MEMORY_ADDR
j ra
nop
#machine/cpu.h
#define UNCACHED_MEMORY_ADDR    0xa0000000

此处是可以从cache空间转换到uncache的空间,ra中保留的是bal_locate这条指令的地址,然后或上UNCACHED_MEMORY_ADDR,该地址就变成uncache的地址了.
为什么pmon的启动地址为0xbfc00000,而ld生成代码的text段的起始地址为0x80010000
应该有从flash到ram的搬移过程
la      s0, start            
       subu    s0, ra, s0
       and     s0, 0xffff0000
   
     这段代码是为了访问数据,因为这段汇编在Rom执行,而编译出来的数据段在0x8002xxxx,为了能够访问数据段的数据,需要进行一个
     地址的修正,s0这是起到这种修正的目的。

bal     1f
nop
BONITO_BIC(BONITO_BONPONCFG,BONITO_BONPONCFG_CPUBIGEND)
展开后变成
.word   0x00000018 | 0x00000002  ,((  0x1fe00000  +( ( 0x100  + 0x00 )   )  ) | 0xa0000000 ) ;  .word   ( ~( 0x00004000  ) ),( 0 )
后面的程序解析这些数据完成对应的初始化操作
...
        EXIT_INIT(0)
展开后变成
.word   0x00000000 ,( 0 );      .word   0,0
这样初始化数据定义完成
下面的程序
1:        move a0,ra
因为前面bal     1f,因此此时ra的值恰好就是定义的初始化数据的地址,下面的reginit开始的
一段程序解析前面的数据来对寄存器进行配置

reginit:                        /* local name */
        lw        t3, Init_Op(a0)
        lw        t0, Init_A0(a0)
        and        t4,t3,OP_MASK
        /*
         * EXIT(STATUS)
         */
        bne        t4, OP_EXIT, 8f
        nop
        move        v0,t0
        b        .done
        nop
        剩下的初始化寄存器的过程省略
       
.done:       
        /* Initialise other low-level I/O devices */

        bal        initserial
        nop
       

        PRINTSTR("/r/nPMON2000 MIPS Initializing. Standby.../r/n")
       
        PRINTSTR("ERRORPC=")
        mfc0        a0, COP_0_ERROR_PC
        bal        hexserial
        nop

        PRINTSTR(" CONFIG=")
        mfc0        a0, COP_0_CONFIG
        bal        hexserial
        nop
        PRINTSTR("/r/n")
       
        PRINTSTR(" PRID=")
        mfc0        a0, COP_0_PRID
        bal        hexserial
        nop
        PRINTSTR("/r/n")
        简单的打印一些寄存器的值
        ....
        一些sdram的配置
        1:        sw        sdCfg,BONITO_SDCFG(bonito)
       
2:        b        3f       
        nop
3:
...
配置pci内存影射
        li        t1,0                # accumulate pcimembasecfg settings
               
        /* set bar0 mask and translation to point to SDRAM */
        sub        t0,msize,1
        not        t0
        srl        t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE0_MASK_SHIFT
        and        t0,BONITO_PCIMEMBASECFG_MEMBASE0_MASK
        or        t1,t0
       
        li        t0,0x00000000
        srl        t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE0_TRANS_SHIFT
        and        t0,BONITO_PCIMEMBASECFG_MEMBASE0_TRANS
        or        t1,t0
        or        t1,BONITO_PCIMEMBASECFG_MEMBASE0_CACHED

        /* set bar1 to minimum size to conserve PCI space */
        li        t0, ~0
        srl        t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE1_MASK_SHIFT
        and        t0,BONITO_PCIMEMBASECFG_MEMBASE1_MASK
        or        t1,t0
       
        li        t0,0x00000000
        srl        t0,BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE1_TRANS_SHIFT
        and        t0,BONITO_PCIMEMBASECFG_MEMBASE1_TRANS
        or        t1,t0
        or        t1,BONITO_PCIMEMBASECFG_MEMBASE1_CACHED

        sw        t1,BONITO_PCIMEMBASECFG(bonito)

        /* enable configuration cycles now */
        lw        t0,BONITO_BONPONCFG(bonito)
        and        t0,~BONITO_BONPONCFG_CONFIG_DIS
        sw        t0,BONITO_BONPONCFG(bonito)

        PRINTSTR("Init SDRAM Done!/r/n");

地址译码的结果和bonito64 的相兼容,为了实现对大容量(2GB)
存储器的支持,将原来的0x8000_0000~0x1_0000_0000 之间的2GB 空间分配给了SDRAM,
为了保持软件的兼容性,把2GB 空间的低256MB 和起始的256MB 存储空间重叠,对应同
一块存储区。
<img src=北桥设计文档.pdf:北桥内部地址空间分配>
初始化cache,将cache寄存器中填入内容,并cache有效?
...

下面完成程序和数据从flash到内存的拷贝

        la        a0, start
        li        a1, 0xbfc00000
        la        a2, _edata
        or      a0, 0xa0000000
        or      a2, 0xa0000000
        subu        t1, a2, a0
        srl        t1, t1, 2

        move        t0, a0
        move        t1, a1
        move        t2, a2

        /* copy text section */
       
1:        and        t3,t0,0x0000ffff
        bnez        t3,2f
        nop
        move        a0,t0
        bal        hexserial
        nop
        li        a0,'/r'
        bal         tgt_putchar
        nop
2:        lw        t3, 0(t1)
        nop
        sw        t3, 0(t0)
        addu        t0, 4
        addu        t1, 4
        bne        t2, t0, 1b
        nop

        PRINTSTR("/ncopy text section done./r/n")
       
        /* Clear BSS */
        la        a0, _edata
        la        a2, _end
2:        sw        zero, 0(a0)
        bne        a2, a0, 2b
        addu        a0, 4


        TTYDBG("Copy PMON to execute location done./r/n")
/* zhb */
#if 0
zhb:
        TTYDBG("Testing.../r/n")
        la        a0, start
        li        a1, 0xbfc00000
        la        a2, _edata
        or      a0, 0xa0000000
        or      a2, 0xa0000000
/*        subu        s6, a2, a0*/
/*        srl        s6, s6, 2*/

        move        t0, a0
        move        t1, a1
        move        t2, a2
        /* copy text section */
       
1:        lw        t4, 0(t1)
        nop
        lw        t5, 0(t0)
        addu        t0, 4
        addu        t1, 4
        beq        t4, t5, 2f
        nop
        move        a0, t0
        subu        a0, 4
        bal        hexserial
        nop
        TTYDBG        (" ")
        move        a0, t4
        bal        hexserial
        nop
        TTYDBG        (" ")
        move        a0, t5
        bal        hexserial
        nop
        TTYDBG        ("/r/n")
2:        bne        t2, t0, 1b
        nop
        TTYDBG        ("test ok!/r/n")
3:        beqz        zero, 3b
        nop
#endif

       
#if 1
        mfc0   a0,COP_0_CONFIG
        and    a0,a0,0xfffffff8
        or     a0,a0,0x2
        mtc0   a0,COP_0_CONFIG
#endif

        li        a0, 4096*1024
        sw        a0, CpuTertiaryCacheSize /* Set L3 cache size */
        move        a0,msize
        srl        a0,20
        la        v0, initmips
        jalr        v0
        nop
       
其中initmips是c代码的入口,初始化过程结束
initmips传入了memorysize,其中memorysize是start.S中的msize,是根据sdram内存条的信息计算出来的。

/home/dsm/pmon2003/src/Targets/Bonito/Bonito/tgt_machdep.c:
140     void
141     initmips(unsigned int memsz)
142     {
143             /*
144              *      Set up memory address decoders to map entire memory.
145              *      But first move away bootrom map to high memory.
146              */
147     #if 0
148             GT_WRITE(BOOTCS_LOW_DECODE_ADDRESS, BOOT_BASE >> 20);
149             GT_WRITE(BOOTCS_HIGH_DECODE_ADDRESS, (BOOT_BASE - 1 + BOOT_SIZE) >> 20);
150     #endif
151             memorysize=(memsz&0x0000ffff) << 20;//recover to original size:256M
152             memorysize_high=((memsz&0xffff0000)>>16) << 20;//0
153
154             /*
155              *  Probe clock frequencys so delays will work properly.
156              */
157             tgt_cpufreq();
158             SBD_DISPLAY("DONE",0);
159             /*
160              *  Init PMON and debug
161              */
162             cpuinfotab[0] = &DBGREG;
163             dbginit(NULL);
164
165             /*
166              *  Set up exception vectors.
167              */
168             SBD_DISPLAY("BEV1",0);
169             bcopy(MipsException, (char *)TLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException);
170             bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException);
171
172             CPU_FlushCache();
173
174             CPU_SetSR(0, SR_BOOT_EXC_VEC);
175             SBD_DISPLAY("BEV0",0);
176
177             printf("BEV in SR set to zero./n");
178
179     #if 0
180             /* memtest */
181             addr_tst1();
182             addr_tst2();
183             movinv1(2,0,~0);
184             movinv1(2,0xaa5555aa,~0xaa5555aa);
185             printf("memtest done/n");
186     #endif
187
188             /*
189              * Launch!
190              */
191             main();
192     }

其中很重要的是dbginit

/home/dsm/pmon2003/src/pmon/common/main.c:
284     void
285     dbginit (char *adr)
286     {
287             int     memsize, freq;
288             char    fs[10], *fp;
289             char    *s;
290
291             /*splhigh();*/
292
293             memsize = memorysize;
(gdb)
294
295             SBD_DISPLAY ("mems", CHKPNT_ENVI);
296             __init();       /* Do all constructor initialisation */
297
298
299             SBD_DISPLAY ("ENVI", CHKPNT_ENVI);
300             envinit ();
301
302     #if defined(SMP)
303             /* Turn on caches unless opted out */
(gdb)
304             if (!getenv("nocache"))
305                     md_cacheon();
306     #endif
307
308             SBD_DISPLAY ("DEVI", CHKPNT_SBDD);
309             tgt_devinit();
310
311     #ifdef INET
312             SBD_DISPLAY ("NETI", CHKPNT_NETI);
313             init_net (1);
(gdb)
314     #endif
315
316     #if NCMD_HIST > 0
317             SBD_DISPLAY ("HSTI", CHKPNT_HSTI);
318             histinit ();
319     #endif
320
321     #if NMOD_SYMBOLS > 0
322             SBD_DISPLAY ("SYMI", CHKPNT_SYMI);
323             syminit ();
(gdb)
324     #endif
325
326     #ifdef DEMO
327             SBD_DISPLAY ("DEMO", CHKPNT_DEMO);
328             demoinit ();
329     #endif
330
331             SBD_DISPLAY ("SBDE", CHKPNT_SBDE);
332             initial_sr |= tgt_enable (tgt_getmachtype ());
333
(gdb)
334     #ifdef SR_FR
335             Status = initial_sr & ~SR_FR; /* don't confuse naive clients */
336     #endif
337             /* Set up initial console terminal state */
338             ioctl(STDIN, TCGETA, &consterm);
339
340     #ifdef HAVE_LOGO
341             tgt_logo();
342     #else
343             printf ("/n * PMON2000 Professional *");
(gdb)
344     #endif
345             printf ("/nConfiguration [%s,%s", TARGETNAME,
346                             BYTE_ORDER == BIG_ENDIAN ? "EB" : "EL");
347     #ifdef INET
348             printf (",NET");
349     #endif
350     #if NSD > 0
351             printf (",SCSI");
352     #endif
353     #if NWD > 0
(gdb)
354             printf (",IDE");
355     #endif
356             printf ("]/nVersion: %s./n", vers);
357             printf ("Supported loaders [%s]/n", getExecString());
358             printf ("Supported filesystems [%s]/n", getFSString());
359             printf ("This software may be redistributed under the BSD copyright./n");
360
361             //print_cmd_name();
362
363             tgt_machprint();
(gdb)
364
365             freq = tgt_pipefreq ();
366             sprintf(fs, "%d", freq);
367             fp = fs + strlen(fs) - 6;
368             fp[3] = '/0';
369             fp[2] = fp[1];
370             fp[1] = fp[0];
371             fp[0] = '.';
372             printf (" %s MHz", fs);
373
(gdb)
374             freq = tgt_cpufreq ();
375             sprintf(fs, "%d", freq);
376             fp = fs + strlen(fs) - 6;
377             fp[3] = '/0';
378             fp[2] = fp[1];
379             fp[1] = fp[0];
380             fp[0] = '.';
381             printf (" / Bus @ %s MHz/n", fs);
382
383             printf ("Memory size %3d MB (%3d MB Low memory, %3d MB High memory) ./n",
(gdb)
384                     (memsize+memorysize_high)>>20,(memsize>>20), (memorysize_high>>20));
385
386             tgt_memprint();
387     #if defined(SMP)
388             tgt_smpstartup();
389     #endif
390
391             printf ("/n");
392
393             md_clreg(NULL);
(gdb)
394             md_setpc(NULL, (int32_t) CLIENTPC);
395             md_setsp(NULL, tgt_clienttos ());
396     #ifdef AUTOLOAD
397             s = getenv ("al");
398             autoload (s);
399     #else
400             s = getenv ("autoboot");
401             autorun (s);
402     #endif
403     }
__init():构造函数初始化.
将所有的constructor的函数执行一遍,建立一些基本的数据结构。在pmon中有三类constructor函数,它们都是静态函数。
1)        命令处理初始化函数,位于pmon/cmds目录下,其名称都叫init_cmd()。
init_cmd是静态函数,几乎在每个命令文件中都有.
2)        文件系统初始化函数。pmon/fs目录下。函数名称叫init_fs()或者init_xxxfs()。
init_diskfs,init_fs,init_netfs等每个都是静态函数.
如src/pmon/fs/diskfs.c中
static FileSystem diskfs =
{
        "fs",FS_FILE,
        diskfs_open,
        diskfs_read,
        diskfs_write,
        diskfs_lseek,
        diskfs_close,
        NULL
};

static void init_fs __P((void)) __attribute__ ((constructor));

static void
   init_fs()
{
        /*
         * Install diskfs based file system.
         */
        filefs_init(&diskfs);
}
int
filefs_init(FileSystem *fs)
{
        SLIST_INSERT_HEAD(&FileSystems, fs, i_next);
        return(0);
}
文件系统初始化就是代表各个文件系统的数据结构插入到相应链表。
对于磁盘文件系统,链表的头指针式DiskFileSystems。对于其他的文件系统,头指针是FileSystems。
这样当需要对某个文件操作(包括虚拟文件,如与用户交互的终端termio)。通过这两个链表可以找到相应的结构,
在通过里面的函数指针就可以对文件进行具体操作了。

3)        可执行文件类型初始化。在pmon/loader目录下。函数名称叫init_exec()
<input type="image" src="">

(gdb) l __init
89
90              /*
91               * Call global constructors.
92               * Arrange to call global destructors at exit.
93               */
94              if (!initialized) {
95                      initialized = 1;
96                      __ctors();
97              }
98      }
75      static void
76      __ctors()
77      {
78              void (**p)(void) = __CTOR_LIST__ + 1;
79
80              while (*p) {
81                      (**p++)();
82              }
83      }

    envinit ();初始化环境变量.从flash中读取并设置环境变量等
    tgt_devinit();初始化与板级相关的过程,在我们系统中主要是初始化北桥和PCI.
    241     void
242     tgt_devinit()
243     {
244             /*
245              *  Gather info about and configure caches.
246              */
247             if(getenv("ocache_off")) {
(gdb)
248                     CpuOnboardCacheOn = 0;
249             }
250             else {
251                     CpuOnboardCacheOn = 1;
252             }
253             if(getenv("ecache_off")) {
254                     CpuExternalCacheOn = 0;
255             }
256             else {
257                     CpuExternalCacheOn = 1;
(gdb)
258             }
259
260            CPU_ConfigCache();
261
262            //godson2_cache_flush();
263
264            //tgt_putchar('&');
265            
266            //test_icache_2(0);
267            //test_icache_3(0);
(gdb)
268            //tgt_putchar(0x30+i);
269            //tgt_putchar('Y');
270           
271            //tgt_test_memory();
272
273            //tgt_putchar('Z');
274
275             _pci_businit(1);        /* PCI bus initialization */
276     }

(gdb) info functions CPU_ConfigCache
File /home/dsm/pmon2003/src/pmon/arch/mips/cache.S:
<function, no debug info> CPU_ConfigCache;

873     _pci_businit (int init)
874     {
...
init = _pci_hwinit (init, &def_bus_iot, &def_bus_memt);
...
}
904_pci_hwinit初始化北桥的寄存器
tgt_devinit()>_pci_businit()>_pci_hwinit
pci_hwinit() 为Pmon主要初始化PCI在北桥的窗口的函数
Located in /home/dsm/pmon2003/src/Targets/Bonito/pci/pci_machdep.c

68      int
69      _pci_hwinit(initialise, iot, memt)
70              int initialise;
71              bus_space_tag_t iot;
72              bus_space_tag_t memt;
73      {
74              /*pcireg_t stat;*/
75              struct pci_device *pd;
76              struct pci_bus *pb;
77
(gdb)
78
79              if (!initialise) {
80                      return(0);
81              }
82
83              pci_local_mem_pci_base = PCI_LOCAL_MEM_PCI_BASE;
84              /*
85               *  Allocate and initialize PCI bus heads.
86               */
87
(gdb)
88              /*
89               * PCI Bus 0
90               */
91              pd = pmalloc(sizeof(struct pci_device));
92              pb = pmalloc(sizeof(struct pci_bus));
93              if(pd == NULL || pb == NULL) {
94                      printf("pci: can't alloc memory. pci not initialized/n");
95                      return(-1);
96              }
97
(gdb)   
98              pd->pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
99              pd->pa.pa_iot = pmalloc(sizeof(bus_space_tag_t));
100             pd->pa.pa_iot->bus_reverse = 1;
101             pd->pa.pa_iot->bus_base = BONITO_PCIIO_BASE_VA;
102             //printf("pd->pa.pa_iot=%p,bus_base=0x%x/n",pd->pa.pa_iot,pd->pa.pa_iot->bus_base);
103             pd->pa.pa_memt = pmalloc(sizeof(bus_space_tag_t));
104             pd->pa.pa_memt->bus_reverse = 1;
105             pd->pa.pa_memt->bus_base = PCI_LOCAL_MEM_PCI_BASE;
106             pd->pa.pa_dmat = &bus_dmamap_tag;
107             pd->bridge.secbus = pb;
(gdb)
108             _pci_head = pd;
109
110             pb->minpcimemaddr  = PCI_MEM_SPACE_PCI_BASE+0x01000000;
111             pb->nextpcimemaddr = PCI_MEM_SPACE_PCI_BASE+BONITO_PCILO_SIZE;
112             pb->minpciioaddr  = PCI_IO_SPACE_BASE+0x000a000;
113             pb->nextpciioaddr =PCI_IO_SPACE_BASE+ BONITO_PCIIO_SIZE;
114             pb->pci_mem_base   = BONITO_PCILO_BASE_VA;
115             pb->pci_io_base    = BONITO_PCIIO_BASE_VA;
116             pb->max_lat = 255;
117             pb->fast_b2b = 1;
(gdb)
118             pb->prefetch = 1;
119             pb->bandwidth = 4000000;
120             pb->ndev = 1;
121             _pci_bushead = pb;
122             _pci_bus[_max_pci_bus++] = pd;
123
124
125             bus_dmamap_tag._dmamap_offs = 0;
126
127             /*set Bonito register*/
(gdb)
128             BONITO_PCIMAP =
129                 BONITO_PCIMAP_WIN(0, PCI_MEM_SPACE_PCI_BASE+0x00000000) |
130                 BONITO_PCIMAP_WIN(1, PCI_MEM_SPACE_PCI_BASE+0x04000000) |
131                 BONITO_PCIMAP_WIN(2, PCI_MEM_SPACE_PCI_BASE+0x08000000) |
132                 BONITO_PCIMAP_PCIMAP_2;
133
134             BONITO_PCIBASE0 = PCI_LOCAL_MEM_PCI_BASE;
135             BONITO_PCIBASE1 = PCI_LOCAL_MEM_ISA_BASE;
136             BONITO_PCIBASE2 = PCI_LOCAL_MEM_PCI_BASE + 0x10000000;
137
(gdb)
138             return(1);
139     }

建立PCI的空间分配的数据结构.其中pci_mem_base为Memory空间的基地址,pci_io_base为IO空间的基地址.
pd->pa.pa_iot对应于pci io空间分配
pd->pa.pa_memt对应于pci mem空间分配
minipciioaddr为IO空间的最小可以分配地址,minipcimemaddr为Memory空间的最小可以分配地址.
nextpcimemaddr为PCI的Memory空间的下一个分配地址,nextpciioaddr为PCI的IO空间的下一个分配地址,
在pmon的中地址分配是逆序分配的.
要分清cpu访问pci的地址和pci访问cpu内存的地址,pcimap寄存器定义的是cpu访问pci的地址,pcimap决定cpu访问pci的地址翻译
pcilo,pcil1,pcilo2分别位于0x10000000-0x1C000000的3个64M的窗口
pciio位于0x000a000;
#define BONITO_PCILO_BASE_VA    0xb0000000
#define BONITO_PCILO_SIZE               0x0c000000
这正好是包括PCI Lo0-Lo2的64Mx3 pci内存窗口
注意0xa0000000是地址uncache bit.因此BONITO_PCILO_BASE_VA就是0x10000000。
#define BONITO_PCIIO_BASE_VA            0xbfd00000
#define BONITO_PCIIO_SIZE               0x00010000
这是低1M的pci io空间窗口.
pci设备北桥的寄存器叫pcibase0-2,这是因为北桥本身是一个pci设备,这三个寄存器就是其配置空间的寄存器。
问题,如果有多个pci master,谁有权利来分配地址空间
cpu通过pci查找找到外设,并分配地址空间,北桥自己的地址空间,cpu什么时候分配的
北桥的配置空间的pcibase0-pcibase2就是北桥本身在pci地址空间上分配的位置。
其中_pci_bushead被设置成为
108             _pci_head = pd;
121             _pci_bushead = pb;
122             _pci_bus[_max_pci_bus++] = pd;


(gdb) l _pci_businit
872     void
873     _pci_businit (int init)
874     {
(gdb)
875             char *v;
876
877             v = getenv("pciverbose");
878             if (v) {
879                 _pciverbose = atol(v);
880             }
881
882             /* intialise the PCI bridge */
883             if (init) {
884                     SBD_DISPLAY ("PCIH", CHKPNT_PCIH);
(gdb)
885                     init = _pci_hwinit (init, &def_bus_iot, &def_bus_memt);
886                     pci_roots = init;//pci_roots = 1;
887                     if (init < 1)
888                             return;
889             }
890             if(monarch_mode) {
891                     int i;
892                     struct pci_device *pb;
893
894                     if (_pciverbose) {
(gdb)
895                             printf("setting up %d bus/n", init);
896                     }
897                     for(i = 0, pb = _pci_head; i < pci_roots; i++, pb = pb->next) {
898                             //_pci_scan_dev(pb, i, 0, init);
899                             _pci_scan_dev(pb, i, 8, init);//from 8+11, hu mingchang
900                     }
901                     _setup_pcibuses(init);
902             }
903     }

191     pcitag_t
192     _pci_make_tag(bus, device, function)
193             int bus;
194             int device;
(gdb)
195             int function;
196     {
197             pcitag_t tag;
198
199             tag = (bus << 16) | (device << 11) | (function << 8);
200             return(tag);
201     }
//从下面的pci配置空间的读操作可以看出,PCI的配置空间的访问分两种情况,类型0和类型1.
其中bus为0的为局部总线访问,采用的是pci类型0;bus为非0的是pci桥的访问采用的是pci类型1.两种类型的pci访问采用的地址译码的方法不同.下面的表说明在pci配置空间访问的时候,出现在pci AD总线上的地址的格式.
Pci ad bus 配置的空间为{ AD16UP ,cpuaddr[15:2],1’b0, Type1}
AD31                                         24 23     16 15           11 10             8 7              2 1   AD0
AD31-11 value-system dependent - to create correct IDSEL                 | Function Number| Register Number| 0| 0
             Fields for ‘‘Type 0’’ cycles

AD31-24 value as needed to create correct IDSEL|Bus Number| Device Number| Function Number| Register Number| 0 | 1
             Fields for ‘‘Type 1’’ cycles

pcireg_t
_pci_conf_readn(pcitag_t tag, int reg, int width)
{
    u_int32_t addr, type;
    pcireg_t data;
    int bus, device, function;

    if ((reg & (width-1)) || reg < 0 || reg >= 0x100) {
        if (_pciverbose >= 1)
            _pci_tagprintf (tag, "_pci_conf_read: bad reg 0x%x/n", reg);
        return ~0;
    }

    _pci_break_tag (tag, &bus, &device, &function);
    if (bus == 0) {
        /* Type 0 configuration on onboard PCI bus */
        if (device > 20 || function > 7)
            return ~0;                /* device out of range */
        addr = (1 << (device+11)) | (function << 8) | reg;
        type = 0x00000;
    }
    else {
        /* Type 1 configuration on offboard PCI bus */
        if (bus > 255 || device > 31 || function > 7)
            return ~0;        /* device out of range */
        addr = (bus << 16) | (device << 11) | (function << 8) | reg;
        type = 0x10000;
    }

    /* clear aborts */
    BONITO_PCICMD |= PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT;

    BONITO_PCIMAP_CFG = (addr >> 16) | type;
    data = *(volatile pcireg_t *)PHYS_TO_UNCACHED(BONITO_PCICFG_BASE | (addr & 0xfffc));


    if (BONITO_PCICMD & PCI_STATUS_MASTER_ABORT) {
        BONITO_PCICMD |= PCI_STATUS_MASTER_ABORT;
#if 0
        if (_pciverbose >= 1)
            _pci_tagprintf (tag, "_pci_conf_read: reg=%x master abort/n", reg);
#endif
        return ~0;
    }

    if (BONITO_PCICMD & PCI_STATUS_MASTER_TARGET_ABORT) {
        BONITO_PCICMD |= PCI_STATUS_MASTER_TARGET_ABORT;
        if (_pciverbose >= 1)
            _pci_tagprintf (tag, "_pci_conf_read: target abort/n");
        return ~0;
    }

    return data;
}

_pci_scan_dev代码
static void
_pci_scan_dev(struct pci_device *dev, int bus, int device, int initialise)
{
        //for(; device < 32; device++)
        for(; device < 19; device++) //to 19+11, hu mingchang
        {
                _pci_query_dev (dev, bus, device, initialise);
        }
}

循环扫描pci设备,首先根据配置空间的ID是否为0或-1,来确定设备是否存在。
然后读PCI BIST/Header Type/Latency Timer/Cache Line Size Register判断设备是否是multi function
对于multi function的情况,0-7每个function调用_pci_query_dev_func。对于只有一个function的情况,直接调用_pci_query_dev_func。
_pci_query_dev_func>
读取配置空间的classid
建立这个设备的pci_device结构,并挂接到设备树上,每个function看作一个设备,挂在parent->bridge.child上,其中parent是现在
查询子设备的pci设备。
清PCI_COMMAND_STATUS_REG中的PCI_COMMAND_MASTER_ENABLE |
                  PCI_COMMAND_IO_ENABLE |
                  PCI_COMMAND_MEM_ENABLE暂时禁用设备,设备在后面安装驱动程序后会重新使能。
{
class = _pci_conf_read(tag, PCI_CLASS_REG);
     id = _pci_conf_read(tag, PCI_ID_REG);
         ...
        _pci_break_tag (tag, &bus, &device, &function);

        pd->pa.pa_bus = bus;
        pd->pa.pa_device = device;
        pd->pa.pa_function = function;
        pd->pa.pa_tag = tag;
        pd->pa.pa_id = id;
        pd->pa.pa_class = class;
        pd->pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
        pd->pa.pa_iot = dev->pa.pa_iot;
        //printf("_pci_query_dev_func:devnum=0x%x,pd->pa.pa_iot=0x%p,pd->pa.pa_iot->bus_base=0x%x/n",device,pd->pa.pa_iot,pd->pa.pa_iot->bus_base);
        pd->pa.pa_memt = dev->pa.pa_memt;
        pd->pa.pa_dmat = dev->pa.pa_dmat;

//(note)pa_iot,pa_memt,pa_dmat都只是说明总线的iobase,membase,dmabase地址.
//(note)所有设备的设定都是相同的,就是北桥的设定.

        pd->parent = dev;
        pd->pcibus = dev->bridge.secbus;
        pb = pd->pcibus;
        _pci_device_insert(dev, pd);
        ...
}
如果设备的class code=0x060400,则说明该设备是PCI 桥。
{
        pd->bridge.pribus_num = bus;
                pd->bridge.secbus_num =  ++_pci_nbus;
                /* Set it temperary to same as secondary bus number */
                pd->bridge.subbus_num =  pd->bridge.secbus_num;

                tmp = _pci_conf_read(tag, PCI_PRIBUS_1);
                tmp &= 0xff000000;
                tmp |= pd->bridge.pribus_num;
                tmp |= pd->bridge.secbus_num << 8;
                tmp |= pd->bridge.subbus_num << 16;
                _pci_conf_write(tag, PCI_PRIBUS_1, tmp);

                /* Update sub bus number */
                for(pcidev = dev; pcidev != NULL; pcidev = pcidev->parent) {
                        pcidev->bridge.subbus_num = pd->bridge.secbus_num;
                        tmp = _pci_conf_read(pcidev->pa.pa_tag, PCI_PRIBUS_1);
                        tmp &= 0xff00ffff;
                        tmp |= pd->bridge.secbus_num << 16;
                        _pci_conf_write(pcidev->pa.pa_tag, PCI_PRIBUS_1, tmp);
                }
//(note)这个地方配置bus no.
//(note)pci设备的父设备是一个桥,因为每个桥下面有多个子设备.因此在pci桥的配置的过程中,当找到一个pci桥的
//(note)桥的时候,还要配置其父桥.

pd->bridge.secbus = pmalloc(sizeof(struct pci_bus));
pd->bridge.secbus->max_lat = 255;
                pd->bridge.secbus->fast_b2b = 1;
                pd->bridge.secbus->prefetch = 1;
                pd->bridge.secbus->freq66 = 1;
                pd->bridge.secbus->bandwidth = 4000000;
                pd->bridge.secbus->ndev = 1;
                pd->bridge.secbus->bus = pd->bridge.secbus_num;
               
_pci_bus_insert(pd->bridge.secbus);

        /* Scan secondary bus of the bridge */
                _pci_scan_dev(pd, pd->bridge.secbus_num, 0, initialise);

                /*
                 * Sum up the address space needed by secondary side of bridge
                 */

                /* Sum up I/O Space needed */
                for(pm = pd->bridge.iospace; pm != NULL; pm = pm->next) {
                        if(pm_io == NULL) {
                                pm_io = pmalloc(sizeof(struct pci_win));
                                if(pm_io == NULL) {
                                        PRINTF ("pci: can't alloc memory for pci memory window/n");
                                        return;
                                }
                                pm_io->device = pd;
                                pm_io->reg = PCI_IOBASEL_1;
                                pm_io->flags = PCI_MAPREG_TYPE_IO;
                        }
                        pm_io->size += pm->size;
                }

                /* Sum up Memory Space needed */
                for(pm = pd->bridge.memspace; pm != NULL; pm = pm->next) {
                        if(pm_mem == NULL) {
                                pm_mem = pmalloc(sizeof(struct pci_win));
                                if(pm_mem == NULL) {
                                        PRINTF ("pci: can't alloc memory for pci memory window/n");
                                        return;
                                }
            
                                pm_mem->device = pd;
                                pm_mem->reg = PCI_MEMBASE_1;
                                pm_mem->flags = PCI_MAPREG_MEM_TYPE_32BIT;
                        }
                        pm_mem->size += pm->size;
                }
        
                /* Round to minimum granularity requierd for a bridge */
                pm_io->size = _pci_roundup(pm_io->size, 0x1000);
                pm_mem->size = _pci_roundup(pm_mem->size, 0x100000);

                if(pm_io) {
                        _insertsort_window(&pd->parent->bridge.iospace, pm_io);
                }
                if(pm_mem) {
                        _insertsort_window(&pd->parent->bridge.memspace,pm_mem);
                }
        }
//(note)pci桥的话,则递规的探测桥下面的子设备,并统计整个桥的io和mem分配情况,插入父桥的io和mem地址空间中.               
static void
_pci_bus_insert(bus)
    struct pci_bus *bus;
{
    struct pci_bus *pb;

    for(pb = _pci_bushead; pb->next != NULL; pb = pb->next)
        ;;

    pb->next = bus;
}

普通设备的情况,下面就得到每个pci设备的pci的地址空间大小了
{
                int skipnext = 0;

                for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
                        struct pci_win *pm;

                        if (skipnext) {
                                skipnext = 0;
                                continue;
                        }

                        old = _pci_conf_read(tag, reg);
                        _pci_conf_write(tag, reg, 0xfffffffe);
                        mask = _pci_conf_read(tag, reg);
                        _pci_conf_write(tag, reg, old);

                        if (mask == 0 || mask == 0xffffffff) {
                                break;
                        }

                        if (_pciverbose >= 3) {
                                //_pci_tagprintf (tag, "reg 0x%x = 0x%x/n",
                                _pci_tagprintf (tag, "reg 0x%x mask= 0x%x/n",
                                                        reg, mask);
                        }

                        if (PCI_MAPREG_TYPE(mask) == PCI_MAPREG_TYPE_IO) {
                                mask |= 0xffff0000; /* must be ones */
                                pm = pmalloc(sizeof(struct pci_win));
                                if(pm == NULL) {
                                        PRINTF ("pci: can't alloc memory for pci memory window/n");
                                        return;
                                }
            
                                pm->device = pd;
                                pm->reg = reg;
                                pm->flags = PCI_MAPREG_TYPE_IO;
                                pm->size = -(PCI_MAPREG_IO_ADDR(mask));
                                _insertsort_window(&pd->parent->bridge.iospace, pm);
                        }
                        else {
                                switch (PCI_MAPREG_MEM_TYPE(mask)) {
                                case PCI_MAPREG_MEM_TYPE_32BIT:
                                case PCI_MAPREG_MEM_TYPE_32BIT_1M:
                                        break;
                                case PCI_MAPREG_MEM_TYPE_64BIT:
                                        _pci_conf_write(tag, reg + 4, 0x0);
                                        skipnext = 1;
                                        break;
                                default:
                                        _pci_tagprintf (tag, "reserved mapping type 0x%x/n",
                                              PCI_MAPREG_MEM_TYPE(mask));
                                        continue;
                                }

                                if  (!PCI_MAPREG_MEM_PREFETCHABLE(mask)) {
                                        pb->prefetch = 0;
                                }

                                pm = pmalloc(sizeof(struct pci_win));
                                if(pm == NULL) {
                                        PRINTF ("pci: can't alloc memory for pci memory window/n");
                                        return;
                                }

                                pm->device = pd;
                                pm->reg = reg;
                                pm->flags = PCI_MAPREG_MEM_TYPE_32BIT;
                                pm->size = -(PCI_MAPREG_MEM_ADDR(mask));
                                _insertsort_window(&pd->parent->bridge.memspace, pm);
                        }
                }
//(note)得到pci设备的地址空间大小,并插入pci桥的地址空间列表中,该列表插入时按照空间大小进行排序。
//(note)可以看出在pci设备结构pd中,并没有pm,pio结构的信息.pm,pio中有pd的信息.

                /* Finally check for Expansion ROM */
                reg = PCI_MAPREG_ROM;
                old = _pci_conf_read(tag, reg);
                _pci_conf_write(tag, reg, 0xfffffffe);
                mask = _pci_conf_read(tag, reg);
                _pci_conf_write(tag, reg, old);

                if (mask != 0 && mask != 0xffffffff) {
                        struct pci_win *pm;

                        if (_pciverbose >= 3) {
                                _pci_tagprintf (tag, "reg 0x%x = 0x%x/n", reg, mask);
                        }

                        pm = pmalloc(sizeof(struct pci_win));
                        if(pm == NULL) {
                                PRINTF ("pci: can't alloc memory for pci memory window/n");
                                return;
                        }
                        pm->device = pd;
                        pm->reg = reg;
                        pm->size = -(PCI_MAPREG_ROM_ADDR(mask));
                        _insertsort_window(&pd->parent->bridge.memspace, pm);
                }
        }
_setup_pcibuses>
        for(i = 0, pd = _pci_head; i < pci_roots; i++, pd = pd->next) {
                _pci_setup_windows (pd);
        }
        分配pci地址空间是从nextpcimemaddr向下减设备内存/io大小的方法来分配的,类似于堆栈的操作方法。
其中有一段特殊的处理,就是对显卡设备,当查到PCI_CLASS_DISPLAY的时候,就知道是一个显卡
                if (PCI_ISCLASS(pd->pa.pa_class, PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA))
                vga_dev = pd;
...
        if (pm->reg == PCI_MAPREG_ROM) {
            /* expansion rom */
                if (_pciverbose >= 2)
                    _pci_tagprintf (pd->pa.pa_tag, "exp @%p, %d bytes/n",
                        pm->address, pm->size);
            _pci_conf_write(pd->pa.pa_tag, pm->reg, pm->address | PCI_MAPREG_TYPE_ROM);
        }
        
这样_pci_devinit就结束了       
    init_net();初始化网络.
下面是dbginit>init_net
init_net>tgt_devconfig
tgt_devconfig();
200     void
201     tgt_devconfig()
202     {
...
218             _pci_devinit(1);        /* PCI device initialization */
219     #if NMOD_X86EMU_INT10 > 0
220             SBD_DISPLAY("VGAI", 0);
221             vga_bios_init();
222     #endif
(gdb)
223             config_init();
224             configure();
225     #if NMOD_VGACON >0
226             rc=kbd_initialize();
227             printf("%s/n",kbd_error_msgs[rc]);
228             if(!rc){
229                     kbd_available=1;
230             }
231     #endif
232             printf("devconfig done./n");
(gdb)
233     }
初始化网络前,先是_pci_devinit
(gdb) l _pci_devinit
973     /*
974      *  Scan list of configured devices, probe and attach.
975      */
976     void
977     _pci_devinit (int initialise)
978     {
979             SBD_DISPLAY ("PCID", CHKPNT_PCID);
980             if(monarch_mode) {
981                     int i;
982                     struct pci_device *pd;
(gdb)
983
984                     for(i = 0, pd = _pci_head; i < pci_roots; i++, pd = pd->next) {
985                             _pci_setup_devices (pd, initialise);
986                     }
987             }
988     }

825     static void
826     _pci_setup_devices (struct pci_device *parent, int initialise)
827     {
(gdb)
828         struct pci_device *pd;
829
830         for (pd = parent->bridge.child; pd ; pd = pd->next) {
831             /* set device parameters */
832             struct pci_bus *pb = pd->pcibus;
833             pcitag_t tag = pd->pa.pa_tag;
834             pcireg_t cmd, misc, class;
835             unsigned int ltim;
836
837             cmd = _pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
(gdb)
838
839             if (initialise) {
840                 class = _pci_conf_read(tag, PCI_CLASS_REG);
841                 cmd |= PCI_COMMAND_MASTER_ENABLE
842                     | PCI_COMMAND_SERR_ENABLE
843                     | PCI_COMMAND_PARITY_ENABLE;
844                 /* always enable i/o & memory space, in case this card is
845                    just snarfing space from the fixed ISA block and doesn't
846                    declare separate PCI space. Exception from this is if
847                    it is a bridge chip which we will initialize later */
(gdb)
848                 cmd |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE;
849
850                 if (pb->fast_b2b)
851                     cmd |= PCI_COMMAND_BACKTOBACK_ENABLE;
852                 _pci_conf_write(tag, PCI_COMMAND_STATUS_REG, cmd);
853
854                 ltim = pd->min_gnt * 33 / 4;
855                 ltim = MIN (MAX (pb->def_ltim, ltim), pb->max_ltim);
856
857                 misc = _pci_conf_read (tag, PCI_BHLC_REG);
(gdb)
858                 misc = (misc & ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT))
859                        | ((ltim & 0xff) << PCI_LATTIMER_SHIFT);
860                 misc = (misc & ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT))
861                        | ((PCI_CACHE_LINE_SIZE & 0xff) << PCI_CACHELINE_SHIFT);
862                 _pci_conf_write (tag, PCI_BHLC_REG, misc);
863                 
864                 if(PCI_CLASS(class) == PCI_CLASS_BRIDGE ||
865                    PCI_SUBCLASS(class) == PCI_SUBCLASS_BRIDGE_PCI || pd->bridge.child != NULL) {
866                         _pci_setup_devices (pd, initialise);
867                 }
(gdb)
868             }
869         }
870     }
可以看出在_pci_setup_devices中首先是设备的使能,即向PCI_COMMAND_STATUS_REG写入PCI_COMMAND_MASTER_ENABLE
842                     | PCI_COMMAND_SERR_ENABLE
843                     | PCI_COMMAND_PARITY_ENABLE|CI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE
_pci_setup_devices是递归调用的

tgt_devconfig>
再来看看tgt_devconfig预编译后的结果
        void
tgt_devconfig()
{

        int rc;

# 217 "/home/dsm/pmon2003/src/Targets/Bonito/Bonito/tgt_machdep.c"

        _pci_devinit(1);        /* PCI device initialization */

        tgt_display( "VGAI" ,   0 ) ;
        vga_bios_init();

        config_init();
        configure();

        rc=kbd_initialize();
        printf("%s/n",kbd_error_msgs[rc]);
        if(!rc){
                kbd_available=1;
        }

        printf("devconfig done./n");
}

/*
*  Configure all devices found that we know about.
*  This is done at boot time.
*/
void
configure()
{
        (void)splhigh();        /* To be really sure.. */
        /*        calc_delayconst(); */
        printf("in configure/n");
        if(config_rootfound("mainbus", "mainbus") == 0)
                panic("no mainbus found");
        /*(void)spl0();*/
        printf("out configure/n");
        cold = 0;
}
/*
* As above, but for root devices.
*/
config_rootfound首先调用config_rootsearch找到设备并返回cf结构,然后调用config_attach分配设备结构,并挂接设备。
struct device *
config_rootfound(rootname, aux)
        char *rootname;
        void *aux;
{
        void *match;
        if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
                return (config_attach(ROOT, match, aux, (cfprint_t)NULL));

        printf("root device %s not configured/n", rootname);
        return (NULL);
}
其中#define        ROOT ((struct device *)NULL)

config_rootsearch先按设备名进行查找,找到后返回cf结构,再调用mapply进行匹配探测,如果匹配成功就返回cf结构。
void *
config_rootsearch(fn, rootname, aux)
        register cfmatch_t fn;
        register char *rootname;
        register void *aux;
{
        register struct cfdata *cf;
        register short *p;
        struct matchinfo m;

        m.fn = fn;
        m.parent = ROOT;
        m.match = NULL;
        m.aux = aux;
        m.indirect = 0;
        m.pri = 0;
        /*
         * Look at root entries for matching name.  We do not bother
         * with found-state here since only one root should ever be
         * searched (and it must be done first).
         */
        for (p = cfroots; *p >= 0; p++) {
                cf = &cfdata[*p];
                if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
                        mapply(&m, cf);
        }
        return (m.match);
}

void
mapply(m, cf)
        register struct matchinfo *m;
        register struct cfdata *cf;
{
...
        if (m->indirect)//->false
                match = config_make_softc(m->parent, cf);
        else
                match = cf;
                if (autoconf_verbose) {
                printf(">>> probing for %s", cf->cf_driver->cd_name);
                if (cf->cf_fstate == FSTATE_STAR)
                        printf("*/n");
                else
                        printf("%d/n", cf->cf_unit);
        }
//(note)打印调试信息probing for
if (m->fn != NULL)
                pri = (*m->fn)(m->parent, match, m->aux);
        else {
...
                pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
        }
        if (autoconf_verbose)
                printf(">>> %s probe returned %d/n", cf->cf_driver->cd_name,
                    pri);
//(note)打印调试信息probe returned
        if (pri > m->pri) {
                if (m->indirect && m->match)
                        free(m->match, M_DEVBUF);
                m->match = match;
                m->pri = pri;
        } else {
                if (m->indirect)
                        free(match, M_DEVBUF);
        }
}

struct device *
config_attach(parent, match, aux, print)
        register struct device *parent;
        void *match;
        register void *aux;
        cfprint_t print;
{
        register struct cfdata *cf;
        register struct device *dev;
        register struct cfdriver *cd;
        register struct cfattach *ca;
        struct cftable *t;

        if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {//->false
                dev = match;
                cf = dev->dv_cfdata;
        } else {
                cf = match;
                dev = config_make_softc(parent, cf);
        }

        cd = cf->cf_driver;
        ca = cf->cf_attach;

        cd->cd_devs[dev->dv_unit] = dev;

        /*
         * If this is a "STAR" device and we used the last unit, prepare for
         * another one.
         */
        if (cf->cf_fstate == FSTATE_STAR) {//->false
                if (dev->dv_unit == cf->cf_unit)
                        cf->cf_unit++;
        } else
                cf->cf_fstate = FSTATE_FOUND;

        TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
        device_ref(dev);

        if (parent == ROOT)
                printf("%s (root)", dev->dv_xname);
        else {
                printf("%s at %s", dev->dv_xname, parent->dv_xname);
                if (print)
                        (void) (*print)(aux, (char *)0);
        }
//(note)config_attach打印调试信息,一个设备找到并挂接

        /*
         * Before attaching, clobber any unfound devices that are
         * otherwise identical, or bump the unit number on all starred
         * cfdata for this device.
         */
        for (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
                for (cf = t->tab; cf->cf_driver; cf++)
                        if (cf->cf_driver == cd &&
                            cf->cf_unit == dev->dv_unit) {
                                if (cf->cf_fstate == FSTATE_NOTFOUND)
                                        cf->cf_fstate = FSTATE_FOUND;
                                if (cf->cf_fstate == FSTATE_STAR)
                                        cf->cf_unit++;
                        }
        }
#if defined(__alpha__) || defined(hp300)
        device_register(dev, aux);
#endif
        (*ca->ca_attach)(parent, dev, aux);
       
        config_process_deferred_children(dev);
        return (dev);
}
在config_attach中利用config_make_softc建立dev结构,设置设备的状态为FSTATE_FOUND,然后调用设备的attach函数
config_make_softc只是分配一个设备结构,并设置设备的名字
struct device *
config_make_softc(parent, cf)
        struct device *parent;
        struct cfdata *cf;
{
        register struct device *dev;
        register struct cfdriver *cd;
        register struct cfattach *ca;
        register size_t lname, lunit;
        register char *xunit;
        char num[10];

        cd = cf->cf_driver;
        ca = cf->cf_attach;
        if (ca->ca_devsize < sizeof(struct device))
                panic("config_make_softc");

        /* get memory for all device vars */
        dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);

//(note)pmon中每个驱动程序的设备结构相当与从基本的struct device结构中派生出来一样
//(note)其结构的第一个元素是struct device,剩下的部分是设备自己的元素
//(note)因此在分配设备结构的时候需要驱动程序自己提供设备结构的实际大小

        if (!dev)
                panic("config_make_softc: allocation for device softc failed");
        bzero(dev, ca->ca_devsize);
        dev->dv_class = cd->cd_class;
        dev->dv_cfdata = cf;
        dev->dv_flags = DVF_ACTIVE;        /* always initially active */

        /* If this is a STAR device, search for a free unit number */
        if (cf->cf_fstate == FSTATE_STAR) {//->false
                for (dev->dv_unit = cf->cf_starunit1;
                    dev->dv_unit < cf->cf_unit; dev->dv_unit++)
                        if (cd->cd_ndevs == 0 ||
                            cd->cd_devs[dev->dv_unit] == NULL)
                                break;
        } else
                dev->dv_unit = cf->cf_unit;

        /* compute length of name and decimal expansion of unit number */
        lname = strlen(cd->cd_name);
        xunit = number(&num[sizeof num], dev->dv_unit);
        lunit = &num[sizeof num] - xunit;
        if (lname + lunit >= sizeof(dev->dv_xname))
                panic("config_make_softc: device name too long");
       
        bcopy(cd->cd_name, dev->dv_xname, lname);
        bcopy(xunit, dev->dv_xname + lname, lunit);
        //->前面这些只是设置设备名
        dev->dv_parent = parent;
       
        /* put this device in the devices array */
        if (dev->dv_unit >= cd->cd_ndevs) {//->false
                /*
                 * Need to expand the array.
                 */
                int old = cd->cd_ndevs, new;
                void **nsp;

                if (old == 0)
                        new = MINALLOCSIZE / sizeof(void *);
                else
                        new = old * 2;
                while (new <= dev->dv_unit)
                        new *= 2;
                cd->cd_ndevs = new;
                nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);       
                if (nsp == 0)
                        panic("config_make_softc: %sing dev array",
                            old != 0 ? "expand" : "creat");
                bzero(nsp + old, (new - old) * sizeof(void *));
                if (old != 0) {
                        bcopy(cd->cd_devs, nsp, old * sizeof(void *));
                        free(cd->cd_devs, M_DEVBUF);
                }
                cd->cd_devs = nsp;
        }
        if (cd->cd_devs[dev->dv_unit])
                panic("config_make_softc: duplicate %s", dev->dv_xname);

        dev->dv_ref = 1;

        return (dev);
}



struct cfdata cfdata[] = {
    /* attachment       driver        unit  state loc     flags parents nm ivstubs starunit1 */
/*  0: mainbus0 at root */
    {&mainbus_ca,        &mainbus_cd,         0, NORM,     loc,    0, pv+ 1, 0, 0,    0},
/*  1: pcibr0 at mainbus0 */
    {&pcibr_ca,                &pcibr_cd,         0, NORM,     loc,    0, pv+ 8, 0, 0,    0},
/*  2: localbus0 at mainbus0 */
    {&localbus_ca,        &localbus_cd,         0, NORM,     loc,    0, pv+ 8, 0, 0,    0},
/*  3: inphy* at fxp0 phy -1 */
    {&inphy_ca,                &inphy_cd,         0, STAR, loc+  1,    0, pv+ 4, 1, 0,    0},
/*  4: pci* at pcibr0 bus -1 */
    {&pci_ca,                &pci_cd,         0, STAR, loc+  1,    0, pv+ 6, 3, 0,    0},
/*  5: fxp0 at pci* dev -1 function -1 */
    {&fxp_ca,                &fxp_cd,         0, NORM, loc+  0,    0, pv+ 0, 5, 0,    0},
/*  6: pciide* at pci* dev -1 function -1 */
    {&pciide_ca,        &pciide_cd,         0, STAR, loc+  0,    0, pv+ 0, 5, 0,    0},
/*  7: wd* at pciide* channel -1 drive -1 */
    {&wd_ca,                &wd_cd,                 0, STAR, loc+  0,    0, pv+ 2, 8, 0,    0},
    {0},
    {0},
    {0},
    {0},
    {0},
    {0},
    {0},
    {0},
    {(struct cfattach *)-1}
};

short cfroots[] = {
         0 /* mainbus0 */,
        -1
};

/* parent vectors */
short pv[10] = {
        4, -1, 6, -1, 5, -1, 1, -1, 0, -1,
};

cfdata实际上是一个设备树,pv数组定义一个设备的父设备.
每个节点的父设备都是一个数组,在设备的cfdata结构中定义数组的开始.
为了简化,pmon将所有设备的设备的父设备数组放在一个数值pv中.其中-1表示数组的结束.
所以设备自动初始化也是利用树进行递归的初始化.


struct cfattach mainbus_ca = {
    sizeof(struct mainbus_softc), mainbus_match, mainbus_attach
};

struct cfdriver mainbus_cd = {
    NULL, "mainbus", DV_DULL, NULL, 0
};

static int
mainbus_match(parent, match, aux)
        struct device *parent;
        void *match;
        void *aux;
{
        /*
         * That one mainbus is always here.
         */
        return (1);
}

static void
mainbus_attach(parent, self, aux)
        struct device *parent, *self;
        void *aux;
{
        struct mainbus_softc *sc = (struct mainbus_softc *)self;
        struct confargs nca;

        printf("/n");
        sc->sc_bus.bh_dv = (struct device *)sc;
        sc->sc_bus.bh_type = BUS_MAIN;
        sc->sc_bus.bh_intr_establish = NULL;
        sc->sc_bus.bh_intr_disestablish = NULL;
        sc->sc_bus.bh_matchname = mb_matchname;
        
        nca.ca_node = NULL;
        nca.ca_name = "localbus";
        nca.ca_bus = &sc->sc_bus;
        config_found(self, &nca, mbprint);

        nca.ca_node = NULL;
        nca.ca_name = "pcibr";
        nca.ca_bus = &sc->sc_bus;
        config_found(self, &nca, mbprint);
//(note)pcibridge查找
        nca.ca_node = NULL;
        nca.ca_name = "pcibr";
        nca.ca_bus = &sc->sc_bus;
        config_found(self, &nca, mbprint);

        nca.ca_node = NULL;
        nca.ca_name = "pcibr";
        nca.ca_bus = &sc->sc_bus;
        config_found(self, &nca, mbprint);
}
mainbus_attach调用config_found.config_find实际上调用的是config_found_sm(parent, aux, print, NULL),其中匹配处理函数submatch设置为空。
struct device *
config_found_sm(parent, aux, print, submatch)
        struct device *parent;
        void *aux;
        cfprint_t print;
        cfmatch_t submatch;
{
        void *match;

        if ((match = config_search(submatch, parent, aux)) != NULL)
                return (config_attach(parent, match, aux, print));
        if (print)
                printf(msgs[(*print)(aux, parent->dv_xname)]);
        return (NULL);
}
config_found主要是调用config_search进行批评如果匹配则调用attach.

void *
config_search(fn, parent, aux)
        cfmatch_t fn;
        register struct device *parent;
        void *aux;
{
        register struct cfdata *cf;
        register short *p;
        struct matchinfo m;
        struct cftable *t;

        m.fn = fn;
        m.parent = parent;
        m.match = NULL;
        m.aux = aux;
        m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;//->false
        m.pri = 0;
       
        for(t = allcftables.tqh_first; t; t = t->list.tqe_next) {
                for (cf = t->tab; cf->cf_driver; cf++) {
                        /*
                         * Skip cf if no longer eligible, otherwise scan
                         * through parents for one matching `parent',
                         * and try match function.
                         */
                        if (cf->cf_fstate == FSTATE_FOUND)
                                continue;
                        if (cf->cf_fstate == FSTATE_DNOTFOUND ||
                            cf->cf_fstate == FSTATE_DSTAR)
                                continue;
                        for (p = cf->cf_parents; *p >= 0; p++)
                                if (parent->dv_cfdata == &(t->tab)[*p])
                                        mapply(&m, cf);
                }
//(note)这段是首先确定现在查找的子设备的父设备是否是当前设备的父设备之一,如果是则调用mapply进行匹配
        }
        if (autoconf_verbose) {
                if (m.match)
                        printf(">>> %s probe won/n",
                            ((struct cfdata *)m.match)->cf_driver->cd_name);
                else
                        printf(">>> no winning probe/n");
        }
//(note)打印调试信息
        return (m.match);
}
在这里要说明的是在前面的config_init的实际上初始化了allcftables,使其挂入了staticcftable,而staticcftable中的就是
cf_data。
void
config_init()
{
        TAILQ_INIT(&deferred_config_queue);
        TAILQ_INIT(&alldevs);
        TAILQ_INIT(&allevents);
        TAILQ_INIT(&allcftables);
        TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
}
因此config_search实际上相当于在cf_data中进行查找。


struct cfattach pcibr_ca = {
        sizeof(struct pcibr_softc), pcibrmatch, pcibrattach,
};

struct cfdriver pcibr_cd = {
        NULL, "pcibr", DV_DULL,
};

void
pcibrattach(parent, self, aux)
        struct device *parent, *self;
        void *aux;
{
        struct pcibr_softc *sc = (struct pcibr_softc *)self;
        /*        struct pcibr_config *lcp; */
        struct pcibus_attach_args pba;

        printf("/n");

        /*
         *  Generic.
         */
#if defined(NEWPCIROOT)
        sc->sc_iobus_space = *_pci_bus[sc->sc_dev.dv_unit]->pa.pa_iot;
        sc->sc_membus_space = *_pci_bus[sc->sc_dev.dv_unit]->pa.pa_memt;
        sc->sc_dmatag = *_pci_bus[sc->sc_dev.dv_unit]->pa.pa_dmat;;
#else
        sc->sc_iobus_space = def_bus_iot;
        sc->sc_membus_space = def_bus_memt;
        sc->sc_dmatag = bus_dmamap_tag;;
#endif

#if 0
        char *bridge;


        lcp = sc->sc_pcibr;

        lcp->lc_pc.pc_conf_v = lcp;
        lcp->lc_pc.pc_attach_hook = mpc_attach_hook;
        lcp->lc_pc.pc_bus_maxdevs = mpc_bus_maxdevs;
        lcp->lc_pc.pc_make_tag = mpc_make_tag;
        lcp->lc_pc.pc_decompose_tag = mpc_decompose_tag;
        lcp->lc_pc.pc_conf_read = mpc_conf_read;
        lcp->lc_pc.pc_conf_write = mpc_conf_write;
        lcp->lc_pc.pc_ether_hw_addr = NULL;
        lcp->lc_iot = &sc->sc_iobus_space;
        lcp->lc_memt = &sc->sc_membus_space;
        lcp->lc_dmat = &sc->sc_dmatag;

        lcp->lc_pc.pc_intr_v = lcp;
        lcp->lc_pc.pc_intr_map = mpc_intr_map;
        lcp->lc_pc.pc_intr_string = mpc_intr_string;
        lcp->lc_pc.pc_intr_establish = NULL;
        lcp->lc_pc.pc_intr_disestablish = NULL;
#endif        

        pba.pba_busname = "pci";
        pba.pba_iot = &sc->sc_iobus_space;
        pba.pba_memt = &sc->sc_membus_space;
        pba.pba_dmat = &sc->sc_dmatag;
        pba.pba_pc = NULL;
        pba.pba_bus = sc->sc_dev.dv_unit;
        config_found(self, &pba, pcibrprint);
}

struct cfdriver {
        void        **cd_devs;                /* devices found */
        char        *cd_name;                /* device name */
        enum        devclass cd_class;        /* device classification */
        int        cd_indirect;                /* indirectly configure subdevices */
        int        cd_ndevs;                /* size of cd_devs array */
};
cfdriver0->cd_indirect的作用是什么
cd_indirect为0的时候,在查找设备的时候,返回的match直接就是cfdata数组中的cfdata结构.
而cd_indirect为1的时候,在查找设备的时候,返回的match是一个设备结构.

对pci来说
config_found_sm(self, &pa, pciprint, pcisubmatch);
localbus是采用indirect.
localbus_cd


设备查找的总结:
查找设备有两个函数config_rootfound和config_found_sm,其结构是一样的,都是调用
先config_search,然后config_attach.其基本结构如下:
struct device *
config_found_sm(parent, aux, print, submatch)
{
...
        if ((match = config_search(submatch, parent, aux)) != NULL)
                return (config_attach(parent, match, aux, print));
...
}
config_search中调用mapply
mapply调用probing,循环设备数组中的每个设备,如果设备的父设备是mapply参数中的parent,就进行probe.
config_search中调用mapply,其中在mapply中会打印 "probing for %s",在mapply推出后,config_search中会打印">>> %s probe won/n"
或者">>> no winning probe/n".config_attach中会打印%s at %s,然后config_attach调用设备自己的ca_attach函数,这个函数再通过
config_found_sm来安装自己的子设备.
config_search从静态的设备树cfdata,查找当前设备的子设备.然后对子设备调用mapply函数.
当submatch为0的时候,mapply采用cf->cf_attach->ca_match作为match函数.
当submatch非0的时候采用submatch作为match函数.匹配函数返回优先级,如果返回的优先级比当前m.pri要高,则当前测试的子设备胜出,
对于indirect释放掉m.match中原有的dev结构,设置成新分配的dev结构;对于非indirect则将m.match设置成当前测试子设备的cfdata结构.
分配dev结构采用的是config_make_softc(parent, cf),每个分配一个dev,都会检测驱动程序的cd_devs[]数组的大小,如果已满则将原大小乘2,
并且分配新的cd_devs[]数组,将原来的拷贝过来,并释放原来的.
cd->cd_devs是数组指针,cd->cd_ndevs是数组的大小,cf->cf_unit是当前最大的设备号.
因此config_search对所有子设备都使用mapply,mapply返回一个优先级m.pri,config_search最后选中的是优先级最高的设备.
config_search匹配成功后返回match,对于父设备为indirect类型的,match返回一个dev结构,否则返回查到的子设备的cfdfata结构.
然后在config_attach函数中,对于父设备非indirect类型的,分配一个device结构.config_attach中将dev放入cd_devs[]数组中.
并将设备挂入alldevs链表中.然后改变cfdata结构中的cf->cf_fstate为FSTATE_FOUND,增加设备的设备号cf->cf_unit.
然后应用设备的attach函数.
cfdata结构中类型"STAR" device,是每增加一个设备,设备驱动新分配一个单元号;而非"STAR" device好像只有一个设备?
config_defer函数的目的是等所有的父设备都attach后,在对子设备进行配置,其将设备挂入deferred_config_queue队列中.
因此在设备的attach后,config_attach调用config_process_deferred_children,对deferred_config_queue队列进行处理,看是否有子设备
在等待目前设备完成后进行配置.
mainbus下是pcibr,pcibr下是pci
void
pcibrattach(parent, self, aux)
        struct device *parent, *self;
        void *aux;
{
...
struct pcibus_attach_args pba;
...
        pba.pba_busname = "pci";
        pba.pba_iot = &sc->sc_iobus_space;
        pba.pba_memt = &sc->sc_membus_space;
        pba.pba_dmat = &sc->sc_dmatag;
        pba.pba_pc = NULL;
        pba.pba_bus = sc->sc_dev.dv_unit;
        config_found(self, &pba, pcibrprint);
}
从pcibrattach中可以看出pba_pc是空的,而且
#define pci_conf_read(a, b, c)                _pci_conf_read(b, c)
其中a代表pba_pc,实际中并未使用。

对pci和mii,有自己的submatch函数.pci采用pcisubmatch.
pci的在pciattach函数中,循环的利用已经找到的pci设备和cfdata中的driver进行匹配。匹配函数使用的是pcisubmatch.

void
pciattach(parent, self, aux)
        struct device *parent, *self;
        void *aux;
{
        struct pcibus_attach_args *pba = aux;
        bus_space_tag_t iot, memt;
        pci_chipset_tag_t pc;
        int bus, device, maxndevs, function, nfunctions;

        pci_attach_hook(parent, self, pba);
        printf("/n");

        printf("/npciattach:pba_iot=%p,bus_base=0x%x/n",pba->pba_iot,pba->pba_iot->bus_base);
        iot = pba->pba_iot;
        memt = pba->pba_memt;
        pc = pba->pba_pc;
        bus = pba->pba_bus;
        maxndevs = pci_bus_maxdevs(pc, bus);

        if (bus == 0)
                pci_isa_bridge_callback = NULL;

        for (device = 0; device < maxndevs; device++) {
                pcitag_t tag;
                pcireg_t id, class, intr, bhlcr;
                struct pci_attach_args pa;
                int pin;

                tag = _pci_make_tag(bus, device, 0);

                if(!_pci_canscan(tag)) {
                        continue;        /* Skip if not configurable */
                }

                id = pci_conf_read(pc, tag, PCI_ID_REG);

                /* Invalid vendor ID value? */
                if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
                        continue;
                /* XXX Not invalid, but we've done this ~forever. */
                if (PCI_VENDOR(id) == 0)
                        continue;

                bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
                nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1;

                for (function = 0; function < nfunctions; function++) {
                        tag = _pci_make_tag(bus, device, function);
                        id = pci_conf_read(pc, tag, PCI_ID_REG);

                        /* Invalid vendor ID value? */
                        if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
                                continue;
                        /* XXX Not invalid, but we've done this ~forever. */
                        if (PCI_VENDOR(id) == 0)
                                continue;

                        class = pci_conf_read(pc, tag, PCI_CLASS_REG);
                        intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);

                        pa.pa_iot = iot;
                        pa.pa_memt = memt;
                        pa.pa_dmat = pba->pba_dmat;
                        pa.pa_pc = pc;
                        pa.pa_device = device;
                        pa.pa_function = function;
                        pa.pa_tag = tag;
                        pa.pa_id = id;
                        pa.pa_class = class;

                        /* This is a simplification of the NetBSD code.
                           We don't support turning off I/O or memory
                           on broken hardware. <[email]csapuntz@stanford.edu[/email]> */
                        pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
#ifdef __i386__
                        /*
                         * on i386 we really need to know the device tag
                         * and not the pci bridge tag, in intr_map
                         * to be able to program the device and the
                         * pci interrupt router.
                         */
                        pa.pa_intrtag = tag;
                        pa.pa_intrswiz = 0;
#else
                        if (bus == 0) {
                                pa.pa_intrswiz = 0;
                                pa.pa_intrtag = tag;
                        } else {
                                pa.pa_intrswiz = pba->pba_intrswiz + device;
                                pa.pa_intrtag = pba->pba_intrtag;
                        }
#endif
                        pin = PCI_INTERRUPT_PIN(intr);
                        if (pin == PCI_INTERRUPT_PIN_NONE) {
                                /* no interrupt */
                                pa.pa_intrpin = 0;
                        } else {
                                /*
                                 * swizzle it based on the number of
                                 * busses we're behind and our device
                                 * number.
                                 */
                                pa.pa_intrpin =                        /* XXX */
                                    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
                        }
                        pa.pa_intrline = PCI_INTERRUPT_LINE(intr);

                        printf("/npciattach:pa.pa_iot=%p,bus_base=0x%x/n",pa.pa_iot,pa.pa_iot->bus_base);

                        config_found_sm(self, &pa, pciprint, pcisubmatch);
                }
        }

        if (bus == 0 && pci_isa_bridge_callback != NULL)
                (*pci_isa_bridge_callback)(pci_isa_bridge_callback_arg);
}

pcisubmatch先判断pci的dev和function,然后调用driver的ca_match.
如果匹配成功的话,向设备的PCI_COMMAND_STATUS_REG中写入PCI_COMMAND_MASTER_ENABLE |
                               PCI_COMMAND_IO_ENABLE |
                               PCI_COMMAND_MEM_ENABLE
使设备使能。
在这里采用直接读配置空间的方法来得到pci设备的class id,device id,memory io allocation,而不是采用前面查找pci设备,并分配空间
得到的结构,是因为对于device no<7的设备,前面没有分配结构。前面只分配了动态可插拔设备的pci设备结构。
int
pcisubmatch(parent, match, aux)
        struct device *parent;
        void *match, *aux;
{
        struct cfdata *cf = match;
        struct pci_attach_args *pa = aux;
        int success;

        if (cf->pcicf_dev != PCI_UNK_DEV &&
            cf->pcicf_dev != pa->pa_device)
                return 0;
        if (cf->pcicf_function != PCI_UNK_FUNCTION &&
            cf->pcicf_function != pa->pa_function)
                return 0;

        success = (*cf->cf_attach->ca_match)(parent, match, aux);

        /* My Dell BIOS does not enable certain non-critical PCI devices
           for IO and memory cycles (e.g. network card). This is
           the generic approach to fixing this problem. Basically, if
           we support the card, then we enable its IO cycles.
        */
        if (success) {
                u_int32_t csr = pci_conf_read(pa->pa_pc, pa->pa_tag,
                                              PCI_COMMAND_STATUS_REG);

                pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
                               csr | PCI_COMMAND_MASTER_ENABLE |
                               PCI_COMMAND_IO_ENABLE |
                               PCI_COMMAND_MEM_ENABLE);
        }

        return (success);
}


考虑pci的时候应该考虑桥的情况,因为有南桥存在.
然后是tgt_devconfig>kbd_initialize初始化键盘
然后回到init_net中
init_net{
...
                for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++) {
                        if (pdev->pdev_count > 0) {
                                (*pdev->pdev_attach)(pdev->pdev_count);
                        }
                }
                ifinit();
                printf("ifinit done./n");
                domaininit();
                printf("domaininit done./n");
                splx(s);
...
printf("init_proc..../n");
        init_proc ();
...
ifconfig (ifn, p);
...
}
pdevinit对伪设备进行初始化.目前只有一个伪设备loop
/* pseudo-devices */
extern void loopattach (int);

char *pdevnames[] = {
        "loop",
};

int pdevnames_size = 1;

struct pdevinit pdevinit[] = {
        { loopattach, 1 },
        { 0, 0 }
};
domaininit对tcp/ip协议进行初始化配置.
最后ifconfig来配置ip地址.
然后回到dbginit
histinit ();初始化命令历史记录.
syminit ();建立符号表
ioctl(STDIN, TCGETA, &consterm);建立终端.

最后运行main