94.html

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

HTML
668
字号
<a name='L104'>
<a name='L105'>  <b>__asm__</b> ("std ; repne ; scasb\n\t"    <i><font color='green'>// 方向位置位,将al(0)与对应每个页面的(di)内容比较,</font></i>
<a name='L106'>           "jne 1f\n\t"         <i><font color='green'>// 如果没有等于0 的字节,则跳转结束(返回0)。</font></i>
<a name='L107'>           "movb $1,1(%%edi)\n\t"       <i><font color='green'>// 将对应页面的内存映像位置1。</font></i>
<a name='L108'>           "sall $12,%%ecx\n\t" <i><font color='green'>// 页面数*4K = 相对页面起始地址。</font></i>
<a name='L109'>           "addl %2,%%ecx\n\t"  <i><font color='green'>// 再加上低端内存地址,即获得页面实际物理起始地址。</font></i>
<a name='L110'>           "movl %%ecx,%%edx\n\t"       <i><font color='green'>// 将页面实际起始地址??edx 寄存器。</font></i>
<a name='L111'>           "movl $1024,%%ecx\n\t"       <i><font color='green'>// 寄存器ecx 置计数值1024。</font></i>
<a name='L112'>           "leal 4092(%%edx),%%edi\n\t" <i><font color='green'>// 将4092+edx 的位置??edi(该页面的末端)。</font></i>
<a name='L113'>           "rep ; stosl\n\t"    <i><font color='green'>// 将edi 所指内存清零(反方向,也即将该页面清零)。</font></i>
<a name='L114'>           "movl %%edx,%%eax\n" <i><font color='green'>// 将页面起始地址??eax(返回值)。</font></i>
<a name='L115'>"1:": "=a" (__res): "" (0), "i" (<a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>), "c" (<a href='../S/94.html#L67' title='Defined at 67 in mm/memory.c.'>PAGING_PAGES</a>), "D" (mem_map + <a href='../S/94.html#L67' title='Defined at 67 in mm/memory.c.'>PAGING_PAGES</a> - 1):"di", "cx",
<a name='L116'>           "dx");
<a name='L117'>  <b>return</b> __res;                 <i><font color='green'>// 返回空闲页面地址(如果无空闲也则返回0)。</font></i>
<a name='L118'><font color='red'>}</font>
<a name='L119'>
<a name='L120'><i><font color='green'>/*</font></i>
<a name='L121'><i><font color='green'>* Free a page of memory at physical address 'addr'. Used by</font></i>
<a name='L122'><i><font color='green'>* 'free_page_tables()'</font></i>
<a name='L123'><i><font color='green'>*/</font></i>
<a name='L124'><i><font color='green'>/*</font></i>
<a name='L125'><i><font color='green'>* 释放物理地址'addr'开始的一页内存。用于函数'free_page_tables()'。</font></i>
<a name='L126'><i><font color='green'>*/</font></i>
<a name='L127'><i><font color='green'>//// 释放物理地址addr 开始的一页面内存。</font></i>
<a name='L128'><i><font color='green'>// 1MB 以下的内存空间用于内核程序和缓冲,不作为分配页面的内存空间。</font></i>
<a name='L129'><b>void</b>
<a name='L130'><a href='../R/468.html' title='Multiple refered from 10 places.'>free_page</a> (<b>unsigned</b> <b>long</b> addr)
<a name='L131'><font color='red'>{</font>
<a name='L132'>  <b>if</b> (addr &lt; <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>)
<a name='L133'>    <b>return</b>;                     <i><font color='green'>// 如果物理地址addr 小于内存低端(1MB),则返回。</font></i>
<a name='L134'>  <b>if</b> (addr &gt;= HIGH_MEMORY)      <i><font color='green'>// 如果物理地址addr&gt;=内存最高端,则显示出错信息。</font></i>
<a name='L135'>    <a href='../S/72.html#L24' title='Defined at 24 in kernel/panic.c.'>panic</a> ("trying to free nonexistent page");
<a name='L136'>  addr -= <a href='../S/94.html#L65' title='Defined at 65 in mm/memory.c.'>LOW_MEM</a>;              <i><font color='green'>// 物理地址减去低端内存位置,再除以4KB,得页面号。</font></i>
<a name='L137'>  addr &gt;&gt;= 12;
<a name='L138'>  <b>if</b> (mem_map[addr]--)
<a name='L139'>    <b>return</b>;                     <i><font color='green'>// 如果对应内存页面映射字节不等于0,则减1 返回。</font></i>
<a name='L140'>  mem_map[addr] = 0;            <i><font color='green'>// 否则置对应页面映射字节为0,并显示出错信息,死机。</font></i>
<a name='L141'>  <a href='../S/72.html#L24' title='Defined at 24 in kernel/panic.c.'>panic</a> ("trying to free free page");
<a name='L142'><font color='red'>}</font>
<a name='L143'>
<a name='L144'><i><font color='green'>/*</font></i>
<a name='L145'><i><font color='green'>* This function frees a continuos block of page tables, as needed</font></i>
<a name='L146'><i><font color='green'>* by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.</font></i>
<a name='L147'><i><font color='green'>*/</font></i>
<a name='L148'><i><font color='green'>/*</font></i>
<a name='L149'><i><font color='green'>* 下面函数释放页表连续的内存块,'exit()'需要该函数。与copy_page_tables()</font></i>
<a name='L150'><i><font color='green'>* 类似,该函数仅处理4Mb 的内存块。</font></i>
<a name='L151'><i><font color='green'>*/</font></i>
<a name='L152'><i><font color='green'>//// 根据指定的线性地址和限长(页表个数),释放对应内存页表所指定的内存块并置表项空闲。</font></i>
<a name='L153'><i><font color='green'>// 页目录位于物理地址0 开始处,共1024 项,占4K 字节。每个目录项指定一个页表。</font></i>
<a name='L154'><i><font color='green'>// 页表从物理地址0x1000 处开始(紧接着目录空间),每个页表有1024 项,也占4K 内存。</font></i>
<a name='L155'><i><font color='green'>// 每个页表项对应一页物理内存(4K)。目录项和页表项的大小均为4 个字节。</font></i>
<a name='L156'><i><font color='green'>// 参数:from - 起始基地址;size - 释放的长度。</font></i>
<a name='L157'><b>int</b>
<a name='L158'><a href='../R/469.html' title='Multiple refered from 6 places.'>free_page_tables</a> (<b>unsigned</b> <b>long</b> from, <b>unsigned</b> <b>long</b> size)
<a name='L159'><font color='red'>{</font>
<a name='L160'>  <b>unsigned</b> <b>long</b> *pg_table;
<a name='L161'>  <b>unsigned</b> <b>long</b> *dir, nr;
<a name='L162'>
<a name='L163'>  <b>if</b> (from &amp; 0x3fffff)          <i><font color='green'>// 要释放内存块的地址需以4M 为边界。</font></i>
<a name='L164'>    <a href='../S/72.html#L24' title='Defined at 24 in kernel/panic.c.'>panic</a> ("free_page_tables called with wrong alignment");
<a name='L165'>  <b>if</b> (!from)                    <i><font color='green'>// 出错,试图释放内核和缓冲所占空间。</font></i>
<a name='L166'>    <a href='../S/72.html#L24' title='Defined at 24 in kernel/panic.c.'>panic</a> ("Trying to free up swapper memory space");
<a name='L167'><i><font color='green'>// 计算所占页目录项数(4M 的进位整数倍),也即所占页表数。</font></i>
<a name='L168'>  size = (size + 0x3fffff) &gt;&gt; 22;
<a name='L169'><i><font color='green'>// 下面一句计算起始目录项。对应的目录项号=from&gt;&gt;22,因每项占4 字节,并且由于页目录是从</font></i>
<a name='L170'><i><font color='green'>// 物理地址0 开始,因此实际的目录项指针=目录项号&lt;&lt;2,也即(from&gt;&gt;20)。与上0xffc 确保</font></i>
<a name='L171'><i><font color='green'>// 目录项指针范围有效。</font></i>
<a name='L172'>  dir = (<b>unsigned</b> <b>long</b> *) ((from &gt;&gt; 20) &amp; 0xffc);       <i><font color='green'>/* _pg_dir = 0 */</font></i>
<a name='L173'>  <b>for</b> (; size-- &gt; 0; dir++)
<a name='L174'>    <font color='red'>{</font>                           <i><font color='green'>// size 现在是需要被释放内存的目录项数。</font></i>
<a name='L175'>      <b>if</b> (!(1 &amp; *dir))          <i><font color='green'>// 如果该目录项无效(P 位=0),则继续。</font></i>
<a name='L176'>        <b>continue</b>;               <i><font color='green'>// 目录项的位0(P 位)表示对应页表是否存在。</font></i>
<a name='L177'>      pg_table = (<b>unsigned</b> <b>long</b> *) (0xfffff000 &amp; *dir); <i><font color='green'>// 取目录项中页表地址。</font></i>
<a name='L178'>      <b>for</b> (nr = 0; nr &lt; 1024; nr++)
<a name='L179'>        <font color='red'>{</font>                       <i><font color='green'>// 每个页表有1024 个页项。</font></i>
<a name='L180'>          <b>if</b> (1 &amp; *pg_table)    <i><font color='green'>// 若该页表项有效(P 位=1),则释放对应内存页。</font></i>
<a name='L181'>            <a href='../S/94.html#L130' title='Defined at 130 in mm/memory.c.'>free_page</a> (0xfffff000 &amp; *pg_table);
<a name='L182'>          *pg_table = 0;        <i><font color='green'>// 该页表项内容清零。</font></i>
<a name='L183'>          pg_table++;           <i><font color='green'>// 指向页表中下一项。</font></i>
<a name='L184'>        <font color='red'>}</font>
<a name='L185'>      <a href='../S/94.html#L130' title='Defined at 130 in mm/memory.c.'>free_page</a> (0xfffff000 &amp; *dir);    <i><font color='green'>// 释放该页表所占内存页面。但由于页表在</font></i>
<a name='L186'><i><font color='green'>// 物理地址1M 以内,所以这句什么都不做。</font></i>
<a name='L187'>      *dir = 0;                 <i><font color='green'>// 对相应页表的目录项清零。</font></i>
<a name='L188'>    <font color='red'>}</font>
<a name='L189'>  <a href='../S/94.html#L59' title='Defined at 59 in mm/memory.c.'>invalidate</a> ();                <i><font color='green'>// 刷新页变换高速缓冲。</font></i>
<a name='L190'>  <b>return</b> 0;
<a name='L191'><font color='red'>}</font>
<a name='L192'>
<a name='L193'><i><font color='green'>/*</font></i>
<a name='L194'><i><font color='green'>* Well, here is one of the most complicated functions in mm. It</font></i>
<a name='L195'><i><font color='green'>* copies a range of linerar addresses by copying only the pages.</font></i>
<a name='L196'><i><font color='green'>* Let's hope this is bug-free, 'cause this one I don't want to debug :-)</font></i>
<a name='L197'><i><font color='green'>*</font></i>
<a name='L198'><i><font color='green'>* Note! We don't copy just any chunks of memory - addresses have to</font></i>
<a name='L199'><i><font color='green'>* be divisible by 4Mb (one page-directory entry), as this makes the</font></i>
<a name='L200'><i><font color='green'>* function easier. It's used only by fork anyway.</font></i>
<a name='L201'><i><font color='green'>*</font></i>
<a name='L202'><i><font color='green'>* NOTE 2!! When from==0 we are copying kernel space for the first</font></i>
<a name='L203'><i><font color='green'>* fork(). Then we DONT want to copy a full page-directory entry, as</font></i>
<a name='L204'><i><font color='green'>* that would lead to some serious memory waste - we just copy the</font></i>
<a name='L205'><i><font color='green'>* first 160 pages - 640kB. Even that is more than we need, but it</font></i>
<a name='L206'><i><font color='green'>* doesn't take any more memory - we don't copy-on-write in the low</font></i>
<a name='L207'><i><font color='green'>* 1 Mb-range, so the pages can be shared with the kernel. Thus the</font></i>
<a name='L208'><i><font color='green'>* special case for nr=xxxx.</font></i>
<a name='L209'><i><font color='green'>*/</font></i>
<a name='L210'><i><font color='green'>/*</font></i>
<a name='L211'><i><font color='green'>* 好了,下面是内存管理mm 中最为复杂的程序之一。它通过只复制内存页面</font></i>
<a name='L212'><i><font color='green'>* 来拷贝一定范围内线性地址中的内容。希望代码中没有错误,因为我不想</font></i>
<a name='L213'><i><font color='green'>* 再调试这块代码了?。</font></i>
<a name='L214'><i><font color='green'>*</font></i>
<a name='L215'><i><font color='green'>* 注意!我们并不是仅复制任何内存块 - 内存块的地址需要是4Mb 的倍数(正好</font></i>
<a name='L216'><i><font color='green'>* 一个页目录项对应的内存大小),因为这样处理可使函数很简单。不管怎样,</font></i>
<a name='L217'><i><font color='green'>* 它仅被fork()使用(fork.c 第56 行)。</font></i>
<a name='L218'><i><font color='green'>*</font></i>
<a name='L219'><i><font color='green'>* 注意2!!当from==0 时,是在为第一次fork()调用复制内核空间。此时我们</font></i>
<a name='L220'><i><font color='green'>* 不想复制整个页目录项对应的内存,因为这样做会导致内存严重的浪费 - 我们</font></i>
<a name='L221'><i><font color='green'>* 只复制头160 个页面 - 对应640kB。即使是复制这些页面也已经超出我们的需求,</font></i>
<a name='L222'><i><font color='green'>* 但这不会占用更多的内存 - 在低1Mb 内存范围内我们不执行写时复制操作,所以</font></i>
<a name='L223'><i><font color='green'>* 这些页面可以与内核共享。因此这是nr=xxxx 的特殊情况(nr 在程序中指页面数)。</font></i>
<a name='L224'><i><font color='green'>*/</font></i>
<a name='L225'><i><font color='green'>//// 复制指定线性地址和长度(页表个数)内存对应的页目录项和页表,从而被复制的页目录和</font></i>
<a name='L226'><i><font color='green'>//// 页表对应的原物理内存区被共享使用。</font></i>
<a name='L227'><i><font color='green'>// 复制指定地址和长度的内存对应的页目录项和页表项。需申请页面来存放新页表,原内存区被共享;</font></i>
<a name='L228'><i><font color='green'>// 此后两个进程将共享内存区,直到有一个进程执行写操作时,才分配新的内存页(写时复制机制)。</font></i>
<a name='L229'><b>int</b>
<a name='L230'><a href='../R/410.html' title='Multiple refered from 2 places.'>copy_page_tables</a> (<b>unsigned</b> <b>long</b> from, <b>unsigned</b> <b>long</b> to, <b>long</b> size)
<a name='L231'><font color='red'>{</font>
<a name='L232'>  <b>unsigned</b> <b>long</b> *from_page_table;
<a name='L233'>  <b>unsigned</b> <b>long</b> *to_page_table;
<a name='L234'>  <b>unsigned</b> <b>long</b> this_page;
<a name='L235'>  <b>unsigned</b> <b>long</b> *from_dir, *to_dir;
<a name='L236'>  <b>unsigned</b> <b>long</b> nr;
<a name='L237'>

⌨️ 快捷键说明

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