android linux 5.1.1,MSM8909+Android5.1.1启动流程(8)---boot_linux()和kernel入口

席波娃
2023-12-01

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

 类似资料: