Android Bootloader LittleKernel的两篇文章 【转】

转自:http://blog.csdn.net/loongembedded/article/details/41747523

 分类:
Android Bootloader(68) 

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.

 

 

[c-sharp] view plaincopyprint?
  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)

 

 

[c-sharp] view plaincopyprint?
  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)











本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/6077828.html,如需转载请自行联系原作者


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/286217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一、首页第一个首页栏制作【仿淘票票系统前后端完全制作(除支付外)】

首页一共分为3个页面&#xff0c;分别是首页&#xff1a; 影院&#xff1a; 我的&#xff1a; 一、标题头制作 首先我们新建一个 web 相对应用&#xff0c;随后点击前台&#xff0c;在前台新建一个页面&#xff1a; 接着给予这个页面一个背景色&#xff1a; 为了使页面…

C# 11 更加实用的 nameof

C# 11 更加实用的 nameofIntro从 C# 6.0 开始&#xff0c;我们可以开始使用 nameof 来引用参数名称&#xff0c;在可能使用 nameof 的地方&#xff0c;一般都推荐使用以便于重构时的自动更新&#xff0c;在之前的 C# 版本中&#xff0c;如果想要在方法参数中或者方法 attribute…

二、首页影院/我的 栏制作《仿淘票票系统前后端完全制作(除支付外)》

页面效果&#xff0c;影院内容&#xff1a; 我的页分为登录、注册、我的&#xff0c;如果登录了那么就显示我的页面否则显示登录页。 登录页&#xff1a; 我的页&#xff1a; 一、标题头部制作 接着我们点击影院&#xff0c;发现当前页内容为空&#xff1a; 我们的影院页…

【数据库系统经典案例】销售系统数据库分析及完整实现过程

文章目录 一、产品表以及产品添加更新二、顾客管理三、销售记帐四、统计问题一、产品表以及产品添加更新 GOODLUCK的产品表:PRODUCTS(PNO,PNAME,PR,QTY) 从该表可以知: PNO->PNAME、PR、QTY 所以这个表只能按产品编号增加行,也就是说:有新产品了,可以在这个表中…

聊聊 C# 方法重载的底层玩法

最近在看 C 的方法重载&#xff0c;我就在想 C# 中的重载底层是怎么玩的&#xff0c;很多朋友应该知道 C 是不支持重载的&#xff0c;比如下面的代码就会报错。#include <stdio.h>int say() {return 1; } int say(int i) {return i; }int main() {say(10);return 0; }从错…

Nginx图片剪裁模块探究 http_image_filter_module

#yum install -y gd-devel Install add http_image_filter_module Module #./configure --prefix/usr/local/nginx_image_filter/ --with-http_image_filter_module #make && make install use: off:关闭模块处理 test:确保图片是jpeg gif png否则返415错误 size:输出有…

三、我的/登录 栏制作《仿淘票票系统前后端完全制作(除支付外)》

我的页分为登录、注册、我的&#xff0c;如果登录了那么就显示我的页面否则显示登录页。 登录页&#xff1a; 我的页&#xff1a; 一、登录页制作 1.1 登录头制作 首先我们创建一个行&#xff0c;命名为登录块&#xff0c;设置高度为包裹&#xff1a; 之后将会在这个行中…

【NOIP2010】【P1317】乌龟棋

似乎很像搜索的DP&#xff08;应该也可以用搜索写&#xff09; 原题&#xff1a; 小明过生日的时候&#xff0c;爸爸送给他一副乌龟棋当作礼物。乌龟棋的棋盘是一行N 个格子&#xff0c;每个格子上一个分数&#xff08;非负整数&#xff09;。棋盘第1格是唯一的起点&#xff0c…

mysql添加普通用户用于管理单一数据库

2019独角兽企业重金招聘Python工程师标准>>> 使用phpmyadmin进行操作 创建用户&#xff0c;输入密码 关键选择&#xff1a;勾选 Create database with same name and grant all privileges 其他权限一律不要勾选 转载于:https://my.oschina.net/u/2485194/blog/5491…

C# 11 新特性:接口中的静态抽象成员

之前假设我们有一个非常复杂的数学运算方法&#xff1a;public static int Calc(int x, int y) > x y;但是&#xff0c;上述方法只能支持int类型。如果需要传入其它数字类型&#xff0c;需要再次定义&#xff1a;public static double Calc(double x, double y) > x y;…

四、一般页面制作《仿淘票票系统前后端完全制作(除支付外)》

一、播放影片影院页制作 上一节已经做完了首页所有栏目内容&#xff0c;那么点击购票后应该出现对应有购票的影院&#xff0c;选择影院后进入购买票务页。 首先新建一个页面命名为播放该影片的影院&#xff1a; 接着复制首页中的标题栏到播放影片的影院页中&#xff0c;此时…

700行无用 纯 CSS 祝考生 金榜高粽《1_bit 的无用 CSS 代码 》

今天才想起来这回事&#xff0c;没办法就急急忙忙的赶工一下&#xff0c;接下来我就画一下这个海报试试手了&#xff1a; 一、背景制作 1.1 准备工作 先给整个网页制作一个布局吧&#xff0c;直接 flex 搞定&#xff0c;并且使其居中 justify-content、align-items 都要赋值为…

【CASS精品教程】win10安装CAD+CASS过程中出现的错误问题及解决办法集锦

文章目录 1. 无法安装2. 提示DWF Viewer、AutoCAD2008未安装3. 安装完成后一直出现如下窗口4. Win10 64位 cass9.1+cad2008打开后出现Frame主框架程序没有加载。5. 注册程序无法运行,提示由于无法安装此service pack。1. 无法安装 解决办法:开启Administrator,以管理员身份…

(01).NET MAUI实战 建项目

1.概要本系列文章将会针对.NET MAUI实战开发的一些内容&#xff0c;会长期不间断更新我了解学习到的内容。当学习新的软件开发技术时&#xff0c;都会从基础建项目开始MAUI也不例外。ref&#xff1a;https://docs.microsoft.com/zh-cn/dotnet/maui/get-started/first-app?pivo…

Android Studio 引用aar包 更新后找不到新增的方法问题(踩坑)

明明已经更新了aar文件&#xff0c;但死活找不到新增的方法&#xff0c;代码提示里也找不到新增的方法名&#xff0c;但编译能编译&#xff0c;运行也一切正常&#xff0c;只是IDE一直提示错误&#xff0c;有强迫症的小猿好几天都想不明白。 其间有高手指教说&#xff1a;“那…

Asp.net 批量导入Excel用户数据功能加强版

平时我们用Asp.net导入用户&#xff0c;一般是提供一个用户Excel表的模板&#xff0c;实际导入数据时并非有些人愿意按你的模版制表&#xff0c;因此对Asp.net导入功能进行加强&#xff0c;可以导入非模版化的Excel数据&#xff0c;并且支持一次处理多个Sheet表&#xff0c;方便…

C#+Signalr+Vue实现B站视频自动回复评论,当一个最懒程序员!

Part1前言前几天刷到了程序员鱼皮的自动回复视频评论的视频&#xff0c;于是我也想来试试&#xff01;Part2开始第一步打开想要自动回复评论的视频url&#xff0c;打开调试模式&#xff01;然后找到可以触发评论的网络请求可以看到我们的oid是可以唯一确定视频的id,那么这个oid…

一张图不用,纯CSS 做个生日贺卡

朋友生日了&#xff0c;直接画&#xff0c;炫技并且表示本人闲的全身疼才会去拿CSS画画&#xff0c;以此嘲弄对方的加班&#xff1a; 既然贺卡做出来了&#xff0c;那就顺便介绍一下贺卡制作流程吧&#xff0c;其实也不是什么技术&#xff0c;也就是CSS 拼拼拼就可以了&#…

Android Notification总结

Android Notification总结 目录[-] &#xfeff;&#xfeff;一、通知的主要功能 二、通知简介 三、通知的使用流程 四、使用NotificationCompat.Builder设置通知的属性&#xff1a; 五、管理通知 &#xfeff;&#xfeff;一、通知的主要功能 显示接收到短消息、即使消息等信…