aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/gdb/transport.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/payloads/libpayload/gdb/transport.c b/payloads/libpayload/gdb/transport.c
index 596ceb5c6d..22983e1bc0 100644
--- a/payloads/libpayload/gdb/transport.c
+++ b/payloads/libpayload/gdb/transport.c
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <endian.h>
#include <gdb.h>
#include <libpayload.h>
+/* MMIO word size is not standardized, but *usually* 32 (even on ARM64) */
+typedef u32 mmio_word_t;
+
static const int timeout_us = 100 * 1000;
static const char output_overrun[] = "GDB output buffer overrun (try "
"increasing reply.size)!\n";
@@ -55,7 +59,7 @@ void gdb_transport_teardown(void)
/* Hex digit character <-> number conversion (illegal chars undefined!). */
-static s8 from_hex(unsigned char c)
+static u8 from_hex(unsigned char c)
{
static const s8 values[] = {
-1, 10, 11, 12, 13, 14, 15, -1,
@@ -74,30 +78,43 @@ static char to_hex(u8 v)
return digits[v & 0xf];
}
-/* Message encode/decode functions */
+/* Message encode/decode functions (must access whole aligned words for MMIO) */
void gdb_message_encode_bytes(struct gdb_message *message, const void *data,
int length)
{
- const u8 *bytes = data;
die_if(message->used + length * 2 > message->size, output_overrun);
+ const mmio_word_t *aligned =
+ (mmio_word_t *)ALIGN_DOWN((uintptr_t)data, sizeof(*aligned));
+ mmio_word_t word = be32toh(readl(aligned++));
while (length--) {
- message->buf[message->used++] = to_hex(*bytes >> 4);
- message->buf[message->used++] = to_hex(*bytes & 0xf);
- bytes++;
+ u8 byte = (word >> ((((void *)aligned - data) - 1) * 8));
+ message->buf[message->used++] = to_hex(byte >> 4);
+ message->buf[message->used++] = to_hex(byte & 0xf);
+ if (length && ++data == (void *)aligned)
+ word = be32toh(readl(aligned++));
}
}
void gdb_message_decode_bytes(const struct gdb_message *message, int offset,
void *data, int length)
{
- u8 *bytes = data;
die_if(offset + 2 * length > message->used, "Decode overrun in GDB "
"message: %.*s", message->used, message->buf);
+ mmio_word_t *aligned =
+ (mmio_word_t *)ALIGN_DOWN((uintptr_t)data, sizeof(*aligned));
+ int shift = ((void *)(aligned + 1) - data) * 8;
+ mmio_word_t word = be32toh(readl(aligned)) >> shift;
while (length--) {
- *bytes = from_hex(message->buf[offset++]) << 4;
- *bytes += from_hex(message->buf[offset++]);
- bytes++;
+ word <<= 8;
+ word |= from_hex(message->buf[offset++]) << 4;
+ word |= from_hex(message->buf[offset++]);
+ if (++data - (void *)aligned == sizeof(*aligned))
+ writel(htobe32(word), aligned++);
+ }
+ if (data != (void *)aligned) {
+ shift = ((void *)(aligned + 1) - data) * 8;
+ clrsetbits_be32(aligned, ~((1 << shift) - 1), word << shift);
}
}