android bootloader (lk)
分类:Android 2011-08-25 20:39 941人阅读 评论(0) 收藏 举报 android descriptor thread timer list linux
http://hi.baidu.com/ktpeng/blog/item/9872d589666b0d03c8fc7a96.html
(L)ittle (K)ernelbootloader
1.主要功能,红色部分是android特有的一些功能,如fastboot,recovery模式等:
* Variety of nand devices for bootup
* USB driver to enable upgrading images over usb during development
* Keypad driver to enable developers enter ‘fastboot’ mode for image upgrades
* Display driver for debugging and splash screen
* Enable Android recovery image and image upgrades
2.配置dram内存大小,供linux kernel使用
The memory tags can be customized inlk/target/<target_name>/atags.c
3.fastboot模式,可以自行打开或者关闭
如,在boot中关闭按键或者usb 驱动,都可以达到此目的
相关文件
k/app/aboot/fastboot.c
lk/app/aboot/aboot.c
4.MTD block setting
可以配置各个mtd image 分区在如下文件中
lk\target\tcc8900_evm\init.c
static struct ptentry board_part_list[]
5.打开或者关闭splash screen in the bootloader
DISPLAY_SPLASH_SCREEN功能可以来打开关闭
开机时候,boot会从’splash’ MTD分区中读取原始的文件到framebuffer中显示,所以也需要加载display 的驱动
*****************************************************************************************************************************************************************************************
http://blog.csdn.net/hankhanti/article/details/6133570
Android Boot loader 的 code 在 bootable/bootloader/lk 底下, LK 是 Little Kernel 的缩写, 是 andriod bootloader 的核心精神.
入口函数在 kernel/main.c 中的 kmain(), 以下就来读读这一段 code.
- voidkmain(void)
- {
- //getusintosomesortofthreadcontext
- thread_init_early();
- //earlyarchstuff
- arch_early_init();
- //doanysuperearlyplatforminitialization
- platform_early_init();
- //doanysuperearlytargetinitialization
- target_early_init();
- dprintf(INFO,"welcometolk/n/n");
- //dealwithanystaticconstructors
- dprintf(SPEW,"callingconstructors/n");
- call_constructors();
- //bringupthekernelheap
- dprintf(SPEW,"initializingheap/n");
- heap_init();
- //initializethethreadingsystem
- dprintf(SPEW,"initializingthreads/n");
- thread_init();
- //initializethedpcsystem
- dprintf(SPEW,"initializingdpc/n");
- dpc_init();
- //initializekerneltimers
- dprintf(SPEW,"initializingtimers/n");
- timer_init();
- #if(!ENABLE_NANDWRITE)
- //createathreadtocompletesysteminitialization
- dprintf(SPEW,"creatingbootstrapcompletionthread/n");
- thread_resume(thread_create("bootstrap2",&bootstrap2,NULL,DEFAULT_PRIORITY,DEFAULT_STACK_SIZE));
- //enableinterrupts
- exit_critical_section();
- //becometheidlethread
- thread_become_idle();
- #else
- bootstrap_nandwrite();
- #endif
- }
In include/debug.h: 我们可以看到 dprintf 的第一个参数是代表 debug level.
view plain print ?
- /*debuglevels*/
- #defineCRITICAL0
- #defineALWAYS0
- #defineINFO1
- #defineSPEW2
In include/debug.h:
view plain print ?
- #definedprintf(level,x...)do{if((level)<=DEBUGLEVEL){_dprintf(x);}}while(0)
所以 dprintf 会依 DEBUGLEVEL 来判断是否输出信息.
来看第一个 call 的函数: thread_init_early, define in thread.c
view plain print ?
- voidthread_init_early(void)
- {
- inti;
- /*initializetherunqueues*/
- for(i=0;i<NUM_PRIORITIES;i++)
- list_initialize(&run_queue[i]);
- /*initializethethreadlist*/
- list_initialize(&thread_list);
- /*createathreadtocoverthecurrentrunningstate*/
- thread_t*t=&bootstrap_thread;
- init_thread_struct(t,"bootstrap");
- /*halfconstructthisthread,sincewe'realreadyrunning*/
- t->priority=HIGHEST_PRIORITY;
- t->state=THREAD_RUNNING;
- t->saved_critical_section_count=1;
- list_add_head(&thread_list,&t->thread_list_node);
- current_thread=t;
- }
#define NUM_PRIORITIES 32 in include/kernel/thread.h
list_initialize() defined in include/list.h: initialized a list
view plain print ?
- staticinlinevoidlist_initialize(structlist_node*list)
- {
- list->prev=list->next=list;
- }
run_queue 是static struct list_node run_queue[NUM_PRIORITIES]
thread_list 是static struct list_node thread_list
再来要 call 的函数是: arch_early_init() defined inarch/arm/arch.c
view plain print ?
- voidarch_early_init(void)
- {
- /*turnoffthecache*/
- arch_disable_cache(UCACHE);
- /*setthevectorbasetoourexceptionvectorssowedontneedtodoublemapat0*/
- #ifARM_CPU_CORTEX_A8
- set_vector_base(MEMBASE);
- #endif
- #ifARM_WITH_MMU
- arm_mmu_init();
- platform_init_mmu_mappings();
- #endif
- /*turnthecachebackon*/
- arch_enable_cache(UCACHE);
- #ifARM_WITH_NEON
- /*enablecp10andcp11*/
- uint32_tval;
- __asm__volatile("mrcp15,0,%0,c1,c0,2":"=r"(val));
- val|=(3<<22)|(3<<20);
- __asm__volatile("mcrp15,0,%0,c1,c0,2"::"r"(val));
- /*setenablebitinfpexc*/
- val=(1<<30);
- __asm__volatile("mcrp10,7,%0,c8,c0,0"::"r"(val));
- #endif
- }
现代操作系统普遍采用虚拟内存管理(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
view plain print ?
- voidplatform_early_init(void)
- {
- uart_init();
- platform_init_interrupts();
- platform_init_timer();
- }
uart_init.c defined in platform/<your-platform>/uart.c 所有用到的变数,也都定义在 uart.c
view plain print ?
- voiduart_init(void)
- {
- uwr(0x0A,UART_CR);/*disableTXandRX*/
- uwr(0x30,UART_CR);/*reseterrorstatus*/
- uwr(0x10,UART_CR);/*resetreceiver*/
- uwr(0x20,UART_CR);/*resettransmitter*/
- #ifPLATFORM_QSD8K
- /*TCXO*/
- uwr(0x06,UART_MREG);
- uwr(0xF1,UART_NREG);
- uwr(0x0F,UART_DREG);
- uwr(0x1A,UART_MNDREG);
- #else
- /*TCXO/4*/
- uwr(0xC0,UART_MREG);
- uwr(0xAF,UART_NREG);
- uwr(0x80,UART_DREG);
- uwr(0x19,UART_MNDREG);
- #endif
- uwr(0x10,UART_CR);/*resetRX*/
- uwr(0x20,UART_CR);/*resetTX*/
- uwr(0x30,UART_CR);/*reseterrorstatus*/
- uwr(0x40,UART_CR);/*resetRXbreak*/
- uwr(0x70,UART_CR);/*rest?*/
- uwr(0xD0,UART_CR);/*reset*/
- uwr(0x7BF,UART_IPR);/*staletimeout=630*bitrate*/
- uwr(0,UART_IMR);
- uwr(115,UART_RFWR);/*RXwatermark=58*2-1*/
- uwr(10,UART_TFWR);/*TXwatermark*/
- uwr(0,UART_RFWR);
- uwr(UART_CSR_115200,UART_CSR);
- uwr(0,UART_IRDA);
- uwr(0x1E,UART_HCR);
- //uwr(0x7F4,UART_MR1);/*RFS/CTS/500chrRFR*/
- uwr(16,UART_MR1);
- uwr(0x34,UART_MR2);/*8N1*/
- uwr(0x05,UART_CR);/*enableTX&RX*/
- uart_ready=1;
- }
platform_init_interrupts: defined in platform/msm8x60/interrupts.c
view plain print ?
- voidplatform_init_interrupts(void)
- {
- platform_gic_dist_init();
- platform_gic_cpu_init();
- }
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
view plain print ?
- voidplatform_init_timer(void)
- {
- writel(0,DGT_ENABLE);
- }
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
view plain print ?
- /*
- *defaultimplementationsoftheseroutines,ifthetargetcode
- *choosesnottoimplement.
- */
- __WEAKvoidtarget_early_init(void)
- {
- }
- __WEAKvoidtarget_init(void)
- {
- }
call_constructors() is defined in kernel/main.c:
view plain print ?
- staticvoidcall_constructors(void)
- {
- void**ctor;
- ctor=&__ctor_list;
- while(ctor!=&__ctor_end){
- void(*func)(void);
- func=(void(*)())*ctor;
- func();
- ctor++;
- }
- }
heap_init is defined in lib/heap/heap.c:
view plain print ?
- voidheap_init(void)
- {
- LTRACE_ENTRY;
- //settheheaprange
- theheap.base=(void*)HEAP_START;
- theheap.len=HEAP_LEN;
- LTRACEF("base%psize%zdbytes/n",theheap.base,theheap.len);
- //initializethefreelist
- list_initialize(&theheap.free_list);
- //createaninitialfreechunk
- heap_insert_free_chunk(heap_create_free_chunk(theheap.base,theheap.len));
- //dumpheapinfo
- //heap_dump();
- //dprintf(INFO,"runningheaptests/n");
- //heap_test();
- }
thread_init is defined in kernel/thread.c but nothing coded, 先记下.
view plain print ?
- voidthread_init(void)
- {
- }
dpc_init() is defined in kernel/dpc.c:
view plain print ?
- voiddpc_init(void)
- {
- event_init(&dpc_event,false,0);
- thread_resume(thread_create("dpc",&dpc_thread_routine,NULL,DPC_PRIORITY,DEFAULT_STACK_SIZE));
- }
dpc 为 Delayed Procedure Call 延迟过程调用的缩写.
timer_init() is defined in kernel/timer.c:
view plain print ?
- voidtimer_init(void)
- {
- list_initialize(&timer_queue);
- /*registerforaperiodictimertick*/
- platform_set_periodic_timer(timer_tick,NULL,10);/*10ms*/
- }
执行 thread_resume 或是 bootstrap_nandwrite
view plain print ?
- #if(!ENABLE_NANDWRITE)
- //createathreadtocompletesysteminitialization
- dprintf(SPEW,"creatingbootstrapcompletionthread/n");
- thread_resume(thread_create("bootstrap2",&bootstrap2,NULL,DEFAULT_PRIORITY,DEFAULT_STACK_SIZE));
- //enableinterrupts
- exit_critical_section();
- //becometheidlethread
- thread_become_idle();
- #else
- bootstrap_nandwrite();
- #endif
In kermel/main.c:
view plain print ?
- staticintbootstrap2(void*arg)
- {
- dprintf(SPEW,"topofbootstrap2()/n");
- arch_init();
- //initializetherestoftheplatform
- dprintf(SPEW,"initializingplatform/n");
- platform_init();
- //initializethetarget
- dprintf(SPEW,"initializingtarget/n");
- target_init();
- dprintf(SPEW,"callingapps_init()/n");
- apps_init();
- return0;
- }
- #if(ENABLE_NANDWRITE)
- voidbootstrap_nandwrite(void)
- {
- dprintf(SPEW,"topofbootstrap2()/n");
- arch_init();
- //initializetherestoftheplatform
- dprintf(SPEW,"initializingplatform/n");
- platform_init();
- //initializethetarget
- dprintf(SPEW,"initializingtarget/n");
- target_init();
- dprintf(SPEW,"callingnandwrite_init()/n");
- nandwrite_init();
- return0;
- }
- #endif
continue to see apps_init():app/app.c:void apps_init(void)
view plain print ?
- #include<app.h>
- #include<kernel/thread.h>
- externconststructapp_descriptor__apps_start;
- externconststructapp_descriptor__apps_end;
- staticvoidstart_app(conststructapp_descriptor*app);
- /*onetimesetup*/
- voidapps_init(void)
- {
- conststructapp_descriptor*app;
- /*callalltheinitroutines*/
- for(app=&__apps_start;app!=&__apps_end;app++){
- if(app->init)
- app->init(app);
- }
- /*startanythatwanttostartonboot*/
- for(app=&__apps_start;app!=&__apps_end;app++){
- if(app->entry&&(app->flags&APP_FLAG_DONT_START_ON_BOOT)==0){
- start_app(app);
- }
- }
- }
- staticintapp_thread_entry(void*arg)
- {
- conststructapp_descriptor*app=(conststructapp_descriptor*)arg;
- app->entry(app,NULL);
- return0;
- }
- staticvoidstart_app(conststructapp_descriptor*app)
- {
- printf("startingapp%s/n",app->name);
- thread_resume(thread_create(app->name,&app_thread_entry,(void*)app,DEFAULT_PRIORITY,DEFAULT_STACK_SIZE));
- }
至于会有那些 app 被放入 boot thread section, 则定义在 include/app.h 中的 APP_START(appname)
view plain print ?
- #defineAPP_START(appname)structapp_descriptor_app_##appname__SECTION(".apps")={.name=#appname,
- #defineAPP_END};
在 app 中只要像 app/aboot/aboot.c 指定就会在 bootloader bootup 时放入 thread section 中被执行.
view plain print ?
- APP_START(aboot)
- .init=aboot_init,
- APP_END
在我的 bootloader 中有 app/aboot/aboot.c, app/tests/tests.c, app/shell/shell.c, 及 app/stringtests/string_tests.c 皆有此声明.
接下来关注: aboot.c 中的 aboot_init()
view plain print ?
- voidaboot_init(conststructapp_descriptor*app)
- {
- unsignedreboot_mode=0;
- unsigneddisp_init=0;
- unsignedusb_init=0;
- //test_ram();
- /*Setuppagesizeinformationfornand/emmcreads*/
- if(target_is_emmc_boot())
- {
- page_size=2048;
- page_mask=page_size-1;
- }
- else
- {
- page_size=flash_page_size();
- page_mask=page_size-1;
- }
- /*Displaysplashscreenifenabled*/
- #ifDISPLAY_SPLASH_SCREEN
- display_init();
- dprintf(INFO,"Diplayinitialized/n");
- disp_init=1;
- diplay_image_on_screen();
- #endif
- /*Checkifweshoulddosomethingotherthanbootingup*/
- if(keys_get_state(KEY_HOME)!=0)
- boot_into_recovery=1;
- if(keys_get_state(KEY_BACK)!=0)
- gotofastboot;
- if(keys_get_state(KEY_CLEAR)!=0)
- gotofastboot;
- #ifNO_KEYPAD_DRIVER
- /*Withnokeypadimplementation,checkthestatusofUSBconnection.*/
- /*IfUSBisconnectedthengointofastbootmode.*/
- usb_init=1;
- udc_init(&surf_udc_device);
- if(usb_cable_status())
- gotofastboot;
- #endif
- init_vol_key();
- if(voldown_press())
- gotofastboot;
- reboot_mode=check_reboot_mode();
- if(reboot_mode==RECOVERY_MODE){
- boot_into_recovery=1;
- }elseif(reboot_mode==FASTBOOT_MODE){
- gotofastboot;
- }
- if(target_is_emmc_boot())
- {
- boot_linux_from_mmc();
- }
- else
- {
- recovery_init();
- boot_linux_from_flash();
- }
- dprintf(CRITICAL,"ERROR:Couldnotdonormalboot.Reverting"
- "tofastbootmode./n");
- fastboot:
- if(!usb_init)
- udc_init(&surf_udc_device);
- fastboot_register("boot",cmd_boot);
- if(target_is_emmc_boot())
- {
- fastboot_register("flash:",cmd_flash_mmc);
- fastboot_register("erase:",cmd_erase_mmc);
- }
- else
- {
- fastboot_register("flash:",cmd_flash);
- fastboot_register("erase:",cmd_erase);
- }
- fastboot_register("continue",cmd_continue);
- fastboot_register("reboot",cmd_reboot);
- fastboot_register("reboot-bootloader",cmd_reboot_bootloader);
- fastboot_publish("product",TARGET(BOARD));
- fastboot_publish("kernel","lk");
- fastboot_init(target_get_scratch_address(),120*1024*1024);
- udc_start();
- target_battery_charging_enable(1,0);
- }
target_is_emmc_boot() is defined in target/init.c: _EMMC_BOOT 是 compiler 时的 flags
view plain print ?
- __WEAKinttarget_is_emmc_boot(void)
- {
- #if_EMMC_BOOT
- return1;
- #else
- return0;
- #endif
- }
check_reboot_mode is defined in target/<your-platform>/init.c:
view plain print ?
- unsignedcheck_reboot_mode(void)
- {
- unsignedrestart_reason=0;
- void*restart_reason_addr=0x401FFFFC;
- /*Readrebootreasonandscrubit*/
- restart_reason=readl(restart_reason_addr);
- writel(0x00,restart_reason_addr);
- returnrestart_reason;
- }
reboot mode in bootloader:
view plain print ?
- #defineRECOVERY_MODE0x77665502
- #defineFASTBOOT_MODE0x77665500
再来就会执行boot_linux_from_mmc():
view plain print ?
- intboot_linux_from_mmc(void)
- {
- structboot_img_hdr*hdr=(void*)buf;
- structboot_img_hdr*uhdr;
- unsignedoffset=0;
- unsignedlonglongptn=0;
- unsignedn=0;
- constchar*cmdline;
- uhdr=(structboot_img_hdr*)EMMC_BOOT_IMG_HEADER_ADDR;
- if(!memcmp(uhdr->magic,BOOT_MAGIC,BOOT_MAGIC_SIZE)){
- dprintf(INFO,"Unifiedbootmethod!/n");
- hdr=uhdr;
- gotounified_boot;
- }
- if(!boot_into_recovery)
- {
- ptn=mmc_ptn_offset("boot");
- if(ptn==0){
- dprintf(CRITICAL,"ERROR:Nobootpartitionfound/n");
- return-1;
- }
- }
- else
- {
- ptn=mmc_ptn_offset("recovery");
- if(ptn==0){
- dprintf(CRITICAL,"ERROR:Norecoverypartitionfound/n");
- return-1;
- }
- }
- if(mmc_read(ptn+offset,(unsignedint*)buf,page_size)){
- dprintf(CRITICAL,"ERROR:Cannotreadbootimageheader/n");
- return-1;
- }
- if(memcmp(hdr->magic,BOOT_MAGIC,BOOT_MAGIC_SIZE)){
- dprintf(CRITICAL,"ERROR:Invaledbootimageheader/n");
- return-1;
- }
- if(hdr->page_size&&(hdr->page_size!=page_size)){
- page_size=hdr->page_size;
- page_mask=page_size-1;
- }
- offset+=page_size;
- n=ROUND_TO_PAGE(hdr->kernel_size,page_mask);
- if(mmc_read(ptn+offset,(void*)hdr->kernel_addr,n)){
- dprintf(CRITICAL,"ERROR:Cannotreadkernelimage/n");
- return-1;
- }
- offset+=n;
- n=ROUND_TO_PAGE(hdr->ramdisk_size,page_mask);
- if(mmc_read(ptn+offset,(void*)hdr->ramdisk_addr,n)){
- dprintf(CRITICAL,"ERROR:Cannotreadramdiskimage/n");
- return-1;
- }
- offset+=n;
- unified_boot:
- dprintf(INFO,"/nkernel@%x(%dbytes)/n",hdr->kernel_addr,
- hdr->kernel_size);
- dprintf(INFO,"ramdisk@%x(%dbytes)/n",hdr->ramdisk_addr,
- hdr->ramdisk_size);
- if(hdr->cmdline[0]){
- cmdline=(char*)hdr->cmdline;
- }else{
- cmdline=DEFAULT_CMDLINE;
- }
- dprintf(INFO,"cmdline='%s'/n",cmdline);
- dprintf(INFO,"/nBootingLinux/n");
- boot_linux((void*)hdr->kernel_addr,(void*)TAGS_ADDR,
- (constchar*)cmdline,board_machtype(),
- (void*)hdr->ramdisk_addr,hdr->ramdisk_size);
- return0;
- }
mmc_read() is defined in platform/<your-platform>/mmc.c:
view plain print ?
- unsignedintmmc_read(unsignedlonglongdata_addr,unsignedint*out,unsignedintdata_len)
- {
- intval=0;
- val=mmc_boot_read_from_card(&mmc_host,&mmc_card,data_addr,data_len,out);
- returnval;
- }
boot_linux(): 启动 Linux, 看看函数定义
view plain print ?
- voidboot_linux(void*kernel,unsigned*tags,
- constchar*cmdline,unsignedmachtype,
- void*ramdisk,unsignedramdisk_size)
- {
- unsigned*ptr=tags;
- unsignedpcount=0;
- void(*entry)(unsigned,unsigned,unsigned*)=kernel;
- structptable*ptable;
- intcmdline_len=0;
- inthave_cmdline=0;
- intpause_at_bootup=0;
- /*CORE*/
- *ptr++=2;
- *ptr++=0x54410001;
- if(ramdisk_size){
- *ptr++=4;
- *ptr++=0x54420005;
- *ptr++=(unsigned)ramdisk;
- *ptr++=ramdisk_size;
- }
- ptr=target_atag_mem(ptr);
- if(!target_is_emmc_boot()){
- /*SkipNANDpartitionATAGSforeMMCboot*/
- if((ptable=flash_get_ptable())&&(ptable->count!=0)){
- inti;
- for(i=0;i<ptable->count;i++){
- structptentry*ptn;
- ptn=ptable_get(ptable,i);
- if(ptn->type==TYPE_APPS_PARTITION)
- pcount++;
- }
- *ptr++=2+(pcount*(sizeof(structatag_ptbl_entry)/
- sizeof(unsigned)));
- *ptr++=0x4d534d70;
- for(i=0;i<ptable->count;++i)
- ptentry_to_tag(&ptr,ptable_get(ptable,i));
- }
- }
- if(cmdline&&cmdline[0]){
- cmdline_len=strlen(cmdline);
- have_cmdline=1;
- }
- if(target_is_emmc_boot()){
- cmdline_len+=strlen(emmc_cmdline);
- }
- if(target_pause_for_battery_charge()){
- pause_at_bootup=1;
- cmdline_len+=strlen(battchg_pause);
- }
- if(cmdline_len>0){
- constchar*src;
- char*dst;
- unsignedn;
- /*includeterminating0androunduptoawordmultiple*/
- n=(cmdline_len+4)&(~3);
- *ptr++=(n/4)+2;
- *ptr++=0x54410009;
- dst=(char*)ptr;
- if(have_cmdline){
- src=cmdline;
- while((*dst++=*src++));
- }
- if(target_is_emmc_boot()){
- src=emmc_cmdline;
- if(have_cmdline)--dst;
- have_cmdline=1;
- while((*dst++=*src++));
- }
- if(pause_at_bootup){
- src=battchg_pause;
- if(have_cmdline)--dst;
- while((*dst++=*src++));
- }
- ptr+=(n/4);
- }
- /*END*/
- *ptr++=0;
- *ptr++=0;
- dprintf(INFO,"bootinglinux@%p,ramdisk@%p(%d)/n",
- kernel,ramdisk,ramdisk_size);
- if(cmdline)
- dprintf(INFO,"cmdline:%s/n",cmdline);
- enter_critical_section();
- platform_uninit_timer();
- arch_disable_cache(UCACHE);
- arch_disable_mmu();
- #ifDISPLAY_SPLASH_SCREEN
- display_shutdown();
- #endif
- entry(0,machtype,tags);
- }
配合 boot.img 来看会比较好理解.
由此可知boot_img_hdr中各成员值为:
TAGS_ADDR 如上 target/<your-platform>/rules.mk 所定义的 : 0x40200100,所以 boot_linux(), 就是传入TAGS_ADDR,
然后将资料写入 tag, tag 的结构如下所示.
然后进入到 kernel 的入口函数: entry(0, machtype, tags)
更多相关文章
- 内存管理Memory Management in Android
- Android(安卓)获得本机ip地址和MAC地址
- 内存管理Memory Management in Android
- Adnroid LearningNotes
- Android(安卓)复习笔记之图解Activity的4种加载模式
- Android中Activity启动模式详解
- android ICS4.0.3去掉相机全景模式
- Android硬件服务访问流程
- android 音频总结