1 /*
2 * Copyright (C) 2008 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
17 #include "bootloader.h"
18 #include "common.h"
19 #include "mtdutils/mtdutils.h"
20 #include "roots.h"
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 static const int MISC_PAGES = 3; // number of pages to save
27 static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
28
29 #undef LOGE
30 #define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__)
31
32 #ifdef LOG_VERBOSE
dump_data(const char * data,int len)33 static void dump_data(const char *data, int len) {
34 int pos;
35 for (pos = 0; pos < len; ) {
36 printf("%05x: %02x", pos, data[pos]);
37 for (++pos; pos < len && (pos % 24) != 0; ++pos) {
38 printf(" %02x", data[pos]);
39 }
40 printf("\n");
41 }
42 }
43 #endif
44
get_bootloader_message(struct bootloader_message * out)45 int get_bootloader_message(struct bootloader_message *out) {
46 size_t write_size;
47 const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME);
48 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
49 LOGE("Can't find %s\n", MISC_NAME);
50 return -1;
51 }
52
53 MtdReadContext *read = mtd_read_partition(part);
54 if (read == NULL) {
55 LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
56 return -1;
57 }
58
59 const ssize_t size = write_size * MISC_PAGES;
60 char data[size];
61 ssize_t r = mtd_read_data(read, data, size);
62 if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
63 mtd_read_close(read);
64 if (r != size) return -1;
65
66 #ifdef LOG_VERBOSE
67 printf("\n--- get_bootloader_message ---\n");
68 dump_data(data, size);
69 printf("\n");
70 #endif
71
72 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
73 return 0;
74 }
75
set_bootloader_message(const struct bootloader_message * in)76 int set_bootloader_message(const struct bootloader_message *in) {
77 size_t write_size;
78 const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME);
79 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
80 LOGE("Can't find %s\n", MISC_NAME);
81 return -1;
82 }
83
84 MtdReadContext *read = mtd_read_partition(part);
85 if (read == NULL) {
86 LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
87 return -1;
88 }
89
90 ssize_t size = write_size * MISC_PAGES;
91 char data[size];
92 ssize_t r = mtd_read_data(read, data, size);
93 if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
94 mtd_read_close(read);
95 if (r != size) return -1;
96
97 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
98
99 #ifdef LOG_VERBOSE
100 printf("\n--- set_bootloader_message ---\n");
101 dump_data(data, size);
102 printf("\n");
103 #endif
104
105 MtdWriteContext *write = mtd_write_partition(part);
106 if (write == NULL) {
107 LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
108 return -1;
109 }
110 if (mtd_write_data(write, data, size) != size) {
111 LOGE("Can't write %s\n(%s)\n", MISC_NAME, strerror(errno));
112 mtd_write_close(write);
113 return -1;
114 }
115 if (mtd_write_close(write)) {
116 LOGE("Can't finish %s\n(%s)\n", MISC_NAME, strerror(errno));
117 return -1;
118 }
119
120 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
121 return 0;
122 }
123
124 /* Update Image
125 *
126 * - will be stored in the "cache" partition
127 * - bad blocks will be ignored, like boot.img and recovery.img
128 * - the first block will be the image header (described below)
129 * - the size is in BYTES, inclusive of the header
130 * - offsets are in BYTES from the start of the update header
131 * - two raw bitmaps will be included, the "busy" and "fail" bitmaps
132 * - for dream, the bitmaps will be 320x480x16bpp RGB565
133 */
134
135 struct update_header {
136 unsigned char MAGIC[UPDATE_MAGIC_SIZE];
137
138 unsigned version;
139 unsigned size;
140
141 unsigned image_offset;
142 unsigned image_length;
143
144 unsigned bitmap_width;
145 unsigned bitmap_height;
146 unsigned bitmap_bpp;
147
148 unsigned busy_bitmap_offset;
149 unsigned busy_bitmap_length;
150
151 unsigned fail_bitmap_offset;
152 unsigned fail_bitmap_length;
153 };
154
write_update_for_bootloader(const char * update,int update_length,int bitmap_width,int bitmap_height,int bitmap_bpp,const char * busy_bitmap,const char * fail_bitmap,const char * log_filename)155 int write_update_for_bootloader(
156 const char *update, int update_length,
157 int bitmap_width, int bitmap_height, int bitmap_bpp,
158 const char *busy_bitmap, const char *fail_bitmap,
159 const char *log_filename) {
160 const MtdPartition *part = mtd_find_partition_by_name(CACHE_NAME);
161 if (part == NULL) {
162 LOGE("Can't find %s\n", CACHE_NAME);
163 return -1;
164 }
165
166 MtdWriteContext *write = mtd_write_partition(part);
167 if (write == NULL) {
168 LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno));
169 return -1;
170 }
171
172 /* Write an invalid (zero) header first, to disable any previous
173 * update and any other structured contents (like a filesystem),
174 * and as a placeholder for the amount of space required.
175 */
176
177 struct update_header header;
178 memset(&header, 0, sizeof(header));
179 const ssize_t header_size = sizeof(header);
180 if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
181 LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
182 mtd_write_close(write);
183 return -1;
184 }
185
186 /* Write each section individually block-aligned, so we can write
187 * each block independently without complicated buffering.
188 */
189
190 memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
191 header.version = UPDATE_VERSION;
192 header.size = header_size;
193
194 if (log_filename != NULL) {
195 // Write 1 byte into the following block, then fill to the end
196 // in order to reserve that block. We'll use the block to
197 // send a copy of the log through to the next invocation of
198 // recovery. We write the log as late as possible in order to
199 // capture any messages emitted by this function.
200 mtd_erase_blocks(write, 0);
201 if (mtd_write_data(write, (char*) &header, 1) != 1) {
202 LOGE("Can't write log block to %s\n(%s)\n",
203 CACHE_NAME, strerror(errno));
204 mtd_write_close(write);
205 return -1;
206 }
207 }
208
209 off_t image_start_pos = mtd_erase_blocks(write, 0);
210 header.image_length = update_length;
211 if ((int) header.image_offset == -1 ||
212 mtd_write_data(write, update, update_length) != update_length) {
213 LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno));
214 mtd_write_close(write);
215 return -1;
216 }
217 off_t busy_start_pos = mtd_erase_blocks(write, 0);
218 header.image_offset = mtd_find_write_start(write, image_start_pos);
219
220 header.bitmap_width = bitmap_width;
221 header.bitmap_height = bitmap_height;
222 header.bitmap_bpp = bitmap_bpp;
223
224 int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;
225
226 LOGE("writing busy bitmap\n");
227 header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
228 if ((int) header.busy_bitmap_offset == -1 ||
229 mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
230 LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
231 mtd_write_close(write);
232 return -1;
233 }
234 LOGE("busy bitmap written\n");
235 off_t fail_start_pos = mtd_erase_blocks(write, 0);
236 LOGE("block padded\n");
237 header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos);
238
239 header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
240 if ((int) header.fail_bitmap_offset == -1 ||
241 mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
242 LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
243 mtd_write_close(write);
244 return -1;
245 }
246 LOGE("finishing block\n");
247 mtd_erase_blocks(write, 0);
248 LOGE("finished block\n");
249 header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos);
250
251 /* Write the header last, after all the blocks it refers to, so that
252 * when the magic number is installed everything is valid.
253 */
254
255 if (mtd_write_close(write)) {
256 LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
257 return -1;
258 }
259
260 write = mtd_write_partition(part);
261 if (write == NULL) {
262 LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
263 return -1;
264 }
265
266 if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
267 LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
268 mtd_write_close(write);
269 return -1;
270 }
271
272 if (log_filename != NULL) {
273 LOGE("writing log\n");
274 size_t erase_size;
275 if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) {
276 LOGE("Error reading block size\n(%s)\n", strerror(errno));
277 mtd_write_close(write);
278 return -1;
279 }
280 mtd_erase_blocks(write, 0);
281
282 if (erase_size > 0) {
283 char* log = malloc(erase_size);
284 FILE* f = fopen(log_filename, "rb");
285 // The fseek() may fail if it tries to go before the
286 // beginning of the log, but that's okay because we want
287 // to be positioned at the start anyway.
288 fseek(f, -(erase_size-sizeof(size_t)-LOG_MAGIC_SIZE), SEEK_END);
289 memcpy(log, LOG_MAGIC, LOG_MAGIC_SIZE);
290 size_t read = fread(log+sizeof(size_t)+LOG_MAGIC_SIZE,
291 1, erase_size-sizeof(size_t)-LOG_MAGIC_SIZE, f);
292 LOGI("read %d bytes from log\n", (int)read);
293 *(size_t *)(log + LOG_MAGIC_SIZE) = read;
294 fclose(f);
295 if (mtd_write_data(write, log, erase_size) != erase_size) {
296 LOGE("failed to store log in cache partition\n(%s)\n",
297 strerror(errno));
298 mtd_write_close(write);
299 }
300 free(log);
301 }
302 }
303
304 if (mtd_erase_blocks(write, 0) != image_start_pos) {
305 LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
306 mtd_write_close(write);
307 return -1;
308 }
309
310 LOGE("closing partition\n");
311 if (mtd_write_close(write)) {
312 LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
313 return -1;
314 }
315
316 return 0;
317 }
318