iBoot/drivers/apple/csi/endpoints/syslog_ep.c

213 lines
5.8 KiB
C

/*
* 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;
}
}