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 
flash_open(const char * name,const void * params)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 
flash_close(struct flash_device * dev)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 
flash_read(struct flash_device * dev,off_t off,void * buff,size_t len)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 
flash_write(struct flash_device * dev,off_t off,void * buff,size_t len)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 
flash_erase(struct flash_device * dev,off_t off,size_t len)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 
flash_get_size(struct flash_device * dev)123 size_t flash_get_size(struct flash_device *dev)
124 {
125 	return dev->ops->get_size(dev->priv_data);
126 }
127 
flash_get_fmap(struct flash_device * dev)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 
flash_get_gbb(struct flash_device * dev,size_t * size)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 
flash_cmd(struct flash_device * dev,int cmd,int ver,const void * odata,int osize,void * idata,int isize)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