zoukankan      html  css  js  c++  java
  • Android Bootloader LittleKernel的两篇文章

    Android 开发之 ---- bootloader (LK)

     

    LK是什么

               LK 是 Little Kernel 它是 appsbl (Applications ARM Boot Loader)流程代码  ,little kernel 是小内核小操作系统。

               LK 代码 在 bootable/bootloadler/lk 目录下

               LK 代码结构

               +app            // 应用相关

               +arch           // arm 体系 

               +dev            // 设备相关

               +include      // 头文件

               +kernel        // lk系统相关   

               +platform    // 相关驱动

               +projiect     // makefile文件

               +scripts      // Jtag 脚本

               +target        // 具体板子相关


    LK 流程分析

              在 bootable/bootloadler/lk/arch/arm/ssystem-onesegment.ld 连接文件中 ENTRY(_start)指定 LK 从_start 函数开始,_start 在 lk/arch/crt0.S中 。crt0.S 主要做一些基本的 CPU 的初始化再通过 bl  kmain ;跳转到 C 代码中。

              kmain 在 lk/kernel/main.c 中


    kmain()

                kmain 主要做两件事:1、本身 lk 这个系统模块的初始化;2、boot 的启动初始化动作。

                kmain 源码分析:

                 void kmain()

              {

               1.初始化进程(lk 中的简单进程)相关结构体

                 thread_init_early();

               2.做一些如 关闭 cache,使能 mmu 的 arm 相关工作。

                arch_early_init();

               3.相关平台的早期初始化

                platform_early_init();

               4.现在就一个函数跳转,初始化UART(板子相关)

                target_early_init();

               5.构造函数相关初始化

                call_constructors();

               6.lk系统相关的堆栈初始化

                heap_init();

               7.简短的初始化定时器对象

                thread_init();

               8.lk系统控制器初始化(相关事件初始化)

                dpc_init();

               9.初始化lk中的定时器

                timer_init();
               
    10.新建线程入口函数 bootstrap2 用于boot 工作(重点
               thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));

             }

       以上与 boot 启动初始化相关函数是 arch_early_init、  platform_early_init 、bootstrap2,这些是启动的重点,我们下面慢慢来看。


    arch_early_init()

             体系架构相关的初始化我们一般用的 ARM 体系

             1.关闭cache

             arch_disable_cache(UCACHE);

             2.设置向量基地址(中断相关)

             set_vector_base(MEMBASE);

             3.初始化MMU

             arm_mmu_init();

             4.初始化MMU映射__平台相关

             platform_init_mmu_mappings();

             5.开启cache         

             arch_enable_cache(UCACHE)

             6.使能 cp10 和 cp11

             __asm__ volatile("mrc    p15, 0, %0, c1, c0, 2" : "=r" (val));

             val |= (3<<22)|(3<<20);

             __asm__ volatile("mcr    p15, 0, %0, c1, c0, 2" :: "r" (val));
     

            7.设置使能 fpexc 位 (中断相关)

            __asm__ volatile("mrc  p10, 7, %0, c8, c0, 0" : "=r" (val));

            val |= (1<<30);

            __asm__ volatile("mcr  p10, 7, %0, c8, c0, 0" :: "r" (val));

            8.使能循环计数寄存器

            __asm__ volatile("mrc    p15, 0, %0, c9, c12, 0" : "=r" (en));

            en &= ~(1<<3); /*循环计算每个周期*/

            en |= 1; 

            __asm__ volatile("mcr    p15, 0, %0, c9, c12, 0" :: "r" (en));

           9.使能循环计数器

           en = (1<<31);
           __asm__ volatile("mcr    p15, 0, %0, c9, c12, 1" :: "r" (en));


    platform_early_init()

           平台相关初始化不同平台不同的初始化下面是msm7x30

            1.初始化中断

            platform_init_interrupts();

            2.初始化定时器

            platform_init_timer();


    bootstrap2 

             bootstrap2 kmain的末尾以线程方式开启。主要分三步:platform_init、target_init、apps_init。

            1.platform_init

                   platform_init 中主要是函数 acpu_clock_init。

                   在 acpu_clock_init 对 arm11 进行系统时钟设置,超频 

            2.target_init

                  针对硬件平台进行设置。主要对 arm9 和 arm11 的分区表进行整合,初始化flash和读取FLASH信息

            3.apps_init  

                 apps_init 是关键,对 LK 中所谓 app 初始化并运行起来,而 aboot_init 就将在这里开始被运行,android linux 内核的加载工作就在 aboot_init 中完成的 。


    aboot_init

            1.设置NAND/ EMMC读取信息页面大小
            if (target_is_emmc_boot())

            {

                      page_size = 2048;

                      page_mask = page_size - 1;

            }

           else

           {

                     page_size = flash_page_size();

                     page_mask = page_size - 1;

            }

          2.读取按键信息,判断是正常开机,还是进入 fastboot ,还是进入recovery 模式

           。。。。。。。。。

          通过一系列的 if (keys_get_state() == XXX) 判断

           。。。。。。。。。

          3.从 nand 中加载 内核

          boot_linux_from_flash();

     

          partition_dump();

          sz = target_get_max_flash_size();

          fastboot_init(target_get_scratch_address(), sz);

          udc_start(); // 开始 USB 协议

     


    boot_linux_from_flash

                 主要是内核的加载过程,我们的 boot.img 包含:kernel 头、kernel、ramdisk、second stage(可以没有)。

               1.读取boot 头部

               flash_read(p, offset, raw_header, 2048) 

               offset += 2048;
               
    2.读取 内核    
               memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)
               n = (hdr->kernel_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1));

               flash_read(p, offset, (void*) hdr->kernel_addr, n)

               offset += n;
               
    3.读取 ramdisk
               n = (hdr->ramdisk_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1));

               flash_read(p, offset, (void*) hdr->ramdisk_addr, n)

               offset += n;

                4.启动内核

                    boot_linux();//在boot_linux 中entry(0,machtype,tags);从kernel加载在内核中的地址开始运行了。

          

            到这里LK的启动过程就结束了。

     

    Android Kernel - Boot Loader

    Android Boot loader 的 code 在 bootable/bootloader/lk 底下, LK 是 Little Kernel 的缩写, 是 andriod bootloader 的核心精神.

     

    入口函数在 kernel/main.c 中的 kmain(), 以下就来读读这一段 code.

     

    1. void kmain(void)  
    2. {  
    3.     // get us into some sort of thread context   
    4.     thread_init_early();  
    5.     // early arch stuff   
    6.     arch_early_init();  
    7.     // do any super early platform initialization   
    8.     platform_early_init();  
    9.     // do any super early target initialization   
    10.     target_early_init();  
    11.     dprintf(INFO, "welcome to lk/n/n");  
    12.       
    13.     // deal with any static constructors   
    14.     dprintf(SPEW, "calling constructors/n");  
    15.     call_constructors();  
    16.     // bring up the kernel heap   
    17.     dprintf(SPEW, "initializing heap/n");  
    18.     heap_init();  
    19.     // initialize the threading system   
    20.     dprintf(SPEW, "initializing threads/n");  
    21.     thread_init();  
    22.     // initialize the dpc system   
    23.     dprintf(SPEW, "initializing dpc/n");  
    24.     dpc_init();  
    25.     // initialize kernel timers   
    26.     dprintf(SPEW, "initializing timers/n");  
    27.     timer_init();  
    28. #if (!ENABLE_NANDWRITE)   
    29.     // create a thread to complete system initialization   
    30.     dprintf(SPEW, "creating bootstrap completion thread/n");  
    31.     thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));  
    32.     // enable interrupts   
    33.     exit_critical_section();  
    34.     // become the idle thread   
    35.     thread_become_idle();  
    36. #else   
    37.         bootstrap_nandwrite();  
    38. #endif   
    39. }  

     

     

    In include/debug.h: 我们可以看到 dprintf 的第一个参数是代表 debug level.

     

    [c-sharp:nogutter] view plaincopyprint?
    1. /* debug levels */ 
    2. #define CRITICAL 0  
    3. #define ALWAYS 0  
    4. #define INFO 1  
    5. #define SPEW 2  

     

     

    In include/debug.h: 

     

    [c-sharp:nogutter] view plaincopyprint?
    1. #define dprintf(level, x...) do { if ((level) <= DEBUGLEVEL) { _dprintf(x); } } while (0)  

     

     

    所以 dprintf 会依 DEBUGLEVEL 来判断是否输出信息.

     

    来看第一个 call 的函数: thread_init_early, define in thread.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void thread_init_early(void)  
    2. {  
    3.         int i;  
    4.         /* initialize the run queues */  
    5.         for (i=0; i < NUM_PRIORITIES; i++)  
    6.                 list_initialize(&run_queue[i]);  
    7.         /* initialize the thread list */  
    8.         list_initialize(&thread_list);  
    9.         /* create a thread to cover the current running state */  
    10.         thread_t *t = &bootstrap_thread;  
    11.         init_thread_struct(t, "bootstrap");  
    12.         /* half construct this thread, since we're already running */  
    13.         t->priority = HIGHEST_PRIORITY;  
    14.         t->state = THREAD_RUNNING;  
    15.         t->saved_critical_section_count = 1;  
    16.         list_add_head(&thread_list, &t->thread_list_node);  
    17.         current_thread = t;  
    18. }  

     

     

    #define NUM_PRIORITIES 32 in include/kernel/thread.h

     

    list_initialize() defined in include/list.h: initialized a list

     

    [c-sharp:nogutter] view plaincopyprint?
    1. static inline void list_initialize(struct list_node *list)  
    2. {  
    3.         list->prev = list->next = list;  
    4. }  

     

     

    run_queue 是 static struct list_node run_queue[NUM_PRIORITIES]

     

    thread_list 是 static struct list_node thread_list

     

    再来要 call  的函数是: arch_early_init() defined in arch/arm/arch.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void arch_early_init(void)  
    2. {  
    3.     /* turn off the cache */  
    4.     arch_disable_cache(UCACHE);  
    5.     /* set the vector base to our exception vectors so we dont need to double map at 0 */ 
    6. #if ARM_CPU_CORTEX_A8   
    7.     set_vector_base(MEMBASE);  
    8. #endif  
    9. #if ARM_WITH_MMU   
    10.     arm_mmu_init();  
    11.     platform_init_mmu_mappings();  
    12. #endif   
    13.     /* turn the cache back on */  
    14.     arch_enable_cache(UCACHE);  
    15. #if ARM_WITH_NEON   
    16.     /* enable cp10 and cp11 */  
    17.     uint32_t val;  
    18.     __asm__ volatile("mrc   p15, 0, %0, c1, c0, 2" : "=r" (val));  
    19.     val |= (3<<22)|(3<<20);  
    20.     __asm__ volatile("mcr   p15, 0, %0, c1, c0, 2" :: "r" (val));  
    21.     /* set enable bit in fpexc */  
    22.     val = (1<<30);  
    23.     __asm__ volatile("mcr  p10, 7, %0, c8, c0, 0" :: "r" (val));  
    24. #endif   
    25. }  

     

     

    现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,

     

    内存管理单元)提供支持。

     

    CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地

     

    址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将VA映射成PA

     

    MMU将VA映射到PA是以页(Page)为单位的,32位处理器的页尺寸通常是4KB。例如,MMU可以通过一个映射项将VA的一页

     

    0xb7001000~0xb7001fff映射到PA的一页0x2000~0x2fff,如果CPU执行单元要访问虚拟地址0xb7001008,则实际访问到的物理地

     

    址是0x2008。物理内存中的页称为物理页面或者页帧(Page Frame)。虚拟内存的哪个页面映射到物理内存的哪个页帧是通过页

     

    表(Page Table)来描述的,页表保存在物理内存中,MMU会查找页表来确定一个VA应该映射到什么PA。

     

     

     

    操作系统和MMU是这样配合的:

     

    1. 操作系统在初始化或分配、释放内存时会执行一些指令在物理内存中填写页表,然后用指令设置MMU,告诉MMU页表在物理内存中

     

       的什么位置。

     

    2. 设置好之后,CPU每次执行访问内存的指令都会自动引发MMU做查表和地址转换操作,地址转换操作由硬件自动完成,不需要用指令

     

        控制MMU去做。

     

     

    MMU除了做地址转换之外,还提供内存保护机制。各种体系结构都有用户模式(User Mode)和特权模式(Privileged Mode)之分,

     

    操作系统可以在页表中设置每个内存页面的访问权限,有些页面不允许访问,有些页面只有在CPU处于特权模式时才允许访问,有些页面

     

    在用户模式和特权模式都可以访问,访问权限又分为可读、可写和可执行三种。这样设定好之后,当CPU要访问一个VA时,MMU会检查

     

    CPU当前处于用户模式还是特权模式,访问内存的目的是读数据、写数据还是取指令,如果和操作系统设定的页面权限相符,就允许访

     

    问,把它转换成PA,否则不允许访问,产生一个异常(Exception)

     

    常见的 segmentation fault 产生的原因:

     

    用户程序要访问一段 VA, 经 MMU 检查后无权访问, MMU 会产生异常, CPU 从用户模式切换到特权模式, 跳转到内核代码中执行异常服务程序.

     

    内核就会把这个异常解释为 segmentation fault, 将引发异常的程序终止.

     

    简单的讲一下 NEON: NEON technology can accelerate multimedia and signal processing algorithms such as video encode/decode,

     

    2D/3D graphics, gaming, audio and speech processing, image processing, telephony, and sound synthesis.

     

    platform_early_init() defined in platform/<your-platform>/platform.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void platform_early_init(void)  
    2. {  
    3.     uart_init();  
    4.     platform_init_interrupts();  
    5.     platform_init_timer();  
    6. }  

     

     

    uart_init.c defined in platform/<your-platform>/uart.c 所有用到的变数,也都定义在 uart.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void uart_init(void)  
    2. {  
    3.     uwr(0x0A, UART_CR);  /* disable TX and RX */  
    4.       
    5.     uwr(0x30, UART_CR);  /* reset error status */  
    6.     uwr(0x10, UART_CR);  /* reset receiver */  
    7.     uwr(0x20, UART_CR);  /* reset transmitter */ 
    8.      
    9. #if PLATFORM_QSD8K   
    10.     /* TCXO */  
    11.     uwr(0x06, UART_MREG);  
    12.     uwr(0xF1, UART_NREG);  
    13.     uwr(0x0F, UART_DREG);  
    14.     uwr(0x1A, UART_MNDREG);  
    15. #else   
    16.     /* TCXO/4 */  
    17.     uwr(0xC0, UART_MREG);  
    18.     uwr(0xAF, UART_NREG);  
    19.     uwr(0x80, UART_DREG);  
    20.     uwr(0x19, UART_MNDREG);      
    21. #endif   
    22.       
    23.     uwr(0x10, UART_CR);  /* reset RX */  
    24.     uwr(0x20, UART_CR);  /* reset TX */  
    25.     uwr(0x30, UART_CR);  /* reset error status */  
    26.     uwr(0x40, UART_CR);  /* reset RX break */  
    27.     uwr(0x70, UART_CR);  /* rest? */  
    28.     uwr(0xD0, UART_CR);  /* reset */  
    29.       
    30.     uwr(0x7BF, UART_IPR); /* stale timeout = 630 * bitrate */  
    31.     uwr(0, UART_IMR);  
    32.     uwr(115, UART_RFWR); /* RX watermark = 58 * 2 - 1 */  
    33.     uwr(10, UART_TFWR);  /* TX watermark */  
    34.       
    35.     uwr(0, UART_RFWR);   
    36.       
    37.     uwr(UART_CSR_115200, UART_CSR);  
    38.     uwr(0, UART_IRDA);  
    39.     uwr(0x1E, UART_HCR);  
    40. //  uwr(0x7F4, UART_MR1); /* RFS/ CTS/ 500chr RFR */   
    41.     uwr(16, UART_MR1);  
    42.     uwr(0x34, UART_MR2); /* 8N1 */  
    43.       
    44.     uwr(0x05, UART_CR); /* enable TX & RX */  
    45.     uart_ready = 1;  
    46. }  

     

     

    platform_init_interrupts: defined in platform/msm8x60/interrupts.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void platform_init_interrupts(void)  
    2. {  
    3.     platform_gic_dist_init();  
    4.     platform_gic_cpu_init();  
    5. }  

     

     

    GIC 指的是 Generic Interrupt Controller. The gic-cpu and gic-dist are two subcomponents of GIC.

     

    Devices are wired to the git-dist which is in charge of distributing interrupts to the gic-cpu (per cpu IRQ IF).

     

    platform_init_timer(): defined in platform/<your-platform>/timer.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void platform_init_timer(void)  
    2. {  
    3.     writel(0, DGT_ENABLE);  
    4. }  

     

     

    DGT: Digital Game Timer: presents the countdowns of two players, it is also called chess timer or chess clock.

     

    target_early_init(): defined in target/init.c

     

    [c-sharp:nogutter] view plaincopyprint?
    1. /* 
    2.  * default implementations of these routines, if the target code 
    3.  * chooses not to implement. 
    4.  */  
    5. __WEAK void target_early_init(void)  
    6. {  
    7. }  
    8. __WEAK void target_init(void)  
    9. {  
    10. }  

     

     

    call_constructors() is defined in kernel/main.c:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. static void call_constructors(void)  
    2. {  
    3.     void **ctor;  
    4.      
    5.     ctor = &__ctor_list;  
    6.     while(ctor != &__ctor_end) {  
    7.         void (*func)(void);  
    8.         func = (void (*)())*ctor;  
    9.         func();  
    10.         ctor++;  
    11.     }  
    12. }  

     

     

     

    heap_init is defined in lib/heap/heap.c:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void heap_init(void)  
    2. {  
    3.     LTRACE_ENTRY;  
    4.     // set the heap range   
    5.     theheap.base = (void *)HEAP_START;  
    6.     theheap.len = HEAP_LEN;  
    7.     LTRACEF("base %p size %zd bytes/n", theheap.base, theheap.len);  
    8.     // initialize the free list   
    9.     list_initialize(&theheap.free_list);  
    10.     // create an initial free chunk   
    11.     heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len));  
    12.     // dump heap info   
    13. //  heap_dump();   
    14. //  dprintf(INFO, "running heap tests/n");   
    15. //  heap_test();   
    16. }  

     

     

     

    thread_init is defined in kernel/thread.c but nothing coded, 先记下.

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void thread_init(void)  
    2. {  
    3. }  

     

     

    dpc_init() is defined in kernel/dpc.c:

     

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void dpc_init(void)  
    2. {  
    3.     event_init(&dpc_event, false, 0);  
    4.     thread_resume(thread_create("dpc", &dpc_thread_routine, NULL, DPC_PRIORITY, DEFAULT_STACK_SIZE));  
    5. }  

     

     

    dpc 为 Delayed Procedure Call 延迟过程调用的缩写.

     

    timer_init() is defined in kernel/timer.c:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void timer_init(void)  
    2. {  
    3.     list_initialize(&timer_queue);  
    4.     /* register for a periodic timer tick */  
    5.     platform_set_periodic_timer(timer_tick, NULL, 10); /* 10ms */  
    6. }  

     

     

     

     

    执行 thread_resume 或是 bootstrap_nandwrite

     

     

    [c-sharp:nogutter] view plaincopyprint?
    1. #if (!ENABLE_NANDWRITE)   
    2.     // create a thread to complete system initialization   
    3.     dprintf(SPEW, "creating bootstrap completion thread/n");  
    4.     thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));  
    5.     // enable interrupts   
    6.     exit_critical_section();  
    7.     // become the idle thread   
    8.     thread_become_idle();  
    9. #else   
    10.         bootstrap_nandwrite();  
    11. #endif  

     

     

    In kermel/main.c:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. static int bootstrap2(void *arg)  
    2. {  
    3.     dprintf(SPEW, "top of bootstrap2()/n");  
    4.     arch_init();  
    5.     // initialize the rest of the platform   
    6.     dprintf(SPEW, "initializing platform/n");  
    7.     platform_init();  
    8.       
    9.     // initialize the target   
    10.     dprintf(SPEW, "initializing target/n");  
    11.     target_init();  
    12.     dprintf(SPEW, "calling apps_init()/n");  
    13.     apps_init();  
    14.     return 0;  
    15. }  
    16. #if (ENABLE_NANDWRITE)   
    17. void bootstrap_nandwrite(void)  
    18. {  
    19.     dprintf(SPEW, "top of bootstrap2()/n");  
    20.     arch_init();  
    21.     // initialize the rest of the platform   
    22.     dprintf(SPEW, "initializing platform/n");  
    23.     platform_init();  
    24.     // initialize the target   
    25.     dprintf(SPEW, "initializing target/n");  
    26.     target_init();  
    27.     dprintf(SPEW, "calling nandwrite_init()/n");  
    28.     nandwrite_init();  
    29.     return 0;  
    30. }  
    31. #endif  

     

     

    continue to see apps_init(): app/app.c:void apps_init(void)

     

    1. #include <app.h>  
    2. #include <kernel/thread.h>   
    3. extern const struct app_descriptor __apps_start;  
    4. extern const struct app_descriptor __apps_end;  
    5. static void start_app(const struct app_descriptor *app);  
    6. /* one time setup */  
    7. void apps_init(void)  
    8. {  
    9.     const struct app_descriptor *app;  
    10.     /* call all the init routines */  
    11.     for (app = &__apps_start; app != &__apps_end; app++) {  
    12.         if (app->init)  
    13.             app->init(app);  
    14.     }  
    15.     /* start any that want to start on boot */  
    16.     for (app = &__apps_start; app != &__apps_end; app++) {  
    17.         if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {  
    18.             start_app(app);  
    19.         }  
    20.     }  
    21. }  
    22. static int app_thread_entry(void *arg)  
    23. {  
    24.     const struct app_descriptor *app = (const struct app_descriptor *)arg;  
    25.     app->entry(app, NULL);  
    26.     return 0;  
    27. }  
    28. static void start_app(const struct app_descriptor *app)  
    29. {  
    30.     printf("starting app %s/n", app->name);  
    31.     thread_resume(thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));     
    32. }  

     

     

    至于会有那些 app 被放入 boot thread section, 则定义在 include/app.h 中的 APP_START(appname)

     

    [c-sharp:nogutter] view plaincopyprint?
    1. #define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname, 
    2. #define APP_END };  

     

     

    在 app 中只要像 app/aboot/aboot.c 指定就会在 bootloader bootup 时放入 thread section 中被执行.

     

    [c-sharp:nogutter] view plaincopyprint?
    1. APP_START(aboot)  
    2.         .init = aboot_init,  
    3. APP_END  

     

     

    在我的 bootloader 中有 app/aboot/aboot.c, app/tests/tests.c, app/shell/shell.c, 及 app/stringtests/string_tests.c 皆有此声明.

     

    接下来关注: aboot.c 中的 aboot_init()

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void aboot_init(const struct app_descriptor *app)  
    2. {  
    3.     unsigned reboot_mode = 0;  
    4.     unsigned disp_init = 0;  
    5.     unsigned usb_init = 0;  
    6.     //test_ram();   
    7.     /* Setup page size information for nand/emmc reads */  
    8.     if (target_is_emmc_boot())  
    9.     {  
    10.         page_size = 2048;  
    11.         page_mask = page_size - 1;  
    12.     }  
    13.     else  
    14.     {  
    15.         page_size = flash_page_size();  
    16.         page_mask = page_size - 1;  
    17.     }  
    18.     /* Display splash screen if enabled */ 
    19.     #if DISPLAY_SPLASH_SCREEN   
    20.     display_init();  
    21.     dprintf(INFO, "Diplay initialized/n");  
    22.     disp_init = 1;  
    23.     diplay_image_on_screen();  
    24.     #endif   
    25.     /* Check if we should do something other than booting up */  
    26.     if (keys_get_state(KEY_HOME) != 0)  
    27.         boot_into_recovery = 1;  
    28.     if (keys_get_state(KEY_BACK) != 0)  
    29.         goto fastboot;  
    30.     if (keys_get_state(KEY_CLEAR) != 0)  
    31.         goto fastboot;  
    32.     #if NO_KEYPAD_DRIVER   
    33.     /* With no keypad implementation, check the status of USB connection. */  
    34.     /* If USB is connected then go into fastboot mode. */  
    35.     usb_init = 1;  
    36.     udc_init(&surf_udc_device);  
    37.     if (usb_cable_status())  
    38.         goto fastboot;  
    39.     #endif   
    40.     init_vol_key();  
    41.     if(voldown_press())  
    42.         goto fastboot;  
    43.     reboot_mode = check_reboot_mode();  
    44.     if (reboot_mode == RECOVERY_MODE) {  
    45.         boot_into_recovery = 1;  
    46.     } else if(reboot_mode == FASTBOOT_MODE) {  
    47.         goto fastboot;  
    48.     }  
    49.     if (target_is_emmc_boot())  
    50.     {  
    51.         boot_linux_from_mmc();  
    52.     }  
    53.     else  
    54.     {  
    55.         recovery_init();  
    56.         boot_linux_from_flash();  
    57.     }  
    58.     dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "  
    59.         "to fastboot mode./n");  
    60. fastboot:  
    61.     if(!usb_init)  
    62.         udc_init(&surf_udc_device);  
    63.     fastboot_register("boot", cmd_boot);  
    64.     if (target_is_emmc_boot())  
    65.     {  
    66.         fastboot_register("flash:", cmd_flash_mmc);  
    67.         fastboot_register("erase:", cmd_erase_mmc);  
    68.     }  
    69.     else  
    70.     {  
    71.         fastboot_register("flash:", cmd_flash);  
    72.         fastboot_register("erase:", cmd_erase);  
    73.     }  
    74.     fastboot_register("continue", cmd_continue);  
    75.     fastboot_register("reboot", cmd_reboot);  
    76.     fastboot_register("reboot-bootloader", cmd_reboot_bootloader);  
    77.     fastboot_publish("product", TARGET(BOARD));  
    78.     fastboot_publish("kernel""lk");  
    79.       
    80.     fastboot_init(target_get_scratch_address(), 120 * 1024 * 1024);  
    81.       
    82.     udc_start();  
    83.     target_battery_charging_enable(1, 0);  
    84. }  

     

     


     

    target_is_emmc_boot() is defined in target/init.c: _EMMC_BOOT 是 compiler 时的 flags

     

    [c-sharp:nogutter] view plaincopyprint?
    1. __WEAK int target_is_emmc_boot(void)  
    2. {  
    3. #if _EMMC_BOOT   
    4.     return 1;  
    5. #else   
    6.     return 0;  
    7. #endif   
    8. }  

     

     

    check_reboot_mode is defined in target/<your-platform>/init.c:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. unsigned check_reboot_mode(void)  
    2. {  
    3.         unsigned restart_reason = 0;  
    4.         void *restart_reason_addr = 0x401FFFFC;  
    5.         /* Read reboot reason and scrub it */  
    6.         restart_reason = readl(restart_reason_addr);  
    7.         writel(0x00, restart_reason_addr);  
    8.         return restart_reason;  
    9. }  

     

     

    reboot mode in bootloader:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. #define RECOVERY_MODE   0x77665502  
    2. #define FASTBOOT_MODE   0x77665500  

     

     

     

    再来就会执行 boot_linux_from_mmc():

     

    [c-sharp:nogutter] view plaincopyprint?
    1. int boot_linux_from_mmc(void)  
    2. {  
    3.     struct boot_img_hdr *hdr = (void*) buf;  
    4.     struct boot_img_hdr *uhdr;  
    5.     unsigned offset = 0;  
    6.     unsigned long long ptn = 0;  
    7.     unsigned n = 0;  
    8.     const char *cmdline;  
    9.     uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;  
    10.     if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {  
    11.         dprintf(INFO, "Unified boot method!/n");  
    12.         hdr = uhdr;  
    13.         goto unified_boot;  
    14.     }  
    15.     if(!boot_into_recovery)  
    16.     {  
    17.         ptn = mmc_ptn_offset("boot");  
    18.         if(ptn == 0) {  
    19.             dprintf(CRITICAL, "ERROR: No boot partition found/n");  
    20.                     return -1;  
    21.         }  
    22.     }  
    23.     else  
    24.     {  
    25.         ptn = mmc_ptn_offset("recovery");  
    26.         if(ptn == 0) {  
    27.             dprintf(CRITICAL, "ERROR: No recovery partition found/n");  
    28.                     return -1;  
    29.         }  
    30.     }  
    31.     if (mmc_read(ptn + offset, (unsigned int *)buf, page_size)) {  
    32.         dprintf(CRITICAL, "ERROR: Cannot read boot image header/n");  
    33.                 return -1;  
    34.     }  
    35.     if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {  
    36.         dprintf(CRITICAL, "ERROR: Invaled boot image header/n");  
    37.                 return -1;  
    38.     }  
    39.     if (hdr->page_size && (hdr->page_size != page_size)) {  
    40.         page_size = hdr->page_size;  
    41.         page_mask = page_size - 1;  
    42.     }  
    43.     offset += page_size;  
    44.     n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);  
    45.     if (mmc_read(ptn + offset, (void *)hdr->kernel_addr, n)) {  
    46.         dprintf(CRITICAL, "ERROR: Cannot read kernel image/n");  
    47.                 return -1;  
    48.     }  
    49.     offset += n;  
    50.     n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);  
    51.     if (mmc_read(ptn + offset, (void *)hdr->ramdisk_addr, n)) {  
    52.         dprintf(CRITICAL, "ERROR: Cannot read ramdisk image/n");  
    53.                 return -1;  
    54.     }  
    55.     offset += n;  
    56. unified_boot:  
    57.     dprintf(INFO, "/nkernel  @ %x (%d bytes)/n", hdr->kernel_addr,  
    58.         hdr->kernel_size);  
    59.     dprintf(INFO, "ramdisk @ %x (%d bytes)/n", hdr->ramdisk_addr,  
    60.         hdr->ramdisk_size);  
    61.     if(hdr->cmdline[0]) {  
    62.         cmdline = (char*) hdr->cmdline;  
    63.     } else {  
    64.         cmdline = DEFAULT_CMDLINE;  
    65.     }  
    66.     dprintf(INFO, "cmdline = '%s'/n", cmdline);  
    67.     dprintf(INFO, "/nBooting Linux/n");  
    68.     boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR,  
    69.            (const char *)cmdline, board_machtype(),  
    70.            (void *)hdr->ramdisk_addr, hdr->ramdisk_size);  
    71.     return 0;  
    72. }  

     

     

    mmc_read() is defined in platform/<your-platform>/mmc.c:

     

    [c-sharp:nogutter] view plaincopyprint?
    1. unsigned int mmc_read (unsigned long long data_addr, unsigned intout, unsigned int data_len)  
    2. {  
    3.     int val = 0;  
    4.     val = mmc_boot_read_from_card( &mmc_host, &mmc_card, data_addr, data_len, out);  
    5.     return val;  
    6. }  

     

     

    boot_linux(): 启动 Linux, 看看函数定义

     

    [c-sharp:nogutter] view plaincopyprint?
    1. void boot_linux(void *kernel, unsigned *tags,   
    2.         const char *cmdline, unsigned machtype,  
    3.         void *ramdisk, unsigned ramdisk_size)  
    4. {  
    5.     unsigned *ptr = tags;  
    6.     unsigned pcount = 0;  
    7.     void (*entry)(unsigned,unsigned,unsigned*) = kernel;  
    8.     struct ptable *ptable;  
    9.     int cmdline_len = 0;  
    10.     int have_cmdline = 0;  
    11.     int pause_at_bootup = 0;  
    12.     /* CORE */  
    13.     *ptr++ = 2;  
    14.     *ptr++ = 0x54410001;  
    15.     if (ramdisk_size) {  
    16.         *ptr++ = 4;  
    17.         *ptr++ = 0x54420005;  
    18.         *ptr++ = (unsigned)ramdisk;  
    19.         *ptr++ = ramdisk_size;  
    20.     }  
    21.     ptr = target_atag_mem(ptr);  
    22.     if (!target_is_emmc_boot()) {  
    23.         /* Skip NAND partition ATAGS for eMMC boot */  
    24.         if ((ptable = flash_get_ptable()) && (ptable->count != 0)) {  
    25.             int i;  
    26.             for(i=0; i < ptable->count; i++) {  
    27.                 struct ptentry *ptn;  
    28.                 ptn =  ptable_get(ptable, i);  
    29.                 if (ptn->type == TYPE_APPS_PARTITION)  
    30.                     pcount++;  
    31.             }  
    32.             *ptr++ = 2 + (pcount * (sizeof(struct atag_ptbl_entry) /  
    33.                                sizeof(unsigned)));  
    34.             *ptr++ = 0x4d534d70;  
    35.             for (i = 0; i < ptable->count; ++i)  
    36.                 ptentry_to_tag(&ptr, ptable_get(ptable, i));  
    37.         }  
    38.     }  
    39.     if (cmdline && cmdline[0]) {  
    40.         cmdline_len = strlen(cmdline);  
    41.         have_cmdline = 1;  
    42.     }  
    43.     if (target_is_emmc_boot()) {  
    44.         cmdline_len += strlen(emmc_cmdline);  
    45.     }  
    46.     if (target_pause_for_battery_charge()) {  
    47.         pause_at_bootup = 1;  
    48.         cmdline_len += strlen(battchg_pause);  
    49.     }  
    50.     if (cmdline_len > 0) {  
    51.         const char *src;  
    52.         char *dst;  
    53.         unsigned n;  
    54.         /* include terminating 0 and round up to a word multiple */  
    55.         n = (cmdline_len + 4) & (~3);  
    56.         *ptr++ = (n / 4) + 2;  
    57.         *ptr++ = 0x54410009;  
    58.         dst = (char *)ptr;  
    59.         if (have_cmdline) {  
    60.             src = cmdline;  
    61.             while ((*dst++ = *src++));  
    62.         }  
    63.         if (target_is_emmc_boot()) {  
    64.             src = emmc_cmdline;  
    65.             if (have_cmdline) --dst;  
    66.             have_cmdline = 1;  
    67.             while ((*dst++ = *src++));  
    68.         }  
    69.         if (pause_at_bootup) {  
    70.             src = battchg_pause;  
    71.             if (have_cmdline) --dst;  
    72.             while ((*dst++ = *src++));  
    73.         }  
    74.         ptr += (n / 4);  
    75.     }  
    76.     /* END */  
    77.     *ptr++ = 0;  
    78.     *ptr++ = 0;  
    79.     dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d)/n",  
    80.         kernel, ramdisk, ramdisk_size);  
    81.     if (cmdline)  
    82.         dprintf(INFO, "cmdline: %s/n", cmdline);  
    83.     enter_critical_section();  
    84.     platform_uninit_timer();  
    85.     arch_disable_cache(UCACHE);  
    86.     arch_disable_mmu();  
    87. #if DISPLAY_SPLASH_SCREEN   
    88.     display_shutdown();  
    89. #endif   
    90.     entry(0, machtype, tags);  
    91. }  

     

     

    配合 boot.img 来看会比较好理解.

     

     

     

    由此可知 boot_img_hdr 中各成员值为:

     

     

     

    TAGS_ADDR 如上 target/<your-platform>/rules.mk 所定义的 : 0x40200100, 所以 boot_linux(), 就是传入TAGS_ADDR,

     

    然后将资料写入 tag, tag 的结构如下所示.

     

     

    然后进入到 kernel 的入口函数: entry(0, machtype, tags)

  • 相关阅读:
    1、编写一个简单的C++程序
    96. Unique Binary Search Trees
    python 操作redis
    json.loads的一个很有意思的现象
    No changes detected
    leetcode 127 wordladder
    django uwsgi websocket踩坑
    you need to build uWSGI with SSL support to use the websocket handshake api function !!!
    pyinstaller 出现str error
    数据库的读现象
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298331.html
Copyright © 2011-2022 走看看