手机U盘模式MSG

1 通用概念
1.1 原理分析
将手机以U盘模式(Mass Storage Gadget,MSG)通过OTG线连到Android手机上(as host),切换手机的USB模式为USB存储,此时我们在Android手机上查看文件管理器是没有外接手机的SD卡存储目录的。

现象是只有/dev/block/sda,但是没有/dev/block/sda1。


原因分析如下(Ubuntu也有该issue):
由于Android是将形如 /dev/block/mmcblk0p1 写到USB的 /sys/class/android_usb/android0/f_mass_storage/lun0/file 里面,并且 /dev/block/mmcblk0p1 只有PBR扇区而没有MBR扇区,导致Linux内核 kernel/block/partitions/msdos.c 分析该分区时没有找到MBR以致产生分区节点失败,为了解决这一问题可以在函数int msdos_partition(struct parsed_partitions *state) 中的 p = (struct partition *) (data + 0x1be)之前添加如下形式的代码:

if (state->bdev->bd_disk->part0.nr_sects > 0) {
    state->parts[1].from = 0;
    state->parts[1].size = state->bdev->bd_disk->part0.nr_sects;
}

即可解决该问题(备注:Android 8.0后只需要修改external/gptfdisk/sgdisk.cc,不再需要修改kernel代码)。

该patch的另外一个应用就是USB-ZIP和USB-FDD格式的安装U盘。原因是:USB-ZIP和USB-FDD会将U盘的第一个扇区格式化成DOS.PBR而不是DOS.MBR。
USB-FDD和USB-ZIP的来历:软盘的容量小,没有分区结构,所以软盘是没有MBR的,整个软盘只有一个分区,第一个扇区就是PBR。

1.2 创建USB-FDD或者USB-ZIP格式U盘步骤
1)Android上:dd if=/dev/zero of=/dev/block/sda bs=512 count=4
2)Windows上:快速格式化该U盘,这个U盘就只有PBR扇区而没有MBR扇区

2 Windows文件系统
2.1 FAT32分配单元大小
FAT32分配单元大小 - 簇的大小,譬如16KB,命令chkdsk f:\

3 Linux文件系统
3.1 GRUB简介
GRUB镜像组成:
- GRUB.MBR(boot.img)
- 硬盘扇区offset 1 到offset 62放置GRUB的core.img
- /boot分区的boot/grub/grub.cfg

3.2 block设备性能分析工具
CONFIG_BLK_DEV_IO_TRACE
@ external/e2fsprogs/debugfs
@ external/blktrace
需要加下面的声明在blkparse.c,否则编译出错。
extern int strverscmp (const char *s1, const char *s2);

blktrace -d /dev/block/sda -o - | blkparse -i - -o /data/blk.parsed

根据扇区offset找到具体的文件:
ls -l /dev/block
debugfs -R "stats" /dev/block/sda1 |grep "Block size"

BLKNO=SECTOR_OFFSET/8
debugfs -R "icheck $BLKNO" /dev/block/sda1

GOT THE INODE NUMBER FROM THE LAST CMD: 9
debugfs -R "ncheck 9" /dev/block/sda1

3.3 ext4调试步骤
@ external/e2fsprogs/misc/dumpe2fs.c

1)找到inode号,stat /data/mytest.txt,磁盘上的inode结构体是struct ext4_inode
2)dumpe2fs /dev/block/mmcblk1p19,从超级块中获得每个块组有多少个inode数目、block size、以及inode的大小(一般256Bytes)
3)块组偏移 = inode号 / 每个块组的inode数目
4)块组内inode偏移 = inode号 % 每个块组的inode数目
5)inode在块组内哪个块which_block,块组内inode偏移 = (4096 / 256) * which_block + 剩余的inode数目residue_inode
6)dumpe2fs /dev/block/mmcblk1p19,获得对应块组Inode table块偏移
7)dd if=/dev/block/mmcblk1p19 bs=4096 skip=<块组Inode table块偏移 + which_block> |busybox hexdump -Cv -n 4096
8)从超级块中可以获得每个inode大小一般是256Bytes,从上一步dump出来的数据中偏移residue_inode * 256Bytes,找到对应的256字节内容
9)i_size在inode中偏移为4字节,大小为4字节;i_block[0]在inode中的偏移为40(0x28)字节,大小为4字节,如果i_block[0]的前2个字节是0xf30a,说明使用了extent tree
10)extent tree包含3种结构:ext4_extent_header(12byte),ext4_extent_idx(12byte),ext4_extent(12byte)
11)查看ext4_extent_header的第6个字节(偏移46和47字节)的eh_depth,如果depth=0,则header后跟一个ext4_extent结构,该结构指向一个数据块
12)读出偏移(0x38,0x39)处的块计数,LE模式
13)读出偏移(0x40,0x41)处的块地址的HI,偏移(0x42,0x43,0x44,0x45)处的块地址的LO,都是LE模式,组成完整的文件起始48位块地址start_block_no
14)查看文件第一个块的内容:dd if=/dev/block/mmcblk1p19 bs=4096 skip=<start_block_no> |busybox hexdump -Cv -n 4096

3.4 Linx command
fdisk -l /dev/block/sda
fdisk -l mbr.img
gdisk -l gpt.img

4 USB MSC
4.1 LUN
LUN - 表示一块硬盘,可以是物理上的,也可以是逻辑上,譬如Android MSG的一个mmcblk0p1分区,命令lsscsi查看
lshw
lsscsi - 返回值Host:Controller:Target:LUN
lscpu
lsusb
lsblk

4.2 SCSI CDB
31个字节长度的USB CBW报文的前15个字节是固定的头,从偏移15开始到偏移30结束是16个字节长度的SCSI CDB。
13个字节长度的USB CSW的最后一个字节表示SCSI CDB执行状态,0表示成功,1或者2表示失败。

4.3 Linux内核SCSI硬盘盘符分配
- usb层和scsi层传自定义参数
通过struct Scsi_Host {}

4.4 TUR执行流程
4.4.1 methodology
drivers/usb/storage/scsiglue.c
queuecommand_lck()
add dump_stack() to find who calls TUR.

4.4.2 enable TUR polling
echo 2000 > \
/sys/module/block/parameters/events_dfl_poll_msecs

dfl means default.

4.4.3 Construct TUR Fail CDB
If the device is not ready, the bCSWStatus field in CSW is set to 0x01 (command failed). When device reports 00h in the bCSWStatus field in CSW, which indicates that media is ready.

// srb->sense_buffer
unsigned char
usb_stor_sense_media_notpresent[18] = {
    [0] = 0x70,
    [2] = 2,           /* Sense Key */
    [7] = 0x0a,
    [12] = 0x3a,   /* ASC */
    [13] = 0,         /* ASCQ */
};

4.5 REQUEST_SENSE auto_sense
USB host MSC(transport.c)每发送一个命令后,都会检测设备返回的CSW的状态值是否为0(Good Status),如果不为0,则USB host MSC马上发送REQUEST_SENSE命令,获取18字节的出错信息,并保存在srb->sense_buffer中供SCSI层分析。

drivers/usb/storage/transport.c
usb_stor_invoke_transport()
srb->sense_buffer

5 Abbreviations
ARC:Argonant RISC Core
AT91SAM9260:SAM means Smart ARM-based Microcontroller
ATMEL SAMBA:ATMEL Smart ARM-based Microcontroller Boot Assistant
DWC2:Design Ware Controller 2,Apple的嵌入式设备,包括iPad和iPhone都是使用的DWC2
ISP1161:Philips' Integrated host Solution Pairs 1161,“Firms introduce USB host controllers”,https://www.eetimes.com/document.asp?doc_id=1290054
MSG:Mass Storage Gadget
Quirks:the attributes of a device that are considered to be noncompliant with expected operation
SL811HS:Cypress/ScanLogic 811 Host/Slave,性能上与ISP1161(Integrated host Solution Pairs 1161)相当
TDI:TransDimension Inc.,该公司首先发明了将TT集成到EHCI RootHub中的方法,这样对于嵌入式系统来说,就省去了OHCI/UHCI的硬件,同时降低了成本,作为对该公司的纪念,Linux内核定义了宏ehci_is_TDI(ehci);产品UHC124表示USB Host Controller;收购了ARC USB技术;现已被chipidea收购,chipidea又被mips收购
TT:Transaction Translator(事务转换器,将USB2.0的包转换成USB1.1的包)
USB BH reset:Bigger Hammer or Brad Hosler,表示warm reset;you may be confused why the USB 3.0 spec calls the same type of reset "warm reset" in some places and "BH reset" in other places. "BH" reset is supposed to stand for "Big Hammer" reset, but it also stands for "Brad Hosler". Brad died shortly after the USB 3.0 bus specification was started, and they decided to name the reset after him. The suggestion was made shortly before the spec was finalized, so the wording is a bit inconsistent.

猜你喜欢

转载自blog.csdn.net/zoosenpin/article/details/29825491