(2) 调用target_volume_down()和target_volume_up()函数判断音量+-按键是否按下,如果按下,就设置key_bitmap[]对应的位为1,比如key_bitmap[KEY_VOLUMEDOWN]=1,这为后面进入线刷、recovery、还是正常启动模式做好判断依据。
这里音量+-是根据GPIO_90和GPIO_91的引脚来判断的。
1.3 target_sdc_init()
调用platform_boot_dev_isemmc()判断启动设备是否是EMMC,如果是就调用target_sdc_init()来初始化SDC(Secure digital controller)控制器接口 Sdc:Secure digital controllerinterface-supports EMMC
1.4 partition_read_table()
先读取MMC的MBR分区,如果是PMBR分区就读取GPT分区信息。 MBR(Master Boot Record)和GPT(GUID Partition Table).
《MBR和GPT概要学习》:
http://www.voidcn.com/blog/LoongEmbedded/article/p-6072230.html
1.4.1 mmc_get_device_blocksize() 获取EMMC的块大小,为512个字节。 1.4.2 mmc_boot_read_mbr() 读取EMMC的MBR
(1) 调用mmc_read()从0地址开始读取512字节的数据到buff中。
(2) partition_verify_mbr_signature()对读取出来数据的进行MBR签名核查。
如果buff[510]不等于0x55,或是buff[511]不等于0xAA,就说明MBR signature不匹配 (3) 在MBR中读取4个分区信息到我们的MBR表
EMMC的MBR由4部分组成,这里是要读分区表信息,其中包含4个分区项,偏移地址是01BEH--01FDH,每个分区表项长16个字节,共64字节为分区项1、分区项2、分区项3、分区项4
读取每个16字节的分区项时,先读取第5个字节对应的分区类型,如果为0xEE 表示该分区表是PMBR,紧随其后的应该是GPT分区表头和GPT分区表,因此这是一块GPT硬盘。 这里读取出来的值就是0xEE,表示此MMC采用GPT分区结构,如果不是,就按照MBR分区结构读取后面的分区信息
1.4.3 mmc_boot_read_gpt(),从MMC中读取GPT信息并填充分区表
GPT分区全名为GloballyUnique Identifier Partition Table Format,即全局唯一标示磁盘分区表格式
(1) mmc_get_device_capacity()获取MMC设备的密度,其值为1 (2) mmc_read()读取第1个扇区内容(第0个扇区是PMBR)。
(3) partition_parse_gpt_header()解析GPT分区表头,如果解析失败再去读取备份GPT分区表头
先读取和解析GPT分区表头,因为GPT分区表信息没有被破坏,就没有去读取备份分区表头信息。
1) 判断GPT头的大小,92个字节。
2) 计算GPT头的CRC并和之前写入的GPT头的CRC对比。 3) 读取GPT头的LBA和分区表项值 具体信息如下:
偏移地址24:当前的LBA(这个GPT头的位),这里为1
偏移地址40:第一个可用于分区的LBA(主分区表的最后一个LBA+1)
偏移地址48:最有一个可用于分区的LBA(备份分区表的第一个LBA-1) 偏移地址80:分区表项的数量,这里为32个
偏移地址84:一个分区表项的大小(通常为128),这里为128
分区表头的格式
起始长度 内容 字节 0
8字签名(\PART\) 节 8
4字修订 节
12 4字分区表头的大小
节
16 4字分区表头(第0-91字节)的CRC32校验,在计算时,把这个字段作为0处理,
节 需要计算出分区串行的CRC32校验后再计算本字段 20 4字保留,必须是 0
节
24 8字当前LBA(这个分区表头的位置)
节
32 8字备份LBA(另一个分区表头的位置)
节
40 8字第一个可用于分区的LBA(主分区表的最后一个LBA + 1)
节
48 8字最后一个可用于分区的LBA(备份分区表的第一个LBA ? 1)
节
56 16字硬盘GUID(在类UNIX系统中也叫UUID)
节
72 8字分区表项的起始LBA(在主分区表中是2)
节
80 4字分区表项的数量
节
84 4字一个分区表项的大小(通常是128)
节
88 4字分区串行的CRC32校验
节 92
(4) 读取GPT分区表中的分区信息,从第2~9个block读取,然后写入到记录分区信息的全局数组中partition_entrie[]
每个entry(分区表项)占128字节,所以一个block包含4个分区表项,而我们分区表项数量是32个,需要32/4=8个block。
GPT分区表项的格式
起始字节 长度
内容
* 保留,剩余的字节必须是0(对于512字节LBA的硬盘即是420个字节)
16字节 分区类型GUID 0
分区GUID 161 6字节
起始LBA(小端格式) 32 8字节 末尾LBA 40 8字节
属性标签(如:60表示\只读\) 48 8字节
分区名(可以包括36个UTF-16(小端格式)字符) 567 2字节
对应的结构体定义如下
/* Unified mbr and gpt entry types */struct partition_entry {
unsignedchar type_guid[PARTITION_TYPE_GUID_SIZE]; unsigneddtype;
unsignedchar unique_partition_guid[UNIQUE_PARTITION_GUID_SIZE];
unsignedlong long first_lba; unsignedlong long last_lba; unsignedlong long size;
unsignedlong long attribute_flag; unsignedchar name[MAX_GPT_NAME_SIZE]; uint8_tlun; };
到此partition_entry关于GPT分区表项的信息已获知。 1.5 shutdown_detect() #if LONG_PRESS_POWER_ON
shutdown_detect();#endif
如果开启长按power按键开机(大概2~3s)机制,就会调用此函数,如果按power按键时间短于这个时间,就会关机。
1.6 target_use_signed_kernel() if (target_use_signed_kernel())
target_crypto_init_params();
target_use_signed_kernel()函数在bootloader/lk/target/init.c实现 __WEAK booltarget_use_signed_kernel(void){#if _SIGNED_KERNEL return1;#else return0;#endif }
没有定义_SIGNED_KERNEL,所以直接返回0,也就没调用target_crypto_init_params()。
1.7 rpm_smd_init() #if SMD_SUPPORT
rpm_smd_init();#endif