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
+100
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
@@ -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
+408
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;
}
@@ -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
+659
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;
}
@@ -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
@@ -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
@@ -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.
*/
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <app.h>
#include <kernel/thread.h>
extern const struct app_descriptor __apps_start;
extern const struct app_descriptor __apps_end;
static void start_app(const struct app_descriptor *app);
/* one time setup */
void apps_init(void)
{
const struct app_descriptor *app;
/* call all the init routines */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->init)
app->init(app);
}
/* start any that want to start on boot */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
start_app(app);
}
}
}
static int app_thread_entry(void *arg)
{
const struct app_descriptor *app = (const struct app_descriptor *)arg;
app->entry(app, NULL);
return 0;
}
static void start_app(const struct app_descriptor *app)
{
thread_t *thr;
printf("starting app %s\n", app->name);
thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
if(!thr)
{
return;
}
thread_resume(thr);
}
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2012, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <string.h>
#include <app.h>
#include <platform.h>
#include <kernel/thread.h>
#include <err.h>
#if defined(WITH_LIB_CONSOLE) && defined(DEBUG_CLOCK)
#include <lib/console.h>
#include <clock.h>
static void print_clock_list()
{
unsigned i;
struct clk_lookup *cl;
unsigned num;
struct clk_list *clock_list = clk_get_list();
if(!clock_list)
return;
cl = clock_list->clist;
num = clock_list->num;
if(!cl || !num)
return;
printf("Clock list:\n");
for(i=0; i < num; i++, cl++)
{
printf("%s\n", cl->con_id);
}
}
static int clock_measure(const char *id)
{
int ret = NO_ERROR;
struct clk *cp, *mcp;
unsigned long rate;
/* Get clk */
cp = clk_get(id);
if(!cp)
{
ret = ERR_NOT_VALID;
goto measure_error;
}
/* Get measure clk */
mcp = clk_get("measure");
if(!mcp)
{
ret = ERR_NOT_VALID;
goto measure_error;
}
/* Set parent clk */
clk_set_parent(mcp, cp);
rate = clk_get_rate(mcp);
printf("Clock %s is running at: %lu Hz.\n", id, rate);
measure_error:
return ret;
}
static int clock_tests(int argc, cmd_args *argv)
{
if (argc < 2) {
printf("not enough arguments:\n");
printf("%s <clock-name>\n", argv[0].str);
printf("%s ?\n", argv[0].str);
goto out;
}
if(argv[1].str[0] == '?')
print_clock_list();
else
clock_measure(argv[1].str);
out:
return 0;
}
STATIC_COMMAND_START
{ "test_clock", "Test Clock", &clock_tests },
STATIC_COMMAND_END(clocktests);
#endif
APP_START(clocktests)
APP_END
@@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
INCLUDES += -I$(LK_TOP_DIR)/platform/msm_shared/include
OBJS += \
$(LOCAL_DIR)/clock_tests.o
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
* Copyright (c) 2009, 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 _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 unused[2]; /* 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
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_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
@@ -0,0 +1,220 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
* Copyright (c) 2009, 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 <app.h>
#include <debug.h>
#include <lib/ptable.h>
#include <malloc.h>
#include <dev/flash.h>
#include <string.h>
#include <jtag.h>
#include <kernel/thread.h>
#include <smem.h>
#include <platform.h>
#include "bootimg.h"
#define FLASH_PAGE_SIZE 2048
#define FLASH_PAGE_BITS 11
unsigned page_size = 0;
unsigned page_mask = 0;
static unsigned load_addr = 0xffffffff;
#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
void acpu_clock_init(void);
int startswith(const char *str, const char *prefix)
{
while(*prefix){
if (*prefix++ != *str++) return 0;
}
return 1;
}
/* XXX */
void verify_flash(struct ptentry *p, void *addr, unsigned len, int extra)
{
uint32_t offset = 0;
void *buf = malloc(FLASH_PAGE_SIZE + extra);
int verify_extra = extra;
if(verify_extra > 4)
verify_extra = 16;
while(len > 0) {
flash_read_ext(p, extra, offset, buf, FLASH_PAGE_SIZE);
if(memcmp(addr, buf, FLASH_PAGE_SIZE + verify_extra)) {
dprintf(CRITICAL, "verify failed at 0x%08x\n", offset);
jtag_fail("verify failed");
return;
}
offset += FLASH_PAGE_SIZE;
addr += FLASH_PAGE_SIZE;
len -= FLASH_PAGE_SIZE;
if(extra) {
addr += extra;
len -= extra;
}
}
dprintf(INFO, "verify done %d extra bytes\n", verify_extra);
jtag_okay("verify done");
}
void handle_flash(const char *name, unsigned addr, unsigned sz)
{
struct ptentry *ptn;
struct ptable *ptable;
void *data = (void *) addr;
unsigned extra = 0;
ptable = flash_get_ptable();
if (ptable == NULL) {
jtag_fail("partition table doesn't exist");
return;
}
ptn = ptable_find(ptable, name);
if (ptn == NULL) {
jtag_fail("unknown partition name");
return;
}
if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
jtag_fail("image is not a boot image");
return;
}
}
if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata") || !strcmp(ptn->name, "persist"))
extra = ((page_size >> 9) * 16);
else
sz = ROUND_TO_PAGE(sz, page_mask);
data = (void *)target_get_scratch_address();
dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
if (flash_write(ptn, extra, data, sz)) {
jtag_fail("flash write failure");
return;
}
dprintf(INFO, "partition '%s' updated\n", ptn->name);
jtag_okay("Done");
enter_critical_section();
platform_uninit_timer();
arch_disable_cache(UCACHE);
arch_disable_mmu();
}
static unsigned char *tmpbuf = 0;
/*XXX*/
void handle_dump(const char *name, unsigned offset)
{
struct ptentry *p;
struct ptable *ptable;
if(tmpbuf == 0) {
tmpbuf = malloc(4096);
}
dprintf(INFO, "dump '%s' partition\n", name);
ptable = flash_get_ptable();
if (ptable == NULL) {
jtag_fail("partition table doesn't exist");
return;
}
p = ptable_find(ptable, name);
if(p == 0) {
jtag_fail("partition not found");
return;
} else {
#if 0
/* XXX reimpl */
if(flash_read_page(p->start * 64, tmpbuf, tmpbuf + 2048)){
jtag_fail("flash_read() failed");
return;
}
#endif
dprintf(INFO, "page %d data:\n", p->start * 64);
hexdump(tmpbuf, 256);
dprintf(INFO, "page %d extra:\n", p->start * 64);
hexdump(tmpbuf, 16);
jtag_okay("done");
enter_critical_section();
platform_uninit_timer();
arch_disable_cache(UCACHE);
arch_disable_mmu();
}
}
void handle_query_load_address(unsigned addr)
{
unsigned *return_addr = (unsigned *)addr;
if (return_addr)
*return_addr = target_get_scratch_address();
jtag_okay("done");
}
void handle_command(const char *cmd, unsigned a0, unsigned a1, unsigned a2)
{
if(startswith(cmd,"flash:")){
handle_flash(cmd + 6, a0, a1);
return;
}
if(startswith(cmd,"dump:")){
handle_dump(cmd + 5, a0);
return;
}
if(startswith(cmd,"loadaddr:")){
handle_query_load_address(a0);
return;
}
jtag_fail("unknown command");
}
void nandwrite_init(void)
{
page_size = flash_page_size();
page_mask = page_size - 1;
jtag_cmd_loop(handle_command);
}
@@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/nandwrite.o \
@@ -0,0 +1,249 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <app.h>
#include <debug.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <compiler.h>
#include <platform.h>
#include <dev/pci.h>
#if defined(WITH_LIB_CONSOLE)
#include <lib/console.h>
/*
* enumerates pci devices
*/
static void pci_list(void)
{
pci_location_t state;
uint16_t device_id, vendor_id;
uint8_t header_type;
int busses = 0, devices = 0, lines = 0, devfn, ret;
char c;
printf("Scanning...\n");
for (state.bus = 0; state.bus <= pci_get_last_bus(); state.bus++) {
busses++;
for (devfn = 0; devfn < 256; devfn++) {
state.dev_fn = devfn;
ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id);
if (ret != _PCI_SUCCESSFUL) goto error;
ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id);
if (ret != _PCI_SUCCESSFUL) goto error;
ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type);
if (ret != _PCI_SUCCESSFUL) goto error;
if (vendor_id != 0xffff) {
printf("%02x:%02x vendor_id=%04x device_id=%04x, header_type=%02x\n", state.bus, state.dev_fn,
vendor_id, device_id, header_type);
devices++;
lines++;
}
if (~header_type & PCI_HEADER_TYPE_MULTI_FN) {
// this is not a multi-function device, so advance to the next device
devfn |= 7;
}
if (lines == 23) {
printf("... press any key to continue, q to quit ...");
while(getc(&c) < 0);
printf("\n");
lines = 0;
if (c == 'q' || c == 'Q') goto quit;
}
}
}
printf("... done. Scanned %d busses, %d device/functions\n", busses, devices);
quit:
return;
error:
printf("Error while reading PCI config space: %02x\n", ret);
}
/*
* a somewhat fugly pci config space examine/modify command. this should probably
* be broken up a bit.
*/
static int pci_config(int argc, const cmd_args *argv)
{
pci_location_t loc;
pci_config_t config;
uint32_t offset;
unsigned int i;
int ret;
if (argc < 5) {
return -1;
}
if (!strcmp(argv[2].str, "dump")) {
loc.bus = atoui(argv[3].str);
loc.dev_fn = atoui(argv[4].str);
for (i=0; i < sizeof(pci_config_t); i++) {
ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i);
if (ret != _PCI_SUCCESSFUL) goto error;
}
printf("Device at %02x:%02x vendor id=%04x device id=%04x\n", loc.bus,
loc.dev_fn, config.vendor_id, config.device_id);
printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n",
config.command, config.status, config.program_interface,
config.sub_class, config.base_class);
for (i=0; i < 6; i+=2) {
printf("bar%d=%08x bar%d=%08x\n", i, config.base_addresses[i],
i+1, config.base_addresses[i+1]);
}
} else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) {
if (argc != 6) {
return -1;
}
loc.bus = atoui(argv[3].str);
loc.dev_fn = atoui(argv[4].str);
offset = atoui(argv[5].str);
switch (argv[2].str[1]) {
case 'b': {
uint8_t value;
ret = pci_read_config_byte(&loc, offset, &value);
if (ret != _PCI_SUCCESSFUL) goto error;
printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
}
break;
case 'h': {
uint16_t value;
ret = pci_read_config_half(&loc, offset, &value);
if (ret != _PCI_SUCCESSFUL) goto error;
printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
}
break;
case 'w': {
uint32_t value;
ret = pci_read_config_word(&loc, offset, &value);
if (ret != _PCI_SUCCESSFUL) goto error;
printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
}
break;
}
} else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) {
if (argc != 7) {
return -1;
}
loc.bus = atoui(argv[3].str);
loc.dev_fn = atoui(argv[4].str);
offset = atoui(argv[5].str);
switch (argv[2].str[1]) {
case 'b': {
uint8_t value = atoui(argv[6].str);
ret = pci_write_config_byte(&loc, offset, value);
if (ret != _PCI_SUCCESSFUL) goto error;
printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
}
break;
case 'h': {
uint16_t value = atoui(argv[6].str);
ret = pci_write_config_half(&loc, offset, value);
if (ret != _PCI_SUCCESSFUL) goto error;
printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
}
break;
case 'w': {
uint32_t value = atoui(argv[6].str);
ret = pci_write_config_word(&loc, offset, value);
if (ret != _PCI_SUCCESSFUL) goto error;
printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
}
break;
}
} else {
return -1;
}
return 0;
error:
printf("Error while reading PCI config space: %02x\n", ret);
return -2;
}
static int pci_cmd(int argc, const cmd_args *argv)
{
if (argc < 2) {
printf("pci commands:\n");
usage:
printf("%s list\n", argv[0].str);
printf("%s config dump <bus> <devfn>\n", argv[0].str);
printf("%s config <rb|rh|rw> <bus> <devfn> <offset>\n", argv[0].str);
printf("%s config <mb|mh|mw> <bus> <devfn> <offset> <value>\n", argv[0].str);
goto out;
}
if (!strcmp(argv[1].str, "list")) {
pci_list();
} else if (!strcmp(argv[1].str, "config")) {
if (pci_config(argc, argv)) {
goto usage;
}
} else {
goto usage;
}
out:
return 0;
}
STATIC_COMMAND_START
{ "pci", "pci toolbox", &pci_cmd },
STATIC_COMMAND_END(pcitests);
#endif
APP_START(pcitests)
APP_END
@@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
#INCLUDES += -I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/pci_tests.o
+8
View File
@@ -0,0 +1,8 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += \
lib/openssl
OBJS += \
$(LOCAL_DIR)/app.o
@@ -0,0 +1,7 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += \
lib/console
OBJS += \
$(LOCAL_DIR)/shell.o
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <app.h>
#include <debug.h>
#include <lib/console.h>
static void shell_init(const struct app_descriptor *app)
{
console_init();
}
static void shell_entry(const struct app_descriptor *app, void *args)
{
console_start();
}
APP_START(shell)
.init = shell_init,
.entry = shell_entry,
APP_END
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <asm.h>
#include <arch/arm/cores.h>
.text
.align 2
.global mymemcpy
mymemcpy:
// check for zero length copy or the same pointer
cmp r2, #0
cmpne r1, r0
bxeq lr
// save a few registers for use and the return code (input dst)
stmfd sp!, {r0, r4, r5, lr}
// check for forwards overlap (src > dst, distance < len)
subs r3, r0, r1
cmpgt r2, r3
bgt .L_forwardoverlap
// check for a short copy len.
// 20 bytes is enough so that if a 16 byte alignment needs to happen there is at least a
// wordwise copy worth of work to be done.
cmp r2, #(16+4)
blt .L_bytewise
// see if they are similarly aligned on 4 byte boundaries
eor r3, r0, r1
tst r3, #3
bne .L_bytewise // dissimilarly aligned, nothing we can do (for now)
// check for 16 byte alignment on dst.
// this will also catch src being not 4 byte aligned, since it is similarly 4 byte
// aligned with dst at this point.
tst r0, #15
bne .L_not16bytealigned
// check to see if we have at least 32 bytes of data to copy.
// if not, just revert to wordwise copy
cmp r2, #32
blt .L_wordwise
.L_bigcopy:
// copy 32 bytes at a time. src & dst need to be at least 4 byte aligned,
// and we need at least 32 bytes remaining to copy
// save r6-r7 for use in the big copy
stmfd sp!, {r6-r7}
sub r2, r2, #32 // subtract an extra 32 to the len so we can avoid an extra compare
.L_bigcopy_loop:
ldmia r1!, {r4, r5, r6, r7}
stmia r0!, {r4, r5, r6, r7}
ldmia r1!, {r4, r5, r6, r7}
subs r2, r2, #32
stmia r0!, {r4, r5, r6, r7}
bge .L_bigcopy_loop
// restore r6-r7
ldmfd sp!, {r6-r7}
// see if we are done
adds r2, r2, #32
beq .L_done
// less then 4 bytes left?
cmp r2, #4
blt .L_bytewise
.L_wordwise:
// copy 4 bytes at a time.
// src & dst are guaranteed to be word aligned, and at least 4 bytes are left to copy.
subs r2, r2, #4
.L_wordwise_loop:
ldr r3, [r1], #4
subs r2, r2, #4
str r3, [r0], #4
bge .L_wordwise_loop
// correct the remaining len and test for completion
adds r2, r2, #4
beq .L_done
.L_bytewise:
// simple bytewise copy
ldrb r3, [r1], #1
subs r2, r2, #1
strb r3, [r0], #1
bgt .L_bytewise
.L_done:
// load dst for return and restore r4,r5
#if ARM_ARCH_LEVEL >= 5
ldmfd sp!, {r0, r4, r5, pc}
#else
ldmfd sp!, {r0, r4, r5, lr}
bx lr
#endif
.L_not16bytealigned:
// dst is not 16 byte aligned, so we will copy up to 15 bytes to get it aligned.
// src is guaranteed to be similarly word aligned with dst.
// set the condition flags based on the alignment.
lsl r12, r0, #28
rsb r12, r12, #0
msr CPSR_f, r12 // move into NZCV fields in CPSR
// move as many bytes as necessary to get the dst aligned
ldrvsb r3, [r1], #1 // V set
ldrcsh r4, [r1], #2 // C set
ldreq r5, [r1], #4 // Z set
strvsb r3, [r0], #1
strcsh r4, [r0], #2
streq r5, [r0], #4
ldmmiia r1!, {r3-r4} // N set
stmmiia r0!, {r3-r4}
// fix the remaining len
sub r2, r2, r12, lsr #28
// test to see what we should do now
cmp r2, #32
bge .L_bigcopy
b .L_wordwise
// src and dest overlap 'forwards' or dst > src
.L_forwardoverlap:
// do a bytewise reverse copy for now
add r1, r1, r2
add r0, r0, r2
.L_bytewisereverse:
// simple bytewise reverse copy
ldrb r3, [r1], #-1
subs r2, r2, #1
strb r3, [r0], #-1
bgt .L_bytewisereverse
b .L_done
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <asm.h>
#include <arch/arm/cores.h>
.text
.align 2
/* void *memset(void *s, int c, size_t n); */
.global mymemset
mymemset:
// check for zero length
cmp r2, #0
bxeq lr
// save the original pointer
mov r12, r0
// short memsets aren't worth optimizing
cmp r2, #(32 + 16)
blt .L_bytewise
// fill a 32 bit register with the 8 bit value
and r1, r1, #0xff
orr r1, r1, r1, lsl #8
orr r1, r1, r1, lsl #16
// check for 16 byte alignment
tst r0, #15
bne .L_not16bytealigned
.L_bigset:
// dump some registers to make space for our values
stmfd sp!, { r4-r5 }
// fill a bunch of registers with the set value
mov r3, r1
mov r4, r1
mov r5, r1
// prepare the count register so we can avoid an extra compare
sub r2, r2, #32
// 32 bytes at a time
.L_bigset_loop:
stmia r0!, { r1, r3, r4, r5 }
subs r2, r2, #32
stmia r0!, { r1, r3, r4, r5 }
bge .L_bigset_loop
// restore our dumped registers
ldmfd sp!, { r4-r5 }
// see if we're done
adds r2, r2, #32
beq .L_done
.L_bytewise:
// bytewise memset
subs r2, r2, #1
strb r1, [r0], #1
bgt .L_bytewise
.L_done:
// restore the base pointer as return value
mov r0, r12
bx lr
.L_not16bytealigned:
// dst is not 16 byte aligned, so we will set up to 15 bytes to get it aligned.
// set the condition flags based on the alignment.
lsl r3, r0, #28
rsb r3, r3, #0
msr CPSR_f, r3 // move into NZCV fields in CPSR
// move as many bytes as necessary to get the dst aligned
strvsb r1, [r0], #1 // V set
strcsh r1, [r0], #2 // C set
streq r1, [r0], #4 // Z set
strmi r1, [r0], #4 // N set
strmi r1, [r0], #4 // N set
// fix the remaining len
sub r2, r2, r3, lsr #28
// do the large memset
b .L_bigset
@@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/string_tests.o \
$(LOCAL_DIR)/mymemcpy.o \
$(LOCAL_DIR)/mymemset.o
@@ -0,0 +1,285 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <string.h>
#include <malloc.h>
#include <app.h>
#include <platform.h>
#include <kernel/thread.h>
static uint8_t *src;
static uint8_t *dst;
static uint8_t *src2;
static uint8_t *dst2;
#define BUFFER_SIZE (1024*1024)
#define ITERATIONS 16
extern void *mymemcpy(void *dst, const void *src, size_t len);
extern void *mymemset(void *dst, int c, size_t len);
static void *null_memcpy(void *dst, const void *src, size_t len)
{
return dst;
}
static time_t bench_memcpy_routine(void *memcpy_routine(void *, const void *, size_t), size_t srcalign, size_t dstalign)
{
int i;
time_t t0;
t0 = current_time();
for (i=0; i < ITERATIONS; i++) {
memcpy_routine(dst + dstalign, src + srcalign, BUFFER_SIZE);
}
return current_time() - t0;
}
static void bench_memcpy(void)
{
time_t null, libc, mine;
size_t srcalign, dstalign;
printf("memcpy speed test\n");
thread_sleep(200); // let the debug string clear the serial port
for (srcalign = 0; srcalign < 64; ) {
for (dstalign = 0; dstalign < 64; ) {
null = bench_memcpy_routine(&null_memcpy, srcalign, dstalign);
libc = bench_memcpy_routine(&memcpy, srcalign, dstalign);
mine = bench_memcpy_routine(&mymemcpy, srcalign, dstalign);
printf("srcalign %lu, dstalign %lu\n", srcalign, dstalign);
printf(" null memcpy %u msecs\n", null);
printf(" libc memcpy %u msecs, %llu bytes/sec\n", libc, BUFFER_SIZE * ITERATIONS * 1000ULL / libc);
printf(" my memcpy %u msecs, %llu bytes/sec\n", mine, BUFFER_SIZE * ITERATIONS * 1000ULL / mine);
if (dstalign == 0)
dstalign = 1;
else
dstalign <<= 1;
}
if (srcalign == 0)
srcalign = 1;
else
srcalign <<= 1;
}
}
static void fillbuf(void *ptr, size_t len, uint32_t seed)
{
size_t i;
for (i = 0; i < len; i++) {
((char *)ptr)[i] = seed;
seed *= 0x1234567;
}
}
static void validate_memcpy(void)
{
size_t srcalign, dstalign, size;
const size_t maxsize = 256;
printf("testing memcpy for correctness\n");
/*
* do the simple tests to make sure that memcpy doesn't color outside
* the lines for all alignment cases
*/
for (srcalign = 0; srcalign < 64; srcalign++) {
for (dstalign = 0; dstalign < 64; dstalign++) {
// printf("srcalign %zu, dstalign %zu\n", srcalign, dstalign);
for (size = 0; size < maxsize; size++) {
// printf("srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size);
fillbuf(src, maxsize * 2, 567);
fillbuf(src2, maxsize * 2, 567);
fillbuf(dst, maxsize * 2, 123514);
fillbuf(dst2, maxsize * 2, 123514);
memcpy(dst + dstalign, src + srcalign, size);
mymemcpy(dst2 + dstalign, src2 + srcalign, size);
int comp = memcmp(dst, dst2, maxsize * 2);
if (comp != 0) {
printf("error! srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size);
}
}
}
}
}
static void validate_memcpy_overlap(void)
{
size_t srcalign, dstalign, size;
const size_t maxsize = 256;
int comp;
printf("testing memcpy for correctness in overlap cases\n");
for (dstalign = 0; dstalign < 64; dstalign++) {
for (size = 0; size < maxsize; size++) {
fillbuf(src, maxsize * 2, 567);
fillbuf(src2, maxsize * 2, 567);
/* Case one will check cpy memory is the same - fwd*/
memcpy(src + dstalign, src, size);
comp = memcmp(src + dstalign, src2, size);
if (comp != 0) {
printf("ERROR (Case1): dstalign %zu, size %zu, ret %d\n", dstalign, size, comp);
}
fillbuf(src, maxsize * 2, 8588485);
fillbuf(src2, maxsize * 2, 8588485);
/* Case two will check cpy memory is the same - bkwd*/
memcpy(src, src + dstalign, size);
comp = memcmp(src, src2 + dstalign, size);
if (comp != 0) {
printf("ERROR (Case2): dstalign %zu, size %zu, ret %d\n", dstalign, size, comp);
}
}
}
}
static time_t bench_memset_routine(void *memset_routine(void *, int, size_t), size_t dstalign)
{
int i;
time_t t0;
t0 = current_time();
for (i=0; i < ITERATIONS; i++) {
memset_routine(dst + dstalign, 0, BUFFER_SIZE);
}
return current_time() - t0;
}
static void bench_memset(void)
{
time_t libc, mine;
size_t dstalign;
printf("memset speed test\n");
thread_sleep(200); // let the debug string clear the serial port
for (dstalign = 0; dstalign < 64; dstalign++) {
libc = bench_memset_routine(&memset, dstalign);
mine = bench_memset_routine(&mymemset, dstalign);
printf("dstalign %lu\n", dstalign);
printf(" libc memset %u msecs, %llu bytes/sec\n", libc, BUFFER_SIZE * ITERATIONS * 1000ULL / libc);
printf(" my memset %u msecs, %llu bytes/sec\n", mine, BUFFER_SIZE * ITERATIONS * 1000ULL / mine);
}
}
static void validate_memset(void)
{
size_t dstalign, size;
int c;
const size_t maxsize = 256;
printf("testing memset for correctness\n");
for (dstalign = 0; dstalign < 64; dstalign++) {
printf("align %zd\n", dstalign);
for (size = 0; size < maxsize; size++) {
for (c = 0; c < 256; c++) {
fillbuf(dst, maxsize * 2, 123514);
fillbuf(dst2, maxsize * 2, 123514);
memset(dst + dstalign, c, size);
mymemset(dst2 + dstalign, c, size);
int comp = memcmp(dst, dst2, maxsize * 2);
if (comp != 0) {
printf("error! align %zu, c %d, size %zu\n", dstalign, c, size);
}
}
}
}
}
#if defined(WITH_LIB_CONSOLE)
#include <lib/console.h>
static int string_tests(int argc, cmd_args *argv)
{
src = memalign(64, BUFFER_SIZE + 256);
dst = memalign(64, BUFFER_SIZE + 256);
src2 = memalign(64, BUFFER_SIZE + 256);
dst2 = memalign(64, BUFFER_SIZE + 256);
printf("src %p, dst %p\n", src, dst);
printf("src2 %p, dst2 %p\n", src2, dst2);
if (argc < 3) {
printf("not enough arguments:\n");
usage:
printf("%s validate <routine>\n", argv[0].str);
printf("%s bench <routine>\n", argv[0].str);
goto out;
}
if (!strcmp(argv[1].str, "validate")) {
if (!strcmp(argv[2].str, "memcpy")) {
validate_memcpy();
} else if (!strcmp(argv[2].str, "memset")) {
validate_memset();
} else if (!strcmp(argv[2].str, "memcpy_overlap")) {
validate_memcpy_overlap();
}
} else if (!strcmp(argv[1].str, "bench")) {
if (!strcmp(argv[2].str, "memcpy")) {
bench_memcpy();
} else if (!strcmp(argv[2].str, "memset")) {
bench_memset();
}
} else {
goto usage;
}
out:
free(src);
free(dst);
free(src2);
free(dst2);
return 0;
}
STATIC_COMMAND_START
{ "string", NULL, &string_tests },
STATIC_COMMAND_END(stringtests);
#endif
APP_START(stringtests)
APP_END
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2012-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, Inc. 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 <pm8x41_adc.h>
#include <debug.h>
void adc_test()
{
uint32_t vadc_chan1;
uint32_t vadc_chan2;
uint16_t iusb = 3250000;
uint16_t ibat = 2500000;
uint16_t batt_id_chan = 49;
uint16_t vbat_sns_chan = 6;
/*
* TEST: Read the voltage on batt_id & vbat_sns channels
*/
vadc_chan1 = pm8x41_adc_channel_read(batt_id_chan);
dprintf(INFO, "The channel [%ud] voltage is :%ud\n",batt_id_chan, vadc_chan1);
vadc_chan2 = pm8x41_adc_channel_read(vbat_sns_chan);
dprintf(INFO, "The channel [%ud] voltage is :%ud\n",vbat_sns_chan, vadc_chan2);
/*
* TEST: Set the IUSB & IBAT max values
*/
if (!pm8x41_iusb_max_config(iusb))
dprintf(INFO, "Iusb max current is set\n");
if (!pm8x41_ibat_max_config(ibat))
dprintf(INFO, "Ibat max current is set\n");
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2012-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, Inc. 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 <i2c_qup.h>
#include <blsp_qup.h>
#define EEPROM_HW_I2C_ADDRESS (0x52)
void eeprom_read_test()
{
struct qup_i2c_dev *dev;
char ret[100] = {'\0'};
dev = qup_blsp_i2c_init(BLSP_ID_2, QUP_ID_4, 100000, 19200000);
if (!dev) {
dprintf(CRITICAL, "Failed initializing I2c\n");
return;
}
/* Create a i2c_msg buffer, to read from eprom */
struct i2c_msg msg_buf[] = {
{EEPROM_HW_I2C_ADDRESS, I2C_M_RD, 100, ret}
};
qup_i2c_xfer(dev, msg_buf, 1);
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __APP_TESTS_H
#define __APP_TESTS_H
int thread_tests(void);
void printf_tests(void);
#endif
@@ -0,0 +1,72 @@
/*
* 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.
*/
#include<dev/pm8921_leds.h>
#include<dev/pm8921.h>
void led_tests()
{
uint32_t duty_us, period_us;
/* 50% Duty cycle */
duty_us = 500000;
period_us = 1000000;
/* Configure PM8921_ID_LED_0 from PWM2*/
pm8921_config_led_current(PM8921_ID_LED_0, 2, PWM2, 1);
/* PWM2 for PM8921_ID_LED_0 is LPG 5
* Configure and enable lpg5
*/
pm_set_pwm_config(5, duty_us, period_us, &pmic);
pm_pwm_channel_enable(5, &pmic);
/* Configure and enable lpg0 for panel backlight*/
pm_set_pwm_config(0, duty_us, period_us, &pmic);
pm_pwm_channel_enable(0, &pmic);
mdelay(10000);
/* Configure PM8921_ID_LED_1 also from PWM2*/
pm8921_config_led_current(PM8921_ID_LED_1, 2, PWM2, 1);
mdelay(10000);
/* Disable PM8921_ID_LED_0 */
pm8921_config_led_current(PM8921_ID_LED_0, 2, 2, 0);
/* Turn on GPIO 24 through LPG 0
* Will be reconfigured during display_init
*/
panel_backlight_on_pwm();
mdelay(10000);
/* Disable PM8921_ID_LED_1 */
pm8921_config_led_current(PM8921_ID_LED_1, 2, 2, 0);
}
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <app/tests.h>
#include <debug.h>
void printf_tests(void)
{
printf("printf tests\n");
printf("numbers:\n");
printf("int8: %hhd %hhd %hhd\n", -12, 0, 254);
printf("uint8: %hhu %hhu %hhu\n", -12, 0, 254);
printf("int16: %hd %hd %hd\n", -1234, 0, 1234);
printf("uint16:%hu %hu %hu\n", -1234, 0, 1234);
printf("int: %d %d %d\n", -12345678, 0, 12345678);
printf("uint: %u %u %u\n", -12345678, 0, 12345678);
printf("long: %ld %ld %ld\n", -12345678, 0, 12345678);
printf("ulong: %lu %lu %lu\n", -12345678, 0, 12345678);
printf("long: %D %D %D\n", -12345678, 0, 12345678);
printf("ulong: %U %U %U\n", -12345678, 0, 12345678);
printf("longlong: %lli %lli %lli\n", -12345678LL, 0LL, 12345678LL);
printf("ulonglong: %llu %llu %llu\n", -12345678LL, 0LL, 12345678LL);
printf("size_t: %zd %zd %zd\n", -12345678, 0, 12345678);
printf("usize_t: %zu %zu %zu\n", -12345678, 0, 12345678);
printf("hex:\n");
printf("uint8: %hhx %hhx %hhx\n", -12, 0, 254);
printf("uint16:%hx %hx %hx\n", -1234, 0, 1234);
printf("uint: %x %x %x\n", -12345678, 0, 12345678);
printf("ulong: %lx %lx %lx\n", -12345678, 0, 12345678);
printf("ulong: %X %X %X\n", -12345678, 0, 12345678);
printf("ulonglong: %llx %llx %llx\n", -12345678LL, 0LL, 12345678LL);
printf("usize_t: %zx %zx %zx\n", -12345678, 0, 12345678);
printf("alt/sign:\n");
printf("uint: %#x %#X\n", 0xabcdef, 0xabcdef);
printf("int: %+d %+d\n", 12345678, -12345678);
printf("formatting\n");
printf("int: a%8da\n", 12345678);
printf("int: a%9da\n", 12345678);
printf("int: a%-9da\n", 12345678);
printf("int: a%10da\n", 12345678);
printf("int: a%-10da\n", 12345678);
printf("int: a%09da\n", 12345678);
printf("int: a%010da\n", 12345678);
printf("int: a%6da\n", 12345678);
printf("a%1sa\n", "b");
printf("a%9sa\n", "b");
printf("a%-9sa\n", "b");
printf("a%5sa\n", "thisisatest");
int err;
err = printf("a");
printf(" returned %d\n", err);
err = printf("ab");
printf(" returned %d\n", err);
err = printf("abc");
printf(" returned %d\n", err);
err = printf("abcd");
printf(" returned %d\n", err);
err = printf("abcde");
printf(" returned %d\n", err);
err = printf("abcdef");
printf(" returned %d\n", err);
}
+10
View File
@@ -0,0 +1,10 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
INCLUDES += -I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/tests.o \
$(LOCAL_DIR)/thread_tests.o \
$(LOCAL_DIR)/printf_tests.o \
$(LOCAL_DIR)/i2c_tests.o \
$(LOCAL_DIR)/adc_tests.o
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <app.h>
#include <debug.h>
#include <app/tests.h>
#include <compiler.h>
#if defined(WITH_LIB_CONSOLE)
#include <lib/console.h>
STATIC_COMMAND_START
STATIC_COMMAND("printf_tests", NULL, (console_cmd)&printf_tests)
STATIC_COMMAND("thread_tests", NULL, (console_cmd)&thread_tests)
STATIC_COMMAND_END(tests);
#endif
static void tests_init(const struct app_descriptor *app)
{
}
APP_START(tests)
.init = tests_init,
.flags = 0,
APP_END
@@ -0,0 +1,322 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <rand.h>
#include <app/tests.h>
#include <kernel/thread.h>
#include <kernel/mutex.h>
#include <kernel/event.h>
static int sleep_thread(void *arg)
{
for(;;) {
printf("sleeper %p\n", current_thread);
thread_sleep(rand() % 500);
}
return 0;
}
int sleep_test(void)
{
int i;
for(i=0; i < 16; i++)
thread_resume(thread_create("sleeper", &sleep_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
return 0;
}
static volatile int shared = 0;
static mutex_t m;
static volatile int mutex_thread_count = 0;
static int mutex_thread(void *arg)
{
int i;
const int iterations = 10000;
atomic_add(&mutex_thread_count, 1);
printf("mutex tester thread %p starting up, will go for %d iterations\n", current_thread, iterations);
for (i = 0; i < iterations; i++) {
mutex_acquire(&m);
if (shared != 0)
panic("someone else has messed with the shared data\n");
shared = (int)current_thread;
thread_yield();
shared = 0;
mutex_release(&m);
thread_yield();
}
atomic_add(&mutex_thread_count, -1);
return 0;
}
static int mutex_timeout_thread(void *arg)
{
mutex_t *timeout_mutex = (mutex_t *)arg;
status_t err;
printf("mutex_timeout_thread acquiring mutex %p with 1 second timeout\n", timeout_mutex);
err = mutex_acquire_timeout(timeout_mutex, 1000);
printf("mutex_acquire_timeout returns %d\n", err);
return err;
}
static int mutex_zerotimeout_thread(void *arg)
{
mutex_t *timeout_mutex = (mutex_t *)arg;
status_t err;
printf("mutex_zerotimeout_thread acquiring mutex %p with zero second timeout\n", timeout_mutex);
err = mutex_acquire_timeout(timeout_mutex, 0);
printf("mutex_acquire_timeout returns %d\n", err);
return err;
}
int mutex_test(void)
{
mutex_init(&m);
int i;
for(i=0; i < 5; i++)
thread_resume(thread_create("mutex tester", &mutex_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(1000);
while (mutex_thread_count > 0)
thread_yield();
printf("done with simple mutex tests\n");
printf("testing mutex timeout\n");
mutex_t timeout_mutex;
mutex_init(&timeout_mutex);
mutex_acquire(&timeout_mutex);
for (i=0; i < 2; i++)
thread_resume(thread_create("mutex timeout tester", &mutex_timeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
for (i=0; i < 2; i++)
thread_resume(thread_create("mutex timeout tester", &mutex_zerotimeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(5000);
mutex_release(&timeout_mutex);
printf("done with mutex tests\n");
mutex_destroy(&timeout_mutex);
return 0;
}
static event_t e;
static int event_signaller(void *arg)
{
printf("event signaller pausing\n");
thread_sleep(1000);
// for (;;) {
printf("signalling event\n");
event_signal(&e, true);
printf("done signalling event\n");
thread_yield();
// }
return 0;
}
static int event_waiter(void *arg)
{
printf("event waiter starting\n");
for (;;) {
printf("%p: waiting on event...\n", current_thread);
if (event_wait(&e) < 0) {
printf("%p: event_wait() returned error\n", current_thread);
return -1;
}
printf("%p: done waiting on event...\n", current_thread);
thread_yield();
}
return 0;
}
void event_test(void)
{
/* make sure signalling the event wakes up all the threads */
event_init(&e, false, 0);
thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(2000);
event_destroy(&e);
/* make sure signalling the event wakes up precisely one thread */
event_init(&e, false, EVENT_FLAG_AUTOUNSIGNAL);
thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(2000);
event_destroy(&e);
}
static int quantum_tester(void *arg)
{
for (;;) {
printf("%p: in this thread. rq %d\n", current_thread, current_thread->remaining_quantum);
}
return 0;
}
void quantum_test(void)
{
thread_resume(thread_create("quantum tester 0", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("quantum tester 1", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("quantum tester 2", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("quantum tester 3", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
}
static event_t context_switch_event;
static event_t context_switch_done_event;
static int context_switch_tester(void *arg)
{
int i;
uint total_count = 0;
const int iter = 100000;
int thread_count = (int)arg;
event_wait(&context_switch_event);
uint count = arch_cycle_count();
for (i = 0; i < iter; i++) {
thread_yield();
}
total_count += arch_cycle_count() - count;
thread_sleep(1000);
printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n",
total_count, iter, total_count / iter, total_count / iter / thread_count);
event_signal(&context_switch_done_event, true);
return 0;
}
void context_switch_test(void)
{
event_init(&context_switch_event, false, 0);
event_init(&context_switch_done_event, false, 0);
thread_resume(thread_create("context switch idle", &context_switch_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(100);
event_signal(&context_switch_event, true);
event_wait(&context_switch_done_event);
thread_sleep(100);
event_unsignal(&context_switch_event);
event_unsignal(&context_switch_done_event);
thread_resume(thread_create("context switch 2a", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("context switch 2b", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(100);
event_signal(&context_switch_event, true);
event_wait(&context_switch_done_event);
thread_sleep(100);
event_unsignal(&context_switch_event);
event_unsignal(&context_switch_done_event);
thread_resume(thread_create("context switch 4a", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("context switch 4b", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("context switch 4c", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("context switch 4d", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
thread_sleep(100);
event_signal(&context_switch_event, true);
event_wait(&context_switch_done_event);
thread_sleep(100);
}
static volatile int atomic;
static volatile int atomic_count;
static int atomic_tester(void *arg)
{
int add = (int)arg;
int i;
TRACEF("add %d\n", add);
for (i=0; i < 1000000; i++) {
atomic_add(&atomic, add);
}
int old = atomic_add(&atomic_count, -1);
TRACEF("exiting, old count %d\n", old);
return 0;
}
static void atomic_test(void)
{
atomic = 0;
atomic_count = 8;
thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
while (atomic_count > 0) {
thread_sleep(1);
}
printf("atomic count == %d (should be zero)\n", atomic);
}
int thread_tests(void)
{
mutex_test();
event_test();
thread_sleep(200);
context_switch_test();
atomic_test();
return 0;
}