From patchwork Tue Dec 18 01:08:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 1014914 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43Jg2921ZTz9s4s for ; Tue, 18 Dec 2018 12:10:57 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 43Jg2904KhzDq6q for ; Tue, 18 Dec 2018 12:10:57 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (bilbo.ozlabs.org [203.11.71.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 43JfzT0TYFzDqjx for ; Tue, 18 Dec 2018 12:08:37 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 43JfzS69y2z9s3q; Tue, 18 Dec 2018 12:08:36 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Tue, 18 Dec 2018 12:08:35 +1100 Message-Id: <20181218010835.15690-1-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 Subject: [Pdbg] [PATCH v4] adu: Add arugments for block size X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" 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 an argument to the put/getmem commands to allow a specific block size to be specified from the command line. Signed-off-by: Alistair Popple --- Changes since v1: - Fixed up comments - Removed debug code Changes since v2: - Added new adu_getmem_io and adu_putmem_io API calls instead of changing existing API. Changes since v3: - Added getmemio and putmemio command line commands instead of adding block size to existing commands. libpdbg/adu.c | 181 +++++++++++++++++++++++++++++++++++++++--------------- libpdbg/libpdbg.h | 22 +++++-- libpdbg/target.h | 4 +- src/mem.c | 37 +++++++---- src/pdbgproxy.c | 2 +- 5 files changed, 174 insertions(+), 72 deletions(-) -- 2.11.0 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/mem.c b/src/mem.c index ce099c2..cadb9c3 100644 --- a/src/mem.c +++ b/src/mem.c @@ -39,8 +39,10 @@ struct mem_flags { }; #define MEM_CI_FLAG ("--ci", ci, parse_flag_noarg, false) +#define BLOCK_SIZE (parse_number8_pow2, "8") -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 mem_flags flags) { struct pdbg_target *target; uint8_t *buf; @@ -59,14 +61,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 (flags.ci) + 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 +81,10 @@ static int getmem(uint64_t addr, uint64_t size, struct mem_flags flags) return rc; } -OPTCMD_DEFINE_CMD_WITH_FLAGS(getmem, getmem, (ADDRESS, DATA), +OPTCMD_DEFINE_CMD_WITH_FLAGS(getmem, getmem, (ADDRESS, DATA, BLOCK_SIZE), mem_flags, (MEM_CI_FLAG)); -static int putmem(uint64_t addr, struct mem_flags flags) +static int putmem(uint64_t addr, uint8_t block_size, struct mem_flags flags) { uint8_t *buf; int read_size, rc = 0; @@ -98,11 +105,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 (flags.ci) + rc = adu_putmem_io(adu_target, addr, buf, read_size, block_size); + else + rc = adu_putmem_ci(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 +124,5 @@ static int putmem(uint64_t addr, struct mem_flags flags) free(buf); return rc; } -OPTCMD_DEFINE_CMD_WITH_FLAGS(putmem, putmem, (ADDRESS), +OPTCMD_DEFINE_CMD_WITH_FLAGS(putmem, putmem, (ADDRESS, BLOCK_SIZE), mem_flags, (MEM_CI_FLAG)); diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c index dedea7a..8d9e1c8 100644 --- a/src/pdbgproxy.c +++ b/src/pdbgproxy.c @@ -223,7 +223,7 @@ static void get_mem(uint64_t *stack, void *priv) linear_map = get_real_addr(addr); if (linear_map != -1UL) { - if (adu_getmem(adu_target, linear_map, (uint8_t *) data, len)) { + if (adu_getmem(adu_target, linear_map, (uint8_t *) data, len)) { PR_ERROR("Unable to read memory\n"); err = 1; }