diff options
author | Rashmica Gupta <rashmica.g@gmail.com> | 2018-09-07 16:40:05 +1000 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2018-09-12 11:08:02 +1000 |
commit | ad9c721057cc1d116ab31383226a7822cada12a4 (patch) | |
tree | 9e06ab72607239811e7b6a3c6713f6f0b52f2079 /libpdbg | |
parent | 72825ee237f0f357a7852a96d2ced7f20309ab90 (diff) | |
download | pdbg-ad9c721057cc1d116ab31383226a7822cada12a4.tar.gz pdbg-ad9c721057cc1d116ab31383226a7822cada12a4.zip |
libpdbg: Add in getxer and putxer functions
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Diffstat (limited to 'libpdbg')
-rw-r--r-- | libpdbg/chip.c | 40 | ||||
-rw-r--r-- | libpdbg/chip.h | 24 | ||||
-rw-r--r-- | libpdbg/libpdbg.h | 4 | ||||
-rw-r--r-- | libpdbg/operations.h | 3 | ||||
-rw-r--r-- | libpdbg/p8chip.c | 86 | ||||
-rw-r--r-- | libpdbg/p9chip.c | 31 | ||||
-rw-r--r-- | libpdbg/target.h | 2 |
7 files changed, 177 insertions, 13 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c index 1c5080e..01c9b58 100644 --- a/libpdbg/chip.c +++ b/libpdbg/chip.c @@ -26,7 +26,7 @@ #include "bitutils.h" #include "debug.h" -static uint64_t mfspr(uint64_t reg, uint64_t spr) +uint64_t mfspr(uint64_t reg, uint64_t spr) { if (reg > 31) PR_ERROR("Invalid register specified for mfspr\n"); @@ -34,7 +34,7 @@ static uint64_t mfspr(uint64_t reg, uint64_t spr) return MFSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6); } -static uint64_t mtspr(uint64_t spr, uint64_t reg) +uint64_t mtspr(uint64_t spr, uint64_t reg) { if (reg > 31) PR_ERROR("Invalid register specified for mtspr\n"); @@ -148,7 +148,7 @@ int ram_sreset_thread(struct pdbg_target *thread_target) * data. Note that only register r0 is saved and restored so opcodes * must not touch other registers. */ -static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes, +int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes, uint64_t *results, int len, unsigned int lpar) { uint64_t opcode = 0, r0 = 0, r1 = 0, scratch = 0; @@ -168,6 +168,7 @@ static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes /* RAM instructions */ for (i = -2; i < len + 2; i++) { if (i == -2) + /* Save r1 (assumes opcodes don't touch other registers) */ opcode = mtspr(277, 1); else if (i == -1) /* Save r0 (assumes opcodes don't touch other registers) */ @@ -309,6 +310,31 @@ int ram_getmem(struct pdbg_target *thread, uint64_t addr, uint64_t *value) return 0; } +int ram_getxer(struct pdbg_target *thread_target, uint64_t *value) +{ + + struct thread *thread; + + assert(!strcmp(thread_target->class, "thread")); + thread = target_to_thread(thread_target); + + CHECK_ERR(thread->ram_getxer(thread_target, value)); + + return 0; +} + +int ram_putxer(struct pdbg_target *thread_target, uint64_t value) +{ + struct thread *thread; + + assert(!strcmp(thread_target->class, "thread")); + thread = target_to_thread(thread_target); + + CHECK_ERR(thread->ram_putxer(thread_target, value)); + + return 0; +} + /* * Read the given ring from the given chiplet. Result must be large enough to hold ring_len bits. */ @@ -368,12 +394,8 @@ int ram_state_thread(struct pdbg_target *thread, struct thread_regs *regs) } printf("CR : 0x%08" PRIx32 "\n", regs->cr); -#if 0 - /* TODO: Disabling because reading SPR 0x1 reliably checkstops a P8 */ - ram_getspr(thread, 0x1, &value); - regs->xer = value; - printf("XER : 0x%08" PRIx32 "\n", regs->xer); -#endif + ram_getxer(thread, ®s->xer); + printf("XER : 0x%08" PRIx64 "\n", regs->xer); printf("GPRS :\n"); for (i = 0; i < 32; i++) { diff --git a/libpdbg/chip.h b/libpdbg/chip.h new file mode 100644 index 0000000..52f3486 --- /dev/null +++ b/libpdbg/chip.h @@ -0,0 +1,24 @@ +/* Copyright 2018 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __LIBPDBG_CHIP_H +#define __LIBPDBG_CHIP_H + +uint64_t mfspr(uint64_t reg, uint64_t spr) __attribute__ ((visibility("hidden"))); +uint64_t mtspr(uint64_t spr, uint64_t reg) __attribute__ ((visibility("hidden"))); +int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes, + uint64_t *results, int len, unsigned int lpar) __attribute__ + ((visibility("hidden"))); +#endif diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h index 1008e6a..68d158c 100644 --- a/libpdbg/libpdbg.h +++ b/libpdbg/libpdbg.h @@ -107,7 +107,7 @@ struct thread_regs { uint64_t ctr; uint64_t tar; uint32_t cr; - uint32_t xer; + uint64_t xer; uint64_t gprs[32]; uint64_t lpcr; @@ -150,6 +150,8 @@ int ram_stop_thread(struct pdbg_target *target); int ram_sreset_thread(struct pdbg_target *target); int ram_state_thread(struct pdbg_target *target, struct thread_regs *regs); struct thread_state thread_status(struct pdbg_target *target); +int ram_getxer(struct pdbg_target *thread, uint64_t *value); +int ram_putxer(struct pdbg_target *thread, uint64_t value); int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]); enum pdbg_sleep_state {PDBG_THREAD_STATE_RUN, PDBG_THREAD_STATE_DOZE, diff --git a/libpdbg/operations.h b/libpdbg/operations.h index 722b53a..971a3f6 100644 --- a/libpdbg/operations.h +++ b/libpdbg/operations.h @@ -64,9 +64,10 @@ #define MFOCRF_OPCODE 0x7c100026UL #define MFSPR_MASK (MFSPR_OPCODE | ((0x1f) << 16) | ((0x3e0) << 6)) #define MFXER_OPCODE (MFSPR_OPCODE | ((1 & 0x1f) << 16) | ((1 & 0x3e0) << 6)) +#define MTXER_OPCODE (MTSPR_OPCODE | ((1 & 0x1f) << 16) | ((1 & 0x3e0) << 6)) #define LD_OPCODE 0xe8000000UL -#define MFSPR_SPR(opcode) (((opcode >> 16) & 0x1f) | ((opcode >> 6) & 0x3e0)) +#define MXSPR_SPR(opcode) (((opcode >> 16) & 0x1f) | ((opcode >> 6) & 0x3e0)) /* GDB server functionality */ int gdbserver_start(uint16_t port); diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c index cb5a46b..89ecfd6 100644 --- a/libpdbg/p8chip.c +++ b/libpdbg/p8chip.c @@ -83,9 +83,61 @@ #define EX_PM_GP0_REG 0xf0100 #define SPECIAL_WKUP_DONE PPC_BIT(31) +/* p8 specific opcodes for instruction ramming*/ +#define MTXERF0_OPCODE 0x00000008UL +#define MTXERF1_OPCODE 0x00000108UL +#define MTXERF2_OPCODE 0x00000208UL +#define MTXERF3_OPCODE 0x00000308UL +#define MFXERF0_OPCODE 0x00000010UL +#define MFXERF1_OPCODE 0x00000110UL +#define MFXERF2_OPCODE 0x00000210UL +#define MFXERF3_OPCODE 0x00000310UL + /* How long (in us) to wait for a special wakeup to complete */ #define SPECIAL_WKUP_TIMEOUT 10 +#include "chip.h" + +static uint64_t mfxerf(uint64_t reg, uint64_t field) +{ + if (reg > 31) + PR_ERROR("Invalid register specified for mfxerf\n"); + + switch (field) { + case 0: + return MFXERF0_OPCODE | (reg << 21); + case 1: + return MFXERF1_OPCODE | (reg << 21); + case 2: + return MFXERF2_OPCODE | (reg << 21); + case 3: + return MFXERF3_OPCODE | (reg << 21); + default: + PR_ERROR("Invalid XER field specified\n"); + } + return 0; +} + +static uint64_t mtxerf(uint64_t reg, uint64_t field) +{ + if (reg > 31) + PR_ERROR("Invalid register specified for mtxerf\n"); + + switch (field) { + case 0: + return MTXERF0_OPCODE | (reg << 21); + case 1: + return MTXERF1_OPCODE | (reg << 21); + case 2: + return MTXERF2_OPCODE | (reg << 21); + case 3: + return MTXERF3_OPCODE | (reg << 21); + default: + PR_ERROR("Invalid XER field specified\n"); + } + return 0; +} + static int assert_special_wakeup(struct core *chip) { int i = 0; @@ -386,6 +438,38 @@ static int p8_ram_destroy(struct thread *thread) return 0; } +static int p8_ram_getxer(struct pdbg_target *thread, uint64_t *value) +{ + uint64_t opcodes[] = {mfxerf(0, 0), mtspr(277, 0), mfxerf(0, 1), + mtspr(277, 0), mfxerf(0, 2), mtspr(277, 0), + mfxerf(0, 3), mtspr(277, 0)}; + uint64_t results[] = {0, 0, 0, 0, 0, 0, 0, 0}; + + /* On POWER8 we can't get xer with getspr. We seem to only be able to + * get and set IBM bits 32-34 and 44-56. + */ + PR_WARNING("Can only get/set IBM bits 32-34 and 44-56 of the XER register\n"); + + + CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); + + *value = results[1] | results[3] | results[5] | results[7]; + return 0; +} + +static int p8_ram_putxer(struct pdbg_target *thread, uint64_t value) +{ + uint64_t fields[] = {value, value, value, value, 0}; + uint64_t opcodes[] = {mfspr(0, 277), mtxerf(0, 0), mtxerf(0, 1), mtxerf(0, 2), mtxerf(0, 3)}; + + /* We seem to only be able to get and set IBM bits 32-34 and 44-56.*/ + PR_WARNING("Can only set IBM bits 32-34 and 44-56 of the XER register\n"); + + CHECK_ERR(ram_instructions(thread, opcodes, fields, ARRAY_SIZE(opcodes), 0)); + + return 0; +} + /* * Initialise all viable threads for ramming on the given core. */ @@ -413,6 +497,8 @@ static struct thread p8_thread = { .ram_setup = p8_ram_setup, .ram_instruction = p8_ram_instruction, .ram_destroy = p8_ram_destroy, + .ram_getxer = p8_ram_getxer, + .ram_putxer = p8_ram_putxer, }; DECLARE_HW_UNIT(p8_thread); diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c index 189d80a..f126968 100644 --- a/libpdbg/p9chip.c +++ b/libpdbg/p9chip.c @@ -292,7 +292,6 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t switch(opcode & OPCODE_MASK) { case MTNIA_OPCODE: predecode = 8; - /* Not currently supported as we can only MTNIA from LR */ PR_ERROR("MTNIA is not currently supported\n"); break; @@ -307,7 +306,18 @@ static int __p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t break; case MFSPR_OPCODE: - switch(MFSPR_SPR(opcode)) { + switch(MXSPR_SPR(opcode)) { + case 1: /* XER */ + predecode = 4; + break; + default: + predecode = 0; + break; + } + break; + + case MTSPR_OPCODE: + switch(MXSPR_SPR(opcode)) { case 1: /* XER */ predecode = 4; break; @@ -395,6 +405,21 @@ static int p9_ram_destroy(struct thread *thread) return 0; } +static int p9_ram_getxer(struct pdbg_target *thread, uint64_t *value) +{ + CHECK_ERR(ram_getspr(thread, 1, value)); + + return 0; +} + +static int p9_ram_putxer(struct pdbg_target *thread, uint64_t value) +{ + CHECK_ERR(ram_putspr(thread, 1, value)); + + return 0; + +} + static struct thread p9_thread = { .target = { .name = "POWER9 Thread", @@ -410,6 +435,8 @@ static struct thread p9_thread = { .ram_setup = p9_ram_setup, .ram_instruction = p9_ram_instruction, .ram_destroy = p9_ram_destroy, + .ram_getxer = p9_ram_getxer, + .ram_putxer = p9_ram_putxer, }; DECLARE_HW_UNIT(p9_thread); diff --git a/libpdbg/target.h b/libpdbg/target.h index 9f055ac..8bad405 100644 --- a/libpdbg/target.h +++ b/libpdbg/target.h @@ -153,6 +153,8 @@ struct thread { int (*ram_setup)(struct thread *); int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch); int (*ram_destroy)(struct thread *); + int (*ram_getxer)(struct pdbg_target *, uint64_t *value); + int (*ram_putxer)(struct pdbg_target *, uint64_t value); }; #define target_to_thread(x) container_of(x, struct thread, target) |