Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fixes from Will Deacon:
 "A mixture of ptdump, compat and MTE fixes that came in during the
  merge window:

   - Fix address handling of final memory region in ptdump

   - Fix emulation of decrementing load/store multiple from 32-bit task

   - Fix SCTLR context-switching for store-only MTE mode

   - Fix numerous issues in MTE selftests"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  selftests/arm64: Add MTE test config fragment
  selftests/arm64: Fix MTE prctl TAP plan
  selftests/arm64: Treat KSM merge_across_nodes as optional
  selftests/arm64: Print missing MTE TAP headers
  arm64: compat: Fix decrementing LDM/STM alignment emulation
  arm64: process: Fix context switching MTE store-only tag check
  KVM: arm64: ptdump: Flush the last region
  arm64: ptdump: Make note_page_flush() range aware
This commit is contained in:
Linus Torvalds
2026-08-28 09:02:04 -07:00
15 changed files with 84 additions and 12 deletions

View File

@@ -264,7 +264,7 @@ static inline void task_set_sve_vl_onexec(struct task_struct *task,
#define SCTLR_USER_MASK \
(SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB | \
SCTLR_EL1_TCF0_MASK)
SCTLR_EL1_TCF0_MASK | SCTLR_EL1_TCSO0_MASK)
static inline void arch_thread_struct_whitelist(unsigned long *offset,
unsigned long *size)

View File

@@ -50,6 +50,8 @@ struct ptdump_pg_state {
const struct addr_marker *marker;
const struct mm_struct *mm;
unsigned long start_address;
/* exclusive end, ULONG_MAX represents an end at 1 << 64 */
unsigned long end_address;
int level;
ptval_t current_prot;
bool check_wx;

View File

@@ -114,8 +114,8 @@ do_alignment_ldrdstrd(unsigned long addr, u32 instr, struct pt_regs *regs)
static int
do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs)
{
unsigned int rd, rn, nr_regs, regbits;
unsigned long eaddr, newaddr;
unsigned int rd, rn, regbits;
unsigned long eaddr, newaddr, nr_regs;
unsigned int val;
/* count the number of registers in the mask to be transferred */

View File

@@ -130,7 +130,7 @@ static struct kvm_ptdump_guest_state *kvm_ptdump_parser_create(struct kvm_s2_mmu
}
st->ipa_marker[0].name = "Guest IPA";
st->ipa_marker[1].start_address = BIT(pgtable->ia_bits);
st->ipa_marker[1].start_address = ULONG_MAX;
st->mmu = mmu;
return st;
@@ -148,18 +148,21 @@ static int kvm_ptdump_guest_show(struct seq_file *m, void *unused)
.flags = KVM_PGTABLE_WALK_LEAF,
};
guard(write_lock)(&kvm->mmu_lock);
st->parser_state = (struct ptdump_pg_state) {
.marker = &st->ipa_marker[0],
.end_address = BIT(mmu->pgt->ia_bits),
.level = -1,
.pg_level = &st->level[0],
.seq = m,
};
write_lock(&kvm->mmu_lock);
ret = kvm_pgtable_walk(mmu->pgt, 0, BIT(mmu->pgt->ia_bits), &walker);
write_unlock(&kvm->mmu_lock);
if (ret)
return ret;
note_page_flush(&st->parser_state.ptdump);
return ret;
return 0;
}
static int kvm_ptdump_guest_open(struct inode *m, struct file *file)

View File

@@ -278,9 +278,19 @@ void note_page_pgd(struct ptdump_state *pt_st, unsigned long addr, pgd_t pgd)
void note_page_flush(struct ptdump_state *pt_st)
{
struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump);
unsigned long end = st->end_address;
pte_t pte_zero = {0};
note_page(pt_st, 0, -1, pte_val(pte_zero));
/*
* Address spaces that end at 1 << 64 have end_address == ULONG_MAX,
* but note_page() expects the exclusive end. In this case adjust end
* to the wraparound value 0.
*/
if (end == ULONG_MAX)
end = 0;
note_page(pt_st, end, -1, pte_val(pte_zero));
}
void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
@@ -296,6 +306,7 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
.marker = info->markers,
.mm = info->mm,
.pg_level = &kernel_pg_levels[0],
.end_address = end,
.level = -1,
.ptdump = {
.note_page_pte = note_page_pte,
@@ -337,6 +348,7 @@ bool ptdump_check_wx(void)
{ -1, NULL},
},
.pg_level = &kernel_pg_levels[0],
.end_address = ~0UL,
.level = -1,
.check_wx = true,
.ptdump = {

View File

@@ -0,0 +1,17 @@
CONFIG_ARM64_BTI=y
CONFIG_ARM64_GCS=y
CONFIG_ARM64_MTE=y
CONFIG_ARM64_POE=y
CONFIG_ARM64_PTR_AUTH=y
CONFIG_ARM64_SME=y
CONFIG_ARM64_SVE=y
CONFIG_ARM64_TAGGED_ADDR_ABI=y
CONFIG_HUGETLBFS=y
CONFIG_KSM=y
CONFIG_PROC_FS=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
CONFIG_SHMEM=y
CONFIG_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y

View File

@@ -406,6 +406,8 @@ int main(int argc, char *argv[])
size_t page_size = getpagesize();
int item = ARRAY_SIZE(sizes);
ksft_print_header();
sizes[item - 3] = page_size - 1;
sizes[item - 2] = page_size;
sizes[item - 1] = page_size + 1;

View File

@@ -146,6 +146,8 @@ int main(int argc, char *argv[])
int err;
int item = ARRAY_SIZE(sizes);
ksft_print_header();
page_size = getpagesize();
if (!page_size) {
ksft_print_msg("ERR: Unable to get page size\n");

View File

@@ -131,6 +131,7 @@ int main(int argc, char *argv[])
if (err)
return err;
ksft_print_header();
ksft_set_plan(1);
evaluate_test(mte_gcr_fork_test(),

View File

@@ -230,6 +230,8 @@ int main(int argc, char *argv[])
void *map_ptr;
unsigned long map_size;
ksft_print_header();
err = mte_default_setup();
if (err)
return err;

View File

@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -22,6 +23,20 @@
static size_t page_sz;
static unsigned long ksm_sysfs[5];
static bool has_merge_across_nodes;
static bool merge_across_nodes_available(void)
{
const char *path = PATH_KSM "merge_across_nodes";
if (!access(path, R_OK | W_OK))
return true;
if (errno == ENOENT)
return false;
ksft_exit_skip("Unable to read and write %s: %s\n", path,
strerror(errno));
}
static unsigned long read_sysfs(char *str)
{
@@ -56,8 +71,10 @@ static void write_sysfs(char *str, unsigned long val)
static void mte_ksm_setup(void)
{
ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
write_sysfs(PATH_KSM "merge_across_nodes", 1);
if (has_merge_across_nodes) {
ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
write_sysfs(PATH_KSM "merge_across_nodes", 1);
}
ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");
write_sysfs(PATH_KSM "sleep_millisecs", 0);
ksm_sysfs[2] = read_sysfs(PATH_KSM "run");
@@ -70,7 +87,8 @@ static void mte_ksm_setup(void)
static void mte_ksm_restore(void)
{
write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
if (has_merge_across_nodes)
write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);
write_sysfs(PATH_KSM "run", ksm_sysfs[2]);
write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);
@@ -132,9 +150,16 @@ int main(int argc, char *argv[])
{
int err;
ksft_print_header();
err = mte_default_setup();
if (err)
return err;
if (geteuid() != 0)
ksft_exit_skip("Please run the test as root\n");
has_merge_across_nodes = merge_across_nodes_available();
page_sz = getpagesize();
if (!page_sz) {
ksft_print_msg("ERR: Unable to get page size\n");

View File

@@ -945,6 +945,8 @@ int main(int argc, char *argv[])
},
};
ksft_print_header();
err = mte_default_setup();
if (err)
return err;

View File

@@ -119,7 +119,7 @@ int main(void)
int i;
ksft_print_header();
ksft_set_plan(ARRAY_SIZE(mte_modes));
ksft_set_plan(ARRAY_SIZE(mte_modes) + 1);
check_basic_read();
for (i = 0; i < ARRAY_SIZE(mte_modes); i++)

View File

@@ -175,6 +175,8 @@ int main(int argc, char *argv[])
{
int err;
ksft_print_header();
err = mte_default_setup();
if (err)
return err;

View File

@@ -201,6 +201,8 @@ int main(int argc, char *argv[])
int tag_offsets[] = {page_sz, MT_GRANULE_SIZE};
char test_name[TEST_NAME_MAX];
ksft_print_header();
page_sz = getpagesize();
if (!page_sz) {
ksft_print_msg("ERR: Unable to get page size\n");