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 /* Read/write/erase Embedded Controller integrated flash */ 17 18 #define LOG_TAG "fwtool" 19 20 #include <stdint.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <sys/ioctl.h> 28 #include <sys/param.h> 29 #include <sys/stat.h> 30 #include <sys/types.h> 31 32 #include "ec_commands.h" 33 #include "flash_device.h" 34 #include "update_log.h" 35 36 #define CROS_EC_DEV_NAME "/dev/cros_ec" 37 38 struct cros_ec_command { 39 uint32_t version; 40 uint32_t command; 41 uint8_t *outdata; 42 uint32_t outsize; 43 uint8_t *indata; 44 uint32_t insize; 45 uint32_t result; 46 }; 47 48 #define CROS_EC_DEV_IOCXCMD _IOWR(':', 0, struct cros_ec_command) 49 #define CROS_EC_DEV_IOCRDMEM _IOWR(':', 1, struct cros_ec_readmem) 50 51 struct ec_data { 52 int fd; 53 struct ec_response_get_protocol_info proto; 54 struct ec_response_flash_info_1 info; 55 struct ec_response_flash_region_info ro_region; 56 }; 57 58 static int ec_command(void *hnd, int command, int version, 59 const void *outdata, int outsize, void *indata, int insize) 60 { 61 struct ec_data *ec = hnd; 62 struct cros_ec_command s_cmd; 63 int r; 64 65 if (ec->fd < 0) 66 return -ENODEV; 67 68 s_cmd.command = command; 69 s_cmd.version = version; 70 s_cmd.result = 0xff; 71 s_cmd.outsize = outsize; 72 s_cmd.outdata = (uint8_t *)outdata; 73 s_cmd.insize = insize; 74 s_cmd.indata = indata; 75 76 r = ioctl(ec->fd, CROS_EC_DEV_IOCXCMD, &s_cmd); 77 if (r < 0) { 78 ALOGD("Cmd 0x%x failed %d\n", command, errno); 79 return -errno; 80 } else if (s_cmd.result != EC_RES_SUCCESS) { 81 ALOGD("Cmd 0x%x error %d\n", command, s_cmd.result); 82 return s_cmd.result; 83 } 84 85 return 0; 86 } 87 88 static void *ec_open(const void *params) 89 { 90 int res; 91 struct ec_params_flash_region_info region; 92 const char *path = params ? params : CROS_EC_DEV_NAME; 93 struct ec_data *dev = calloc(1, sizeof(struct ec_data)); 94 if (!dev) 95 return NULL; 96 97 dev->fd = open(path, O_RDWR); 98 if (dev->fd == -1) { 99 ALOGE("Cannot open EC device %s : %d\n", path, errno); 100 goto out_free; 101 } 102 103 res = ec_command(dev, EC_CMD_GET_PROTOCOL_INFO, 0, NULL, 0, 104 &dev->proto, sizeof(dev->proto)); 105 if (res) { 106 ALOGE("Cannot get EC protocol info for %s : %d\n", path, res); 107 goto out_close; 108 } 109 110 res = ec_command(dev, EC_CMD_FLASH_INFO, 1, NULL, 0, 111 &dev->info, sizeof(dev->info)); 112 if (res) { 113 ALOGE("Cannot get EC flash info for %s : %d\n", path, res); 114 goto out_close; 115 } 116 117 region.region = EC_FLASH_REGION_RO; 118 res = ec_command(dev, EC_CMD_FLASH_REGION_INFO, 1, 119 ®ion, sizeof(region), 120 &dev->ro_region, sizeof(dev->ro_region)); 121 if (res) { 122 ALOGE("Cannot get EC RO info for %s : %d\n", path, res); 123 goto out_close; 124 } 125 126 ALOGD("EC %s: size %d erase_block_size %d write_ideal_size %d\n", 127 path, dev->info.flash_size, dev->info.erase_block_size, 128 dev->info.write_ideal_size); 129 130 return dev; 131 132 out_close: 133 close(dev->fd); 134 dev->fd = -1; 135 out_free: 136 free(dev); 137 138 return NULL; 139 } 140 141 static void ec_close(void *hnd) 142 { 143 struct ec_data *dev = hnd; 144 145 close(dev->fd); 146 free(dev); 147 } 148 149 static int ec_read(void *hnd, off_t offset, void *buffer, size_t count) 150 { 151 struct ec_data *dev = hnd; 152 ssize_t res; 153 struct ec_params_flash_read p; 154 uint8_t *ptr = buffer; 155 uint32_t read_size = dev->proto.max_response_packet_size 156 - sizeof(struct ec_host_response); 157 158 while (count) { 159 p.offset = offset; 160 p.size = MIN(read_size, count); 161 res = ec_command(dev, EC_CMD_FLASH_READ, 0, &p, sizeof(p), 162 ptr, read_size); 163 if (res) { 164 ALOGW("Cannot read at %ld : %zd\n", offset, res); 165 return res; 166 } 167 count -= p.size; 168 ptr += p.size; 169 offset += p.size; 170 } 171 return 0; 172 } 173 174 static int ec_write(void *hnd, off_t offset, void *buffer, size_t count) 175 { 176 struct ec_data *dev = hnd; 177 ssize_t res; 178 struct ec_params_flash_write *p; 179 uint8_t *packet_data; 180 uint8_t *ptr = buffer; 181 uint32_t write_size = dev->info.write_ideal_size; 182 uint32_t total_size = sizeof(*p) + write_size; 183 184 p = malloc(total_size); 185 if (!p) 186 return -ENOMEM; 187 packet_data = (uint8_t *)p + sizeof(*p); 188 189 while (count) { 190 p->offset = offset; 191 p->size = write_size; 192 memcpy(packet_data, ptr, write_size); 193 res = ec_command(dev, EC_CMD_FLASH_WRITE, 1, p, total_size, 194 NULL, 0); 195 if (res) { 196 ALOGW("Cannot write at %ld : %zd\n", offset, res); 197 return res; 198 } 199 count -= write_size; 200 ptr += write_size; 201 offset += write_size; 202 } 203 return 0; 204 } 205 206 static int ec_erase(void *hnd, off_t offset, size_t count) 207 { 208 struct ec_data *dev = hnd; 209 int res; 210 struct ec_params_flash_erase erase; 211 212 erase.offset = offset; 213 erase.size = count; 214 res = ec_command(dev, EC_CMD_FLASH_ERASE, 0, &erase, sizeof(erase), 215 NULL, 0); 216 if (res) { 217 ALOGW("Cannot erase at %ld : %d\n", offset, res); 218 return res; 219 } 220 221 return 0; 222 } 223 224 static size_t ec_get_size(void *hnd) 225 { 226 struct ec_data *dev = hnd; 227 228 return dev && dev->fd > 0 ? dev->info.flash_size : 0; 229 } 230 231 static size_t ec_get_write_size(void *hnd) 232 { 233 struct ec_data *dev = hnd; 234 235 return dev && dev->fd > 0 ? dev->info.write_ideal_size : 0; 236 } 237 238 static size_t ec_get_erase_size(void *hnd) 239 { 240 struct ec_data *dev = hnd; 241 242 return dev && dev->fd > 0 ? dev->info.erase_block_size : 0; 243 } 244 245 static off_t ec_get_fmap_offset(void *hnd) 246 { 247 struct ec_data *dev = hnd; 248 249 if (!hnd) 250 return 0; 251 252 /* 253 * Try to find the FMAP signature at 64-byte boundaries 254 * from the end of the RO region. 255 */ 256 return dev->ro_region.offset + dev->ro_region.size; 257 } 258 259 const struct flash_device_ops flash_ec_ops = { 260 .name = "ec", 261 .open = ec_open, 262 .close = ec_close, 263 .read = ec_read, 264 .write = ec_write, 265 .erase = ec_erase, 266 .get_size = ec_get_size, 267 .get_write_size = ec_get_write_size, 268 .get_erase_size = ec_get_erase_size, 269 .get_fmap_offset = ec_get_fmap_offset, 270 .cmd = ec_command, 271 }; 272