• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2013, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *  * Neither the name of Google, Inc. nor the names of its contributors
15  *    may be used to endorse or promote products derived from this
16  *    software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <inttypes.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 #include <sys/reboot.h>
40 #include <fcntl.h>
41 
42 #include "bootimg.h"
43 #include "commands/boot.h"
44 #include "commands/flash.h"
45 #include "commands/partitions.h"
46 #include "commands/virtual_partitions.h"
47 #include "debug.h"
48 #include "protocol.h"
49 #include "trigger.h"
50 #include "utils.h"
51 
52 #define ATAGS_LOCATION "/proc/atags"
53 
cmd_boot(struct protocol_handle * phandle,const char * arg)54 static void cmd_boot(struct protocol_handle *phandle, const char *arg)
55 {
56     int sz, atags_sz, new_atags_sz;
57     int rv;
58     unsigned kernel_actual;
59     unsigned ramdisk_actual;
60     unsigned second_actual;
61     void *kernel_ptr;
62     void *ramdisk_ptr;
63     void *second_ptr;
64     struct boot_img_hdr *hdr;
65     char *ptr = NULL;
66     char *atags_ptr = NULL;
67     char *new_atags = NULL;
68     int data_fd = 0;
69 
70     D(DEBUG, "cmd_boot %s\n", arg);
71 
72     if (phandle->download_fd < 0) {
73         fastboot_fail(phandle, "no kernel file");
74         return;
75     }
76 
77     atags_ptr = read_atags(ATAGS_LOCATION, &atags_sz);
78     if (atags_ptr == NULL) {
79         fastboot_fail(phandle, "atags read error");
80         goto error;
81     }
82 
83     // TODO: With cms we can also verify partition name included as
84     // cms signed attribute
85     if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
86         fastboot_fail(phandle, "Access forbiden you need the certificate");
87         return;
88     }
89 
90     sz = get_file_size(data_fd);
91 
92     ptr = (char *) mmap(NULL, sz, PROT_READ,
93                         MAP_POPULATE | MAP_PRIVATE, data_fd, 0);
94 
95     hdr = (struct boot_img_hdr *) ptr;
96 
97     if (ptr == MAP_FAILED) {
98         fastboot_fail(phandle, "internal fastbootd error");
99         goto error;
100     }
101 
102     if ((size_t) sz < sizeof(*hdr)) {
103         fastboot_fail(phandle, "invalid bootimage header");
104         goto error;
105     }
106 
107     kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, hdr->page_size);
108     ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, hdr->page_size);
109     second_actual = ROUND_TO_PAGE(hdr->second_size, hdr->page_size);
110 
111     new_atags = (char *) create_atags((unsigned *) atags_ptr, atags_sz, hdr, &new_atags_sz);
112 
113     if (new_atags == NULL) {
114         fastboot_fail(phandle, "atags generate error");
115         goto error;
116     }
117     if (new_atags_sz > 0x4000) {
118         fastboot_fail(phandle, "atags file to large");
119         goto error;
120     }
121 
122     if ((int) (hdr->page_size + kernel_actual + ramdisk_actual) < sz) {
123         fastboot_fail(phandle, "incomplete bootimage");
124         goto error;
125     }
126 
127     kernel_ptr = (void *)((uintptr_t) ptr + hdr->page_size);
128     ramdisk_ptr = (void *)((uintptr_t) kernel_ptr + kernel_actual);
129     second_ptr = (void *)((uintptr_t) ramdisk_ptr + ramdisk_actual);
130 
131     D(INFO, "preparing to boot");
132     // Prepares boot physical address. Addresses from header are ignored
133     rv = prepare_boot_linux(hdr->kernel_addr, kernel_ptr, kernel_actual,
134                             hdr->ramdisk_addr, ramdisk_ptr, ramdisk_actual,
135                             hdr->second_addr, second_ptr, second_actual,
136                             hdr->tags_addr, new_atags, ROUND_TO_PAGE(new_atags_sz, hdr->page_size));
137     if (rv < 0) {
138         fastboot_fail(phandle, "kexec prepare failed");
139         goto error;
140     }
141 
142     fastboot_okay(phandle, "");
143 
144     free(atags_ptr);
145     munmap(ptr, sz);
146     free(new_atags);
147     close(data_fd);
148 
149     D(INFO, "Kexec going to reboot");
150     reboot(LINUX_REBOOT_CMD_KEXEC);
151 
152     fastboot_fail(phandle, "reboot error");
153 
154     return;
155 
156 error:
157 
158     if (atags_ptr != NULL)
159         free(atags_ptr);
160     if (ptr != NULL)
161         munmap(ptr, sz);
162 
163 }
164 
cmd_erase(struct protocol_handle * phandle,const char * arg)165 static void cmd_erase(struct protocol_handle *phandle, const char *arg)
166 {
167     int partition_fd;
168     char path[PATH_MAX];
169     D(DEBUG, "cmd_erase %s\n", arg);
170 
171     if (flash_find_entry(arg, path, PATH_MAX)) {
172         fastboot_fail(phandle, "partition table doesn't exist");
173         return;
174     }
175 
176     if (path == NULL) {
177         fastboot_fail(phandle, "Couldn't find partition");
178         return;
179     }
180 
181     partition_fd = flash_get_partiton(path);
182     if (partition_fd < 0) {
183         fastboot_fail(phandle, "partiton file does not exists");
184     }
185 
186     if (flash_erase(partition_fd)) {
187         fastboot_fail(phandle, "failed to erase partition");
188         flash_close(partition_fd);
189         return;
190     }
191 
192     if (flash_close(partition_fd) < 0) {
193         D(ERR, "could not close device %s", strerror(errno));
194         fastboot_fail(phandle, "failed to erase partition");
195         return;
196     }
197     fastboot_okay(phandle, "");
198 }
199 
GPT_header_location()200 static int GPT_header_location() {
201     const char *location_str = fastboot_getvar("gpt_sector");
202     char *str;
203     int location;
204 
205     if (!strcmp("", location_str)) {
206         D(INFO, "GPT location not specified using second sector");
207         return 1;
208     }
209     else {
210         location = strtoul(location_str, &str, 10);
211         D(INFO, "GPT location specified as %d", location);
212 
213         if (*str != '\0')
214             return -1;
215 
216         return location - 1;
217     }
218 }
219 
cmd_gpt_layout(struct protocol_handle * phandle,const char * arg)220 static void cmd_gpt_layout(struct protocol_handle *phandle, const char *arg) {
221     struct GPT_entry_table *oldtable;
222     int location;
223     struct GPT_content content;
224     const char *device;
225     device = fastboot_getvar("blockdev");
226 
227     if (!strcmp(device, "")) {
228         fastboot_fail(phandle, "blockdev not defined in config file");
229         return;
230     }
231 
232     //TODO: add same verification as in cmd_flash
233     if (phandle->download_fd < 0) {
234         fastboot_fail(phandle, "no layout file");
235         return;
236     }
237 
238     location = GPT_header_location();
239     oldtable = GPT_get_device(device, location);
240 
241     GPT_default_content(&content, oldtable);
242     if (oldtable == NULL)
243         D(WARN, "Could not get old gpt table");
244     else
245         GPT_release_device(oldtable);
246 
247     if (!GPT_parse_file(phandle->download_fd, &content)) {
248         fastboot_fail(phandle, "Could not parse partition config file");
249         return;
250     }
251 
252     if (trigger_gpt_layout(&content)) {
253         fastboot_fail(phandle, "Vendor forbids this opperation");
254         GPT_release_content(&content);
255         return;
256     }
257 
258     if (!GPT_write_content(device, &content)) {
259         fastboot_fail(phandle, "Unable to write gpt file");
260         GPT_release_content(&content);
261         return;
262     }
263 
264     GPT_release_content(&content);
265     fastboot_okay(phandle, "");
266 }
267 
cmd_flash(struct protocol_handle * phandle,const char * arg)268 static void cmd_flash(struct protocol_handle *phandle, const char *arg)
269 {
270     int partition;
271     uint64_t sz;
272     char data[BOOT_MAGIC_SIZE];
273     char path[PATH_MAX];
274     ssize_t header_sz = 0;
275     int data_fd = 0;
276 
277     D(DEBUG, "cmd_flash %s\n", arg);
278 
279     if (try_handle_virtual_partition(phandle, arg)) {
280         return;
281     }
282 
283     if (phandle->download_fd < 0) {
284         fastboot_fail(phandle, "no kernel file");
285         return;
286     }
287 
288     if (flash_find_entry(arg, path, PATH_MAX)) {
289         fastboot_fail(phandle, "partition table doesn't exist");
290         return;
291     }
292 
293     if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
294         fastboot_fail(phandle, "Access forbiden you need certificate");
295         return;
296     }
297 
298     // TODO: Maybe its goot idea to check whether the partition is bootable
299     if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
300         if (read_data_once(data_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
301             fastboot_fail(phandle, "incoming data read error, cannot read boot header");
302             return;
303         }
304         if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
305             fastboot_fail(phandle, "image is not a boot image");
306             return;
307         }
308     }
309 
310     partition = flash_get_partiton(path);
311 
312     sz = get_file_size64(data_fd);
313 
314     sz -= header_sz;
315 
316     if (sz > get_file_size64(partition)) {
317         flash_close(partition);
318         D(WARN, "size of file too large");
319         fastboot_fail(phandle, "size of file too large");
320         return;
321     }
322 
323     D(INFO, "writing %"PRId64" bytes to '%s'\n", sz, arg);
324 
325     if (flash_write(partition, phandle->download_fd, sz, header_sz)) {
326         fastboot_fail(phandle, "flash write failure");
327         return;
328     }
329     D(INFO, "partition '%s' updated\n", arg);
330 
331     flash_close(partition);
332     close(data_fd);
333 
334     fastboot_okay(phandle, "");
335 }
336 
cmd_continue(struct protocol_handle * phandle,const char * arg)337 static void cmd_continue(struct protocol_handle *phandle, const char *arg)
338 {
339     fastboot_okay(phandle, "");
340 #if 0
341     udc_stop();
342 
343     boot_linux_from_flash();
344 #endif
345 }
346 
cmd_getvar(struct protocol_handle * phandle,const char * arg)347 static void cmd_getvar(struct protocol_handle *phandle, const char *arg)
348 {
349     const char *value;
350     D(DEBUG, "cmd_getvar %s\n", arg);
351 
352     value = fastboot_getvar(arg);
353 
354     fastboot_okay(phandle, value);
355 }
356 
cmd_download(struct protocol_handle * phandle,const char * arg)357 static void cmd_download(struct protocol_handle *phandle, const char *arg)
358 {
359     unsigned len = strtoul(arg, NULL, 16);
360     int old_fd;
361 
362     if (len > 256 * 1024 * 1024) {
363         fastboot_fail(phandle, "data too large");
364         return;
365     }
366 
367     fastboot_data(phandle, len);
368 
369     old_fd = protocol_get_download(phandle);
370     if (old_fd >= 0) {
371         off_t len = lseek(old_fd, 0, SEEK_END);
372         D(INFO, "disposing of unused fd %d, size %ld", old_fd, len);
373         close(old_fd);
374     }
375 
376     phandle->download_fd = protocol_handle_download(phandle, len);
377     if (phandle->download_fd < 0) {
378         fastboot_fail(phandle, "download failed");
379         return;
380     }
381 
382     fastboot_okay(phandle, "");
383 }
384 
cmd_oem(struct protocol_handle * phandle,const char * arg)385 static void cmd_oem(struct protocol_handle *phandle, const char *arg) {
386     const char *response = "";
387 
388     //TODO: Maybe it should get download descriptor also
389     if (trigger_oem_cmd(arg, &response))
390         fastboot_fail(phandle, response);
391     else
392         fastboot_okay(phandle, response);
393 }
394 
commands_init()395 void commands_init()
396 {
397     virtual_partition_register("partition-table", cmd_gpt_layout);
398 
399     fastboot_register("boot", cmd_boot);
400     fastboot_register("erase:", cmd_erase);
401     fastboot_register("flash:", cmd_flash);
402     fastboot_register("continue", cmd_continue);
403     fastboot_register("getvar:", cmd_getvar);
404     fastboot_register("download:", cmd_download);
405     fastboot_register("oem", cmd_oem);
406     //fastboot_publish("version", "0.5");
407     //fastboot_publish("product", "swordfish");
408     //fastboot_publish("kernel", "lk");
409 }
410