1 // Copyright 2018 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 <stdbool.h> 8 9 #include <fbl/function.h> 10 #include <fbl/string.h> 11 #include <fbl/unique_fd.h> 12 #include <fbl/unique_ptr.h> 13 #include <fbl/vector.h> 14 #include <gpt/gpt.h> 15 #include <zircon/types.h> 16 17 #include <utility> 18 19 namespace paver { 20 21 enum class Partition { 22 kUnknown, 23 kBootloader, 24 kKernelC, 25 kEfi, 26 kZirconA, 27 kZirconB, 28 kZirconR, 29 kVbMetaA, 30 kVbMetaB, 31 kFuchsiaVolumeManager, 32 // The following are only valid for WipePartition. 33 kInstallType, 34 kSystem, 35 kBlob, 36 kData, 37 }; 38 39 // A special filter for test injection. 40 // API should return true if device passed in should be filtered out. 41 extern bool (*TestBlockFilter)(const fbl::unique_fd&); 42 43 // Abstract device partitioner definition. 44 // This class defines common APIs for interacting with a device partitioner. 45 class DevicePartitioner { 46 public: 47 // Factory method which automatically returns the correct DevicePartitioner 48 // implementation. Returns nullptr on failure. 49 static fbl::unique_ptr<DevicePartitioner> Create(); 50 51 virtual ~DevicePartitioner() = default; 52 53 virtual bool IsCros() const = 0; 54 55 // Whether to use skip block interface or block interface for non-FVM 56 // partitions. 57 virtual bool UseSkipBlockInterface() const = 0; 58 59 // Returns a file descriptor to a partition of type |partition_type|, creating it. 60 // Assumes that the partition does not already exist. 61 virtual zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) = 0; 62 63 // Returns a file descriptor to a partition of type |partition_type| if one exists. 64 virtual zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const = 0; 65 66 // Finalizes the partition of type |partition_type| after it has been 67 // written. 68 virtual zx_status_t FinalizePartition(Partition partition_type) = 0; 69 70 // Wipes Fuchsia specific partitions. 71 virtual zx_status_t WipePartitions() = 0; 72 73 // Returns block size in bytes for specified device. 74 virtual zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, 75 uint32_t* block_size) const = 0; 76 }; 77 78 // Useful for when a GPT table is available (e.g. x86 devices). Provides common 79 // utility functions. 80 class GptDevicePartitioner { 81 public: 82 using FilterCallback = fbl::Function<bool(const gpt_partition_t&)>; 83 84 // Find and initialize a GPT based device. 85 static zx_status_t InitializeGpt(fbl::unique_fd devfs_root, 86 fbl::unique_ptr<GptDevicePartitioner>* gpt_out); 87 ~GptDevicePartitioner()88 virtual ~GptDevicePartitioner() { 89 if (gpt_) { 90 gpt_device_release(gpt_); 91 } 92 } 93 94 // Returns block info for a specified block device. GetBlockInfo(block_info_t * block_info)95 zx_status_t GetBlockInfo(block_info_t* block_info) const { 96 memcpy(block_info, &block_info_, sizeof(*block_info)); 97 return ZX_OK; 98 } 99 GetGpt()100 gpt_device_t* GetGpt() const { return gpt_; } GetFd()101 int GetFd() const { return fd_.get(); } 102 103 // Find the first spot that has at least |bytes_requested| of space. 104 // 105 // Returns the |start_out| block and |length_out| blocks, indicating 106 // how much space was found, on success. This may be larger than 107 // the number of bytes requested. 108 zx_status_t FindFirstFit(size_t bytes_requested, size_t* start_out, size_t* length_out) const; 109 110 // Creates a partition, adds an entry to the GPT, and returns a file descriptor to it. 111 // Assumes that the partition does not already exist. 112 zx_status_t AddPartition(const char* name, uint8_t* type, size_t minimum_size_bytes, 113 size_t optional_reserve_bytes, fbl::unique_fd* out_fd); 114 115 // Returns a file descriptor to a partition which can be paved, 116 // if one exists. 117 zx_status_t FindPartition(FilterCallback filter, gpt_partition_t** out, 118 fbl::unique_fd* out_fd); 119 zx_status_t FindPartition(FilterCallback filter, fbl::unique_fd* out_fd) const; 120 121 // Wipes a specified partition from the GPT, and overwrites first 8KiB with 122 // nonsense. 123 zx_status_t WipePartitions(FilterCallback filter); 124 125 private: 126 // Find and return the topological path of the GPT which we will pave. 127 static bool FindTargetGptPath(const fbl::unique_fd& devfs_root, fbl::String* out); 128 GptDevicePartitioner(fbl::unique_fd devfs_root,fbl::unique_fd fd,gpt_device_t * gpt,block_info_t block_info)129 GptDevicePartitioner(fbl::unique_fd devfs_root, fbl::unique_fd fd, gpt_device_t* gpt, 130 block_info_t block_info) 131 : devfs_root_(std::move(devfs_root)), fd_(std::move(fd)), gpt_(gpt), 132 block_info_(block_info) {} 133 134 zx_status_t CreateGptPartition(const char* name, uint8_t* type, uint64_t offset, 135 uint64_t blocks, uint8_t* out_guid); 136 137 fbl::unique_fd devfs_root_; 138 fbl::unique_fd fd_; 139 gpt_device_t* gpt_; 140 block_info_t block_info_; 141 }; 142 143 // DevicePartitioner implementation for EFI based devices. 144 class EfiDevicePartitioner : public DevicePartitioner { 145 public: 146 static zx_status_t Initialize(fbl::unique_fd devfs_root, 147 fbl::unique_ptr<DevicePartitioner>* partitioner); 148 IsCros()149 bool IsCros() const override { return false; } 150 UseSkipBlockInterface()151 bool UseSkipBlockInterface() const override { return false; } 152 153 zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override; 154 155 zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 156 FinalizePartition(Partition unused)157 zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; } 158 159 zx_status_t WipePartitions() override; 160 161 zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 162 163 private: EfiDevicePartitioner(fbl::unique_ptr<GptDevicePartitioner> gpt)164 EfiDevicePartitioner(fbl::unique_ptr<GptDevicePartitioner> gpt) 165 : gpt_(std::move(gpt)) {} 166 167 fbl::unique_ptr<GptDevicePartitioner> gpt_; 168 }; 169 170 // DevicePartitioner implementation for ChromeOS devices. 171 class CrosDevicePartitioner : public DevicePartitioner { 172 public: 173 static zx_status_t Initialize(fbl::unique_fd devfs_root, 174 fbl::unique_ptr<DevicePartitioner>* partitioner); 175 IsCros()176 bool IsCros() const override { return true; } 177 UseSkipBlockInterface()178 bool UseSkipBlockInterface() const override { return false; } 179 180 zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override; 181 182 zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 183 184 zx_status_t FinalizePartition(Partition unused) override; 185 186 zx_status_t WipePartitions() override; 187 188 zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 189 190 private: CrosDevicePartitioner(fbl::unique_ptr<GptDevicePartitioner> gpt)191 CrosDevicePartitioner(fbl::unique_ptr<GptDevicePartitioner> gpt) 192 : gpt_(std::move(gpt)) {} 193 194 fbl::unique_ptr<GptDevicePartitioner> gpt_; 195 }; 196 197 // DevicePartitioner implementation for devices which have fixed partition maps (e.g. ARM 198 // devices). It will not attempt to write a partition map of any kind to the device. 199 // Assumes standardized partition layout structure (e.g. ZIRCON-A, ZIRCON-B, 200 // ZIRCON-R). 201 class FixedDevicePartitioner : public DevicePartitioner { 202 public: 203 static zx_status_t Initialize(fbl::unique_fd devfs_root, 204 fbl::unique_ptr<DevicePartitioner>* partitioner); 205 IsCros()206 bool IsCros() const override { return false; } 207 UseSkipBlockInterface()208 bool UseSkipBlockInterface() const override { return false; } 209 AddPartition(Partition partition_type,fbl::unique_fd * out_fd)210 zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override { 211 return ZX_ERR_NOT_SUPPORTED; 212 } 213 214 zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 215 FinalizePartition(Partition unused)216 zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; } 217 218 zx_status_t WipePartitions() override; 219 220 zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 221 222 private: FixedDevicePartitioner(fbl::unique_fd devfs_root)223 FixedDevicePartitioner(fbl::unique_fd devfs_root) 224 : devfs_root_(std::move(devfs_root)) {} 225 226 fbl::unique_fd devfs_root_; 227 }; 228 229 // DevicePartitioner implementation for devices which have fixed partition maps, but do not expose a 230 // block device interface. Instead they expose devices with skip-block IOCTL interfaces. Like the 231 // FixedDevicePartitioner, it will not attempt to write a partition map of any kind to the device. 232 // Assumes standardized partition layout structure (e.g. ZIRCON-A, ZIRCON-B, 233 // ZIRCON-R). 234 class SkipBlockDevicePartitioner : public DevicePartitioner { 235 public: 236 static zx_status_t Initialize(fbl::unique_fd devfs_root, 237 fbl::unique_ptr<DevicePartitioner>* partitioner); 238 IsCros()239 bool IsCros() const override { return false; } 240 UseSkipBlockInterface()241 bool UseSkipBlockInterface() const override { return true; } 242 AddPartition(Partition partition_type,fbl::unique_fd * out_fd)243 zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override { 244 return ZX_ERR_NOT_SUPPORTED; 245 } 246 247 zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 248 FinalizePartition(Partition unused)249 zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; } 250 251 zx_status_t WipePartitions() override; 252 253 zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 254 255 private: SkipBlockDevicePartitioner(fbl::unique_fd devfs_root,fbl::unique_fd block_devfs_root)256 SkipBlockDevicePartitioner(fbl::unique_fd devfs_root, fbl::unique_fd block_devfs_root) 257 : devfs_root_(std::move(devfs_root)), block_devfs_root_(std::move(block_devfs_root)) {} 258 259 fbl::unique_fd devfs_root_; 260 fbl::unique_fd block_devfs_root_; 261 }; 262 } // namespace paver 263