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