94.html
来自「linux 0.11中文版 有注释」· HTML 代码 · 共 668 行 · 第 1/5 页
HTML
668 行
<a name='L372'><i><font color='green'>* This routine handles present pages, when users try to write</font></i>
<a name='L373'><i><font color='green'>* to a shared page. It is done by copying the page to a new address</font></i>
<a name='L374'><i><font color='green'>* and decrementing the shared-page counter for the old page.</font></i>
<a name='L375'><i><font color='green'>*</font></i>
<a name='L376'><i><font color='green'>* If it's in code space we exit with a segment error.</font></i>
<a name='L377'><i><font color='green'>*/</font></i>
<a name='L378'><i><font color='green'>/*</font></i>
<a name='L379'><i><font color='green'>* 当用户试图往一个共享页面上写时,该函数处理已存在的内存页面,(写时复制)</font></i>
<a name='L380'><i><font color='green'>* 它是通过将页面复制到一个新地址上并递减原页面的共享页面计数值实现的。</font></i>
<a name='L381'><i><font color='green'>*</font></i>
<a name='L382'><i><font color='green'>* 如果它在代码空间,我们就以段错误信息退出。</font></i>
<a name='L383'><i><font color='green'>*/</font></i>
<a name='L384'><i><font color='green'>//// 页异常中断处理调用的C 函数。写共享页面处理函数。在page.s 程序中被调用。</font></i>
<a name='L385'><i><font color='green'>// 参数error_code 是由CPU 自动产生,address 是页面线性地址。</font></i>
<a name='L386'><i><font color='green'>// 写共享页面时,需复制页面(写时复制)。</font></i>
<a name='L387'><b>void</b>
<a name='L388'>do_wp_page (<b>unsigned</b> <b>long</b> error_code, <b>unsigned</b> <b>long</b> address)
<a name='L389'><font color='red'>{</font>
<a name='L390'><font color='darkred'>#if</font> 0
<a name='L391'><i><font color='green'>/* we cannot do this yet: the estdio library writes to code space */</font></i>
<a name='L392'><i><font color='green'>/* stupid, stupid. I really want the libc.a from GNU */</font></i>
<a name='L393'><i><font color='green'>/* 我们现在还不能这样做:因为estdio 库会在代码空间执行写操作 */</font></i>
<a name='L394'><i><font color='green'>/* 真是太愚蠢了。我真想从GNU 得到libc.a 库。*/</font></i>
<a name='L395'> <b>if</b> (<a href='../S/94.html#L73' title='Defined at 73 in mm/memory.c.'>CODE_SPACE</a> (address)) <i><font color='green'>// 如果地址位于代码空间,则终止执行程序。</font></i>
<a name='L396'> <a href='../S/67.html#L139' title='Defined at 139 in kernel/exit.c.'>do_exit</a> (<a href='../S/39.html#L24' title='Defined at 24 in include/signal.h.'>SIGSEGV</a>);
<a name='L397'><font color='darkred'>#endif</font>
<a name='L398'><i><font color='green'>// 处理取消页面保护。参数指定页面在页表中的页表项指针,其计算方法是:</font></i>
<a name='L399'><i><font color='green'>// ((address>>10) & 0xffc):计算指定地址的页面在页表中的偏移地址;</font></i>
<a name='L400'><i><font color='green'>// (0xfffff000 &((address>>20) &0xffc)):取目录项中页表的地址值,</font></i>
<a name='L401'><i><font color='green'>// 其中((address>>20) &0xffc)计算页面所在页表的目录项指针;</font></i>
<a name='L402'><i><font color='green'>// 两者相加即得指定地址对应页面的页表项指针。这里对共享的页面进行复制。</font></i>
<a name='L403'> <a href='../S/94.html#L344' title='Defined at 344 in mm/memory.c.'>un_wp_page</a> ((<b>unsigned</b> <b>long</b> *)
<a name='L404'> (((address >> 10) & 0xffc) + (0xfffff000 &
<a name='L405'> *((<b>unsigned</b> <b>long</b>
<a name='L406'> *) ((address >> 20) &
<a name='L407'> 0xffc)))));
<a name='L408'>
<a name='L409'><font color='red'>}</font>
<a name='L410'>
<a name='L411'><i><font color='green'>//// 写页面验证。</font></i>
<a name='L412'><i><font color='green'>// 若页面不可写,则复制页面。在fork.c 第34 行被调用。</font></i>
<a name='L413'><b>void</b>
<a name='L414'><a href='../R/738.html' title='Multiple refered from 2 places.'>write_verify</a> (<b>unsigned</b> <b>long</b> address)
<a name='L415'><font color='red'>{</font>
<a name='L416'> <b>unsigned</b> <b>long</b> page;
<a name='L417'>
<a name='L418'><i><font color='green'>// 判断指定地址所对应页目录项的页表是否存在(P),若不存在(P=0)则返回。</font></i>
<a name='L419'> <b>if</b> (!((page = *((<b>unsigned</b> <b>long</b> *) ((address >> 20) & 0xffc))) & 1))
<a name='L420'> <b>return</b>;
<a name='L421'><i><font color='green'>// 取页表的地址,加上指定地址的页面在页表中的页表项偏移值,得对应物理页面的页表项指针。</font></i>
<a name='L422'> page &= 0xfffff000;
<a name='L423'> page += ((address >> 10) & 0xffc);
<a name='L424'><i><font color='green'>// 如果该页面不可写(标志R/W 没有置位),则执行共享检验和复制页面操作(写时复制)。</font></i>
<a name='L425'> <b>if</b> ((3 & *(<b>unsigned</b> <b>long</b> *) page) == 1) <i><font color='green'>/* non-writeable, present */</font></i>
<a name='L426'> <a href='../S/94.html#L344' title='Defined at 344 in mm/memory.c.'>un_wp_page</a> ((<b>unsigned</b> <b>long</b> *) page);
<a name='L427'> <b>return</b>;
<a name='L428'><font color='red'>}</font>
<a name='L429'>
<a name='L430'><i><font color='green'>//// 取得一页空闲内存并映射到指定线性地址处。</font></i>
<a name='L431'><i><font color='green'>// 与get_free_page()不同。get_free_page()仅是申请取得了主内存区的一页物理内存。而该函数</font></i>
<a name='L432'><i><font color='green'>// 不仅是获取到一页物理内存页面,还进一步调用put_page(),将物理页面映射到指定的线性地址</font></i>
<a name='L433'><i><font color='green'>// 处。</font></i>
<a name='L434'><b>void</b>
<a name='L435'><a href='../S/94.html#L592' title='Refered from 592 in mm/memory.c.'>get_empty_page</a> (<b>unsigned</b> <b>long</b> address)
<a name='L436'><font color='red'>{</font>
<a name='L437'> <b>unsigned</b> <b>long</b> tmp;
<a name='L438'>
<a name='L439'><i><font color='green'>// 若不能取得一空闲页面,或者不能将页面放置到指定地址处,则显示内存不够的信息。</font></i>
<a name='L440'><i><font color='green'>// 279 行上英文注释的含义是:即使执行get_free_page()返回0 也无所谓,因为put_page()</font></i>
<a name='L441'><i><font color='green'>// 中还会对此情况再次申请空闲物理页面的,见210 行。</font></i>
<a name='L442'> <b>if</b> (!(tmp = <a href='../S/94.html#L101' title='Defined at 101 in mm/memory.c.'>get_free_page</a> ()) || !<a href='../S/94.html#L306' title='Defined at 306 in mm/memory.c.'>put_page</a> (tmp, address))
<a name='L443'> <font color='red'>{</font>
<a name='L444'> <a href='../S/94.html#L130' title='Defined at 130 in mm/memory.c.'>free_page</a> (tmp); <i><font color='green'>/* 0 is ok - ignored */</font></i>
<a name='L445'> <a href='../S/94.html#L49' title='Defined at 49 in mm/memory.c.'>oom</a> ();
<a name='L446'> <font color='red'>}</font>
<a name='L447'><font color='red'>}</font>
<a name='L448'>
<a name='L449'><i><font color='green'>/*</font></i>
<a name='L450'><i><font color='green'>* try_to_share() checks the page at address "address" in the task "p",</font></i>
<a name='L451'><i><font color='green'>* to see if it exists, and if it is clean. If so, share it with the current</font></i>
<a name='L452'><i><font color='green'>* task.</font></i>
<a name='L453'><i><font color='green'>*</font></i>
<a name='L454'><i><font color='green'>* NOTE! This assumes we have checked that p != current, and that they</font></i>
<a name='L455'><i><font color='green'>* share the same executable.</font></i>
<a name='L456'><i><font color='green'>*/</font></i>
<a name='L457'><i><font color='green'>/*</font></i>
<a name='L458'><i><font color='green'>* try_to_share()在任务"p"中检查位于地址"address"处的页面,看页面是否存在,是否干净。</font></i>
<a name='L459'><i><font color='green'>* 如果是干净的话,就与当前任务共享。</font></i>
<a name='L460'><i><font color='green'>*</font></i>
<a name='L461'><i><font color='green'>* 注意!这里我们已假定p !=当前任务,并且它们共享同一个执行程序。</font></i>
<a name='L462'><i><font color='green'>*/</font></i>
<a name='L463'><i><font color='green'>//// 尝试对进程指定地址处的页面进行共享操作。</font></i>
<a name='L464'><i><font color='green'>// 同时还验证指定的地址处是否已经申请了页面,若是则出错,死机。</font></i>
<a name='L465'><i><font color='green'>// 返回1-成功,0-失败。</font></i>
<a name='L466'><b>static</b> <b>int</b>
<a name='L467'><a href='../S/94.html#L565' title='Refered from 565 in mm/memory.c.'>try_to_share</a> (<b>unsigned</b> <b>long</b> address, <b>struct</b> task_struct *p)
<a name='L468'><font color='red'>{</font>
<a name='L469'> <b>unsigned</b> <b>long</b> from;
<a name='L470'> <b>unsigned</b> <b>long</b> to;
<a name='L471'> <b>unsigned</b> <b>long</b> from_page;
<a name='L472'> <b>unsigned</b> <b>long</b> to_page;
<a name='L473'> <b>unsigned</b> <b>long</b> phys_addr;
<a name='L474'>
<a name='L475'><i><font color='green'>// 求指定内存地址的页目录项。</font></i>
<a name='L476'> from_page = to_page = ((address >> 20) & 0xffc);
<a name='L477'><i><font color='green'>// 计算进程p 的代码起始地址所对应的页目录项。</font></i>
<a name='L478'> from_page += ((p->start_code >> 20) & 0xffc);
<a name='L479'><i><font color='green'>// 计算当前进程中代码起始地址所对应的页目录项。</font></i>
<a name='L480'> to_page += ((current->start_code >> 20) & 0xffc);
<a name='L481'><i><font color='green'>/* is there a page-directory at from? */</font></i>
<a name='L482'><i><font color='green'>/* 在from 处是否存在页目录?*/</font></i>
<a name='L483'><i><font color='green'>// *** 对p 进程页面进行操作。</font></i>
<a name='L484'><i><font color='green'>// 取页目录项内容。如果该目录项无效(P=0),则返回。否则取该目录项对应页表地址??from。</font></i>
<a name='L485'> from = *(<b>unsigned</b> <b>long</b> *) from_page;
<a name='L486'> <b>if</b> (!(from & 1))
<a name='L487'> <b>return</b> 0;
<a name='L488'> from &= 0xfffff000;
<a name='L489'><i><font color='green'>// 计算地址对应的页表项指针值,并取出该页表项内容??phys_addr。</font></i>
<a name='L490'> from_page = from + ((address >> 10) & 0xffc);
<a name='L491'> phys_addr = *(<b>unsigned</b> <b>long</b> *) from_page;
<a name='L492'><i><font color='green'>/* is the page clean and present? */</font></i>
<a name='L493'><i><font color='green'>/* 页面干净并且存在吗?*/</font></i>
<a name='L494'><i><font color='green'>// 0x41 对应页表项中的Dirty 和Present 标志。如果页面不干净或无效则返回。</font></i>
<a name='L495'> <b>if</b> ((phys_addr & 0x41) != 0x01)
<a name='L496'> <b>return</b> 0;
<a name='L497'><i><font color='green'>// 取页面的地址??phys_addr。如果该页面地址不存在或小于内存低端(1M)也返回退出。</font></i>
<a name='L498'> phys_addr &= 0xfffff000;
<a name='L499'> <b>if</b> (phys_addr >= HIGH_MEMORY || phys_addr < <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>)
<a name='L500'> <b>return</b> 0;
<a name='L501'><i><font color='green'>// *** 对当前进程页面进行操作。</font></i>
<a name='L502'><i><font color='green'>// 取页目录项内容??to。如果该目录项无效(P=0),则取空闲页面,并更新to_page 所指的目录项。</font></i>
<a name='L503'> to = *(<b>unsigned</b> <b>long</b> *) to_page;
<a name='L504'> <b>if</b> (!(to & 1))
<a name='L505'> <b>if</b> (to = <a href='../S/94.html#L101' title='Defined at 101 in mm/memory.c.'>get_free_page</a> ())
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?