blob: e2e4fe63036f36824bc7e276f75a8cd098ffeb09 [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 "firmware.h"
20#include "roots.h"
21
22#include <errno.h>
23#include <string.h>
24#include <sys/reboot.h>
25
26static const char *update_type = NULL;
27static const char *update_data = NULL;
28static int update_length = 0;
29
30int remember_firmware_update(const char *type, const char *data, int length) {
31 if (update_type != NULL || update_data != NULL) {
32 LOGE("Multiple firmware images\n");
33 return -1;
34 }
35
36 update_type = type;
37 update_data = data;
38 update_length = length;
39 return 0;
40}
41
Doug Zongker07e1dca2009-05-28 19:02:45 -070042// Return true if there is a firmware update pending.
43int firmware_update_pending() {
44 return update_data != NULL && update_length > 0;
45}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080046
47/* Bootloader / Recovery Flow
48 *
49 * On every boot, the bootloader will read the bootloader_message
50 * from flash and check the command field. The bootloader should
51 * deal with the command field not having a 0 terminator correctly
52 * (so as to not crash if the block is invalid or corrupt).
53 *
54 * The bootloader will have to publish the partition that contains
55 * the bootloader_message to the linux kernel so it can update it.
56 *
57 * if command == "boot-recovery" -> boot recovery.img
58 * else if command == "update-radio" -> update radio image (below)
59 * else if command == "update-hboot" -> update hboot image (below)
60 * else -> boot boot.img (normal boot)
61 *
62 * Radio/Hboot Update Flow
63 * 1. the bootloader will attempt to load and validate the header
64 * 2. if the header is invalid, status="invalid-update", goto #8
65 * 3. display the busy image on-screen
66 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
67 * 5. attempt to update the firmware (depending on the command)
68 * 6. if successful, status="okay", goto #8
69 * 7. if failed, and the old image can still boot, status="failed-update"
70 * 8. write the bootloader_message, leaving the recovery field
71 * unchanged, updating status, and setting command to
72 * "boot-recovery"
73 * 9. reboot
74 *
75 * The bootloader will not modify or erase the cache partition.
76 * It is recovery's responsibility to clean up the mess afterwards.
77 */
78
79int maybe_install_firmware_update(const char *send_intent) {
80 if (update_data == NULL || update_length == 0) return 0;
81
82 /* We destroy the cache partition to pass the update image to the
83 * bootloader, so all we can really do afterwards is wipe cache and reboot.
84 * Set up this instruction now, in case we're interrupted while writing.
85 */
86
87 struct bootloader_message boot;
88 memset(&boot, 0, sizeof(boot));
89 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
90 strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command));
91 if (send_intent != NULL) {
92 strlcat(boot.recovery, "--send_intent=", sizeof(boot.recovery));
93 strlcat(boot.recovery, send_intent, sizeof(boot.recovery));
94 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
95 }
96 if (set_bootloader_message(&boot)) return -1;
97
98 int width = 0, height = 0, bpp = 0;
99 char *busy_image = ui_copy_image(
100 BACKGROUND_ICON_FIRMWARE_INSTALLING, &width, &height, &bpp);
101 char *fail_image = ui_copy_image(
102 BACKGROUND_ICON_FIRMWARE_ERROR, &width, &height, &bpp);
103
104 ui_print("Writing %s image...\n", update_type);
105 if (write_update_for_bootloader(
106 update_data, update_length,
107 width, height, bpp, busy_image, fail_image)) {
108 LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno));
109 format_root_device("CACHE:"); // Attempt to clean cache up, at least.
110 return -1;
111 }
112
113 free(busy_image);
114 free(fail_image);
115
116 /* The update image is fully written, so now we can instruct the bootloader
117 * to install it. (After doing so, it will come back here, and we will
118 * wipe the cache and reboot into the system.)
119 */
120 snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
121 if (set_bootloader_message(&boot)) {
122 format_root_device("CACHE:");
123 return -1;
124 }
125
126 reboot(RB_AUTOBOOT);
127
128 // Can't reboot? WTF?
129 LOGE("Can't reboot\n");
130 return -1;
131}