blob: d4039d8ca94bac8ecc4f6a8cddc5d747f8f6475a [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
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
Doug Zongkerd4208f92010-09-20 12:16:13 -070026static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
27static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
28static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
29static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
30
31int get_bootloader_message(struct bootloader_message *out) {
32 Volume* v = volume_for_path("/misc");
Kolja Dummann75017982010-12-28 23:54:29 +010033 if(v)
34 {
35 if (strcmp(v->fs_type, "mtd") == 0) {
36 return get_bootloader_message_mtd(out, v);
37 } else if (strcmp(v->fs_type, "emmc") == 0) {
38 return get_bootloader_message_block(out, v);
39 }
40 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
41 return -1;
Doug Zongkerd4208f92010-09-20 12:16:13 -070042 }
Doug Zongkerd4208f92010-09-20 12:16:13 -070043 return -1;
44}
45
46int set_bootloader_message(const struct bootloader_message *in) {
47 Volume* v = volume_for_path("/misc");
Kolja Dummann75017982010-12-28 23:54:29 +010048 if(v)
49 {
50 if (strcmp(v->fs_type, "mtd") == 0) {
51 return set_bootloader_message_mtd(in, v);
52 } else if (strcmp(v->fs_type, "emmc") == 0) {
53 return set_bootloader_message_block(in, v);
54 }
55 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
56 return -1;
Doug Zongkerd4208f92010-09-20 12:16:13 -070057 }
Doug Zongkerd4208f92010-09-20 12:16:13 -070058 return -1;
59}
60
61// ------------------------------
62// for misc partitions on MTD
63// ------------------------------
64
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080065static const int MISC_PAGES = 3; // number of pages to save
66static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
67
Doug Zongkerd4208f92010-09-20 12:16:13 -070068static int get_bootloader_message_mtd(struct bootloader_message *out,
69 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080070 size_t write_size;
Doug Zongkerd4208f92010-09-20 12:16:13 -070071 mtd_scan_partitions();
72 const MtdPartition *part = mtd_find_partition_by_name(v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080073 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Doug Zongkerd4208f92010-09-20 12:16:13 -070074 LOGE("Can't find %s\n", v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080075 return -1;
76 }
77
78 MtdReadContext *read = mtd_read_partition(part);
79 if (read == NULL) {
Doug Zongkerd4208f92010-09-20 12:16:13 -070080 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080081 return -1;
82 }
83
84 const ssize_t size = write_size * MISC_PAGES;
85 char data[size];
86 ssize_t r = mtd_read_data(read, data, size);
Doug Zongkerd4208f92010-09-20 12:16:13 -070087 if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080088 mtd_read_close(read);
89 if (r != size) return -1;
90
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080091 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
92 return 0;
93}
Doug Zongkerd4208f92010-09-20 12:16:13 -070094static int set_bootloader_message_mtd(const struct bootloader_message *in,
95 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080096 size_t write_size;
Doug Zongkerd4208f92010-09-20 12:16:13 -070097 mtd_scan_partitions();
98 const MtdPartition *part = mtd_find_partition_by_name(v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080099 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700100 LOGE("Can't find %s\n", v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800101 return -1;
102 }
103
104 MtdReadContext *read = mtd_read_partition(part);
105 if (read == NULL) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700106 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800107 return -1;
108 }
109
110 ssize_t size = write_size * MISC_PAGES;
111 char data[size];
112 ssize_t r = mtd_read_data(read, data, size);
Doug Zongkerd4208f92010-09-20 12:16:13 -0700113 if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800114 mtd_read_close(read);
115 if (r != size) return -1;
116
117 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
118
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800119 MtdWriteContext *write = mtd_write_partition(part);
120 if (write == NULL) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700121 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800122 return -1;
123 }
124 if (mtd_write_data(write, data, size) != size) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700125 LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800126 mtd_write_close(write);
127 return -1;
128 }
129 if (mtd_write_close(write)) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700130 LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800131 return -1;
132 }
133
134 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
135 return 0;
136}
Doug Zongkerd4208f92010-09-20 12:16:13 -0700137
138
139// ------------------------------------
140// for misc partitions on block devices
141// ------------------------------------
142
143static int get_bootloader_message_block(struct bootloader_message *out,
144 const Volume* v) {
145 FILE* f = fopen(v->device, "rb");
146 if (f == NULL) {
147 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
148 return -1;
149 }
150 struct bootloader_message temp;
151 int count = fread(&temp, sizeof(temp), 1, f);
152 if (count != 1) {
153 LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno));
154 return -1;
155 }
156 if (fclose(f) != 0) {
157 LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
158 return -1;
159 }
160 memcpy(out, &temp, sizeof(temp));
161 return 0;
162}
163
164static int set_bootloader_message_block(const struct bootloader_message *in,
165 const Volume* v) {
166 FILE* f = fopen(v->device, "wb");
167 if (f == NULL) {
168 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
169 return -1;
170 }
171 int count = fwrite(in, sizeof(*in), 1, f);
172 if (count != 1) {
173 LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno));
174 return -1;
175 }
176 if (fclose(f) != 0) {
177 LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
178 return -1;
179 }
180 return 0;
181}
Koushik Dutta7f13e152011-09-08 16:55:35 -0700182
183/* Update Image
184 *
185 * - will be stored in the "cache" partition
186 * - bad blocks will be ignored, like boot.img and recovery.img
187 * - the first block will be the image header (described below)
188 * - the size is in BYTES, inclusive of the header
189 * - offsets are in BYTES from the start of the update header
190 * - two raw bitmaps will be included, the "busy" and "fail" bitmaps
191 * - for dream, the bitmaps will be 320x480x16bpp RGB565
192 */
193
194#define UPDATE_MAGIC "MSM-RADIO-UPDATE"
195#define UPDATE_MAGIC_SIZE 16
196#define UPDATE_VERSION 0x00010000
197
198struct update_header {
199 unsigned char MAGIC[UPDATE_MAGIC_SIZE];
200
201 unsigned version;
202 unsigned size;
203
204 unsigned image_offset;
205 unsigned image_length;
206
207 unsigned bitmap_width;
208 unsigned bitmap_height;
209 unsigned bitmap_bpp;
210
211 unsigned busy_bitmap_offset;
212 unsigned busy_bitmap_length;
213
214 unsigned fail_bitmap_offset;
215 unsigned fail_bitmap_length;
216};
217
218int write_update_for_bootloader(
219 const char *update, int update_length,
220 int bitmap_width, int bitmap_height, int bitmap_bpp,
221 const char *busy_bitmap, const char *fail_bitmap) {
222 if (ensure_path_unmounted("/cache")) {
223 LOGE("Can't unmount /cache\n");
224 return -1;
225 }
226
227 const MtdPartition *part = mtd_find_partition_by_name("cache");
228 if (part == NULL) {
229 LOGE("Can't find cache\n");
230 return -1;
231 }
232
233 MtdWriteContext *write = mtd_write_partition(part);
234 if (write == NULL) {
235 LOGE("Can't open cache\n(%s)\n", strerror(errno));
236 return -1;
237 }
238
239 /* Write an invalid (zero) header first, to disable any previous
240 * update and any other structured contents (like a filesystem),
241 * and as a placeholder for the amount of space required.
242 */
243
244 struct update_header header;
245 memset(&header, 0, sizeof(header));
246 const ssize_t header_size = sizeof(header);
247 if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
248 LOGE("Can't write header to cache\n(%s)\n", strerror(errno));
249 mtd_write_close(write);
250 return -1;
251 }
252
253 /* Write each section individually block-aligned, so we can write
254 * each block independently without complicated buffering.
255 */
256
257 memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
258 header.version = UPDATE_VERSION;
259 header.size = header_size;
260
261 off_t image_start_pos = mtd_erase_blocks(write, 0);
262 header.image_length = update_length;
263 if ((int) header.image_offset == -1 ||
264 mtd_write_data(write, update, update_length) != update_length) {
265 LOGE("Can't write update to cache\n(%s)\n", strerror(errno));
266 mtd_write_close(write);
267 return -1;
268 }
269 off_t busy_start_pos = mtd_erase_blocks(write, 0);
270 header.image_offset = mtd_find_write_start(write, image_start_pos);
271
272 header.bitmap_width = bitmap_width;
273 header.bitmap_height = bitmap_height;
274 header.bitmap_bpp = bitmap_bpp;
275
276 int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;
277
278 header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
279 if ((int) header.busy_bitmap_offset == -1 ||
280 mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
281 LOGE("Can't write bitmap to cache\n(%s)\n", strerror(errno));
282 mtd_write_close(write);
283 return -1;
284 }
285 off_t fail_start_pos = mtd_erase_blocks(write, 0);
286 header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos);
287
288 header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
289 if ((int) header.fail_bitmap_offset == -1 ||
290 mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
291 LOGE("Can't write bitmap to cache\n(%s)\n", strerror(errno));
292 mtd_write_close(write);
293 return -1;
294 }
295 mtd_erase_blocks(write, 0);
296 header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos);
297
298 /* Write the header last, after all the blocks it refers to, so that
299 * when the magic number is installed everything is valid.
300 */
301
302 if (mtd_write_close(write)) {
303 LOGE("Can't finish writing cache\n(%s)\n", strerror(errno));
304 return -1;
305 }
306
307 write = mtd_write_partition(part);
308 if (write == NULL) {
309 LOGE("Can't reopen cache\n(%s)\n", strerror(errno));
310 return -1;
311 }
312
313 if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
314 LOGE("Can't rewrite header to cache\n(%s)\n", strerror(errno));
315 mtd_write_close(write);
316 return -1;
317 }
318
319 if (mtd_erase_blocks(write, 0) != image_start_pos) {
320 LOGE("Misalignment rewriting cache\n(%s)\n", strerror(errno));
321 mtd_write_close(write);
322 return -1;
323 }
324
325 if (mtd_write_close(write)) {
326 LOGE("Can't finish header of cache\n(%s)\n", strerror(errno));
327 return -1;
328 }
329
330 return 0;
331}