summaryrefslogtreecommitdiffstats
path: root/src/core/gdbstub.c
diff options
context:
space:
mode:
authorStefan Hajnoczi2008-06-05 21:07:23 +0200
committerMichael Brown2008-06-30 20:19:48 +0200
commit9ec3ff95f04d02d1cc6288608477a6c593ffe836 (patch)
tree6caf8ddf3bfad3ad0fbcb8ceffc52335e8297c66 /src/core/gdbstub.c
parent[GDB] Handle kill and detach packets. (diff)
downloadipxe-9ec3ff95f04d02d1cc6288608477a6c593ffe836.tar.gz
ipxe-9ec3ff95f04d02d1cc6288608477a6c593ffe836.tar.xz
ipxe-9ec3ff95f04d02d1cc6288608477a6c593ffe836.zip
[GDB] Atomic read/write for device memory
Diffstat (limited to 'src/core/gdbstub.c')
-rw-r--r--src/core/gdbstub.c66
1 files changed, 53 insertions, 13 deletions
diff --git a/src/core/gdbstub.c b/src/core/gdbstub.c
index 544595e6..df50dc81 100644
--- a/src/core/gdbstub.c
+++ b/src/core/gdbstub.c
@@ -27,7 +27,7 @@
#include <stddef.h>
#include <stdio.h>
#include <ctype.h>
-#include <assert.h>
+#include <byteswap.h>
#include <gpxe/process.h>
#include <gpxe/serial.h>
#include "gdbmach.h"
@@ -67,20 +67,60 @@ static uint8_t gdbstub_to_hex_digit ( uint8_t b ) {
return ( b < 0xa ? '0' : 'a' - 0xa ) + b;
}
-static void gdbstub_from_hex_buf ( char *dst, char *src, int len ) {
- while ( len-- > 0 ) {
- *dst = gdbstub_from_hex_digit ( *src++ );
- if ( len-- > 0 ) {
- *dst = (*dst << 4) | gdbstub_from_hex_digit ( *src++ );
+/*
+ * To make reading/writing device memory atomic, we check for
+ * 2- or 4-byte aligned operations and handle them specially.
+ */
+
+static void gdbstub_from_hex_buf ( char *dst, char *src, int lenbytes ) {
+ if ( lenbytes == 2 && ( ( unsigned long ) dst & 0x1 ) == 0 ) {
+ uint16_t i = gdbstub_from_hex_digit ( src [ 2 ] ) << 12 |
+ gdbstub_from_hex_digit ( src [ 3 ] ) << 8 |
+ gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+ gdbstub_from_hex_digit ( src [ 1 ] );
+ * ( uint16_t * ) dst = cpu_to_le16 ( i );
+ } else if ( lenbytes == 4 && ( ( unsigned long ) dst & 0x3 ) == 0 ) {
+ uint32_t i = gdbstub_from_hex_digit ( src [ 6 ] ) << 28 |
+ gdbstub_from_hex_digit ( src [ 7 ] ) << 24 |
+ gdbstub_from_hex_digit ( src [ 4 ] ) << 20 |
+ gdbstub_from_hex_digit ( src [ 5 ] ) << 16 |
+ gdbstub_from_hex_digit ( src [ 2 ] ) << 12 |
+ gdbstub_from_hex_digit ( src [ 3 ] ) << 8 |
+ gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+ gdbstub_from_hex_digit ( src [ 1 ] );
+ * ( uint32_t * ) dst = cpu_to_le32 ( i );
+ } else {
+ while ( lenbytes-- > 0 ) {
+ *dst++ = gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+ gdbstub_from_hex_digit ( src [ 1 ] );
+ src += 2;
}
- dst++;
}
}
-static void gdbstub_to_hex_buf ( char *dst, char *src, int len ) {
- while ( len-- > 0 ) {
- *dst++ = gdbstub_to_hex_digit ( *src >> 4 );
- *dst++ = gdbstub_to_hex_digit ( *src++ );
+static void gdbstub_to_hex_buf ( char *dst, char *src, int lenbytes ) {
+ if ( lenbytes == 2 && ( ( unsigned long ) src & 0x1 ) == 0 ) {
+ uint16_t i = cpu_to_le16 ( * ( uint16_t * ) src );
+ dst [ 0 ] = gdbstub_to_hex_digit ( i >> 4 );
+ dst [ 1 ] = gdbstub_to_hex_digit ( i );
+ dst [ 2 ] = gdbstub_to_hex_digit ( i >> 12 );
+ dst [ 3 ] = gdbstub_to_hex_digit ( i >> 8 );
+ } else if ( lenbytes == 4 && ( ( unsigned long ) src & 0x3 ) == 0 ) {
+ uint32_t i = cpu_to_le32 ( * ( uint32_t * ) src );
+ dst [ 0 ] = gdbstub_to_hex_digit ( i >> 4 );
+ dst [ 1 ] = gdbstub_to_hex_digit ( i );
+ dst [ 2 ] = gdbstub_to_hex_digit ( i >> 12 );
+ dst [ 3 ] = gdbstub_to_hex_digit ( i >> 8 );
+ dst [ 4 ] = gdbstub_to_hex_digit ( i >> 20 );
+ dst [ 5 ] = gdbstub_to_hex_digit ( i >> 16);
+ dst [ 6 ] = gdbstub_to_hex_digit ( i >> 28 );
+ dst [ 7 ] = gdbstub_to_hex_digit ( i >> 24 );
+ } else {
+ while ( lenbytes-- > 0 ) {
+ *dst++ = gdbstub_to_hex_digit ( *src >> 4 );
+ *dst++ = gdbstub_to_hex_digit ( *src );
+ src++;
+ }
}
}
@@ -179,7 +219,7 @@ static void gdbstub_write_regs ( struct gdbstub *stub ) {
gdbstub_send_errno ( stub, POSIX_EINVAL );
return;
}
- gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], stub->len );
+ gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], GDBMACH_SIZEOF_REGS );
gdbstub_send_ok ( stub );
}
@@ -204,7 +244,7 @@ static void gdbstub_write_mem ( struct gdbstub *stub ) {
gdbstub_send_errno ( stub, POSIX_EINVAL );
return;
}
- gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], stub->len - colon - 1 );
+ gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], ( stub->len - colon - 1 ) / 2 );
gdbstub_send_ok ( stub );
}