• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "mtdutils/mtdutils.h"
20 #include "roots.h"
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 static const char *CACHE_NAME = "CACHE:";
27 static const char *MISC_NAME = "MISC:";
28 static const int MISC_PAGES = 3;         // number of pages to save
29 static const int MISC_COMMAND_PAGE = 1;  // bootloader command is this page
30 
31 #ifdef LOG_VERBOSE
dump_data(const char * data,int len)32 static void dump_data(const char *data, int len) {
33     int pos;
34     for (pos = 0; pos < len; ) {
35         printf("%05x: %02x", pos, data[pos]);
36         for (++pos; pos < len && (pos % 24) != 0; ++pos) {
37             printf(" %02x", data[pos]);
38         }
39         printf("\n");
40     }
41 }
42 #endif
43 
get_bootloader_message(struct bootloader_message * out)44 int get_bootloader_message(struct bootloader_message *out) {
45     size_t write_size;
46     const MtdPartition *part = get_root_mtd_partition(MISC_NAME);
47     if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
48         LOGE("Can't find %s\n", MISC_NAME);
49         return -1;
50     }
51 
52     MtdReadContext *read = mtd_read_partition(part);
53     if (read == NULL) {
54         LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
55         return -1;
56     }
57 
58     const ssize_t size = write_size * MISC_PAGES;
59     char data[size];
60     ssize_t r = mtd_read_data(read, data, size);
61     if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
62     mtd_read_close(read);
63     if (r != size) return -1;
64 
65 #ifdef LOG_VERBOSE
66     printf("\n--- get_bootloader_message ---\n");
67     dump_data(data, size);
68     printf("\n");
69 #endif
70 
71     memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
72     return 0;
73 }
74 
set_bootloader_message(const struct bootloader_message * in)75 int set_bootloader_message(const struct bootloader_message *in) {
76     size_t write_size;
77     const MtdPartition *part = get_root_mtd_partition(MISC_NAME);
78     if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
79         LOGE("Can't find %s\n", MISC_NAME);
80         return -1;
81     }
82 
83     MtdReadContext *read = mtd_read_partition(part);
84     if (read == NULL) {
85         LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
86         return -1;
87     }
88 
89     ssize_t size = write_size * MISC_PAGES;
90     char data[size];
91     ssize_t r = mtd_read_data(read, data, size);
92     if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
93     mtd_read_close(read);
94     if (r != size) return -1;
95 
96     memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
97 
98 #ifdef LOG_VERBOSE
99     printf("\n--- set_bootloader_message ---\n");
100     dump_data(data, size);
101     printf("\n");
102 #endif
103 
104     MtdWriteContext *write = mtd_write_partition(part);
105     if (write == NULL) {
106         LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
107         return -1;
108     }
109     if (mtd_write_data(write, data, size) != size) {
110         LOGE("Can't write %s\n(%s)\n", MISC_NAME, strerror(errno));
111         mtd_write_close(write);
112         return -1;
113     }
114     if (mtd_write_close(write)) {
115         LOGE("Can't finish %s\n(%s)\n", MISC_NAME, strerror(errno));
116         return -1;
117     }
118 
119     LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
120     return 0;
121 }
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 
write_update_for_bootloader(const char * update,int update_length,int bitmap_width,int bitmap_height,int bitmap_bpp,const char * busy_bitmap,const char * fail_bitmap)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     header.image_offset = 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 
210     header.bitmap_width = bitmap_width;
211     header.bitmap_height = bitmap_height;
212     header.bitmap_bpp = bitmap_bpp;
213 
214     int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;
215 
216     header.busy_bitmap_offset = mtd_erase_blocks(write, 0);
217     header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
218     if ((int) header.busy_bitmap_offset == -1 ||
219         mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
220         LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
221         mtd_write_close(write);
222         return -1;
223     }
224 
225     header.fail_bitmap_offset = mtd_erase_blocks(write, 0);
226     header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
227     if ((int) header.fail_bitmap_offset == -1 ||
228         mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
229         LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
230         mtd_write_close(write);
231         return -1;
232     }
233 
234     /* Write the header last, after all the blocks it refers to, so that
235      * when the magic number is installed everything is valid.
236      */
237 
238     if (mtd_write_close(write)) {
239         LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
240         return -1;
241     }
242 
243     write = mtd_write_partition(part);
244     if (write == NULL) {
245         LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
246         return -1;
247     }
248 
249     if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
250         LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
251         mtd_write_close(write);
252         return -1;
253     }
254 
255     if (mtd_erase_blocks(write, 0) != (off_t) header.image_offset) {
256         LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
257         mtd_write_close(write);
258         return -1;
259     }
260 
261     if (mtd_write_close(write)) {
262         LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
263         return -1;
264     }
265 
266     return 0;
267 }
268