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