blob: d23d1e9cdea36e5e30c84b3e58a5996d87fee549 [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>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080033
that4e0e3fc2015-04-13 19:52:49 +020034// fake Volume struct that allows us to use the AOSP code easily
35struct Volume
36{
37 char fs_type[8];
38 char blk_device[256];
39};
Dees_Troy1669f892013-09-04 18:35:08 +000040
that4e0e3fc2015-04-13 19:52:49 +020041static Volume misc;
42
43void set_misc_device(const char* type, const char* name) {
44 strlcpy(misc.fs_type, type, sizeof(misc.fs_type));
45 if (strlen(name) >= sizeof(misc.blk_device)) {
46 LOGE("New device name of '%s' is too large for bootloader.cpp\n", name);
47 } else {
48 strcpy(misc.blk_device, name);
49 }
50}
51
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070052static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
53static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
54static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
55static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
that4e0e3fc2015-04-13 19:52:49 +020056
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070057int get_bootloader_message(struct bootloader_message *out) {
that4e0e3fc2015-04-13 19:52:49 +020058#if 0
59 Volume* v = volume_for_path("/misc");
60 if (v == NULL) {
Adam Blissb2ceb692011-07-13 15:13:54 -070061 LOGE("Cannot load volume /misc!\n");
62 return -1;
63 }
that4e0e3fc2015-04-13 19:52:49 +020064#else
65 Volume* v = &misc;
66 if (v->fs_type[0] == 0) {
67 LOGI("Not using /misc, not defined in fstab.\n");
68 return -1;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080069 }
that4e0e3fc2015-04-13 19:52:49 +020070#endif
71 if (strcmp(v->fs_type, "mtd") == 0) {
72 return get_bootloader_message_mtd(out, v);
73 } else if (strcmp(v->fs_type, "emmc") == 0) {
74 return get_bootloader_message_block(out, v);
75 }
76 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070077 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070078}
79
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070080int set_bootloader_message(const struct bootloader_message *in) {
that4e0e3fc2015-04-13 19:52:49 +020081#if 0
82 Volume* v = volume_for_path("/misc");
83 if (v == NULL) {
Adam Blissb2ceb692011-07-13 15:13:54 -070084 LOGE("Cannot load volume /misc!\n");
85 return -1;
86 }
that4e0e3fc2015-04-13 19:52:49 +020087#else
88 Volume* v = &misc;
89 if (v->fs_type[0] == 0) {
90 LOGI("Not using /misc, not defined in fstab.\n");
91 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070092 }
that4e0e3fc2015-04-13 19:52:49 +020093#endif
94 if (strcmp(v->fs_type, "mtd") == 0) {
95 return set_bootloader_message_mtd(in, v);
96 } else if (strcmp(v->fs_type, "emmc") == 0) {
97 return set_bootloader_message_block(in, v);
98 }
99 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700100 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -0700101}
102
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700103// ------------------------------
104// for misc partitions on MTD
105// ------------------------------
Doug Zongker04611da2010-08-12 15:35:29 -0700106
107static const int MISC_PAGES = 3; // number of pages to save
108static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
that4e0e3fc2015-04-13 19:52:49 +0200109
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700110static int get_bootloader_message_mtd(struct bootloader_message *out,
111 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800112 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700113 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800114 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800115 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800116 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800117 return -1;
118 }
119
120 MtdReadContext *read = mtd_read_partition(part);
121 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800122 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800123 return -1;
124 }
125
126 const ssize_t size = write_size * MISC_PAGES;
127 char data[size];
128 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800129 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 -0800130 mtd_read_close(read);
131 if (r != size) return -1;
132
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800133 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
134 return 0;
135}
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700136static int set_bootloader_message_mtd(const struct bootloader_message *in,
137 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800138 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700139 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800140 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800141 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800142 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800143 return -1;
144 }
145
146 MtdReadContext *read = mtd_read_partition(part);
147 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800148 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800149 return -1;
150 }
151
152 ssize_t size = write_size * MISC_PAGES;
153 char data[size];
154 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800155 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 -0800156 mtd_read_close(read);
157 if (r != size) return -1;
158
159 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
160
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800161 MtdWriteContext *write = mtd_write_partition(part);
162 if (write == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800163 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800164 return -1;
165 }
166 if (mtd_write_data(write, data, size) != size) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800167 LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800168 mtd_write_close(write);
169 return -1;
170 }
171 if (mtd_write_close(write)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800172 LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800173 return -1;
174 }
175
176 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
177 return 0;
178}
Doug Zongker04611da2010-08-12 15:35:29 -0700179
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700180
181// ------------------------------------
182// for misc partitions on block devices
183// ------------------------------------
184
Doug Zongkercfd256a2011-04-22 09:26:44 -0700185static void wait_for_device(const char* fn) {
186 int tries = 0;
187 int ret;
188 struct stat buf;
189 do {
190 ++tries;
191 ret = stat(fn, &buf);
192 if (ret) {
193 printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
194 sleep(1);
195 }
196 } while (ret && tries < 10);
197 if (ret) {
198 printf("failed to stat %s\n", fn);
199 }
200}
that4e0e3fc2015-04-13 19:52:49 +0200201
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700202static int get_bootloader_message_block(struct bootloader_message *out,
203 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800204 wait_for_device(v->blk_device);
205 FILE* f = fopen(v->blk_device, "rb");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700206 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800207 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700208 return -1;
209 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500210#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
211 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
212#endif
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700213 struct bootloader_message temp;
214 int count = fread(&temp, sizeof(temp), 1, f);
215 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800216 LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700217 return -1;
218 }
219 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800220 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700221 return -1;
222 }
223 memcpy(out, &temp, sizeof(temp));
224 return 0;
225}
226
227static int set_bootloader_message_block(const struct bootloader_message *in,
228 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800229 wait_for_device(v->blk_device);
Matt Mower2fec60a2014-07-09 11:50:05 -0500230 FILE* f = fopen(v->blk_device, "rb+");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700231 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800232 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700233 return -1;
234 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500235#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
236 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
237#endif
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700238 int count = fwrite(in, sizeof(*in), 1, f);
239 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800240 LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700241 return -1;
242 }
243 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800244 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700245 return -1;
246 }
247 return 0;
248}
Dees_Troy1669f892013-09-04 18:35:08 +0000249
Dees_Troya449a6f2013-04-07 17:50:11 -0500250
251static const char *COMMAND_FILE = "/cache/recovery/command";
252static const int MAX_ARG_LENGTH = 4096;
253static const int MAX_ARGS = 100;
254
255// command line args come from, in decreasing precedence:
256// - the actual command line
257// - the bootloader control block (one per line, after "recovery")
258// - the contents of COMMAND_FILE (one per line)
259void
260get_args(int *argc, char ***argv) {
261 struct bootloader_message boot;
262 memset(&boot, 0, sizeof(boot));
263 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
264
265 if (boot.command[0] != 0 && boot.command[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200266 LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
Dees_Troya449a6f2013-04-07 17:50:11 -0500267 }
268
269 if (boot.status[0] != 0 && boot.status[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200270 LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
Dees_Troya449a6f2013-04-07 17:50:11 -0500271 }
272
273 // --- if arguments weren't supplied, look in the bootloader control block
274 if (*argc <= 1) {
275 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
276 const char *arg = strtok(boot.recovery, "\n");
277 if (arg != NULL && !strcmp(arg, "recovery")) {
278 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
279 (*argv)[0] = strdup(arg);
280 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
281 if ((arg = strtok(NULL, "\n")) == NULL) break;
282 (*argv)[*argc] = strdup(arg);
283 }
284 LOGI("Got arguments from boot message\n");
285 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
286 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
287 }
288 }
289
290 // --- if that doesn't work, try the command file
291 if (*argc <= 1) {
292 FILE *fp = fopen(COMMAND_FILE, "r");
293 if (fp != NULL) {
that9eadc512015-03-27 00:06:51 +0100294 char *token;
Dees_Troya449a6f2013-04-07 17:50:11 -0500295 char *argv0 = (*argv)[0];
296 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
297 (*argv)[0] = argv0; // use the same program name
298
299 char buf[MAX_ARG_LENGTH];
300 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
301 if (!fgets(buf, sizeof(buf), fp)) break;
that9eadc512015-03-27 00:06:51 +0100302 token = strtok(buf, "\r\n");
303 if (token != NULL) {
304 (*argv)[*argc] = strdup(token); // Strip newline.
305 } else {
306 --*argc;
307 }
Dees_Troya449a6f2013-04-07 17:50:11 -0500308 }
309
310 fflush(fp);
that9eadc512015-03-27 00:06:51 +0100311 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno));
312 fclose(fp);
Dees_Troya449a6f2013-04-07 17:50:11 -0500313 LOGI("Got arguments from %s\n", COMMAND_FILE);
314 }
315 }
316
317 // --> write the arguments we have back into the bootloader control block
318 // always boot into recovery after this (until finish_recovery() is called)
319 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
320 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
321 int i;
322 for (i = 1; i < *argc; ++i) {
323 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
324 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
325 }
326 set_bootloader_message(&boot);
327}