summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2018-11-07 13:49:50 +1100
committerAlistair Popple <alistair@popple.id.au>2018-12-18 18:31:34 +1100
commit302f249d95f03fbd039b5bb80ee6ba42593fccbe (patch)
treec9b9f91728003a0582b92badbd37cd36330ded2c
parente09316fbf5ab120f147703b420bfe58518985601 (diff)
downloadpdbg-302f249d95f03fbd039b5bb80ee6ba42593fccbe.tar.gz
pdbg-302f249d95f03fbd039b5bb80ee6ba42593fccbe.zip
adu: Add arugments for block size
Not all memory can be read with the default ADU block size of 8 bytes. Specifically cache-inhibited access to some MMIO regions such as PCIe BAR spaces requires 4 byte accesses to avoid check stopping the machine. This patch adds library functions to read/write IO memory which takes a block size argument and two new put/getmemio commands to allow a specific block size to be specified from the command line. Signed-off-by: Alistair Popple <alistair@popple.id.au> Reviewed-by: Amitay Isaacs <amitay@ozlabs.org>
-rw-r--r--libpdbg/adu.c181
-rw-r--r--libpdbg/libpdbg.h22
-rw-r--r--libpdbg/target.h4
-rw-r--r--src/main.c12
-rw-r--r--src/mem.c63
5 files changed, 207 insertions, 75 deletions
diff --git a/libpdbg/adu.c b/libpdbg/adu.c
index b67a43e..5cb1373 100644
--- a/libpdbg/adu.c
+++ b/libpdbg/adu.c
@@ -84,20 +84,34 @@
#define FBC_ALTD_DATA_DONE PPC_BIT(3)
#define FBC_ALTD_PBINIT_MISSING PPC_BIT(18)
-int adu_getmem(struct pdbg_target *adu_target, uint64_t start_addr,
- uint8_t *output, uint64_t size)
-{
- return __adu_getmem(adu_target, start_addr, output, size, false);
-}
-
-int adu_getmem_ci(struct pdbg_target *adu_target, uint64_t start_addr,
- uint8_t *output, uint64_t size)
+/* There are more general implementations of this with a loop and more
+ * performant implementations using GCC builtins which aren't
+ * portable. Given we only need a limited domain this is quick, easy
+ * and portable. */
+uint8_t blog2(uint8_t x)
{
- return __adu_getmem(adu_target, start_addr, output, size, true);
+ switch(x) {
+ case 1:
+ return 0;
+ case 2:
+ return 1;
+ case 4:
+ return 2;
+ case 8:
+ return 3;
+ case 16:
+ return 4;
+ case 32:
+ return 5;
+ case 64:
+ return 6;
+ default:
+ assert(0);
+ }
}
-int __adu_getmem(struct pdbg_target *adu_target, uint64_t start_addr,
- uint8_t *output, uint64_t size, bool ci)
+static int __adu_getmem_blocksize(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *output, uint64_t size, uint8_t block_size, bool ci)
{
struct adu *adu;
uint8_t *output0;
@@ -109,33 +123,34 @@ int __adu_getmem(struct pdbg_target *adu_target, uint64_t start_addr,
output0 = output;
- /* Align start address to 8-byte boundary */
- addr0 = 8 * (start_addr / 8);
+ /* Align start address to block_sized boundary */
+ addr0 = block_size * (start_addr / block_size);
- /* We read data in 8-byte aligned chunks */
- for (addr = addr0; addr < start_addr + size; addr += 8) {
+ /* We read data in block_sized aligned chunks */
+ for (addr = addr0; addr < start_addr + size; addr += block_size) {
uint64_t data;
- if (adu->getmem(adu, addr, &data, ci))
+ if (adu->getmem(adu, addr, &data, ci, block_size))
return -1;
- /* ADU returns data in big-endian form in the register */
+ /* ADU returns data in big-endian form in the register. */
data = __builtin_bswap64(data);
+ data >>= (addr & 0x7ull)*8;
if (addr < start_addr) {
size_t offset = start_addr - addr;
- size_t n = (size <= 8-offset ? size : 8-offset);
+ size_t n = (size <= block_size-offset ? size : block_size-offset);
memcpy(output, ((uint8_t *) &data) + offset, n);
output += n;
- } else if (addr + 8 > start_addr + size) {
+ } else if (addr + block_size > start_addr + size) {
uint64_t offset = start_addr + size - addr;
memcpy(output, &data, offset);
output += offset;
} else {
- memcpy(output, &data, 8);
- output += 8;
+ memcpy(output, &data, block_size);
+ output += block_size;
}
pdbg_progress_tick(output - output0, size);
@@ -146,20 +161,37 @@ int __adu_getmem(struct pdbg_target *adu_target, uint64_t start_addr,
return rc;
}
-int adu_putmem(struct pdbg_target *adu_target, uint64_t start_addr,
+int adu_getmem(struct pdbg_target *adu_target, uint64_t start_addr,
uint8_t *output, uint64_t size)
{
- return __adu_putmem(adu_target, start_addr, output, size, false);
+ return __adu_getmem_blocksize(adu_target, start_addr, output,
+ size, 8, false);
}
-int adu_putmem_ci(struct pdbg_target *adu_target, uint64_t start_addr,
+int adu_getmem_ci(struct pdbg_target *adu_target, uint64_t start_addr,
uint8_t *output, uint64_t size)
{
- return __adu_putmem(adu_target, start_addr, output, size, true);
+ return __adu_getmem_blocksize(adu_target, start_addr, output,
+ size, 8, true);
}
-int __adu_putmem(struct pdbg_target *adu_target, uint64_t start_addr,
- uint8_t *input, uint64_t size, bool ci)
+int adu_getmem_io(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *output, uint64_t size, uint8_t blocksize)
+{
+ /* There is no equivalent for cachable memory as blocksize
+ * does not apply to cachable reads */
+ return __adu_getmem_blocksize(adu_target, start_addr, output,
+ size, blocksize, true);
+}
+
+int __adu_getmem(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *output, uint64_t size, bool ci)
+{
+ return __adu_getmem_blocksize(adu_target, start_addr, output,
+ size, 8, ci);
+}
+static int __adu_putmem_blocksize(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *input, uint64_t size, uint8_t block_size, bool ci)
{
struct adu *adu;
int rc = 0, tsize;
@@ -169,20 +201,25 @@ int __adu_putmem(struct pdbg_target *adu_target, uint64_t start_addr,
adu = target_to_adu(adu_target);
end_addr = start_addr + size;
for (addr = start_addr; addr < end_addr; addr += tsize, input += tsize) {
- if ((addr % 8) || (addr + 8 > end_addr)) {
- /* If the address is not 64-bit aligned we
- * copy in a byte at a time until it is. */
+ if ((addr % block_size) || (addr + block_size > end_addr)) {
+ /* If the address is not aligned to block_size
+ * we copy the data in one byte at a time
+ * until it is aligned. */
tsize = 1;
- /* Copy the input data in with correct alignment */
+ /* Copy the input data in with correct
+ * alignment. Bytes need to aligned to the
+ * correct byte offset in the data register
+ * regardless of address. */
data = ((uint64_t) *input) << 8*(8 - (addr % 8) - 1);
} else {
- tsize = 8;
- memcpy(&data, input, sizeof(data));
+ tsize = block_size;
+ memcpy(&data, input, block_size);
data = __builtin_bswap64(data);
+ data >>= (addr & 7ull)*8;
}
- adu->putmem(adu, addr, data, tsize, ci);
+ adu->putmem(adu, addr, data, tsize, ci, block_size);
pdbg_progress_tick(addr - start_addr, size);
}
@@ -191,6 +228,30 @@ int __adu_putmem(struct pdbg_target *adu_target, uint64_t start_addr,
return rc;
}
+int adu_putmem(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *input, uint64_t size)
+{
+ return __adu_putmem_blocksize(adu_target, start_addr, input, size, 8, false);
+}
+
+int adu_putmem_ci(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *input, uint64_t size)
+{
+ return __adu_putmem_blocksize(adu_target, start_addr, input, size, 8, true);
+}
+
+int adu_putmem_io(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *input, uint64_t size, uint8_t block_size)
+{
+ return __adu_putmem_blocksize(adu_target, start_addr, input, size, block_size, true);
+}
+
+int __adu_putmem(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *input, uint64_t size, bool ci)
+{
+ return __adu_putmem_blocksize(adu_target, start_addr, input, size, 8, ci);
+}
+
static int adu_lock(struct adu *adu)
{
uint64_t val;
@@ -234,7 +295,8 @@ static int adu_reset(struct adu *adu)
return 0;
}
-static int p8_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data, int ci)
+static int p8_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data,
+ int ci, uint8_t block_size)
{
uint64_t ctrl_reg, cmd_reg, val;
int rc = 0;
@@ -242,12 +304,15 @@ static int p8_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data, int ci)
CHECK_ERR(adu_lock(adu));
ctrl_reg = P8_TTYPE_TREAD;
- if (ci)
+ if (ci) {
/* Do cache inhibited access */
ctrl_reg = SETFIELD(P8_FBC_ALTD_TTYPE, ctrl_reg, P8_TTYPE_CI_PARTIAL_READ);
- else
+ block_size = (blog2(block_size) + 1) << 1;
+ } else {
ctrl_reg = SETFIELD(P8_FBC_ALTD_TTYPE, ctrl_reg, P8_TTYPE_DMA_PARTIAL_READ);
- ctrl_reg = SETFIELD(P8_FBC_ALTD_TSIZE, ctrl_reg, 8);
+ block_size = 0;
+ }
+ ctrl_reg = SETFIELD(P8_FBC_ALTD_TSIZE, ctrl_reg, block_size);
CHECK_ERR_GOTO(out, rc = pib_read(&adu->target, P8_ALTD_CMD_REG, &cmd_reg));
cmd_reg |= FBC_ALTD_START_OP;
@@ -292,19 +357,23 @@ out:
}
-int p8_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size, int ci)
+int p8_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size,
+ int ci, uint8_t block_size)
{
int rc = 0;
uint64_t cmd_reg, ctrl_reg, val;
CHECK_ERR(adu_lock(adu));
ctrl_reg = P8_TTYPE_TWRITE;
- if (ci)
+ if (ci) {
/* Do cache inhibited access */
ctrl_reg = SETFIELD(P8_FBC_ALTD_TTYPE, ctrl_reg, P8_TTYPE_CI_PARTIAL_WRITE);
- else
+ block_size = (blog2(block_size) + 1) << 1;
+ } else {
ctrl_reg = SETFIELD(P8_FBC_ALTD_TTYPE, ctrl_reg, P8_TTYPE_DMA_PARTIAL_WRITE);
- ctrl_reg = SETFIELD(P8_FBC_ALTD_TSIZE, ctrl_reg, size);
+ block_size <<= 1;
+ }
+ ctrl_reg = SETFIELD(P8_FBC_ALTD_TSIZE, ctrl_reg, block_size);
CHECK_ERR_GOTO(out, rc = pib_read(&adu->target, P8_ALTD_CMD_REG, &cmd_reg));
cmd_reg |= FBC_ALTD_START_OP;
@@ -349,19 +418,25 @@ out:
return rc;
}
-static int p9_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data, int ci)
+static int p9_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data,
+ int ci, uint8_t block_size)
{
uint64_t ctrl_reg, cmd_reg, val;
cmd_reg = P9_TTYPE_TREAD;
- if (ci)
+ if (ci) {
/* Do cache inhibited access */
cmd_reg = SETFIELD(P9_FBC_ALTD_TTYPE, cmd_reg, P9_TTYPE_CI_PARTIAL_READ);
- else
+ block_size = (blog2(block_size) + 1) << 1;
+ } else {
cmd_reg = SETFIELD(P9_FBC_ALTD_TTYPE, cmd_reg, P9_TTYPE_DMA_PARTIAL_READ);
- /* For a read size is apparently always 0 */
- cmd_reg = SETFIELD(P9_FBC_ALTD_TSIZE, cmd_reg, 0);
+ /* For normal reads the size is ignored as HW always
+ * returns a cache line */
+ block_size = 0;
+ }
+
+ cmd_reg = SETFIELD(P9_FBC_ALTD_TSIZE, cmd_reg, block_size);
cmd_reg |= FBC_ALTD_START_OP;
cmd_reg = SETFIELD(FBC_ALTD_SCOPE, cmd_reg, SCOPE_REMOTE);
cmd_reg = SETFIELD(FBC_ALTD_DROP_PRIORITY, cmd_reg, DROP_PRIORITY_LOW);
@@ -400,7 +475,8 @@ retry:
return 0;
}
-static int p9_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size, int ci)
+static int p9_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size,
+ int ci, uint8_t block_size)
{
uint64_t ctrl_reg, cmd_reg, val;
@@ -409,12 +485,15 @@ static int p9_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size
size <<= 1;
cmd_reg = P9_TTYPE_TWRITE;
- if (ci)
+ if (ci) {
/* Do cache inhibited access */
cmd_reg = SETFIELD(P9_FBC_ALTD_TTYPE, cmd_reg, P9_TTYPE_CI_PARTIAL_WRITE);
- else
+ block_size = (blog2(block_size) + 1) << 1;
+ } else {
cmd_reg = SETFIELD(P9_FBC_ALTD_TTYPE, cmd_reg, P9_TTYPE_DMA_PARTIAL_WRITE);
- cmd_reg = SETFIELD(P9_FBC_ALTD_TSIZE, cmd_reg, size);
+ block_size <<= 1;
+ }
+ cmd_reg = SETFIELD(P9_FBC_ALTD_TSIZE, cmd_reg, block_size);
cmd_reg |= FBC_ALTD_START_OP;
cmd_reg = SETFIELD(FBC_ALTD_SCOPE, cmd_reg, SCOPE_REMOTE);
cmd_reg = SETFIELD(FBC_ALTD_DROP_PRIORITY, cmd_reg, DROP_PRIORITY_LOW);
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index 301c2c8..ee8437f 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -204,12 +204,22 @@ int htm_status(struct pdbg_target *target);
int htm_dump(struct pdbg_target *target, char *filename);
int htm_record(struct pdbg_target *target, char *filename);
-int adu_getmem(struct pdbg_target *target, uint64_t addr, uint8_t *ouput, uint64_t size);
-int adu_putmem(struct pdbg_target *target, uint64_t addr, uint8_t *input, uint64_t size);
-int adu_getmem_ci(struct pdbg_target *target, uint64_t addr, uint8_t *ouput, uint64_t size);
-int adu_putmem_ci(struct pdbg_target *target, uint64_t addr, uint8_t *input, uint64_t size);
-int __adu_getmem(struct pdbg_target *target, uint64_t addr, uint8_t *ouput, uint64_t size, bool ci);
-int __adu_putmem(struct pdbg_target *target, uint64_t addr, uint8_t *input, uint64_t size, bool ci);
+int adu_getmem(struct pdbg_target *target, uint64_t addr,
+ uint8_t *ouput, uint64_t size);
+int adu_putmem(struct pdbg_target *target, uint64_t addr,
+ uint8_t *input, uint64_t size);
+int adu_getmem_ci(struct pdbg_target *target, uint64_t addr,
+ uint8_t *ouput, uint64_t size);
+int adu_putmem_ci(struct pdbg_target *target, uint64_t addr,
+ uint8_t *input, uint64_t size);
+int adu_getmem_io(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *output, uint64_t size, uint8_t blocksize);
+int adu_putmem_io(struct pdbg_target *adu_target, uint64_t start_addr,
+ uint8_t *input, uint64_t size, uint8_t block_size);
+int __adu_getmem(struct pdbg_target *target, uint64_t addr, uint8_t *ouput,
+ uint64_t size, bool ci);
+int __adu_putmem(struct pdbg_target *target, uint64_t addr, uint8_t *input,
+ uint64_t size, bool ci);
int opb_read(struct pdbg_target *target, uint32_t addr, uint32_t *data);
int opb_write(struct pdbg_target *target, uint32_t addr, uint32_t data);
diff --git a/libpdbg/target.h b/libpdbg/target.h
index 7cc855d..16ae304 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -107,8 +107,8 @@ struct htm {
struct adu {
struct pdbg_target target;
- int (*getmem)(struct adu *, uint64_t, uint64_t *, int);
- int (*putmem)(struct adu *, uint64_t, uint64_t, int, int);
+ int (*getmem)(struct adu *, uint64_t, uint64_t *, int, uint8_t);
+ int (*putmem)(struct adu *, uint64_t, uint64_t, int, int, uint8_t);
};
#define target_to_adu(x) container_of(x, struct adu, target)
diff --git a/src/main.c b/src/main.c
index 1f68fa8..22e74a5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -91,8 +91,9 @@ extern struct optcmd_cmd
optcmd_getnia, optcmd_putnia, optcmd_getmsr, optcmd_putmsr,
optcmd_getring, optcmd_start, optcmd_stop, optcmd_step,
optcmd_threadstatus, optcmd_sreset, optcmd_regs, optcmd_probe,
- optcmd_getmem, optcmd_putmem, optcmd_getxer, optcmd_putxer,
- optcmd_getcr, optcmd_putcr, optcmd_gdbserver;
+ optcmd_getmem, optcmd_putmem, optcmd_getmemio, optcmd_putmemio,
+ optcmd_getxer, optcmd_putxer, optcmd_getcr, optcmd_putcr,
+ optcmd_gdbserver;
static struct optcmd_cmd *cmds[] = {
&optcmd_getscom, &optcmd_putscom, &optcmd_getcfam, &optcmd_putcfam,
@@ -100,8 +101,9 @@ static struct optcmd_cmd *cmds[] = {
&optcmd_getnia, &optcmd_putnia, &optcmd_getmsr, &optcmd_putmsr,
&optcmd_getring, &optcmd_start, &optcmd_stop, &optcmd_step,
&optcmd_threadstatus, &optcmd_sreset, &optcmd_regs, &optcmd_probe,
- &optcmd_getmem, &optcmd_putmem, &optcmd_getxer, &optcmd_putxer,
- &optcmd_getcr, &optcmd_putcr, &optcmd_gdbserver,
+ &optcmd_getmem, &optcmd_putmem, &optcmd_getmemio, &optcmd_putmemio,
+ &optcmd_getxer, &optcmd_putxer, &optcmd_getcr, &optcmd_putcr,
+ &optcmd_gdbserver,
};
/* Purely for printing usage text. We could integrate printing argument and flag
@@ -136,7 +138,9 @@ static struct action actions[] = {
{ "getscom", "<address>", "Read system scom" },
{ "putscom", "<address> <value> [<mask>]", "Write system scom" },
{ "getmem", "<address> <count>", "Read system memory" },
+ { "getmemio", "<address> <count> <block size>", "Read memory cache inhibited with specified transfer size" },
{ "putmem", "<address>", "Write to system memory" },
+ { "putmemio", "<address> <block size>", "Write system memory cache inhibited with specified transfer size" },
{ "threadstatus", "", "Print the status of a thread" },
{ "sreset", "", "Reset" },
{ "regs", "[--backtrace]", "State (optionally display backtrace)" },
diff --git a/src/mem.c b/src/mem.c
index ce099c2..6454739 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -39,8 +39,9 @@ struct mem_flags {
};
#define MEM_CI_FLAG ("--ci", ci, parse_flag_noarg, false)
+#define BLOCK_SIZE (parse_number8_pow2, NULL)
-static int getmem(uint64_t addr, uint64_t size, struct mem_flags flags)
+static int _getmem(uint64_t addr, uint64_t size, uint8_t block_size)
{
struct pdbg_target *target;
uint8_t *buf;
@@ -59,14 +60,19 @@ static int getmem(uint64_t addr, uint64_t size, struct mem_flags flags)
pdbg_set_progress_tick(progress_tick);
progress_init();
- if (!__adu_getmem(target, addr, buf, size, flags.ci)) {
- if (write(STDOUT_FILENO, buf, size) < 0)
- PR_ERROR("Unable to write stdout.\n");
- else
- rc++;
- } else
+ if (block_size)
+ rc = adu_getmem_io(target, addr, buf, size, block_size);
+ else
+ rc = adu_getmem(target, addr, buf, size);
+
+ if (rc)
PR_ERROR("Unable to read memory.\n");
- /* We only ever care about getting memory from a single processor */
+
+ if (write(STDOUT_FILENO, buf, size) < 0)
+ PR_ERROR("Unable to write stdout.\n");
+ else
+ rc++;
+
progress_end();
break;
}
@@ -74,10 +80,24 @@ static int getmem(uint64_t addr, uint64_t size, struct mem_flags flags)
return rc;
}
+
+static int getmem(uint64_t addr, uint64_t size, struct mem_flags flags)
+{
+ if (flags.ci)
+ return _getmem(addr, size, 8);
+ else
+ return _getmem(addr, size, 0);
+}
OPTCMD_DEFINE_CMD_WITH_FLAGS(getmem, getmem, (ADDRESS, DATA),
mem_flags, (MEM_CI_FLAG));
-static int putmem(uint64_t addr, struct mem_flags flags)
+static int getmemio(uint64_t addr, uint64_t size, uint8_t block_size)
+{
+ return _getmem(addr, size, block_size);
+}
+OPTCMD_DEFINE_CMD_WITH_ARGS(getmemio, getmemio, (ADDRESS, DATA, BLOCK_SIZE));
+
+static int _putmem(uint64_t addr, uint8_t block_size)
{
uint8_t *buf;
int read_size, rc = 0;
@@ -98,11 +118,17 @@ static int putmem(uint64_t addr, struct mem_flags flags)
if (read_size <= 0)
break;
- if (__adu_putmem(adu_target, addr, buf, read_size, flags.ci)) {
+ if (block_size)
+ rc = adu_putmem_io(adu_target, addr, buf, read_size, block_size);
+ else
+ rc = adu_putmem(adu_target, addr, buf, read_size);
+
+ if (rc) {
rc = 0;
printf("Unable to write memory.\n");
break;
}
+
rc += read_size;
} while (read_size > 0);
progress_end();
@@ -111,5 +137,18 @@ static int putmem(uint64_t addr, struct mem_flags flags)
free(buf);
return rc;
}
-OPTCMD_DEFINE_CMD_WITH_FLAGS(putmem, putmem, (ADDRESS),
- mem_flags, (MEM_CI_FLAG));
+
+static int putmem(uint64_t addr, struct mem_flags flags)
+{
+ if (flags.ci)
+ return _putmem(addr, 8);
+ else
+ return _putmem(addr, 0);
+}
+OPTCMD_DEFINE_CMD_WITH_FLAGS(putmem, putmem, (ADDRESS), mem_flags, (MEM_CI_FLAG));
+
+static int putmemio(uint64_t addr, uint8_t block_size)
+{
+ return _putmem(addr, block_size);
+}
+OPTCMD_DEFINE_CMD_WITH_ARGS(putmemio, putmemio, (ADDRESS, BLOCK_SIZE));
OpenPOWER on IntegriCloud