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 & 0x3fffff) || (to & 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 >> 20) & 0xffc); <i><font color='green'>/* _pg_dir = 0 */</font></i>
<a name='L243'> to_dir = (<b>unsigned</b> <b>long</b> *) ((to >> 20) & 0xffc);
<a name='L244'><i><font color='green'>// 计算要复制的内存块占用的页表数(也即目录项数)。</font></i>
<a name='L245'> size = ((<b>unsigned</b>) (size + 0x3fffff)) >> 22;
<a name='L246'><i><font color='green'>// 下面开始对每个占用的页表依次进行复制操作。</font></i>
<a name='L247'> <b>for</b> (; size-- > 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 & *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 & *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 & *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-- > 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 & 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 &= ~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 > <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 >>= 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 < <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a> || page >= 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>) >> 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 >> 20) & 0xffc);
<a name='L321'><i><font color='green'>// 如果该目录项有效(P=1)(也即指定的页表在内存中),则从中取得指定页表的地址??page_table。</font></i>
<a name='L322'> <b>if</b> ((*page_table) & 1)
<a name='L323'> page_table = (<b>unsigned</b> <b>long</b> *) (0xfffff000 & *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 >> 12) & 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 & *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 >= <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a> && 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[]>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 >= <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 + -
显示快捷键?