Machine_desc & boot & Kernel_init & initcall & module_init

跳转到start_kernel中,与本题相关的主要是setup_arch()和rest_init(),其中前者执行的较早,而后者做为start_kernel执行的最后一个函数。

函数start_kernel()和rest_init()定义在kernel/init/main.c中,函数setup_arch()定义在kernel/arch/arch_name/kernel/setup.c中。

1.setup_arch()在.init.text中,会执行machine_desc.init_very_early和machine_desc.init_early,代码如下,

[cpp]  view plain copy
  1. 915void __init setup_arch(char **cmdline_p)  
  2. 916{  
  3. 917 struct machine_desc *mdesc;  
  4. 918  
  5. 919 unwind_init();  
  6. 920  
  7. 921 setup_processor();  
  8. 922 mdesc = setup_machine_fdt(__atags_pointer);  
  9. 923 if (!mdesc)  
  10. 924     mdesc = setup_machine_tags(machine_arch_type);  
  11. 925 machine_desc = mdesc;  
  12. 926 machine_name = mdesc->name;  
  13. 927  
  14. 928 if (mdesc->soft_reboot)  
  15. 929     reboot_setup("s");  
  16. 930  
  17. 931 init_mm.start_code = (unsigned long) _text;  
  18. 932 init_mm.end_code   = (unsigned long) _etext;  
  19. 933 init_mm.end_data   = (unsigned long) _edata;  
  20. 934 init_mm.brk    = (unsigned long) _end;  
  21. 935  
  22. 936 /* populate cmd_line too for later use, preserving boot_command_line */  
  23. 937 strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);  
  24. 938 *cmdline_p = cmd_line;  
  25. 939  
  26. 940 parse_early_param();  
  27. 941  
  28. 942 if (mdesc->init_very_early)  
  29. 943     mdesc->init_very_early();  
  30. 944  
  31. 945 sanity_check_meminfo();  
  32. 946 arm_memblock_init(&meminfo, mdesc);  
  33. 947  
  34. 948 paging_init(mdesc);  
  35. 949 request_standard_resources(mdesc);  
  36. 950  
  37. 951 unflatten_device_tree();  
  38. 952  
  39. 953#ifdef CONFIG_SMP  
  40. 954 if (is_smp())  
  41. 955     smp_init_cpus();  
  42. 956#endif  
  43. 957 reserve_crashkernel();  
  44. 958  
  45. 959 cpu_init();  
  46. 960 tcm_init();  
  47. 961  
  48. 962#ifdef CONFIG_MULTI_IRQ_HANDLER  
  49. 963 handle_arch_irq = mdesc->handle_irq;  
  50. 964#endif  
  51. 965  
  52. 966#ifdef CONFIG_VT  
  53. 967#if defined(CONFIG_VGA_CONSOLE)  
  54. 968 conswitchp = &vga_con;  
  55. 969#elif defined(CONFIG_DUMMY_CONSOLE)  
  56. 970 conswitchp = &dummy_con;  
  57. 971#endif  
  58. 972#endif  
  59. 973 early_trap_init();  
  60. 974  
  61. 975 if (mdesc->init_early)  
  62. 976     mdesc->init_early();  
  63. 977}  

2. rest_init()执行后,创建内核线程kernel_init,这也是内核第一个线程,kernel_init做的与本题相关的初始化是do_pre_smp_initcalls()和do_basic_setup(),然后变成用户态进程init。代码如下,

[cpp]  view plain copy
  1. 841static int __init kernel_init(void * unused)  
  2. 842{  
  3. 843 /* 
  4. 844  * Wait until kthreadd is all set-up. 
  5. 845  */  
  6. 846 wait_for_completion(&kthreadd_done);  
  7. 847 /* 
  8. 848  * init can allocate pages on any node 
  9. 849  */  
  10. 850 set_mems_allowed(node_states[N_HIGH_MEMORY]);  
  11. 851 /* 
  12. 852  * init can run on any cpu. 
  13. 853  */  
  14. 854 set_cpus_allowed_ptr(current, cpu_all_mask);  
  15. 855  
  16. 856 cad_pid = task_pid(current);  
  17. 857  
  18. 858 smp_prepare_cpus(setup_max_cpus);  
  19. 859  
  20. 860 do_pre_smp_initcalls();  
  21. 861 lockup_detector_init();  
  22. 862  
  23. 863 smp_init();  
  24. 864 sched_init_smp();  
  25. 865  
  26. 866 do_basic_setup();  
  27. 867  
  28. 868 /* Open the /dev/console on the rootfs, this should never fail */  
  29. 869 if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)  
  30. 870     printk(KERN_WARNING "Warning: unable to open an initial console.\n");  
  31. 871  
  32. 872 (void) sys_dup(0);  
  33. 873 (void) sys_dup(0);  
  34. 874 /* 
  35. 875  * check if there is an early userspace init.  If yes, let it do all 
  36. 876  * the work 
  37. 877  */  
  38. 878  
  39. 879 if (!ramdisk_execute_command)  
  40. 880     ramdisk_execute_command = "/init";  
  41. 881  
  42. 882 if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {  
  43. 883     ramdisk_execute_command = NULL;  
  44. 884     prepare_namespace();  
  45. 885 }  
  46. 886  
  47. 887 /* 
  48. 888  * Ok, we have completed the initial bootup, and 
  49. 889  * we're essentially up and running. Get rid of the 
  50. 890  * initmem segments and start the user-mode stuff.. 
  51. 891  */  
  52. 892  
  53. 893 init_post();  
  54. 894 return 0;  
  55. 895}  

do_pre_smp_initcalls()做.initcallearly.init section函数的执行,早于.initcall0.init-.initcall7.init;在初始化完smp调度后,.initcalln.init函数在do_basic_setup()被调用

do_pre_smp_initcalls()代码如下,

[cpp]  view plain copy
  1. 786static void __init do_pre_smp_initcalls(void)  
  2. 787{  
  3. 788 initcall_t *fn;  
  4. 789  
  5. 790 for (fn = __initcall_start; fn < __initcall0_start; fn++)  
  6. 791     do_one_initcall(*fn);  
  7. 792}  

do_basic_setup()及调用.initcalln.init的代码如下,

[cpp]  view plain copy
  1. 743static void __init do_initcall_level(int level)  
  2. 744{  
  3. 745 extern const struct kernel_param __start___param[], __stop___param[];  
  4. 746 initcall_t *fn;  
  5. 747  
  6. 748 strcpy(static_command_line, saved_command_line);  
  7. 749 parse_args(initcall_level_names[level],  
  8. 750        static_command_line, __start___param,  
  9. 751        __stop___param - __start___param,  
  10. 752        level, level,  
  11. 753        repair_env_string);  
  12. 754  
  13. 755 for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)  
  14. 756     do_one_initcall(*fn);  
  15. 757}  
  16. 758  
  17. 759static void __init do_initcalls(void)  
  18. 760{  
  19. 761 int level;  
  20. 762  
  21. 763 for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)  
  22. 764     do_initcall_level(level);  
  23. 765}  
  24. 766  
  25. 767/* 
  26. 768 * Ok, the machine is now initialized. None of the devices 
  27. 769 * have been touched yet, but the CPU subsystem is up and 
  28. 770 * running, and memory and process management works. 
  29. 771 * 
  30. 772 * Now we can finally start doing some real work.. 
  31. 773 */  
  32. 774static void __init do_basic_setup(void)  
  33. 775{  
  34. 776 cpuset_init_smp();  
  35. 777 usermodehelper_init();  
  36. 778 shmem_init();  
  37. 779 driver_init();  
  38. 780 init_irq_proc();  
  39. 781 do_ctors();  
  40. 782 usermodehelper_enable();  
  41. 783 do_initcalls();  
  42. 784}  

各.initcalln.init的宏定义如下

[cpp]  view plain copy
  1. 168/* initcalls are now grouped by functionality into separate 
  2. 169 * subsections. Ordering inside the subsections is determined 
  3. 170 * by link order. 
  4. 171 * For backwards compatibility, initcall() puts the call in 
  5. 172 * the device init subsection. 
  6. 173 * 
  7. 174 * The `id' arg to __define_initcall() is needed so that multiple initcalls 
  8. 175 * can point at the same handler without causing duplicate-symbol build errors. 
  9. 176 */  
  10. 177  
  11. 178#define __define_initcall(level,fn,id) \  
  12. 179 static initcall_t __initcall_##fn##id __used \  
  13. 180 __attribute__((__section__(".initcall" level ".init"))) = fn  
  14. 181  
  15. 182/* 
  16. 183 * Early initcalls run before initializing SMP. 
  17. 184 * 
  18. 185 * Only for built-in code, not modules. 
  19. 186 */  
  20. 187#define early_initcall(fn)       __define_initcall("early",fn,early)  
  21. 188  
  22. 189/* 
  23. 190 * A "pure" initcall has no dependencies on anything else, and purely 
  24. 191 * initializes variables that couldn't be statically initialized. 
  25. 192 * 
  26. 193 * This only exists for built-in code, not for modules. 
  27. 194 */  
  28. 195#define pure_initcall(fn)        __define_initcall("0",fn,0)  
  29. 196  
  30. 197#define core_initcall(fn)        __define_initcall("1",fn,1)  
  31. 198#define core_initcall_sync(fn)       __define_initcall("1s",fn,1s)  
  32. 199#define postcore_initcall(fn)        __define_initcall("2",fn,2)  
  33. 200#define postcore_initcall_sync(fn)   __define_initcall("2s",fn,2s)  
  34. 201#define arch_initcall(fn)        __define_initcall("3",fn,3)  
  35. 202#define arch_initcall_sync(fn)       __define_initcall("3s",fn,3s)  
  36. 203#define subsys_initcall(fn)      __define_initcall("4",fn,4)  
  37. 204#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)  
  38. 205#define fs_initcall(fn)          __define_initcall("5",fn,5)  
  39. 206#define fs_initcall_sync(fn)     __define_initcall("5s",fn,5s)  
  40. 207#define rootfs_initcall(fn)      __define_initcall("rootfs",fn,rootfs)  
  41. 208#define device_initcall(fn)      __define_initcall("6",fn,6)  
  42. 209#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)  
  43. 210#define late_initcall(fn)        __define_initcall("7",fn,7)  
  44. 211#define late_initcall_sync(fn)       __define_initcall("7s",fn,7s)  
  45. 212  
  46. 213#define __initcall(fn) device_initcall(fn)  
  47. 214  
  48. 215#define __exitcall(fn) \  
  49. 216 static exitcall_t __exitcall_##fn __exit_call = fn  
  50. 217  
  51. 218#define console_initcall(fn) \  
  52. 219 static initcall_t __initcall_##fn \  
  53. 220 __used __section(.con_initcall.init) = fn  
  54. 221  
  55. 222#define security_initcall(fn) \  
  56. 223 static initcall_t __initcall_##fn \  
  57. 224 __used __section(.security_initcall.init) = fn  

machine_desc.init_machine在customize_machine() @ kernel/arch/arm/kernel/setup.c中被调用,而customize_machine指针引用在.initcall3.init中。customize_machine()代码如下,

[cpp]  view plain copy
  1. 842static int __init customize_machine(void)  
  2. 843{  
  3. 844 /* customizes platform devices, or adds new ones */  
  4. 845 if (machine_desc->init_machine)  
  5. 846     machine_desc->init_machine();  
  6. 847 return 0;  
  7. 848}  
  8. 849arch_initcall(customize_machine);  

各module_init(fn)设备驱动在.initcall6.init中被调用,由以下module_init的宏定义可以看出,

[cpp]  view plain copy
  1. 259/** 
  2. 260 * module_init() - driver initialization entry point 
  3. 261 * @x: function to be run at kernel boot time or module insertion 
  4. 262 * 
  5. 263 * module_init() will either be called during do_initcalls() (if 
  6. 264 * builtin) or at module insertion time (if a module).  There can only 
  7. 265 * be one per module. 
  8. 266 */  
  9. 267#define module_init(x)   __initcall(x);  

而__initcall(x)宏定义为

[cpp]  view plain copy
  1. 213#define __initcall(fn) device_initcall(fn)  

综上,题中提及各初始化的顺序是machine_desc.init_very_early, machine_desc.init_early, .initcallearly.init, machine_desc.init_machine(.initcall3.init), module_init(.initcall6.init) 。

[End]

[参考文章]

http://blog.csdn.net/paomadi/article/details/8611408

一、定义

[cpp]  view plain copy
  1. #define MACHINE_START(_type,_name)          \   //板类型,板名字  
  2. static const struct machine_desc __mach_desc_##_type    \  
  3.  __used                     \  
  4.  __attribute__((__section__(".arch.info.init"))) = {    \  
  5.     .nr     = MACH_TYPE_##_type,    \  
  6.     .name       = _name,  
  7.   
  8. #define MACHINE_END             \  
  9. };  

MACHINE_START和MACHINE_END框起了一个machine_desc结构体的声明并根据MACHINE_START宏的参数初始化其.nr和.name成员

并将该结构体标记编译到.arch.info.init段

在MACHINE_START和MACHINE_END宏之间可以初始化machine_desc结构体的剩余成员

machine_desc结构体的定义

[cpp]  view plain copy
  1. struct machine_desc {  
  2.     unsigned int    nr;     /* architecture number 编号   */  
  3.     const char  *name;      /* architecture name 名字 */  
  4.     unsigned long   boot_params;    /* tagged list      */  
  5.     unsigned int    nr_irqs;        /* number of IRQs 中断数   */  
  6.     unsigned int    video_start;    /* start of video RAM   */  
  7.     unsigned int    video_end;  /* end of video RAM */  
  8.     unsigned int    reserve_lp0 :1; /* never has lp0    */  
  9.     unsigned int    reserve_lp1 :1; /* never has lp1    */  
  10.     unsigned int    reserve_lp2 :1; /* never has lp2    */  
  11.     unsigned int    soft_reboot :1; /* soft reboot      */  
  12.     void    (*fixup)(struct machine_desc *,struct tag *, char **,struct meminfo *);  
  13.     void    (*reserve)(void);       /* reserve mem blocks   */  
  14.     void    (*map_io)(void);        /* IO mapping function io映射函数 */  
  15.     void    (*init_irq)(void);      /* 中断初始化函数 */  
  16.     struct sys_timer    *timer;     /* system tick timer 滴答定时器 */  
  17.     void    (*init_machine)(void);  /* 初始化函数 */  
  18. };  

使用例子:

[cpp]  view plain copy
  1. MACHINE_START(SMDKC110, "SMDKC110")  
  2.     /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */  
  3.     .boot_params    = S5P_PA_SDRAM + 0x100,  
  4.     .init_irq   = s5pv210_init_irq,  
  5.     .map_io     = smdkc110_map_io,  
  6.     .init_machine   = smdkc110_machine_init,  
  7.     .timer      = &s3c24xx_timer,  
  8. MACHINE_END  

这里smdkc110_machine_init就是对应的板级初始化函数,s5pv210_init_irq就是板级中断初始化函数,smdkc110_map_io就是板级io初始化函数...
二、调用关系

MACHINE_START宏将machine_desc标记编译到.arch.info.init段, 而/arch/arm/kernel/vmlinux.lds中

[cpp]  view plain copy
  1. __arch_info_begin = .;  
  2.  *(.arch.info.init)  
  3. __arch_info_end = .;  

 当系统启动时在linux启动函数start_kernel中调用了setup_arch(&command_line);

[cpp]  view plain copy
  1. void __init setup_arch(char **cmdline_p)  
  2. {  
  3.     struct tag *tags = (struct tag *)&init_tags;  
  4.     struct machine_desc *mdesc; //声明了一个machine_desc结构体指针  
  5.     char *from = default_command_line;  
  6.   
  7.     init_tags.mem.start = PHYS_OFFSET;  
  8.   
  9.     unwind_init();  
  10.   
  11.     setup_processor();  
  12.     mdesc = setup_machine(machine_arch_type);   //0根据machine_arch_type获取machine_desc  
  13.     machine_name = mdesc->name;  //设置名字  
  14.   
  15.     if (mdesc->soft_reboot)  //需要软重启?  
  16.         reboot_setup("s");  
  17.   
  18.     if (__atags_pointer)  
  19.         tags = phys_to_virt(__atags_pointer);  
  20.     else if (mdesc->boot_params) {   //处理启动参数  
  21. #ifdef CONFIG_MMU  
  22.         if (mdesc->boot_params < PHYS_OFFSET ||  
  23.             mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {  
  24.             printk(KERN_WARNING"Default boot params at physical 0x%08lx out of reach\n",mdesc->boot_params);  
  25.         } else  
  26. #endif  
  27.         {  
  28.             tags = phys_to_virt(mdesc->boot_params);  
  29.         }  
  30.     }  
  31.   
  32. #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)  
  33.     if (tags->hdr.tag != ATAG_CORE)  
  34.         convert_to_tag_list(tags);  
  35. #endif  
  36.     if (tags->hdr.tag != ATAG_CORE)  
  37.         tags = (struct tag *)&init_tags;  
  38.   
  39.     if (mdesc->fixup)    //若存在fixup方法则调用其方法  
  40.         mdesc->fixup(mdesc, tags, &from, &meminfo);  
  41.   
  42.     if (tags->hdr.tag == ATAG_CORE) {  
  43.         if (meminfo.nr_banks != 0)  
  44.             squash_mem_tags(tags);  
  45.         save_atags(tags);  
  46.         parse_tags(tags);  
  47.     }  
  48.   
  49.     init_mm.start_code = (unsigned long) _text;  
  50.     init_mm.end_code   = (unsigned long) _etext;  
  51.     init_mm.end_data   = (unsigned long) _edata;  
  52.     init_mm.brk    = (unsigned long) _end;  
  53.   
  54.     /* parse_early_param needs a boot_command_line */  
  55.     strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);  
  56.   
  57.     /* populate cmd_line too for later use, preserving boot_command_line */  
  58.     strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);  
  59.     *cmdline_p = cmd_line;  
  60.   
  61.     parse_early_param();  
  62.   
  63.     arm_memblock_init(&meminfo, mdesc); //这里可能会调用reserve方法  
  64.   
  65.     paging_init(mdesc); //->devicemaps_init(mdesc)->map_io方法  
  66.     request_standard_resources(&meminfo, mdesc);    //这里可能会调用video_start方法  
  67.   
  68. #ifdef CONFIG_SMP  
  69.     if (is_smp())  
  70.         smp_init_cpus();  
  71. #endif  
  72.     reserve_crashkernel();  
  73.     cpu_init();  
  74.     tcm_init();  
  75.   
  76.     arch_nr_irqs = mdesc->nr_irqs;   //1设置全局变量 中断个数  
  77.     init_arch_irq = mdesc->init_irq; //2设置全局变量 中断初始化函数  
  78.     system_timer = mdesc->timer; //3设置全局变量 sys_timer结构体  
  79.     init_machine = mdesc->init_machine;  //4设置全局变量 板级初始化函数  
  80.   
  81. #ifdef CONFIG_VT  
  82. #if defined(CONFIG_VGA_CONSOLE)  
  83.     conswitchp = &vga_con;  
  84. #elif defined(CONFIG_DUMMY_CONSOLE)  
  85.     conswitchp = &dummy_con;  
  86. #endif  
  87. #endif  
  88.     early_trap_init();  
  89. }  

 0. 结构machine_desc安装

[cpp]  view plain copy
  1. static struct machine_desc * __init setup_machine(unsigned int nr)  
  2. {  
  3.     extern struct machine_desc __arch_info_begin[], __arch_info_end[];  
  4.     struct machine_desc *p;  
  5.   
  6.     for (p = __arch_info_begin; p < __arch_info_end; p++)//遍历__arch_info_begin和__arch_info_end之间的machine_desc结构体  
  7.         if (nr == p->nr) {   //找到对应的板  
  8.             printk("Machine: %s\n", p->name);//打印板级信息  
  9.             return p;  
  10.         }  
  11.   
  12.     early_print("\n"  
  13.         "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"  
  14.         "Available machine support:\n\nID (hex)\tNAME\n", nr);  
  15.   
  16.     for (p = __arch_info_begin; p < __arch_info_end; p++)  
  17.         early_print("%08x\t%s\n", p->nr, p->name);  
  18.   
  19.     early_print("\nPlease check your kernel config and/or bootloader.\n");  
  20.   
  21.     while (true)  
  22.         /* can't use cpu_relax() here as it may require MMU setup */;  
  23. }  

1.中断个数

start_kernel->early_irq_init->arch_probe_nr_irqs函数中nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS;设置全局nr_irqs变量
2.中断初始化函数

start_kernel->init_IRQ->init_arch_irq()

3.sys_timer结构体

start_kernel->time_init()调用system_timer->init()方法既sys_timer->init()

4.板级初始化函数

[cpp]  view plain copy
  1. static void (*init_machine)(void) __initdata;  
  2.   
  3. static int __init customize_machine(void)  
  4. {  
  5.     /* customizes platform devices, or adds new ones */  
  6.     if (init_machine)//全局函数init_machine存在  
  7.         init_machine();//则调用,既mdesc->init_machine()  
  8.     return 0;  
  9. }  
  10. arch_initcall(customize_machine);//用arch_initcall修饰customize_machine函数  

arch_iniitcall函数在/include/linux/init.h中定义

[cpp]  view plain copy
  1. #define arch_initcall(fn)       __define_initcall("3",fn,3)  

__define_initcall的定义

[cpp]  view plain copy
  1. #define __define_initcall(level,fn,id) \  
  2.     static initcall_t __initcall_##fn##id __used \  
  3.     __attribute__((__section__(".initcall" level ".init"))) = fn  


展开就是static initcall_t __initcall_customize_machine3 __used __attribute__((__section__(".initcall3.init")))=customize_machine

在vmlinux.lds中

[cpp]  view plain copy
  1. __initcall_start = .;   
  2. *(.initcallearly.init)   
  3. __early_initcall_end = .;   
  4. *(.initcall0.init)   
  5. *(.initcall0s.init)   
  6. *(.initcall1.init)   
  7. *(.initcall1s.init)   
  8. *(.initcall2.init)   
  9. *(.initcall2s.init)   
  10. *(.initcall3.init)   
  11. *(.initcall3s.init)   
  12. *(.initcall4.init)   
  13. *(.initcall4s.init)   
  14. *(.initcall5.init)   
  15. *(.initcall5s.init)   
  16. *(.initcallrootfs.init)   
  17. *(.initcall6.init)   
  18. *(.initcall6s.init)   
  19. *(.initcall7.init)   
  20. *(.initcall7s.init)   
  21. __initcall_end = .;  


标注为.initcall3.init的函数编译进__initcall_start和__initcall_end框起的section中

而在系统启动的时候start_kernel->rest_init()->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);创建了kernel线程

kernel_init->do_pre_smp_initcalls()

[cpp]  view plain copy
  1. static void __init do_pre_smp_initcalls(void)  
  2. {  
  3.     initcall_t *fn;  
  4.   
  5.     for (fn = __initcall_start; fn < __early_initcall_end; fn++)  
  6.         do_one_initcall(*fn);  
  7. }  


该函数遍历__initcall_start和__early_initcall_end中的函数,并调用do_one_initcall

[cpp]  view plain copy
  1. int __init_or_module do_one_initcall(initcall_t fn)  
  2. {  
  3.     int count = preempt_count();  
  4.     int ret;  
  5.   
  6.     if (initcall_debug)  
  7.         ret = do_one_initcall_debug(fn);  
  8.     else  
  9.         ret = fn();//执行了fn函数也就是customize_machine  
  10.   
  11.     msgbuf[0] = 0;  
  12.   
  13.     if (ret && ret != -ENODEV && initcall_debug)  
  14.         sprintf(msgbuf, "error code %d ", ret);  
  15.   
  16.     if (preempt_count() != count) {  
  17.         strlcat(msgbuf, "preemption imbalance "sizeof(msgbuf));  
  18.         preempt_count() = count;  
  19.     }  
  20.     if (irqs_disabled()) {  
  21.         strlcat(msgbuf, "disabled interrupts "sizeof(msgbuf));  
  22.         local_irq_enable();  
  23.     }  
  24.     if (msgbuf[0]) {  
  25.         printk("initcall %pF returned with %s\n", fn, msgbuf);  
  26.     }  
  27.   
  28.     return ret;  
  29. }  


http://blog.csdn.net/cxw3506/article/details/8475965

Machine定义以MACHINE_START开始并以MACHINE_END结束,如下mini2440开发板的移植为示例

[cpp]  view plain copy
  1. MACHINE_START(MINI2440, "MINI2440")  
  2.     .phys_io    = S3C2410_PA_UART,  
  3.     .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,  
  4.     .boot_params    = S3C2410_SDRAM_PA + 0x100,  
  5.     .map_io     = mini2440_map_io,  
  6.     .init_machine   = mini2440_init,  
  7.     .init_irq   = s3c24xx_init_irq,  
  8.     .timer      = &s3c24xx_timer,  
  9. MACHINE_END  

MACHINE_START、MACHINE_END都是定义的宏,代码如下

[cpp]  view plain copy
  1. <span style="font-size:12px;">/* 
  2.  * Set of macros to define architecture features.  This is built into 
  3.  * a table by the linker. 
  4.  */  
  5. #define MACHINE_START(_type,_name)          \  
  6. static const struct machine_desc __mach_desc_##_type    \  
  7.  __used                         \  
  8.  __attribute__((__section__(".arch.info.init"))) = {    \  
  9.     .nr     = MACH_TYPE_##_type,        \  
  10.     .name       = _name,  
  11.   
  12. #define MACHINE_END             \  
  13. };</span>  

这两个宏一起定义了一个类型为struct machine_desc的变量,结构体定义如下

[cpp]  view plain copy
  1. <span style="font-size:12px;">struct machine_desc {  
  2.     /* 
  3.      * Note! The first four elements are used 
  4.      * by assembler code in head.S, head-common.S 
  5.      */  
  6.     unsigned int        nr;     /* architecture number  */  
  7.     unsigned int        phys_io;    /* start of physical io */  
  8.     unsigned int        io_pg_offst;    /* byte offset for io  
  9.                          * page tabe entry  */  
  10.   
  11.     const char      *name;      /* architecture name    */  
  12.     unsigned long       boot_params;    /* tagged list      */  
  13.   
  14.     unsigned int        video_start;    /* start of video RAM   */  
  15.     unsigned int        video_end;  /* end of video RAM */  
  16.   
  17.     unsigned int        reserve_lp0 :1; /* never has lp0    */  
  18.     unsigned int        reserve_lp1 :1; /* never has lp1    */  
  19.     unsigned int        reserve_lp2 :1; /* never has lp2    */  
  20.     unsigned int        soft_reboot :1; /* soft reboot      */  
  21.     void            (*fixup)(struct machine_desc *,  
  22.                      struct tag *, char **,  
  23.                      struct meminfo *);  
  24.     void            (*map_io)(void);/* IO mapping function  */  
  25.     void            (*init_irq)(void);  
  26.     struct sys_timer    *timer;     /* system tick timer    */  
  27.     void            (*init_machine)(void);  
  28. };</span>  

这个类型的变量放在内核代码段.arch.info.init中,在内核运行初期,被函数lookup_machine_type(此函数用汇编实现,在汇编文件中)取出,读取流程为

Start_kernel() -> setup_arch() -> setup_machine() -> lookup_machine_type()

在函数setup_machine()中,利用这个结构体类型的变量初始化一些全局变量,以备内核运行时使用,比如

       init_arch_irq = mdesc->init_irq;

       system_timer = mdesc->timer;

       init_machine = mdesc->init_machine;

这个结构体中,成员init_machine保存的是开发板资源注册的初始化代码,init_irq保存的是中断初始化指针,timer保存的是一个struct sys_timer类型的指针…..如果我们要给自己的开发板定制内核,那么我们必须自己实现以上成员函数,其中函数init_machine()是我们向内核传递开发板设备信息的重要的常规途径,分析mini2440开发板内核移植代码知道,在这个函数中,注册了开发板所用到的所有设备的相关硬件信息!

[cpp]  view plain copy
  1. static void __init mini2440_init(void)  
  2. {  
  3.     struct mini2440_features_t features = { 0 };  
  4.     int i;  
  5.   
  6.     printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",  
  7.             mini2440_features_str);  
  8.   
  9.     /* Parse the feature string */  
  10.     mini2440_parse_features(&features, mini2440_features_str);  
  11.   
  12.     /* turn LCD on */  
  13.     s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);  
  14.   
  15.     /* Turn the backlight early on */  
  16.     WARN_ON(gpio_request(S3C2410_GPG(4), "backlight"));  
  17.     gpio_direction_output(S3C2410_GPG(4), 1);  
  18.   
  19.     /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */  
  20.     s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);  
  21.     s3c2410_gpio_setpin(S3C2410_GPB(1), 0);  
  22.     s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);  
  23.   
  24.     /* Make sure the D+ pullup pin is output */  
  25.     WARN_ON(gpio_request(S3C2410_GPC(5), "udc pup"));  
  26.     gpio_direction_output(S3C2410_GPC(5), 0);  
  27.   
  28.     /* mark the key as input, without pullups (there is one on the board) */  
  29.     for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {  
  30.         s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);  
  31.         s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);  
  32.     }  
  33.     if (features.lcd_index != -1) {  
  34.         int li;  
  35.   
  36.         mini2440_fb_info.displays =  
  37.             &mini2440_lcd_cfg[features.lcd_index];  
  38.   
  39.         printk(KERN_INFO "MINI2440: LCD");  
  40.         for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)  
  41.             if (li == features.lcd_index)  
  42.                 printk(" [%d:%dx%d]", li,  
  43.                     mini2440_lcd_cfg[li].width,  
  44.                     mini2440_lcd_cfg[li].height);  
  45.             else  
  46.                 printk(" %d:%dx%d", li,  
  47.                     mini2440_lcd_cfg[li].width,  
  48.                     mini2440_lcd_cfg[li].height);  
  49.         printk("\n");  
  50.         s3c24xx_fb_set_platdata(&mini2440_fb_info);  
  51.     }  
  52.   
  53.     s3c24xx_udc_set_platdata(&mini2440_udc_cfg);  
  54.     s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);  
  55.     s3c_nand_set_platdata(&mini2440_nand_info);  
  56.     s3c_i2c0_set_platdata(NULL);  
  57.   
  58.     i2c_register_board_info(0, mini2440_i2c_devs,  
  59.                 ARRAY_SIZE(mini2440_i2c_devs));  
  60.   
  61.     platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));  
  62.   
  63.     if (features.count) /* the optional features */  
  64.         platform_add_devices(features.optional, features.count);  
  65.   
  66. }  

那么成员函数init_machine什么时候被调用呢?

在函数setup_machine()中有一条语句init_machine = mdesc->init_machine;其中init_machine为全局函数指针变量,此变量在函数customize_machine()中被调用,代码如下所示:

[cpp]  view plain copy
  1. static int __init customize_machine(void)  
  2.   
  3. {  
  4.   
  5.        /* customizes platform devices, or adds new ones */  
  6.   
  7.        if (init_machine)  
  8.   
  9.               init_machine();  
  10.   
  11.        return 0;  
  12.   
  13. }  
  14.   
  15. arch_initcall(customize_machine);  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值