<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程二

          淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程二

          作者: 時(shí)間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
          4.1. 處理器、設(shè)備4.2. 描述
          設(shè)備描述主要兩個(gè)結(jié)構(gòu)體完成:structresource和structplatform_device。
          先來看看著兩個(gè)結(jié)構(gòu)體的定義:
          structresource{
          resource_size_tstart;
          resource_size_tend;
          constchar*name;
          unsignedlongflags;
          structresource*parent,*sibling,*child;
          };
          Resource結(jié)構(gòu)體主要是描述了設(shè)備在系統(tǒng)中的起止地址、名稱、標(biāo)志以及為了鏈?zhǔn)矫枋龇奖阒赶虮窘Y(jié)構(gòu)體類型的指針。Resource定義的實(shí)例將被添加到platform_device結(jié)構(gòu)體對象中去。
          structplatform_device{
          constchar *name;
          u32 id;
          structdevice dev;
          u32 num_resources;
          structresource *resource;
          };
          Platform_device結(jié)構(gòu)體包括結(jié)構(gòu)體的名稱、ID號(hào)、平臺(tái)相關(guān)的信息、設(shè)備的數(shù)目以及上面定義的resource信息。Platform_device結(jié)構(gòu)對象將被直接通過設(shè)備操作函數(shù)注冊導(dǎo)系統(tǒng)中去。具體注冊和注銷過程在下一節(jié)介紹。
          4.3. 處理器、設(shè)備4.4. 操作
          (1)intplatform_device_register(structplatform_device*pdev);注冊設(shè)備
          (2)voidplatform_device_unregister(structplatform_device*pdev);注銷設(shè)備
          (3)intplatform_add_devices(structplatform_device**devs,intnum);添加設(shè)備,通過調(diào)用上面兩個(gè)函數(shù)實(shí)現(xiàn)。
          4.5. 添加Nandflash設(shè)備4.6.
          下面以nandflash設(shè)備的描述為例,具體介紹下設(shè)備的描述和注冊過程。
          //resource結(jié)構(gòu)體實(shí)例s3c_nand_resource對nandflash控制器描述,包括控制器的起止地址和標(biāo)志。
          staticstructresources3c_nand_resource[]={
          [0]={
          .start=S3C2410_PA_NAND,
          .end=S3C2410_PA_NAND+S3C24XX_SZ_NAND-1,
          .flags=IORESOURCE_MEM,
          }
          };
          //platform_device結(jié)構(gòu)體實(shí)例s3c_device_nand定義了設(shè)備的名稱、ID號(hào)并把resource對象作為其成員之一。
          structplatform_devices3c_device_nand={
          .name ="s3c2410-nand",
          .id =-1,
          .num_resources =ARRAY_SIZE(s3c_nand_resource),
          .resource =s3c_nand_resource,
          };
          //nandflash的分區(qū)情況,由mtd_partition結(jié)構(gòu)體定義。
          staticstructmtd_partitionsmdk_default_nand_part[]={
          [0]={
          .name ="BootAgent",
          .size =SZ_16K,
          .offset =0,
          },
          [1]={
          .name ="S3C2410flashpartition1",
          .offset=0,
          .size =SZ_2M,
          },
          [2]={
          .name ="S3C2410flashpartition2",
          .offset=SZ_4M,
          .size =SZ_4M,
          },
          [3]={
          .name ="S3C2410flashpartition3",
          .offset =SZ_8M,
          .size =SZ_2M,
          },
          [4]={
          .name ="S3C2410flashpartition4",

          .offset = SZ_1M * 10,
          .size = SZ_4M,
          },
          [5] = {
          .name = "S3C2410 flash partition 5",
          .offset = SZ_1M * 14,
          .size = SZ_1M * 10,
          },
          [6] = {
          .name = "S3C2410 flash partition 6",
          .offset = SZ_1M * 24,
          .size = SZ_1M * 24,
          },
          [7] = {
          .name = "S3C2410 flash partition 7",
          .offset = SZ_1M * 48,
          .size = SZ_16M,
          }
          };

          static struct s3c2410_nand_set smdk_nand_sets[] = {
          [0] = {
          .name = "NAND",
          .nr_chips = 1,
          .nr_partitions = ARRAY_SIZE(smdk_default_nand_part),
          .partitions = smdk_default_nand_part,
          },
          };

          本文引用地址:http://www.ex-cimer.com/article/201611/318027.htm

          /* choose a set of timings which should suit most 512Mbit
          * chips and beyond.
          */

          static struct s3c2410_platform_nand smdk_nand_info = {
          .tacls = 20,
          .twrph0 = 60,
          .twrph1 = 20,
          .nr_sets = ARRAY_SIZE(smdk_nand_sets),
          .sets = smdk_nand_sets,
          };

          /* devices we initialise */
          // 最后將nand flash 設(shè)備加入到系統(tǒng)即將注冊的設(shè)備集合中。
          static struct platform_device __initdata *smdk_devs[] = {
          &s3c_device_nand,
          &smdk_led4,
          &smdk_led5,
          &smdk_led6,
          &smdk_led7,
          };

          然后通過smdk_machine_init()函數(shù),調(diào)用設(shè)備添加函數(shù)platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)) 完成設(shè)備的注冊。具體過程參見系統(tǒng)初始化的相關(guān)部分。
          5. 系統(tǒng)初始化
          5.1. 系統(tǒng)初始化的主干線
          Start_kernel() èsetup_arch() èreset_init() è kernel_thread(init …) è init() è do_basic_setup() èdriver_init() è do_initcall()

          Start_kernel()函數(shù)負(fù)責(zé)初始化內(nèi)核各個(gè)子系統(tǒng),最后調(diào)用reset_init(),啟動(dòng)一個(gè)叫做init的內(nèi)核線程,繼續(xù)初始化。Start_kernel()函數(shù)在init/main.c中實(shí)現(xiàn)。

          asmlinkage void __init start_kernel(void)
          {
          char * command_line;
          extern struct kernel_param __start___param[], __stop___param[];

          smp_setup_processor_id();

          /*
          * Need to run as early as possible, to initialize the
          * lockdep hash:
          */
          lockdep_init();

          local_irq_disable();
          early_boot_irqs_off();
          early_init_irq_lock_class();

          /*
          * Interrupts are still disabled. Do necessary setups, then
          * enable them
          */
          lock_kernel();
          boot_cpu_init();
          page_address_init();
          printk(KERN_NOTICE);
          printk(linux_banner);
          setup_arch(&command_line);
          //setup processor and machine and destinate some pointers for do_initcalls() s

          5、淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程 咨詢QQ:313807838
          // for example init_machine pointer is initialized with smdk_machine_init() , and //init_machine() is called by customize_machine(), and the is processed by //arch_initcall(fn). Therefore smdk_machine_init() is issured. by edwin
          setup_per_cpu_areas();
          smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */

          /*
          * Set up the scheduler prior starting any interrupts (such as the
          * timer interrupt). Full topology setup happens at smp_init()
          * time - but meanwhile we still have a ing scheduler.
          */
          sched_init();
          /*
          * Disable preemption - early bootup scheduling is extremely
          * fragile until we cpu_idle() for the first time.
          */
          preempt_disable();
          build_all_zonelists();
          page_alloc_init();
          printk(KERN_NOTICE "Kernel command line: %sn", saved_command_line);
          parse_early_param();
          parse_args("Booting kernel", command_line, __start___param,
          __stop___param - __start___param,
          &unknown_bootoption);
          sort_main_extable();
          unwind_init();
          trap_init();
          rcu_init();
          init_IRQ();
          pidhash_init();
          init_timers();
          hrtimers_init();
          softirq_init();
          timekeeping_init();
          time_init();
          profile_init();
          if (!irqs_disabled())
          printk("start_kernel(): bug: interrupts were enabled earlyn");
          early_boot_irqs_on();
          local_irq_enable();

          /*
          * HACK ALERT! This is early. Were enabling the console before
          * weve done PCI setups etc, and console_init() must be aware of
          * this. But we do want output early, in case something goes wrong.
          */
          console_init();
          if (panic_later)
          panic(panic_later, panic_param);

          lockdep_info();

          /*
          * Need to run this when irqs are enabled, because it wants
          * to self-test [hard/soft]-irqs on/off lock inversion bugs
          * too:
          */
          locking_selftest();

          #ifdef CONFIG_BLK_DEV_INITRD
          if (initrd_start && !initrd_below_start_ok &&
          initrd_start < min_low_pfn << PAGE_SHIFT) {
          printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "

          6、淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程咨詢QQ:313807838
          "disabling it.n",initrd_start,min_low_pfn << PAGE_SHIFT);
          initrd_start = 0;
          }
          #endif
          vfs_caches_init_early();
          cpuset_init_early();
          mem_init();
          kmem_cache_init();
          setup_per_cpu_pageset();
          numa_policy_init();
          if (late_time_init)
          late_time_init();
          calibrate_delay();
          pidmap_init();
          pgtable_cache_init();
          prio_tree_init();
          anon_vma_init();
          #ifdef CONFIG_X86
          if (efi_enabled)
          efi_enter_virtual_mode();
          #endif
          fork_init(num_physpages);
          proc_caches_init();
          buffer_init();
          unnamed_dev_init();
          key_init();
          security_init();
          vfs_caches_init(num_physpages);
          radix_tree_init();
          signals_init();
          /* rootfs populating might need page-writeback */
          page_writeback_init();
          #ifdef CONFIG_PROC_FS
          proc_root_init();
          #endif
          cpuset_init();
          taskstats_init_early();
          delayacct_init();

          check_bugs();

          acpi_early_init(); /* before LAPIC and SMP init */

          /* Do the rest non-__inited, were now alive */
          rest_init();
          }

          分析start_kernel()源碼, 其中setup_arch() 和 reset_init()是兩個(gè)比較關(guān)鍵的函數(shù)。下面將具體分析這兩個(gè)函數(shù)。
          5.2. setup_arch()函數(shù)分析
          首先我們來分析下setup_arch()函數(shù)。
          Setup_arch()函數(shù)主要工作是安裝cpu和machine,并為start_kernel()后面的初始化函數(shù)指針指定值。
          其中setup_processor()函數(shù)調(diào)用linux/arch/arm/kernel/head_common.S 中的lookup_processor_type函數(shù)查詢處理器的型號(hào)并安裝。

          Setup_machine()函數(shù)調(diào)用inux/arch/arm/kernel/head_common.S 中的lookup_machine_type(__machine_arch_type)函數(shù)根據(jù)體系結(jié)構(gòu)號(hào)__machine_arch_type,在 __arch_info_begin和__arch_info_end段空間查詢體系結(jié)構(gòu)。問題是__machine_arch_type是在什么時(shí)候賦 的初值?__arch_info_begin和__arch_info_end段空間到底放的是什么內(nèi)容?
          __machine_arch_type是一個(gè)全局變量,在linux/boot/decompress/misc.c的解壓縮函數(shù)中得以賦值。
          decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, int arch_id)
          {
          __machine_arch_type = arch_id;
          }

          __arch_info_begin和__arch_info_end段空間到底放的內(nèi)容由鏈接器決定,存放是.arch.info.init段的 內(nèi)容。這個(gè)段是通過段屬性__attribute__指定的。Grep一下.arch.info.init 得到./include/asm/mach/arch.h:53: __attribute__((__section__(".arch.info.init"))) = { 在linux/include/asm-arm/mach/arch.h 中發(fā)現(xiàn)MACHINE_START宏定義。

          #define MACHINE_START(_type,_name)
          static const struct machine_desc __mach_desc_##_type
          __attribute_used__
          __attribute__((__section__(".arch.info.init"))) = {
          .nr = MACH_TYPE_##_type,
          .name = _name,

          #define MACHINE_END
          };

          inux/arch/arm/mach-s3c2410/mach-smdk2410.c中對.arch.info.init段的初始化如下。

          MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
          * to SMDK2410 */
          /* Maintainer: Jonas Dietsche */
          .phys_io = S3C2410_PA_UART,
          .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
          .boot_params = S3C2410_SDRAM_PA + 0x100,
          .map_io = smdk2410_map_io,
          .init_irq = s3c24xx_init_irq,
          .init_machine = smdk_machine_init,
          .timer = &s3c24xx_timer,
          MACHINE_END

          由此可見在.arch.info.init段內(nèi)存放了__desc_mach_desc_SMDK2410結(jié)構(gòu)體。初始化了相應(yīng)的初始化函數(shù)指針。問題又來了, 這些初始化指針函數(shù)是什么時(shí)候被調(diào)用的呢?
          分析發(fā)現(xiàn),不一而同。
          如 s3c24xx_init_irq()函數(shù)是通過start_kernel()里的init_IRQ()函數(shù)調(diào)用init_arch_irq()實(shí)現(xiàn)的。 因?yàn)樵贛ACHINE_START結(jié)構(gòu)體中 .init_irq = s3c24xx_init_irq,而在setup_arch()函數(shù)中init_arch_irq = mdesc->init_irq, 所以調(diào)用init_arch_irq()就相當(dāng)于調(diào)用了s3c24xx_init_irq()。
          又如smdk_machine_init()函數(shù) 的初始化。在MACHINE_START結(jié)構(gòu)體中,函數(shù)指針賦值,.init_machine = smdk_machine_init。而init_machine()函數(shù)被linux/arch/arm/kernel/setup.c文件中的 customize_machine()函數(shù)調(diào)用并被arch_initcall(Fn)宏處 理,arch_initcall(customize_machine)。 被arch_initcall(Fn)宏處理過函數(shù)將linux/init/main.c
          do_initcalls()函數(shù)調(diào)用。 具體參看下邊的部分。

          void __init setup_arch(char **cmdline_p)
          {
          struct tag *tags = (struct tag *)&init_tags;
          struct machine_desc *mdesc;
          char *from = default_command_line;

          setup_processor();
          mdesc = setup_machine(machine_arch_type);//machine_arch_type =SMDK2410 by edwin
          machine_name = mdesc->name;

          if (mdesc->soft_reboot)
          reboot_setup("s");

          if (mdesc->boot_params)
          tags = phys_to_virt(mdesc->boot_params);

          /*
          * If we have the old style parameters, convert them to
          * a tag list.
          */
          if (tags->hdr.tag != ATAG_CORE)
          convert_to_tag_list(tags);
          if (tags->hdr.tag != ATAG_CORE)
          tags = (struct tag *)&init_tags;

          if (mdesc->fixup)
          mdesc->fixup(mdesc, tags, &from, &meminfo);

          if (tags->hdr.tag == ATAG_CORE) {
          if (meminfo.nr_banks != 0)
          squash_mem_tags(tags);
          parse_tags(tags);
          }

          init_mm.start_code = (unsigned long) &_text;
          init_mm.end_code = (unsigned long) &_etext;
          init_mm.end_data = (unsigned long) &_edata;
          init_mm.brk = (unsigned long) &_end;

          memcpy(saved_command_line, from, COMMAND_LINE_SIZE);

          8、淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程 咨詢QQ:313807838
          saved_command_line[COMMAND_LINE_SIZE-1] = ;
          parse_cmdline(cmdline_p, from);
          paging_init(&meminfo, mdesc);
          request_standard_resources(&meminfo, mdesc);

          #ifdef CONFIG_SMP
          smp_init_cpus();
          #endif

          cpu_init();

          /*
          * Set up various architecture-specific pointers
          */
          init_arch_irq = mdesc->init_irq;
          system_timer = mdesc->timer;
          init_machine = mdesc->init_machine;

          #ifdef CONFIG_VT
          #if defined(CONFIG_VGA_CONSOLE)
          conswitchp = &vga_con;
          #elif defined(CONFIG_DUMMY_CONSOLE)
          conswitchp = &dummy_con;
          #endif
          #endif
          }
          5.3. rest_init()函數(shù)分析
          下面我們來分析下rest_init()函數(shù)。
          Start_kernel() 函數(shù)負(fù)責(zé)初始化內(nèi)核各子系統(tǒng),最后調(diào)用reset_init(),啟動(dòng)一個(gè)叫做init的內(nèi)核線程,繼續(xù)初始化。在init內(nèi)核線程中,將執(zhí)行下列 init()函數(shù)的程序。Init()函數(shù)負(fù)責(zé)完成根文件系統(tǒng)的掛接、初始化設(shè)備驅(qū)動(dòng)程序和啟動(dòng)用戶空間的init進(jìn)程等重要工作。

          static void noinline rest_init(void)
          __releases(kernel_lock)
          {
          kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
          numa_default_policy();
          unlock_kernel();

          /*
          * The boot idle thread must execute schedule()
          * at least one to get things moving:
          */
          preempt_enable_no_resched();
          schedule();
          preempt_disable();

          /* Call into cpu_idle with preempt disabled */
          cpu_idle();
          }


          static int init(void * unused)
          {
          lock_kernel();
          /*
          * init can run on any cpu.
          */
          set_cpus_allowed(current, CPU_MASK_ALL);
          /*
          * Tell the world that were going to be the grim
          * reaper of innocent orphaned children.
          *
          * We dont want people to have to make incorrect
          * assumptions about where in the task array this
          * can be found.
          */
          child_reaper = current;

          smp_prepare_cpus(max_cpus);

          do_pre_smp_initcalls();

          smp_init();
          sched_init_smp();

          cpuset_init_smp();

          /*
          * Do this before initcalls, because some drivers want to access
          * firmware files.
          */
          populate_rootfs(); //掛接根文件系統(tǒng)

          do_basic_setup(); //初始化設(shè)備驅(qū)動(dòng)程序

          /*
          * check if there is an early userspace init. If yes, let it do all
          * the work //啟動(dòng)用戶空間的init進(jìn)程

          9、淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程 咨詢QQ:313807838
          */

          if (!ramdisk_execute_command)
          ramdisk_execute_command = "/init";

          if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
          ramdisk_execute_command = NULL;
          prepare_namespace();
          }

          /*
          * Ok, we have completed the initial bootup, and
          * were essentially up and running. Get rid of the
          * initmem segments and start the user-mode stuff..
          */
          free_initmem();
          unlock_kernel();
          mark_rodata_ro();
          system_state = SYSTEM_RUNNING;
          numa_default_policy();

          if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
          printk(KERN_WARNING "Warning: unable to open an initial console.n");

          (void) sys_dup(0);
          (void) sys_dup(0);

          if (ramdisk_execute_command) {
          run_init_process(ramdisk_execute_command);
          printk(KERN_WARNING "Failed to execute %sn",
          ramdisk_execute_command);
          }

          /*
          * We try each of these until one succeeds.
          *
          * The Bourne shell can be used instead of init if we are
          * trying to recover a really broken machine.
          */
          if (execute_command) {
          run_init_process(execute_command);
          printk(KERN_WARNING "Failed to execute %s. Attempting "
          "defaults...n", execute_command);
          }
          run_init_process("/sbin/init");
          run_init_process("/etc/init");
          run_init_process("/bin/init");
          run_init_process("/bin/sh");

          panic("No init found. Try passing init= option to kernel.");
          }

          5.3.1. 掛接根文件系統(tǒng)
          Linux/init/ramfs.c
          void __init populate_rootfs(void)
          {
          char *err = unpack_to_rootfs(__initramfs_start,
          __initramfs_end - __initramfs_start, 0);
          if (err)
          panic(err);
          #ifdef CONFIG_BLK_DEV_INITRD
          if (initrd_start) {
          #ifdef CONFIG_BLK_DEV_RAM
          int fd;
          printk(KERN_INFO "checking if image is initramfs...");
          err = unpack_to_rootfs((char *)initrd_start,
          initrd_end - initrd_start, 1);
          if (!err) {
          printk(" it isn");
          unpack_to_rootfs((char *)initrd_start,
          initrd_end - initrd_start, 0);
          free_initrd();
          return;
          }
          printk("it isnt (%s); looks like an initrdn", err);

          fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
          if (fd >= 0) {
          sys_write(fd, (char *)initrd_start,
          initrd_end - initrd_start);
          sys_close(fd);
          free_initrd();
          }
          #else
          printk(KERN_INFO "Unpacking initramfs...");
          err = unpack_to_rootfs((char *)initrd_start,
          initrd_end - initrd_start, 0);
          if (err)
          panic(err);
          printk(" donen");
          free_initrd();
          #endif
          }
          #endif
          }

          5.3.2. 初始化設(shè)備5.3.3. 驅(qū)動(dòng)程序
          linux/init/main.c
          static void __init do_basic_setup(void)
          {
          /* drivers will send hotplug events */
          init_workqueues();
          usermodehelper_init();
          driver_init(); /* 初始化驅(qū)動(dòng)程序模型。調(diào)用驅(qū)動(dòng)初始化函數(shù)初始化子系統(tǒng)。 */

          #ifdef CONFIG_SYSCTL
          sysctl_init();
          #endif

          do_initcalls();
          }


          linux/init/main.c
          extern initcall_t __initcall_start[], __initcall_end[];

          static void __init do_initcalls(void)
          {
          initcall_t *call;
          int count = preempt_count();

          for (call = __initcall_start; call < __initcall_end; call++) {
          char *msg = NULL;
          char msgbuf[40];
          int result;

          if (initcall_debug) {
          printk("Calling initcall 0x%p", *call);
          print_fn_deor_symbol(": %s()",
          (unsigned long) *call);
          printk("n");
          }

          result = (*call)();

          ……
          ……
          ……
          }

          /* Make sure there is no pending stuff from the initcall sequence */
          flush_scheduled_work();
          }
          分 析上面一段代碼可以看出,設(shè)備的初始化是通過do_basic_setup()函數(shù)調(diào)用do_initcalls()函數(shù),實(shí)現(xiàn) __initcall_start, __initcall_end段之間的指針函數(shù)執(zhí)行的。而到底是那些驅(qū)動(dòng)函數(shù)怎么會(huì)被集中到這個(gè)段內(nèi)的呢?我們知道系統(tǒng)內(nèi)存空間的分配是由鏈接器ld讀取 鏈接腳本文件決定。鏈接器將同樣屬性的文件組織到相同的段里面去,如所有的.text段都被放在一起。在鏈接腳本里面可以獲得某塊內(nèi)存空間的具體地址。我 們來看下linux-2.6.18.8archarmkernelvmlinux.lds.S文件。由于文件過長,只貼出和 __initcall_start, __initcall_end相關(guān)的部分。
          __initcall_start = .;
          *(.initcall1.init)
          *(.initcall2.init)
          *(.initcall3.init)
          *(.initcall4.init)
          *(.initcall5.init)
          *(.initcall6.init)
          *(.initcall7.init)
          __initcall_end = .;
          從 腳本文件中我們可以看出, 在__initcall_start, __initcall_end之間放置的是屬行為(.initcall*.init)的函數(shù)數(shù)據(jù) 。在linux/include/linux/init.h文件中可以知道,(.initcall*.init)屬性是由 __define_initcall(level, fn)宏設(shè)定的。

          #define __define_initcall(level,fn)
          static initcall_t __initcall_##fn __attribute_used__

          11、淺談分析Arm linux 內(nèi)核移植及系統(tǒng)初始化的過程咨詢QQ:313807838
          __attribute__((__section__(".initcall" level ".init"))) = fn

          #define core_initcall(fn) __define_initcall("1",fn)
          #define postcore_initcall(fn) __define_initcall("2",fn)
          #define arch_initcall(fn) __define_initcall("3",fn)
          #define subsys_initcall(fn) __define_initcall("4",fn)
          #define fs_initcall(fn) __define_initcall("5",fn)
          #define device_initcall(fn) __define_initcall("6",fn)
          #define late_initcall(fn) __define_initcall("7",fn)
          #define __initcall(fn) device_initcall(fn)

          由此可以判斷,所有的設(shè)備驅(qū)動(dòng)函數(shù)都必然通過*_initcall(fn)宏的處理。以此為入口,可以查詢所有的設(shè)備驅(qū)動(dòng)。
          core_initcall(fn)
          static int __init consistent_init(void) linux/arch/arm/mm/consistent.c
          static int __init v6_userpage_init(void) linux/arch/arm/mm/copypage-v6.c
          static int __init init_dma(void) linux/arch/arm/kernel/dma.c
          static int __init s3c2410_core_init(void) linux/arch/arm/mach-s3c2410/s3c2410.c

          postcore_initcall(fn)
          static int ecard_bus_init(void) linux/arch/arm/kernel/ecard.c

          arch_initcall(fn)
          static __init int bast_irq_init(void) linux/arch/arm/mach-s3c2410/bast-irq.c
          static int __init s3c_arch_init(void) linux/arch/arm/mach-s3c2410/cpu.c
          static __init int pm_simtec_init(void) linux/arch/arm/mach-s3c2410/pm-simtec.c
          static int __init customize_machine(void) linux/arch/arm/kernel/setup.c

          subsys_initcall(fn)
          static int __init ecard_init(void) linux/arch/arm/kernel/ecard.c
          int __init scoop_init(void) linux/arch/arm/common/scoop.c
          static int __init topology_init(void) linux/arch/arm/kernel/setup.c

          fs_initcall(fn)
          static int __init alignment_init(void) linux/arch/arm/mm/alignment.c

          device_initcall(fn)
          static int __init leds_init(void) linux/arch/arm/kernel/time.c
          static int __init timer_init_sysfs(void) linux/arch/arm/kernel/time.c

          late_initcall(fn)
          static int __init crunch_init(void) arch/arm/kernel/crunch.c
          static int __init arm_mrc_hook_init(void) linux/arch/arm/kernel/traps.c



          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();