diff options
Diffstat (limited to 'libpdbg/p8chip.c')
-rw-r--r-- | libpdbg/p8chip.c | 131 |
1 files changed, 128 insertions, 3 deletions
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c index cd4a50b..1202caa 100644 --- a/libpdbg/p8chip.c +++ b/libpdbg/p8chip.c @@ -29,6 +29,7 @@ #define RAS_STATUS_TIMEOUT 100 #define DIRECT_CONTROLS_REG 0x0 +#define DIRECT_CONTROL_SP_SRESET PPC_BIT(60) #define DIRECT_CONTROL_SP_STEP PPC_BIT(61) #define DIRECT_CONTROL_SP_START PPC_BIT(62) #define DIRECT_CONTROL_SP_STOP PPC_BIT(63) @@ -314,10 +315,60 @@ static int p8_thread_start(struct thread *thread) return 0; } -static int p8_thread_sreset(struct thread *thread) +static void p8_ram_unquiesce_siblings(struct thread *thread) +{ + struct pdbg_target *target; + struct core *chip = target_to_core( + pdbg_target_require_parent("core", &thread->target)); + + pdbg_for_each_compatible(&chip->target, target, "ibm,power8-thread") { + struct thread *tmp; + + if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED) + continue; + + tmp = target_to_thread(target); + if (!tmp->status.quiesced) + continue; + + if (!tmp->ram_did_quiesce) + continue; + + p8_thread_start(tmp); + + tmp->ram_did_quiesce = false; + } +} + +static int p8_ram_quiesce_siblings(struct thread *thread) { - /* Broken on p8 */ - return 1; + struct pdbg_target *target; + struct core *chip = target_to_core( + pdbg_target_require_parent("core", &thread->target)); + int rc = 0; + + pdbg_for_each_compatible(&chip->target, target, "ibm,power8-thread") { + struct thread *tmp; + + if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED) + continue; + + tmp = target_to_thread(target); + if (tmp->status.quiesced) + continue; + + rc = p8_thread_stop(tmp); + if (rc) + break; + tmp->ram_did_quiesce = true; + } + + if (!rc) + return 0; + + p8_ram_unquiesce_siblings(thread); + + return rc; } static int p8_ram_setup(struct thread *thread) @@ -458,6 +509,80 @@ static int p8_ram_putxer(struct pdbg_target *thread, uint64_t value) return 0; } +#define SPR_SRR0 0x01a +#define SPR_SRR1 0x01b + +#define HID0_HILE PPC_BIT(19) + +#define MSR_HV PPC_BIT(3) /* Hypervisor mode */ +#define MSR_EE PPC_BIT(48) /* External Int. Enable */ +#define MSR_PR PPC_BIT(49) /* Problem State */ +#define MSR_FE0 PPC_BIT(52) /* FP Exception 0 */ +#define MSR_FE1 PPC_BIT(55) /* FP Exception 1 */ +#define MSR_IR PPC_BIT(58) /* Instructions reloc */ +#define MSR_DR PPC_BIT(59) /* Data reloc */ +#define MSR_RI PPC_BIT(62) /* Recoverable Interrupt */ +#define MSR_LE PPC_BIT(63) /* Little Endian */ + +static int p8_get_hid0(struct pdbg_target *chip, uint64_t *value); +static int emulate_sreset(struct thread *thread) +{ + struct pdbg_target *chip = pdbg_target_parent("core", &thread->target); + uint64_t hid0; + uint64_t old_nia, old_msr; + uint64_t new_nia, new_msr; + + printf("emulate sreset begin\n"); + CHECK_ERR(p8_get_hid0(chip, &hid0)); + printf("emulate sreset HILE=%d\n", !!(hid0 & HID0_HILE)); + CHECK_ERR(ram_getnia(&thread->target, &old_nia)); + CHECK_ERR(ram_getmsr(&thread->target, &old_msr)); + new_nia = 0x100; + new_msr = (old_msr & ~(MSR_PR | MSR_IR | MSR_DR | MSR_FE0 | MSR_FE1 | MSR_EE | MSR_RI)) | MSR_HV; + if (hid0 & HID0_HILE) + new_msr |= MSR_LE; + else + new_msr &= ~MSR_LE; + printf("emulate sreset old NIA: 0x%016" PRIx64 " MSR: 0x%016" PRIx64 "\n", old_nia, old_msr); + printf("emulate sreset new NIA: 0x%016" PRIx64 " MSR: 0x%016" PRIx64 "\n", new_nia, new_msr); + CHECK_ERR(ram_putspr(&thread->target, SPR_SRR0, old_nia)); + CHECK_ERR(ram_putspr(&thread->target, SPR_SRR1, old_msr)); + CHECK_ERR(ram_putnia(&thread->target, new_nia)); + CHECK_ERR(ram_putmsr(&thread->target, new_msr)); + printf("emulate sreset done\n"); + + return 0; +} + +static int p8_thread_sreset(struct thread *thread) +{ + int rc; + + if (!(thread->status.active)) { + CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_SRESET)); + thread->status = get_thread_status(thread); + + return 0; + } + + rc = p8_ram_quiesce_siblings(thread); + if (rc) + return rc; + + /* Thread was active, emulate the sreset */ + rc = p8_ram_setup(thread); + if (rc) { + p8_ram_unquiesce_siblings(thread); + return rc; + } + rc = emulate_sreset(thread); + p8_ram_destroy(thread); + p8_ram_unquiesce_siblings(thread); + if (rc) + return rc; + return p8_thread_start(thread); +} + /* * Initialise all viable threads for ramming on the given core. */ |