189580Smsmith// Copyright 2018 The Fuchsia Authors. All rights reserved. 289580Smsmith// Use of this source code is governed by a BSD-style license that can be 389580Smsmith// found in the LICENSE file. 489580Smsmith 589580Smsmith#pragma once 689580Smsmith 789580Smsmith#include <stdbool.h> 889580Smsmith 989580Smsmith#include <fbl/function.h> 1089580Smsmith#include <fbl/string.h> 1189580Smsmith#include <fbl/unique_fd.h> 1289580Smsmith#include <fbl/unique_ptr.h> 1389580Smsmith#include <fbl/vector.h> 1489580Smsmith#include <gpt/gpt.h> 1589580Smsmith#include <zircon/types.h> 1689580Smsmith 1789580Smsmithnamespace paver { 1889580Smsmith 1989580Smsmithenum class Partition { 2089580Smsmith kBootloader, 2189580Smsmith kKernelC, 2289580Smsmith kEfi, 2389580Smsmith kZirconA, 2489580Smsmith kZirconB, 2589580Smsmith kZirconR, 2689580Smsmith kFuchsiaVolumeManager, 2789580Smsmith // The following are only valid for WipePartition. 2889580Smsmith kInstallType, 2989580Smsmith kSystem, 3089580Smsmith kBlob, 3189580Smsmith kData, 3289580Smsmith}; 3389580Smsmith 3489580Smsmith// A special filter for test injection. 3589580Smsmith// API should return true if device passed in should be filtered out. 3689580Smsmithextern bool (*TestBlockFilter)(const fbl::unique_fd&); 3789580Smsmithextern bool (*TestSkipBlockFilter)(const fbl::unique_fd&); 3889580Smsmith 3989580Smsmith// Abstract device partitioner definition. 4089580Smsmith// This class defines common APIs for interacting with a device partitioner. 4189580Smsmithclass DevicePartitioner { 4289580Smsmithpublic: 4389580Smsmith // Factory method which automatically returns the correct DevicePartitioner 4495533Smike // implementation. Returns nullptr on failure. 4589580Smsmith static fbl::unique_ptr<DevicePartitioner> Create(); 4689580Smsmith 4789580Smsmith virtual ~DevicePartitioner() = default; 4889580Smsmith 4989580Smsmith virtual bool IsCros() const = 0; 5089580Smsmith 5189580Smsmith // Whether to use skip block interface or block interface for non-FVM 5289580Smsmith // partitions. 5389580Smsmith virtual bool UseSkipBlockInterface() const = 0; 5489580Smsmith 5589580Smsmith // Returns a file descriptor to a partition of type |partition_type|, creating it. 5689580Smsmith // Assumes that the partition does not already exist. 5789580Smsmith virtual zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) = 0; 5889580Smsmith 5989580Smsmith // Returns a file descriptor to a partition of type |partition_type| if one exists. 6089580Smsmith virtual zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const = 0; 6189580Smsmith 6289580Smsmith // Finalizes the partition of type |partition_type| after it has been 6389580Smsmith // written. 6489580Smsmith virtual zx_status_t FinalizePartition(Partition partition_type) = 0; 6589580Smsmith 6689580Smsmith // Wipes partition list specified. 6789580Smsmith virtual zx_status_t WipePartitions(const fbl::Vector<Partition>& partitions) = 0; 6889580Smsmith 6989580Smsmith // Returns block size in bytes for specified device. 7089580Smsmith virtual zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, 7189580Smsmith uint32_t* block_size) const = 0; 7289580Smsmith}; 7389580Smsmith 7489580Smsmith// Useful for when a GPT table is available (e.g. x86 devices). Provides common 7589580Smsmith// utility functions. 7689580Smsmithclass GptDevicePartitioner { 7789580Smsmithpublic: 7889580Smsmith using FilterCallback = fbl::Function<bool(const gpt_partition_t&)>; 7989580Smsmith 8089580Smsmith // Find and initialize a GPT based device. 8189580Smsmith static zx_status_t InitializeGpt(fbl::unique_ptr<GptDevicePartitioner>* gpt_out); 8289580Smsmith 8389580Smsmith virtual ~GptDevicePartitioner() { 8489580Smsmith if (gpt_) { 8589580Smsmith gpt_device_release(gpt_); 8689580Smsmith } 8789580Smsmith } 8889580Smsmith 8989580Smsmith // Returns block info for a specified block device. 9089580Smsmith zx_status_t GetBlockInfo(block_info_t* block_info) const { 9189580Smsmith memcpy(block_info, &block_info_, sizeof(*block_info)); 9289580Smsmith return ZX_OK; 9389580Smsmith } 9489580Smsmith 9589580Smsmith gpt_device_t* GetGpt() const { return gpt_; } 9689580Smsmith int GetFd() const { return fd_.get(); } 9789580Smsmith 9889580Smsmith // Find the first spot that has at least |bytes_requested| of space. 9989580Smsmith // 10089580Smsmith // Returns the |start_out| block and |length_out| blocks, indicating 10189580Smsmith // how much space was found, on success. This may be larger than 10289580Smsmith // the number of bytes requested. 10389580Smsmith zx_status_t FindFirstFit(size_t bytes_requested, size_t* start_out, size_t* length_out) const; 10489580Smsmith 10589580Smsmith // Creates a partition, adds an entry to the GPT, and returns a file descriptor to it. 10689580Smsmith // Assumes that the partition does not already exist. 10789580Smsmith zx_status_t AddPartition(const char* name, uint8_t* type, size_t minimum_size_bytes, 10889580Smsmith size_t optional_reserve_bytes, fbl::unique_fd* out_fd); 10989580Smsmith 11089580Smsmith // Returns a file descriptor to a partition which can be paved, 11189580Smsmith // if one exists. 11289580Smsmith zx_status_t FindPartition(FilterCallback filter, gpt_partition_t** out, 11389580Smsmith fbl::unique_fd* out_fd); 11489580Smsmith zx_status_t FindPartition(FilterCallback filter, fbl::unique_fd* out_fd) const; 11589580Smsmith 11689580Smsmith // Wipes a specified partition from the GPT, and ovewrites first 8KiB with 11789580Smsmith // nonsense. 11889580Smsmith zx_status_t WipePartitions(FilterCallback filter); 11989580Smsmith 12089580Smsmithprivate: 12189580Smsmith // Find and return the topological path of the GPT which we will pave. 12289580Smsmith static bool FindTargetGptPath(fbl::String* out); 12389580Smsmith 12489580Smsmith GptDevicePartitioner(fbl::unique_fd fd, gpt_device_t* gpt, block_info_t block_info) 12589580Smsmith : fd_(fbl::move(fd)), gpt_(gpt), block_info_(block_info) {} 12689580Smsmith 12789580Smsmith zx_status_t CreateGptPartition(const char* name, uint8_t* type, uint64_t offset, 12889580Smsmith uint64_t blocks, uint8_t* out_guid); 12989580Smsmith 13089580Smsmith fbl::unique_fd fd_; 13189580Smsmith gpt_device_t* gpt_; 13289580Smsmith block_info_t block_info_; 13389580Smsmith}; 13489580Smsmith 13589580Smsmith// DevicePartitioner implementation for EFI based devices. 13689580Smsmithclass EfiDevicePartitioner : public DevicePartitioner { 13789580Smsmithpublic: 13889580Smsmith static zx_status_t Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner); 13989580Smsmith 14089580Smsmith bool IsCros() const override { return false; } 14189580Smsmith 14289580Smsmith bool UseSkipBlockInterface() const override { return false; } 14389580Smsmith 14489580Smsmith zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override; 14589580Smsmith 14689580Smsmith zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 14789580Smsmith 14889580Smsmith zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; } 14989580Smsmith 15089580Smsmith zx_status_t WipePartitions(const fbl::Vector<Partition>& partitions) override; 15189580Smsmith 15289580Smsmith zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 15389580Smsmith 15489580Smsmithprivate: 15589580Smsmith EfiDevicePartitioner(fbl::unique_ptr<GptDevicePartitioner> gpt) 15689580Smsmith : gpt_(fbl::move(gpt)) {} 15789580Smsmith 15889580Smsmith static bool FilterZirconPartition(const block_info_t& info, const gpt_partition_t& part); 15989580Smsmith 16089580Smsmith fbl::unique_ptr<GptDevicePartitioner> gpt_; 16189580Smsmith}; 16289580Smsmith 16389580Smsmith// DevicePartitioner implementation for ChromeOS devices. 16489580Smsmithclass CrosDevicePartitioner : public DevicePartitioner { 16589580Smsmithpublic: 16689580Smsmith static zx_status_t Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner); 16789580Smsmith 16889580Smsmith bool IsCros() const override { return true; } 16989580Smsmith 17089580Smsmith bool UseSkipBlockInterface() const override { return false; } 17189580Smsmith 17289580Smsmith zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override; 17389580Smsmith 17489580Smsmith zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 17589580Smsmith 17689580Smsmith zx_status_t FinalizePartition(Partition unused) override; 17789580Smsmith 17889580Smsmith zx_status_t WipePartitions(const fbl::Vector<Partition>& partitions) override; 17989580Smsmith 18089580Smsmith zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 18189580Smsmith 18289580Smsmithprivate: 18389580Smsmith CrosDevicePartitioner(fbl::unique_ptr<GptDevicePartitioner> gpt) 18489580Smsmith : gpt_(fbl::move(gpt)) {} 18589580Smsmith 18689580Smsmith fbl::unique_ptr<GptDevicePartitioner> gpt_; 18789580Smsmith}; 18889580Smsmith 18989580Smsmith// DevicePartitioner implementation for devices which have fixed partition maps (e.g. ARM 19089580Smsmith// devices). It will not attempt to write a partition map of any kind to the device. 19189580Smsmith// Assumes standardized partition layout structure (e.g. ZIRCON-A, ZIRCON-B, 19289580Smsmith// ZIRCON-R). 19389580Smsmithclass FixedDevicePartitioner : public DevicePartitioner { 19489580Smsmithpublic: 19589580Smsmith static zx_status_t Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner); 19689580Smsmith 19789580Smsmith bool IsCros() const override { return false; } 19889580Smsmith 19989580Smsmith bool UseSkipBlockInterface() const override { return false; } 20089580Smsmith 20189580Smsmith zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override { 20289580Smsmith return ZX_ERR_NOT_SUPPORTED; 20389580Smsmith } 20489580Smsmith 20589580Smsmith zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 20689580Smsmith 20789580Smsmith zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; } 20889580Smsmith 20989580Smsmith zx_status_t WipePartitions(const fbl::Vector<Partition>& partitions) override; 21089580Smsmith 21189580Smsmith zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 21289580Smsmith 21389580Smsmithprivate: 21489580Smsmith FixedDevicePartitioner() {} 21589580Smsmith}; 21689580Smsmith 21789580Smsmith// DevicePartitioner implementation for devices which have fixed partition maps, but do not expose a 21889580Smsmith// block device interface. Instead they expose devices with skip-block IOCTL interfaces. Like the 21989580Smsmith// FixedDevicePartitioner, it will not attempt to write a partition map of any kind to the device. 22089580Smsmith// Assumes standardized partition layout structure (e.g. ZIRCON-A, ZIRCON-B, 22189580Smsmith// ZIRCON-R). 22289580Smsmithclass SkipBlockDevicePartitioner : public DevicePartitioner { 22389580Smsmithpublic: 22489580Smsmith static zx_status_t Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner); 22589580Smsmith 22689580Smsmith bool IsCros() const override { return false; } 22789580Smsmith 22889580Smsmith bool UseSkipBlockInterface() const override { return true; } 22989580Smsmith 23089580Smsmith zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override { 23189580Smsmith return ZX_ERR_NOT_SUPPORTED; 23289580Smsmith } 23389580Smsmith 23489580Smsmith zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override; 23589580Smsmith 23689580Smsmith zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; } 23789580Smsmith 23889580Smsmith zx_status_t WipePartitions(const fbl::Vector<Partition>& partitions) override; 23989580Smsmith 24089580Smsmith zx_status_t GetBlockSize(const fbl::unique_fd& device_fd, uint32_t* block_size) const override; 24189580Smsmith 24289580Smsmithprivate: 24389580Smsmith SkipBlockDevicePartitioner() {} 24489580Smsmith}; 24589580Smsmith} // namespace paver 24689580Smsmith