summaryrefslogtreecommitdiff
path: root/cesar
diff options
context:
space:
mode:
authorNicolas Schodet2010-11-16 10:54:01 +0100
committerNicolas Schodet2010-12-08 17:41:55 +0100
commit74b96133757bacc1901b40a0bb398246635a7bfe (patch)
tree6d9d78b673cac0ec1e26840a077ec8bd0b732c24 /cesar
parent4883fa5bf186a67fb8460819a69c6db4db549685 (diff)
cesar/hal/hle: add debug dump over ipmbox, closes #2062
Diffstat (limited to 'cesar')
-rw-r--r--cesar/hal/hle/Config1
-rw-r--r--cesar/hal/hle/Module4
-rw-r--r--cesar/hal/hle/defs.h7
-rw-r--r--cesar/hal/hle/doc/claudia_ipmbox.odtbin190080 -> 196207 bytes
-rw-r--r--cesar/hal/hle/inc/hal_ipmbox.h9
-rw-r--r--cesar/hal/hle/inc/ipmbox.h7
-rw-r--r--cesar/hal/hle/ipmbox.h9
-rw-r--r--cesar/hal/hle/maximus/src/maximus_ipmbox.c4
-rw-r--r--cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c2
-rw-r--r--cesar/hal/hle/src/ipmbox.c36
-rw-r--r--cesar/hal/hle/src/ipmbox_debug_dump.c111
-rw-r--r--cesar/hal/hle/test/Config1
-rw-r--r--cesar/hal/hle/test/src/hal_hle_ipmbox.c160
13 files changed, 346 insertions, 5 deletions
diff --git a/cesar/hal/hle/Config b/cesar/hal/hle/Config
new file mode 100644
index 0000000000..6e41f6bf52
--- /dev/null
+++ b/cesar/hal/hle/Config
@@ -0,0 +1 @@
+CONFIG_IPMBOX_DEBUG_DUMP = n
diff --git a/cesar/hal/hle/Module b/cesar/hal/hle/Module
index e3d78156f4..5ba71bcf93 100644
--- a/cesar/hal/hle/Module
+++ b/cesar/hal/hle/Module
@@ -1 +1,5 @@
SOURCES := hal_ipmbox.c ipmbox.c
+
+ifeq ($(CONFIG_IPMBOX_DEBUG_DUMP),y)
+SOURCES += ipmbox_debug_dump.c
+endif
diff --git a/cesar/hal/hle/defs.h b/cesar/hal/hle/defs.h
index c934d165a6..546eda230e 100644
--- a/cesar/hal/hle/defs.h
+++ b/cesar/hal/hle/defs.h
@@ -26,6 +26,8 @@
#define IPMBOX_REG__PARAM_INTERFACE_TYPE 19, 12 /* 8 bits. */
#define IPMBOX_REG__PARAM_INTERFACE_LENGTH 30, 20 /* 11 bits. */
+#define IPMBOX_REG__PARAM_DEBUG_DUMP_LENGTH 27, 12 /* 16 bits. */
+
/** Message header (32 bits). */
struct ipmbox_msg_hdr_t
{
@@ -46,8 +48,9 @@ enum hle_msg_type_t
HLE_MSG_TYPE_BUFFER_ADD = 0x01, /*< Buffer alloc message type. */
HLE_MSG_TYPE_SEND_DONE = 0x02, /*< Buffer dealloc message type. */
HLE_MSG_TYPE_INTERFACE = 0x03, /*< Interface message type. */
- HLE_MSG_TYPE_NB, /*< Number of defined message types. */
- HLE_MSG_TYPE_NONE = HLE_MSG_TYPE_NB /*< Invalid message type. */
+ HLE_MSG_TYPE_BASE_NB, /*< Number of defined base message types. */
+ HLE_MSG_TYPE_DEBUG_DUMP = 0x40, /*< Debug dump message type. */
+ HLE_MSG_TYPE_NONE = 0xff /*< Invalid message type. */
};
typedef enum hle_msg_type_t hle_msg_type_t;
diff --git a/cesar/hal/hle/doc/claudia_ipmbox.odt b/cesar/hal/hle/doc/claudia_ipmbox.odt
index 8c257be59e..760fb0bb60 100644
--- a/cesar/hal/hle/doc/claudia_ipmbox.odt
+++ b/cesar/hal/hle/doc/claudia_ipmbox.odt
Binary files differ
diff --git a/cesar/hal/hle/inc/hal_ipmbox.h b/cesar/hal/hle/inc/hal_ipmbox.h
index cd4a853edb..a04367a78b 100644
--- a/cesar/hal/hle/inc/hal_ipmbox.h
+++ b/cesar/hal/hle/inc/hal_ipmbox.h
@@ -77,6 +77,15 @@ clr_L2Aa_interrupt (void)
}
/**
+ * Read the Arm to Leon Interrupt.
+ */
+extern inline bool
+get_A2Lt_interrupt (void)
+{
+ return (A2L_IT & A2LT_MASK) ? true : false;
+}
+
+/**
* Set the Leon to Arm Interrupt.
*/
extern inline void
diff --git a/cesar/hal/hle/inc/ipmbox.h b/cesar/hal/hle/inc/ipmbox.h
index 7ad0518a85..a273a8edfa 100644
--- a/cesar/hal/hle/inc/ipmbox.h
+++ b/cesar/hal/hle/inc/ipmbox.h
@@ -102,4 +102,11 @@ struct ipmbox_t {
cyg_handle_t rx_it_handle;
};
+/**
+ * Initialise debug dump code.
+ * \param ctx ipmbox context
+ */
+void
+ipmbox_debug_dump_init (ipmbox_t *ctx);
+
#endif /* ipmbox_h */
diff --git a/cesar/hal/hle/ipmbox.h b/cesar/hal/hle/ipmbox.h
index 9507383928..e0d79c5e8d 100644
--- a/cesar/hal/hle/ipmbox.h
+++ b/cesar/hal/hle/ipmbox.h
@@ -57,6 +57,15 @@ ipmbox_uninit (ipmbox_t *ctx);
void
ipmbox_tx (ipmbox_t *ctx, u32 *first_msg, uint length);
+/**
+ * Receive message from mailbox, interrupts locked.
+ * \param ctx ipmbox context
+ * \param first_msg pointer to store first received message address
+ * \return total length (in word) of received messages
+ */
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg);
+
END_DECLS
#endif /* hal_hle_ipmbox_h */
diff --git a/cesar/hal/hle/maximus/src/maximus_ipmbox.c b/cesar/hal/hle/maximus/src/maximus_ipmbox.c
index ac2dfc2596..5f66c4bb1e 100644
--- a/cesar/hal/hle/maximus/src/maximus_ipmbox.c
+++ b/cesar/hal/hle/maximus/src/maximus_ipmbox.c
@@ -203,9 +203,9 @@ ipmbox_tx (ipmbox_t *ctx, u32 *first_msg, uint length)
else
{
ipmbox_msg_hdr_t hdr = *(ipmbox_msg_hdr_t *)first_msg;
- dbg_assert(HLE_MSG_TYPE_NB > hdr.type);
+ dbg_assert(HLE_MSG_TYPE_BASE_NB > hdr.type);
dbg_assert(1 == hdr.length);
- if ((HLE_MSG_TYPE_NB <= hdr.type)
+ if ((HLE_MSG_TYPE_BASE_NB <= hdr.type)
|| (1 != hdr.length))
{
errno = EINVAL;
diff --git a/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c b/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c
index 0fb58ada0f..98ae2f38ea 100644
--- a/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c
+++ b/cesar/hal/hle/maximus/test/src/test_maximus_ipmbox.c
@@ -150,7 +150,7 @@ void ipmbox_tx_test_case(test_t t)
errno = 0;
} test_end;
- for (hdr.type = HLE_MSG_TYPE_DATA; hdr.type < HLE_MSG_TYPE_NB; hdr.type++)
+ for (hdr.type = HLE_MSG_TYPE_DATA; hdr.type < HLE_MSG_TYPE_BASE_NB; hdr.type++)
{
/* Fill sci data. */
diff --git a/cesar/hal/hle/src/ipmbox.c b/cesar/hal/hle/src/ipmbox.c
index 002d5c9863..890b8fb9c1 100644
--- a/cesar/hal/hle/src/ipmbox.c
+++ b/cesar/hal/hle/src/ipmbox.c
@@ -20,6 +20,8 @@
#include "hal/hle/inc/ipmbox.h"
#include "hal/hle/defs.h"
+#include "config/ipmbox.h"
+
/** Rx Mailbox interrupt number */
#define MAILBOX_RX_IT_NUM CYGNUM_HAL_INTERRUPT_GIC2_14
@@ -129,6 +131,35 @@ void mailbox_rx_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t dat
A2Lt_it_enable ();
}
+#if CONFIG_IPMBOX_DEBUG_DUMP
+
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg)
+{
+ uint size;
+ /* Only if interrupt set. */
+ if (get_A2Lt_interrupt ())
+ {
+ /* Clear interrupt. */
+ clr_A2Lt_interrupt ();
+ /* Try to slurp all RX queue. */
+ size = A2L_RING_USED_WORDS (A2L_HEAD, A2L_TAIL);
+ if (size)
+ {
+ /* Copy messages out of mailbox, because callback can not handle
+ * circular buffers. */
+ halmbx_copy_from_ring (rx_msgs, size);
+ /* Return received messages. */
+ *first_msg = rx_msgs;
+ return size;
+ }
+ }
+ /* Nothing. */
+ return 0;
+}
+
+#endif /* CONFIG_IPMBOX_DEBUG_DUMP */
+
/**
* Uninitialise the HAL HLE.
* \param ctx ipmbox context
@@ -182,6 +213,11 @@ ipmbox_t * ipmbox_init (void *user_data, ipmbox_rx_cb_t rx_cb)
/* Unmask. */
cyg_drv_interrupt_unmask (MAILBOX_RX_IT_NUM);
+#if CONFIG_IPMBOX_DEBUG_DUMP
+ /* Register debug dump code. */
+ ipmbox_debug_dump_init (ctx);
+#endif
+
return ctx;
}
diff --git a/cesar/hal/hle/src/ipmbox_debug_dump.c b/cesar/hal/hle/src/ipmbox_debug_dump.c
new file mode 100644
index 0000000000..13ce329aa8
--- /dev/null
+++ b/cesar/hal/hle/src/ipmbox_debug_dump.c
@@ -0,0 +1,111 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2010 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/hle/src/ipmbox_debug_dump.c
+ * \brief Handle debug dump over mailbox.
+ * \ingroup hal_hle
+ *
+ * This implements a debug dump over the mailbox to be used for fatal error
+ * dumps.
+ *
+ * When a buffer is to be dumped, this codes reads all messages from mailbox
+ * and only process debug messages. If a message gives a debug buffer, it is
+ * filled and sent back to ARM side.
+ */
+#include "common/std.h"
+
+#include "hal/hle/ipmbox.h"
+#include "hal/hle/defs.h"
+
+/**
+ * Synchronous dump to ARM side.
+ * \param user user parameter (ipmbox context)
+ * \param text text buffer with text to write
+ * \param text_size size of text to write
+ * \return sent size
+ */
+int
+ipmbox_dump (void *user, const char *text, uint text_size)
+{
+ const u32 *msg_buffer;
+ uint msg_buffer_length;
+ const u32 *m, *mend;
+ uint msg, type;
+ u32 *buffer;
+ uint buffer_length;
+ uint dump, dumped;
+ u32 w;
+ uint wb;
+ int sent = text_size;
+ ipmbox_t *ctx = user;
+ dbg_assert (ctx);
+ /** Loop until satisfied. */
+ while (text_size)
+ {
+ /* Get mailbox content. */
+ msg_buffer = NULL;
+ msg_buffer_length = ipmbox_rx_sync (ctx, &msg_buffer);
+ m = msg_buffer;
+ mend = msg_buffer + msg_buffer_length;
+ /* Read messages. */
+ while (m != mend)
+ {
+ msg = m[0];
+ type = BF_GET (IPMBOX_REG__MSG_TYPE, msg);
+ switch (type)
+ {
+ case HLE_MSG_TYPE_DEBUG_DUMP:
+ /* Dump buffer. */
+ buffer_length =
+ BF_GET (IPMBOX_REG__PARAM_DEBUG_DUMP_LENGTH, msg);
+ buffer = (u32 *) m[1];
+ /* Fill it, little endian. */
+ dumped = dump = MIN (text_size, buffer_length);
+ for (; dump >= 4; dump -= 4)
+ {
+ w = *text++;
+ w |= *text++ << 8;
+ w |= *text++ << 16;
+ w |= *text++ << 24;
+ *buffer++ = w;
+ }
+ w = 0; wb = 0;
+ for (; dump; dump--)
+ {
+ w |= *text++ << wb;
+ wb += 8;
+ }
+ if (wb)
+ *buffer++ = w;
+ text_size -= dumped;
+ /* Send back message. */
+ u32 msg_tx[2];
+ msg_tx[0] = BF_FILL (IPMBOX_REG,
+ (MSG_TYPE, HLE_MSG_TYPE_DEBUG_DUMP),
+ (MSG_LENGTH, 1),
+ (PARAM_DEBUG_DUMP_LENGTH, dumped));
+ msg_tx[1] = m[1];
+ ipmbox_tx (ctx, msg_tx, 2);
+ break;
+ default:
+ /* Ignore message. */
+ break;
+ }
+ /* Message length + the message header. */
+ m += BF_GET (IPMBOX_REG__MSG_LENGTH, msg) + 1;
+ }
+ }
+ return sent;
+}
+
+void
+ipmbox_debug_dump_init (ipmbox_t *ctx)
+{
+ dbg_register_dump_callback (ipmbox_dump, ctx);
+}
+
diff --git a/cesar/hal/hle/test/Config b/cesar/hal/hle/test/Config
new file mode 100644
index 0000000000..d164b2c80e
--- /dev/null
+++ b/cesar/hal/hle/test/Config
@@ -0,0 +1 @@
+CONFIG_IPMBOX_DEBUG_DUMP = y
diff --git a/cesar/hal/hle/test/src/hal_hle_ipmbox.c b/cesar/hal/hle/test/src/hal_hle_ipmbox.c
index 5bd60daeb5..82532f20db 100644
--- a/cesar/hal/hle/test/src/hal_hle_ipmbox.c
+++ b/cesar/hal/hle/test/src/hal_hle_ipmbox.c
@@ -41,6 +41,9 @@ ipmbox_t *ctx;
bool dsr_posted;
+int
+ipmbox_dump (void *user, const char *text, uint text_size);
+
void my_callback(void *user_data, u32 *first_msg, uint length)
{
}
@@ -249,6 +252,161 @@ test_ipmbox_budget (void)
} test_end;
}
+void
+test_ipmbox_sync (void)
+{
+ uint i, j;
+ test_case_begin (test, "sync");
+ ctx = ipmbox_init (NULL, my_callback); /* Callback not used. */
+ utest_A2L_head = A2L_RING_BASE_ADDR;
+ utest_A2L_tail = A2L_RING_BASE_ADDR;
+ /* Read with roll-over. */
+ test_begin (test, "rollover")
+ {
+ /* Fill mailbox with a roll-over. */
+ utest_A2L_head += A2L_RING_SIZE * 3 / 4;
+ utest_A2L_tail = utest_A2L_head;
+ for (i = 0, j = A2L_RING_WORDS * 3 / 4;
+ i < A2L_RING_WORDS / 4;
+ i++, j++)
+ A2L_ring[j] = i;
+ for (j = 0;
+ i < A2L_RING_WORDS / 2;
+ i++, j++)
+ A2L_ring[j] = i;
+ utest_A2L_tail += A2L_RING_SIZE / 2;
+ /* Set interrupt. */
+ utest_A2L_it = A2LT_MASK;
+ /* Read everything. */
+ const u32 *rx_msg = NULL;
+ uint rx_msg_length;
+ rx_msg_length = ipmbox_rx_sync (ctx, &rx_msg);
+ /* Check result. */
+ test_fail_unless (rx_msg_length == A2L_RING_WORDS / 2);
+ test_fail_unless (rx_msg);
+ for (i = 0; i < rx_msg_length; i++)
+ test_fail_unless (rx_msg[i] == i);
+ } test_end;
+ /* No interrupt. */
+ test_begin (test, "no interrupt")
+ {
+ /* Read everything. */
+ const u32 *rx_msg = NULL;
+ uint rx_msg_length;
+ rx_msg_length = ipmbox_rx_sync (ctx, &rx_msg);
+ /* Check result. */
+ test_fail_unless (rx_msg_length == 0);
+ test_fail_unless (rx_msg == NULL);
+ } test_end;
+ /* Nothing to read. */
+ test_begin (test, "nothing to read")
+ {
+ /* Set interrupt. */
+ utest_A2L_it = A2LT_MASK;
+ /* Read everything. */
+ const u32 *rx_msg = NULL;
+ uint rx_msg_length;
+ rx_msg_length = ipmbox_rx_sync (ctx, &rx_msg);
+ /* Check result. */
+ test_fail_unless (rx_msg_length == 0);
+ test_fail_unless (rx_msg == NULL);
+ } test_end;
+}
+
+static void
+test_ipmbox_debug_dump_step (test_t test, uint *i, uint *n, const char *sdump,
+ const char *s1, const char *s2)
+{
+ test_within (test);
+ char buffer1[16];
+ char buffer2[16];
+ /* Fill mailbox with a debug dump message. */
+ A2L_ring[*i + 0] = 0x10140;
+ A2L_ring[*i + 1] = (u32) buffer1;
+ utest_A2L_tail += 8;
+ *n += 8;
+ if (s2)
+ {
+ A2L_ring[*i + 2] = 0x10140;
+ A2L_ring[*i + 3] = (u32) buffer2;
+ utest_A2L_tail += 8;
+ *n += 8;
+ }
+ utest_A2L_it = A2LT_MASK;
+ /* Dump. */
+ ipmbox_dump (ctx, sdump, strlen (sdump));
+ /* Check result, little endian. */
+#if DEFS_BIG_ENDIAN
+# error "test defined for little endian"
+#endif
+ test_fail_unless (utest_L2A_tail - utest_L2A_head == *n);
+ test_fail_unless (L2A_ring[*i + 0] == (0x140 | strlen (s1) << 12));
+ test_fail_unless (L2A_ring[*i + 1] == (u32) buffer1);
+ test_fail_unless (memcmp (buffer1, s1, strlen (s1)) == 0);
+ *i += 2;
+ if (s2)
+ {
+ test_fail_unless (L2A_ring[*i + 0] == (0x140 | strlen (s2) << 12));
+ test_fail_unless (L2A_ring[*i + 1] == (u32) buffer2);
+ test_fail_unless (memcmp (buffer2, s2, strlen (s2)) == 0);
+ *i += 2;
+ }
+}
+
+void
+test_ipmbox_debug_dump (void)
+{
+ uint i, n;
+ test_case_begin (test, "debug dump");
+ ctx = ipmbox_init (NULL, my_callback); /* Callback not used. */
+ utest_A2L_head = A2L_RING_BASE_ADDR;
+ utest_A2L_tail = utest_A2L_head;
+ utest_L2A_head = L2A_RING_BASE_ADDR;
+ utest_L2A_tail = utest_L2A_head;
+ i = 0;
+ n = 0;
+ /* Nothing to dump. */
+ test_begin (test, "nothing")
+ {
+ /* Dump. */
+ ipmbox_dump (ctx, "", 0);
+ /* Check result. */
+ test_fail_unless (utest_L2A_tail - utest_L2A_head == 0);
+ } test_end;
+ /* Various sizes. */
+ test_begin (test, "1 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "a", "a", NULL);
+ } test_end;
+ test_begin (test, "2 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "ba", "ba", NULL);
+ } test_end;
+ test_begin (test, "3 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "cba", "cba", NULL);
+ } test_end;
+ test_begin (test, "4 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "dcba", "dcba", NULL);
+ } test_end;
+ test_begin (test, "5 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "edcba", "edcba", NULL);
+ } test_end;
+ test_begin (test, "16 char")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "0123456789abcdef",
+ "0123456789abcdef", NULL);
+ } test_end;
+ /* Buffer overflow. */
+ test_begin (test, "17 char, buffer overflow")
+ {
+ test_ipmbox_debug_dump_step (test, &i, &n, "0123456789abcdefg",
+ "0123456789abcdef", "g");
+ } test_end;
+}
+
int main (int argc, char **argv)
{
test_init (test, argc, argv);
@@ -258,7 +416,9 @@ int main (int argc, char **argv)
test_ipmbox_tx();
test_ipmbox_irq();
test_ipmbox_budget();
+ test_ipmbox_sync();
test_ipmbox_uninit();
+ test_ipmbox_debug_dump();
test_result (test);
return test_nb_failed (test) == 0 ? 0 : 1;