📄 linux-+
字号:
<p><b><font size="6" color="#0000FF"><a name="初始化和固定映射">初始化和固定映射
</a></font></b></p>
<p><b> </b>把固定映射放到这里,一个是固定映射不会变动,另一个是对固定映射所知较少.</p>
<p> 最不会引起争议的是,<b><font color="#FF0000">linux/init/main.c</font></b>
中的 <font color="#800080" size="5"><b>start_kernel</b></font>是启动后内核的入口. </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>(&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->need_resched = 1;
cpu_idle();
}</pre>
<p><font color="#FF0000"><b>arch/i386/kernel/setup.c </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) &_text;<font color="#0000FF"> //初始化</font> <b><font color="#800080">init_mm</font></b>
......
code_resource.start = virt_to_bus(&_text);
......
data_resource.start = virt_to_bus(&_etext);
......
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
/*
* <font color="#0000FF">128MB for vmalloc and initrd</font>
*/
#define <font color="#FF0000">VMALLOC_RESERVE</font> (unsigned long)(128 << 20)
#define <font color="#FF0000">MAXMEM</font> (unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)
#define MAXMEM_PFN PFN_DOWN(MAXMEM)
#define MAX_NONPAE_PFN (1 << 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(&_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 > MAXMEM_PFN) {
<font color="#800080"><b>highstart_pfn</b></font> = MAXMEM_PFN;
printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
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>(&iomem_resource, &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 见专门章节吧!我们的重点是 <br>
<font color="#FF0000"><b>arch/i386/mm/Init.c </b></font><br>
<font color="#800080">/*<br>
* paging_init() sets up the page tables - note that the first 8MB are<br>
* already mapped by head.S.<br>
*<br>
* This routines also unmaps the page at virtual kernel address 0, so<br>
* that we can trap those pesky NULL-reference errors in the kernel.<br>
*/</font><br>
void __init <b><font color="#0000FF">paging_init</font></b>(void)<br>
{<br>
<font color="#0000FF">pagetable_init(); //设置页表<br>
</font> __asm__( "movl %%ecx,%%cr3\n"
::"c"(__pa(swapper_pg_dir))); <font color="#0000FF">//重置cpu页目录<br>
</font> __flush_tlb_all();<br>
#ifdef CONFIG_HIGHMEM<br>
<font color="#0000FF">kmap_init();</font><br>
#endif<br>
{ <font color="#0000FF">//计算管理区大小</font><br>
unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};<br>
unsigned int max_dma, high, low;<br>
}<br>
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) & 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>
在一般情况下,Linux在初始化时,总是尽可能的将所有的物理内存映射到内核地址空间中去。如果内核地址空间起始于0xC0000000,为vmalloc保留的虚拟地址空间是128M,那么最多只能有(1G-128M)的物理内存直接映射到内核空间中,内核可以直接访问。如果还有更多的内存,就称为高端内存,内核不能直接访问,只能通过修改页表映射后才能进行访问。<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -