⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux-+

📁 linux下内存管理的文章 很长
💻
📖 第 1 页 / 共 4 页
字号:
<p><b><font size="6" color="#0000FF"><a name="初始化和固定映射">初始化和固定映射&nbsp;          
&nbsp;</a></font></b></p>   
<p><b>&nbsp;</b>把固定映射放到这里,一个是固定映射不会变动,另一个是对固定映射所知较少.</p> 
<p>&nbsp; 最不会引起争议的是,<b><font color="#FF0000">linux/init/main.c</font></b>           
中的 <font color="#800080" size="5"><b>start_kernel</b></font>是启动后内核的入口.&nbsp;</p>          
<pre><font color="#0000FF">(为了节省篇幅,省去了无关代码)</font>
/*
 *	Activate the first processor.
 */
asmlinkage void __init <font color="#0000FF">start_kernel</font>(void)
{
	char * command_line;
	unsigned long mempages;
	extern char saved_command_line[];
/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
	....
	<font color="#0000FF"><a href="#setup_arch">setup_arch</a></font>(&amp;command_line); <font color="#0000FF">//体系相关部分的初始化</font>
	....<font color="#0000FF">
</font>        <font color="#0000FF">kmem_cache_init</font>();
	....
	mem_init();
	kmem_cache_sizes_init();
        ....
	proc_caches_init();
	vfs_caches_init(mempages);
	buffer_init(mempages);
	page_cache_init(mempages);
	....
        kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
	unlock_kernel();
	current-&gt;need_resched = 1;
 	cpu_idle();
}</pre> 
<p><font color="#FF0000"><b>arch/i386/kernel/setup.c&nbsp;</b></font></p> 
<pre>void __init <b><font color="#0000FF"><a name="setup_arch">setup_arch</a></font></b>(char **cmdline_p)
{
	unsigned long bootmap_size;
	unsigned long start_pfn, max_pfn, max_low_pfn;
	int i;</pre> 
<pre>        .......
	<font color="#0000FF">setup_memory_region</font>(); <font color="#0000FF">//有的系统 e820 不太好使,可能伪造一个 bios</font> <b><font color="#800080">e820
</font></b>        .......
        init_mm.start_code = (unsigned long) &amp;_text;<font color="#0000FF"> //初始化</font> <b><font color="#800080">init_mm</font></b>
	......
        code_resource.start = virt_to_bus(&amp;_text);
        ......
	data_resource.start = virt_to_bus(&amp;_etext);
	......
#define PFN_UP(x)	(((x) + PAGE_SIZE-1) &gt;&gt; PAGE_SHIFT)
#define PFN_DOWN(x)	((x) &gt;&gt; PAGE_SHIFT)
#define PFN_PHYS(x)	((x) &lt;&lt; PAGE_SHIFT)
/*
 * <font color="#0000FF">128MB for vmalloc and initrd</font>
 */
#define <font color="#FF0000">VMALLOC_RESERVE</font>	(unsigned long)(128 &lt;&lt; 20)
#define <font color="#FF0000">MAXMEM</font>		(unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)
#define MAXMEM_PFN	PFN_DOWN(MAXMEM)
#define MAX_NONPAE_PFN	(1 &lt;&lt; 20)</pre> 
<pre>	/*
	 * <font color="#0000FF">partially used pages are not usable - thus</font>
	 * <font color="#0000FF">we are rounding upwards:</font>
	 */
	start_pfn = PFN_UP(__pa(&amp;_end));</pre> 
<pre>	/*
	 * <font color="#0000FF">Find the highest page frame number(pfn) we have available in E820</font>
	 */
	max_pfn = 0;
        .......
	/*
	 * <font color="#0000FF">Determine low and high memory ranges: (确定高端内存)</font>
	 */
#ifdef CONFIG_HIGHMEM
	<b><font color="#800080">highstart_pfn</font></b> = <b><font color="#800080">highend_pfn</font></b> = max_pfn;
	if (max_pfn &gt; MAXMEM_PFN) {
		<font color="#800080"><b>highstart_pfn</b></font> = MAXMEM_PFN;
		printk(KERN_NOTICE &quot;%ldMB HIGHMEM available.\n&quot;,
			pages_to_mb(highend_pfn - highstart_pfn));
	}
#endif
	/*
	 * <font color="#0000FF">Initialize the boot-time allocator (with low memory only):</font>
	 */
	bootmap_size = <font color="#0000FF">init_bootmem</font>(start_pfn, max_low_pfn);</pre> 
<pre>	/*
	 * <font color="#0000FF">把所有可用的低端内存注册于 bootmem allocator .</font>
	 */
	.......
	/*
	 * <font color="#0000FF">Reserve the bootmem bitmap itself as well. We do this in two</font>
	 * <font color="#0000FF">steps (first step was init_bootmem()) because this catches</font>
	 * <font color="#0000FF">the (very unlikely) case of us accidentally initializing the</font>
	 *<font color="#0000FF"> bootmem allocator with an invalid RAM area.</font>
	 */
	reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
			 bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));</pre> 
<pre>	<font color="#0000FF">/*
	 * reserve physical page 0 - it's a special BIOS page on many boxes,
	 * enabling clean reboots, SMP operation, laptop functions.
	 */</font>
	reserve_bootmem(0, PAGE_SIZE);
        ......
	<font color="#FF0000"><b>paging_init</b></font>();
        ......
	<font color="#0000FF">/*
	 * Request address space for all standard RAM and ROM resources
	 * and also for regions reported as reserved by the e820.
	 */</font>
        .....
	<font color="#0000FF">request_resource</font>(&amp;iomem_resource, &amp;vram_resource); <font color="#0000FF">//可以研究一下
</font>	<font color="#0000FF">/* request I/O space for devices used on all i[345]86 PCs */</font>
        .......	</pre> 
<pre>}</pre> 
<p><b><font color="#FF0000">什么是<a href="#Method E820H">e820</a>? </font></b>跟着链接去看看<font color="#FF0000">.<br>          
</font>boot mem 见专门章节吧!我们的重点是&nbsp;<br>         
<font color="#FF0000"><b>arch/i386/mm/Init.c&nbsp;&nbsp;</b></font><br> 
<font color="#800080">/*<br> 
&nbsp;* paging_init() sets up the page tables - note that the first 8MB are<br> 
&nbsp;* already mapped by head.S.<br> 
&nbsp;*<br> 
&nbsp;* This routines also unmaps the page at virtual kernel address 0, so<br> 
&nbsp;* that we can trap those pesky NULL-reference errors in the kernel.<br> 
&nbsp;*/</font><br> 
void __init <b><font color="#0000FF">paging_init</font></b>(void)<br>         
{<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#0000FF">pagetable_init(); //设置页表<br>         
</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__( &quot;movl %%ecx,%%cr3\n&quot;          
::&quot;c&quot;(__pa(swapper_pg_dir))); <font color="#0000FF">//重置cpu页目录<br>         
</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __flush_tlb_all();<br>         
#ifdef CONFIG_HIGHMEM<br>         
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#0000FF">kmap_init();</font><br>         
#endif<br> 
 { <font color="#0000FF">//计算管理区大小</font><br>         
&nbsp;&nbsp;&nbsp; unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};<br>         
&nbsp;&nbsp;&nbsp; unsigned int max_dma, high, low;<br>         
&nbsp; }<br>         
&nbsp;&nbsp; return;<br>         
}<br> 
<br> 
static void __init <b><font color="#0000FF">pagetable_init</font></b> (void)<br>         
{<br> 
unsigned long vaddr, end;<br>         
pgd_t *pgd, *pgd_base;<br>         
int i, j, k;<br>         
pmd_t *pmd;<br>         
pte_t *pte;</p>         
<pre>	/*
	 * This can be zero as well - no problem, in that case we exit
	 * the loops anyway due to the PTRS_PER_* conditions.
	 */
	end = (unsigned long)__va(<b><font color="#800080">max_low_pfn</font></b>*PAGE_SIZE); <font color="#0000FF">//首先设置低端内存</font>
        pgd_base = <b><font color="#800080">swapper_pg_dir</font></b>;
        .....
        i = __pgd_offset(PAGE_OFFSET); <font color="#0000FF">//看到设置的虚拟空间了吧?</font>
        .....
	<font color="#0000FF">/*
	 * Fixed mappings, only the page table structure has to be
	 * created - mappings will be set by set_fixmap():
	 */</font>
	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) &amp; PMD_MASK;
	<font color="#0000FF">fixrange_init</font>(vaddr, 0, pgd_base);</pre> 
<pre>#if CONFIG_HIGHMEM
	/*
	 * Permanent kmaps:
	 */
	vaddr = PKMAP_BASE;
	fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
	pgd = swapper_pg_dir + __pgd_offset(vaddr);
	pmd = pmd_offset(pgd, vaddr);
	pte = pte_offset(pmd, vaddr);
	<b><font color="#800080">pkmap_page_table</font></b> = pte;   <font color="#0000FF">//找到 pkmap区(4m)在内核虚拟空间所对应的页表 </font>
#endif</pre> 
<pre>
}</pre> 
<p>希望能够理清高端内存和固定映射的概念及管理方式.为此再看看          
<font color="#0000FF">kmap_init()</font></p> 
<pre><font color="#0000FF">/*
 * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
 * physical space so we can cache the place of the first one and move
 * around without checking the pgd every time.
 */
</font>#if CONFIG_HIGHMEM
pte_t *<b><font color="#800080">kmap_pte</font></b>;    <font color="#0000FF">//内核映射的页表</font>
pgprot_t <b><font color="#800080">kmap_prot</font></b>; </pre> 
<pre>#define kmap_get_fixmap_pte(vaddr)					\
	pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))</pre> 
<pre>void __init <b><font color="#0000FF">kmap_init</font></b>(void)
{
	unsigned long kmap_vstart;</pre> 
<pre>	/* cache the first kmap pte */
	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);</pre> 
<pre>	kmap_prot = PAGE_KERNEL;
}
#endif /* CONFIG_HIGHMEM */</pre> 
<p> </p>
<hr>
<p><b><font size="6" color="#0000FF"><a name="Boot mem">Boot mem</a></font></b></p>         
<p> </p>
<hr>
<p> </p>
<p><b><font size="6" color="#0000FF"><a name="高端内存">高端内存</a></font></b></p>
<p><span class="post"><br>
&nbsp; 在一般情况下,Linux在初始化时,总是尽可能的将所有的物理内存映射到内核地址空间中去。如果内核地址空间起始于0xC0000000,为vmalloc保留的虚拟地址空间是128M,那么最多只能有(1G-128M)的物理内存直接映射到内核空间中,内核可以直接访问。如果还有更多的内存,就称为高端内存,内核不能直接访问,只能通过修改页表映射后才能进行访问。<br>         

⌨️ 快捷键说明

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