Merge remote-tracking branch 'remotes/powerpc/topic/ppc-kvm' into kvm-ppc-next
This merges in the ppc-kvm topic branch from the powerpc tree to get patches which touch both general powerpc code and KVM code, one of which is a prerequisite for following patches. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
commit
a878957a81
|
@ -56,3 +56,35 @@ POWER9. Loads and stores to the watchpoint locations will not be
|
|||
trapped in GDB. The watchpoint is remembered, so if the guest is
|
||||
migrated back to the POWER8 host, it will start working again.
|
||||
|
||||
Force enabling the DAWR
|
||||
=============================
|
||||
Kernels (since ~v5.2) have an option to force enable the DAWR via:
|
||||
|
||||
echo Y > /sys/kernel/debug/powerpc/dawr_enable_dangerous
|
||||
|
||||
This enables the DAWR even on POWER9.
|
||||
|
||||
This is a dangerous setting, USE AT YOUR OWN RISK.
|
||||
|
||||
Some users may not care about a bad user crashing their box
|
||||
(ie. single user/desktop systems) and really want the DAWR. This
|
||||
allows them to force enable DAWR.
|
||||
|
||||
This flag can also be used to disable DAWR access. Once this is
|
||||
cleared, all DAWR access should be cleared immediately and your
|
||||
machine once again safe from crashing.
|
||||
|
||||
Userspace may get confused by toggling this. If DAWR is force
|
||||
enabled/disabled between getting the number of breakpoints (via
|
||||
PTRACE_GETHWDBGINFO) and setting the breakpoint, userspace will get an
|
||||
inconsistent view of what's available. Similarly for guests.
|
||||
|
||||
For the DAWR to be enabled in a KVM guest, the DAWR needs to be force
|
||||
enabled in the host AND the guest. For this reason, this won't work on
|
||||
POWERVM as it doesn't allow the HCALL to work. Writes of 'Y' to the
|
||||
dawr_enable_dangerous file will fail if the hypervisor doesn't support
|
||||
writing the DAWR.
|
||||
|
||||
To double check the DAWR is working, run this kernel selftest:
|
||||
tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c
|
||||
Any errors/failures/skips mean something is wrong.
|
||||
|
|
|
@ -90,10 +90,18 @@ static inline void hw_breakpoint_disable(void)
|
|||
extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
|
||||
int hw_breakpoint_handler(struct die_args *args);
|
||||
|
||||
extern int set_dawr(struct arch_hw_breakpoint *brk);
|
||||
extern bool dawr_force_enable;
|
||||
static inline bool dawr_enabled(void)
|
||||
{
|
||||
return dawr_force_enable;
|
||||
}
|
||||
|
||||
#else /* CONFIG_HAVE_HW_BREAKPOINT */
|
||||
static inline void hw_breakpoint_disable(void) { }
|
||||
static inline void thread_change_pc(struct task_struct *tsk,
|
||||
struct pt_regs *regs) { }
|
||||
static inline bool dawr_enabled(void) { return false; }
|
||||
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
|
||||
|
|
|
@ -186,8 +186,8 @@
|
|||
#define OPAL_XIVE_FREE_IRQ 140
|
||||
#define OPAL_XIVE_SYNC 141
|
||||
#define OPAL_XIVE_DUMP 142
|
||||
#define OPAL_XIVE_RESERVED3 143
|
||||
#define OPAL_XIVE_RESERVED4 144
|
||||
#define OPAL_XIVE_GET_QUEUE_STATE 143
|
||||
#define OPAL_XIVE_SET_QUEUE_STATE 144
|
||||
#define OPAL_SIGNAL_SYSTEM_RESET 145
|
||||
#define OPAL_NPU_INIT_CONTEXT 146
|
||||
#define OPAL_NPU_DESTROY_CONTEXT 147
|
||||
|
@ -210,7 +210,8 @@
|
|||
#define OPAL_PCI_GET_PBCQ_TUNNEL_BAR 164
|
||||
#define OPAL_PCI_SET_PBCQ_TUNNEL_BAR 165
|
||||
#define OPAL_NX_COPROC_INIT 167
|
||||
#define OPAL_LAST 167
|
||||
#define OPAL_XIVE_GET_VP_STATE 170
|
||||
#define OPAL_LAST 170
|
||||
|
||||
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
|
||||
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
|
||||
|
|
|
@ -279,6 +279,13 @@ int64_t opal_xive_allocate_irq(uint32_t chip_id);
|
|||
int64_t opal_xive_free_irq(uint32_t girq);
|
||||
int64_t opal_xive_sync(uint32_t type, uint32_t id);
|
||||
int64_t opal_xive_dump(uint32_t type, uint32_t id);
|
||||
int64_t opal_xive_get_queue_state(uint64_t vp, uint32_t prio,
|
||||
__be32 *out_qtoggle,
|
||||
__be32 *out_qindex);
|
||||
int64_t opal_xive_set_queue_state(uint64_t vp, uint32_t prio,
|
||||
uint32_t qtoggle,
|
||||
uint32_t qindex);
|
||||
int64_t opal_xive_get_vp_state(uint64_t vp, __be64 *out_w01);
|
||||
int64_t opal_pci_set_p2p(uint64_t phb_init, uint64_t phb_target,
|
||||
uint64_t desc, uint16_t pe_number);
|
||||
|
||||
|
|
|
@ -109,12 +109,26 @@ extern int xive_native_configure_queue(u32 vp_id, struct xive_q *q, u8 prio,
|
|||
extern void xive_native_disable_queue(u32 vp_id, struct xive_q *q, u8 prio);
|
||||
|
||||
extern void xive_native_sync_source(u32 hw_irq);
|
||||
extern void xive_native_sync_queue(u32 hw_irq);
|
||||
extern bool is_xive_irq(struct irq_chip *chip);
|
||||
extern int xive_native_enable_vp(u32 vp_id, bool single_escalation);
|
||||
extern int xive_native_disable_vp(u32 vp_id);
|
||||
extern int xive_native_get_vp_info(u32 vp_id, u32 *out_cam_id, u32 *out_chip_id);
|
||||
extern bool xive_native_has_single_escalation(void);
|
||||
|
||||
extern int xive_native_get_queue_info(u32 vp_id, uint32_t prio,
|
||||
u64 *out_qpage,
|
||||
u64 *out_qsize,
|
||||
u64 *out_qeoi_page,
|
||||
u32 *out_escalate_irq,
|
||||
u64 *out_qflags);
|
||||
|
||||
extern int xive_native_get_queue_state(u32 vp_id, uint32_t prio, u32 *qtoggle,
|
||||
u32 *qindex);
|
||||
extern int xive_native_set_queue_state(u32 vp_id, uint32_t prio, u32 qtoggle,
|
||||
u32 qindex);
|
||||
extern int xive_native_get_vp_state(u32 vp_id, u64 *out_state);
|
||||
|
||||
#else
|
||||
|
||||
static inline bool xive_enabled(void) { return false; }
|
||||
|
|
|
@ -29,11 +29,15 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/hw_breakpoint.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sstep.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/debugfs.h>
|
||||
#include <asm/hvcall.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
/*
|
||||
|
@ -174,7 +178,7 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
|
|||
if (!ppc_breakpoint_available())
|
||||
return -ENODEV;
|
||||
length_max = 8; /* DABR */
|
||||
if (cpu_has_feature(CPU_FTR_DAWR)) {
|
||||
if (dawr_enabled()) {
|
||||
length_max = 512 ; /* 64 doublewords */
|
||||
/* DAWR region can't cross 512 boundary */
|
||||
if ((attr->bp_addr >> 9) !=
|
||||
|
@ -376,3 +380,59 @@ void hw_breakpoint_pmu_read(struct perf_event *bp)
|
|||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
bool dawr_force_enable;
|
||||
EXPORT_SYMBOL_GPL(dawr_force_enable);
|
||||
|
||||
static ssize_t dawr_write_file_bool(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct arch_hw_breakpoint null_brk = {0, 0, 0};
|
||||
size_t rc;
|
||||
|
||||
/* Send error to user if they hypervisor won't allow us to write DAWR */
|
||||
if ((!dawr_force_enable) &&
|
||||
(firmware_has_feature(FW_FEATURE_LPAR)) &&
|
||||
(set_dawr(&null_brk) != H_SUCCESS))
|
||||
return -1;
|
||||
|
||||
rc = debugfs_write_file_bool(file, user_buf, count, ppos);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* If we are clearing, make sure all CPUs have the DAWR cleared */
|
||||
if (!dawr_force_enable)
|
||||
smp_call_function((smp_call_func_t)set_dawr, &null_brk, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations dawr_enable_fops = {
|
||||
.read = debugfs_read_file_bool,
|
||||
.write = dawr_write_file_bool,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int __init dawr_force_setup(void)
|
||||
{
|
||||
dawr_force_enable = false;
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_DAWR)) {
|
||||
/* Don't setup sysfs file for user control on P8 */
|
||||
dawr_force_enable = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PVR_VER(mfspr(SPRN_PVR)) == PVR_POWER9) {
|
||||
/* Turn DAWR off by default, but allow admin to turn it on */
|
||||
dawr_force_enable = false;
|
||||
debugfs_create_file_unsafe("dawr_enable_dangerous", 0600,
|
||||
powerpc_debugfs_root,
|
||||
&dawr_force_enable,
|
||||
&dawr_enable_fops);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(dawr_force_setup);
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include <asm/cpu_has_feature.h>
|
||||
#include <asm/asm-prototypes.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/hw_breakpoint.h>
|
||||
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kdebug.h>
|
||||
|
@ -784,7 +785,7 @@ static inline int set_dabr(struct arch_hw_breakpoint *brk)
|
|||
return __set_dabr(dabr, dabrx);
|
||||
}
|
||||
|
||||
static inline int set_dawr(struct arch_hw_breakpoint *brk)
|
||||
int set_dawr(struct arch_hw_breakpoint *brk)
|
||||
{
|
||||
unsigned long dawr, dawrx, mrd;
|
||||
|
||||
|
@ -816,7 +817,7 @@ void __set_breakpoint(struct arch_hw_breakpoint *brk)
|
|||
{
|
||||
memcpy(this_cpu_ptr(¤t_brk), brk, sizeof(*brk));
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_DAWR))
|
||||
if (dawr_enabled())
|
||||
// Power8 or later
|
||||
set_dawr(brk);
|
||||
else if (!cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
|
@ -830,8 +831,8 @@ void __set_breakpoint(struct arch_hw_breakpoint *brk)
|
|||
/* Check if we have DAWR or DABR hardware */
|
||||
bool ppc_breakpoint_available(void)
|
||||
{
|
||||
if (cpu_has_feature(CPU_FTR_DAWR))
|
||||
return true; /* POWER8 DAWR */
|
||||
if (dawr_enabled())
|
||||
return true; /* POWER8 DAWR or POWER9 forced DAWR */
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
return false; /* POWER9 with DAWR disabled */
|
||||
/* DABR: Everything but POWER8 and POWER9 */
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <asm/tm.h>
|
||||
#include <asm/asm-prototypes.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/hw_breakpoint.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/syscalls.h>
|
||||
|
@ -3088,7 +3089,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
|||
dbginfo.sizeof_condition = 0;
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
|
||||
if (cpu_has_feature(CPU_FTR_DAWR))
|
||||
if (dawr_enabled())
|
||||
dbginfo.features |= PPC_DEBUG_FEATURE_DATA_BP_DAWR;
|
||||
#else
|
||||
dbginfo.features = 0;
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#include <asm/opal.h>
|
||||
#include <asm/xics.h>
|
||||
#include <asm/xive.h>
|
||||
#include <asm/hw_breakpoint.h>
|
||||
|
||||
#include "book3s.h"
|
||||
|
||||
|
@ -3410,7 +3411,7 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
|
|||
mtspr(SPRN_PURR, vcpu->arch.purr);
|
||||
mtspr(SPRN_SPURR, vcpu->arch.spurr);
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_DAWR)) {
|
||||
if (dawr_enabled()) {
|
||||
mtspr(SPRN_DAWR, vcpu->arch.dawr);
|
||||
mtspr(SPRN_DAWRX, vcpu->arch.dawrx);
|
||||
}
|
||||
|
|
|
@ -794,18 +794,21 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
|
|||
mtspr SPRN_IAMR, r5
|
||||
mtspr SPRN_PSPB, r6
|
||||
mtspr SPRN_FSCR, r7
|
||||
ld r5, VCPU_DAWR(r4)
|
||||
ld r6, VCPU_DAWRX(r4)
|
||||
ld r7, VCPU_CIABR(r4)
|
||||
ld r8, VCPU_TAR(r4)
|
||||
/*
|
||||
* Handle broken DAWR case by not writing it. This means we
|
||||
* can still store the DAWR register for migration.
|
||||
*/
|
||||
BEGIN_FTR_SECTION
|
||||
LOAD_REG_ADDR(r5, dawr_force_enable)
|
||||
lbz r5, 0(r5)
|
||||
cmpdi r5, 0
|
||||
beq 1f
|
||||
ld r5, VCPU_DAWR(r4)
|
||||
ld r6, VCPU_DAWRX(r4)
|
||||
mtspr SPRN_DAWR, r5
|
||||
mtspr SPRN_DAWRX, r6
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_DAWR)
|
||||
1:
|
||||
ld r7, VCPU_CIABR(r4)
|
||||
ld r8, VCPU_TAR(r4)
|
||||
mtspr SPRN_CIABR, r7
|
||||
mtspr SPRN_TAR, r8
|
||||
ld r5, VCPU_IC(r4)
|
||||
|
@ -2499,11 +2502,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
|||
blr
|
||||
|
||||
2:
|
||||
BEGIN_FTR_SECTION
|
||||
/* POWER9 with disabled DAWR */
|
||||
LOAD_REG_ADDR(r11, dawr_force_enable)
|
||||
lbz r11, 0(r11)
|
||||
cmpdi r11, 0
|
||||
li r3, H_HARDWARE
|
||||
blr
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_DAWR)
|
||||
beqlr
|
||||
/* Emulate H_SET_DABR/X on P8 for the sake of compat mode guests */
|
||||
rlwimi r5, r4, 5, DAWRX_DR | DAWRX_DW
|
||||
rlwimi r5, r4, 2, DAWRX_WT
|
||||
|
|
|
@ -260,6 +260,9 @@ OPAL_CALL(opal_xive_get_vp_info, OPAL_XIVE_GET_VP_INFO);
|
|||
OPAL_CALL(opal_xive_set_vp_info, OPAL_XIVE_SET_VP_INFO);
|
||||
OPAL_CALL(opal_xive_sync, OPAL_XIVE_SYNC);
|
||||
OPAL_CALL(opal_xive_dump, OPAL_XIVE_DUMP);
|
||||
OPAL_CALL(opal_xive_get_queue_state, OPAL_XIVE_GET_QUEUE_STATE);
|
||||
OPAL_CALL(opal_xive_set_queue_state, OPAL_XIVE_SET_QUEUE_STATE);
|
||||
OPAL_CALL(opal_xive_get_vp_state, OPAL_XIVE_GET_VP_STATE);
|
||||
OPAL_CALL(opal_signal_system_reset, OPAL_SIGNAL_SYSTEM_RESET);
|
||||
OPAL_CALL(opal_npu_init_context, OPAL_NPU_INIT_CONTEXT);
|
||||
OPAL_CALL(opal_npu_destroy_context, OPAL_NPU_DESTROY_CONTEXT);
|
||||
|
|
|
@ -437,6 +437,12 @@ void xive_native_sync_source(u32 hw_irq)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_sync_source);
|
||||
|
||||
void xive_native_sync_queue(u32 hw_irq)
|
||||
{
|
||||
opal_xive_sync(XIVE_SYNC_QUEUE, hw_irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_sync_queue);
|
||||
|
||||
static const struct xive_ops xive_native_ops = {
|
||||
.populate_irq_data = xive_native_populate_irq_data,
|
||||
.configure_irq = xive_native_configure_irq,
|
||||
|
@ -711,3 +717,96 @@ bool xive_native_has_single_escalation(void)
|
|||
return xive_has_single_esc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_has_single_escalation);
|
||||
|
||||
int xive_native_get_queue_info(u32 vp_id, u32 prio,
|
||||
u64 *out_qpage,
|
||||
u64 *out_qsize,
|
||||
u64 *out_qeoi_page,
|
||||
u32 *out_escalate_irq,
|
||||
u64 *out_qflags)
|
||||
{
|
||||
__be64 qpage;
|
||||
__be64 qsize;
|
||||
__be64 qeoi_page;
|
||||
__be32 escalate_irq;
|
||||
__be64 qflags;
|
||||
s64 rc;
|
||||
|
||||
rc = opal_xive_get_queue_info(vp_id, prio, &qpage, &qsize,
|
||||
&qeoi_page, &escalate_irq, &qflags);
|
||||
if (rc) {
|
||||
pr_err("OPAL failed to get queue info for VCPU %d/%d : %lld\n",
|
||||
vp_id, prio, rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (out_qpage)
|
||||
*out_qpage = be64_to_cpu(qpage);
|
||||
if (out_qsize)
|
||||
*out_qsize = be32_to_cpu(qsize);
|
||||
if (out_qeoi_page)
|
||||
*out_qeoi_page = be64_to_cpu(qeoi_page);
|
||||
if (out_escalate_irq)
|
||||
*out_escalate_irq = be32_to_cpu(escalate_irq);
|
||||
if (out_qflags)
|
||||
*out_qflags = be64_to_cpu(qflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_get_queue_info);
|
||||
|
||||
int xive_native_get_queue_state(u32 vp_id, u32 prio, u32 *qtoggle, u32 *qindex)
|
||||
{
|
||||
__be32 opal_qtoggle;
|
||||
__be32 opal_qindex;
|
||||
s64 rc;
|
||||
|
||||
rc = opal_xive_get_queue_state(vp_id, prio, &opal_qtoggle,
|
||||
&opal_qindex);
|
||||
if (rc) {
|
||||
pr_err("OPAL failed to get queue state for VCPU %d/%d : %lld\n",
|
||||
vp_id, prio, rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (qtoggle)
|
||||
*qtoggle = be32_to_cpu(opal_qtoggle);
|
||||
if (qindex)
|
||||
*qindex = be32_to_cpu(opal_qindex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_get_queue_state);
|
||||
|
||||
int xive_native_set_queue_state(u32 vp_id, u32 prio, u32 qtoggle, u32 qindex)
|
||||
{
|
||||
s64 rc;
|
||||
|
||||
rc = opal_xive_set_queue_state(vp_id, prio, qtoggle, qindex);
|
||||
if (rc) {
|
||||
pr_err("OPAL failed to set queue state for VCPU %d/%d : %lld\n",
|
||||
vp_id, prio, rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_set_queue_state);
|
||||
|
||||
int xive_native_get_vp_state(u32 vp_id, u64 *out_state)
|
||||
{
|
||||
__be64 state;
|
||||
s64 rc;
|
||||
|
||||
rc = opal_xive_get_vp_state(vp_id, &state);
|
||||
if (rc) {
|
||||
pr_err("OPAL failed to get vp state for VCPU %d : %lld\n",
|
||||
vp_id, rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (out_state)
|
||||
*out_state = be64_to_cpu(state);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xive_native_get_vp_state);
|
||||
|
|
Loading…
Reference in New Issue