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

进程user态下的分段

 

User态中将进程空间分为textdatastack segment三部分。

 

estabur(nt, nd, ns,sep)根据各个segment的大小,为各段分配page,参数如下:

1 nt—— text segment的长度(block

2 nd—— data segment的长度(block

3 ns—— stack segment的长度(block

     4 sep——是否“i”、“d”分区。(我们只探讨sep0的情况

 

1650: estabur(nt, nd, ns, sep)

1651: {

1652:      register a, *ap, *dp;

1653:

1654:      if(sep) {

                           ……

1659:     } else

1660:          if(nseg(nt)+nseg(nd)+nseg(ns) > 8)       /函数nseg会将block数转化为page数,

1661:                 goto err;                                          /1 page最多128block,进程user态最多8page

1662:     if(nt+nd+ns+USIZE > maxmem)            

1663:             goto err;

1664:     a = 0;                                                          /uisa[]0开始计数,单位是block

1665:     ap = &u.u_uisa[0];                          

1666:     dp = &u.u_uisd[0];

1667:     while(nt >= 128) {                                   /映射text segment

1668:          *dp++ = (127<<8) | RO;                   /1page最多128block

1669:          *ap++ = a;                                           /text segment是只读的,故为RO

1670:           a =+ 128;

1671:           nt =- 128;

1672:      }

1673:      if(nt) {                                                   /不够128block的部分,

1674:          *dp++ = ((nt-1)<<8) | RO;               /也必须映射到一个单独的page

1675:          *ap++ = a;

1676:      }

1677:      if(sep)

             ……

1681:          }

1682:       a = USIZE;                                            /a回滚了,与Text segment的设置有重叠

1683:       while(nd >= 128) {

1684:            *dp++ = (127<<8) | RW;                /除了状态为RW外,其他设置与text类似

1685:            *ap++ = a;                          

1686:            a =+ 128;

1687:            nd =- 128;

1688:       }

1689:       if(nd) {

1690:           *dp++ = ((nd-1)<<8) | RW;

1691:           *ap++ = a;

1692:           a =+ nd;

1693:       }

1694:       while(ap < &u.u_uisa[8]) {                  /剩下的page0

1695:           *dp++ = 0;

1696:           *ap++ = 0;

1697:        }

1698:        if(sep)

               ……

1702:        }

1703:        a =+ ns;                                            /a指向stack segment的最后

1704:        while(ns >= 128) {

1705:              a =- 128;                                    /设置stack segment

1706:              ns =- 128;

1707:              *--dp = (127<<8) | RW;

1708:              *--ap = a;

1709:        }

1710:        if(ns) {

1711:              *--dp = ((128-ns)<<8) | RW | ED;

1712:              *--ap = a-128;

1713:        }

1714:       if(!sep) {                                             /如未进行“i”、“d”分区

1715:            ap = &u.u_uisa[0];                    

1716:            dp = &u.u_uisa[8];

1717:            while(ap < &u.u_uisa[8])              /uisa[8~15] = uisa[0~7]

1718:                 *dp++ = *ap++;

1719:            ap = &u.u_uisd[0];

1720:            dp = &u.u_uisd[8];

1721:            while(ap < &u.u_uisd[8])              /uisd[8~15] = uisd[0~7]

1722:                  *dp++ = *ap++;

1723:      }

1724:      sureg();                                                /稍后讨论

1725:      return(0);

1726:

1727: err:

1728:      u.u_error = ENOMEM;

1729:      return(-1);

1730: }

 

从代码中得知:

1unix会将textdatastack映射到不同的page上去;

2uisd[]中记录的似乎就是相应的page description register的值;

3uisa[]却不是page address register的值—— textdata segment有重叠。

它是什么呢?我们接着往下看。

 

sureg()会根据u_uisa[]u_uisd[]数组来设置相应的UISAUISD register,通过这个函数,

我们可以清楚的知道u_uisa[]u_uisd[]数组的真正含义。

 

1739: sureg()

1740: {

1741:     register *up, *rp, a;

1742:

1743:     a = u.u_procp->p_addr;          /a为进程私有空间的开始block

1744:     up = &u.u_uisa[16];

1745:     rp = &UISA->r[16];

1746:     if(cputype == 40) {                                         /PDP-11/40,未进行“i”、“d”分区

1747:         up -= 8;                                                        /故,u_uisa[8~15]是无效的

1748:         rp -= 8;

1749:     }

1750     while(rp > &UISA->r[0])                                 /UISA[ ] = u_uisa[ ] + a

1751:         *--rp = *--up + a;

1752:     if((up=u.u_procp->p_textp) != NULL)          /text segment已经分配了地址,text segment

1753:         a -= up->x_caddr;                                        /需要特殊调整。up->x_caddrtext segment

1754:     up = &u.u_uisd[16];                                        /core load地址,对#1进程,a值未变(可认其

1755:     rp = &UISD->r[16];                                        /core load地址为0

1756:     if(cputype == 40) {  

1757:         up -= 8;

1758:         rp -= 8;

1759:     }

1760:     while(rp > &UISD->r[0]) {

1761:         *--rp = *--up;                                           /UISA[ ] = u_uisd[ ]

1762:         if((*rp & WO) == 0)                               /只有text segment是不可写的

1763:            rp[(UISA-UISD)/2] -= a;                    /重新调整text segmentpage address register

1764:     }                                                                 /rp现在指向UISD,通过UISAUISD地址计算

1765: }                                                                    /出偏移量,直接通过rp操作UISA

 

显然:

1u_uisd[]中记录的就是相应的page description register的值;

2data segmentstack segment均被映射到进程的“私有空间”的PPDA之后;

        对这两种segmentu_uisa[]protype)记录的为相对于PPDA的偏移block数;

        【注】:这两个user态的segment被映射到进程的“私有空间”之后,也变成了进程的“私有空间”的一

                       部分。也就是说,进程拥有连续的私有空间,且可以分为两部分:一部分在kernel使用,一部分

                       在user态使用。连续的空间为swap提供了方便。

 

3text segment如已有地址,则从原来地址开始映射,否则(如我们的#1进程),从第0block开始映射。

       text segmentu_uisa[]记录的为相对于core Load地址(#1进程为0)的偏移block数。

 

u中还有一些变量与这三个segment有关,如:

0440: int u_tsize; /* text size (*64) */ 记录的是block

0441: int u_dsize; /* data size (*64) */

0442: int u_ssize; /* stack size (*64) */

 

protype再分析】:

      为什么会设计protype Address呢?很简单,进程在其生存期内是有可能被换出内存的,当再次被换进内存时,

     它占据的物理位置就会发生变化——而其protype Address不变。这样通过调用sureg()就可以方便的设置好

     user Address register

 

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

    博客专栏地址: http://blog.csdn.net/column/details/lions-unix.html

目 录 献辞 致谢 序(一) 序(二) 历史注记 上篇 UNIX操作系统版本6源代码 UNIX操作系统过程分类索引 3 UNIX操作系统文件及过程 5 UNIX操作系统定义的符号列表 7 UNIX操作系统源代码交叉引用列表 9 第一部分 初始化、进程初始化 25 第二部分 陷入、中断、系统调用和 进程管理 75 第三部分 程序交换、基本输入/输出、 块设备 109 第四部分 文件和目录、文件系统、管道 133 第五部分 面向字符的特殊文件 181 下篇 莱昂UNIX源代码分析 前言 207 第1章 绪论 209 1.1 UNIX操作系统 209 1.2 公用程序 209 1.3 其他文档 210 1.4 UNIX程序员手册 210 1.5 UNIX文档 211 1.6 UNIX操作系统源代码 211 1.7 源代码中各部分 212 1.8 源代码文件 212 1.9 分析的使用 212 1.10 对程序设计水平的一条注释 212 第2章 基础知识 214 2.1 处理机 214 2.2 处理机状态字 214 2.3 通用寄存器 214 2.4 指令集 215 2.5 寻址方式 216 2.5.1 寄存器方式 217 2.5.2 寄存器延迟方式 217 2.5.3 自动增1方式 217 2.5.4 自动减1方式 217 2.5.5 变址方式 217 2.5.6 立即方式 218 2.5.7 相对方式 218 2.6 UNIX汇编程序 219 2.7 存储管理 219 2.8 段寄存器 220 2.9 页说明寄存器 220 2.10 存储分配 220 2.11 状态寄存器 221 2.12 “i”和“d”空间 221 2.13 启动条件 221 2.14 专用设备寄存器 221 第3章 阅读“C”程序 222 3.1 某些选出的例子 222 3.2 例1 222 3.3 例2 223 3.4 例3 223 3.5 例4 225 3.6 例5 225 3.7 例6 227 3.8 例7 227 3.9 例8 228 3.10 例9 228 3.11 例10 229 3.12 例11 229 3.13 例12 230 3.14 例13 230 3.15 例14 231 3.16 例15 231 3.17 例16 232 3.18 例17 233 第4章 概述 235 4.1 变量分配 235 4.2 全局变量 235 4.3 “C”预处理程序 235 4.4 第一部分 236 4.4.1 第1组“.h”文件 236 4.4.2 汇编语言文件 237 4.4.3 在第一部分中的其他文件 237 4.5 第二部分 237 4.6 第三部分 238 4.7 第四部分 238 4.8 第五部分 239 第一部分 初始化、进程初始化 第5章 两个文件 241 5.1 文件malloc.c 241 5.1.1 列表维护规则 241 5.1.2 malloc(2528) 242 5.1.3 mfree(2556) 243 5.1.4 结论 244 5.2 文件prf.c 244 5.2.1 printf(2340) 244 5.2.2 printn(2369) 245 5.2.3 putchar(2386) 246 5.2.4 panic(2419) 247 5.2.5 prdev(2433)、deverror(2447) 247 5.3 包含的文件 247 第6章 系统初启 249 6.1 操作员的动作 249 6.2 start(0612) 249 6.3 main(1550) 251 6.4 进程 252 6.5 proc〔0〕的初始化 252 6.6 sched(1940) 253 6.7 sleep(2066) 253 6.8 swtch(2178) 253 6.9 再回到main 254 第7章 进程 256 7.1 进程映像 256 7.2 proc结构(0358) 257 7.3 user结构(0413) 257 7.4 每个进程数据区 258 7.5 段 258 7.6 映像的执行 258 7.7 核心态执行 259 7.8 用户态执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值