blob: 3884c287036dcf1c40abc9629c854d65b6874ffd [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
Dees_Troy1669f892013-09-04 18:35:08 +000017/*
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080018#include <fs_mgr.h>
Dees_Troy1669f892013-09-04 18:35:08 +000019*/
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080020#include "bootloader.h"
21#include "common.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040022extern "C" {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080023#include "mtdutils/mtdutils.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040024}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080025#include "roots.h"
26
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
Doug Zongkercfd256a2011-04-22 09:26:44 -070030#include <sys/stat.h>
31#include <unistd.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080032
Dees_Troy1669f892013-09-04 18:35:08 +000033static char device_type = 'e'; // e for emmc or m for mtd, default is emmc
34static char device_name[256];
35
36/*
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070037static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
38static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
39static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
40static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
Dees_Troy1669f892013-09-04 18:35:08 +000041*/
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070042int get_bootloader_message(struct bootloader_message *out) {
Dees_Troy1669f892013-09-04 18:35:08 +000043 //volume_for_path("/misc");
44 if (device_name[0] == 0) {
Adam Blissb2ceb692011-07-13 15:13:54 -070045 LOGE("Cannot load volume /misc!\n");
46 return -1;
47 }
Dees_Troy1669f892013-09-04 18:35:08 +000048 if (device_type == 'm') {
49 return get_bootloader_message_mtd_name(out);
50 } else if (device_type == 'e') {
51 return get_bootloader_message_block_name(out);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080052 }
Dees_Troy1669f892013-09-04 18:35:08 +000053 LOGE("unknown misc partition fs_type \"%c\"\n", device_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070054 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070055}
56
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070057int set_bootloader_message(const struct bootloader_message *in) {
Dees_Troy1669f892013-09-04 18:35:08 +000058 //volume_for_path("/misc");
59 if (device_name[0] == 0) {
Adam Blissb2ceb692011-07-13 15:13:54 -070060 LOGE("Cannot load volume /misc!\n");
61 return -1;
62 }
Dees_Troy1669f892013-09-04 18:35:08 +000063 if (device_type == 'm') {
64 return set_bootloader_message_mtd_name(in, device_name);
65 } else if (device_type == 'e') {
66 return set_bootloader_message_block_name(in, device_name);
Doug Zongker04611da2010-08-12 15:35:29 -070067 }
Dees_Troy1669f892013-09-04 18:35:08 +000068 LOGE("unknown misc partition type \"%c\"\n", device_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070069 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070070}
71
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070072// ------------------------------
73// for misc partitions on MTD
74// ------------------------------
Doug Zongker04611da2010-08-12 15:35:29 -070075
76static const int MISC_PAGES = 3; // number of pages to save
77static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
Dees_Troy1669f892013-09-04 18:35:08 +000078/*
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070079static int get_bootloader_message_mtd(struct bootloader_message *out,
80 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080081 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070082 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080083 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080084 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080085 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080086 return -1;
87 }
88
89 MtdReadContext *read = mtd_read_partition(part);
90 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080091 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080092 return -1;
93 }
94
95 const ssize_t size = write_size * MISC_PAGES;
96 char data[size];
97 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080098 if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080099 mtd_read_close(read);
100 if (r != size) return -1;
101
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800102 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
103 return 0;
104}
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700105static int set_bootloader_message_mtd(const struct bootloader_message *in,
106 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800107 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700108 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800109 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800110 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800111 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800112 return -1;
113 }
114
115 MtdReadContext *read = mtd_read_partition(part);
116 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800117 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800118 return -1;
119 }
120
121 ssize_t size = write_size * MISC_PAGES;
122 char data[size];
123 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800124 if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800125 mtd_read_close(read);
126 if (r != size) return -1;
127
128 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
129
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800130 MtdWriteContext *write = mtd_write_partition(part);
131 if (write == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800132 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800133 return -1;
134 }
135 if (mtd_write_data(write, data, size) != size) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800136 LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800137 mtd_write_close(write);
138 return -1;
139 }
140 if (mtd_write_close(write)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800141 LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800142 return -1;
143 }
144
145 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
146 return 0;
147}
Dees_Troy1669f892013-09-04 18:35:08 +0000148*/
Doug Zongker04611da2010-08-12 15:35:29 -0700149
Dees_Troy1669f892013-09-04 18:35:08 +0000150void set_device_type(char new_type) {
151 device_type = new_type;
152}
153
154void set_device_name(const char* new_name) {
155 if (strlen(new_name) >= sizeof(device_name)) {
156 LOGE("New device name of '%s' is too large for bootloader.cpp\n", new_name);
157 } else {
158 strcpy(device_name, new_name);
159 }
160}
161
162int get_bootloader_message_mtd_name(struct bootloader_message *out) {
163 size_t write_size;
164 mtd_scan_partitions();
165 const MtdPartition *part = mtd_find_partition_by_name(device_name);
166 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
167 LOGE("Can't find %s\n", device_name);
168 return -1;
169 }
170
171 MtdReadContext *read = mtd_read_partition(part);
172 if (read == NULL) {
173 LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno));
174 return -1;
175 }
176
177 const ssize_t size = write_size * MISC_PAGES;
178 char data[size];
179 ssize_t r = mtd_read_data(read, data, size);
180 if (r != size) LOGE("Can't read %s\n(%s)\n", device_name, strerror(errno));
181 mtd_read_close(read);
182 if (r != size) return -1;
183
184 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
185 return 0;
186}
Doug Zongker04611da2010-08-12 15:35:29 -0700187
Dees_Troy2673cec2013-04-02 20:22:16 +0000188int set_bootloader_message_mtd_name(const struct bootloader_message *in,
189 const char* mtd_name) {
190 size_t write_size;
191 mtd_scan_partitions();
192 const MtdPartition *part = mtd_find_partition_by_name(mtd_name);
193 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
194 printf("Can't find %s\n", mtd_name);
195 return -1;
196 }
197
198 MtdReadContext *read = mtd_read_partition(part);
199 if (read == NULL) {
200 printf("Can't open %s\n(%s)\n", mtd_name, strerror(errno));
201 return -1;
202 }
203
204 ssize_t size = write_size * MISC_PAGES;
205 char data[size];
206 ssize_t r = mtd_read_data(read, data, size);
207 if (r != size) printf("Can't read %s\n(%s)\n", mtd_name, strerror(errno));
208 mtd_read_close(read);
209 if (r != size) return -1;
210
211 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
212
213 MtdWriteContext *write = mtd_write_partition(part);
214 if (write == NULL) {
215 printf("Can't open %s\n(%s)\n", mtd_name, strerror(errno));
216 return -1;
217 }
218 if (mtd_write_data(write, data, size) != size) {
219 printf("Can't write %s\n(%s)\n", mtd_name, strerror(errno));
220 mtd_write_close(write);
221 return -1;
222 }
223 if (mtd_write_close(write)) {
224 printf("Can't finish %s\n(%s)\n", mtd_name, strerror(errno));
225 return -1;
226 }
227
228 printf("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
229 return 0;
230}
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700231
232// ------------------------------------
233// for misc partitions on block devices
234// ------------------------------------
235
Doug Zongkercfd256a2011-04-22 09:26:44 -0700236static void wait_for_device(const char* fn) {
237 int tries = 0;
238 int ret;
239 struct stat buf;
240 do {
241 ++tries;
242 ret = stat(fn, &buf);
243 if (ret) {
244 printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
245 sleep(1);
246 }
247 } while (ret && tries < 10);
248 if (ret) {
249 printf("failed to stat %s\n", fn);
250 }
251}
Dees_Troy1669f892013-09-04 18:35:08 +0000252/*
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700253static int get_bootloader_message_block(struct bootloader_message *out,
254 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800255 wait_for_device(v->blk_device);
256 FILE* f = fopen(v->blk_device, "rb");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700257 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800258 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700259 return -1;
260 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500261#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
262 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
263#endif
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700264 struct bootloader_message temp;
265 int count = fread(&temp, sizeof(temp), 1, f);
266 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800267 LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700268 return -1;
269 }
270 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800271 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700272 return -1;
273 }
274 memcpy(out, &temp, sizeof(temp));
275 return 0;
276}
277
278static int set_bootloader_message_block(const struct bootloader_message *in,
279 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800280 wait_for_device(v->blk_device);
Matt Mower2fec60a2014-07-09 11:50:05 -0500281 FILE* f = fopen(v->blk_device, "rb+");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700282 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800283 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700284 return -1;
285 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500286#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
287 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
288#endif
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700289 int count = fwrite(in, sizeof(*in), 1, f);
290 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800291 LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700292 return -1;
293 }
294 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800295 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700296 return -1;
297 }
298 return 0;
299}
Dees_Troy1669f892013-09-04 18:35:08 +0000300*/
301
302int get_bootloader_message_block_name(struct bootloader_message *out) {
303 wait_for_device(device_name);
304 FILE* f = fopen(device_name, "rb");
305 if (f == NULL) {
306 LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno));
307 return -1;
308 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500309#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
310 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
311#endif
Dees_Troy1669f892013-09-04 18:35:08 +0000312 struct bootloader_message temp;
313 int count = fread(&temp, sizeof(temp), 1, f);
314 if (count != 1) {
315 LOGE("Failed reading %s\n(%s)\n", device_name, strerror(errno));
316 return -1;
317 }
318 if (fclose(f) != 0) {
319 LOGE("Failed closing %s\n(%s)\n", device_name, strerror(errno));
320 return -1;
321 }
322 memcpy(out, &temp, sizeof(temp));
323 return 0;
324}
Dees_Troy2673cec2013-04-02 20:22:16 +0000325
326int set_bootloader_message_block_name(const struct bootloader_message *in,
327 const char* block_name) {
328 wait_for_device(block_name);
Matt Mower2fec60a2014-07-09 11:50:05 -0500329 FILE* f = fopen(block_name, "rb+");
Dees_Troy2673cec2013-04-02 20:22:16 +0000330 if (f == NULL) {
331 printf("Can't open %s\n(%s)\n", block_name, strerror(errno));
332 return -1;
333 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500334#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
335 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
336#endif
Dees_Troy2673cec2013-04-02 20:22:16 +0000337 int count = fwrite(in, sizeof(*in), 1, f);
338 if (count != 1) {
339 printf("Failed writing %s\n(%s)\n", block_name, strerror(errno));
340 return -1;
341 }
342 if (fclose(f) != 0) {
343 printf("Failed closing %s\n(%s)\n", block_name, strerror(errno));
344 return -1;
345 }
346 return 0;
347}
Dees_Troya449a6f2013-04-07 17:50:11 -0500348
349static const char *COMMAND_FILE = "/cache/recovery/command";
350static const int MAX_ARG_LENGTH = 4096;
351static const int MAX_ARGS = 100;
352
353// command line args come from, in decreasing precedence:
354// - the actual command line
355// - the bootloader control block (one per line, after "recovery")
356// - the contents of COMMAND_FILE (one per line)
357void
358get_args(int *argc, char ***argv) {
359 struct bootloader_message boot;
360 memset(&boot, 0, sizeof(boot));
361 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
362
363 if (boot.command[0] != 0 && boot.command[0] != 255) {
364 LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
365 }
366
367 if (boot.status[0] != 0 && boot.status[0] != 255) {
368 LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
369 }
370
371 // --- if arguments weren't supplied, look in the bootloader control block
372 if (*argc <= 1) {
373 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
374 const char *arg = strtok(boot.recovery, "\n");
375 if (arg != NULL && !strcmp(arg, "recovery")) {
376 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
377 (*argv)[0] = strdup(arg);
378 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
379 if ((arg = strtok(NULL, "\n")) == NULL) break;
380 (*argv)[*argc] = strdup(arg);
381 }
382 LOGI("Got arguments from boot message\n");
383 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
384 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
385 }
386 }
387
388 // --- if that doesn't work, try the command file
389 if (*argc <= 1) {
390 FILE *fp = fopen(COMMAND_FILE, "r");
391 if (fp != NULL) {
392 char *argv0 = (*argv)[0];
393 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
394 (*argv)[0] = argv0; // use the same program name
395
396 char buf[MAX_ARG_LENGTH];
397 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
398 if (!fgets(buf, sizeof(buf), fp)) break;
399 (*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
400 }
401
402 fflush(fp);
403 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno));
404 fclose(fp);
405 LOGI("Got arguments from %s\n", COMMAND_FILE);
406 }
407 }
408
409 // --> write the arguments we have back into the bootloader control block
410 // always boot into recovery after this (until finish_recovery() is called)
411 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
412 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
413 int i;
414 for (i = 1; i < *argc; ++i) {
415 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
416 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
417 }
418 set_bootloader_message(&boot);
419}