(莱昂氏unix源代码分析导读-8)系统初启(1)

现在,到了真正开始阅读unix源码的时候了。当然,要从系统启动开始。

 

PDP-11启动时,首先激活常驻在处理机中ROM里的引导程序。ROM中的引导装入程序装入一更大

的装入程序(从系统盘的#0块),该程序查找并将称为“ / u n i x”的文件装入到内存的低地址部分。

然后,它将控制转移到已装入#0地址的指令。

 

我们的代码之旅,就从#0地址开始。

502   br4   = 200

503   br5   = 240

504   br6   = 300

505   br7   = 340

506

507    .=0^.                         /当前地址 =0 octal

508     br        1f                  /跳到后面的标号“1”

509     4                              /其实是”IOT”指令啦,反正目前执行不到,不多说了。

510

511  / Trap Vector

512     Trap; br7+0;                  

     …………………..

522 1:   jump   start                       /跳到start处执行

 

 start

611     .globl  _start, _end, _edata, _main

612      start:

613         bit     $1, SSR0        /检查SSR0 bit 0,即存管系统indicator”

614         bne     start             /存管系统已启用,错误!跳回start

615         reset                       / reset

616     .

当系统初次启动时,存管indicator应该是关闭的。之所以要进行这种看似不必要的检查,莱昂书中

的解释是:当双总线超时错时,会跳到#0地址执行中断处理程序(即它的中断矢量地址是#0)。但是

,翻遍了全书,也找不到对“双总线超时”的中断的介绍。而且,PDP-11unibus系统,这个双总线

也不知是何物。我猜测是其它系统的硬件中断,代码移植时保留了下来。姑且存疑。

 

617      / initialize systems segments

618      .

619          mov   $KISA0, r0       /r0指向Kernel Address Register的第一个(编号为:0

620          mov   $KISD0, r1       /r1指向Kernel Description Register的第一个(编号为:0

621          mov   $200, r4         

622          clr     r2

623          mov   $6, r3

624      1:

625          mov   r2, (r0)+

626          mov  $77406, (r1)+

627          add   r4, r2

628          sob   r3, 1b           

循环结束后,前6Address Registerkisa0~kisa5)分别被设置为:00200040006000100001200

如果您做过前面的思考题,应该对这6个数字很熟悉——这样设置,正好将前6个虚存page映射到前6个物理page上。

 

629         .

630      /*  initialize user segment

631      .

632          mov   $_end+63., r2          /_end以前的地址已经被启动进程的程序区和数据区占用了

                                                         /_end地址开始,内存可以分配作它用 

633          ash    $-6, r2                     /圆整到一个block的起始地址

634          bic    $!1777, r2

635          mov   r2, (r0)+                  /kisa6指向为bss段后的第一个block

636          mov   $USIZE-1\8|6, (r1)+     

637       .

638      / initialize io segment

639      /set up counts on supervisor segment

640      .

641           mov   $IO, (r0)+                      /kisa7指向最后一个物理Page,以访问外设

642           mov   $77046, (r1)+         

643       .

644      /set a sp and start segment

645      .

646           mov    $_u+[USIZE*64.], sp       /sp指向PPDA后,见以下解释

 

首先要明确一点,即内核程序Load系统之后,它占据的是物理内存的低地址空间,它的逻辑地址和物理地址是重合的,

此时 ~ _end之间的物理空间已经被Load进系统的程序占据,而_end也就是可用于分配的最低物理地址。正如代码所示,

会首先会为当前进程分配一个很重要的区域,即进程数据区(PPDA区域)——每个进程都有一个私有的PPDA区域。

7Page Registerkisa6)将指向这一个特殊的区域。

 

PPDA区域分为两部分,开头是struct user结构,其后是核心stack

0413: struct user

0414: {

0415:        int u_rsav[2]; /* save r5,r6 when exchanging stacks */

0416:        int u_fsav[25];

                 ……

0458: } u;

 

【注】: _u被编址为0140000,即第7个逻辑page的开头,而这个page正好指向PPDA区域,因此u就被编址到PPDA区的开头。

1440: .globl _u

1441: _u = 140000

 

读到这里,我们可以画出进程的栈空间配置:

(莱昂氏unix源代码分析导读-8)系统初启(1)_第1张图片

整个PPDA长1024个字节,u占用了低地址部分。sp初始化为PPDA的尾部,指针向上移动以分配空间。

 

611           inc     SSR0                   /8Page Register已经设置好了,开启存管系统

612      .

613      /clear bss

614      .   

615           mov    $_edata, r0           /下列代码将地址处于_data ~ _end之间的内容清0

616      1:                                          /即将bss段初始化为0

617           clr     (r0)+

618           cmp    r0, $_end

619           blo     1b

 

正如前面所说的那样,data segment属于二进制文件的一部分,随着文件的装入,data segment就完成了初始化。

bss不同,必须由进程进行初始化。

 

620      

621     / clear user block

622     .

623          mov   $_u, r0                    /clear整个PPDA区域

624     1:

625          clr     (r0)+

626          cmp    r0, _u+[USIZE*64.]

627          blo     1b

628      

629     / set up previos mode and call main

630     / on return enter user mode at 0R

631     .

632          mov    $30000, PS

633          jsr     pc, _main                      /执行main

634          mov    $170000, -(sp)

635          clr     -(sp)

636          rtt

 

博客地址:http://blog.csdn.net/cszhao1980

 

你可能感兴趣的:(unix,vector,struct,IO,user,代码分析)