1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 /* Handle read/write/erase of various devices used by the firmware */ 17 18 #define LOG_TAG "fwtool" 19 20 #include <errno.h> 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include "flash_device.h" 27 #include "fmap.h" 28 #include "update_log.h" 29 #include "vboot_interface.h" 30 31 static const struct flash_device_ops *devices[] = { 32 &flash_mtd_ops, 33 &flash_ec_ops, 34 &flash_file_ops, 35 }; 36 37 struct flash_device { 38 const struct flash_device_ops *ops; 39 void *priv_data; 40 struct fmap *fmap; 41 uint8_t *gbb; 42 size_t gbb_size; 43 size_t total_size; 44 size_t write_size; 45 size_t erase_size; 46 }; 47 48 struct flash_device *flash_open(const char *name, const void *params) 49 { 50 const struct flash_device_ops *ops = devices[0]; 51 struct flash_device *dev; 52 53 if (name) { 54 unsigned i; 55 for (i = 0; i < sizeof(devices)/sizeof(devices[0]); i++) 56 if (!strcmp(devices[i]->name, name)) { 57 ops = devices[i]; 58 break; 59 } 60 } 61 ALOGD("Using flash device '%s'\n", ops->name); 62 63 dev = calloc(1, sizeof(struct flash_device)); 64 if (!dev) 65 return NULL; 66 67 dev->ops = ops; 68 dev->priv_data = dev->ops->open(params); 69 if (!dev->priv_data) 70 goto out_free; 71 72 dev->fmap = NULL; 73 dev->gbb = NULL; 74 dev->gbb_size = 0; 75 dev->total_size = dev->ops->get_size(dev->priv_data); 76 dev->write_size = dev->ops->get_write_size(dev->priv_data); 77 dev->erase_size = dev->ops->get_erase_size(dev->priv_data); 78 79 return dev; 80 81 out_free: 82 free(dev); 83 84 return NULL; 85 } 86 87 void flash_close(struct flash_device *dev) 88 { 89 dev->ops->close(dev->priv_data); 90 if (dev->gbb) 91 free(dev->gbb); 92 if (dev->fmap) 93 free(dev->fmap); 94 free(dev); 95 } 96 97 int flash_read(struct flash_device *dev, off_t off, void *buff, size_t len) 98 { 99 return dev->ops->read(dev->priv_data, off, buff, len); 100 } 101 102 int flash_write(struct flash_device *dev, off_t off, void *buff, size_t len) 103 { 104 if ((off % dev->write_size) || (len % dev->write_size)) { 105 ALOGW("Bad write alignment offset %ld size %zd\n", 106 off, len); 107 return -EINVAL; 108 } 109 return dev->ops->write(dev->priv_data, off, buff, len); 110 } 111 112 int flash_erase(struct flash_device *dev, off_t off, size_t len) 113 { 114 if ((off % dev->erase_size) || (len % dev->erase_size)) { 115 ALOGW("Bad erase alignment offset %ld size %zd\n", 116 off, len); 117 return -EINVAL; 118 } 119 120 return dev->ops->erase(dev->priv_data, off, len); 121 } 122 123 size_t flash_get_size(struct flash_device *dev) 124 { 125 return dev->ops->get_size(dev->priv_data); 126 } 127 128 struct fmap *flash_get_fmap(struct flash_device *dev) 129 { 130 if (!dev->fmap) { 131 off_t end = dev->ops->get_fmap_offset(dev->priv_data); 132 off_t off = fmap_scan_offset(dev, end); 133 dev->fmap = fmap_load(dev, off); 134 } 135 136 if (!dev->fmap) 137 ALOGW("No FMAP found\n"); 138 139 return dev->fmap; 140 } 141 142 uint8_t *flash_get_gbb(struct flash_device *dev, size_t *size) 143 { 144 if (!dev->gbb) 145 dev->gbb = fmap_read_section(dev, "GBB", &dev->gbb_size, NULL); 146 147 if (!dev->gbb) 148 ALOGW("No GBB found\n"); 149 else if (size) 150 *size = dev->gbb_size; 151 152 return dev->gbb; 153 } 154 155 int flash_cmd(struct flash_device *dev, int cmd, int ver, 156 const void *odata, int osize, void *idata, int isize) 157 { 158 if (!dev->ops->cmd) 159 return -ENOENT; 160 161 return dev->ops->cmd(dev->priv_data, cmd, ver, 162 odata, osize, idata, isize); 163 } 164