forked from xuzhongxing/fuchsia-notes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
paving.txt
553 lines (420 loc) · 21.7 KB
/
paving.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
在x64上,制作zedboot启动盘:
fx mkzedboot
目前mkzedboot只支持x64
exec 3>>/dev/sde 将fd 3重定向到/dev/sde
cgpt create /dev/sde
Save(drive, drive->gpt.primary_header,
GPT_PMBR_SECTORS,
drive->gpt.sector_bytes, GPT_HEADER_SECTORS)
cgpt boot -p /dev/sde
dd if=zedboot.esp.blk of=/dev/sde seek= efi system 分区
dd if=zedboot.vboot 第2个分区 这个是启动chromebook用的
kernel-image.elf:
ld -nostdlib --build-id -z noexecstack -z max-page-size=4096 --gc-sections --build-id=none \
-o kernel-image.elf -T kernel/image.ld --just-symbols zircon.elf \
kernel-vars.ld kernel.image.o
--just-symbols的作用:
start.S:
// These symbols are used by image.S
.global IMAGE_ELF_ENTRY
.global IMAGE_MULTIBOOT_ENTRY
IMAGE_ELF_ENTRY = _start
IMAGE_MULTIBOOT_ENTRY = _multiboot_start
kernel.zbi:
x86_64-elf-objcopy -O binary kernel-image.elf kernel.zbi
zircon.bin: == kernel.zbi 这个文件是zbi文件
包含的纯代码,就是elf加载之后的内存映像
链接脚本指定的链接时用的地址就是每个segment加载到内存中的地址。
zedboot.zbi:
[6820/25205] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin ../build-zircon/tools/zbi
--output=zedboot.zbi
--depfile=zedboot.zbi.d
--complete=x64
../build-zircon/build-x64/zircon.bin
obj/build/images/zedboot/zedboot.manifest
--entry=config/devmgr=obj/build/images/zedboot/devmgr_config.txt
--type=cmdline
zbi命令生成了包含几个部分的文件:kernel, boot fs, cmdline, kernel和bootfs都有自己的header
uefi spec:3.5, 13.3, 4
uefi分区的文件系统是fat32, bootloader的名字是/EFI/BOOT/BOOTx64.EFI, 格式是PE32+
bootx64.so: elf x86 64 so文件
./prebuilt/downloads/gcc/bin/x86_64-elf-ld
-o /home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/bootx64.so
-nostdlib -T bootloader/build/efi-x86-64.lds -pie -Lout
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/osboot.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/diskio.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/cmdline.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/zircon.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/misc.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/netboot.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/netifc.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/inet6.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/pci.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/framebuffer.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/src/device_id.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/efi/guids.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/xefi.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/loadfile.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/console-printf.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/ctype.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/printf.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/stdlib.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/string.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/strings.o
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/lib/inet.o
/home/xzx/fuchsia/out/build-zircon/build-x64/EFI_libs/libtftp.a
bootx64.efi: pe32+ efi application
./prebuilt/downloads/gcc/bin/x86_64-elf-objcopy
--target=pei-x86-64 --subsystem 10 -j .text -j .data -j .reloc
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/bootx64.so
/home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/bootx64.efi
make-efi会把zedboot.bin写到esp里。所以bootx64.efi会在esp里寻找需要加载的内核。
zedboot.esp.blk:
[8357/25205] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin host_x64/make-efi
--output /home/xzx/fuchsia/out/x64/zedboot.esp.blk
--mkfs /home/xzx/fuchsia/out/build-zircon/tools/mkfs-msdosfs
--zedboot /home/xzx/fuchsia/out/x64/zedboot.zbi
--cmdline /home/xzx/fuchsia/build/images/zedboot/efi_cmdline.txt
--efi-bootloader /home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/bootx64.efi
zedboot.vboot: 启动chromebook用的
[6830/25205] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin
host_x64/futility
vbutil_kernel
--pack /home/xzx/fuchsia/out/x64/zedboot.vboot
--keyblock /home/xzx/fuchsia/third_party/vboot_reference/tests/devkeys/kernel.keyblock
--signprivate /home/xzx/fuchsia/third_party/vboot_reference/tests/devkeys/kernel_data_key.vbprivk
--bootloader /home/xzx/fuchsia/out/x64/zedboot.zbi
--vmlinuz /home/xzx/fuchsia/out/build-zircon/build-x64/zircon.bin
--version 1
--flags 0x2
zedboot的意思是启动之后连接服务进行paving
fx boot 启动 boot server
ramdisk=fuchsia.zbi
x64:
--efi fuchsia.esp.blk
--kernc fuchsia.vboot
arm64:
--zircona fuchsia.zbi
--zirconr zedboot.zbi
--fvm fvm.sparse.blk
--fvm fvm.data.sparse.blk
fuchsia.zbi:
[23936/23998] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin
../build-zircon/tools/zbi
--output=fuchsia.zbi
--depfile=fuchsia.zbi.d
--complete=arm64
../build-zircon/build-arm64/zircon.bin
obj/build/images/boot.manifest
--entry=config/devmgr=obj/build/images/devmgr_config.txt
--type=cmdline
fuchsia.esp.blk
[25127/25205] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin host_x64/make-efi
--output /home/xzx/fuchsia/out/x64/fuchsia.esp.blk
--mkfs /home/xzx/fuchsia/out/build-zircon/tools/mkfs-msdosfs
--zircon /home/xzx/fuchsia/out/x64/fuchsia.zbi
--zedboot /home/xzx/fuchsia/out/x64/zedboot.zbi
--cmdline /home/xzx/fuchsia/build/images/efi_local_cmdline.txt
--efi-bootloader /home/xzx/fuchsia/out/build-zircon/build-x64/bootloader/bootx64.efi
对于efi启动,bootx64.efi会从esp分区直接读取fuchsia.zbi, 里面包含了kernel以及boot fs
====
fuchsia.vboot: 启动chromebook用的
[23942/23998] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin host_x64/futility
vbutil_kernel
--pack /home/xzx/fuchsia/out/arm64/fuchsia.vboot
--keyblock /home/xzx/fuchsia/third_party/vboot_reference/tests/devkeys/kernel.keyblock
--signprivate /home/xzx/fuchsia/third_party/vboot_reference/tests/devkeys/kernel_data_key.vbprivk
--bootloader /home/xzx/fuchsia/out/arm64/fuchsia.zbi
--vmlinuz /home/xzx/fuchsia/out/build-zircon/build-arm64/zircon.bin
--version 1
--flags 0x2
====
fvm.sparse.blk:
[23986/23998] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin
../build-zircon/tools/fvm
obj/build/images/fvm.sparse.blk
sparse
--compress lz4
--blob obj/build/images/blob.blk
main()
SparseContainer::Create
sparseContainer->Init
缺省slice size = 64MB
add_partitions(sparseContainer.get(), argc - i, argv + i)
container->AddPartition(partition_path, partition_type)
Format::Create(path, type_name, &format)
AllocatePartition(fbl::move(format)
format->MakeFvmReady(SliceSize(), part_index)
把blob fs的head拷贝给fvm的head
AllocateExtent
blocksperslice=2^13, kFVMBlockMapStart=2^16, 所以slice_start=8
blockmap从第8个slice开始
nodemap从第16个slice开始
data从第24个slice开始
这里的vslice start在pave-lib里起作用
sparseContainer->Commit()
PrepareWrite(extent_size_)
WriteData(format->Data(), format->BlockSize())
CompleteWrite()
fvm-sparse.h里有文件的格式
blobfs里面的blocksize是8kb
====
fvm.data.sparse.blk:
[3538/23998] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin
../build-zircon/tools/fvm
obj/build/images/fvm.data.sparse.blk
sparse
--compress lz4
--zxcrypt
--data obj/build/images/data.blk
====
blob.blk:
[23960/23998] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin
../build-zircon/tools/blobfs
--depfile 指定需要dep文件,就是目标文件名后面加.d, 所以这个命令会生成2个文件,blob.blk.d里存放的是manifest里的文件名
obj/build/images/blob.blk
create
--manifest blob.manifest
details:
FsCreator::ProcessArgs()
fd_.reset(open(device, open_flags, 0644));
depfile_.reset(open(buf, O_CREAT|O_TRUNC|O_WRONLY, 0644));
FsCreator::ProcessManifest
BlobfsCreator::ProcessManifestLine
BlobfsCreator::ProcessBlob
ProcessBlocks(stats.st_size) // 累加需要的size
data_blocks_ += MerkleTreeBlocks(node) + BlobDataBlocks(node);
blob_list_.push_back(path);
ResizeFile
BlobfsCreator::CalculateRequiredSize()
这里计算出来的是整个的包含blockmap和nodemap的文件大小
FsCreator::RunCommand()
BlobfsCreator::Mkfs()
blobfs::blobfs_mkfs(fd_.get(), block_count);
block count是这个文件总共的block数,包括头,一个block是8k
inode count是缺省的32768
第一个block是blobfs_info_t
BlockMapStartBlock=1
NodeMapStartBlock=1 + block_count / 8k*8
block count设置成为data block
把head, blockmap, nodemap都写入磁盘
Add()
blobfs_create(&blobfs, fbl::move(fd_) // host.cpp
readblk(fd.get(), 0, (void*)info_block.block)
把刚写入磁盘的meta信息读出来
Blobfs::Create(fbl::move(fd), 0, info_block, extent_lengths, out)
分成4个extent:head, blockmap, nodemap, data blocks
====>
thread:
AppendDepfile(blob_list_[i].c_str())
AddBlob(blobfs.get(), blob_list_[i].c_str())
blobfs::blobfs_add_blob(blobfs, data_fd.get())
MerkleTree::Create(blob_data, s.st_size, merkle_tree.get(), merkle_size, &digest)
mt.CreateInit(data_len, tree_len)
mt.CreateUpdate(data, data_len, tree)
mt.CreateFinal(tree, digest)
总结:数据每8k变成32字节,所以第0层树长度是filedatalen / 256, 每层长度都是前一层的1/256
每层的digest顺序排列在tree buffer里。
bs->NewBlob(digest, &inode_block)
先找到一个空闲的inode,并且检查所有的inode是否有重复的digest
bno是inode在nodemap区域的block索引号
bs->AllocateBlocks(inode->num_blocks, reinterpret_cast<size_t*>(&inode->start_block)
给要写入的文件分配block(8k一个),最少占用2个block
blockmap用来标记哪些block被分配了
bs->WriteData(inode, merkle_tree.get(), data)
把merkle tree和data依次写入磁盘
bs->WriteBitmap(inode->num_blocks, inode->start_block)
写入block bitmap
bs->WriteNode(fbl::move(inode_block))
把inode所在的block写入磁盘
bs->WriteInfo()
对于每个文件,先存放它的merkletree, 然后存它的data, inode里有root hash
blobfs 的结构:
blobfshead | block bitmap | inodes | merkle1+data1, merkle2+data2, ...
写入fvm分区之后:
0 | slice 8 | slice 16 | slice 24
data.blk:
[6591/25205] /usr/bin/env ../../build/gn_run_binary.sh ../../buildtools/linux-x64/clang/bin
../build-zircon/tools/minfs
obj/build/images/data.blk@10m
create
创建一个10兆的minfs
bootserver
--efi fuchsia.esp.blk
--kernc fuchsia.vboot
--fvm fvm.sparse.blk
--fvm fvm.data.sparse.blk
zircon.bin (kernel)
fuchsia.zbi (ramdisk)
main
use_tftp = true
xfer(ramdisk, "<<netboot>> ramdisk.bin")
xfer "<<netboot>> kernel.bin"
xfer "<<image>> efi.img"
xfer "<<image>> sparse.fvm" fvm.sparse.blk
xfer "<<image>> sparse.fvm" fvm.data.sparse.blk
tftp_xfer()
file_init(&xd);
tftp_init
tftp_push_file
transfer_file
transport_send
state->target_addr.sin6_port = htons(NB_TFTP_INCOMING_PORT);
====
send_boot_command
====
在device端,netsvc.advertise是true, netsvc.netboot是true
main
netboot_advertise(nodename);
udp6_send: 33330 => 33331
for(;;)
netifc_open(interface)
open("/dev/class/ethernet", O_DIRECTORY|O_RDONLY)
fdio_watch_directory(dirfd, netifc_open_cb, ZX_TIME_INFINITE, (void*)interface);
netifc_open_cb
netfd = openat(dirfd, fn, O_RDWR)
eth_create
ioctl_ethernet_start
ip6_init
netifc_poll
for (;;)
eth_complete_rx
rx_complete
netifc_recv
eth_recv
_udp6_recv
udp6_recv
tftp_recv
tftp_handle_msg
tftp_process_msg
tftp_handle_wrq
tftp_handle_request
session->file_interface.open_write
file_open_write
如果是<<netboot>>文件,存在buffer里
netboot_get_buffer
如果是<<image>>文件,调用
aver_open_write
tftp_handle_data
eth_queue_rx
====
fuchsia有2个gpt分区,一个是efi分区,一个是fvm分区
uapp/disk-pave
install-disk-image install-efi install-fvm
RealMain
DevicePartitioner::Create();
EfiDevicePartitioner::Initialize(&device_partitioner)
GptDevicePartitioner::InitializeGpt(&gpt)
FindTargetGptPath
gpt_device_init
PartitionPave(fbl::move(device_partitioner), fbl::move(flags.payload_fd),Partition::kEfi, flags.arch);
partitioner->FindPartition(partition_type, &partition_fd)
gpt_->FindPartition(filter, out_fd);
找到已有的"EFI Gigaboot"分区
如果没找到则执行添加
partitioner->AddPartition(partition_type, &partition_fd)
WriteVmoToBlock
partitioner->FinalizePartition(partition_type)
====
slice_size是64兆,在system/host/fvm/main.cpp
块设备的block size缺省是512 bytes
FvmPave(fbl::move(device_partitioner), fbl::move(flags.payload_fd));
device_partitioner->FindPartition(Partition::kFuchsiaVolumeManager, &partition_fd);
若无,device_partitioner->AddPartition
EfiDevicePartitioner::AddPartition
GptDevicePartitioner::AddPartition
最小要8GB
GptDevicePartitioner::FindFirstFit
寻找分区之间的满足需求的空隙
CreateGptPartition(name, type, start, length, guid)
gpt_partition_add(gpt_, name, type, out_guid, offset, blocks, 0)
partition_init(part, name, type, guid, first, last, flags);
OpenBlockPartition(guid, type, ZX_SEC(5), out_fd)
OpenPartition(kBlockDevPath, cb, timeout, out_fd);
FvmStreamPartitions(fbl::move(partition_fd), fbl::move(payload_fd))
fvm::SparseReader::Create(fbl::move(src_fd), &reader)
FvmPartitionFormat(fbl::move(partition_fd), hdr->slice_size)
detect_disk_format(partition_fd.get());
检测gpt分区的前8个字节是不是fvm magic
若不是,先初始化fvm分区的head
fvm_init(partition_fd.get(), slice_size)
把fvm_t在分区头上写2遍
sb->pslice_count = (disk_size - metadata_size * 2) / slice_size;
物理slice的数量是整个分区的size减去2个header除以slice size
每个vpart中的slice的编号是由alloc table记录的,每个vpart自己不记录它拥有哪些slice
TryBindToFvmDriver
====>
fvm_bind
对fvm image里的每个分区,实际上一个image里面目前只有一个分区
去fvm分区里找对应的子分区。
检查是不是fvm的子分区,检查是不是gpt分区
分配新的vpart, 最后会删除老的vpart
用第一个extent的slice count创建分区,后面会拓展
fvm_allocate_partition
ioctl_block_fvm_alloc_partition
====> devhost
VPartitionManager::DdkIoctl
FindFreeVPartEntryLocked
GetVPartEntryLocked
fvm分区的metadata包括2个header, vpart entry, alloc table. 是之前fvm驱动加载的时候读入内存的。
创建VPartition
填充vpart entry metadata
AllocateSlicesLocked(vpart.get(), 0,request->slice_count)
vslice从0开始
先验证vslice没有被分配
然后寻找空闲的pslice
SliceExtent放的是连续的vslice到pslice的映射,用一个vector表示。
新建的情况下会分配一个sliceextent, 存放所有的vslice
设置alloc table中pslice的vpart.
WriteFvmLocked
把metadata写回磁盘
VPartition是一个in memory data structure
AddPartition(fbl::move(vpart))
从刚更新的vpart entry里获得名字
添加Vpartition设备。它实现了ioctl接口
打开新建分区对应的/dev/class/block/下面的块设备
for later extent:
ioctl_block_fvm_extend
fzl::MappedVmo::Create(vmo_size, "fvm-stream", &mvmo)
创建一个1兆的vmo
for each partition:
RegisterFastBlockIo(parts[p].new_part, mvmo->GetVmo(), &vmoid, &client);
ioctl_block_get_fifos(fd.get(), fifo.reset_and_get_address())
====> devhost:
blkdev_get_fifos
blockserver_create
BlockServer::Create
BlockServer::BlockServer
device_ioctl(dev_, IOCTL_BLOCK_GET_INFO, nullptr, 0, &info_, sizeof(info_), &actual)
这个block设备的父亲设备是VPartition
fzl::create_fifo
创建fifo,一头给block server, 一头传出去
初始化bs里的每个tx group
bp->ops->query(bp->ctx, &bs->info_, &bs->block_op_size_);
==VPartition::BlockQuery
thrd_create(&thread, blockserver_thread, bdev)
zx_handle_duplicate(vmo, ZX_RIGHT_SAME_RIGHTS, dup.reset_and_get_address())
ioctl_block_attach_vmo(fd.get(), &h, vmoid_out)
blkdev_attach_vmo(blkdev, cmd, cmdlen, reply, max, out_actual);
blockserver_attach_vmo(bdev->bs, h, out_buf)
vmo是blockserver的iobuffer
block_client::Client::Create(fbl::move(fifo), client_out)
block_fifo_create_client
client里只有一个fifo
vmoid是blockio_write要用的参数
StreamFvmPartition
把metadata(image head + partition desc + extent desc)之后的slice写入磁盘
这里用到的extent的slice_start
reader->ReadData
读到vmo里
client.Transaction(request, 1)
block_fifo_txn(client_, requests, count)
group是0
do_write(client->fifo, &requests[0], count)
最终放入队列:
VPartition::BlockQueue
====
vim2的分区信息是由uboot里硬编码给出的。
具体的分区映射定义在zircon.c里。
bootpart驱动会使用这个分区映射信息。
device-partitioner.cpp会利用bootpart驱动找到对应的分区。