first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
#include <arch.h>
|
||||
#include <debug.h>
|
||||
#include <sys/task.h>
|
||||
#include <drivers/csi.h>
|
||||
#include <drivers/a7iop/a7iop.h>
|
||||
|
||||
#include "csi_private.h"
|
||||
|
||||
//
|
||||
// Private Data
|
||||
//
|
||||
|
||||
static volatile csi_status_t last_error = CSI_STATUS_OK;
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_send_message
|
||||
//
|
||||
// Send message for the built-in endpoint. If the IOP becomes unreachable
|
||||
// at some point stop sending message and instead directly fails to avoid
|
||||
// multiple timeout error.
|
||||
//
|
||||
csi_status_t
|
||||
bi_ep_send_message (void *token, msg_payload_t msg_payload)
|
||||
{
|
||||
csi_status_t status;
|
||||
|
||||
// make sure the previous send was not a timeout
|
||||
if (CSI_STATUS_OK != last_error) {
|
||||
// the IOP is not responding, error out right away
|
||||
return last_error;
|
||||
}
|
||||
|
||||
// send the message
|
||||
status = csi_send_message (token, msg_payload);
|
||||
if (CSI_STATUS_TIMEOUT == status) {
|
||||
// the IOP is not responding, save the error status
|
||||
last_error = CSI_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
#include <arch.h>
|
||||
#include <debug.h>
|
||||
#include <sys/task.h>
|
||||
#include <drivers/csi.h>
|
||||
#include <drivers/a7iop/a7iop.h>
|
||||
|
||||
#include "csi_private.h"
|
||||
#include "endpoints/console_ep.h"
|
||||
|
||||
#include <csi_ipc_protocol.h>
|
||||
#include <csi_console_defines.h>
|
||||
#include <csi_console_protocol.h>
|
||||
|
||||
|
||||
//
|
||||
// Global Data
|
||||
//
|
||||
|
||||
static ep_console_desc_t *console_descs[CSI_COPROC_MAX] = {NULL};
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
int ep_console_task (void *arg);
|
||||
void console_msg_handler (ep_console_desc_t *console, msg_payload_t msg);
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_console_create
|
||||
//
|
||||
void
|
||||
bi_ep_console_create (csi_coproc_t which_coproc)
|
||||
{
|
||||
// enforce single instance
|
||||
REQUIRE(console_descs[which_coproc]==NULL);
|
||||
console_descs[which_coproc] = malloc(sizeof(ep_console_desc_t));
|
||||
REQUIRE(console_descs[which_coproc]!=NULL);
|
||||
|
||||
console_descs[which_coproc]->coproc = which_coproc;
|
||||
|
||||
task_start(task_create("csi ep console", ep_console_task, console_descs[which_coproc], kTaskStackSize_endpoints));
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
console_quiesce (csi_coproc_t which_coproc, csi_power_state_t ps)
|
||||
{
|
||||
ep_console_desc_t *console = console_descs[which_coproc];
|
||||
|
||||
// free the sahred memory
|
||||
if (!(ps & CSI_PS_SHARED_PRESERVED) && (NULL != console->buffers)) {
|
||||
csi_free_shared_memory(console->buffers);
|
||||
console->buffers = NULL;
|
||||
console->allocated = 0;
|
||||
}
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_console_send_custom_cmd
|
||||
//
|
||||
csi_status_t
|
||||
bi_ep_console_send_custom_cmd (csi_coproc_t which_coproc, uint32_t payload)
|
||||
{
|
||||
ep_console_desc_t *console;
|
||||
ipc_msg_t resp;
|
||||
|
||||
console = console_descs[which_coproc];
|
||||
|
||||
if (console == NULL) {
|
||||
return CSI_STATUS_UNAVAILABLE;
|
||||
}
|
||||
|
||||
ipc_console_create_custom_cmd(&resp, payload);
|
||||
|
||||
return bi_ep_send_message (console->csi_token, resp);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_console_set_verbosity
|
||||
//
|
||||
csi_status_t
|
||||
bi_ep_console_set_verbosity (csi_coproc_t which_coproc, uint32_t verbosity)
|
||||
{
|
||||
ep_console_desc_t *console;
|
||||
ipc_msg_t resp;
|
||||
|
||||
console = console_descs[which_coproc];
|
||||
|
||||
if (console == NULL) {
|
||||
return CSI_STATUS_UNAVAILABLE;
|
||||
}
|
||||
|
||||
console->verbosity = verbosity;
|
||||
ipc_console_create_flow_enable_cmd(&resp, console->verbosity);
|
||||
|
||||
return bi_ep_send_message (console->csi_token, resp);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Console Message handler
|
||||
//
|
||||
|
||||
int
|
||||
ep_console_task (void *arg)
|
||||
{
|
||||
csi_status_t result;
|
||||
msg_payload_t rcv_msg;
|
||||
|
||||
ep_console_desc_t *console = (ep_console_desc_t*)arg;
|
||||
|
||||
event_init(&console->msg_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
||||
|
||||
result = csi_register_endpoint(console->coproc, IPC_ENDPOINT_BUILT_IN_CONSOLE, &console->msg_event, &console->csi_token, &console->name);
|
||||
REQUIRE(result==CSI_STATUS_OK);
|
||||
|
||||
console->verbosity = 1;
|
||||
console->buffers = NULL;
|
||||
console->allocated = 0;
|
||||
console->scratch = malloc(CONSOLE_BUFFER_SIZE+1);
|
||||
REQUIRE(console->scratch!=NULL);
|
||||
|
||||
for (;;) {
|
||||
event_wait(&console->msg_event);
|
||||
|
||||
// empty the rcv queue
|
||||
while (csi_receive_message(console->csi_token, &rcv_msg) == CSI_STATUS_OK) {
|
||||
console_msg_handler(console, rcv_msg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
console_msg_handler (ep_console_desc_t *console, msg_payload_t msg)
|
||||
{
|
||||
uint64_t paddr;
|
||||
ipc_msg_t resp;
|
||||
uint32_t cmd;
|
||||
uint32_t rd_off;
|
||||
uint32_t wr_off;
|
||||
uint32_t size;
|
||||
console_buffer_t *buffer_desc;
|
||||
csi_status_t status;
|
||||
|
||||
// the console endpoint use the reserved 2 bits of the buffer message to encode commands
|
||||
// decode the command and respond to it
|
||||
cmd = ipc_msg_extract(msg, IPC_MSG_BUFF_MSG_FLAG_RV_LEN, IPC_MSG_BUFF_MSG_FLAG_RV_POS);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case REQUEST_NEW_BUFFER:
|
||||
// allocate a console buffer of the requested size.
|
||||
console->allocated = ipc_buff_msg_get_size(msg);
|
||||
console->buffers = csi_allocate_shared_memory(console->csi_token, console->allocated);
|
||||
REQUIRE(console->buffers!=NULL);
|
||||
paddr = mem_static_map_physical((uintptr_t)console->buffers);
|
||||
|
||||
// send the new buffer response back to the IOP
|
||||
ipc_buff_create_msg(&resp, paddr, console->allocated);
|
||||
resp |= ipc_msg_set(HERE_IS_A_NEW_BUFFER, IPC_MSG_BUFF_MSG_FLAG_RV_LEN, IPC_MSG_BUFF_MSG_FLAG_RV_POS);
|
||||
status = bi_ep_send_message (console->csi_token, resp);
|
||||
if (CSI_STATUS_OK != status) {
|
||||
CSI_EP_LOG(CRITICAL, console->coproc, console->name, "unable to reply to REQUEST_NEW_BUFFER: %x\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
// this transaction occurs when the console endpoint is initially up and ready
|
||||
// and so is an appropriate time to communicate console verbosity to the IOP
|
||||
ipc_console_create_flow_enable_cmd(&resp, console->verbosity);
|
||||
status = bi_ep_send_message (console->csi_token, resp);
|
||||
if (CSI_STATUS_OK != status) {
|
||||
CSI_EP_LOG(CRITICAL, console->coproc, console->name, "unable to send console verbosity: %x\n", status);
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_BUFFER:
|
||||
buffer_desc = &((console_buffer_t*)(console->buffers))[ipc_console_iocmd_get_channel(&msg)];
|
||||
|
||||
rd_off = ipc_console_iocmd_get_rdptr(&msg);
|
||||
wr_off = ipc_console_iocmd_get_wrptr(&msg);
|
||||
|
||||
if (rd_off<=wr_off) {
|
||||
size = wr_off - rd_off;
|
||||
REQUIRE(size<=CONSOLE_BUFFER_SIZE);
|
||||
maybe_do_cache_operation(CACHE_INVALIDATE, &buffer_desc->buffer[rd_off], size);
|
||||
memcpy(console->scratch, &buffer_desc->buffer[rd_off], size);
|
||||
} else {
|
||||
size = CONSOLE_BUFFER_SIZE - rd_off;
|
||||
REQUIRE((size+wr_off)<=CONSOLE_BUFFER_SIZE);
|
||||
maybe_do_cache_operation(CACHE_INVALIDATE, &buffer_desc->buffer[rd_off], size);
|
||||
memcpy(console->scratch, &buffer_desc->buffer[rd_off], size);
|
||||
maybe_do_cache_operation(CACHE_INVALIDATE, buffer_desc->buffer, wr_off);
|
||||
memcpy((console->scratch+size), buffer_desc->buffer, wr_off);
|
||||
size += wr_off;
|
||||
}
|
||||
console->scratch[size] = '\0';
|
||||
|
||||
CSI_EP_LOG(CONSOLE, console->coproc, console->name, "%s\n", console->scratch);
|
||||
|
||||
// only send message if the other side is not shutting down. Otherwise this
|
||||
// might create a lock up in suspend to RAM situation.
|
||||
if (!csi_is_shutdown_in_progress(console->coproc)) {
|
||||
ipc_console_create_iocmd(&resp, DONE_WITH_BUFFER, ipc_console_iocmd_get_channel(&msg), wr_off, wr_off);
|
||||
status = bi_ep_send_message (console->csi_token, resp);
|
||||
}
|
||||
break;
|
||||
|
||||
case BUFFER_OVERFLOWED:
|
||||
CSI_EP_LOG(CONSOLE, console->coproc, console->name, "Console buffer overflow - message truncated\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
CSI_EP_LOG(CRITICAL, console->coproc, console->name, "unimplemented console command: %x\n", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
#include <arch.h>
|
||||
#include <debug.h>
|
||||
#include <sys/task.h>
|
||||
#include <drivers/csi.h>
|
||||
#include <drivers/a7iop/a7iop.h>
|
||||
|
||||
#include "csi_private.h"
|
||||
#include "endpoints/crashlog_ep.h"
|
||||
|
||||
#include <csi_ipc_protocol.h>
|
||||
#include <csi_frame.h>
|
||||
#include <csi_crashlog_defines.h>
|
||||
|
||||
|
||||
//
|
||||
// Global Data
|
||||
//
|
||||
|
||||
static ep_crashlog_desc_t *crashlog_descs[CSI_COPROC_MAX] = {NULL};
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
int ep_crashlog_task (void *arg);
|
||||
void crashlog_msg_handler (ep_crashlog_desc_t *clog, msg_payload_t msg);
|
||||
|
||||
csi_status_t cl_print (ep_crashlog_desc_t *clog);
|
||||
void cl_print_register_frame (CrashLogDataHeader_t *section);
|
||||
void cl_print_os_info (CrashLogDataHeader_t *section);
|
||||
void cl_print_string (CrashLogDataHeader_t *section);
|
||||
void cl_print_mailbox (CrashLogDataHeader_t *section);
|
||||
void cl_print_call_stack (CrashLogDataHeader_t *section);
|
||||
|
||||
static const char* get_signature_string (CrashLogSignature_t sig);
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_crashlog_create
|
||||
//
|
||||
void bi_ep_crashlog_create (csi_coproc_t which_coproc)
|
||||
{
|
||||
// enforce single instance
|
||||
REQUIRE(crashlog_descs[which_coproc]==NULL);
|
||||
crashlog_descs[which_coproc] = malloc(sizeof(ep_crashlog_desc_t));
|
||||
REQUIRE(crashlog_descs[which_coproc]!=NULL);
|
||||
|
||||
crashlog_descs[which_coproc]->coproc = which_coproc;
|
||||
|
||||
task_start(task_create("csi ep crashlog", ep_crashlog_task, crashlog_descs[which_coproc], kTaskStackSize_endpoints));
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
crashlog_quiesce (csi_coproc_t which_coproc, csi_power_state_t ps)
|
||||
{
|
||||
ep_crashlog_desc_t *clog = crashlog_descs[which_coproc];
|
||||
|
||||
// free all shared memory if we are not preserving it
|
||||
if (!(ps & CSI_PS_SHARED_PRESERVED) && (NULL != clog->buffer)) {
|
||||
csi_free_shared_memory(clog->buffer);
|
||||
clog->buffer = NULL;
|
||||
clog->allocated = 0;
|
||||
}
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_crashlog_force_event
|
||||
//
|
||||
// force a crashlog generation through various means
|
||||
//
|
||||
csi_status_t
|
||||
bi_ep_crashlog_force_event (csi_coproc_t which_coproc, csi_crashlog_t crashlog_type)
|
||||
{
|
||||
if (crashlog_descs[which_coproc]==NULL) {
|
||||
return CSI_STATUS_UNAVAILABLE;
|
||||
}
|
||||
|
||||
switch (crashlog_type) {
|
||||
default:
|
||||
return CSI_STATUS_ERROR;
|
||||
|
||||
case CSI_CRASHLOG_TYPE_NMI:
|
||||
akf_send_nmi(KFW(which_coproc));
|
||||
break;
|
||||
|
||||
case CSI_CRASHLOG_TYPE_MSG_CRASH:
|
||||
case CSI_CRASHLOG_TYPE_MSG_LOG:
|
||||
return bi_ep_send_message (crashlog_descs[which_coproc]->csi_token, (msg_payload_t)((crashlog_type==CSI_CRASHLOG_TYPE_MSG_CRASH) ? CL_NMI_MSG_CRASH : CL_NMI_MSG_LOG));
|
||||
break;
|
||||
}
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Crashlog Message Handler
|
||||
//
|
||||
|
||||
int
|
||||
ep_crashlog_task(void *arg)
|
||||
{
|
||||
csi_status_t result;
|
||||
msg_payload_t rcv_msg;
|
||||
|
||||
ep_crashlog_desc_t *clog = (ep_crashlog_desc_t*)arg;
|
||||
|
||||
event_init(&clog->msg_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
||||
|
||||
result = csi_register_endpoint(clog->coproc, IPC_ENDPOINT_BUILT_IN_CRASHLOG, &clog->msg_event, &clog->csi_token, &clog->name);
|
||||
REQUIRE(result==CSI_STATUS_OK);
|
||||
|
||||
clog->buffer = NULL;
|
||||
clog->allocated = 0;
|
||||
|
||||
for (;;) {
|
||||
event_wait(&clog->msg_event);
|
||||
|
||||
// empty the rcv queue
|
||||
while(csi_receive_message(clog->csi_token, &rcv_msg) == CSI_STATUS_OK) {
|
||||
crashlog_msg_handler(clog, rcv_msg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// crashlog_msg_handler
|
||||
//
|
||||
// handle an asynchronous message from the coproc
|
||||
//
|
||||
// All message are using the buffer protocol.
|
||||
// If a zero address is received this is a shared buffer allocation request and a new buffer
|
||||
// physical address is returned.
|
||||
// Otherwise this is interpreted as a crash log and it is displayed on the screen/saved for
|
||||
// future use as appropriate
|
||||
//
|
||||
void
|
||||
crashlog_msg_handler (ep_crashlog_desc_t *clog, msg_payload_t msg)
|
||||
{
|
||||
uint64_t paddr;
|
||||
ipc_msg_t resp;
|
||||
csi_status_t status;
|
||||
|
||||
// the first message is a buffer request, identified by a NULL address in the upper portion
|
||||
// of the payload
|
||||
if (ipc_buff_msg_get_address(msg) == 0x00) {
|
||||
|
||||
// allocate a console buffer of the requested size.
|
||||
clog->allocated = ipc_buff_msg_get_size(msg);
|
||||
clog->buffer = csi_allocate_shared_memory(clog->csi_token, clog->allocated);
|
||||
REQUIRE(clog->buffer!=NULL);
|
||||
paddr = mem_static_map_physical((uintptr_t)clog->buffer);
|
||||
CSI_EP_LOG(DEBUG_SPEW, clog->coproc, clog->name, "buffer request of size %u bytes, allocated @ physical 0x%llx (AP %p)\n",
|
||||
clog->allocated, paddr, clog->buffer);
|
||||
|
||||
// send the response back to the IOP
|
||||
ipc_buff_create_msg(&resp, paddr, clog->allocated);
|
||||
status = bi_ep_send_message (clog->csi_token, resp);
|
||||
if (CSI_STATUS_OK != status) {
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// A crash log has been received, decode it
|
||||
maybe_do_cache_operation(CACHE_INVALIDATE, clog->buffer, clog->allocated);
|
||||
status = cl_print(clog);
|
||||
if (CSI_STATUS_PANIC_RECOVER == status) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "Recoverable panic, reseting\n");
|
||||
status = csi_panic_recover (clog->coproc);
|
||||
}
|
||||
else if (status != CSI_STATUS_OK) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "data is corrupt or unrecognizable (%x)\n", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// *** Crashlog Decoder ***
|
||||
//
|
||||
|
||||
#define RUN_IF_COMPATIBLE(version, version_expected, expr) \
|
||||
do { \
|
||||
if(LOG_MAJOR_VERSION(version) == LOG_MAJOR_VERSION(version_expected)) \
|
||||
expr; \
|
||||
else \
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "Not executing " #expr " because version %u.%u is not compatible with expected version %u.%u\n", \
|
||||
LOG_PRINT_VERSION(version), LOG_PRINT_VERSION(version_expected)); \
|
||||
} while(0)
|
||||
|
||||
static const char*
|
||||
get_exc_type_str(uint16_t exc_type)
|
||||
{
|
||||
switch (exc_type & CL_TYPE_MASK) {
|
||||
case CL_ARM_EXCEPTION_UNDEF: return "UNDEF exception";
|
||||
case CL_ARM_EXCEPTION_PREFETCH_ABORT: return "PREFETCH ABORT";
|
||||
case CL_ARM_EXCEPTION_DATA_ABORT: return "DATA ABORT";
|
||||
case CL_KERNEL_PANIC: return "PANIC";
|
||||
case CL_NMI: return "NMI FIQ";
|
||||
case CL_NMI_MSG_LOG: return "forced log msg";
|
||||
case CL_NMI_MSG_CRASH: return "forced crash msg";
|
||||
case CL_STACK_GUARD_FAULT: return "Stack guard fault";
|
||||
case CL_FLOW_ERROR: return "Mailbox error";
|
||||
case CL_PANIC_RECOVERY: return "Recoverable PANIC";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// cl_print
|
||||
//
|
||||
// Decode and print the crash log using the registered section decoders.
|
||||
// Make sure the section version match the supported version before
|
||||
// decoding them.
|
||||
//
|
||||
csi_status_t
|
||||
cl_print (ep_crashlog_desc_t *clog)
|
||||
{
|
||||
uint8_t *cl_buffer;
|
||||
CrashLogHeader_t *cl_header;
|
||||
uint32_t cl_size;
|
||||
CrashLogHeader_t *end_header;
|
||||
const char *cl_type_str;
|
||||
uint8_t *log;
|
||||
|
||||
cl_buffer = clog->buffer;
|
||||
cl_header = (CrashLogHeader_t*)cl_buffer;
|
||||
cl_size = cl_header->size - sizeof (CrashLogHeader_t);
|
||||
|
||||
// validate the signature
|
||||
if (CRASH_LOG_HEADER_SIGNATURE != cl_header->signature) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "invalid log signature: 0x%x, should be 0x%x.\n", cl_header->signature, CRASH_LOG_HEADER_SIGNATURE);
|
||||
return CSI_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// ensure the version is compatible
|
||||
if (LOG_MAJOR_VERSION(CRASH_LOG_VERSION) != LOG_MAJOR_VERSION(cl_header->version)) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "invalid log major version: %u, should be %u.\n",
|
||||
LOG_MAJOR_VERSION(cl_header->version), LOG_MAJOR_VERSION(CRASH_LOG_VERSION));
|
||||
return CSI_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// If this is neither a partial nor nested log make sure the header at
|
||||
// the beginning of the log match the one at the end.
|
||||
// Issue a warning if they don't and still try to decode the log.
|
||||
end_header = (CrashLogHeader_t*)(cl_buffer + cl_size);
|
||||
|
||||
if (cl_header->exception & CL_LOG_INITIAL_FLAG) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "partial log, log might be incomplete\n");
|
||||
// revert size to the one in the header, as we don't know what is at the end.
|
||||
cl_size = cl_header->size;
|
||||
}
|
||||
else if (memcmp (cl_header, end_header, sizeof (CrashLogHeader_t))) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "end header does not match log header, log might be corrupted (cl_size=%d %p %p)\n", cl_size, cl_header, end_header);
|
||||
// revert size to the one in the header, as we don't know what is at the end.
|
||||
cl_size = cl_header->size;
|
||||
}
|
||||
|
||||
// validate the checksum
|
||||
// TBD
|
||||
|
||||
#if !RELEASE_BUILD
|
||||
// Print the log
|
||||
cl_type_str = get_exc_type_str(cl_header->exception);
|
||||
if (cl_type_str != NULL) {
|
||||
CSI_EP_LOG(CRASHLOG, clog->coproc, clog->name, "%s\n", cl_type_str);
|
||||
} else {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "crash log of unexpected type 0x%0x\n", cl_header->exception);
|
||||
}
|
||||
if (cl_header->exception & CL_LOG_NESTED_FLAG) {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "a nested %s occured @ 0x%08x\n",
|
||||
get_exc_type_str(cl_header->nestedException), cl_header->nestedLr);
|
||||
}
|
||||
|
||||
// Decode the data section
|
||||
// A duplicate log header is placed at the end of the data section, ignore it.
|
||||
log = (cl_buffer + sizeof (CrashLogHeader_t));
|
||||
|
||||
while (log < (uint8_t*)end_header) {
|
||||
CrashLogDataHeader_t *header = (CrashLogDataHeader_t*)log;
|
||||
switch (header->signature) {
|
||||
case CRASH_LOG_DATA_REGISTER_SIGNATURE:
|
||||
RUN_IF_COMPATIBLE(header->version, CRASH_LOG_DATA_REGISTER_VERSION, cl_print_register_frame(header));
|
||||
break;
|
||||
case CRASH_LOG_DATA_OS_INFO_SIGNATURE:
|
||||
RUN_IF_COMPATIBLE(header->version, CRASH_LOG_DATA_OS_INFO_VERSION, cl_print_os_info(header));
|
||||
break;
|
||||
case CRASH_LOG_DATA_STRING_SIGNATURE:
|
||||
RUN_IF_COMPATIBLE(header->version, CRASH_LOG_DATA_STRING_VERSION, cl_print_string(header));
|
||||
break;
|
||||
case CRASH_LOG_DATA_MAILBOX_SIGNATURE:
|
||||
RUN_IF_COMPATIBLE(header->version, CRASH_LOG_DATA_MAILBOX_VERSION, cl_print_mailbox(header));
|
||||
break;
|
||||
case CRASH_LOG_DATA_CALL_STACK_SIGNATURE:
|
||||
RUN_IF_COMPATIBLE(header->version, CRASH_LOG_DATA_CALL_STACK_VERSION, cl_print_call_stack(header));
|
||||
break;
|
||||
default:
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "found unknown %s section of size %d, version %x.%x\n",
|
||||
get_signature_string(header->signature), header->size, LOG_PRINT_VERSION(header->version));
|
||||
break;
|
||||
}
|
||||
log += header->size;
|
||||
}
|
||||
#else
|
||||
// silence all warnings
|
||||
(void)cl_type_str;
|
||||
(void)log;
|
||||
#endif
|
||||
|
||||
// if we received a recoverable panic reset the IOP
|
||||
if (CL_PANIC_RECOVERY == cl_header->exception) {
|
||||
// if we are not already in panic recovery and one was requested try it
|
||||
if (!csi_is_panic_recovery(clog->coproc)) {
|
||||
csi_set_feature (clog->coproc, COPROC_FEATURE_PANIC_RECOVERY);
|
||||
return CSI_STATUS_PANIC_RECOVER;
|
||||
} else {
|
||||
CSI_EP_LOG(CRITICAL, clog->coproc, clog->name, "failed panic recovery, hanging...\n");
|
||||
}
|
||||
}
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// *** Register section ***
|
||||
//
|
||||
|
||||
typedef struct _fsr_entry_t {
|
||||
const uint32_t value;
|
||||
const char* const reason;
|
||||
} fsr_entry_t;
|
||||
|
||||
static const fsr_entry_t fsr_short_descriptor_table[] = { // From DDI0406C Table B3-23: VMSAv7 Short-descriptor format FSR encodings
|
||||
{1, "Alignment fault"},
|
||||
{4, "Instruction cache maintenance fault"},
|
||||
{12, "Translation table walk synchronous external abort (1st level)"},
|
||||
{14, "Translation table walk synchronous external abort (2nd level)"},
|
||||
{28, "Translation table walk synchronous parity error (1st level)"},
|
||||
{30, "Translation table walk synchronous parity error (2nd level)"},
|
||||
{5, "Translation fault (section)"},
|
||||
{7, "Translation fault (page)"},
|
||||
{3, "Access Flag fault (section)"},
|
||||
{6, "Access Flag fault (page)"},
|
||||
{9, "Domain fault (section)"},
|
||||
{11, "Domain fault (page)"},
|
||||
{13, "Permission fault (section)"},
|
||||
{15, "Permission fault (page)"},
|
||||
{2, "Debug event"},
|
||||
{8, "Synchronous external abort"},
|
||||
{16, "TLB conflict abort"},
|
||||
{20, "Implementation defined (Lockdown)"},
|
||||
{26, "Implementation defined (Coprocessor abort)"},
|
||||
{25, "Memory access synchronous parity error"},
|
||||
{22, "Asynchronous external abort"},
|
||||
{24, "Memory access asynchronous parity error"},
|
||||
{(uint32_t)-1, "Unknown"} // Terminated by value = (unsigned int)-1, which is never a valid encoding
|
||||
};
|
||||
|
||||
static const fsr_entry_t fsr_long_descriptor_table[] = { // From DDI0406C Table B3-24: VMSAv7 Long-descriptor format FSR encodings
|
||||
{4, "Translation fault level %u"},
|
||||
{8, "Access flag fault level %u"},
|
||||
{12, "Permission fault level %u"},
|
||||
{20, "Synchronous external abort on translation table walk level %u"},
|
||||
{28, "Synchronous parity error on memory access on translation table walk level %u"},
|
||||
{60, "Domain fault level %u"},
|
||||
{16, "Synchronous external abort"},
|
||||
{24, "Synchronous parity error on memory access"},
|
||||
{17, "Asynchronous external abort"},
|
||||
{25, "Asynchronous parity error on memory access"},
|
||||
{33, "Alignment fault"},
|
||||
{34, "Debug event"},
|
||||
{48, "TLB conflict abort"},
|
||||
{52, "Implementation defined (Lockdown)"},
|
||||
{58, "Implementation defined (Coprocessor abort)"},
|
||||
{(uint32_t)-1, "Unknown"} // Terminated by value = (unsigned int)-1, which is never a valid encoding
|
||||
};
|
||||
|
||||
|
||||
static const char*
|
||||
cl_decode_fsr(uint32_t fsr_val)
|
||||
{
|
||||
// holder for the processed lookup level FSR entries
|
||||
static char fsr_status_string[80];
|
||||
|
||||
uint32_t fault_status;
|
||||
uint32_t fault_lookup_level = 0;
|
||||
uint32_t fault_status_ll = 0;
|
||||
|
||||
const fsr_entry_t *fsr_table;
|
||||
|
||||
// Check the LPAE bit to see if this is short or long descriptor
|
||||
if ((fsr_val & (1u<<9)) == 0 )
|
||||
{
|
||||
// Non-LPAE, using short-descriptor format
|
||||
fault_status = ((fsr_val & (1u<<10)) >> 6 ) | (fsr_val & 0xf); // [10, 3:0]
|
||||
fsr_table = fsr_short_descriptor_table;
|
||||
}
|
||||
else
|
||||
{
|
||||
// LPAE, using long-descriptor format
|
||||
fault_status = (fsr_val & 0x3f); // [5:0]
|
||||
fault_lookup_level = (fsr_val & 0x03); // [1:0]
|
||||
fault_status_ll = (fsr_val & 0x3c); // [5:2]
|
||||
fsr_table = fsr_long_descriptor_table;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
// if a match for non-lookup level entry or the terminator
|
||||
if( (fault_status == fsr_table->value)
|
||||
|| (fault_status_ll == fsr_table->value)
|
||||
|| (fsr_table->value == (uint32_t)-1) )
|
||||
{
|
||||
snprintf(fsr_status_string, sizeof(fsr_status_string), fsr_table->reason, fault_lookup_level);
|
||||
return fsr_status_string;
|
||||
}
|
||||
|
||||
fsr_table++;
|
||||
}
|
||||
|
||||
// Control should never reach here since fsr tables are terminated by value = -1
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// cl_print_register_frame
|
||||
//
|
||||
// Decode and print the register frame section
|
||||
//
|
||||
void
|
||||
cl_print_register_frame (CrashLogDataHeader_t *section)
|
||||
{
|
||||
CrashLogRegisterSection_t *regSection = (CrashLogRegisterSection_t*) section;
|
||||
|
||||
CSI_LOG_RAW(CRASHLOG, "Failing task register frame:\n");
|
||||
CSI_LOG_RAW(CRASHLOG, " Faulting PC=0x%08x\n", regSection->registerFrame.pc);
|
||||
|
||||
// print additional information register data
|
||||
switch (regSection->exception) {
|
||||
case CL_ARM_EXCEPTION_PREFETCH_ABORT:
|
||||
CSI_LOG_RAW(CRASHLOG, " ifsr=0x%08x (%s) ifar=0x%08x\n",
|
||||
regSection->registerFrame.extra_info1, cl_decode_fsr(regSection->registerFrame.extra_info1),
|
||||
regSection->registerFrame.extra_info2);
|
||||
break;
|
||||
|
||||
case CL_STACK_GUARD_FAULT:
|
||||
case CL_ARM_EXCEPTION_DATA_ABORT:
|
||||
CSI_LOG_RAW(CRASHLOG, " dfsr=0x%08x (%s) dfar=0x%08x\n",
|
||||
regSection->registerFrame.extra_info1, cl_decode_fsr(regSection->registerFrame.extra_info1),
|
||||
regSection->registerFrame.extra_info2);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// print faulting task registers
|
||||
CSI_LOG_RAW(CRASHLOG, " r00=0x%08x r01=0x%08x r02=0x%08x r03=0x%08x\n"
|
||||
" r04=0x%08x r05=0x%08x r06=0x%08x r07=0x%08x\n"
|
||||
" r08=0x%08x r09=0x%08x r10=0x%08x r11=0x%08x\n"
|
||||
" r12=0x%08x sp=0x%08x lr=0x%08x pc=0x%08x\n"
|
||||
" spsr=0x%08x\n",
|
||||
regSection->registerFrame.r0, regSection->registerFrame.r1, regSection->registerFrame.r2, regSection->registerFrame.r3,
|
||||
regSection->registerFrame.r4, regSection->registerFrame.r5, regSection->registerFrame.r6, regSection->registerFrame.r7,
|
||||
regSection->registerFrame.r8, regSection->registerFrame.r9, regSection->registerFrame.r10, regSection->registerFrame.r11,
|
||||
regSection->registerFrame.r12, regSection->registerFrame.sp, regSection->registerFrame.lr, regSection->registerFrame.pc,
|
||||
regSection->registerFrame.spsr);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// *** OS Section ***
|
||||
//
|
||||
|
||||
const char*
|
||||
cl_decode_task_status(uint32_t status)
|
||||
{
|
||||
if (status & 0x100) return "INACTIVE";
|
||||
if (status & 0x080) return "QUEUE_WAIT";
|
||||
if (status & 0x040) return "SEMAPHORE_WAIT";
|
||||
if (status & 0x020) return "MSG_WAIT";
|
||||
if (status & 0x010) return "BLOCK_WAIT";
|
||||
if (status & 0x008) return "RESOURCE_WAIT";
|
||||
if (status & 0x004) return "DELAY_WAIT";
|
||||
if (status & 0x002) return "PARTITION_WAIT";
|
||||
if ((status & 0xffe) == 0x000) return "READY";
|
||||
if ((status & 0x001) == 0x001) return "SUSPENDED";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
//
|
||||
// cl_print_os_info
|
||||
//
|
||||
// Decode the OS section
|
||||
//
|
||||
void
|
||||
cl_print_os_info (CrashLogDataHeader_t *section)
|
||||
{
|
||||
CrashLogRtxcSection_t *rtxcSection = (CrashLogRtxcSection_t*) section;
|
||||
|
||||
// display the current task list
|
||||
CSI_LOG_RAW(CRASHLOG, "RTXC Task List:\n"
|
||||
" name | pri | lr | stack use | status\n");
|
||||
|
||||
CrashLogRtxcTask_t *taskLog = (CrashLogRtxcTask_t*)((uint8_t*)(section) + sizeof (CrashLogRtxcSection_t));
|
||||
|
||||
for (int i = 0; i < (int)rtxcSection->numTask; i++) {
|
||||
// add a '*' in front of the hipri task
|
||||
if (taskLog->id == rtxcSection->taskId) {
|
||||
CSI_LOG_RAW(CRASHLOG, "*");
|
||||
} else {
|
||||
CSI_LOG_RAW(CRASHLOG, " ");
|
||||
}
|
||||
|
||||
CSI_LOG_RAW(CRASHLOG, "%2d %-15s | %03d | 0x%08x | %04u/%04u | %s\n",
|
||||
taskLog->id, taskLog->name, taskLog->priority,
|
||||
taskLog->lr, taskLog->stackUsed, taskLog->stackSize,
|
||||
cl_decode_task_status(taskLog->status));
|
||||
taskLog++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// *** string section ***
|
||||
//
|
||||
|
||||
void
|
||||
cl_print_string (CrashLogDataHeader_t *section)
|
||||
{
|
||||
// this section is a header with a NULL terminated string
|
||||
CrashLogStringSection_t *stringSection = (CrashLogStringSection_t*) section;
|
||||
|
||||
// make sure the string is NULL terminated, force it if not
|
||||
char *str = &(stringSection->data.string);
|
||||
size_t len = section->size - sizeof (CrashLogStringSection_t) - 1; // length of the string without the null termination
|
||||
|
||||
if ('\0' != str[len]) {
|
||||
str[len] = '\0';
|
||||
}
|
||||
|
||||
// print the section
|
||||
CSI_LOG_RAW(CRASHLOG, "%s\n", str);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// *** Mailbox Section ***
|
||||
//
|
||||
|
||||
void
|
||||
cl_print_mailbox (CrashLogDataHeader_t *section)
|
||||
{
|
||||
CrashLogMailboxData_t *mailSection = &(((CrashLogMailboxSection_t*)section)->data);
|
||||
|
||||
if (CL_MAILBOX_NO_ERROR == mailSection->error) {
|
||||
CSI_LOG_RAW(CRASHLOG, "Mailbox status:\n");
|
||||
} else {
|
||||
CSI_LOG_RAW(CRASHLOG, "Mailbox status: (error = 0x%x\n", mailSection->error);
|
||||
}
|
||||
CSI_LOG_RAW(CRASHLOG, " Inbox AKF_KIC_INBOX_CTRL = 0x%08x, AKF_KIC_MAILBOX_SET = 0x%08x\n"
|
||||
" Outbox AKF_AP_OUTBOX_CTRL = 0x%08x, AKF_AP_MAILBOX_SET = 0x%08x\n",
|
||||
mailSection->inboxCtrl, mailSection->inboxInt,
|
||||
mailSection->outboxCtrl, mailSection->outboxInt);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// *** Call Stack section ***
|
||||
//
|
||||
|
||||
static const char *
|
||||
get_call_stack_error_string(uint32_t error_code)
|
||||
{
|
||||
const char *error_string;
|
||||
|
||||
switch (error_code) {
|
||||
default:
|
||||
case CL_CALL_STACK_NO_ERROR:
|
||||
error_string = "";
|
||||
break;
|
||||
case CL_CALL_STACK_OVERFLOW:
|
||||
error_string = "error: stack too big for crash log";
|
||||
break;
|
||||
case CL_CALL_STACK_FP_NULL:
|
||||
error_string = "error: fp is null => possible stack corruption";
|
||||
break;
|
||||
case CL_CALL_STACK_FP_INVALID:
|
||||
error_string = "error: fp is invalid => possible stack corruption";
|
||||
break;
|
||||
}
|
||||
|
||||
return error_string;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// cl_print_call_stack
|
||||
//
|
||||
// Print the call stack of a task.
|
||||
// There is one of these section per task.
|
||||
//
|
||||
void
|
||||
cl_print_call_stack (CrashLogDataHeader_t *section)
|
||||
{
|
||||
bool isAPanic;
|
||||
CrashLogCallStackSection_t *callStackSection;
|
||||
uint32_t *callStack;
|
||||
|
||||
callStackSection = (CrashLogCallStackSection_t*) section;
|
||||
isAPanic = ((callStackSection->panickingFuncIndex>0) && (callStackSection->panickingFuncIndex<callStackSection->stackDepth));
|
||||
callStack = (uint32_t*)(callStackSection+1);
|
||||
|
||||
CSI_LOG_RAW(CRASHLOG, "Task %2u Call Stack:%s%s - ",
|
||||
callStackSection->taskId,
|
||||
(isAPanic?" (@=>panicking function)":""),
|
||||
get_call_stack_error_string(callStackSection->error));
|
||||
|
||||
for ( uint32_t j=0; j<callStackSection->stackDepth; j++ ) {
|
||||
CSI_LOG_RAW(CRASHLOG, " %s0x%08x", ((isAPanic&&(j==callStackSection->panickingFuncIndex))?"@":" "), *callStack++);
|
||||
}
|
||||
|
||||
CSI_LOG_RAW(CRASHLOG, "\n");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Private utility function
|
||||
//
|
||||
|
||||
const char*
|
||||
get_signature_string (CrashLogSignature_t sig)
|
||||
{
|
||||
static char sig_str[5];
|
||||
// signature are 4 ascii bytes packed into a 32 bit word
|
||||
// extract and print
|
||||
sig_str[0] = (char)((sig >> 24) & 0x00FF);
|
||||
sig_str[1] = (char)((sig >> 16) & 0x00FF);
|
||||
sig_str[2] = (char)((sig >> 8) & 0x00FF);
|
||||
sig_str[3] = (char)(sig & 0x00FF);
|
||||
sig_str[4] = (char)('\0');
|
||||
|
||||
return sig_str;
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
#include <arch.h>
|
||||
#include <debug.h>
|
||||
#include <sys/task.h>
|
||||
#include <drivers/csi.h>
|
||||
#include <drivers/a7iop/a7iop.h>
|
||||
|
||||
#include "csi_private.h"
|
||||
#include "endpoints/management_ep.h"
|
||||
#include "endpoints/crashlog_ep.h"
|
||||
#include "endpoints/console_ep.h"
|
||||
#include "endpoints/syslog_ep.h"
|
||||
|
||||
|
||||
//
|
||||
// Global Data
|
||||
//
|
||||
|
||||
ep_mgmt_desc_t *mgmt_descs[CSI_COPROC_MAX] = {NULL};
|
||||
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
int ep_mgmt_task (void *arg);
|
||||
|
||||
csi_status_t mgmt_msg_handler (ep_mgmt_desc_t *mgmt, msg_payload_t msg);
|
||||
csi_status_t handle_hello (ep_mgmt_desc_t *mgmt, ipc_msg_t msg_in);
|
||||
csi_status_t handle_power_state (ep_mgmt_desc_t *mgmt, ipc_msg_t msg_in);
|
||||
csi_status_t handle_power_state_ack (ep_mgmt_desc_t *mgmt, ipc_msg_t msg_in);
|
||||
csi_status_t validate_protocol (ep_mgmt_desc_t *mgmt, csi_protocol_version_t protocol_version);
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_mgmt_create
|
||||
//
|
||||
// create a new management endpoint.
|
||||
//
|
||||
void
|
||||
bi_ep_mgmt_create (csi_coproc_t which_coproc, struct task_event *ps_event)
|
||||
{
|
||||
ep_mgmt_desc_t *mgmt;
|
||||
|
||||
// enforce single instance
|
||||
REQUIRE(mgmt_descs[which_coproc] == NULL);
|
||||
|
||||
mgmt = malloc(sizeof(ep_mgmt_desc_t));
|
||||
REQUIRE(mgmt != NULL);
|
||||
|
||||
mgmt->coproc = which_coproc;
|
||||
mgmt->ps_event = ps_event;
|
||||
mgmt->power_state = CSI_PS_OFF;
|
||||
|
||||
mgmt_descs[which_coproc] = mgmt;
|
||||
|
||||
task_start(task_create("csi ep mgmt", ep_mgmt_task, mgmt_descs[which_coproc], kTaskStackSize_endpoints));
|
||||
}
|
||||
|
||||
mgmt_state_t
|
||||
bi_ep_mgmt_get_state (csi_coproc_t which_coproc)
|
||||
{
|
||||
if (mgmt_descs[which_coproc] == NULL) {
|
||||
return MGMT_NONEXISTENT;
|
||||
}
|
||||
|
||||
return mgmt_descs[which_coproc]->state;
|
||||
}
|
||||
|
||||
csi_power_state_t
|
||||
bi_ep_mgmt_get_power_state (csi_coproc_t which_coproc)
|
||||
{
|
||||
if (mgmt_descs[which_coproc] == NULL) {
|
||||
return CSI_PS_OFF;
|
||||
}
|
||||
|
||||
return mgmt_descs[which_coproc]->power_state;
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
bi_ep_mgmt_send_ps (csi_coproc_t which_coproc, csi_power_state_t ps)
|
||||
{
|
||||
ep_mgmt_desc_t *mgmt;
|
||||
msg_payload_t ps_msg;
|
||||
|
||||
mgmt = mgmt_descs[which_coproc];
|
||||
|
||||
csi_mgmt_create_msg (&ps_msg, MGMT_MSG_POWER_STATE, csi_mgmt_create_ps_msg(ps));
|
||||
|
||||
return csi_send_message (mgmt->csi_token, ps_msg);
|
||||
}
|
||||
|
||||
//
|
||||
// mgmt endpoint: task
|
||||
//
|
||||
int
|
||||
ep_mgmt_task (void *arg)
|
||||
{
|
||||
csi_status_t result;
|
||||
msg_payload_t rcv_msg;
|
||||
|
||||
ep_mgmt_desc_t *mgmt = (ep_mgmt_desc_t*)arg;
|
||||
|
||||
event_init(&mgmt->msg_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
||||
|
||||
result = csi_register_endpoint(mgmt->coproc, IPC_ENDPOINT_BUILT_IN_MGMT, &mgmt->msg_event, &mgmt->csi_token, &mgmt->name);
|
||||
REQUIRE(result==CSI_STATUS_OK);
|
||||
|
||||
mgmt->state = MGMT_QUIESCED;
|
||||
mgmt->remoteVersion = MGMT_UNSUPPORTED_VERSION;
|
||||
|
||||
// FixMe - pinger_init(&mgmt->pinger);
|
||||
|
||||
mgmt->ping_test_waiting = false;
|
||||
mgmt->ping_test_seqnum = (csi_ping_seqnum_t)0x1234;
|
||||
|
||||
|
||||
for (;;) {
|
||||
event_wait(&mgmt->msg_event);
|
||||
// empty the rcv queue
|
||||
while(csi_receive_message(mgmt->csi_token, &rcv_msg) == CSI_STATUS_OK) {
|
||||
mgmt_msg_handler(mgmt, rcv_msg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
mgmt_msg_handler (ep_mgmt_desc_t *mgmt, msg_payload_t msg)
|
||||
{
|
||||
csi_mgmt_msg_t type;
|
||||
csi_status_t status;
|
||||
|
||||
type = csi_mgmt_get_type(msg);
|
||||
status = CSI_STATUS_OK;
|
||||
|
||||
// get the type and dispatch to the appropriate handler
|
||||
switch (type) {
|
||||
case MGMT_MSG_HELLO:
|
||||
status = handle_hello(mgmt, msg);
|
||||
break;
|
||||
|
||||
case MGMT_MSG_HELLO_ACK:
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "unsupported HELLO_ACK message received: %llx\n", msg);
|
||||
break;
|
||||
|
||||
case MGMT_MSG_PING:
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "unsupported PING message received: %llx\n", msg);
|
||||
break;
|
||||
|
||||
case MGMT_MSG_PING_ACK:
|
||||
// in lieu of autonomous pinger
|
||||
if (!mgmt->ping_test_waiting) {
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "unexpected ping ack received\n");
|
||||
}
|
||||
mgmt->ping_test_ack = msg;
|
||||
mgmt->ping_test_waiting = false;
|
||||
break;
|
||||
|
||||
case MGMT_MSG_POWER_STATE:
|
||||
status = handle_power_state(mgmt, msg);
|
||||
break;
|
||||
|
||||
case MGMT_MSG_POWER_STATE_ACK:
|
||||
status = handle_power_state_ack(mgmt, msg);
|
||||
break;
|
||||
|
||||
case MGMT_MSG_NOP:
|
||||
// nop message are silently discarded
|
||||
status = CSI_STATUS_OK;
|
||||
break;
|
||||
|
||||
case MGMT_MSG_ENDPOINT_STATUS:
|
||||
// these should never happen
|
||||
|
||||
default:
|
||||
// all other message type are currently unsupported
|
||||
// ignore them to support upward compatibility
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "invalid or unsupported message type received: %d\n", type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CSI_STATUS_OK != status) {
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "failed to process message of type %d\n", type);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
handle_hello (ep_mgmt_desc_t *mgmt, ipc_msg_t msg_in)
|
||||
{
|
||||
csi_status_t status;
|
||||
msg_payload_t msg_out;
|
||||
|
||||
// Check status of the endpoint.
|
||||
// If we are not waiting for a hello message (quiesced state) ignore it
|
||||
if ((MGMT_QUIESCED != mgmt->state) && (MGMT_UNSUPPORTED_PROTOCOL_VERSION != mgmt->state)) {
|
||||
return CSI_STATUS_ERROR;
|
||||
}
|
||||
mgmt->power_state = CSI_PS_ON;
|
||||
|
||||
// Validate the other side protocol version
|
||||
status = validate_protocol(mgmt, csi_mgmt_get_prot(msg_in));
|
||||
if (CSI_STATUS_OK == status) {
|
||||
// supported version - send our version in the ACK message
|
||||
if (csi_is_panic_recovery(mgmt->coproc)) {
|
||||
// set the panic recovery feature flag
|
||||
csi_mgmt_create_msg (&msg_out, MGMT_MSG_HELLO_ACK, csi_mgmt_create_hello_msg (CSI_FEATURE_PANIC_RECOVERY, APPLE_CSI_PROTOCOL_VERSION));
|
||||
} else {
|
||||
// no feature support by default.
|
||||
csi_mgmt_create_msg (&msg_out, MGMT_MSG_HELLO_ACK, csi_mgmt_create_hello_msg (CSI_FEATURE_NONE, APPLE_CSI_PROTOCOL_VERSION));
|
||||
}
|
||||
|
||||
CSI_EP_LOG (DEBUG_SPEW, mgmt->coproc, mgmt->name, "coproc running, protocol version %x.%x\n",
|
||||
csi_mgmt_get_prot_major(mgmt->remoteVersion), csi_mgmt_get_prot_minor(mgmt->remoteVersion));
|
||||
|
||||
} else {
|
||||
// unsupported version - signal the other side we do not support them
|
||||
CSI_EP_LOG (CRITICAL, mgmt->coproc, mgmt->name, "coproc running unsupported version %x.%x\n",
|
||||
csi_mgmt_get_prot_major(mgmt->remoteVersion), csi_mgmt_get_prot_minor(mgmt->remoteVersion));
|
||||
|
||||
csi_mgmt_create_msg (&msg_out, MGMT_MSG_HELLO_ACK, MGMT_UNSUPPORTED_VERSION);
|
||||
}
|
||||
|
||||
return bi_ep_send_message (mgmt->csi_token, msg_out);
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
handle_power_state (ep_mgmt_desc_t *mgmt, ipc_msg_t msg_in)
|
||||
{
|
||||
msg_payload_t ps_msg;
|
||||
csi_power_state_t ps;
|
||||
|
||||
// the IOP is requesting a power state change.
|
||||
// Used for debugging purpose, might be removed later.
|
||||
ps = csi_mgmt_get_ps_state (msg_in);
|
||||
|
||||
csi_mgmt_create_msg (&ps_msg, MGMT_MSG_POWER_STATE, csi_mgmt_create_ps_msg(ps));
|
||||
|
||||
return bi_ep_send_message (mgmt->csi_token, ps_msg);
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
handle_power_state_ack (ep_mgmt_desc_t *mgmt, ipc_msg_t msg_in)
|
||||
{
|
||||
csi_power_state_t ps = csi_mgmt_get_ps_state (msg_in);
|
||||
|
||||
// transition to ON means the IOP is now running
|
||||
// not used in iBoot.
|
||||
if (CSI_PS_ON == ps) {
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
// if the power state is not ON quiesce built in endpoints.
|
||||
syslog_quiesce(mgmt->coproc, ps);
|
||||
console_quiesce(mgmt->coproc, ps);
|
||||
crashlog_quiesce(mgmt->coproc, ps);
|
||||
|
||||
// set the new power state
|
||||
mgmt->power_state = ps;
|
||||
mgmt->state = MGMT_QUIESCED;
|
||||
|
||||
CSI_EP_LOG(DEBUG, mgmt->coproc, mgmt->name, "IOP state changed to 0x%x (mgmt state=%x)\n", mgmt->power_state, mgmt->state);
|
||||
|
||||
// signal the power state change event
|
||||
event_signal(mgmt->ps_event);
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
validate_protocol (ep_mgmt_desc_t *mgmt, csi_protocol_version_t protocol_version)
|
||||
{
|
||||
// store the remote protocol version for future use.
|
||||
mgmt->remoteVersion = protocol_version;
|
||||
|
||||
// Validate the protocol version
|
||||
// Current version support: major has to match.
|
||||
if (APPLE_CSI_PROTOCOL_VERSION == protocol_version) {
|
||||
// valid version
|
||||
mgmt->state = MGMT_VERSION_OK;
|
||||
return CSI_STATUS_OK;
|
||||
} else {
|
||||
// unsupported version
|
||||
mgmt->state = MGMT_UNSUPPORTED_PROTOCOL_VERSION;
|
||||
return CSI_STATUS_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
bi_ep_mgmt_send_ping(csi_coproc_t which_coproc, int ping_count)
|
||||
{
|
||||
int j;
|
||||
ep_mgmt_desc_t *mgmt;
|
||||
u_int64_t cum_start_ticks;
|
||||
u_int64_t per_ping_start_ticks;
|
||||
ipc_msg_t ping_msg;
|
||||
csi_status_t status;
|
||||
|
||||
mgmt = mgmt_descs[which_coproc];
|
||||
|
||||
if (mgmt==NULL) {
|
||||
return CSI_STATUS_UNAVAILABLE;
|
||||
}
|
||||
|
||||
cum_start_ticks = timer_get_ticks();
|
||||
|
||||
for ( j=ping_count; --j>=0; ) {
|
||||
mgmt->ping_test_waiting = true;
|
||||
mgmt->ping_test_seqnum++;
|
||||
|
||||
csi_mgmt_create_msg (&ping_msg, MGMT_MSG_PING, csi_mgmt_create_ping_msg(mgmt->ping_test_seqnum, (csi_ping_timestamp_t)timer_get_ticks()));
|
||||
status = bi_ep_send_message (mgmt->csi_token, ping_msg);
|
||||
if (CSI_STATUS_OK != status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
per_ping_start_ticks = timer_get_ticks();
|
||||
|
||||
while (mgmt->ping_test_waiting) {
|
||||
if (timer_ticks_to_usecs(timer_get_ticks()-per_ping_start_ticks) >= 500000) {
|
||||
// ping ack not received within expected period
|
||||
// FixMe - expected period is warped for fastsim's notion of time
|
||||
mgmt->ping_test_waiting = false;
|
||||
return CSI_STATUS_TIMEOUT;
|
||||
}
|
||||
task_yield();
|
||||
}
|
||||
|
||||
if (csi_mgmt_get_ping_seqnum(mgmt->ping_test_ack) != mgmt->ping_test_seqnum) {
|
||||
return CSI_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ping_count == 1) {
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "ping rtt: %lld usec\n", timer_ticks_to_usecs(timer_get_ticks()-cum_start_ticks));
|
||||
} else {
|
||||
CSI_EP_LOG(CRITICAL, mgmt->coproc, mgmt->name, "%d pings cumulative rtt: %lld usec\n", ping_count, timer_ticks_to_usecs(timer_get_ticks()-cum_start_ticks));
|
||||
}
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
#include <arch.h>
|
||||
#include <debug.h>
|
||||
#include <sys/task.h>
|
||||
#include <drivers/csi.h>
|
||||
#include <drivers/a7iop/a7iop.h>
|
||||
|
||||
#include "csi_private.h"
|
||||
#include "endpoints/syslog_ep.h"
|
||||
|
||||
#include <csi_ipc_protocol.h>
|
||||
#include <csi_syslog_defines.h>
|
||||
#include <csi_syslog_protocol.h>
|
||||
|
||||
|
||||
//
|
||||
// Syslog Object
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
csi_coproc_t coproc;
|
||||
struct task_event msg_event;
|
||||
void *csi_token;
|
||||
const char *name;
|
||||
uint32_t verbosity;
|
||||
syslog_database_t *buffer;
|
||||
uint32_t allocated;
|
||||
} ep_syslog_desc_t;
|
||||
|
||||
//
|
||||
// Global Data
|
||||
//
|
||||
|
||||
static ep_syslog_desc_t *syslog_descs[CSI_COPROC_MAX] = {NULL};
|
||||
|
||||
const char* syslog_priority_names[] = SYSLOG_PRIORITY_NAMES;
|
||||
const char* syslog_facility_names[] = SYSLOG_FACILITY_NAMES;
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
int ep_syslog_task (void *arg);
|
||||
void syslog_msg_handler (ep_syslog_desc_t *syslog, msg_payload_t msg);
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_syslog_create
|
||||
//
|
||||
// Create a new syslog endpoint
|
||||
//
|
||||
void
|
||||
bi_ep_syslog_create (csi_coproc_t which_coproc)
|
||||
{
|
||||
// enforce single instance
|
||||
REQUIRE(syslog_descs[which_coproc]==NULL);
|
||||
syslog_descs[which_coproc] = malloc(sizeof(ep_syslog_desc_t));
|
||||
REQUIRE(syslog_descs[which_coproc]!=NULL);
|
||||
|
||||
syslog_descs[which_coproc]->coproc = which_coproc;
|
||||
|
||||
task_start(task_create("csi ep syslog", ep_syslog_task, syslog_descs[which_coproc], kTaskStackSize_endpoints));
|
||||
}
|
||||
|
||||
|
||||
csi_status_t
|
||||
syslog_quiesce (csi_coproc_t which_coproc, csi_power_state_t ps)
|
||||
{
|
||||
ep_syslog_desc_t *syslog = syslog_descs[which_coproc];
|
||||
|
||||
// free all shared memory if we are not preserving it
|
||||
if (!(ps & CSI_PS_SHARED_PRESERVED) && (NULL != syslog->buffer)) {
|
||||
csi_free_shared_memory(syslog->buffer);
|
||||
syslog->buffer = NULL;
|
||||
syslog->allocated = 0;
|
||||
}
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// bi_ep_syslog_verbosity
|
||||
//
|
||||
// Set the syslog endpoint verbosity
|
||||
//
|
||||
csi_status_t
|
||||
bi_ep_syslog_verbosity (csi_coproc_t which_coproc, uint32_t verbosity)
|
||||
{
|
||||
|
||||
ep_syslog_desc_t *syslog = syslog_descs[which_coproc];
|
||||
|
||||
if (syslog==NULL) {
|
||||
return CSI_STATUS_UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (verbosity > LOG_DEBUG) {
|
||||
return CSI_STATUS_ERROR;
|
||||
}
|
||||
|
||||
syslog->verbosity = verbosity;
|
||||
|
||||
return CSI_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// syslog endpoint: task
|
||||
//
|
||||
|
||||
int
|
||||
ep_syslog_task(void *arg)
|
||||
{
|
||||
csi_status_t result;
|
||||
msg_payload_t rcv_msg;
|
||||
|
||||
ep_syslog_desc_t *syslog = (ep_syslog_desc_t*)arg;
|
||||
|
||||
event_init(&syslog->msg_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
||||
|
||||
result = csi_register_endpoint(syslog->coproc, IPC_ENDPOINT_BUILT_IN_SYSLOG, &syslog->msg_event, &syslog->csi_token, &syslog->name);
|
||||
REQUIRE(result==CSI_STATUS_OK);
|
||||
|
||||
syslog->verbosity = LOG_DEFAULT;
|
||||
|
||||
syslog->buffer = NULL;
|
||||
syslog->allocated = 0;
|
||||
|
||||
for (;;) {
|
||||
event_wait(&syslog->msg_event);
|
||||
|
||||
// empty the rcv queue
|
||||
while (csi_receive_message(syslog->csi_token, &rcv_msg) == CSI_STATUS_OK) {
|
||||
syslog_msg_handler(syslog, rcv_msg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
syslog_msg_handler(ep_syslog_desc_t *syslog, msg_payload_t msg)
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint32_t entry;
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
csi_status_t status;
|
||||
|
||||
cmd = syslog_get_cmd(&msg);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case REQUEST_SYSLOGDB_BUFFER:
|
||||
|
||||
syslog->allocated = ipc_buff_msg_get_size(msg);
|
||||
REQUIRE(syslog->buffer==NULL);
|
||||
syslog->buffer = csi_allocate_shared_memory(syslog->csi_token, syslog->allocated);
|
||||
REQUIRE(syslog->buffer!=NULL);
|
||||
|
||||
// send the response back to the coproc
|
||||
uint64_t buffer_phys = mem_static_map_physical((uintptr_t)syslog->buffer);
|
||||
status = bi_ep_send_message (syslog->csi_token, syslog_construct_msg(HERE_IS_YOUR_SYSLOGDB_BUFFER, buffer_phys, ipc_buff_msg_get_size(msg)));
|
||||
if (status == CSI_STATUS_OK) {
|
||||
CSI_EP_LOG(DEBUG_SPEW, syslog->coproc, syslog->name, "buffer request of size %u bytes, allocated @ physical 0x%llx (AP %p)\n",
|
||||
syslog->allocated, buffer_phys, syslog->buffer);
|
||||
} else {
|
||||
CSI_EP_LOG(CRITICAL, syslog->coproc, syslog->name, "unable to reply to REQUEST_SYSLOGDB_BUFFER cmd.\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_SYSLOG_ENTRY:
|
||||
entry = (uint32_t)syslog_get_address(&msg);
|
||||
maybe_do_cache_operation(CACHE_INVALIDATE, &syslog->buffer->entries[entry], sizeof(syslog_entry_t));
|
||||
type = syslog->buffer->entries[entry].type;
|
||||
if (LOG_PRI(type) <= syslog->verbosity) {
|
||||
if (LOG_FAC(type) != LOG_KERN) {
|
||||
CSI_EP_LOG (SYSLOG, syslog->coproc, syslog->name, "%s: %s\n", syslog_get_facility_name(type), syslog->buffer->entries[entry].message);
|
||||
} else {
|
||||
CSI_EP_LOG (SYSLOG, syslog->coproc, syslog->name, "task #%d, file: %s: %s\n",
|
||||
syslog->buffer->entries[entry].taskid, syslog->buffer->entries[entry].filename, syslog->buffer->entries[entry].message);
|
||||
}
|
||||
}
|
||||
status = bi_ep_send_message (syslog->csi_token, syslog_construct_msg(OUTPUTTED_SYSLOG_ENTRY, entry, 0));
|
||||
break;
|
||||
|
||||
case SYSLOG_ENTRY_TRUNCATED:
|
||||
size = (uint32_t)syslog_get_address(&msg); // in this message the address field is used to report the log entry length
|
||||
CSI_EP_LOG(CRITICAL, syslog->coproc, syslog->name, "coproc tried to print a 0x%x byte message, but message buffer is only %d bytes long.\n", size, SYSLOG_MESSAGE_SIZE);
|
||||
break;
|
||||
|
||||
case SYSLOGDB_OVERFLOW:
|
||||
CSI_EP_LOG(CRITICAL, syslog->coproc, syslog->name, "coproc database overflowed.\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
CSI_EP_LOG(CRITICAL, syslog->coproc, syslog->name, "unimplemented syslog command: %x\n", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user