GDB firewire backend.
authorJoshua Oreman <oremanj@xenon.get-linux.org>
Mon, 6 Apr 2009 05:23:27 +0000 (22:23 -0700)
committerJoshua Oreman <oremanj@xenon.get-linux.org>
Mon, 6 Apr 2009 05:23:27 +0000 (22:23 -0700)
src/core/gdbfire.c [new file with mode: 0644]
src/include/gpxe/gdbfire.h [new file with mode: 0644]

diff --git a/src/core/gdbfire.c b/src/core/gdbfire.c
new file mode 100644 (file)
index 0000000..8807591
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/gdbstub.h>
+
+#define GDBFIRE_DEF_RINGSIZE   1024
+
+static struct gdbfire_comm gdbfire_link;
+
+/* Returns the new position of either head or tail after adding
+   data. */
+static inline u32 ring_add(u32 idx, u32 off, u32 size) 
+{
+       return (idx + off) & (size - 1);
+}
+
+/* Returns the number of bytes we can add without overwriting
+   unread data. */
+static inline u32 ring_space(u32 tail, u32 head, u32 size) 
+{
+       return (size - 1) - ((head - tail) & (size - 1));
+}
+
+static size_t gdbfire_recv(char *buf, size_t len) 
+{
+       struct gdbfire_comm *l = &gdbfire_link;
+       u32 rx_put, to_get;
+
+       /* Wait for the ring to be non-empty */
+       while (l->rx_get == l->rx_put)
+               ;
+
+       /* rx_put is volatile, get a value now so we're not confused. It's
+          OK if more gets written while we work. */
+       rx_put = l->rx_put;
+       to_get = rx_put - l->rx_get;
+       if (to_get > len) to_get = len;
+
+       if (to_get <= 0)
+               return 0;
+
+       memcpy(buf, l->rx_ring + l->rx_get, to_get);
+       l->rx_get = ring_add(l->rx_get, to_get, l->size);
+
+       return to_get;
+}
+
+static size_t gdbfire_send(const char *buf, size_t len)
+{
+       struct gdbfire_comm *l = &gdbfire_link;
+       u32 tx_get, to_put;
+
+       /* Wait for the ring to be non-full */
+       while (!ring_space(l->tx_get, l->tx_put, l->size))
+               ;
+
+       /* Again, save the volatile so this operation is atomic. */
+       tx_get = l->tx_get;
+       to_put = ring_space(tx_get, l->tx_put, l->size);
+       if (to_put > len) to_put = len;
+
+       if (to_put <= 0)
+               return 0;
+       
+       memcpy(l->tx_ring + l->tx_put, buf, to_put);
+       l->rx_put = ring_add(l->rx_put, to_put, l->size);
+
+       return to_put;
+}
+
+static int gdbfire_init(int argc, char **argv) 
+{
+       static int initialized = 0;
+       struct gdbfire_comm *l = &gdbfire_link;
+       int size = GDBFIRE_DEF_RINGSIZE;
+
+       if (initialized) {
+               printf("%s: already initialized; point your debugger to "
+                      "address %08X\n", l);
+               return 0;
+       }
+
+       if (argc > 1) {
+               size = atoi(argv[1]);
+               if (size & (size - 1)) {
+                       printf("%s: size must be a power of 2\n");
+                       return 1;
+               }
+       } else {
+               printf("%s: using default ring buffer size %d\n", size);
+       }
+
+       l->size = size;
+       l->rx_put = l->rx_get = 0;
+       l->tx_put = l->tx_get = 0;
+       l->rx_ring = malloc_dma(size, 8);
+       l->tx_ring = malloc_dma(size, 8);
+       l->magic = GDBFIRE_MAGIC_READY;
+
+       printf("%s: ready; point your debugger to address %08X\n", l);
+       return 0;
+}
+
+struct gdb_transport firewire_gdb_transport __gdb_transport = {
+       .name = "firewire",
+       .init = gdbfire_init,
+       .send = gdbfire_send,
+       .recv = gdbfire_recv,
+};
diff --git a/src/include/gpxe/gdbfire.h b/src/include/gpxe/gdbfire.h
new file mode 100644 (file)
index 0000000..4bd1739
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _GPXE_GDBFIRE_H
+#define _GPXE_GDBFIRE_H
+
+#include <stdint.h>
+
+/**
+ * In-memory structure used for communication over IEEE1394 DMA
+ * with a debugging host.
+ *
+ * All entries are 32-bit (we don't yet support 64-bit debugging)
+ * because the IEEE1394 controller can't write less than 4-byte
+ * increments.
+ */
+struct gdbfire_comm 
+{
+       /** Size of receive and send buffers (both the same size). */
+       u32 size;
+
+       /** Receive ring buffer (debugger writes). */
+       u8 *rx_ring;
+       /** Index of the next byte for debugger to write; this is updated
+           remotely by the debugger after it writes data. */
+       volatile u32 rx_put;
+       /** Index of the next byte for the stub to read. */
+       u32 rx_get;
+
+       /** Send ring buffer (debugger reads). */
+       u8 *tx_ring;
+       /** Index of the next byte for the stub to write. */
+       u32 tx_put;
+       /** Index of the next byte for the debugger to read; this is
+           updated remotely by the debugger after it reads data. */
+       volatile u32 tx_get;
+
+       /** Magic number. This is kept at the end to catch size
+           mismatches. Updated by the debugger when it connects. */
+#define GDBFIRE_MAGIC_READY    0x45585067 /* 'gPXE' */
+#define GDBFIRE_MAGIC_ATTACHED 0x2b424447 /* 'GDB+' */
+       volatile u32 magic;
+};
+
+#endif