2010年9月14日 星期二

setup_arch函数部分代碼分析

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/60314/showart_473186.html

1、//在分析setup_processor()函数之前,先看一下在proc-arm920.S中__arm920_proc_info的定义:
/*.section ".proc.info", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long 0x00000c1e   @ mmuflags
b __arm920_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
.long cpu_arm920_info
.long arm920_processor_functions
.size __arm920_proc_info, . - __arm920_proc_info

其中几个变量的定义:
arm920_processor_functions:
.word cpu_arm920_data_abort
.word cpu_arm920_check_bugs
.word cpu_arm920_proc_init
.word cpu_arm920_proc_fin
.word cpu_arm920_reset
.word   cpu_arm920_do_idle

/* cache */
.word cpu_arm920_cache_clean_invalidate_all
.word cpu_arm920_cache_clean_invalidate_range
.word cpu_arm920_flush_ram_page

/* dcache */
.word cpu_arm920_dcache_invalidate_range
.word cpu_arm920_dcache_clean_range
.word cpu_arm920_dcache_clean_page
.word cpu_arm920_dcache_clean_entry

/* icache */
.word cpu_arm920_icache_invalidate_range
.word cpu_arm920_icache_invalidate_page

/* tlb */
.word cpu_arm920_tlb_invalidate_all
.word cpu_arm920_tlb_invalidate_range
.word cpu_arm920_tlb_invalidate_page

/* pgtable */
.word cpu_arm920_set_pgd
.word cpu_arm920_set_pmd
.word cpu_arm920_set_pte
.size arm920_processor_functions, . - arm920_processor_functions

.type cpu_arm920_info, #object
cpu_manu_name:
.asciz "ARM/CIRRUS"
ENTRY(cpu_arm920_name)
.ascii "Arm920T"
#if defined(CONFIG_CPU_ARM920_CPU_IDLE)
.ascii "s"
#endif
#if defined(CONFIG_CPU_ARM920_I_CACHE_ON)
.ascii "i"
#endif
#if defined(CONFIG_CPU_ARM920_D_CACHE_ON)
.ascii "d"
#if defined(CONFIG_CPU_ARM920_WRITETHROUGH)
.ascii "(wt)"
#else
.ascii "(wb)"
#endif
#endif
.ascii "\0"
.align

.type cpu_arm920_info, #object
cpu_arm920_info:
.long cpu_manu_name
.long cpu_arm920_name
.size cpu_arm920_info, . - cpu_arm920_info

.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv4"
.size cpu_arch_name, . - cpu_arch_name

.type cpu_elf_name, #object
cpu_elf_name:
.asciz "v4"
.size cpu_elf_name, . - cpu_elf_name
.align*/

static void __init setup_processor(void)
{
//原始定义在include/linux/init.h
#define __init          __attribute__ ((__section__ (".init.text")))
    extern struct proc_info_list __proc_info_begin, __proc_info_end;
    struct proc_info_list *list;
    /*
     * locate processor in the list of supported processor
     * types.  The linker builds this table for us from the
     * entries in arch/arm/mm/proc-*.S
     */
    for (list = &__proc_info_begin; list cpu_mask) == list->cpu_val)
            break;
    /*注意学习:list指针与汇编中初始化的结构体结合起来的精妙*/
    /*
     * If processor type is unrecognised, then we
     * can do nothing...
     */
    if (list >= &__proc_info_end) {
        printk("CPU configuration botched (ID %08x), unable "
               "to continue.\n", processor_id);
        while (1);
    }
    proc_info = *list->info;
//需要判断宏MULTI_CPU是否有定义,判断过程如下:在文件proc-fns.h中,可以看到
/*#include
/*
* Work out if we need multiple CPU support
*/
#undef MULTI_CPU
#undef CPU_NAME

#ifdef CONFIG_CPU_32
# define CPU_INCLUDE_NAME "asm/cpu-multi32.h"
# ifdef CONFIG_CPU_ARM920T
#  ifdef CPU_NAME
#   undef  MULTI_CPU
#   define MULTI_CPU
#  else
#   define CPU_NAME arm920
#  endif
# endif
#endif

#ifndef MULTI_CPU
#undef CPU_INCLUDE_NAME
#define CPU_INCLUDE_NAME "asm/cpu-single.h"
#endif

#include CPU_INCLUDE_NAME
#endif */
#ifdef MULTI_CPU
    processor = *list->proc;
#endif
    printk("Processor: %s %s revision %d\n",
           proc_info.manufacturer, proc_info.cpu_name,
           (int)processor_id & 15);
/*
static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)

该宏用来判断处理器的大小端模式,注意体会这段代码。另外,从head-armv.S的分析,我们知道现在是小端模式。*/
    sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
    sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
    elf_hwcap = list->elf_hwcap;
//elf_hwcap = HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
    cpu_proc_init();
//该函数定义在asm/cpu-single.h中
#ifdef __STDC__
#define __cpu_fn(name,x) cpu_##name##x
#else
#define __cpu_fn(name,x) cpu_/**/name/**/x
#endif
#define cpu_fn(name,x)  __cpu_fn(name,x)

#define cpu_proc_init   cpu_fn(CPU_NAME,_proc_init) 
因此该函数调用cpu_arm920_proc_init,在文件proc-arm920.S中
/*
* cpu_arm920_proc_init()
*/
ENTRY(cpu_arm920_proc_init)
mov pc, lr

*/
}
2、//在分析setup_architecture()函数之前,先看一下几个结构
/*struct machine_desc {
/*
  * Note! The first four elements are used
  * by assembler code in head-armv.S
  */
unsigned int  nr;  /* architecture number */
unsigned int  phys_ram; /* start of physical ram */
unsigned int  phys_io; /* start of physical io */
unsigned int  io_pg_offst; /* byte offset for io
       * page tabe entry */

const char  *name;  /* architecture name */
unsigned int  param_offset; /* parameter page */

unsigned int  video_start; /* start of video RAM */
unsigned int  video_end; /* end of video RAM */

unsigned int  reserve_lp0 :1; /* never has lp0 */
unsigned int  reserve_lp1 :1; /* never has lp1 */
unsigned int  reserve_lp2 :1; /* never has lp2 */
unsigned int  soft_reboot :1; /* soft reboot  */
void   (*fixup)(struct machine_desc *,
      struct param_struct *, char **,
      struct meminfo *);
void   (*map_io)(void);/* IO mapping function */
void   (*init_irq)(void);
};

/*
* Set of macros to define architecture features.  This is built into
* a table by the linker.
*/
#define MACHINE_START(_type,_name)  \
const struct machine_desc __mach_desc_##_type \
__attribute__((__section__(".arch.info"))) = { \
nr:  MACH_TYPE_##_type, \
name:  _name,

#define MAINTAINER(n)
#define BOOT_MEM(_pram,_pio,_vio)  \
phys_ram: _pram,                 \
phys_io: _pio,                   \
io_pg_offst: ((_vio)>>18)&0xfffc,

#define BOOT_PARAMS(_params)   \
param_offset: _params,

#define VIDEO(_start,_end)   \
video_start: _start,   \
video_end: _end,

#define DISABLE_PARPORT(_n)   \
reserve_lp##_n: 1,

#define BROKEN_HLT /* unused */
#define SOFT_REBOOT    \
soft_reboot: 1,

#define FIXUP(_func)    \
fixup:  _func,

#define MAPIO(_func)    \
map_io:  _func,

#define INITIRQ(_func)    \
init_irq: _func,

#define MACHINE_END    \
};

MACHINE_START(MX1ADS, "Motorola MX1ADS")
MAINTAINER("WBSG SPS Motorola")
#ifdef CONFIG_ARCH_MX1ADS_SRAM
BOOT_MEM(0x12000000, 0x00200000, 0xf0200000)
#else
BOOT_MEM(0x08000000, 0x00200000, 0xf0200000)
#endif
FIXUP(mx1ads_fixup)
MAPIO(mx1ads_map_io)
INITIRQ(mx1ads_init_irq)
MACHINE_END*/

static struct machine_desc * __init setup_architecture(unsigned int nr)
{
extern struct machine_desc __arch_info_begin, __arch_info_end;
struct machine_desc *list;
/*
  * locate architecture in the list of supported architectures.
  */
for (list = &__arch_info_begin; list nr == nr)
   break;
/*
  * If the architecture type is not recognised, then we
  * can co nothing...
  */
if (list >= &__arch_info_end) {
  printk("Architecture configuration botched (nr %d), unable "
         "to continue.\n", nr);
  while (1);
}
printk("Architecture: %s\n", list->name);
if (compat)
  printk(KERN_WARNING "Using compatibility code "
   "scheduled for removal in v%d.%d.%d\n",
   compat >> 24, (compat >> 12) & 0x3ff,
   compat & 0x3ff);
return list;
//返回指向machine_desc结构体的指针
}
3、bootmem_init函数在内核结尾(按页对齐)分一页出来作位图,根据具体系统的内存大小,以页 (4k)为单位映射整个可用内存,同时保留内核代码(.text【0x08008000】--.end),一级页表 (0x08004000--0x08008000)和位图所占用的页
/*
* Initialise the bootmem allocator for all nodes.  This is called
* early during the architecture specific initialisation.
*/
void __init bootmem_init(struct meminfo *mi)
{
struct node_info node_info[NR_NODES], *np = node_info;
unsigned int bootmap_pages, bootmap_pfn, map_pg;
int node, initrd_node;
bootmap_pages = find_memend_and_nodes(mi, np);
bootmap_pfn   = find_bootmap_pfn(0, mi, bootmap_pages);
initrd_node   = check_initrd(mi);
map_pg = bootmap_pfn;
/*
  * Initialise the bootmem nodes.
  *
  * What we really want to do is:
  *
  *   unmap_all_regions_except_kernel();
  *   for_each_node_in_reverse_order(node) {
  *     map_node(node);
  *     allocate_bootmem_map(node);
  *     init_bootmem_node(node);
  *     free_bootmem_node(node);
  *   }
  *
  * but this is a 2.5-type change.  For now, we just set
  * the nodes up in reverse order.
  *
  * (we could also do with rolling bootmem_init and paging_init
  * into one generic "memory_init" type function).
  */
np += numnodes - 1;
for (node = numnodes - 1; node >= 0; node--, np--) {
  /*
   * If there are no pages in this node, ignore it.
   * Note that node 0 must always have some pages.
   */
  if (np->end == 0) {
   if (node == 0)
    BUG();
   continue;
  }
  /*
   * Initialise the bootmem allocator.
   */
  init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);
  free_bootmem_node_bank(node, mi);
  map_pg += np->bootmap_pages;
  /*
   * If this is node 0, we need to reserve some areas ASAP -
   * we may use bootmem on node 0 to setup the other nodes.
   */
  if (node == 0)
   reserve_node_zero(bootmap_pfn, bootmap_pages);
}
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_node >= 0)
  reserve_bootmem_node(NODE_DATA(initrd_node), __pa(initrd_start),
         initrd_end - initrd_start);
#endif
if (map_pg != bootmap_pfn + bootmap_pages)
  BUG();
}

沒有留言:

張貼留言