code:main - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Source

  • 操作系统的初始化程序之c语言版,被start函数(初始化程序之汇编版)所调用
  • 作用:
    • 1.清所有用户可用的内存单元,并检测其实际长度,建立内存可用区表coremap
    • 2.建立盘交换区可用存储区表swapmap
    • 3.确定每个进程可用的最大存储空间
    • 4.初始化0号进程与1号进程,从此刻起他们将各司其职
    • 5.初始化字符设备缓存,块设备缓存以及文件系统
    • 6.设置根目录与当前目录
  • 参看系统初启

1531

1532 /*

1533  * Initialization code.

1534  * Called from m40.s or m45.s as

1535  * soon as a stack and segmentation

1536  * have been established.

1537  * Functions:

1538  * clear and free user core

1539  * find which clock is configured

1540  * hand craft 0th process

1541  * call all initialization routines

1542  * fork - process 0 to schedule

1543  * - process 1 execute bootstrap

1544  *

1545  * panic: no clock -- neither clock responds

1546  * loop at loc 6 in user mode -- /etc/init

1547  * cannot be executed

1548  */

1549

1550 main()

1551 {

1552     extern schar;

1553     register i, *p;

1554

1555     /*

1556     * zero and free all of core

1557     */

1558

1559     updlock = 0;

  • 初始化 updlock (update锁标志) ,以防止update函数死锁
1560     i = *ka6 + USIZE;
  • i = 0#进程PPDA区后第一个块的块号
1561     UISD->r[0] = 077406;
1562     for(;;) {

1563           UISA->r[0] = i;

1564           if(fuibyte(0) < 0)

1565                         break;

1566           clearseg(i);

1567           maxmem++;

1568           mfree(coremap, 1, i);

1569           i++;

1570     }

1562 - 1569
  • 从0#进程PPDA区后的第一个块开始:
  • 尝试读取每一个块的第一个字节,若能读取成功,表明该块为可用内存块
    • 清该块内容
    • 内存最大块数+1
    • 将该块加入内存可用区表
    • 继续取下一个内存块,直到该块读取出错为止,表明可用内存到此为止
1571     if(cputype == 70)

1572     for(i=0; i<62; i=+2) {

1573           UBMAP->r[i] = i<<12;

1574           UBMAP->r[i+1] = 0;

1575     }

  • 对于pdp11/40,上述部分不会执行
1576     printf("mem = %l \n", maxmem*5/16);

1577     printf("RESTRICTED RIGHTS \n \n");

1578     printf("Use, duplication or disclosure is subject to \n");

1579     printf("restrictions stated in Contract with Western \n");

1580     printf("Electric Company, Inc. \n");

  • 输出相关信息
1581

1582     maxmem = min(maxmem, MAXMEM);

  • 计算单个进程能使用的最大内存空间
1583     mfree(swapmap, nswap, swplo);
  • swplo为起始地址,nswap为大小,建立盘交换区可用存储区表swapmap
1584

1585     /*

1586     * set up system process

1587     */

1588

1589     proc[0].p_addr = *ka6;

1590     proc[0].p_size = USIZE;

1591     proc[0].p_stat = SRUN;

1592     proc[0].p_flag =| SLOAD|SSYS;

1593     u.u_procp = &proc[0];

  • 对0#进程进行初始化参数设置
1594

1595     /*

1596     * determine clock

1597     */

1598

1599     UISA->r[7] = ka6[1]; /* io segment */

1600     UISD->r[7] = 077406;

1601     lks = CLOCK1;

1602     if(fuiword(lks) == -1) {

1603           lks = CLOCK2;

1604           if(fuiword(lks) == -1)

1605                     panic("no clock");

1606     }

1607     *lks = 0115;

1601 - 1607
  • 判断当前时钟的种类,并且对时钟寄存器进行初始化
  • 参看时钟
关于1599 - 1600 1602 1604的说明
  • 1599 - 1600 置 UISA7/UISD7 为I/O页
    • 为了使用 fuiword寻址 时钟寄存器
  • 关于 使用fuiword寻址 时钟寄存器 ,而不直接寻址 的说明
    • 由于CLOCK1 CLOCK2 地址不一定存在,所以 借用fuiword的出错处理机制,对地址不存在的情况进行处理
1608

1609     /*

1610     * set up 'known' i-nodes

1611     */

1612

1613     cinit();

1614     binit();

1615     iinit();

  • 初始化块缓存
  • 初始化字符缓存
  • 初始化文件系统
1616     rootdir = iget(rootdev, ROOTINO);

1617     rootdir->i_flag =& ~ILOCK;

1618     u.u_cdir = iget(rootdev, ROOTINO);

1619     u.u_cdir->i_flag =& ~ILOCK;

1620

1621     /*

1622     * make init process

1623     * enter scheduling loop

1624     * with system process

1625     */

1626

1627     if(newproc()) {

1628           expand(USIZE+1);

1629           estabur(0, 1, 0, 0);

1630           copyout(icode, 0, sizeof icode);

1631     /*

1632     * Return goes to loc. 0 of user init

1633     * code just copied out.

1634     */

1635     return;

1636     }

  • 创建1号进程
    • 对于新创建的1#进程
    • 扩展进程图像
    • 设置相对地址映照
    • icode数组中的内容拷贝到用户态地址空间的起始地址
icode存放的是用户态启动程序的二进制代码 详细参看 LIONS代码分析
1637     sched();
  • 对于0#进程,执行进程图像调入调出主循环
1638 }

1639 /* ------------------------- */

Ref

⚠️ **GitHub.com Fallback** ⚠️