MSM8909+Android5.1.1启动流程(8)---boot_linux()和kernel入口
Smem:sharedmemory
上一篇:MSM8909+Android5.1.1启动流程(7)---boot_linux_from_mmc()
/bootable/bootloader/lk/app/aboot/aboot.c中的boot_linux()函数主要实现了内核引导参数参数的处理过程。
typedef void entry_func_ptr(unsigned,unsigned, unsigned*);
void boot_linux(void *kernel, unsigned*tags,
constchar *cmdline, unsigned machtype,
void*ramdisk, unsigned ramdisk_size)
{
unsignedchar *final_cmdline;
#if DEVICE_TREE
intret = 0;
#endif
void(*entry)(unsigned, unsigned, unsigned*) =(entry_func_ptr*)(PA((addr_t)kernel));//kernel是内核入口地址
uint32_ttags_phys = PA((addr_t)tags);//设备树在内存的地址
structkernel64_hdr *kptr = (struct kernel64_hdr*)kernel;
ramdisk= PA(ramdisk);
cmdline指向的命令行数据如下:
ttyHSL0,115200,n8 androidboot.console=ttyHSL0androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3androidboot.bootdevice=7824900.sdhci lpm_levels.sleep_disabled=1 earlyprintk
更新cmdline后,多增加了androidboot.emmc=trueandroidboot.seria[1010]
然后把更新后的cmdline写到tags_addr地址,把参数传给kernel,kernel起来以后会到这个地址读取参数。
final_cmdline= update_cmdline((const char*)cmdline);
dprintf(INFO, "Updating device tree:start\n");
//更新设备树,主要包括:
1.通过smem(共享内存)得到可用内存的分区表
2.找到/memory节点下根据得到可用内存的开始地址(addr)创建一个reg节点,并addr和size赋值:reg = ;
3.找到/chosen节点,把cmdline内容追加到bootargs属性后面,下面是追加之前的:
chosen {
bootargs= "sched_enable_hmp=1";
};
4.在/chosen节点下面创建"linux,initrd-start"和"linux,initrd-end"属性,并分别用ramdisk和(ramdisk +ramdisk_size)赋值
/*Update the Device Tree */
ret= update_device_tree((void *)tags, final_cmdline, ramdisk, ramdisk_size);
if(ret)
{
dprintf(CRITICAL,"ERROR: Updating Device Tree Failed \n");
ASSERT(0);
}
dprintf(INFO,"Updating device tree: done\n");
//具体target的清理
/* Perform target specific cleanup */
target_uninit();
/*Turn off splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
target_display_shutdown();
#endif
dprintf(INFO,"booting linux @ %p, ramdisk @ %p (%d), tags/device tree @ %p\n",
entry,ramdisk, ramdisk_size, tags_phys);
enter_critical_section();
/*do any platform specific cleanup before kernel entry */
platform_uninit();
//禁用cache
arch_disable_cache(UCACHE);
#if ARM_WITH_MMU
arch_disable_mmu();
#endif
bs_set_timestamp(BS_KERNEL_ENTRY);
//msm8909是32位的
if(IS_ARM64(kptr))
/*Jump to a 64bit kernel */
scm_elexec_call((paddr_t)kernel,tags_phys);
else
/*Jump to a 32bit kernel */
entry(0,machtype, (unsigned*)tags_phys);
}
我们是msm8909平台,就调用entry(0,machtype, (unsigned*)tags_phys)
entry函数地址在boot_linux()刚开始这样赋值:
void (*entry)(unsigned, unsigned,unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel));
uint32_t tags_phys = PA((addr_t)tags);
kernel和tags地址由\bootable\bootloader\lk\project\msm8909.mk定义如下:
DEFINES+=ABOOT_FORCE_KERNEL_ADDR=0x80008000
DEFINES +=ABOOT_FORCE_TAGS_ADDR=0x81E00000
那entry对应的入口函数是哪个呢,我们知道boot.img由文件头(2k/4k)+kernel+ramdisk.img(根文件系统)+dt.img(device tree)组成
要知道入口函数是哪个,就要先知道boot.img是怎么编译生成的
\kernel\arch\arm\boot\Makefile
INSTALLED_KERNEL_TARGET :=$(PRODUCT_OUT)/kernel
BUILT_RAMDISK_TARGET :=$(PRODUCT_OUT)/ramdisk.img
# We just build this directly to theinstall location.
INSTALLED_RAMDISK_TARGET :=$(BUILT_RAMDISK_TARGET)
# the boot image, which is a collection ofother images.
INTERNAL_BOOTIMAGE_ARGS := \
$(addprefix--second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
--kernel$(INSTALLED_KERNEL_TARGET) \
--ramdisk$(INSTALLED_RAMDISK_TARGET)
Kernel的入口是stext,在arch/arm/kernel/vmlinux.lds.S中定义的:
ENTRY(stext)// 表示程序的入口是在符号stext
#ifndef __ARMEB__
jiffies = jiffies_64;
#else
jiffies = jiffies_64 + 4;
#endif
SECTIONS
{
#ifdefCONFIG_XIP_KERNEL
.= XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
.= PAGE_OFFSET + TEXT_OFFSET;
#endif
.head.text: {
_text= .;
HEAD_TEXT
}
…
}
这里的PAGE_OFFSET在\kernel\arch\arm\Kconfig中定义如下:
config PAGE_OFFSET
hex
default0x40000000 if VMSPLIT_1G
default0x80000000 if VMSPLIT_2G
default0xC0000000
TEXT_OFFSET的值是0x00008000在\kernel\arch\arm\Makefile中定义如下:
# defines filename extension depending memorymanagement type.
ifeq ($(CONFIG_MMU),)//实际上CONFIG_MMU=y,所以MMUEXT为空
MMUEXT :=-nommu
KBUILD_CFLAGS += $(call cc-option,-mno-unaligned-access)
Endif
head-y :=arch/arm/kernel/head$(MMUEXT).o//也就是head.o,y表示yes
textofs-y :=0x00008000
# The byte offset of the kernel image inRAM from the start of RAM.
TEXT_OFFSET := $(textofs-y)
符号stext是在arch/arm/kernel/head.S中定义,从head-y :=arch/arm/kernel/head$(MMUEXT).o也可看出来
/*
*Kernel startup entry point.
*---------------------------
*
*This is normally called from the decompressor code. The requirements
*are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
* r1= machine nr, r2 = atags or dtb pointer.
*
*This code is mostly position independent, so if you link the kernel at
*0xc0008000, you call this at __pa(0xc0008000).
*
*See linux/arch/arm/tools/mach-types for the complete list of machine
*numbers for r1.
*
*We're trying to keep crap to a minimum; DO NOT add any machine specific
*crap here - that's what the boot loader (or in extreme, well justified
*circumstances, zImage) is for.
*/
.arm
__HEAD
ENTRY(stext)
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
…
参考链接:
Android bootloader—LK的分析之如何解析boot.img
arm linux kernel 从入口到start_kernel 的代码分析
ARM linux kernel启动流程 head.S