Loading...
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 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2022, Linaro Limited */ #define LOG_CATEGORY UCLASS_FWU_MDATA #include <common.h> #include <dm.h> #include <efi_loader.h> #include <fwu.h> #include <fwu_mdata.h> #include <log.h> #include <linux/errno.h> #include <linux/types.h> #include <u-boot/crc.h> /** * fwu_get_mdata_part_num() - Get the FWU metadata partition numbers * @dev: FWU metadata device * @mdata_parts: array for storing the metadata partition numbers * * Get the partition numbers on the storage device on which the * FWU metadata is stored. Two partition numbers will be returned. * * Return: 0 if OK, -ve on error * */ int fwu_get_mdata_part_num(struct udevice *dev, uint *mdata_parts) { const struct fwu_mdata_ops *ops = device_get_ops(dev); if (!ops->get_mdata_part_num) { log_debug("get_mdata_part_num() method not defined\n"); return -ENOSYS; } return ops->get_mdata_part_num(dev, mdata_parts); } /** * fwu_read_mdata_partition() - Read the FWU metadata from a partition * @dev: FWU metadata device * @mdata: Copy of the FWU metadata * @part_num: Partition number from which FWU metadata is to be read * * Read the FWU metadata from the specified partition number * * Return: 0 if OK, -ve on error * */ int fwu_read_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata, uint part_num) { const struct fwu_mdata_ops *ops = device_get_ops(dev); if (!ops->read_mdata_partition) { log_debug("read_mdata_partition() method not defined\n"); return -ENOSYS; } return ops->read_mdata_partition(dev, mdata, part_num); } /** * fwu_write_mdata_partition() - Write the FWU metadata to a partition * @dev: FWU metadata device * @mdata: Copy of the FWU metadata * @part_num: Partition number to which FWU metadata is to be written * * Write the FWU metadata to the specified partition number * * Return: 0 if OK, -ve on error * */ int fwu_write_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata, uint part_num) { const struct fwu_mdata_ops *ops = device_get_ops(dev); if (!ops->write_mdata_partition) { log_debug("write_mdata_partition() method not defined\n"); return -ENOSYS; } return ops->write_mdata_partition(dev, mdata, part_num); } /** * fwu_mdata_check() - Check if the FWU metadata is valid * @dev: FWU metadata device * * Validate both copies of the FWU metadata. If one of the copies * has gone bad, restore it from the other copy. * * Return: 0 if OK, -ve on error * */ int fwu_mdata_check(struct udevice *dev) { const struct fwu_mdata_ops *ops = device_get_ops(dev); if (!ops->check_mdata) { log_debug("check_mdata() method not defined\n"); return -ENOSYS; } return ops->check_mdata(dev); } /** * fwu_get_mdata() - Get a FWU metadata copy * @dev: FWU metadata device * @mdata: Copy of the FWU metadata * * Get a valid copy of the FWU metadata. * * Note: This function is to be called first when modifying any fields * in the metadata. The sequence of calls to modify any field in the * metadata would be 1) fwu_get_mdata 2) Modify metadata, followed by * 3) fwu_update_mdata * * Return: 0 if OK, -ve on error * */ int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata) { const struct fwu_mdata_ops *ops = device_get_ops(dev); if (!ops->get_mdata) { log_debug("get_mdata() method not defined\n"); return -ENOSYS; } return ops->get_mdata(dev, mdata); } /** * fwu_update_mdata() - Update the FWU metadata * @dev: FWU metadata device * @mdata: Copy of the FWU metadata * * Update the FWU metadata structure by writing to the * FWU metadata partitions. * * Note: This function is not to be called directly to update the * metadata fields. The sequence of function calls should be * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata() * * The sequence of updating the partitions should be, update the * primary metadata partition (first partition encountered), followed * by updating the secondary partition. With this update sequence, in * the rare scenario that the two metadata partitions are valid but do * not match, maybe due to power outage at the time of updating the * metadata copies, the secondary partition can be updated from the * primary. * * Return: 0 if OK, -ve on error * */ int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata) { void *buf; const struct fwu_mdata_ops *ops = device_get_ops(dev); if (!ops->update_mdata) { log_debug("get_mdata() method not defined\n"); return -ENOSYS; } /* * Calculate the crc32 for the updated FWU metadata * and put the updated value in the FWU metadata crc32 * field */ buf = &mdata->version; mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); return ops->update_mdata(dev, mdata); } UCLASS_DRIVER(fwu_mdata) = { .id = UCLASS_FWU_MDATA, .name = "fwu-mdata", }; |