1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #pragma once
6
7 #include <digest/digest.h>
8 #include <gpt/gpt.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #define FVM_MAGIC (0x54524150204d5646ull) // 'FVM PART'
13 #define FVM_VERSION 0x00000001
14 #define FVM_SLICE_ENTRY_FREE 0
15 #define FVM_BLOCK_SIZE 8192lu
16 #define FVM_GUID_LEN GPT_GUID_LEN
17 #define FVM_GUID_STRLEN GPT_GUID_STRLEN
18 #define FVM_NAME_LEN 24
19
20 #ifdef __cplusplus
21
22 #include <fbl/algorithm.h>
23
24 namespace fvm {
25
26 typedef struct {
27 uint64_t magic;
28 uint64_t version;
29 uint64_t pslice_count; // Slices which can be used by vpartitions
30 uint64_t slice_size; // All sizes in bytes
31 uint64_t fvm_partition_size;
32 uint64_t vpartition_table_size;
33 uint64_t allocation_table_size;
34 uint64_t generation;
35 uint8_t hash[SHA256_DIGEST_LENGTH];
36 uint8_t reserved[0]; // Up to the rest of the block
37 } fvm_t;
38
39 static_assert(sizeof(fvm_t) <= FVM_BLOCK_SIZE, "FVM Superblock too large");
40
41 #define FVM_MAX_ENTRIES 1024
42
43 // Identifies that the partition is inactive, and should be destroyed on
44 // reboot (unless activated before rebinding the FVM).
45 constexpr uint32_t kVPartFlagInactive = 0x00000001;
46 constexpr uint32_t kVPartAllocateMask = 0x00000001; // All acceptable flags to pass to allocate.
47
48 typedef struct {
init__anon695da0bc020849 void init(const uint8_t* type_, const uint8_t* guid_, uint32_t slices_,
50 const char* name_, uint32_t flags_) {
51 slices = slices_;
52 memcpy(type, type_, FVM_GUID_LEN);
53 memcpy(guid, guid_, FVM_GUID_LEN);
54 memcpy(name, name_, FVM_NAME_LEN);
55 flags = flags_;
56 }
57
clear__anon695da0bc020858 void clear() {
59 memset(this, 0, sizeof(*this));
60 }
61
62 uint8_t type[FVM_GUID_LEN]; // Mirroring GPT value
63 uint8_t guid[FVM_GUID_LEN]; // Mirroring GPT value
64 uint32_t slices; // '0' if unallocated
65 uint32_t flags;
66 uint8_t name[FVM_NAME_LEN];
67 } vpart_entry_t;
68
69 static_assert(sizeof(vpart_entry_t) == 64, "Unexpected VPart entry size");
70 static_assert(FVM_BLOCK_SIZE % sizeof(vpart_entry_t) == 0,
71 "VPart entries might cross block");
72 static_assert(sizeof(vpart_entry_t) * FVM_MAX_ENTRIES % FVM_BLOCK_SIZE == 0,
73 "VPart entries don't cleanly fit within block");
74
75 #define VPART_BITS 16
76 #define VPART_MAX ((1UL << VPART_BITS) - 1)
77 #define VPART_MASK VPART_MAX
78
79 #define VSLICE_BITS 32
80 #define VSLICE_MAX ((1UL << VSLICE_BITS) - 1)
81 #define VSLICE_MASK ((VSLICE_MAX) << VPART_BITS)
82
83 #define RESERVED_BITS 16
84
85 #define PSLICE_UNALLOCATED 0
86
87 // A Slice Entry represents the allocation of a slice.
88 //
89 // Slice Entries are laid out in an array on disk. The index into this array
90 // determines the "physical slice" being accessed, where physical slices consist
91 // of all disk space immediately following the FVM metadata on an FVM partition.
92 //
93 // The "Vpart" field describes which virtual partition allocated the slice.
94 // If this field is set to FVM_SLICE_ENTRY_FREE, the slice is not allocated.
95 //
96 // If the slice is allocated, the "Vslice" field describes which virtual slice
97 // within the virtual partition is using this slice.
98 typedef struct slice_entry {
99 uint64_t data;
100
101 // Vpart is set to 'FVM_SLICE_ENTRY_FREE' if unallocated.
102 uint64_t Vpart() const;
103 void SetVpart(uint64_t vpart);
104
105 // Vslice is only valid if Vpart is not set to 'FVM_SLICE_ENTRY_FREE'.
106 uint64_t Vslice() const;
107 void SetVslice(uint64_t vslice);
108 } slice_entry_t;
109
110 static_assert(FVM_MAX_ENTRIES <= VPART_MAX, "vpart address space too small");
111 static_assert(sizeof(slice_entry_t) == 8, "Unexpected FVM slice entry size");
112 static_assert(FVM_BLOCK_SIZE % sizeof(slice_entry_t) == 0,
113 "FVM slice entry might cross block");
114
115 constexpr size_t kVPartTableOffset = FVM_BLOCK_SIZE;
116 constexpr size_t kVPartTableLength = (sizeof(vpart_entry_t) * FVM_MAX_ENTRIES);
117 constexpr size_t kAllocTableOffset = kVPartTableOffset + kVPartTableLength;
118
AllocTableLength(size_t total_size,size_t slice_size)119 constexpr size_t AllocTableLength(size_t total_size, size_t slice_size) {
120 return fbl::round_up(sizeof(slice_entry_t) * (total_size / slice_size),
121 FVM_BLOCK_SIZE);
122 }
123
MetadataSize(size_t total_size,size_t slice_size)124 constexpr size_t MetadataSize(size_t total_size, size_t slice_size) {
125 return kAllocTableOffset + AllocTableLength(total_size, slice_size);
126 }
127
BackupStart(size_t total_size,size_t slice_size)128 constexpr size_t BackupStart(size_t total_size, size_t slice_size) {
129 return MetadataSize(total_size, slice_size);
130 }
131
SlicesStart(size_t total_size,size_t slice_size)132 constexpr size_t SlicesStart(size_t total_size, size_t slice_size) {
133 return 2 * MetadataSize(total_size, slice_size);
134 }
135
UsableSlicesCount(size_t total_size,size_t slice_size)136 constexpr size_t UsableSlicesCount(size_t total_size, size_t slice_size) {
137 return (total_size - SlicesStart(total_size, slice_size)) / slice_size;
138 }
139
SliceStart(size_t total_size,size_t slice_size,size_t pslice)140 constexpr size_t SliceStart(size_t total_size, size_t slice_size, size_t pslice) {
141 return SlicesStart(total_size, slice_size) + (pslice - 1) * slice_size;
142 }
143
BlocksToSlices(size_t slice_size,size_t block_size,size_t block_count)144 constexpr size_t BlocksToSlices(size_t slice_size, size_t block_size, size_t block_count) {
145 if (slice_size == 0 || slice_size < block_size) {
146 return 0;
147 }
148
149 const size_t kBlocksPerSlice = slice_size / block_size;
150 return (block_count + kBlocksPerSlice - 1) / kBlocksPerSlice;
151 }
152
SlicesToBlocks(size_t slice_size,size_t block_size,size_t slice_count)153 constexpr size_t SlicesToBlocks(size_t slice_size, size_t block_size, size_t slice_count) {
154 return slice_count * slice_size / block_size;
155 }
156
157 } // namespace fvm
158
159 #endif // __cplusplus
160
161 __BEGIN_CDECLS
162
163 // Update's the metadata's hash field to accurately reflect
164 // the contents of metadata.
165 void fvm_update_hash(void* metadata, size_t metadata_size);
166
167 // Validate the FVM header information, and identify which
168 // copy of metadata (primary or backup) should be used for
169 // initial reading, if either.
170 //
171 // "out" is an optional output parameter which is equal to a
172 // valid copy of either metadata or backup on success.
173 zx_status_t fvm_validate_header(const void* metadata, const void* backup,
174 size_t metadata_size, const void** out);
175
176 __END_CDECLS
177