summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm64/kvm/mmu.c5
-rw-r--r--arch/loongarch/kernel/smp.c1
-rw-r--r--arch/mips/dec/prom/console.c7
-rw-r--r--arch/mips/kernel/smp.c2
-rw-r--r--arch/riscv/include/asm/cacheflush.h25
-rw-r--r--arch/riscv/include/asm/kfence.h7
-rw-r--r--arch/riscv/kernel/entry.S6
-rw-r--r--arch/x86/kvm/hyperv.c5
-rw-r--r--arch/x86/kvm/mmu/mmu.c28
-rw-r--r--arch/x86/kvm/svm/sev.c1
10 files changed, 60 insertions, 27 deletions
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 0d38dc72dfc6..403a63548351 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1444,6 +1444,11 @@ static void sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn,
if (!kvm_has_mte(kvm))
return;
+ if (is_zero_pfn(pfn)) {
+ WARN_ON_ONCE(nr_pages != 1);
+ return;
+ }
+
if (folio_test_hugetlb(folio)) {
/* Hugetlb has MTE flags set on head page only */
if (folio_try_hugetlb_mte_tagging(folio)) {
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 46036d98da75..5d6a60294fb2 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -688,6 +688,7 @@ static void stop_this_cpu(void *dummy)
set_cpu_online(smp_processor_id(), false);
calculate_cpu_foreign_map();
local_irq_disable();
+ rcutree_report_cpu_dead();
while (true);
}
diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c
index 31a8441d8431..b4f0dba3fa20 100644
--- a/arch/mips/dec/prom/console.c
+++ b/arch/mips/dec/prom/console.c
@@ -2,8 +2,9 @@
/*
* DECstation PROM-based early console support.
*
- * Copyright (C) 2004, 2007 Maciej W. Rozycki
+ * Copyright (C) 2004, 2007, 2026 Maciej W. Rozycki
*/
+#include <linux/bug.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -14,9 +15,11 @@
static void __init prom_console_write(struct console *con, const char *s,
unsigned int c)
{
- char buf[81];
+ static char buf[81] __initdata = { 0 };
unsigned int chunk = sizeof(buf) - 1;
+ BUG_ON((long)buf != (int)(long)buf);
+
while (c > 0) {
if (chunk > c)
chunk = c;
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 4868e79f3b30..0f28b4a62e72 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -20,6 +20,7 @@
#include <linux/sched/mm.h>
#include <linux/cpumask.h>
#include <linux/cpu.h>
+#include <linux/rcupdate.h>
#include <linux/err.h>
#include <linux/ftrace.h>
#include <linux/irqdomain.h>
@@ -422,6 +423,7 @@ static void stop_this_cpu(void *dummy)
set_cpu_online(smp_processor_id(), false);
calculate_cpu_foreign_map();
local_irq_disable();
+ rcutree_report_cpu_dead();
while (1);
}
diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h
index 0092513c3376..b1a2ac665792 100644
--- a/arch/riscv/include/asm/cacheflush.h
+++ b/arch/riscv/include/asm/cacheflush.h
@@ -43,20 +43,23 @@ do { \
#ifdef CONFIG_64BIT
extern u64 new_vmalloc[NR_CPUS / sizeof(u64) + 1];
extern char _end[];
+static inline void mark_new_valid_map(void)
+{
+ int i;
+
+ /*
+ * We don't care if concurrently a cpu resets this value since
+ * the only place this can happen is in handle_exception() where
+ * an sfence.vma is emitted.
+ */
+ for (i = 0; i < ARRAY_SIZE(new_vmalloc); ++i)
+ new_vmalloc[i] = -1ULL;
+}
#define flush_cache_vmap flush_cache_vmap
static inline void flush_cache_vmap(unsigned long start, unsigned long end)
{
- if (is_vmalloc_or_module_addr((void *)start)) {
- int i;
-
- /*
- * We don't care if concurrently a cpu resets this value since
- * the only place this can happen is in handle_exception() where
- * an sfence.vma is emitted.
- */
- for (i = 0; i < ARRAY_SIZE(new_vmalloc); ++i)
- new_vmalloc[i] = -1ULL;
- }
+ if (is_vmalloc_or_module_addr((void *)start))
+ mark_new_valid_map();
}
#define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end)
#endif
diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h
index d08bf7fb3aee..29cb3a6ee113 100644
--- a/arch/riscv/include/asm/kfence.h
+++ b/arch/riscv/include/asm/kfence.h
@@ -6,6 +6,7 @@
#include <linux/kfence.h>
#include <linux/pfn.h>
#include <asm-generic/pgalloc.h>
+#include <asm/cacheflush.h>
#include <asm/pgtable.h>
static inline bool arch_kfence_init_pool(void)
@@ -17,10 +18,12 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect)
{
pte_t *pte = virt_to_kpte(addr);
- if (protect)
+ if (protect) {
set_pte(pte, __pte(pte_val(ptep_get(pte)) & ~_PAGE_PRESENT));
- else
+ } else {
set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT));
+ mark_new_valid_map();
+ }
preempt_disable();
local_flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 9b9dec6893b8..e7bd03a9ced5 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -107,8 +107,10 @@ SYM_CODE_START(handle_exception)
#ifdef CONFIG_64BIT
/*
- * The RISC-V kernel does not eagerly emit a sfence.vma after each
- * new vmalloc mapping, which may result in exceptions:
+ * The RISC-V kernel does not flush TLBs on all CPUS after each new
+ * vmalloc mapping or kfence_unprotect(), which may result in
+ * exceptions:
+ *
* - if the uarch caches invalid entries, the new mapping would not be
* observed by the page table walker and an invalidation is needed.
* - if the uarch does not cache invalid entries, a reordered access
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index f279561154bc..4ebb3c40c6bb 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -1839,6 +1839,11 @@ static bool hv_is_vp_in_sparse_set(u32 vp_id, u64 valid_bank_mask, u64 sparse_ba
int valid_bit_nr = vp_id / HV_VCPUS_PER_SPARSE_BANK;
unsigned long sbank;
+ BUILD_BUG_ON(BITS_PER_TYPE(valid_bank_mask) != HV_MAX_SPARSE_VCPU_BANKS);
+
+ if (valid_bit_nr >= HV_MAX_SPARSE_VCPU_BANKS)
+ return false;
+
if (!test_bit(valid_bit_nr, (unsigned long *)&valid_bank_mask))
return false;
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 0bd0cb8992c9..eadeca9786f6 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -2453,13 +2453,15 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
u64 *sptep, gfn_t gfn,
bool direct, unsigned int access)
{
- union kvm_mmu_page_role role;
+ union kvm_mmu_page_role role = kvm_mmu_child_role(sptep, direct, access);
- if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
- spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
+ if (is_shadow_present_pte(*sptep) &&
+ !is_large_pte(*sptep) &&
+ spte_to_child_sp(*sptep) &&
+ spte_to_child_sp(*sptep)->gfn == gfn &&
+ spte_to_child_sp(*sptep)->role.word == role.word)
return ERR_PTR(-EEXIST);
- role = kvm_mmu_child_role(sptep, direct, access);
return kvm_mmu_get_shadow_page(vcpu, gfn, role);
}
@@ -7179,13 +7181,19 @@ restart:
sp = sptep_to_sp(sptep);
/*
- * We cannot do huge page mapping for indirect shadow pages,
- * which are found on the last rmap (level = 1) when not using
- * tdp; such shadow pages are synced with the page table in
- * the guest, and the guest page table is using 4K page size
- * mapping if the indirect sp has level = 1.
+ * Direct shadow page can be replaced by a hugepage if the host
+ * mapping level allows it and the memslot maps all of the host
+ * hugepage. Note! If the memslot maps only part of the
+ * hugepage, sp->gfn may be below slot->base_gfn, and querying
+ * the max mapping level would cause an out-of-bounds lpage_info
+ * access. So the gfn bounds check *must* be done first.
+ *
+ * Indirect shadow pages are created when the guest page tables
+ * are using 4K pages. Since the host mapping is always
+ * constrained by the page size in the guest, indirect shadow
+ * pages are never collapsible.
*/
- if (sp->role.direct &&
+ if (sp->role.direct && is_gfn_in_memslot(slot, sp->gfn) &&
sp->role.level < kvm_mmu_max_mapping_level(kvm, NULL, slot, sp->gfn)) {
kvm_zap_one_rmap_spte(kvm, rmap_head, sptep);
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 6d4574eb8a4c..8b807f8eb067 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -1340,6 +1340,7 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
s_off = vaddr & ~PAGE_MASK;
d_off = dst_vaddr & ~PAGE_MASK;
len = min_t(size_t, (PAGE_SIZE - s_off), size);
+ len = min_t(size_t, len, PAGE_SIZE - d_off);
if (dec)
ret = __sev_dbg_decrypt_user(kvm,