first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+55
View File
@@ -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;
}
+237
View File
@@ -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;
}
}
+666
View File
@@ -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;
}
+362
View File
@@ -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;
}
+212
View File
@@ -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;
}
}