94.html

来自「linux 0.11中文版 有注释」· HTML 代码 · 共 668 行 · 第 1/5 页

HTML
668
字号
<a name='L238'><i><font color='green'>// 源地址和目的地址都需要是在4Mb 的内存边界地址上。否则出错,死机。</font></i>
<a name='L239'>  <b>if</b> ((from &amp; 0x3fffff) || (to &amp; 0x3fffff))
<a name='L240'>    <a href='../S/72.html#L24' title='Defined at 24 in kernel/panic.c.'>panic</a> ("copy_page_tables called with wrong alignment");
<a name='L241'><i><font color='green'>// 取得源地址和目的地址的目录项(from_dir 和to_dir)。参见对115 句的注释。</font></i>
<a name='L242'>  from_dir = (<b>unsigned</b> <b>long</b> *) ((from &gt;&gt; 20) &amp; 0xffc);  <i><font color='green'>/* _pg_dir = 0 */</font></i>
<a name='L243'>  to_dir = (<b>unsigned</b> <b>long</b> *) ((to &gt;&gt; 20) &amp; 0xffc);
<a name='L244'><i><font color='green'>// 计算要复制的内存块占用的页表数(也即目录项数)。</font></i>
<a name='L245'>  size = ((<b>unsigned</b>) (size + 0x3fffff)) &gt;&gt; 22;
<a name='L246'><i><font color='green'>// 下面开始对每个占用的页表依次进行复制操作。</font></i>
<a name='L247'>  <b>for</b> (; size-- &gt; 0; from_dir++, to_dir++)
<a name='L248'>    <font color='red'>{</font>
<a name='L249'><i><font color='green'>// 如果目的目录项指定的页表已经存在(P=1),则出错,死机。</font></i>
<a name='L250'>      <b>if</b> (1 &amp; *to_dir)
<a name='L251'>        <a href='../S/72.html#L24' title='Defined at 24 in kernel/panic.c.'>panic</a> ("copy_page_tables: already exist");
<a name='L252'><i><font color='green'>// 如果此源目录项未被使用,则不用复制对应页表,跳过。</font></i>
<a name='L253'>      <b>if</b> (!(1 &amp; *from_dir))
<a name='L254'>        <b>continue</b>;
<a name='L255'><i><font color='green'>// 取当前源目录项中页表的地址??from_page_table。</font></i>
<a name='L256'>      from_page_table = (<b>unsigned</b> <b>long</b> *) (0xfffff000 &amp; *from_dir);
<a name='L257'><i><font color='green'>// 为目的页表取一页空闲内存,如果返回是0 则说明没有申请到空闲内存页面。返回值=-1,退出。</font></i>
<a name='L258'>      <b>if</b> (!(to_page_table = (<b>unsigned</b> <b>long</b> *) <a href='../S/94.html#L101' title='Defined at 101 in mm/memory.c.'>get_free_page</a> ()))
<a name='L259'>        <b>return</b> -1;              <i><font color='green'>/* Out of memory, see freeing */</font></i>
<a name='L260'><i><font color='green'>// 设置目的目录项信息。7 是标志信息,表示(Usr, R/W, Present)。</font></i>
<a name='L261'>      *to_dir = ((<b>unsigned</b> <b>long</b>) to_page_table) | 7;
<a name='L262'><i><font color='green'>// 针对当前处理的页表,设置需复制的页面数。如果是在内核空间,则仅需复制头160 页,否则需要</font></i>
<a name='L263'><i><font color='green'>// 复制1 个页表中的所有1024 页面。</font></i>
<a name='L264'>      nr = (from == 0) ? 0xA0 : 1024;
<a name='L265'><i><font color='green'>// 对于当前页表,开始复制指定数目nr 个内存页面。</font></i>
<a name='L266'>      <b>for</b> (; nr-- &gt; 0; from_page_table++, to_page_table++)
<a name='L267'>        <font color='red'>{</font>
<a name='L268'>          this_page = *from_page_table; <i><font color='green'>// 取源页表项内容。</font></i>
<a name='L269'>          <b>if</b> (!(1 &amp; this_page)) <i><font color='green'>// 如果当前源页面没有使用,则不用复制。</font></i>
<a name='L270'>            <b>continue</b>;
<a name='L271'><i><font color='green'>// 复位页表项中R/W 标志(置0)。(如果U/S 位是0,则R/W 就没有作用。如果U/S 是1,而R/W 是0,</font></i>
<a name='L272'><i><font color='green'>// 那么运行在用户层的代码就只能读页面。如果U/S 和R/W 都置位,则就有写的权限。)</font></i>
<a name='L273'>          this_page &amp;= ~2;
<a name='L274'>          *to_page_table = this_page;   <i><font color='green'>// 将该页表项复制到目的页表中。</font></i>
<a name='L275'><i><font color='green'>// 如果该页表项所指页面的地址在1M 以上,则需要设置内存页面映射数组mem_map[],于是计算</font></i>
<a name='L276'><i><font color='green'>// 页面号,并以它为索引在页面映射数组相应项中增加引用次数。</font></i>
<a name='L277'>          <b>if</b> (this_page &gt; <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>)
<a name='L278'>            <font color='red'>{</font>
<a name='L279'><i><font color='green'>// 下面这句的含义是令源页表项所指内存页也为只读。因为现在开始有两个进程共用内存区了。</font></i>
<a name='L280'><i><font color='green'>// 若其中一个内存需要进行写操作,则可以通过页异常的写保护处理,为执行写操作的进程分配</font></i>
<a name='L281'><i><font color='green'>// 一页新的空闲页面,也即进行写时复制的操作。</font></i>
<a name='L282'>              *from_page_table = this_page;     <i><font color='green'>// 令源页表项也只读。</font></i>
<a name='L283'>              this_page -= <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>;
<a name='L284'>              this_page &gt;&gt;= 12;
<a name='L285'>              mem_map[this_page]++;
<a name='L286'>            <font color='red'>}</font>
<a name='L287'>        <font color='red'>}</font>
<a name='L288'>    <font color='red'>}</font>
<a name='L289'>  <a href='../S/94.html#L59' title='Defined at 59 in mm/memory.c.'>invalidate</a> ();                <i><font color='green'>// 刷新页变换高速缓冲。</font></i>
<a name='L290'>  <b>return</b> 0;
<a name='L291'><font color='red'>}</font>
<a name='L292'>
<a name='L293'><i><font color='green'>/*</font></i>
<a name='L294'><i><font color='green'>* This function puts a page in memory at the wanted address.</font></i>
<a name='L295'><i><font color='green'>* It returns the physical address of the page gotten, 0 if</font></i>
<a name='L296'><i><font color='green'>* out of memory (either when trying to access page-table or</font></i>
<a name='L297'><i><font color='green'>* page.)</font></i>
<a name='L298'><i><font color='green'>*/</font></i>
<a name='L299'><i><font color='green'>/*</font></i>
<a name='L300'><i><font color='green'>* 下面函数将一内存页面放置在指定地址处。它返回页面的物理地址,如果</font></i>
<a name='L301'><i><font color='green'>* 内存不够(在访问页表或页面时),则返回0。</font></i>
<a name='L302'><i><font color='green'>*/</font></i>
<a name='L303'><i><font color='green'>//// 把一物理内存页面映射到指定的线性地址处。</font></i>
<a name='L304'><i><font color='green'>// 主要工作是在页目录和页表中设置指定页面的信息。若成功则返回页面地址。</font></i>
<a name='L305'><b>unsigned</b> <b>long</b>
<a name='L306'><a href='../R/558.html' title='Multiple refered from 4 places.'>put_page</a> (<b>unsigned</b> <b>long</b> page, <b>unsigned</b> <b>long</b> address)
<a name='L307'><font color='red'>{</font>
<a name='L308'>  <b>unsigned</b> <b>long</b> tmp, *page_table;
<a name='L309'>
<a name='L310'><i><font color='green'>/* NOTE !!! This uses the fact that _pg_dir=0 */</font></i>
<a name='L311'><i><font color='green'>/* 注意!!!这里使用了页目录基址_pg_dir=0 的条件 */</font></i>
<a name='L312'>
<a name='L313'><i><font color='green'>// 如果申请的页面位置低于LOW_MEM(1Mb)或超出系统实际含有内存高端HIGH_MEMORY,则发出警告。</font></i>
<a name='L314'>  <b>if</b> (page &lt; <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a> || page &gt;= HIGH_MEMORY)
<a name='L315'>    <a href='../S/73.html#L30' title='Defined at 30 in kernel/printk.c.'>printk</a> ("Trying to put page %p at %p\n", page, address);
<a name='L316'><i><font color='green'>// 如果申请的页面在内存页面映射字节图中没有置位,则显示警告信息。</font></i>
<a name='L317'>  <b>if</b> (mem_map[(page - <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>) &gt;&gt; 12] != 1)
<a name='L318'>    <a href='../S/73.html#L30' title='Defined at 30 in kernel/printk.c.'>printk</a> ("mem_map disagrees with %p at %p\n", page, address);
<a name='L319'><i><font color='green'>// 计算指定地址在页目录表中对应的目录项指针。</font></i>
<a name='L320'>  page_table = (<b>unsigned</b> <b>long</b> *) ((address &gt;&gt; 20) &amp; 0xffc);
<a name='L321'><i><font color='green'>// 如果该目录项有效(P=1)(也即指定的页表在内存中),则从中取得指定页表的地址??page_table。</font></i>
<a name='L322'>  <b>if</b> ((*page_table) &amp; 1)
<a name='L323'>    page_table = (<b>unsigned</b> <b>long</b> *) (0xfffff000 &amp; *page_table);
<a name='L324'>  <b>else</b>
<a name='L325'>    <font color='red'>{</font>
<a name='L326'><i><font color='green'>// 否则,申请空闲页面给页表使用,并在对应目录项中置相应标志7(User, U/S, R/W)。然后将</font></i>
<a name='L327'><i><font color='green'>// 该页表的地址??page_table。</font></i>
<a name='L328'>      <b>if</b> (!(tmp = <a href='../S/94.html#L101' title='Defined at 101 in mm/memory.c.'>get_free_page</a> ()))
<a name='L329'>        <b>return</b> 0;
<a name='L330'>      *page_table = tmp | 7;
<a name='L331'>      page_table = (<b>unsigned</b> <b>long</b> *) tmp;
<a name='L332'>    <font color='red'>}</font>
<a name='L333'><i><font color='green'>// 在页表中设置指定地址的物理内存页面的页表项内容。每个页表共可有1024 项(0x3ff)。</font></i>
<a name='L334'>  page_table[(address &gt;&gt; 12) &amp; 0x3ff] = page | 7;
<a name='L335'><i><font color='green'>/* no need for invalidate */</font></i>
<a name='L336'><i><font color='green'>/* 不需要刷新页变换高速缓冲 */</font></i>
<a name='L337'>  <b>return</b> page;                  <i><font color='green'>// 返回页面地址。</font></i>
<a name='L338'><font color='red'>}</font>
<a name='L339'>
<a name='L340'><i><font color='green'>//// 取消写保护页面函数。用于页异常中断过程中写保护异常的处理(写时复制)。</font></i>
<a name='L341'><i><font color='green'>// 输入参数为页表项指针。</font></i>
<a name='L342'><i><font color='green'>// [ un_wp_page 意思是取消页面的写保护:Un-Write Protected。]</font></i>
<a name='L343'><b>void</b>
<a name='L344'><a href='../R/718.html' title='Multiple refered from 2 places.'>un_wp_page</a> (<b>unsigned</b> <b>long</b> *table_entry)
<a name='L345'><font color='red'>{</font>
<a name='L346'>  <b>unsigned</b> <b>long</b> old_page, new_page;
<a name='L347'>
<a name='L348'>  old_page = 0xfffff000 &amp; *table_entry; <i><font color='green'>// 取原页面对应的目录项号。</font></i>
<a name='L349'><i><font color='green'>// 如果原页面地址大于内存低端LOW_MEM(1Mb),并且其在页面映射字节图数组中值为1(表示仅</font></i>
<a name='L350'><i><font color='green'>// 被引用1 次,页面没有被共享),则在该页面的页表项中置R/W 标志(可写),并刷新页变换</font></i>
<a name='L351'><i><font color='green'>// 高速缓冲,然后返回。</font></i>
<a name='L352'>  <b>if</b> (old_page &gt;= <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a> &amp;&amp; mem_map[<a href='../S/94.html#L68' title='Defined at 68 in mm/memory.c.'>MAP_NR</a> (old_page)] == 1)
<a name='L353'>    <font color='red'>{</font>
<a name='L354'>      *table_entry |= 2;
<a name='L355'>      <a href='../S/94.html#L59' title='Defined at 59 in mm/memory.c.'>invalidate</a> ();
<a name='L356'>      <b>return</b>;
<a name='L357'>    <font color='red'>}</font>
<a name='L358'><i><font color='green'>// 否则,在主内存区内申请一页空闲页面。</font></i>
<a name='L359'>  <b>if</b> (!(new_page = <a href='../S/94.html#L101' title='Defined at 101 in mm/memory.c.'>get_free_page</a> ()))
<a name='L360'>    <a href='../S/94.html#L49' title='Defined at 49 in mm/memory.c.'>oom</a> ();                     <i><font color='green'>// Out of Memory。内存不够处理。</font></i>
<a name='L361'><i><font color='green'>// 如果原页面大于内存低端(则意味着mem_map[]&gt;1,页面是共享的),则将原页面的页面映射</font></i>
<a name='L362'><i><font color='green'>// 数组值递减1。然后将指定页表项内容更新为新页面的地址,并置可读写等标志(U/S, R/W, P)。</font></i>
<a name='L363'><i><font color='green'>// 刷新页变换高速缓冲。最后将原页面内容复制到新页面。</font></i>
<a name='L364'>  <b>if</b> (old_page &gt;= <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>)
<a name='L365'>    mem_map[<a href='../S/94.html#L68' title='Defined at 68 in mm/memory.c.'>MAP_NR</a> (old_page)]--;
<a name='L366'>  *table_entry = new_page | 7;
<a name='L367'>  <a href='../S/94.html#L59' title='Defined at 59 in mm/memory.c.'>invalidate</a> ();
<a name='L368'>  <a href='../S/94.html#L79' title='Defined at 79 in mm/memory.c.'>copy_page</a> (old_page, new_page);
<a name='L369'><font color='red'>}</font>
<a name='L370'>
<a name='L371'><i><font color='green'>/*</font></i>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?