mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 19:47:08 +02:00
Linux 6.1-rc2
-----BEGIN PGP SIGNATURE----- iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAmNVv9UeHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiGInQH/0YTqoWH4mYpBSgy KLOaLxs3fRY0B0EmSItcQfish1GuE0wsNClm6us4+CxcHIQPGnhoPdjobAp+W9X1 JkBpxs+WbozGf23IGiVV8cFRXvpLL5TmiB5IeXo3kzvqGG2yvgEZ2uvclDeRN8bj Z0DlcPGG1Of9Fhmj+CsEwu0YOJ4o5kPNtuXrp1YVyiLlmyrGN68cb0vzZuEMQ6mg D7BkseqfE0lblKQCTyt1Uwxc08YR/LmmdkZ4d206NpKmJZaSFKhnfeXteljnvw/u vi3Rl1SKRxRsqZheJYSTGOmw0a6vu/6LDrsS3IVr1A54oS6tM77Y2WVbE+msyFaw R7EkOVc= =RQLk -----END PGP SIGNATURE----- Merge tag 'v6.1-rc2' into android-mainline Linux 6.1-rc2 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ib5212f4a6567c2452e703b52a9b7b0b6394bc6c7
This commit is contained in:
commit
429562c3d3
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 6
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc1
|
||||
EXTRAVERSION = -rc2
|
||||
NAME = Hurr durr I'ma ninja sloth
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -13,6 +13,18 @@
|
|||
|
||||
#define KVM_PGTABLE_MAX_LEVELS 4U
|
||||
|
||||
/*
|
||||
* The largest supported block sizes for KVM (no 52-bit PA support):
|
||||
* - 4K (level 1): 1GB
|
||||
* - 16K (level 2): 32MB
|
||||
* - 64K (level 2): 512MB
|
||||
*/
|
||||
#ifdef CONFIG_ARM64_4K_PAGES
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1U
|
||||
#else
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2U
|
||||
#endif
|
||||
|
||||
static inline u64 kvm_get_parange(u64 mmfr0)
|
||||
{
|
||||
u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
|
|
@ -58,11 +70,7 @@ static inline u64 kvm_granule_size(u32 level)
|
|||
|
||||
static inline bool kvm_level_supports_block_mapping(u32 level)
|
||||
{
|
||||
/*
|
||||
* Reject invalid block mappings and don't bother with 4TB mappings for
|
||||
* 52-bit PAs.
|
||||
*/
|
||||
return !(level == 0 || (PAGE_SIZE != SZ_4K && level == 1));
|
||||
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,13 +10,6 @@
|
|||
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
/*
|
||||
* PGDIR_SHIFT determines the size a top-level page table entry can map
|
||||
* and depends on the number of levels in the page table. Compute the
|
||||
* PGDIR_SHIFT for a given number of levels.
|
||||
*/
|
||||
#define pt_levels_pgdir_shift(lvls) ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - (lvls))
|
||||
|
||||
/*
|
||||
* The hardware supports concatenation of up to 16 tables at stage2 entry
|
||||
* level and we use the feature whenever possible, which means we resolve 4
|
||||
|
|
@ -30,11 +23,6 @@
|
|||
#define stage2_pgtable_levels(ipa) ARM64_HW_PGTABLE_LEVELS((ipa) - 4)
|
||||
#define kvm_stage2_levels(kvm) VTCR_EL2_LVLS(kvm->arch.vtcr)
|
||||
|
||||
/* stage2_pgdir_shift() is the size mapped by top-level stage2 entry for the VM */
|
||||
#define stage2_pgdir_shift(kvm) pt_levels_pgdir_shift(kvm_stage2_levels(kvm))
|
||||
#define stage2_pgdir_size(kvm) (1ULL << stage2_pgdir_shift(kvm))
|
||||
#define stage2_pgdir_mask(kvm) ~(stage2_pgdir_size(kvm) - 1)
|
||||
|
||||
/*
|
||||
* kvm_mmmu_cache_min_pages() is the number of pages required to install
|
||||
* a stage-2 translation. We pre-allocate the entry level page table at
|
||||
|
|
@ -42,12 +30,4 @@
|
|||
*/
|
||||
#define kvm_mmu_cache_min_pages(kvm) (kvm_stage2_levels(kvm) - 1)
|
||||
|
||||
static inline phys_addr_t
|
||||
stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
phys_addr_t boundary = (addr + stage2_pgdir_size(kvm)) & stage2_pgdir_mask(kvm);
|
||||
|
||||
return (boundary - 1 < end - 1) ? boundary : end;
|
||||
}
|
||||
|
||||
#endif /* __ARM64_S2_PGTABLE_H_ */
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@
|
|||
|
||||
incdir := $(srctree)/$(src)/include
|
||||
subdir-asflags-y := -I$(incdir)
|
||||
subdir-ccflags-y := -I$(incdir) \
|
||||
-fno-stack-protector \
|
||||
-DDISABLE_BRANCH_PROFILING \
|
||||
$(DISABLE_STACKLEAK_PLUGIN)
|
||||
subdir-ccflags-y := -I$(incdir)
|
||||
|
||||
obj-$(CONFIG_KVM) += vhe/ nvhe/ pgtable.o
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ asflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS
|
|||
# will explode instantly (Words of Marc Zyngier). So introduce a generic flag
|
||||
# __DISABLE_TRACE_MMIO__ to disable MMIO tracing for nVHE KVM.
|
||||
ccflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS -D__DISABLE_TRACE_MMIO__
|
||||
ccflags-y += -fno-stack-protector \
|
||||
-DDISABLE_BRANCH_PROFILING \
|
||||
$(DISABLE_STACKLEAK_PLUGIN)
|
||||
|
||||
hostprogs := gen-hyprel
|
||||
HOST_EXTRACFLAGS += -I$(objtree)/include
|
||||
|
|
@ -89,6 +92,10 @@ quiet_cmd_hypcopy = HYPCOPY $@
|
|||
# Remove ftrace, Shadow Call Stack, and CFI CFLAGS.
|
||||
# This is equivalent to the 'notrace', '__noscs', and '__nocfi' annotations.
|
||||
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_CFI), $(KBUILD_CFLAGS))
|
||||
# Starting from 13.0.0 llvm emits SHT_REL section '.llvm.call-graph-profile'
|
||||
# when profile optimization is applied. gen-hyprel does not support SHT_REL and
|
||||
# causes a build failure. Remove profile optimization flags.
|
||||
KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%, $(KBUILD_CFLAGS))
|
||||
|
||||
# KVM nVHE code is run at a different exception code with a different map, so
|
||||
# compiler instrumentation that inserts callbacks or checks into the code may
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@ static phys_addr_t hyp_idmap_vector;
|
|||
|
||||
static unsigned long io_map_base;
|
||||
|
||||
static phys_addr_t stage2_range_addr_end(phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
phys_addr_t size = kvm_granule_size(KVM_PGTABLE_MIN_BLOCK_LEVEL);
|
||||
phys_addr_t boundary = ALIGN_DOWN(addr + size, size);
|
||||
|
||||
return (boundary - 1 < end - 1) ? boundary : end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release kvm_mmu_lock periodically if the memory region is large. Otherwise,
|
||||
|
|
@ -52,7 +59,7 @@ static int stage2_apply_range(struct kvm *kvm, phys_addr_t addr,
|
|||
if (!pgt)
|
||||
return -EINVAL;
|
||||
|
||||
next = stage2_pgd_addr_end(kvm, addr, end);
|
||||
next = stage2_range_addr_end(addr, end);
|
||||
ret = fn(pgt, addr, next - addr);
|
||||
if (ret)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -2149,7 +2149,7 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
|
|||
|
||||
memset(entry, 0, esz);
|
||||
|
||||
while (len > 0) {
|
||||
while (true) {
|
||||
int next_offset;
|
||||
size_t byte_offset;
|
||||
|
||||
|
|
@ -2162,6 +2162,9 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
|
|||
return next_offset;
|
||||
|
||||
byte_offset = next_offset * esz;
|
||||
if (byte_offset >= len)
|
||||
break;
|
||||
|
||||
id += next_offset;
|
||||
gpa += byte_offset;
|
||||
len -= byte_offset;
|
||||
|
|
|
|||
|
|
@ -42,16 +42,8 @@ void flush_icache_mm(struct mm_struct *mm, bool local);
|
|||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/*
|
||||
* The T-Head CMO errata internally probe the CBOM block size, but otherwise
|
||||
* don't depend on Zicbom.
|
||||
*/
|
||||
extern unsigned int riscv_cbom_block_size;
|
||||
#ifdef CONFIG_RISCV_ISA_ZICBOM
|
||||
void riscv_init_cbom_blocksize(void);
|
||||
#else
|
||||
static inline void riscv_init_cbom_blocksize(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RISCV_DMA_NONCOHERENT
|
||||
void riscv_noncoherent_supported(void);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu);
|
|||
int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu);
|
||||
void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu);
|
||||
void kvm_riscv_guest_timer_init(struct kvm *kvm);
|
||||
void kvm_riscv_vcpu_timer_sync(struct kvm_vcpu *vcpu);
|
||||
void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu);
|
||||
bool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
|
|
|||
|
|
@ -708,6 +708,9 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
|
|||
clear_bit(IRQ_VS_SOFT, &v->irqs_pending);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync-up timer CSRs */
|
||||
kvm_riscv_vcpu_timer_sync(vcpu);
|
||||
}
|
||||
|
||||
int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
|
|
|
|||
|
|
@ -320,6 +320,21 @@ void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
|
|||
kvm_riscv_vcpu_timer_unblocking(vcpu);
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_timer_sync(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
|
||||
|
||||
if (!t->sstc_enabled)
|
||||
return;
|
||||
|
||||
#if defined(CONFIG_32BIT)
|
||||
t->next_cycles = csr_read(CSR_VSTIMECMP);
|
||||
t->next_cycles |= (u64)csr_read(CSR_VSTIMECMPH) << 32;
|
||||
#else
|
||||
t->next_cycles = csr_read(CSR_VSTIMECMP);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_vcpu_timer *t = &vcpu->arch.timer;
|
||||
|
|
@ -327,13 +342,11 @@ void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
|
|||
if (!t->sstc_enabled)
|
||||
return;
|
||||
|
||||
t = &vcpu->arch.timer;
|
||||
#if defined(CONFIG_32BIT)
|
||||
t->next_cycles = csr_read(CSR_VSTIMECMP);
|
||||
t->next_cycles |= (u64)csr_read(CSR_VSTIMECMPH) << 32;
|
||||
#else
|
||||
t->next_cycles = csr_read(CSR_VSTIMECMP);
|
||||
#endif
|
||||
/*
|
||||
* The vstimecmp CSRs are saved by kvm_riscv_vcpu_timer_sync()
|
||||
* upon every VM exit so no need to save here.
|
||||
*/
|
||||
|
||||
/* timer should be enabled for the remaining operations */
|
||||
if (unlikely(!t->init_done))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (C) 2017 SiFive
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
|
@ -86,3 +87,40 @@ void flush_icache_pte(pte_t pte)
|
|||
flush_icache_all();
|
||||
}
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
unsigned int riscv_cbom_block_size;
|
||||
EXPORT_SYMBOL_GPL(riscv_cbom_block_size);
|
||||
|
||||
void riscv_init_cbom_blocksize(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
unsigned long cbom_hartid;
|
||||
u32 val, probed_block_size;
|
||||
int ret;
|
||||
|
||||
probed_block_size = 0;
|
||||
for_each_of_cpu_node(node) {
|
||||
unsigned long hartid;
|
||||
|
||||
ret = riscv_of_processor_hartid(node, &hartid);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/* set block-size for cbom extension if available */
|
||||
ret = of_property_read_u32(node, "riscv,cbom-block-size", &val);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
if (!probed_block_size) {
|
||||
probed_block_size = val;
|
||||
cbom_hartid = hartid;
|
||||
} else {
|
||||
if (probed_block_size != val)
|
||||
pr_warn("cbom-block-size mismatched between harts %lu and %lu\n",
|
||||
cbom_hartid, hartid);
|
||||
}
|
||||
}
|
||||
|
||||
if (probed_block_size)
|
||||
riscv_cbom_block_size = probed_block_size;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,8 @@
|
|||
#include <linux/dma-direct.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
unsigned int riscv_cbom_block_size;
|
||||
EXPORT_SYMBOL_GPL(riscv_cbom_block_size);
|
||||
|
||||
static bool noncoherent_supported;
|
||||
|
||||
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
|
||||
|
|
@ -77,42 +72,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
|
|||
dev->dma_coherent = coherent;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RISCV_ISA_ZICBOM
|
||||
void riscv_init_cbom_blocksize(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
unsigned long cbom_hartid;
|
||||
u32 val, probed_block_size;
|
||||
int ret;
|
||||
|
||||
probed_block_size = 0;
|
||||
for_each_of_cpu_node(node) {
|
||||
unsigned long hartid;
|
||||
|
||||
ret = riscv_of_processor_hartid(node, &hartid);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/* set block-size for cbom extension if available */
|
||||
ret = of_property_read_u32(node, "riscv,cbom-block-size", &val);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
if (!probed_block_size) {
|
||||
probed_block_size = val;
|
||||
cbom_hartid = hartid;
|
||||
} else {
|
||||
if (probed_block_size != val)
|
||||
pr_warn("cbom-block-size mismatched between harts %lu and %lu\n",
|
||||
cbom_hartid, hartid);
|
||||
}
|
||||
}
|
||||
|
||||
if (probed_block_size)
|
||||
riscv_cbom_block_size = probed_block_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
void riscv_noncoherent_supported(void)
|
||||
{
|
||||
WARN(!riscv_cbom_block_size,
|
||||
|
|
|
|||
|
|
@ -6442,26 +6442,22 @@ static int kvm_add_msr_filter(struct kvm_x86_msr_filter *msr_filter,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
|
||||
static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm,
|
||||
struct kvm_msr_filter *filter)
|
||||
{
|
||||
struct kvm_msr_filter __user *user_msr_filter = argp;
|
||||
struct kvm_x86_msr_filter *new_filter, *old_filter;
|
||||
struct kvm_msr_filter filter;
|
||||
bool default_allow;
|
||||
bool empty = true;
|
||||
int r = 0;
|
||||
u32 i;
|
||||
|
||||
if (copy_from_user(&filter, user_msr_filter, sizeof(filter)))
|
||||
return -EFAULT;
|
||||
|
||||
if (filter.flags & ~KVM_MSR_FILTER_DEFAULT_DENY)
|
||||
if (filter->flags & ~KVM_MSR_FILTER_DEFAULT_DENY)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(filter.ranges); i++)
|
||||
empty &= !filter.ranges[i].nmsrs;
|
||||
for (i = 0; i < ARRAY_SIZE(filter->ranges); i++)
|
||||
empty &= !filter->ranges[i].nmsrs;
|
||||
|
||||
default_allow = !(filter.flags & KVM_MSR_FILTER_DEFAULT_DENY);
|
||||
default_allow = !(filter->flags & KVM_MSR_FILTER_DEFAULT_DENY);
|
||||
if (empty && !default_allow)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -6469,8 +6465,8 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
|
|||
if (!new_filter)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(filter.ranges); i++) {
|
||||
r = kvm_add_msr_filter(new_filter, &filter.ranges[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(filter->ranges); i++) {
|
||||
r = kvm_add_msr_filter(new_filter, &filter->ranges[i]);
|
||||
if (r) {
|
||||
kvm_free_msr_filter(new_filter);
|
||||
return r;
|
||||
|
|
@ -6493,6 +6489,62 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_COMPAT
|
||||
/* for KVM_X86_SET_MSR_FILTER */
|
||||
struct kvm_msr_filter_range_compat {
|
||||
__u32 flags;
|
||||
__u32 nmsrs;
|
||||
__u32 base;
|
||||
__u32 bitmap;
|
||||
};
|
||||
|
||||
struct kvm_msr_filter_compat {
|
||||
__u32 flags;
|
||||
struct kvm_msr_filter_range_compat ranges[KVM_MSR_FILTER_MAX_RANGES];
|
||||
};
|
||||
|
||||
#define KVM_X86_SET_MSR_FILTER_COMPAT _IOW(KVMIO, 0xc6, struct kvm_msr_filter_compat)
|
||||
|
||||
long kvm_arch_vm_compat_ioctl(struct file *filp, unsigned int ioctl,
|
||||
unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct kvm *kvm = filp->private_data;
|
||||
long r = -ENOTTY;
|
||||
|
||||
switch (ioctl) {
|
||||
case KVM_X86_SET_MSR_FILTER_COMPAT: {
|
||||
struct kvm_msr_filter __user *user_msr_filter = argp;
|
||||
struct kvm_msr_filter_compat filter_compat;
|
||||
struct kvm_msr_filter filter;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&filter_compat, user_msr_filter,
|
||||
sizeof(filter_compat)))
|
||||
return -EFAULT;
|
||||
|
||||
filter.flags = filter_compat.flags;
|
||||
for (i = 0; i < ARRAY_SIZE(filter.ranges); i++) {
|
||||
struct kvm_msr_filter_range_compat *cr;
|
||||
|
||||
cr = &filter_compat.ranges[i];
|
||||
filter.ranges[i] = (struct kvm_msr_filter_range) {
|
||||
.flags = cr->flags,
|
||||
.nmsrs = cr->nmsrs,
|
||||
.base = cr->base,
|
||||
.bitmap = (__u8 *)(ulong)cr->bitmap,
|
||||
};
|
||||
}
|
||||
|
||||
r = kvm_vm_ioctl_set_msr_filter(kvm, &filter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
|
||||
static int kvm_arch_suspend_notifier(struct kvm *kvm)
|
||||
{
|
||||
|
|
@ -6915,9 +6967,16 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||
case KVM_SET_PMU_EVENT_FILTER:
|
||||
r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
|
||||
break;
|
||||
case KVM_X86_SET_MSR_FILTER:
|
||||
r = kvm_vm_ioctl_set_msr_filter(kvm, argp);
|
||||
case KVM_X86_SET_MSR_FILTER: {
|
||||
struct kvm_msr_filter __user *user_msr_filter = argp;
|
||||
struct kvm_msr_filter filter;
|
||||
|
||||
if (copy_from_user(&filter, user_msr_filter, sizeof(filter)))
|
||||
return -EFAULT;
|
||||
|
||||
r = kvm_vm_ioctl_set_msr_filter(kvm, &filter);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
r = -ENOTTY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,14 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
|
|||
goto err_map;
|
||||
}
|
||||
|
||||
/* Parse the device's DT node for an endianness specification */
|
||||
if (of_property_read_bool(np, "big-endian"))
|
||||
syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
|
||||
else if (of_property_read_bool(np, "little-endian"))
|
||||
syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
|
||||
else if (of_property_read_bool(np, "native-endian"))
|
||||
syscon_config.val_format_endian = REGMAP_ENDIAN_NATIVE;
|
||||
|
||||
/*
|
||||
* search for reg-io-width property in DT. If it is not provided,
|
||||
* default to 4 bytes. regmap_init_mmio will return an error if values
|
||||
|
|
|
|||
|
|
@ -1390,6 +1390,8 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
|||
struct kvm_enable_cap *cap);
|
||||
long kvm_arch_vm_ioctl(struct file *filp,
|
||||
unsigned int ioctl, unsigned long arg);
|
||||
long kvm_arch_vm_compat_ioctl(struct file *filp, unsigned int ioctl,
|
||||
unsigned long arg);
|
||||
|
||||
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);
|
||||
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);
|
||||
|
|
|
|||
|
|
@ -756,11 +756,14 @@ struct perf_event {
|
|||
struct fasync_struct *fasync;
|
||||
|
||||
/* delayed work for NMIs and such */
|
||||
int pending_wakeup;
|
||||
int pending_kill;
|
||||
int pending_disable;
|
||||
unsigned int pending_wakeup;
|
||||
unsigned int pending_kill;
|
||||
unsigned int pending_disable;
|
||||
unsigned int pending_sigtrap;
|
||||
unsigned long pending_addr; /* SIGTRAP */
|
||||
struct irq_work pending;
|
||||
struct irq_work pending_irq;
|
||||
struct callback_head pending_task;
|
||||
unsigned int pending_work;
|
||||
|
||||
atomic_t event_limit;
|
||||
|
||||
|
|
@ -877,6 +880,14 @@ struct perf_event_context {
|
|||
#endif
|
||||
void *task_ctx_data; /* pmu specific data */
|
||||
struct rcu_head rcu_head;
|
||||
|
||||
/*
|
||||
* Sum (event->pending_sigtrap + event->pending_work)
|
||||
*
|
||||
* The SIGTRAP is targeted at ctx->task, as such it won't do changing
|
||||
* that until the signal is delivered.
|
||||
*/
|
||||
local_t nr_pending;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <uapi/linux/utsname.h>
|
||||
|
||||
enum uts_proc {
|
||||
UTS_PROC_ARCH,
|
||||
UTS_PROC_OSTYPE,
|
||||
UTS_PROC_OSRELEASE,
|
||||
UTS_PROC_VERSION,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
#include <linux/highmem.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <linux/buildid.h>
|
||||
#include <linux/task_work.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
|
@ -2276,11 +2277,26 @@ event_sched_out(struct perf_event *event,
|
|||
event->pmu->del(event, 0);
|
||||
event->oncpu = -1;
|
||||
|
||||
if (READ_ONCE(event->pending_disable) >= 0) {
|
||||
WRITE_ONCE(event->pending_disable, -1);
|
||||
if (event->pending_disable) {
|
||||
event->pending_disable = 0;
|
||||
perf_cgroup_event_disable(event, ctx);
|
||||
state = PERF_EVENT_STATE_OFF;
|
||||
}
|
||||
|
||||
if (event->pending_sigtrap) {
|
||||
bool dec = true;
|
||||
|
||||
event->pending_sigtrap = 0;
|
||||
if (state != PERF_EVENT_STATE_OFF &&
|
||||
!event->pending_work) {
|
||||
event->pending_work = 1;
|
||||
dec = false;
|
||||
task_work_add(current, &event->pending_task, TWA_RESUME);
|
||||
}
|
||||
if (dec)
|
||||
local_dec(&event->ctx->nr_pending);
|
||||
}
|
||||
|
||||
perf_event_set_state(event, state);
|
||||
|
||||
if (!is_software_event(event))
|
||||
|
|
@ -2432,7 +2448,7 @@ static void __perf_event_disable(struct perf_event *event,
|
|||
* hold the top-level event's child_mutex, so any descendant that
|
||||
* goes to exit will block in perf_event_exit_event().
|
||||
*
|
||||
* When called from perf_pending_event it's OK because event->ctx
|
||||
* When called from perf_pending_irq it's OK because event->ctx
|
||||
* is the current context on this CPU and preemption is disabled,
|
||||
* hence we can't get into perf_event_task_sched_out for this context.
|
||||
*/
|
||||
|
|
@ -2471,9 +2487,8 @@ EXPORT_SYMBOL_GPL(perf_event_disable);
|
|||
|
||||
void perf_event_disable_inatomic(struct perf_event *event)
|
||||
{
|
||||
WRITE_ONCE(event->pending_disable, smp_processor_id());
|
||||
/* can fail, see perf_pending_event_disable() */
|
||||
irq_work_queue(&event->pending);
|
||||
event->pending_disable = 1;
|
||||
irq_work_queue(&event->pending_irq);
|
||||
}
|
||||
|
||||
#define MAX_INTERRUPTS (~0ULL)
|
||||
|
|
@ -3428,11 +3443,23 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
|
|||
raw_spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING);
|
||||
if (context_equiv(ctx, next_ctx)) {
|
||||
|
||||
perf_pmu_disable(pmu);
|
||||
|
||||
/* PMIs are disabled; ctx->nr_pending is stable. */
|
||||
if (local_read(&ctx->nr_pending) ||
|
||||
local_read(&next_ctx->nr_pending)) {
|
||||
/*
|
||||
* Must not swap out ctx when there's pending
|
||||
* events that rely on the ctx->task relation.
|
||||
*/
|
||||
raw_spin_unlock(&next_ctx->lock);
|
||||
rcu_read_unlock();
|
||||
goto inside_switch;
|
||||
}
|
||||
|
||||
WRITE_ONCE(ctx->task, next);
|
||||
WRITE_ONCE(next_ctx->task, task);
|
||||
|
||||
perf_pmu_disable(pmu);
|
||||
|
||||
if (cpuctx->sched_cb_usage && pmu->sched_task)
|
||||
pmu->sched_task(ctx, false);
|
||||
|
||||
|
|
@ -3473,6 +3500,7 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
|
|||
raw_spin_lock(&ctx->lock);
|
||||
perf_pmu_disable(pmu);
|
||||
|
||||
inside_switch:
|
||||
if (cpuctx->sched_cb_usage && pmu->sched_task)
|
||||
pmu->sched_task(ctx, false);
|
||||
task_ctx_sched_out(cpuctx, ctx, EVENT_ALL);
|
||||
|
|
@ -4940,7 +4968,7 @@ static void perf_addr_filters_splice(struct perf_event *event,
|
|||
|
||||
static void _free_event(struct perf_event *event)
|
||||
{
|
||||
irq_work_sync(&event->pending);
|
||||
irq_work_sync(&event->pending_irq);
|
||||
|
||||
unaccount_event(event);
|
||||
|
||||
|
|
@ -6440,7 +6468,8 @@ static void perf_sigtrap(struct perf_event *event)
|
|||
return;
|
||||
|
||||
/*
|
||||
* perf_pending_event() can race with the task exiting.
|
||||
* Both perf_pending_task() and perf_pending_irq() can race with the
|
||||
* task exiting.
|
||||
*/
|
||||
if (current->flags & PF_EXITING)
|
||||
return;
|
||||
|
|
@ -6449,23 +6478,33 @@ static void perf_sigtrap(struct perf_event *event)
|
|||
event->attr.type, event->attr.sig_data);
|
||||
}
|
||||
|
||||
static void perf_pending_event_disable(struct perf_event *event)
|
||||
/*
|
||||
* Deliver the pending work in-event-context or follow the context.
|
||||
*/
|
||||
static void __perf_pending_irq(struct perf_event *event)
|
||||
{
|
||||
int cpu = READ_ONCE(event->pending_disable);
|
||||
int cpu = READ_ONCE(event->oncpu);
|
||||
|
||||
/*
|
||||
* If the event isn't running; we done. event_sched_out() will have
|
||||
* taken care of things.
|
||||
*/
|
||||
if (cpu < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Yay, we hit home and are in the context of the event.
|
||||
*/
|
||||
if (cpu == smp_processor_id()) {
|
||||
WRITE_ONCE(event->pending_disable, -1);
|
||||
|
||||
if (event->attr.sigtrap) {
|
||||
if (event->pending_sigtrap) {
|
||||
event->pending_sigtrap = 0;
|
||||
perf_sigtrap(event);
|
||||
atomic_set_release(&event->event_limit, 1); /* rearm event */
|
||||
return;
|
||||
local_dec(&event->ctx->nr_pending);
|
||||
}
|
||||
if (event->pending_disable) {
|
||||
event->pending_disable = 0;
|
||||
perf_event_disable_local(event);
|
||||
}
|
||||
|
||||
perf_event_disable_local(event);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -6485,35 +6524,62 @@ static void perf_pending_event_disable(struct perf_event *event)
|
|||
* irq_work_queue(); // FAILS
|
||||
*
|
||||
* irq_work_run()
|
||||
* perf_pending_event()
|
||||
* perf_pending_irq()
|
||||
*
|
||||
* But the event runs on CPU-B and wants disabling there.
|
||||
*/
|
||||
irq_work_queue_on(&event->pending, cpu);
|
||||
irq_work_queue_on(&event->pending_irq, cpu);
|
||||
}
|
||||
|
||||
static void perf_pending_event(struct irq_work *entry)
|
||||
static void perf_pending_irq(struct irq_work *entry)
|
||||
{
|
||||
struct perf_event *event = container_of(entry, struct perf_event, pending);
|
||||
struct perf_event *event = container_of(entry, struct perf_event, pending_irq);
|
||||
int rctx;
|
||||
|
||||
rctx = perf_swevent_get_recursion_context();
|
||||
/*
|
||||
* If we 'fail' here, that's OK, it means recursion is already disabled
|
||||
* and we won't recurse 'further'.
|
||||
*/
|
||||
rctx = perf_swevent_get_recursion_context();
|
||||
|
||||
perf_pending_event_disable(event);
|
||||
|
||||
/*
|
||||
* The wakeup isn't bound to the context of the event -- it can happen
|
||||
* irrespective of where the event is.
|
||||
*/
|
||||
if (event->pending_wakeup) {
|
||||
event->pending_wakeup = 0;
|
||||
perf_event_wakeup(event);
|
||||
}
|
||||
|
||||
__perf_pending_irq(event);
|
||||
|
||||
if (rctx >= 0)
|
||||
perf_swevent_put_recursion_context(rctx);
|
||||
}
|
||||
|
||||
static void perf_pending_task(struct callback_head *head)
|
||||
{
|
||||
struct perf_event *event = container_of(head, struct perf_event, pending_task);
|
||||
int rctx;
|
||||
|
||||
/*
|
||||
* If we 'fail' here, that's OK, it means recursion is already disabled
|
||||
* and we won't recurse 'further'.
|
||||
*/
|
||||
preempt_disable_notrace();
|
||||
rctx = perf_swevent_get_recursion_context();
|
||||
|
||||
if (event->pending_work) {
|
||||
event->pending_work = 0;
|
||||
perf_sigtrap(event);
|
||||
local_dec(&event->ctx->nr_pending);
|
||||
}
|
||||
|
||||
if (rctx >= 0)
|
||||
perf_swevent_put_recursion_context(rctx);
|
||||
preempt_enable_notrace();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GUEST_PERF_EVENTS
|
||||
struct perf_guest_info_callbacks __rcu *perf_guest_cbs;
|
||||
|
||||
|
|
@ -9198,8 +9264,8 @@ int perf_event_account_interrupt(struct perf_event *event)
|
|||
*/
|
||||
|
||||
static int __perf_event_overflow(struct perf_event *event,
|
||||
int throttle, struct perf_sample_data *data,
|
||||
struct pt_regs *regs)
|
||||
int throttle, struct perf_sample_data *data,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
int events = atomic_read(&event->event_limit);
|
||||
int ret = 0;
|
||||
|
|
@ -9222,24 +9288,36 @@ static int __perf_event_overflow(struct perf_event *event,
|
|||
if (events && atomic_dec_and_test(&event->event_limit)) {
|
||||
ret = 1;
|
||||
event->pending_kill = POLL_HUP;
|
||||
event->pending_addr = data->addr;
|
||||
|
||||
perf_event_disable_inatomic(event);
|
||||
}
|
||||
|
||||
if (event->attr.sigtrap) {
|
||||
/*
|
||||
* Should not be able to return to user space without processing
|
||||
* pending_sigtrap (kernel events can overflow multiple times).
|
||||
*/
|
||||
WARN_ON_ONCE(event->pending_sigtrap && event->attr.exclude_kernel);
|
||||
if (!event->pending_sigtrap) {
|
||||
event->pending_sigtrap = 1;
|
||||
local_inc(&event->ctx->nr_pending);
|
||||
}
|
||||
event->pending_addr = data->addr;
|
||||
irq_work_queue(&event->pending_irq);
|
||||
}
|
||||
|
||||
READ_ONCE(event->overflow_handler)(event, data, regs);
|
||||
|
||||
if (*perf_event_fasync(event) && event->pending_kill) {
|
||||
event->pending_wakeup = 1;
|
||||
irq_work_queue(&event->pending);
|
||||
irq_work_queue(&event->pending_irq);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int perf_event_overflow(struct perf_event *event,
|
||||
struct perf_sample_data *data,
|
||||
struct pt_regs *regs)
|
||||
struct perf_sample_data *data,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
return __perf_event_overflow(event, 1, data, regs);
|
||||
}
|
||||
|
|
@ -11556,8 +11634,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
|
|||
|
||||
|
||||
init_waitqueue_head(&event->waitq);
|
||||
event->pending_disable = -1;
|
||||
init_irq_work(&event->pending, perf_pending_event);
|
||||
init_irq_work(&event->pending_irq, perf_pending_irq);
|
||||
init_task_work(&event->pending_task, perf_pending_task);
|
||||
|
||||
mutex_init(&event->mmap_mutex);
|
||||
raw_spin_lock_init(&event->addr_filters.lock);
|
||||
|
|
@ -11579,9 +11657,6 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
|
|||
if (parent_event)
|
||||
event->event_caps = parent_event->event_caps;
|
||||
|
||||
if (event->attr.sigtrap)
|
||||
atomic_set(&event->event_limit, 1);
|
||||
|
||||
if (task) {
|
||||
event->attach_state = PERF_ATTACH_TASK;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ static void perf_output_wakeup(struct perf_output_handle *handle)
|
|||
atomic_set(&handle->rb->poll, EPOLLIN);
|
||||
|
||||
handle->event->pending_wakeup = 1;
|
||||
irq_work_queue(&handle->event->pending);
|
||||
irq_work_queue(&handle->event->pending_irq);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -687,6 +687,7 @@ BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
|
|||
|
||||
perf_sample_data_init(sd, 0, 0);
|
||||
sd->raw = &raw;
|
||||
sd->sample_flags |= PERF_SAMPLE_RAW;
|
||||
|
||||
err = __bpf_perf_event_output(regs, map, flags, sd);
|
||||
|
||||
|
|
@ -745,6 +746,7 @@ u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
|
|||
perf_fetch_caller_regs(regs);
|
||||
perf_sample_data_init(sd, 0, 0);
|
||||
sd->raw = &raw;
|
||||
sd->sample_flags |= PERF_SAMPLE_RAW;
|
||||
|
||||
ret = __bpf_perf_event_output(regs, map, flags, sd);
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ static int proc_do_uts_string(struct ctl_table *table, int write,
|
|||
static DEFINE_CTL_TABLE_POLL(hostname_poll);
|
||||
static DEFINE_CTL_TABLE_POLL(domainname_poll);
|
||||
|
||||
// Note: update 'enum uts_proc' to match any changes to this table
|
||||
static struct ctl_table uts_kern_table[] = {
|
||||
{
|
||||
.procname = "arch",
|
||||
|
|
|
|||
|
|
@ -1177,6 +1177,7 @@ struct kvm_ppc_resize_hpt {
|
|||
#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
|
||||
#define KVM_CAP_S390_ZPCI_OP 221
|
||||
#define KVM_CAP_S390_CPU_TOPOLOGY 222
|
||||
#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
|
|
|||
|
|
@ -662,8 +662,8 @@ int test_kvm_device(uint32_t gic_dev_type)
|
|||
: KVM_DEV_TYPE_ARM_VGIC_V2;
|
||||
|
||||
if (!__kvm_test_create_device(v.vm, other)) {
|
||||
ret = __kvm_test_create_device(v.vm, other);
|
||||
TEST_ASSERT(ret && (errno == EINVAL || errno == EEXIST),
|
||||
ret = __kvm_create_device(v.vm, other);
|
||||
TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
|
||||
"create GIC device while other version exists");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct memslot_antagonist_args {
|
|||
static void add_remove_memslot(struct kvm_vm *vm, useconds_t delay,
|
||||
uint64_t nr_modifications)
|
||||
{
|
||||
const uint64_t pages = 1;
|
||||
uint64_t pages = max_t(int, vm->page_size, getpagesize()) / vm->page_size;
|
||||
uint64_t gpa;
|
||||
int i;
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
|
|||
.remove_on_exec = 1, /* Required by sigtrap. */
|
||||
.sigtrap = 1, /* Request synchronous SIGTRAP on event. */
|
||||
.sig_data = TEST_SIG_DATA(addr, id),
|
||||
.exclude_kernel = 1, /* To allow */
|
||||
.exclude_hv = 1, /* running as !root */
|
||||
};
|
||||
return attr;
|
||||
}
|
||||
|
|
@ -93,9 +95,13 @@ static void *test_thread(void *arg)
|
|||
|
||||
__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
|
||||
iter = ctx.iterate_on; /* read */
|
||||
for (i = 0; i < iter - 1; i++) {
|
||||
__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
|
||||
ctx.iterate_on = iter; /* idempotent write */
|
||||
if (iter >= 0) {
|
||||
for (i = 0; i < iter - 1; i++) {
|
||||
__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
|
||||
ctx.iterate_on = iter; /* idempotent write */
|
||||
}
|
||||
} else {
|
||||
while (ctx.iterate_on);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -208,4 +214,27 @@ TEST_F(sigtrap_threads, signal_stress)
|
|||
EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
|
||||
}
|
||||
|
||||
TEST_F(sigtrap_threads, signal_stress_with_disable)
|
||||
{
|
||||
const int target_count = NUM_THREADS * 3000;
|
||||
int i;
|
||||
|
||||
ctx.iterate_on = -1;
|
||||
|
||||
EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
|
||||
pthread_barrier_wait(&self->barrier);
|
||||
while (__atomic_load_n(&ctx.signal_count, __ATOMIC_RELAXED) < target_count) {
|
||||
EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
|
||||
EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
|
||||
}
|
||||
ctx.iterate_on = 0;
|
||||
for (i = 0; i < NUM_THREADS; i++)
|
||||
ASSERT_EQ(pthread_join(self->threads[i], NULL), 0);
|
||||
EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
|
||||
|
||||
EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
|
||||
EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
|
||||
EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
|
|
|||
|
|
@ -4839,6 +4839,12 @@ struct compat_kvm_clear_dirty_log {
|
|||
};
|
||||
};
|
||||
|
||||
long __weak kvm_arch_vm_compat_ioctl(struct file *filp, unsigned int ioctl,
|
||||
unsigned long arg)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
static long kvm_vm_compat_ioctl(struct file *filp,
|
||||
unsigned int ioctl, unsigned long arg)
|
||||
{
|
||||
|
|
@ -4847,6 +4853,11 @@ static long kvm_vm_compat_ioctl(struct file *filp,
|
|||
|
||||
if (kvm->mm != current->mm || kvm->vm_dead)
|
||||
return -EIO;
|
||||
|
||||
r = kvm_arch_vm_compat_ioctl(filp, ioctl, arg);
|
||||
if (r != -ENOTTY)
|
||||
return r;
|
||||
|
||||
switch (ioctl) {
|
||||
#ifdef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||
case KVM_CLEAR_DIRTY_LOG: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user