1 /*
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 "mtdutils/mtdutils.h"
21 #include "mincrypt/sha.h"
22
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/reboot.h>
26
27 /* Bootloader / Recovery Flow
28 *
29 * On every boot, the bootloader will read the bootloader_message
30 * from flash and check the command field. The bootloader should
31 * deal with the command field not having a 0 terminator correctly
32 * (so as to not crash if the block is invalid or corrupt).
33 *
34 * The bootloader will have to publish the partition that contains
35 * the bootloader_message to the linux kernel so it can update it.
36 *
37 * if command == "boot-recovery" -> boot recovery.img
38 * else if command == "update-radio" -> update radio image (below)
39 * else if command == "update-hboot" -> update hboot image (below)
40 * else -> boot boot.img (normal boot)
41 *
42 * Radio/Hboot Update Flow
43 * 1. the bootloader will attempt to load and validate the header
44 * 2. if the header is invalid, status="invalid-update", goto #8
45 * 3. display the busy image on-screen
46 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
47 * 5. attempt to update the firmware (depending on the command)
48 * 6. if successful, status="okay", goto #8
49 * 7. if failed, and the old image can still boot, status="failed-update"
50 * 8. write the bootloader_message, leaving the recovery field
51 * unchanged, updating status, and setting command to
52 * "boot-recovery"
53 * 9. reboot
54 *
55 * The bootloader will not modify or erase the cache partition.
56 * It is recovery's responsibility to clean up the mess afterwards.
57 */
58
59 #undef LOGE
60 #define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__)
61
62
verify_image(const uint8_t * expected_sha1)63 int verify_image(const uint8_t* expected_sha1) {
64 MtdPartition* part = mtd_find_partition_by_name(CACHE_NAME);
65 if (part == NULL) {
66 printf("verify image: failed to find cache partition\n");
67 return -1;
68 }
69
70 size_t block_size;
71 if (mtd_partition_info(part, NULL, &block_size, NULL) != 0) {
72 printf("verify image: failed to get cache partition block size\n");
73 return -1;
74 }
75 printf("block size is 0x%x\n", block_size);
76
77 char* buffer = malloc(block_size);
78 if (buffer == NULL) {
79 printf("verify image: failed to allocate memory\n");
80 return -1;
81 }
82
83 MtdReadContext* ctx = mtd_read_partition(part);
84 if (ctx == NULL) {
85 printf("verify image: failed to init read context\n");
86 return -1;
87 }
88
89 size_t pos = 0;
90 if (mtd_read_data(ctx, buffer, block_size) != block_size) {
91 printf("verify image: failed to read header\n");
92 return -1;
93 }
94 pos += block_size;
95
96 if (strncmp(buffer, "MSM-RADIO-UPDATE", 16) != 0) {
97 printf("verify image: header missing magic\n");
98 return -1;
99 }
100
101 unsigned image_offset = *(unsigned*)(buffer+24);
102 unsigned image_length = *(unsigned*)(buffer+28);
103 printf("image offset 0x%x length 0x%x\n", image_offset, image_length);
104 mtd_read_skip_to(ctx, image_offset);
105
106 FILE* f = fopen("/tmp/read-radio.dat", "wb");
107 if (f == NULL) {
108 printf("verify image: failed to open temp file\n");
109 }
110
111 SHA_CTX sha_ctx;
112 SHA_init(&sha_ctx);
113
114 size_t total = 0;
115 while (total < image_length) {
116 size_t to_read = image_length - total;
117 if (to_read > block_size) to_read = block_size;
118 ssize_t read = mtd_read_data(ctx, buffer, to_read);
119 if (read < 0) {
120 printf("verify image: failed reading image (read 0x%x so far)\n",
121 total);
122 return -1;
123 }
124 if (f) {
125 fwrite(buffer, 1, read, f);
126 }
127 SHA_update(&sha_ctx, buffer, read);
128 total += read;
129 }
130
131 if (f) fclose(f);
132
133 free(buffer);
134 mtd_read_close(ctx);
135
136 const uint8_t* sha1 = SHA_final(&sha_ctx);
137 if (memcmp(sha1, expected_sha1, SHA_DIGEST_SIZE) != 0) {
138 printf("verify image: sha1 doesn't match\n");
139 return -1;
140 }
141
142 printf("verify image: verification succeeded\n");
143
144 return 0;
145 }
146
install_firmware_update(const char * update_type,const char * update_data,size_t update_length,int width,int height,int bpp,const char * busy_image,const char * fail_image,const char * log_filename,const uint8_t * expected_sha1)147 int install_firmware_update(const char *update_type,
148 const char *update_data,
149 size_t update_length,
150 int width, int height, int bpp,
151 const char* busy_image,
152 const char* fail_image,
153 const char *log_filename,
154 const uint8_t* expected_sha1) {
155 if (update_data == NULL || update_length == 0) return 0;
156
157 mtd_scan_partitions();
158
159 /* We destroy the cache partition to pass the update image to the
160 * bootloader, so all we can really do afterwards is wipe cache and reboot.
161 * Set up this instruction now, in case we're interrupted while writing.
162 */
163
164 struct bootloader_message boot;
165 memset(&boot, 0, sizeof(boot));
166 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
167 strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command));
168 if (set_bootloader_message(&boot)) return -1;
169
170 if (write_update_for_bootloader(
171 update_data, update_length,
172 width, height, bpp, busy_image, fail_image, log_filename)) {
173 LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno));
174 return -1;
175 }
176
177 if (verify_image(expected_sha1) == 0) {
178 /* The update image is fully written, so now we can instruct
179 * the bootloader to install it. (After doing so, it will
180 * come back here, and we will wipe the cache and reboot into
181 * the system.)
182 */
183 snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
184 if (set_bootloader_message(&boot)) {
185 return -1;
186 }
187
188 reboot(RB_AUTOBOOT);
189
190 // Can't reboot? WTF?
191 LOGE("Can't reboot\n");
192 }
193 return -1;
194 }
195