blob: b5b20e9c90082616b3edffe33b02bae754c8f298 [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}
that4e0e3fc2015-04-13 19:52:49 +020025/*
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080026#include "roots.h"
that4e0e3fc2015-04-13 19:52:49 +020027*/
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080028#include <errno.h>
29#include <stdio.h>
30#include <string.h>
Doug Zongkercfd256a2011-04-22 09:26:44 -070031#include <sys/stat.h>
32#include <unistd.h>
Ethan Yonkerc798c9c2015-10-09 11:15:26 -050033#include <stdlib.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080034
that4e0e3fc2015-04-13 19:52:49 +020035// fake Volume struct that allows us to use the AOSP code easily
36struct Volume
37{
38 char fs_type[8];
39 char blk_device[256];
40};
Dees_Troy1669f892013-09-04 18:35:08 +000041
that4e0e3fc2015-04-13 19:52:49 +020042static Volume misc;
43
44void set_misc_device(const char* type, const char* name) {
45 strlcpy(misc.fs_type, type, sizeof(misc.fs_type));
46 if (strlen(name) >= sizeof(misc.blk_device)) {
47 LOGE("New device name of '%s' is too large for bootloader.cpp\n", name);
48 } else {
49 strcpy(misc.blk_device, name);
50 }
51}
52
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070053static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
54static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
55static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
56static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
that4e0e3fc2015-04-13 19:52:49 +020057
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070058int get_bootloader_message(struct bootloader_message *out) {
that4e0e3fc2015-04-13 19:52:49 +020059#if 0
60 Volume* v = volume_for_path("/misc");
61 if (v == NULL) {
Adam Blissb2ceb692011-07-13 15:13:54 -070062 LOGE("Cannot load volume /misc!\n");
63 return -1;
64 }
that4e0e3fc2015-04-13 19:52:49 +020065#else
66 Volume* v = &misc;
67 if (v->fs_type[0] == 0) {
68 LOGI("Not using /misc, not defined in fstab.\n");
69 return -1;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080070 }
that4e0e3fc2015-04-13 19:52:49 +020071#endif
72 if (strcmp(v->fs_type, "mtd") == 0) {
73 return get_bootloader_message_mtd(out, v);
74 } else if (strcmp(v->fs_type, "emmc") == 0) {
75 return get_bootloader_message_block(out, v);
76 }
77 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070078 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070079}
80
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070081int set_bootloader_message(const struct bootloader_message *in) {
that4e0e3fc2015-04-13 19:52:49 +020082#if 0
83 Volume* v = volume_for_path("/misc");
84 if (v == NULL) {
Adam Blissb2ceb692011-07-13 15:13:54 -070085 LOGE("Cannot load volume /misc!\n");
86 return -1;
87 }
that4e0e3fc2015-04-13 19:52:49 +020088#else
89 Volume* v = &misc;
90 if (v->fs_type[0] == 0) {
91 LOGI("Not using /misc, not defined in fstab.\n");
92 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070093 }
that4e0e3fc2015-04-13 19:52:49 +020094#endif
95 if (strcmp(v->fs_type, "mtd") == 0) {
96 return set_bootloader_message_mtd(in, v);
97 } else if (strcmp(v->fs_type, "emmc") == 0) {
98 return set_bootloader_message_block(in, v);
99 }
100 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700101 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -0700102}
103
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700104// ------------------------------
105// for misc partitions on MTD
106// ------------------------------
Doug Zongker04611da2010-08-12 15:35:29 -0700107
108static const int MISC_PAGES = 3; // number of pages to save
109static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
that4e0e3fc2015-04-13 19:52:49 +0200110
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700111static int get_bootloader_message_mtd(struct bootloader_message *out,
112 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800113 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700114 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800115 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800116 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800117 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800118 return -1;
119 }
120
121 MtdReadContext *read = mtd_read_partition(part);
122 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800123 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800124 return -1;
125 }
126
127 const ssize_t size = write_size * MISC_PAGES;
128 char data[size];
129 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800130 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 -0800131 mtd_read_close(read);
132 if (r != size) return -1;
133
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800134 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
135 return 0;
136}
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700137static int set_bootloader_message_mtd(const struct bootloader_message *in,
138 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800139 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700140 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800141 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800142 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800143 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800144 return -1;
145 }
146
147 MtdReadContext *read = mtd_read_partition(part);
148 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800149 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800150 return -1;
151 }
152
153 ssize_t size = write_size * MISC_PAGES;
154 char data[size];
155 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800156 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 -0800157 mtd_read_close(read);
158 if (r != size) return -1;
159
160 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
161
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800162 MtdWriteContext *write = mtd_write_partition(part);
163 if (write == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800164 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800165 return -1;
166 }
167 if (mtd_write_data(write, data, size) != size) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800168 LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800169 mtd_write_close(write);
170 return -1;
171 }
172 if (mtd_write_close(write)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800173 LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800174 return -1;
175 }
176
177 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
178 return 0;
179}
Doug Zongker04611da2010-08-12 15:35:29 -0700180
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700181
182// ------------------------------------
183// for misc partitions on block devices
184// ------------------------------------
185
Doug Zongkercfd256a2011-04-22 09:26:44 -0700186static void wait_for_device(const char* fn) {
187 int tries = 0;
188 int ret;
189 struct stat buf;
190 do {
191 ++tries;
192 ret = stat(fn, &buf);
193 if (ret) {
194 printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
195 sleep(1);
196 }
197 } while (ret && tries < 10);
198 if (ret) {
199 printf("failed to stat %s\n", fn);
200 }
201}
that4e0e3fc2015-04-13 19:52:49 +0200202
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700203static int get_bootloader_message_block(struct bootloader_message *out,
204 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800205 wait_for_device(v->blk_device);
206 FILE* f = fopen(v->blk_device, "rb");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700207 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800208 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700209 return -1;
210 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500211#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
212 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
213#endif
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700214 struct bootloader_message temp;
215 int count = fread(&temp, sizeof(temp), 1, f);
216 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800217 LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700218 return -1;
219 }
220 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800221 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700222 return -1;
223 }
224 memcpy(out, &temp, sizeof(temp));
225 return 0;
226}
227
228static int set_bootloader_message_block(const struct bootloader_message *in,
229 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800230 wait_for_device(v->blk_device);
Matt Mower2fec60a2014-07-09 11:50:05 -0500231 FILE* f = fopen(v->blk_device, "rb+");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700232 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800233 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700234 return -1;
235 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500236#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
237 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
238#endif
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700239 int count = fwrite(in, sizeof(*in), 1, f);
240 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800241 LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700242 return -1;
243 }
244 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800245 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700246 return -1;
247 }
248 return 0;
249}
Dees_Troy1669f892013-09-04 18:35:08 +0000250
Dees_Troya449a6f2013-04-07 17:50:11 -0500251
252static const char *COMMAND_FILE = "/cache/recovery/command";
253static const int MAX_ARG_LENGTH = 4096;
254static const int MAX_ARGS = 100;
255
256// command line args come from, in decreasing precedence:
257// - the actual command line
258// - the bootloader control block (one per line, after "recovery")
259// - the contents of COMMAND_FILE (one per line)
260void
261get_args(int *argc, char ***argv) {
262 struct bootloader_message boot;
263 memset(&boot, 0, sizeof(boot));
264 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
265
266 if (boot.command[0] != 0 && boot.command[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200267 LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
Dees_Troya449a6f2013-04-07 17:50:11 -0500268 }
269
270 if (boot.status[0] != 0 && boot.status[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200271 LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
Dees_Troya449a6f2013-04-07 17:50:11 -0500272 }
273
274 // --- if arguments weren't supplied, look in the bootloader control block
275 if (*argc <= 1) {
276 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
277 const char *arg = strtok(boot.recovery, "\n");
278 if (arg != NULL && !strcmp(arg, "recovery")) {
279 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
280 (*argv)[0] = strdup(arg);
281 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
282 if ((arg = strtok(NULL, "\n")) == NULL) break;
283 (*argv)[*argc] = strdup(arg);
284 }
285 LOGI("Got arguments from boot message\n");
286 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
287 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
288 }
289 }
290
291 // --- if that doesn't work, try the command file
292 if (*argc <= 1) {
293 FILE *fp = fopen(COMMAND_FILE, "r");
294 if (fp != NULL) {
that9eadc512015-03-27 00:06:51 +0100295 char *token;
Dees_Troya449a6f2013-04-07 17:50:11 -0500296 char *argv0 = (*argv)[0];
297 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
298 (*argv)[0] = argv0; // use the same program name
299
300 char buf[MAX_ARG_LENGTH];
301 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
302 if (!fgets(buf, sizeof(buf), fp)) break;
that9eadc512015-03-27 00:06:51 +0100303 token = strtok(buf, "\r\n");
304 if (token != NULL) {
305 (*argv)[*argc] = strdup(token); // Strip newline.
306 } else {
307 --*argc;
308 }
Dees_Troya449a6f2013-04-07 17:50:11 -0500309 }
310
311 fflush(fp);
that9eadc512015-03-27 00:06:51 +0100312 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno));
313 fclose(fp);
Dees_Troya449a6f2013-04-07 17:50:11 -0500314 LOGI("Got arguments from %s\n", COMMAND_FILE);
315 }
316 }
317
318 // --> write the arguments we have back into the bootloader control block
319 // always boot into recovery after this (until finish_recovery() is called)
320 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
321 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
322 int i;
323 for (i = 1; i < *argc; ++i) {
324 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
325 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
326 }
327 set_bootloader_message(&boot);
328}