M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _BOOT_IMAGE_H_
#define _BOOT_IMAGE_H_
typedef struct boot_img_hdr boot_img_hdr;
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned dt_size; /* device_tree in bytes */
unsigned unused; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
/*
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
** | device tree | p pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
** p = (dt_size + page_size - 1) / page_size
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
** 2. second is optional (second_size == 0 -> no second)
** 3. load each element (kernel, ramdisk, second) at
** the specified physical address (kernel_addr, etc)
** 4. prepare tags at tag_addr. kernel_args[] is
** appended to the kernel commandline in the tags.
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
** 6. if second_size != 0: jump to second_addr
** else: jump to kernel_addr
*/
boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
void *ramdisk, unsigned ramdisk_size,
void *second, unsigned second_size,
unsigned page_size,
unsigned *bootimg_size);
void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);
#endif

View File

@@ -0,0 +1,45 @@
/*
* * Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEVINFO_H_
#define _DEVINFO_H_
typedef struct device_info device_info;
#define DEVICE_MAGIC "ANDROID-BOOT!"
#define DEVICE_MAGIC_SIZE 13
struct device_info
{
unsigned char magic[DEVICE_MAGIC_SIZE];
bool is_unlocked;
bool is_tampered;
};
#endif

View File

@@ -0,0 +1,408 @@
/*
* Copyright (c) 2009, Google Inc.
* All rights reserved.
*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <debug.h>
#include <string.h>
#include <stdlib.h>
#include <platform.h>
#include <kernel/thread.h>
#include <kernel/event.h>
#include <dev/udc.h>
#include "fastboot.h"
#define MAX_USBFS_BULK_SIZE (32 * 1024)
void boot_linux(void *bootimg, unsigned sz);
/* todo: give lk strtoul and nuke this */
static unsigned hex2unsigned(const char *x)
{
unsigned n = 0;
while(*x) {
switch(*x) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = (n << 4) | (*x - '0');
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
n = (n << 4) | (*x - 'a' + 10);
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
n = (n << 4) | (*x - 'A' + 10);
break;
default:
return n;
}
x++;
}
return n;
}
struct fastboot_cmd {
struct fastboot_cmd *next;
const char *prefix;
unsigned prefix_len;
void (*handle)(const char *arg, void *data, unsigned sz);
};
struct fastboot_var {
struct fastboot_var *next;
const char *name;
const char *value;
};
static struct fastboot_cmd *cmdlist;
void fastboot_register(const char *prefix,
void (*handle)(const char *arg, void *data, unsigned sz))
{
struct fastboot_cmd *cmd;
cmd = malloc(sizeof(*cmd));
if (cmd) {
cmd->prefix = prefix;
cmd->prefix_len = strlen(prefix);
cmd->handle = handle;
cmd->next = cmdlist;
cmdlist = cmd;
}
}
static struct fastboot_var *varlist;
void fastboot_publish(const char *name, const char *value)
{
struct fastboot_var *var;
var = malloc(sizeof(*var));
if (var) {
var->name = name;
var->value = value;
var->next = varlist;
varlist = var;
}
}
static event_t usb_online;
static event_t txn_done;
static struct udc_endpoint *in, *out;
static struct udc_request *req;
int txn_status;
static void *download_base;
static unsigned download_max;
static unsigned download_size;
#define STATE_OFFLINE 0
#define STATE_COMMAND 1
#define STATE_COMPLETE 2
#define STATE_ERROR 3
static unsigned fastboot_state = STATE_OFFLINE;
static void req_complete(struct udc_request *req, unsigned actual, int status)
{
txn_status = status;
req->length = actual;
event_signal(&txn_done, 0);
}
static int usb_read(void *_buf, unsigned len)
{
int r;
unsigned xfer;
unsigned char *buf = _buf;
int count = 0;
if (fastboot_state == STATE_ERROR)
goto oops;
while (len > 0) {
xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
req->buf = PA((addr_t)buf);
req->length = xfer;
req->complete = req_complete;
r = udc_request_queue(out, req);
if (r < 0) {
dprintf(INFO, "usb_read() queue failed\n");
goto oops;
}
event_wait(&txn_done);
if (txn_status < 0) {
dprintf(INFO, "usb_read() transaction failed\n");
goto oops;
}
count += req->length;
buf += req->length;
len -= req->length;
/* short transfer? */
if (req->length != xfer) break;
}
/*
* Force reload of buffer from memory
* since transaction is complete now.
*/
arch_invalidate_cache_range(_buf, count);
return count;
oops:
fastboot_state = STATE_ERROR;
return -1;
}
static int usb_write(void *buf, unsigned len)
{
int r;
if (fastboot_state == STATE_ERROR)
goto oops;
req->buf = PA((addr_t)buf);
req->length = len;
req->complete = req_complete;
r = udc_request_queue(in, req);
if (r < 0) {
dprintf(INFO, "usb_write() queue failed\n");
goto oops;
}
event_wait(&txn_done);
if (txn_status < 0) {
dprintf(INFO, "usb_write() transaction failed\n");
goto oops;
}
return req->length;
oops:
fastboot_state = STATE_ERROR;
return -1;
}
void fastboot_ack(const char *code, const char *reason)
{
STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
if (fastboot_state != STATE_COMMAND)
return;
if (reason == 0)
reason = "";
snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
fastboot_state = STATE_COMPLETE;
usb_write(response, strlen(response));
}
void fastboot_info(const char *reason)
{
STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
if (fastboot_state != STATE_COMMAND)
return;
if (reason == 0)
return;
snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
usb_write(response, strlen(response));
}
void fastboot_fail(const char *reason)
{
fastboot_ack("FAIL", reason);
}
void fastboot_okay(const char *info)
{
fastboot_ack("OKAY", info);
}
static void cmd_getvar(const char *arg, void *data, unsigned sz)
{
struct fastboot_var *var;
for (var = varlist; var; var = var->next) {
if (!strcmp(var->name, arg)) {
fastboot_okay(var->value);
return;
}
}
fastboot_okay("");
}
static void cmd_download(const char *arg, void *data, unsigned sz)
{
STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE);
unsigned len = hex2unsigned(arg);
int r;
download_size = 0;
if (len > download_max) {
fastboot_fail("data too large");
return;
}
snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
if (usb_write(response, strlen(response)) < 0)
return;
r = usb_read(download_base, len);
if ((r < 0) || ((unsigned) r != len)) {
fastboot_state = STATE_ERROR;
return;
}
download_size = len;
fastboot_okay("");
}
static void fastboot_command_loop(void)
{
struct fastboot_cmd *cmd;
int r;
dprintf(INFO,"fastboot: processing commands\n");
uint8_t *buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
if (!buffer)
{
dprintf(CRITICAL, "Could not allocate memory for fastboot buffer\n.");
ASSERT(0);
}
again:
while (fastboot_state != STATE_ERROR) {
r = usb_read(buffer, MAX_RSP_SIZE);
if (r < 0) break;
buffer[r] = 0;
dprintf(INFO,"fastboot: %s\n", buffer);
for (cmd = cmdlist; cmd; cmd = cmd->next) {
if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
continue;
fastboot_state = STATE_COMMAND;
cmd->handle((const char*) buffer + cmd->prefix_len,
(void*) download_base, download_size);
if (fastboot_state == STATE_COMMAND)
fastboot_fail("unknown reason");
goto again;
}
fastboot_fail("unknown command");
}
fastboot_state = STATE_OFFLINE;
dprintf(INFO,"fastboot: oops!\n");
free(buffer);
}
static int fastboot_handler(void *arg)
{
for (;;) {
event_wait(&usb_online);
fastboot_command_loop();
}
return 0;
}
static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
{
if (event == UDC_EVENT_ONLINE) {
event_signal(&usb_online, 0);
}
}
static struct udc_endpoint *fastboot_endpoints[2];
static struct udc_gadget fastboot_gadget = {
.notify = fastboot_notify,
.ifc_class = 0xff,
.ifc_subclass = 0x42,
.ifc_protocol = 0x03,
.ifc_endpoints = 2,
.ifc_string = "fastboot",
.ept = fastboot_endpoints,
};
int fastboot_init(void *base, unsigned size)
{
thread_t *thr;
dprintf(INFO, "fastboot_init()\n");
download_base = base;
download_max = size;
event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
if (!in)
goto fail_alloc_in;
out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
if (!out)
goto fail_alloc_out;
fastboot_endpoints[0] = in;
fastboot_endpoints[1] = out;
req = udc_request_alloc();
if (!req)
goto fail_alloc_req;
if (udc_register_gadget(&fastboot_gadget))
goto fail_udc_register;
fastboot_register("getvar:", cmd_getvar);
fastboot_register("download:", cmd_download);
fastboot_publish("version", "0.5");
thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
if (!thr)
{
goto fail_alloc_in;
}
thread_resume(thr);
return 0;
fail_udc_register:
udc_request_free(req);
fail_alloc_req:
udc_endpoint_free(out);
fail_alloc_out:
udc_endpoint_free(in);
fail_alloc_in:
return -1;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2009, Google Inc.
* All rights reserved.
*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __APP_FASTBOOT_H
#define __APP_FASTBOOT_H
#define MAX_RSP_SIZE 64
#define MAX_GET_VAR_NAME_SIZE 256
int fastboot_init(void *xfer_buffer, unsigned max);
/* register a command handler
* - command handlers will be called if their prefix matches
* - they are expected to call fastboot_okay() or fastboot_fail()
* to indicate success/failure before returning
*/
void fastboot_register(const char *prefix,
void (*handle)(const char *arg, void *data, unsigned size));
/* publish a variable readable by the built-in getvar command */
void fastboot_publish(const char *name, const char *value);
/* only callable from within a command handler */
void fastboot_okay(const char *result);
void fastboot_fail(const char *reason);
void fastboot_info(const char *reason);
#endif

View File

@@ -0,0 +1,659 @@
/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <debug.h>
#include <arch/arm.h>
#include <dev/udc.h>
#include <string.h>
#include <kernel/thread.h>
#include <arch/ops.h>
#include <dev/flash.h>
#include <lib/ptable.h>
#include <dev/keys.h>
#include <platform.h>
#include <target.h>
#include <partition_parser.h>
#include <mmc.h>
#include "recovery.h"
#include "bootimg.h"
#include "smem.h"
#define BOOT_FLAGS 1
#define UPDATE_STATUS 2
#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
static const int MISC_PAGES = 3; // number of pages to save
static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
static char buf[4096];
unsigned boot_into_recovery = 0;
extern uint32_t get_page_size();
extern void reset_device_info();
extern void set_device_root();
int get_recovery_message(struct recovery_message *out)
{
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
unsigned pagesize = flash_page_size();
ptable = flash_get_ptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: Partition table not found\n");
return -1;
}
ptn = ptable_find(ptable, "misc");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No misc partition found\n");
return -1;
}
offset += (pagesize * MISC_COMMAND_PAGE);
if (flash_read(ptn, offset, (void *) buf, pagesize)) {
dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
return -1;
}
memcpy(out, buf, sizeof(*out));
return 0;
}
int set_recovery_message(const struct recovery_message *in)
{
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
unsigned pagesize = flash_page_size();
unsigned n = 0;
ptable = flash_get_ptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: Partition table not found\n");
return -1;
}
ptn = ptable_find(ptable, "misc");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No misc partition found\n");
return -1;
}
n = pagesize * (MISC_COMMAND_PAGE + 1);
if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
return -1;
}
offset += (pagesize * MISC_COMMAND_PAGE);
offset += SCRATCH_ADDR;
memcpy((void *) offset, in, sizeof(*in));
if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: flash write fail!\n");
return -1;
}
return 0;
}
int read_update_header_for_bootloader(struct update_header *header)
{
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
unsigned pagesize = flash_page_size();
ptable = flash_get_ptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: Partition table not found\n");
return -1;
}
ptn = ptable_find(ptable, "cache");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No cache partition found\n");
return -1;
}
if (flash_read(ptn, offset, buf, pagesize)) {
dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
return -1;
}
memcpy(header, buf, sizeof(*header));
if (strncmp((char *) header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
{
return -1;
}
return 0;
}
int update_firmware_image (struct update_header *header, char *name)
{
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
unsigned pagesize = flash_page_size();
unsigned pagemask = pagesize -1;
unsigned n = 0;
ptable = flash_get_ptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: Partition table not found\n");
return -1;
}
ptn = ptable_find(ptable, "cache");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No cache partition found\n");
return -1;
}
offset += header->image_offset;
n = (header->image_length + pagemask) & (~pagemask);
if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
return -1;
}
ptn = ptable_find(ptable, name);
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
return -1;
}
if (flash_write(ptn, 0, (void *) SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: flash write fail!\n");
return -1;
}
dprintf(INFO, "Partition writen successfully!");
return 0;
}
static int set_ssd_radio_update (char *name)
{
struct ptentry *ptn;
struct ptable *ptable;
unsigned int ssd_cookie[2] = {0x53534443, 0x4F4F4B49};
unsigned pagesize = flash_page_size();
unsigned pagemask = pagesize -1;
unsigned n = 0;
ptable = flash_get_ptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: Partition table not found\n");
return -1;
}
n = (sizeof(ssd_cookie) + pagemask) & (~pagemask);
ptn = ptable_find(ptable, name);
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
return -1;
}
if (flash_write(ptn, 0, ssd_cookie, n)) {
dprintf(CRITICAL, "ERROR: flash write fail!\n");
return -1;
}
dprintf(INFO, "FOTA partition written successfully!");
return 0;
}
int get_boot_info_apps (char type, unsigned int *status)
{
boot_info_for_apps apps_boot_info;
int ret = 0;
ret = smem_read_alloc_entry(SMEM_BOOT_INFO_FOR_APPS,
&apps_boot_info, sizeof(apps_boot_info));
if (ret)
{
dprintf(CRITICAL, "ERROR: unable to read shared memory for apps boot info %d\n",ret);
return ret;
}
dprintf(INFO,"boot flag %x update status %x\n",apps_boot_info.boot_flags,
apps_boot_info.status.update_status);
if(type == BOOT_FLAGS)
*status = apps_boot_info.boot_flags;
else if(type == UPDATE_STATUS)
*status = apps_boot_info.status.update_status;
return ret;
}
/* Bootloader / Recovery Flow
*
* On every boot, the bootloader will read the recovery_message
* from flash and check the command field. The bootloader should
* deal with the command field not having a 0 terminator correctly
* (so as to not crash if the block is invalid or corrupt).
*
* The bootloader will have to publish the partition that contains
* the recovery_message to the linux kernel so it can update it.
*
* if command == "boot-recovery" -> boot recovery.img
* else if command == "update-radio" -> update radio image (below)
* else -> boot boot.img (normal boot)
*
* Radio Update Flow
* 1. the bootloader will attempt to load and validate the header
* 2. if the header is invalid, status="invalid-update", goto #8
* 3. display the busy image on-screen
* 4. if the update image is invalid, status="invalid-radio-image", goto #8
* 5. attempt to update the firmware (depending on the command)
* 6. if successful, status="okay", goto #8
* 7. if failed, and the old image can still boot, status="failed-update"
* 8. write the recovery_message, leaving the recovery field
* unchanged, updating status, and setting command to
* "boot-recovery"
* 9. reboot
*
* The bootloader will not modify or erase the cache partition.
* It is recovery's responsibility to clean up the mess afterwards.
*/
int recovery_init (void)
{
struct recovery_message msg;
char partition_name[32];
unsigned valid_command = 0;
int update_status = 0;
// get recovery message
if (get_recovery_message(&msg))
return -1;
msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
if (msg.command[0] != 0 && msg.command[0] != 255) {
dprintf(INFO,"Recovery command: %d %s\n",
sizeof(msg.command), msg.command);
}
if (!strcmp("boot-recovery",msg.command))
{
if(!strcmp("RADIO",msg.status))
{
/* We're now here due to radio update, so check for update status */
int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
if(!ret && (update_status & 0x01))
{
dprintf(INFO,"radio update success\n");
strlcpy(msg.status, "OKAY", sizeof(msg.status));
}
else
{
dprintf(INFO,"radio update failed\n");
strlcpy(msg.status, "failed-update", sizeof(msg.status));
}
strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
set_recovery_message(&msg); // send recovery message
boot_into_recovery = 1; // Boot in recovery mode
return 0;
}
valid_command = 1;
strlcpy(msg.command, "", sizeof(msg.command)); // to safe against multiple reboot into recovery
strlcpy(msg.status, "OKAY", sizeof(msg.status));
set_recovery_message(&msg); // send recovery message
boot_into_recovery = 1; // Boot in recovery mode
return 0;
}
if (!strcmp("update-radio",msg.command)) {
dprintf(INFO,"start radio update\n");
valid_command = 1;
strlcpy(partition_name, "FOTA", sizeof(partition_name));
}
//Todo: Add support for bootloader update too.
if(!valid_command) {
//We need not to do anything
return 0; // Boot in normal mode
}
#ifdef OLD_FOTA_UPGRADE
if (read_update_header_for_bootloader(&header)) {
strlcpy(msg.status, "invalid-update", sizeof(msg.status));
goto SEND_RECOVERY_MSG;
}
if (update_firmware_image (&header, partition_name)) {
strlcpy(msg.status, "failed-update", sizeof(msg.status));
goto SEND_RECOVERY_MSG;
}
#else
if (set_ssd_radio_update(partition_name)) {
/* If writing to FOTA partition fails */
strlcpy(msg.command, "", sizeof(msg.command));
strlcpy(msg.status, "failed-update", sizeof(msg.status));
goto SEND_RECOVERY_MSG;
}
else {
/* Setting this to check the radio update status */
strlcpy(msg.command, "boot-recovery", sizeof(msg.command));
strlcpy(msg.status, "RADIO", sizeof(msg.status));
goto SEND_RECOVERY_MSG;
}
#endif
strlcpy(msg.status, "OKAY", sizeof(msg.status));
SEND_RECOVERY_MSG:
set_recovery_message(&msg); // send recovery message
boot_into_recovery = 1; // Boot in recovery mode
reboot_device(0);
return 0;
}
static int emmc_set_recovery_msg(struct recovery_message *out)
{
char *ptn_name = "misc";
unsigned long long ptn = 0;
unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
unsigned char data[size];
int index = INVALID_PTN;
index = partition_get_index((unsigned char *) ptn_name);
ptn = partition_get_offset(index);
if(ptn == 0) {
dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
return -1;
}
memcpy(data, out, sizeof(*out));
if (mmc_write(ptn , size, (unsigned int*)data)) {
dprintf(CRITICAL,"mmc write failure %s %d\n",ptn_name, sizeof(*out));
return -1;
}
return 0;
}
static int emmc_get_recovery_msg(struct recovery_message *in)
{
char *ptn_name = "misc";
unsigned long long ptn = 0;
unsigned int size = ROUND_TO_PAGE(sizeof(*in),511);
unsigned char data[size];
int index = INVALID_PTN;
index = partition_get_index((unsigned char *) ptn_name);
ptn = partition_get_offset(index);
if(ptn == 0) {
dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
return -1;
}
if (mmc_read(ptn , (unsigned int*)data, size)) {
dprintf(CRITICAL,"mmc read failure %s %d\n",ptn_name, size);
return -1;
}
memcpy(in, data, sizeof(*in));
return 0;
}
int _emmc_recovery_init(void)
{
int update_status = 0;
struct recovery_message msg;
// get recovery message
if(emmc_get_recovery_msg(&msg))
return -1;
msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
if (msg.command[0] != 0 && msg.command[0] != 255) {
dprintf(INFO,"Recovery command: %d %s\n",
sizeof(msg.command), msg.command);
}
if (!strncmp(msg.command, "boot-recovery", strlen("boot-recovery"))) {
boot_into_recovery = 1;
}
if (!strcmp("update-radio",msg.command))
{
/* We're now here due to radio update, so check for update status */
int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
if(!ret && (update_status & 0x01))
{
dprintf(INFO,"radio update success\n");
strlcpy(msg.status, "OKAY", sizeof(msg.status));
}
else
{
dprintf(INFO,"radio update failed\n");
strlcpy(msg.status, "failed-update", sizeof(msg.status));
}
boot_into_recovery = 1; // Boot in recovery mode
}
if (!strcmp("reset-device-info",msg.command))
{
reset_device_info();
}
if (!strcmp("root-detect",msg.command))
{
set_device_root();
}
else
return 0; // do nothing
strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
emmc_set_recovery_msg(&msg); // send recovery message
return 0;
}
static int read_misc(unsigned page_offset, void *buf, unsigned size)
{
const char *ptn_name = "misc";
uint32_t pagesize = get_page_size();
unsigned offset;
if (size == 0 || buf == NULL)
return -1;
offset = page_offset * pagesize;
if (target_is_emmc_boot())
{
int index;
unsigned long long ptn;
unsigned long long ptn_size;
index = partition_get_index(ptn_name);
if (index == INVALID_PTN)
{
dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
return -1;
}
ptn = partition_get_offset(index);
ptn_size = partition_get_size(index);
if (ptn_size < offset + size)
{
dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
ptn_name);
return -1;
}
if (mmc_read(ptn + offset, (unsigned int *)buf, size))
{
dprintf(CRITICAL, "Reading MMC failed\n");
return -1;
}
}
else
{
dprintf(CRITICAL, "Misc partition not supported for NAND targets.\n");
return -1;
}
return 0;
}
int write_misc(unsigned page_offset, void *buf, unsigned size)
{
const char *ptn_name = "misc";
void *scratch_addr = target_get_scratch_address();
unsigned offset;
unsigned aligned_size;
if (size == 0 || buf == NULL || scratch_addr == NULL)
return -1;
if (target_is_emmc_boot())
{
int index;
unsigned long long ptn;
unsigned long long ptn_size;
index = partition_get_index(ptn_name);
if (index == INVALID_PTN)
{
dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
return -1;
}
ptn = partition_get_offset(index);
ptn_size = partition_get_size(index);
offset = page_offset * BLOCK_SIZE;
aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
if (ptn_size < offset + aligned_size)
{
dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
ptn_name);
return -1;
}
if (scratch_addr != buf)
memcpy(scratch_addr, buf, size);
if (mmc_write(ptn + offset, aligned_size, (unsigned int *)scratch_addr))
{
dprintf(CRITICAL, "Writing MMC failed\n");
return -1;
}
}
else
{
struct ptentry *ptn;
struct ptable *ptable;
unsigned pagesize = flash_page_size();
ptable = flash_get_ptable();
if (ptable == NULL)
{
dprintf(CRITICAL, "Partition table not found\n");
return -1;
}
ptn = ptable_find(ptable, ptn_name);
if (ptn == NULL)
{
dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
return -1;
}
offset = page_offset * pagesize;
aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
if (ptn->length < offset + aligned_size)
{
dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
ptn_name);
return -1;
}
if (scratch_addr != buf)
memcpy(scratch_addr, buf, size);
if (flash_write(ptn, offset, scratch_addr, aligned_size)) {
dprintf(CRITICAL, "Writing flash failed\n");
return -1;
}
}
return 0;
}
int get_ffbm(char *ffbm, unsigned size)
{
const char *ffbm_cmd = "ffbm-";
uint32_t page_size = get_page_size();
char *ffbm_page_buffer = NULL;
int retval = 0;
if (size < FFBM_MODE_BUF_SIZE || size >= page_size)
{
dprintf(CRITICAL, "Invalid size argument passed to get_ffbm\n");
retval = -1;
goto cleanup;
}
ffbm_page_buffer = (char*)malloc(page_size);
if (!ffbm_page_buffer)
{
dprintf(CRITICAL, "Failed to alloc buffer for ffbm cookie\n");
retval = -1;
goto cleanup;
}
if (read_misc(0, ffbm_page_buffer, page_size))
{
dprintf(CRITICAL, "Error reading MISC partition\n");
retval = -1;
goto cleanup;
}
ffbm_page_buffer[size] = '\0';
if (strncmp(ffbm_cmd, ffbm_page_buffer, strlen(ffbm_cmd)))
{
retval = 0;
goto cleanup;
}
else
{
if (strlcpy(ffbm, ffbm_page_buffer, size) <
FFBM_MODE_BUF_SIZE -1)
{
dprintf(CRITICAL, "Invalid string in misc partition\n");
retval = -1;
}
else
retval = 1;
}
cleanup:
if(ffbm_page_buffer)
free(ffbm_page_buffer);
return retval;
}

View File

@@ -0,0 +1,86 @@
/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _BOOTLOADER_RECOVERY_H
#define _BOOTLOADER_RECOVERY_H
#define UPDATE_MAGIC "MSM-RADIO-UPDATE"
#define UPDATE_MAGIC_SIZE 16
#define UPDATE_VERSION 0x00010000
#define FFBM_MODE_BUF_SIZE 8
/* Recovery Message */
struct recovery_message {
char command[32];
char status[32];
char recovery[1024];
};
struct update_header {
unsigned char MAGIC[UPDATE_MAGIC_SIZE];
unsigned version;
unsigned size;
unsigned image_offset;
unsigned image_length;
unsigned bitmap_width;
unsigned bitmap_height;
unsigned bitmap_bpp;
unsigned busy_bitmap_offset;
unsigned busy_bitmap_length;
unsigned fail_bitmap_offset;
unsigned fail_bitmap_length;
};
int write_misc(unsigned page_offset, void *buf, unsigned size);
int get_recovery_message(struct recovery_message *out);
int set_recovery_message(const struct recovery_message *in);
int read_update_header_for_bootloader(struct update_header *header);
int update_firmware_image (struct update_header *header, char *name);
int recovery_init (void);
/* This function will look for the ffbm cookie in the misc partition.
* Upon finding a valid cookie it will return 1 and place the cookie
* into ffbm.If it does not find a valid cookie it will return 0.If
* an error is hit it will return -1.If either of these return values
* is seen the data in ffbm should not be used and should be considered
* invalid.
*/
int get_ffbm(char *ffbm, unsigned size);
extern unsigned boot_into_recovery;
#endif

View File

@@ -0,0 +1,9 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
INCLUDES += -I$(LK_TOP_DIR)/platform/msm_shared/include
OBJS += \
$(LOCAL_DIR)/aboot.o \
$(LOCAL_DIR)/fastboot.o \
$(LOCAL_DIR)/recovery.o

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
typedef struct sparse_header {
uint32_t magic; /* 0xed26ff3a */
uint16_t major_version; /* (0x1) - reject images with higher major versions */
uint16_t minor_version; /* (0x0) - allow images with higer minor versions */
uint16_t file_hdr_sz; /* 28 bytes for first revision of the file format */
uint16_t chunk_hdr_sz; /* 12 bytes for first revision of the file format */
uint32_t blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
uint32_t total_blks; /* total blocks in the non-sparse output image */
uint32_t total_chunks; /* total chunks in the sparse input image */
uint32_t image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
/* as 0. Standard 802.3 polynomial, use a Public Domain */
/* table implementation */
} sparse_header_t;
#define SPARSE_HEADER_MAGIC 0xed26ff3a
#define CHUNK_TYPE_RAW 0xCAC1
#define CHUNK_TYPE_FILL 0xCAC2
#define CHUNK_TYPE_DONT_CARE 0xCAC3
#define CHUNK_TYPE_CRC 0xCAC4
typedef struct chunk_header {
uint16_t chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
uint16_t reserved1;
uint32_t chunk_sz; /* in blocks in output image */
uint32_t total_sz; /* in bytes of chunk input file including chunk header and data */
} chunk_header_t;
/* Following a Raw or Fill chunk is data. For a Raw chunk, it's the data in chunk_sz * blk_sz.
* For a Fill chunk, it's 4 bytes of the fill data.
*/