edk2/QcomModulePkg/Library/avb/VerifiedBoot.c
DEBUG ((EFI_D_ERROR, "LoadImageAndAuth failed %r\n", Status)); in LoadImageAndAuth()edk2/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c
DEBUG ((EFI_D_ERROR, "LoadImageAndAuth failed: %r\n", Status));BootLib/PartitionTableUpdate.c
/QcomModulePkg/Library/avb/libavb/avb_slot_verify.c
LinuxLoaderEntryStatus = GetRebootReason (&BootReason);校验启动原因EnumeratePartitions()FindPtnActiveSlotUpdatePartitionEntries() ----- 加载avb分区LoadImageAndAuth --------------- VerifiedBoot.c FindBootableSlot -------------- PartitionTableUpdate.c//errorGetBootPartitionEntry HandleActiveSlotUnbootable //一直返回错误GetBootPartitionEntry // BootEntry 检测没过GetActiveSlot //successGetBootPartitionEntry ----- for()LoadImageAndAuthVB2 --------------- VerifiedBoot.c avb_should_update_rollbackIsCurrentSlotBootableavb_slot_verify ------------------ avb_slot_verify.cload_and_verify_vbmetaops->read_from_partition(ops, AvbReadFromPartition"Load Image %a total time: %lu ms \n"avb_vbmeta_image_verifyavb_rsa_verifyiavb_parse_key_data //Unexpected key lengthavb_manage_hashtree_error_modeavb_append_options //avb 根据resolved_hashtree_error_mode 设置verity_modecmdline_append_option //设置verity_mode到slot_data->cmdlineavb_sub_cmdlineHandleActiveSlotUnbootable //当前槽置为unbootableAppendVBCmdLine //cmdline赋值到VBCmdLineDisplayVerifiedBootScreenDisplayVerifiedBootMenuBootLinux (&Info);UpdateCmdLineAddtoBootConfigList //gBS = SystemTable->BootServices;这里会利用uefi boot服务记录map


• 块设备的控制器传输的固定数据单元大小称为扇区(sector)。因此I/O调度器
和块设备驱动必须以扇区为单位管理数据。
• 虚拟文件系统、映射层(mapping layer)管理磁盘数据的逻辑单元大小称为块
(block)。对于文件系统来说,块是最小的磁盘数据存储单元。
• 前面在分散/聚合DMA中,我们提到块设备驱动应该能够处理称为“段”的数据
单元;每个“段”是内存中的一页或页的一部分,“段”中的数据在磁盘上是
连续的。
• 磁盘缓冲区处理的数据单元大小为“页”,每个对应一个页帧。(注1)
• 通用块设备层粘合所有上层和底层的部分,这样它就知道扇区、块、段和数据
页。

bi_io_vecs指向一个bio_vec结构体数组,该结构体链表包含了一个特定I/O操作所需要
使用到的所有段(segment)。每个bio_vec结构都是一个形式为
它描述的是一个特定的段:段所在的物理页、块在物理页中的偏移量、从给定偏移量开始的
块长度。整个bio_io_vec结构体数组表示了一个完整的缓冲区。bio_vec结构体定义在文件
include/linux/bio.h中。
内核使用gendisk结构,定义在include/linux/genhd.h中,来表示一个独立的磁盘设备。
实际上内核还使用gendisk表示分区,但是驱动程序不需要了解这些。在gendisk结构中的许
多成员必须由驱动程序进行初始化。
物理磁盘通常被分成多个逻辑分区。每个块设备文件可以表示一个整个物理磁盘或者其
中的一个分区。如/dev/sda、/dev/sda1、/dev/sda2等。若一个物理磁盘有多个分区,则磁
盘的布局保存在hd_struct数据结构数组中,数组的地址由gendisk结构体中的part成员保存。
hd_struct数据结构的定义在文件include/linux/genhd.h中。

当内核在系统中发现一个新磁盘时,调用alloc_disk()分配相关数据结构,如gendisk,
hd_struct等,然后调用add_disk()将磁盘添加到系统中。注意:一旦调用了add_disk,
磁盘设备就被“激活“,表示可以使用,并随时会调用它们提供的方法。
generic_make_request函数将bio连接到current->bio_list链表中,并调用__generic_make_request函数提交链表中所有的bio。

__generic_make_request函数最终会调用块设备的请求队列中的make_request_fn成员函数将bio请求发送给I/O调度层,至此对磁盘的数据请求离开通用块层,进入下一层——I/O调度层

verity_mapbio->bi_end_io = verity_end_io;verity_end_ioINIT_WORK(&io->work, verity_work);queue_work(io->v->verify_wq, &io->work);verity_workverity_finish_ioverity_verify_iostruct bio *bio = dm_bio_from_per_bio_datafor (b = 0; b < io->n_blocks; b++)verity_fec_decodeDMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name);verity_handle_errDMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,type_str, block);__submit_bioblk_mq_submit_biobio_endio ///kernel_platform/msm-kernel/block/bio.cbio->bi_end_io
struct dm_verity_io {
72 struct dm_verity *v;
73
74 /* original value of bio->bi_end_io */
75 bio_end_io_t *orig_bi_end_io;
76
77 sector_t block;
78 unsigned n_blocks;
79
80 struct bvec_iter iter;
81
82 struct work_struct work;
83
84 /*
85 * Three variably-size fields follow this struct:
86 *
87 * u8 hash_req[v->ahash_reqsize];
88 * u8 real_digest[v->digest_size];
89 * u8 want_digest[v->digest_size];
90 *
91 * To access them use: verity_io_hash_req(), verity_io_real_digest()
92 * and verity_io_want_digest().
93 */
94 };
int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
335 sector_t block, u8 *digest, bool *is_zero)
336 {
337 int r = 0, i;
339 if (likely(v->levels)) {
340 /*
341 * First, we try to get the requested hash for
342 * the current block. If the hash block itself is
343 * verified, zero is returned. If it isn't, this
344 * function returns 1 and we fall back to whole
345 * chain verification.
346 */
347 r = verity_verify_level(v, io, block, 0, true, digest);
348 if (likely(r <= 0))
349 goto out;
350 }
352 memcpy(digest, v->root_digest, v->digest_size);
354 for (i = v->levels - 1; i >= 0; i--) {
355 r = verity_verify_level(v, io, block, i, false, digest);
356 if (unlikely(r))
357 goto out;
358 }
359 out:
360 if (!r && v->zero_digest)
361 *is_zero = !memcmp(v->zero_digest, digest, v->digest_size);
362 else
363 *is_zero = false;
364
365 return r;
366 }
struct dm_verity {
35 struct dm_dev *data_dev;
36 struct dm_dev *hash_dev;
37 struct dm_target *ti;
38 struct dm_bufio_client *bufio;
39 char *alg_name;
40 struct crypto_ahash *tfm;
41 u8 *root_digest; /* digest of the root block */
42 u8 *salt; /* salt: its size is salt_size */
43 u8 *zero_digest; /* digest for a zero block */
44 unsigned salt_size;
45 sector_t data_start; /* data offset in 512-byte sectors */
46 sector_t hash_start; /* hash start in blocks */
47 sector_t data_blocks; /* the number of data blocks */
48 sector_t hash_blocks; /* the number of hash blocks */
49 unsigned char data_dev_block_bits; /* log2(data blocksize) */
50 unsigned char hash_dev_block_bits; /* log2(hash blocksize) */
51 unsigned char hash_per_block_bits; /* log2(hashes in hash block) */
52 unsigned char levels; /* the number of tree levels */
53 unsigned char version;
54 unsigned digest_size; /* digest size for the current hash algorithm */
55 unsigned int ahash_reqsize;/* the size of temporary space for crypto */
56 int hash_failed; /* set to 1 if hash of any block failed */
57 enum verity_mode mode; /* mode for handling verification errors */
58 unsigned corrupted_errs;/* Number of errors for corrupted blocks */
59
60 struct workqueue_struct *verify_wq;
61
62 /* starting blocks for each tree level. 0 is the lowest level. */
63 sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
64
65 struct dm_verity_fec *fec; /* forward error correction */
66 unsigned long *validated_blocks; /* bitset blocks validated */
67
68 char *signature_key_desc; /* signature keyring reference */
69 };
70
[??? 3.809367] v->hash_blocks = 662070?? (662070-656896=5174)
[??? 3.812900] v->data_dev_block_bits=12
[??? 3.816608] v->hash_dev_block_bits=12
[??? 3.820279] v->hash_per_block_bits=7?? (4096/32 = 128, 指一个4K块上有128个哈希值)
[??? 3.823888] v->levels=3
[??? 3.826380] v->version =1
[??? 3.829033] v->digest_size=32
数据块有656896X4X1024? (超过了2G)
Level 0 :? 656896/128 = 5132个4k块
Level 1 :? 5132/128= 41个4k块
Level 2:? 40 /128 = 0,即1个4k块
共 5132+41+1 = 5174 个块
static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
193 sector_t *hash_block, unsigned *offset)
194 {
195 sector_t position = verity_position_at_level(v, block, level);
196 unsigned idx;
198 *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
200 if (!offset)
201 return;
203 idx = position & ((1 << v->hash_per_block_bits) - 1);
204 if (!v->version)
205 *offset = idx * v->digest_size;
206 else
207 *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
208 }static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
92 int level)
93 {
94 return block >> (level * v->hash_per_block_bits);
95 }
FirstStageMainFirstStageMount::DoFirstStageMountFirstStageMount::MountPartitionsFirstStageMount::MountPartitionFirstStageMountVBootV2::SetUpDmVerityAvbHandle::LoadAndVerifyVbmetaFailed to load offline vbmeta for
参考:
https://aliez22.github.io/posts/11537/
https://www.shili8.cn/article/detail_20000194464.html