linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)

linux驱动由浅入深系列:块设备驱动之二(从用户空间的read、write到实际设备物理操作整体架构分析)
linux驱动由浅入深系列:块设备驱动之三(块设备驱动结构分析,以mmc为例)

块设备驱动的模型还是基本基于字符设备驱动的,可以简单理解为块设备仅仅增加了操作缓冲区,对用户请求顺序进行队列重拍等等。字符设备驱动的相关分析可以查看本博客相关的博文。 

按照本博客的行文习惯,在具体分析块设备驱动代码之前,我们会从整体上了解一下研究对象的特征,以及用户空间的使用方法。下面我们就自己写一个小工具(可以读取Rom中任意一个物理扇区的内容)来分析一下高通的分区信息。

在用户空间看到的块设备当然是以块设备节点展现的,如下图。其中mmcblk开头的就是今天我们分析的重点,可以看到这些文件名分为三类:mmcblk0、mmcblk0pX、mmcblk0rpmb。其中mmcblk0是设备节点,其余的为该设备的分区节点(mmcblk0rpmb RPMB是Replay Protected Memory Block的缩写,他的存在目的是用来给系统存放一些特殊的、需要进行访问授权的数据。暂时不做考虑)。Mmcblk0是当前系统的第一个mmc设备(为我们的eMMC存储器),如果插入tf卡,应该会出现mmcblk1设备。

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第1张图片

下面我们来实现一个用户空间的小程序来读取eMMC中的原始数据进行分析。

我们在external/文件夹下建立radia_test.c、android.mk,代码如下:

radia_test.c

/*************************************************************************
    File Name: radia_test.c
    Author: [email protected]
    Created Time: 2017.6.9
	brief:adjust audio parameters
 ************************************************************************/
#include  
#include  
#include  
#include  
#include  
#include  
#include 
#include 
#include  

//extern int errno; 

int get_disk_sector(int fd){ 
	int sectorsize; 

	ioctl(fd, BLKSSZGET, §orsize) ; 

	return sectorsize; 
} 
/** 
* read_disk_sector: 
* @dev: raw disk FILE * 
* @sector: 
* return is the disk sectorsize 
* */ 
int read_disk_sector(int fd, unsigned long sector, char **p){ 
	int sectorsize; 
	FILE *fp; 

	/* get disk sector size */ 
	sectorsize = get_disk_sector(fd); 
	if (sectorsize == 0){ 
	fprintf(stderr, "get disk sector size failed\n"); 
	return (-1); 
	} 

	/* seek it */ 
	lseek(fd, 0 ,SEEK_SET);

	//注,在offset设置得过大时,lseek可能返回OVERFLOW的错误,但实际上,它已经执行了定位,只是返回的值超出了范围。返回值为-1时,此时要判断一下错误号
	if (lseek(fd, (sectorsize * sector), SEEK_CUR) == -1 ){ 
	fprintf(stderr, "seek to %d failed\n" 
	, sectorsize * sector); 
	return (-1); 
	} 
	/* read it */ 
	*p = (char *)malloc(sectorsize); 
	if (*p == NULL){ 
	fprintf(stderr, "malloc memory failed\n"); 
	return (-1); 
	} 

	return read(fd, *p, sectorsize); 
} 
/* dump data for display */ 
void dump_disk_sector(char *p, int size){ 
	int i; 
	for (i = 0; i< size; i++){ 
		if (i % 16 == 0 && i != 0) 
			printf("\n"); 
		printf("0x%02x,", (unsigned int )*p++ & 0xff); 
	} 

	printf("\n"); 
	return ; 
} 

int main(int argc, char **argv){ 
	char *d; 
	int size, sector_num; 
	int fd; 
	char dev[50] = "/dev/block/mmcblk0"; 

	printf("enter read mmcblk0 sector:\n");
	if(argc != 3)
		printf("error num of arg!\n");
	else{
		strcpy(dev, argv[1]);
		sscanf(argv[2], "%d", §or_num);
		printf("read sector_num:%d\n", sector_num);
	}
	/* open it */ 
	fd = open(dev, O_RDONLY); 
	if (fd == -1){ 
	//fprintf(stderr, "open %s failed %s\n", dev, strerror(errno)); 
	return (-1); 
	} 

	size = read_disk_sector(fd, sector_num, &d); 
	printf("sector size:%d\n", size);
	close(fd); 

	if (size <= 0) return (0); 

	dump_disk_sector(d, size); 

	free(d); 

	return (0); 
}

android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_SRC_FILES:= radia_test.c
LOCAL_MODULE := radia_test
LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)

使用mm命令编译出radia_test的bin文件。 

adb push radia_test  /system/bin

使用方法,第一个参数为块设备文件的路径,第二个参数为扇区号。


如下读出eMMC中的0 扇区数据:

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第2张图片

可能比较抽象,简单介绍一下GPT分区的结构:

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第3张图片

结构

LBA 0

GPT分区表的最开头,处于兼容性考虑仍然存储了一份传统的MBRLBA 0),这个MBR也叫做保护性MBRProtective MBR)。

保护性MBR保护GPT磁盘不受以前发布的MBR磁盘工具(比如FDISKWindowsNT磁盘管理器)的危害。这些工具不能感知GPT,也无法正确地访问GPT磁盘。不能识别GPT的旧软件在访问GPT磁盘时只解释保护性MBR。这些工具通过解释保护性MBR,将GPT磁盘看成一个封装的(可能无法识别)分区,而不是错误地当成一个未分区的磁盘,并且拒绝对硬盘进行操作,除非用户特别要求删除这个分区。这就避免了意外删除分区的危险。例如,当在32位的Windows XP系统中挂载GPT磁盘时,会将其识别为GPT保护分区GPT Protective Partition,并且用户无法对这个分区进行任何操作(除非使用命令行工具)[2]  ,这是因为32位的Windows XP并不支持GPT,它仅仅只是知道挂载的是一个GPT磁盘而已。

在支持从GPT启动的操作系统中,这里也用于存储第一阶段的启动代码。在这个MBR中,只有一个标识为0xEE的分区,以此来表示这块硬盘使用GPT分区表。

另外,能够识别GPT分区表的操作系统会检查保护MBR中的分区表,如果分区类型不是0xEE或者MBR分区表中有多个项,也会拒绝对硬盘进行操作。

在使用MBR/GPT混合分区表的硬盘中,这部分存储了GPT分区表的一部分分区(通常是前四个分区),可以使不支持从GPT启动的操作系统从这个MBR启动,启动后只能操作MBR分区表中的分区。如Boot Camp就是使用这种方式启动Windows

LBA 1

分区表头LBA 1)定义了硬盘的可用空间以及组成分区表的项的大小和数量。在使用64Windows Server 2003的机器上,最多可以创建128个分区,即分区表中保留了128个项,其中每个都是128字节。(EFI标准要求分区表最小要有16,384字节,即128个分区项的大小)

分区表头还记录了这块硬盘的GUID,记录了分区表头本身的位置和大小(位置总是在LBA 1)以及备份分区表头和分区表的位置和大小(在硬盘的最后)。它还储存着它本身和分区表的CRC32校验。固件、引导程序和操作系统在启动时可以根据这个校验值来判断分区表是否出错,如果出错了,可以使用软件从硬盘最后的备份GPT中恢复整个分区表,如果备份GPT也校验错误,硬盘将不可使用。所以GPT硬盘的分区表不可以直接使用16进制编辑器修改。


分区表头的格式

起始字节

 长度

 内容

0

8字节

签名("EFI PART"

8

4字节

修订

12

4字节

分区表头的大小

16

4字节

分区表头(第091字节)的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

*

保留,剩余的字节必须是0(对于512字节LBA的硬盘即是420个字节)


主分区表和备份分区表的头分别位于硬盘的第二个扇区(LBA 1)以及硬盘的最后一个扇区。备份分区表头中的信息是关于备份分区表的。[3] 

LBA 2–33

LBA 2–33的位置存放的是分区表项GPT分区表使用简单而直接的方式表示分区。一个分区表项的前16字节是分区类型GUID。例如,EFI系统分区的GUID类型是{C12A7328-F81F-11D2-BA4B-00A0C93EC93B}。接下来的16字节是该分区唯一的GUID(这个GUID指的是该分区本身,而之前的GUID指的是该分区的类型)。再接下来是分区起始和末尾的64LBA编号,以及分区的名字和属性。[3] 

GPT分区表项的格式

起始字节

 长度

 内容

0

16字节

分区类型GUID

16

16字节

分区GUID

32

8字节

起始LBA(小端格式)

40

8字节

末尾LBA

48

8字节

属性标签(如:60表示"只读")

56

72字节

分区名(可以包括36个UTF-16(小端格式)字符)

 

 

了解了GPT的大概内容,我们再回来看读取到的0 sector,其中分区表位置指示的分区类型为0xee。仅仅起保护作用,不做过多分析。

重点来看第1 sector:

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第4张图片

按照上面的知识,我们可以了解到当前磁盘有0x34个分区,一个分区表项的大小为0x80等等。

读取第2、3、4sector:看到各个分区的相关信息,如分区其实位置,结束位置等。

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第5张图片

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第6张图片

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第7张图片


上面有五十个分区节点,都是高通平台把ROM按需进行的分割。ls –al /dev/block/platform/soc/7824900.sdhci/by-name可以看到各个分区的别名:

linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)_第8张图片

如下是各个分区的简介:

 Label Purpose of this partition


Modem     Partition for modem
Fsc Cookie partition to store Modem File System’s cookies.
Ssd           Partition for ssd diag module. stores the encrypted RSA keys
sbl1           Partition for secondary boot loader
sbl1bak     Back up Partition for secondary boot loader
Rpm         Partition for rpm image
Rpmbak     Back up  Partition for rpm image
Tz             Partition for tz image
tzbak         Back up  Partition for tz image
Hyp           Partition for hypervisor image
hypbak     Back up  Partition for hypervisor image
Dsp           Partition for adsp dymanic loaders image
modemst1     Copy of Modem File System (Encrypted)
modemst2     Copy of Modem File System (Encrypted)
DDR         Partition for DDR.
Fsg           Golden copy or backup of Modem File System (Encrypted). Also used to pre-populate the file system.
Sec           Sec.dat contains fuse settings, mainly for secure boot and oem setting
splash       The splash screen is displayed during the apps bootloader (also called the LK). The display driver in LK will read the splash image data from a separate eMMC partition named as ’splash’
aboot         Partition for apps boot loader
abootbak   Back up Partition for apps boot loader
boot         This is the boot partition of your android device,It includes the android kernel and the ramdisk.
recovery   This is specially designed for backup. The recovery partition can be considered as an alternative boot partition
devinfo     Device information including:iis_unlocked, is_tampered, is_verified, charger_screen_enabled, display_panel, bootloader_version, radio_version All these attirbutes are set based on some specific conditions and written on devinfo partition,.
system     This partition contains the entire Android OS, other than the kernel and the ramdisk. This includes the Android GUI and all the system applications that come pre-installed on the device
cache       This is the partition where Android stores frequently accessed data and app components
persist     Partition entry for persist image. which contains data which shouldn’t be changed after the device shipped, for example: calibration data of chips(wifi, bt, camera, etc.), certificates and other security related files. 
misc         This partition contains miscellaneous system settings in form of on/off switches. These settings may include CID (Carrier or Region ID), USB configuration and certain hardware settings etc
keystore   Partition for keystore service.
config       Partition needed during display panel initialization. More info at Display_panel_configuration_in_Device_Tree
oem         "It is meant for storing OEM specific info. Customer in this case can decide whether he wants to keep this partition or not typically reserved partitions are kept for future use
limits       Partition to store LMh params on 8976 target. LMh (Limits management) driver in SBL writes the LMh HW trimmed data into separate partition and uses the same data for later reboots
mota       Backup partition for M ota upgrade
devcfg     Partition needed by TZ for M upgrades.
Dip         Partition needed for  SafeSwitch, feature (FR26255) designed to allow OEMs and carriers to address new smartphone theft bill issues.
mdtp       Partition needed for  SafeSwitch, feature (FR26255) designed to allow OEMs and carriers to address new smartphone theft bill issues.
userdata   Partition for userdata image       
cmnlib     Verified boot feature introduced in M needLK to load cmnlib corresponding partitions
keymaster     Verified boot feature introduced in M needs LK to load keymaster from corresponding partitions
syscfg     Syscfg is internal testing for Vmin and CPR  characterization
mcfg         All MBNs place holder in flash. Specific MBN would be loaded by mcfg image based on the SIM/Carrier.
msadp     used for modem debug policy
apdp         used for persisting the debug policy. "Debug policy" is used to better support development and debug on secure/fuse-blown devices One instance of the debug policy will be signed for the AP
dpo         This partition will store a policy override



你可能感兴趣的:(Linux,Driver)