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函数来实现。


                                                   

原创粉丝点击