linux 启动之setup_arch函数(二)
来源:互联网 发布:如何在淘宝开旗舰店 编辑:程序博客网 时间:2024/04/25 17:20
01static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,02 unsigned long end, unsigned long phys,03 const struct mem_type *type)04{05 pmd_t *pmd = pmd_offset(pgd, addr);0607 /*08 * Try a section mapping - end, addr and phys must all be aligned09 * to a section boundary. Note that PMDs refer to the individual10 * L1 entries, whereas PGDs refer to a group of L1 entries making11 * up one logical pointer to an L2 table.12 */13 if (((addr | end | phys) & ~SECTION_MASK) == 0) {14 pmd_t *p = pmd;1516 if (addr & SECTION_SIZE)17 pmd++;1819 do {20 *pmd = __pmd(phys | type->prot_sect);21 phys += SECTION_SIZE;22 } while (pmd++, addr += SECTION_SIZE, addr != end);2324 flush_pmd_entry(p);25 } else {26 /*27 * No need to loop; pte's aren't interested in the28 * individual L1 entries.29 */30 alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);31 }32}
第5行取出页表的值,在pgd中使用索引号取出是页表的值。
第13行进行检查
第14行一级赋予pmd类型的指针
第19行循环进行映射,循环多少次,是循环0xc0008000-0xc0007000这么多次。
条21行mmu的映射可以有四中方式进行,段,大页,小页,无映射,在这里面使用了段的映射。以1M的段进行映射,映射后的物理
第22行页表是以4个字节的步长进行增加
第30行以大页方式进行映射
01static unsigned long __init bootmap_bytes(unsigned long pages)02{ 03 unsigned long bytes = (pages + 7) / 8; 04 05 return ALIGN(bytes, sizeof(long)); 06} 07unsigned long __init bootmem_bootmap_pages(unsigned long pages)08{09 unsigned long bytes = bootmap_bytes(pages); 10 return PAGE_ALIGN(bytes) >> PAGE_SHIFT;11}
第3行计算出需要多少字节,这里的加7是为了字节对齐,如果只有一位,也需要分配一个字节
第4行返回以8个字节对齐方式
第9行得到里面的字节
第10总字节数除以4K,得到需要页数为4,所以可以有这么多位图4*1024*8
02static unsigned int __init find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)03{04 unsigned int start_pfn, i, bootmap_pfn;0506 start_pfn = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT;07 bootmap_pfn = 0;0809 for_each_nodebank(i, mi, node) {10 struct membank *bank = &mi->bank[i];11 unsigned int start, end;1213 start = bank_pfn_start(bank);14 end = bank_pfn_end(bank);1516 if (end < start_pfn)17 continue;1819 if (start < start_pfn)20 start = start_pfn;2122 if (end <= start)23 continue;2425 if (end - start >= bootmap_pages) {26 bootmap_pfn = start;27 break;28 }29 }3031 if (bootmap_pfn == 0)32 BUG();3334 return bootmap_pfn;35}
第6行从内核的映像文件结束位置开始,第一个可以使用的页帧号,PAGE_ALIGN宏是页对齐方式。第9行循环找出每个结点对应的内存,并记录下开始的页帧号和结束的页帧号。第13行开始的页帧号第14行结束的页帧号第34行返回可以用的第一个页帧号
01unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,02 unsigned long startpfn, unsigned long endpfn)03{04 return init_bootmem_core(pgdat->bdata, freepfn, startpfn, endpfn);05}06static void __init link_bootmem(bootmem_data_t *bdata)07{08 struct list_head *iter;0910 list_for_each(iter, &bdata_list) {11 bootmem_data_t *ent;1213 ent = list_entry(iter, bootmem_data_t, list);14 if (bdata->node_min_pfn < ent->node_min_pfn)15 break;16 }17 list_add_tail(&bdata->list, iter);18}19static unsigned long __init init_bootmem_core(bootmem_data_t *bdata,20 unsigned long mapstart, unsigned long start, unsigned long end)21{22 unsigned long mapsize;2324 mminit_validate_memmodel_limits(&start, &end);25 bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));26 bdata->node_min_pfn = start;27 bdata->node_low_pfn = end;28 link_bootmem(bdata);2930 /*31 * Initially all pages are reserved - setup_arch() has to32 * register free RAM areas explicitly.33 */34 mapsize = bootmap_bytes(end - start);35 memset(bdata->node_bootmem_map, 0xff, mapsize);3637 bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx\n",38 bdata - bootmem_node_data, start, mapstart, end, mapsize);3940 return mapsize;41}4243
这个函数主要返回要映射的大小,以字节为单位。
第26行开始的页帧号
第34行 计算出映射的长度
第35行,用1来初始化。
第40行返回映射的大小,其实这个是页表的大小16K=4*4*1024.
01void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,02 unsigned long size)03{04 unsigned long start, end;0506 start = PFN_UP(physaddr);07 end = PFN_DOWN(physaddr + size);0809 mark_bootmem_node(pgdat->bdata, start, end, 0, 0);10}11static int __init mark_bootmem_node(bootmem_data_t *bdata,12 unsigned long start, unsigned long end,13 int reserve, int flags)14{15 unsigned long sidx, eidx;1617 bdebug("nid=%td start=%lx end=%lx reserve=%d flags=%x\n",18 bdata - bootmem_node_data, start, end, reserve, flags);1920 BUG_ON(start < bdata->node_min_pfn);21 BUG_ON(end > bdata->node_low_pfn);2223 sidx = start - bdata->node_min_pfn;24 eidx = end - bdata->node_min_pfn;2526 if (reserve)27 return __reserve(bdata, sidx, eidx, flags);28 else29 __free(bdata, sidx, eidx);30 return 0;31}32static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx,33 unsigned long eidx, int flags)34{35 unsigned long idx;36 int exclusive = flags & BOOTMEM_EXCLUSIVE;3738 bdebug("nid=%td start=%lx end=%lx flags=%x\n",39 bdata - bootmem_node_data,40 sidx + bdata->node_min_pfn,41 eidx + bdata->node_min_pfn,42 flags);4344 for (idx = sidx; idx < eidx; idx++)45 if (test_and_set_bit(idx, bdata->node_bootmem_map)) {46 if (exclusive) {47 __free(bdata, sidx, idx);48 return -EBUSY;49 }50 bdebug("silent double reserve of PFN %lx\n",51 idx + bdata->node_min_pfn);52 }53 return 0;54}55
第23行开始的索引号为0x00000000
第24行结束的索引号为0x00004000.
第26行如果是保留这个标识为真,就进行保留,开始分配的内核空间,是需要保留的。
第28-29行如果为假,就进行内存的回收,怎么回收,只需要在位图上相应的位置0,就可以了。
01int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,02 unsigned long size, int flags)03{04 unsigned long start, end;0506 start = PFN_DOWN(physaddr);07 end = PFN_UP(physaddr + size);0809 return mark_bootmem_node(pgdat->bdata, start, end, 1, flags);10}
第6行计算出开始的页帧号。
第7行计算出结束的页帧号。
第9行调用这个函数来标识出哪些空间需要保留。
01static void __init devicemaps_init(struct machine_desc *mdesc)02{03 struct map_desc map;04 unsigned long addr;05 void *vectors;0607 /*08 * Allocate the vector page early.09 */10 vectors = alloc_bootmem_low_pages(PAGE_SIZE);1112 for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)13 pmd_clear(pmd_off_k(addr));1415 /*16 * Map the kernel if it is XIP.17 * It is always first in the modulearea.18 */19#ifdef CONFIG_XIP_KERNEL20 map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK);21 map.virtual = MODULES_VADDR;22 map.length = ((unsigned long)_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK;23 map.type = MT_ROM;24 create_mapping(&map);25#endif2627 /*28 * Map the cache flushing regions.29 */30#ifdef FLUSH_BASE31 map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);32 map.virtual = FLUSH_BASE;33 map.length = SZ_1M;34 map.type = MT_CACHECLEAN;35 create_mapping(&map);36#endif37#ifdef FLUSH_BASE_MINICACHE38 map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M);39 map.virtual = FLUSH_BASE_MINICACHE;40 map.length = SZ_1M;41 map.type = MT_MINICLEAN;42 create_mapping(&map);43#endif4445 /*46 * Create a mapping for the machine vectors at the high-vectors47 * location (0xffff0000). If we aren't using high-vectors, also48 * create a mapping at the low-vectors virtual address.49 */50 map.pfn = __phys_to_pfn(virt_to_phys(vectors));51 map.virtual = 0xffff0000;52 map.length = PAGE_SIZE;53 map.type = MT_HIGH_VECTORS;54 create_mapping(&map);5556 if (!vectors_high()) {57 map.virtual = 0;58 map.type = MT_LOW_VECTORS;59 create_mapping(&map);60 }6162 /*63 * Ask the machine support to map in the statically mapped devices.64 */65 if (mdesc->map_io)66 mdesc->map_io();6768 /*69 * Finally flush the caches and tlb to ensure that we're in a70 * consistent state wrt the writebuffer. This also ensures that71 * any write-allocated cache lines in the vector page are written72 * back. After this point, we can start to touch devices again.73 */74 local_flush_tlb_all();75 flush_cache_all();76}
第10行使用 alloc分配器
对设备的映射,和对内存的映射相似。
01static void __init kmap_init(void)02{03#ifdef CONFIG_HIGHMEM04 pmd_t *pmd = pmd_off_k(PKMAP_BASE);05 pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));06 BUG_ON(!pmd_none(*pmd) || !pte);07 __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE);08 pkmap_page_table = pte + PTRS_PER_PTE;09#endif10}
如果有高端内存,进行永久内核映射
01static void __init02request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)03{04 struct resource *res;05 int i;0607 kernel_code.start = virt_to_phys(_text);08 kernel_code.end = virt_to_phys(_etext - 1);09 kernel_data.start = virt_to_phys(_data);10 kernel_data.end = virt_to_phys(_end - 1);1112 for (i = 0; i < mi->nr_banks; i++) {13 if (mi->bank[i].size == 0)14 continue;1516 res = alloc_bootmem_low(sizeof(*res));17 res->name = "System RAM";18 res->start = mi->bank[i].start;19 res->end = mi->bank[i].start + mi->bank[i].size - 1;20 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;2122 request_resource(&iomem_resource, res);2324 if (kernel_code.start >= res->start &&25 kernel_code.end <= res->end)26 request_resource(res, &kernel_code);27 if (kernel_data.start >= res->start &&28 kernel_data.end <= res->end)29 request_resource(res, &kernel_data);30 }3132 if (mdesc->video_start) {33 video_ram.start = mdesc->video_start;34 video_ram.end = mdesc->video_end;35 request_resource(&iomem_resource, &video_ram);36 }3738 /*39 * Some machines don't have the possibility of ever40 * possessing lp0, lp1 or lp241 */42 if (mdesc->reserve_lp0)43 request_resource(&ioport_resource, &lp0);44 if (mdesc->reserve_lp1)45 request_resource(&ioport_resource, &lp1);46 if (mdesc->reserve_lp2)47 request_resource(&ioport_resource, &lp2);48}
第4行定义一个资源的结构体
第7行kernel的代码段的物理开始地址
第8行kernel的代码段的物理结束地址
第9行kernel的数据段的物理开始地址
第10行kernel的数据段的物理结束地址
第16行使用alloc分配器分配空间
第17-21行对资源进行初始化
第22行调用请求函数,请求资源,这里我的理解是内存映射到映射内存
第24-26行如果满足条件对kernel的代码段映射到内存上物理地址
第27-30行如果满足条件对kernel的数据段映射到内存上物理地址
01void cpu_init(void)02{03 unsigned int cpu = smp_processor_id();04 struct stack *stk = &stacks[cpu];0506 if (cpu >= NR_CPUS) {07 printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);08 BUG();09 }1011 /*12 * setup stacks for re-entrant exception handlers13 */14 __asm__ (15 "msr cpsr_c, %1\n\t"16 "add sp, %0, %2\n\t"17 "msr cpsr_c, %3\n\t"18 "add sp, %0, %4\n\t"19 "msr cpsr_c, %5\n\t"20 "add sp, %0, %6\n\t"21 "msr cpsr_c, %7"22 :23 : "r" (stk),24 "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),25 "I" (offsetof(struct stack, irq[0])),26 "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),27 "I" (offsetof(struct stack, abt[0])),28 "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),29 "I" (offsetof(struct stack, und[0])),30 "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)31 : "r14");32}
主要对CPU的堆栈进行初始化。
01void __init early_trap_init(void)02{03 unsigned long vectors = CONFIG_VECTORS_BASE;04 extern char __stubs_start[], __stubs_end[];05 extern char __vectors_start[], __vectors_end[];06 extern char __kuser_helper_start[], __kuser_helper_end[];07 int kuser_sz = __kuser_helper_end - __kuser_helper_start;0809 /*10 * Copy the vectors, stubs and kuser helpers (in entry-armv.S)11 * into the vector page, mapped at 0xffff0000, and ensure these12 * are visible to the instruction stream.13 */14 memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);15 memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);16 memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);1718 /*19 * Copy signal return handlers into the vector page, and20 * set sigreturn to be a pointer to these.21 */22 memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,23 sizeof(sigreturn_codes));2425 flush_icache_range(vectors, vectors + PAGE_SIZE);26 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);27}
来实现把向量表搬移到0xffff0000这个位置上。通过使用memcpy函数来实现。
- linux 启动之setup_arch函数(二)
- linux 启动之setup_arch函数(一)
- linux内核启动之setup_arch
- 29、(8)Linux内核启动第二阶段之 setup_arch函数分析
- linux内核启动第二阶段之setup_arch()函数分析-2.6.36
- linux内核启动第二阶段之setup_arch()函数分析-2.6.36
- linux内核启动第二阶段之setup_arch()函数分析-2.6.36
- linux内核启动第二阶段之setup_arch()函数分析-2.6.36
- linux内核启动第二阶段之setup_arch()函数分析-2.6.36
- linux内核启动第二阶段分析-setup_arch()函数
- linux内核启动第二阶段分析-setup_arch()函数
- Linux内核启动:setup_arch
- (二)start_kernel分析二---之setup_arch()函数分析
- setup_arch之paging_init函数
- Linux启动中setup_arch分析
- linux 3.6 启动源码分析(三) setup_arch
- linux kernel启动时卡在setup_arch
- linux 3.6 启动源码分析(三) setup_arch
- linux 启动之setup_arch函数(一)
- 下一代互联网服务总线
- 梦想、执行力与新起点
- 永远没有满分
- 如何提升工作中的影响力
- linux 启动之setup_arch函数(二)
- linux 内核的启动构架
- C# Attributes Inheritance (A brief look)
- 线性表的顺序存储结构---顺序表
- C++读取lua脚本
- 74. A straight foot is not afraid of crooked shoe. 身正不怕影子斜
- CRC12 ,16 ,32校验方法
- 2011.10.18陪塞利卡看病。
- 我的最大缺点曝光.....