• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ec_command(void * hnd,int command,int version,const void * outdata,int outsize,void * indata,int insize)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 
ec_open(const void * params)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 			 &region, 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 
ec_close(void * hnd)141 static void ec_close(void *hnd)
142 {
143 	struct ec_data *dev = hnd;
144 
145 	close(dev->fd);
146 	free(dev);
147 }
148 
ec_read(void * hnd,off_t offset,void * buffer,size_t count)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 
ec_write(void * hnd,off_t offset,void * buffer,size_t count)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 
ec_erase(void * hnd,off_t offset,size_t count)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 
ec_get_size(void * hnd)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 
ec_get_write_size(void * hnd)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 
ec_get_erase_size(void * hnd)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 
ec_get_fmap_offset(void * hnd)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