Skip to content

Commit 107629b

Browse files
committed
forward port excluded bootloader stuff from eclair
Change-Id: I03fb0d4dc982a3718a616c6204e70a3e11cff8f8
1 parent 0eb14b3 commit 107629b

File tree

6 files changed

+349
-0
lines changed

6 files changed

+349
-0
lines changed

bootloader.c

+150
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,153 @@ int set_bootloader_message(const struct bootloader_message *in) {
119119
LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
120120
return 0;
121121
}
122+
123+
/* Update Image
124+
*
125+
* - will be stored in the "cache" partition
126+
* - bad blocks will be ignored, like boot.img and recovery.img
127+
* - the first block will be the image header (described below)
128+
* - the size is in BYTES, inclusive of the header
129+
* - offsets are in BYTES from the start of the update header
130+
* - two raw bitmaps will be included, the "busy" and "fail" bitmaps
131+
* - for dream, the bitmaps will be 320x480x16bpp RGB565
132+
*/
133+
134+
#define UPDATE_MAGIC "MSM-RADIO-UPDATE"
135+
#define UPDATE_MAGIC_SIZE 16
136+
#define UPDATE_VERSION 0x00010000
137+
138+
struct update_header {
139+
unsigned char MAGIC[UPDATE_MAGIC_SIZE];
140+
141+
unsigned version;
142+
unsigned size;
143+
144+
unsigned image_offset;
145+
unsigned image_length;
146+
147+
unsigned bitmap_width;
148+
unsigned bitmap_height;
149+
unsigned bitmap_bpp;
150+
151+
unsigned busy_bitmap_offset;
152+
unsigned busy_bitmap_length;
153+
154+
unsigned fail_bitmap_offset;
155+
unsigned fail_bitmap_length;
156+
};
157+
158+
int write_update_for_bootloader(
159+
const char *update, int update_length,
160+
int bitmap_width, int bitmap_height, int bitmap_bpp,
161+
const char *busy_bitmap, const char *fail_bitmap) {
162+
if (ensure_root_path_unmounted(CACHE_NAME)) {
163+
LOGE("Can't unmount %s\n", CACHE_NAME);
164+
return -1;
165+
}
166+
167+
const MtdPartition *part = get_root_mtd_partition(CACHE_NAME);
168+
if (part == NULL) {
169+
LOGE("Can't find %s\n", CACHE_NAME);
170+
return -1;
171+
}
172+
173+
MtdWriteContext *write = mtd_write_partition(part);
174+
if (write == NULL) {
175+
LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno));
176+
return -1;
177+
}
178+
179+
/* Write an invalid (zero) header first, to disable any previous
180+
* update and any other structured contents (like a filesystem),
181+
* and as a placeholder for the amount of space required.
182+
*/
183+
184+
struct update_header header;
185+
memset(&header, 0, sizeof(header));
186+
const ssize_t header_size = sizeof(header);
187+
if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
188+
LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
189+
mtd_write_close(write);
190+
return -1;
191+
}
192+
193+
/* Write each section individually block-aligned, so we can write
194+
* each block independently without complicated buffering.
195+
*/
196+
197+
memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
198+
header.version = UPDATE_VERSION;
199+
header.size = header_size;
200+
201+
off_t image_start_pos = mtd_erase_blocks(write, 0);
202+
header.image_length = update_length;
203+
if ((int) header.image_offset == -1 ||
204+
mtd_write_data(write, update, update_length) != update_length) {
205+
LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno));
206+
mtd_write_close(write);
207+
return -1;
208+
}
209+
off_t busy_start_pos = mtd_erase_blocks(write, 0);
210+
header.image_offset = mtd_find_write_start(write, image_start_pos);
211+
212+
header.bitmap_width = bitmap_width;
213+
header.bitmap_height = bitmap_height;
214+
header.bitmap_bpp = bitmap_bpp;
215+
216+
int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;
217+
218+
header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
219+
if ((int) header.busy_bitmap_offset == -1 ||
220+
mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
221+
LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
222+
mtd_write_close(write);
223+
return -1;
224+
}
225+
off_t fail_start_pos = mtd_erase_blocks(write, 0);
226+
header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos);
227+
228+
header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
229+
if ((int) header.fail_bitmap_offset == -1 ||
230+
mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
231+
LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
232+
mtd_write_close(write);
233+
return -1;
234+
}
235+
mtd_erase_blocks(write, 0);
236+
header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos);
237+
238+
/* Write the header last, after all the blocks it refers to, so that
239+
* when the magic number is installed everything is valid.
240+
*/
241+
242+
if (mtd_write_close(write)) {
243+
LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
244+
return -1;
245+
}
246+
247+
write = mtd_write_partition(part);
248+
if (write == NULL) {
249+
LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
250+
return -1;
251+
}
252+
253+
if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
254+
LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
255+
mtd_write_close(write);
256+
return -1;
257+
}
258+
259+
if (mtd_erase_blocks(write, 0) != image_start_pos) {
260+
LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
261+
mtd_write_close(write);
262+
return -1;
263+
}
264+
265+
if (mtd_write_close(write)) {
266+
LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
267+
return -1;
268+
}
269+
270+
return 0;
271+
}

bootloader.h

+9
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@ struct bootloader_message {
4747
int get_bootloader_message(struct bootloader_message *out);
4848
int set_bootloader_message(const struct bootloader_message *in);
4949

50+
/* Write an update to the cache partition for update-radio or update-hboot.
51+
* Note, this destroys any filesystem on the cache partition!
52+
* The expected bitmap format is 240x320, 16bpp (2Bpp), RGB 5:6:5.
53+
*/
54+
int write_update_for_bootloader(
55+
const char *update, int update_len,
56+
int bitmap_width, int bitmap_height, int bitmap_bpp,
57+
const char *busy_bitmap, const char *error_bitmap);
58+
5059
#endif

common.h

+7
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,17 @@ enum {
5252
BACKGROUND_ICON_NONE,
5353
BACKGROUND_ICON_INSTALLING,
5454
BACKGROUND_ICON_ERROR,
55+
BACKGROUND_ICON_FIRMWARE_INSTALLING,
56+
BACKGROUND_ICON_FIRMWARE_ERROR,
5557
NUM_BACKGROUND_ICONS
5658
};
5759
void ui_set_background(int icon);
5860

61+
// Get a malloc'd copy of the screen image showing (only) the specified icon.
62+
// Also returns the width, height, and bits per pixel of the returned image.
63+
// TODO: Use some sort of "struct Bitmap" here instead of all these variables?
64+
char *ui_copy_image(int icon, int *width, int *height, int *bpp);
65+
5966
// Show a progress bar and define the scope of the next operation:
6067
// portion - fraction of the progress bar the next operation will use
6168
// seconds - expected time interval (progress bar moves at this minimum rate)

firmware.c

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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 "roots.h"
21+
22+
#include <errno.h>
23+
#include <string.h>
24+
#include <sys/reboot.h>
25+
26+
static const char *update_type = NULL;
27+
static const char *update_data = NULL;
28+
static int update_length = 0;
29+
30+
int 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+
42+
// Return true if there is a firmware update pending.
43+
int firmware_update_pending() {
44+
return update_data != NULL && update_length > 0;
45+
}
46+
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+
79+
int 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+
}

firmware.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
#ifndef _RECOVERY_FIRMWARE_H
18+
#define _RECOVERY_FIRMWARE_H
19+
20+
/* Save a radio or bootloader update image for later installation.
21+
* The type should be one of "hboot" or "radio".
22+
* Takes ownership of type and data. Returns nonzero on error.
23+
*/
24+
int remember_firmware_update(const char *type, const char *data, int length);
25+
26+
/* Returns true if a firmware update has been saved. */
27+
int firmware_update_pending();
28+
29+
/* If an update was saved, reboot into the bootloader now to install it.
30+
* Returns 0 if no radio image was defined, nonzero on error,
31+
* doesn't return at all on success...
32+
*/
33+
int maybe_install_firmware_update(const char *send_intent);
34+
35+
#endif

ui.c

+17
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,23 @@ void ui_init(void)
359359
pthread_create(&t, NULL, input_thread, NULL);
360360
}
361361

362+
char *ui_copy_image(int icon, int *width, int *height, int *bpp) {
363+
pthread_mutex_lock(&gUpdateMutex);
364+
draw_background_locked(gBackgroundIcon[icon]);
365+
*width = gr_fb_width();
366+
*height = gr_fb_height();
367+
*bpp = sizeof(gr_pixel) * 8;
368+
int size = *width * *height * sizeof(gr_pixel);
369+
char *ret = malloc(size);
370+
if (ret == NULL) {
371+
LOGE("Can't allocate %d bytes for image\n", size);
372+
} else {
373+
memcpy(ret, gr_fb_data(), size);
374+
}
375+
pthread_mutex_unlock(&gUpdateMutex);
376+
return ret;
377+
}
378+
362379
void ui_set_background(int icon)
363380
{
364381
pthread_mutex_lock(&gUpdateMutex);

0 commit comments

Comments
 (0)