summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-30 11:31:01 +0000
committerMark Brown <broonie@kernel.org>2026-10-30 11:31:01 +0000
commit4e40f1ef79584fe42f420c809fe80fcf23a4d1ba (patch)
treeaef4a33470000d8a53cb18e730c8a9fe022db9c8
parentd2d6acfbd25859ba59489875e228ee4739af0590 (diff)
parentd957b367d560c4a74637d400ca4e0e63bbdfbcd1 (diff)
downloadlinux-next-4e40f1ef79584fe42f420c809fe80fcf23a4d1ba.tar.gz
linux-next-4e40f1ef79584fe42f420c809fe80fcf23a4d1ba.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc.git
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/include/asm/cacheflush_64.h9
-rw-r--r--arch/sparc/include/asm/highmem.h3
-rw-r--r--arch/sparc/include/asm/leon.h2
-rw-r--r--arch/sparc/include/asm/page_32.h16
-rw-r--r--arch/sparc/include/asm/pgtable_32.h3
-rw-r--r--arch/sparc/include/asm/pgtable_64.h8
-rw-r--r--arch/sparc/include/asm/pgtsrmmu.h1
-rw-r--r--arch/sparc/include/asm/seccomp.h15
-rw-r--r--arch/sparc/include/asm/syscall.h11
-rw-r--r--arch/sparc/include/asm/thread_info_32.h2
-rw-r--r--arch/sparc/include/asm/thread_info_64.h15
-rw-r--r--arch/sparc/kernel/entry.S42
-rw-r--r--arch/sparc/kernel/entry.h2
-rw-r--r--arch/sparc/kernel/head_32.S2
-rw-r--r--arch/sparc/kernel/kernel.h3
-rw-r--r--arch/sparc/kernel/nmi.c2
-rw-r--r--arch/sparc/kernel/ptrace_32.c26
-rw-r--r--arch/sparc/kernel/ptrace_64.c28
-rw-r--r--arch/sparc/kernel/setup_32.c91
-rw-r--r--arch/sparc/kernel/smp_64.c51
-rw-r--r--arch/sparc/kernel/syscalls.S28
-rw-r--r--arch/sparc/kernel/time_64.c6
-rw-r--r--arch/sparc/kernel/tsb.S24
-rw-r--r--arch/sparc/kernel/urtt_fill.S10
-rw-r--r--arch/sparc/mm/fault_32.c32
-rw-r--r--arch/sparc/mm/fault_64.c9
-rw-r--r--arch/sparc/mm/init_32.c167
-rw-r--r--arch/sparc/mm/init_64.c65
-rw-r--r--arch/sparc/mm/leon_mm.c1
-rw-r--r--arch/sparc/mm/srmmu.c70
-rw-r--r--arch/sparc/mm/tlb.c2
-rw-r--r--arch/sparc/mm/ultra.S25
-rw-r--r--arch/sparc/mm/viking.S6
-rw-r--r--arch/sparc/prom/memory.c51
-rw-r--r--tools/testing/selftests/seccomp/seccomp_bpf.c52
36 files changed, 481 insertions, 401 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 742ffff8c37f..29efac409a1a 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -23,7 +23,7 @@ config SPARC
select HAVE_ASM_MODVERSIONS
select HAVE_ARCH_KGDB if !SMP || SPARC64
select HAVE_ARCH_TRACEHOOK
- select HAVE_ARCH_SECCOMP if SPARC64
+ select HAVE_ARCH_SECCOMP_FILTER
select HAVE_EXIT_THREAD
select HAVE_PCI
select SYSCTL_EXCEPTION_TRACE
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
index 06092572c045..54a2d37008e6 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -38,11 +38,12 @@ void __flush_dcache_page(void *addr, int flush_icache);
void flush_dcache_folio_impl(struct folio *folio);
#ifdef CONFIG_SMP
void smp_flush_dcache_folio_impl(struct folio *folio, int cpu);
-void flush_dcache_folio_all(struct mm_struct *mm, struct folio *folio);
#else
#define smp_flush_dcache_folio_impl(folio, cpu) flush_dcache_folio_impl(folio)
-#define flush_dcache_folio_all(mm, folio) flush_dcache_folio_impl(folio)
#endif
+void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
+void __flush_dcache_all(unsigned long size, unsigned long line_size);
+void flush_dcache_all(void);
void __flush_dcache_range(unsigned long start, unsigned long end);
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
@@ -74,9 +75,9 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *,
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-#define flush_cache_vmap(start, end) do { } while (0)
+void flush_cache_vmap(unsigned long start, unsigned long end);
#define flush_cache_vmap_early(start, end) do { } while (0)
-#define flush_cache_vunmap(start, end) do { } while (0)
+#define flush_cache_vunmap(start, end) flush_cache_vmap(start, end)
#endif /* !__ASSEMBLER__ */
diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h
index c7b2e208328b..b1b915ac604d 100644
--- a/arch/sparc/include/asm/highmem.h
+++ b/arch/sparc/include/asm/highmem.h
@@ -26,9 +26,6 @@
#include <asm/vaddrs.h>
#include <asm/pgtsrmmu.h>
-/* declarations for highmem.c */
-extern unsigned long highstart_pfn, highend_pfn;
-
#define kmap_prot __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE)
extern pte_t *pkmap_page_table;
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index 053a24b67aed..2a1bdc2c2f1d 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -251,7 +251,7 @@ extern int leon_ipi_irq;
/* macros used in leon_mm.c */
#define PFN(x) ((x) >> PAGE_SHIFT)
-#define _pfn_valid(pfn) ((pfn < last_valid_pfn) && (pfn >= PFN(phys_base)))
+#define _pfn_valid(pfn) ((pfn < max_pfn) && (pfn >= PFN(phys_base)))
#define _SRMMU_PTE_PMASK_LEON 0xffffffff
/*
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index 9f0b54f70908..7429291fb118 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -28,22 +28,6 @@
(void)(vaddr); \
} while (0)
-/* The following structure is used to hold the physical
- * memory configuration of the machine. This is filled in
- * prom_meminit() and is later used by mem_init() to set up
- * mem_map[]. We statically allocate SPARC_PHYS_BANKS+1 of
- * these structs, this is arbitrary. The entry after the
- * last valid one has num_bytes==0.
- */
-struct sparc_phys_banks {
- unsigned long base_addr;
- unsigned long num_bytes;
-};
-
-#define SPARC_PHYS_BANKS 32
-
-extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
-
/* passing structs on the Sparc slow us down tremendously... */
/* #define STRICT_MM_TYPECHECKS */
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 5a5f54a090f5..749bed304efe 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -37,8 +37,7 @@ struct vm_area_struct;
struct page;
void load_mmu(void);
-unsigned long calc_highpages(void);
-unsigned long __init bootmem_init(unsigned long *pages_avail);
+void __init find_ramdisk(unsigned long end_of_phys_memory);
#define PTRS_PER_PTE 64
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 44d1333065a6..c26f2888aa18 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -936,6 +936,10 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
set_pte_at((mm), (addr), (ptep), __pte(0UL))
#ifdef DCACHE_ALIASING_POSSIBLE
+/* This flushes only the page the PTE maps, so it relies on move_ptes()
+ * calling it for one PTE at a time, which the default pte_batch_hint()
+ * guarantees.
+ */
#define __HAVE_ARCH_MOVE_PTE
#define move_pte(pte, old_addr, new_addr) \
({ \
@@ -945,8 +949,8 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
\
if (pfn_valid(this_pfn) && \
(((old_addr) ^ (new_addr)) & (1 << 13))) \
- flush_dcache_folio_all(current->mm, \
- page_folio(pfn_to_page(this_pfn))); \
+ flush_dcache_page_all(current->mm, \
+ pfn_to_page(this_pfn)); \
} \
newpte; \
})
diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h
index a265822a475e..a2a6c8564c3e 100644
--- a/arch/sparc/include/asm/pgtsrmmu.h
+++ b/arch/sparc/include/asm/pgtsrmmu.h
@@ -98,7 +98,6 @@
restore %g0, %g0, %g0;
#ifndef __ASSEMBLER__
-extern unsigned long last_valid_pfn;
/* This makes sense. Honest it does - Anton */
/* XXX Yes but it's ugly as sin. FIXME. -KMW */
diff --git a/arch/sparc/include/asm/seccomp.h b/arch/sparc/include/asm/seccomp.h
index 62d4579efb1a..1ea70080f5cd 100644
--- a/arch/sparc/include/asm/seccomp.h
+++ b/arch/sparc/include/asm/seccomp.h
@@ -6,6 +6,21 @@
#define __NR_seccomp_sigreturn_32 __NR_sigreturn
+#ifdef CONFIG_SPARC64
+# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_SPARC64
+# define SECCOMP_ARCH_NATIVE_NR NR_syscalls
+# define SECCOMP_ARCH_NATIVE_NAME "sparc64"
+# ifdef CONFIG_COMPAT
+# define SECCOMP_ARCH_COMPAT AUDIT_ARCH_SPARC
+# define SECCOMP_ARCH_COMPAT_NR NR_syscalls
+# define SECCOMP_ARCH_COMPAT_NAME "sparc"
+# endif
+#else
+# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_SPARC
+# define SECCOMP_ARCH_NATIVE_NR NR_syscalls
+# define SECCOMP_ARCH_NATIVE_NAME "sparc"
+#endif
+
#include <asm-generic/seccomp.h>
#endif /* _ASM_SECCOMP_H */
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
index b0233924d323..fc225f2ee23c 100644
--- a/arch/sparc/include/asm/syscall.h
+++ b/arch/sparc/include/asm/syscall.h
@@ -40,12 +40,11 @@ static inline void syscall_set_nr(struct task_struct *task,
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
- /* XXX This needs some thought. On Sparc we don't
- * XXX save away the original %o0 value somewhere.
- * XXX Instead we hold it in register %l5 at the top
- * XXX level trap frame and pass this down to the signal
- * XXX dispatch code which is the only place that value
- * XXX ever was needed.
+ /* Every caller rolls back before the syscall has been invoked
+ * (a ptrace entry abort or a seccomp user notification), and at
+ * that point the arguments in pt_regs are still intact: the
+ * return value only overwrites u_regs[UREG_I0] once the syscall
+ * has actually run. Nothing to undo.
*/
}
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index fdaf7b171e0a..b51b080f1810 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -110,6 +110,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define TIF_POLLING_NRFLAG 9 /* true if poll_idle() is polling
* TIF_NEED_RESCHED */
#define TIF_MEMDIE 10 /* is terminating due to OOM killer */
+#define TIF_SECCOMP 11 /* secure computing */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -119,6 +120,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | \
_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h
index c8a73dff27f8..3518ea8b1b5e 100644
--- a/arch/sparc/include/asm/thread_info_64.h
+++ b/arch/sparc/include/asm/thread_info_64.h
@@ -99,13 +99,8 @@ struct thread_info {
#define FAULT_CODE_BLKCOMMIT 0x10 /* Use blk-commit ASI in copy_page */
#define FAULT_CODE_BAD_RA 0x20 /* Bad RA for sun4v */
-#if PAGE_SHIFT == 13
-#define THREAD_SIZE (2*PAGE_SIZE)
-#define THREAD_SHIFT (PAGE_SHIFT + 1)
-#else /* PAGE_SHIFT == 13 */
-#define THREAD_SIZE PAGE_SIZE
-#define THREAD_SHIFT PAGE_SHIFT
-#endif /* PAGE_SHIFT == 13 */
+#define THREAD_SIZE (4*PAGE_SIZE)
+#define THREAD_SHIFT (PAGE_SHIFT + 2)
/*
* macros/functions for gaining access to the thread information structure
@@ -128,11 +123,7 @@ extern struct thread_info *current_thread_info(void);
#endif
/* thread information allocation */
-#if PAGE_SHIFT == 13
-#define THREAD_SIZE_ORDER 1
-#else /* PAGE_SHIFT == 13 */
-#define THREAD_SIZE_ORDER 0
-#endif /* PAGE_SHIFT == 13 */
+#define THREAD_SIZE_ORDER 2
#define __thread_flag_byte_ptr(ti) \
((unsigned char *)(&((ti)->flags)))
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index ea51ef52c952..a0c444ea1107 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -252,7 +252,8 @@ smp4m_ticker:
WRITE_PAUSE
call smp4m_percpu_timer_interrupt
add %sp, STACKFRAME_SZ, %o0
- wr %l0, PSR_ET, %psr
+ or %l0, PSR_PIL, %g2 ! keep PIL raised until rett
+ wr %g2, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL
@@ -353,7 +354,8 @@ smp4d_ticker:
WRITE_PAUSE
call smp4d_percpu_timer_interrupt
add %sp, STACKFRAME_SZ, %o0
- wr %l0, PSR_ET, %psr
+ or %l0, PSR_PIL, %g2 ! keep PIL raised until rett
+ wr %g2, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL
@@ -407,7 +409,8 @@ smpleon_ipi:
WRITE_PAUSE
call leonsmp_ipi_interrupt
add %sp, STACKFRAME_SZ, %o1 ! pt_regs
- wr %l0, PSR_ET, %psr
+ or %l0, PSR_PIL, %g2 ! keep PIL raised until rett
+ wr %g2, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL
@@ -825,8 +828,8 @@ sys_sigreturn:
be 1f
nop
- call syscall_trace
- mov 1, %o1
+ call syscall_trace_leave
+ nop
1:
/* We don't want to muck with user registers like a
@@ -845,9 +848,8 @@ sys_rt_sigreturn:
be 1f
nop
- add %sp, STACKFRAME_SZ, %o0
- call syscall_trace
- mov 1, %o1
+ call syscall_trace_leave
+ add %sp, STACKFRAME_SZ, %o0
1:
/* We are returning to a signal handler. */
@@ -929,12 +931,11 @@ linux_sparc_ni_syscall:
or %l7, %lo(sys_ni_syscall), %l7
linux_syscall_trace:
- add %sp, STACKFRAME_SZ, %o0
- call syscall_trace
- mov 0, %o1
- cmp %o0, 0
- bne 3f
- mov -ENOSYS, %o0
+ call syscall_trace_enter
+ add %sp, STACKFRAME_SZ, %o0
+ cmp %o0, -1
+ be linux_syscall_trace_exit
+ nop
/* Syscall tracing can modify the registers. */
ld [%sp + STACKFRAME_SZ + PT_G1], %g1
@@ -1006,7 +1007,7 @@ do_syscall:
ld [%curptr + TI_FLAGS], %l5
mov %i3, %o3
- andcc %l5, _TIF_SYSCALL_TRACE, %g0
+ andcc %l5, _TIF_SYSCALL_TRACE | _TIF_SECCOMP, %g0
mov %i4, %o4
bne linux_syscall_trace
mov %i0, %l6
@@ -1049,11 +1050,14 @@ ret_sys_call:
b ret_trap_entry
st %l2, [%sp + STACKFRAME_SZ + PT_NPC]
+linux_syscall_trace_exit:
+ /* The syscall was skipped - exit tracing */
+ ld [%sp + STACKFRAME_SZ + PT_NPC], %l1
+
linux_syscall_trace2:
- add %sp, STACKFRAME_SZ, %o0
- mov 1, %o1
- call syscall_trace
- add %l1, 0x4, %l2 /* npc = npc+4 */
+ call syscall_trace_leave
+ add %sp, STACKFRAME_SZ, %o0
+ add %l1, 0x4, %l2 /* npc = npc+4 */
st %l1, [%sp + STACKFRAME_SZ + PT_PC]
b ret_trap_entry
st %l2, [%sp + STACKFRAME_SZ + PT_NPC]
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index c746c0fd5d6b..734a649301ea 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -82,7 +82,7 @@ void do_notify_resume(struct pt_regs *regs,
unsigned long orig_i0,
unsigned long thread_info_flags);
-asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+asmlinkage long syscall_trace_enter(struct pt_regs *regs);
asmlinkage void syscall_trace_leave(struct pt_regs *regs);
void bad_trap_tl1(struct pt_regs *regs, long lvl);
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S
index 8c320fa25a67..11a1746829a4 100644
--- a/arch/sparc/kernel/head_32.S
+++ b/arch/sparc/kernel/head_32.S
@@ -69,7 +69,7 @@ sun4e_notsup:
*/
.ascii "HdrS"
.word LINUX_VERSION_CODE
- .half 0x0203 /* HdrS version */
+ .half 0x0300 /* HdrS version */
root_flags:
.half 1
root_dev:
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 4ee85051521a..e215157d5120 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -172,7 +172,8 @@ asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr,
unsigned long sp);
/* ptrace_32.c */
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+asmlinkage void syscall_trace_leave(struct pt_regs *regs);
/* unaligned_32.c */
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn);
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c
index 149adc094753..1571d629863f 100644
--- a/arch/sparc/kernel/nmi.c
+++ b/arch/sparc/kernel/nmi.c
@@ -41,7 +41,7 @@ static int panic_on_timeout;
* <0: the NMI watchdog has not been set up, and cannot be enabled
* 0: the NMI watchdog is disabled, but can be enabled
*/
-atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+atomic_t nmi_active = ATOMIC_INIT(0);
EXPORT_SYMBOL(nmi_active);
static int nmi_init_done;
static unsigned int nmi_hz = HZ;
diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c
index 5991b1731fee..25d10c1b075f 100644
--- a/arch/sparc/kernel/ptrace_32.c
+++ b/arch/sparc/kernel/ptrace_32.c
@@ -24,6 +24,7 @@
#include <linux/uaccess.h>
#include <asm/cacheflush.h>
+#include <asm/syscall.h>
#include "kernel.h"
@@ -433,16 +434,23 @@ long arch_ptrace(struct task_struct *child, long request,
return ret;
}
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
- int ret = 0;
-
- if (test_thread_flag(TIF_SYSCALL_TRACE)) {
- if (syscall_exit_p)
- ptrace_report_syscall_exit(regs, 0);
- else
- ret = !ptrace_report_syscall_permit_entry(regs);
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ !ptrace_report_syscall_permit_entry(regs)) {
+ syscall_set_return_value(current, regs, -ENOSYS, 0);
+ return -1;
}
- return ret;
+ /* Do seccomp after ptrace; syscall may have changed. */
+ if (!seccomp_permit_syscall())
+ return -1;
+
+ return 0;
+}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ ptrace_report_syscall_exit(regs, 0);
}
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index 825ddf55fece..6f4a005e674f 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -38,6 +38,7 @@
#include <asm/page.h>
#include <asm/cpudata.h>
#include <asm/cacheflush.h>
+#include <asm/syscall.h>
#define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h>
@@ -1082,18 +1083,27 @@ long arch_ptrace(struct task_struct *child, long request,
return ret;
}
-asmlinkage int syscall_trace_enter(struct pt_regs *regs)
+/*
+ * Returns 0 to let the syscall through, or -1 to skip it. On skip the
+ * return value and the carry bit have already been set in pt_regs; the
+ * assembler caller must return through the syscall exit work without
+ * writing to them.
+ */
+asmlinkage long syscall_trace_enter(struct pt_regs *regs)
{
- int ret = 0;
-
- /* do the secure computing check first */
- secure_computing_strict(regs->u_regs[UREG_G1]);
-
if (test_thread_flag(TIF_NOHZ))
user_exit();
- if (test_thread_flag(TIF_SYSCALL_TRACE))
- ret = !ptrace_report_syscall_permit_entry(regs);
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ !ptrace_report_syscall_permit_entry(regs)) {
+ /* The tracer aborted the syscall. */
+ syscall_set_return_value(current, regs, -ENOSYS, 0);
+ return -1;
+ }
+
+ /* Do seccomp after ptrace, to catch any tracer changes. */
+ if (!seccomp_permit_syscall())
+ return -1;
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->u_regs[UREG_G1]);
@@ -1102,7 +1112,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
regs->u_regs[UREG_I1], regs->u_regs[UREG_I2],
regs->u_regs[UREG_I3]);
- return ret;
+ return 0;
}
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
index 1b0db16cd37b..246533fba60d 100644
--- a/arch/sparc/kernel/setup_32.c
+++ b/arch/sparc/kernel/setup_32.c
@@ -23,6 +23,7 @@
#include <linux/syscalls.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
+#include <linux/memblock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -254,6 +255,78 @@ static __init void leon_patch(void)
struct tt_entry *sparc_ttable;
+unsigned long phys_base;
+EXPORT_SYMBOL(phys_base);
+
+unsigned long pfn_base;
+EXPORT_SYMBOL(pfn_base);
+
+static unsigned long __init calc_max_low_pfn(void)
+{
+ unsigned long limit = pfn_base + PHYS_PFN(SRMMU_MAXMEM);
+ unsigned long start_pfn, end_pfn;
+ unsigned long last_pfn = 0;
+ int i;
+
+ for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) {
+ if (start_pfn >= limit) {
+ if (last_pfn < limit)
+ limit = last_pfn;
+ break;
+ }
+
+ last_pfn = end_pfn;
+ }
+
+ return limit;
+}
+
+static void __init setup_memory(void)
+{
+ unsigned long ram_base = memblock_start_of_DRAM();
+ unsigned long size;
+
+ memblock_set_bottom_up(true);
+ memblock_allow_resize();
+
+ phys_base = ram_base;
+ /* phys_base must describe what PAGE_OFFSET maps to, not where RAM starts. */
+ if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d) {
+ unsigned long real_base = __get_phys(PAGE_OFFSET);
+
+ prom_printf("phys_base: RAM starts at 0x%lx, kernel is at 0x%lx\n",
+ phys_base, real_base);
+
+ if (real_base && real_base != phys_base) {
+ phys_base = real_base;
+ memblock_remove(0, phys_base);
+ prom_printf("phys_base: adopted 0x%lx, RAM below it dropped\n",
+ phys_base);
+ }
+ }
+
+ if (cmdline_memory_size)
+ memblock_enforce_memory_limit(cmdline_memory_size);
+
+ min_low_pfn = PFN_DOWN(memblock_start_of_DRAM());
+ pfn_base = PHYS_PFN(phys_base);
+ max_pfn = PFN_DOWN(memblock_end_of_DRAM());
+ max_low_pfn = max_pfn;
+
+ if (max_low_pfn > pfn_base + PHYS_PFN(SRMMU_MAXMEM))
+ max_low_pfn = calc_max_low_pfn();
+
+ find_ramdisk(memblock_end_of_DRAM());
+
+ /* Reserve the kernel text/data/bss. */
+ size = __pa(PAGE_ALIGN((unsigned long)&_end)) - phys_base;
+ memblock_reserve(phys_base, size);
+ memblock_add(phys_base, size);
+
+ /* Only allow low memory to be allocated by memblock. */
+ memblock_set_current_limit(PFN_PHYS(max_low_pfn));
+}
+
/* Called from head_32.S - before we have setup anything
* in the kernel. Be very careful with what you do here.
*/
@@ -282,9 +355,6 @@ void __init sparc32_start_kernel(struct linux_romvec *rp)
void __init setup_arch(char **cmdline_p)
{
- int i;
- unsigned long highest_paddr;
-
sparc_ttable = &trapbase[0];
/* Initialize PROM console and command line. */
@@ -319,20 +389,7 @@ void __init setup_arch(char **cmdline_p)
idprom_init();
load_mmu();
-
- phys_base = 0xffffffffUL;
- highest_paddr = 0UL;
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- unsigned long top;
-
- if (sp_banks[i].base_addr < phys_base)
- phys_base = sp_banks[i].base_addr;
- top = sp_banks[i].base_addr +
- sp_banks[i].num_bytes;
- if (highest_paddr < top)
- highest_paddr = top;
- }
- pfn_base = phys_base >> PAGE_SHIFT;
+ setup_memory();
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 371460e34484..ed6900b5d562 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -801,6 +801,15 @@ static void xcall_deliver(u64 data0, u64 data1, u64 data2, const cpumask_t *mask
local_irq_save(flags);
this_cpu = smp_processor_id();
+
+ /* The mondo block and cpu list are not set up until init_IRQ(),
+ * so do not touch them unless there is a cpu to send to.
+ */
+ if (cpumask_any_and_but(mask, cpu_online_mask, this_cpu) >= nr_cpu_ids) {
+ local_irq_restore(flags);
+ return;
+ }
+
tb = &trap_block[this_cpu];
mondo = __va(tb->cpu_mondo_block_pa);
@@ -915,6 +924,7 @@ extern unsigned long xcall_kgdb_capture;
#ifdef DCACHE_ALIASING_POSSIBLE
extern unsigned long xcall_flush_dcache_page_cheetah;
+extern unsigned long xcall_flush_dcache_all;
#endif
extern unsigned long xcall_flush_dcache_page_spitfire;
@@ -982,8 +992,9 @@ void smp_flush_dcache_folio_impl(struct folio *folio, int cpu)
put_cpu();
}
-void flush_dcache_folio_all(struct mm_struct *mm, struct folio *folio)
+void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
{
+ struct folio *folio = page_folio(page);
void *pg_addr;
u64 data0;
@@ -996,7 +1007,7 @@ void flush_dcache_folio_all(struct mm_struct *mm, struct folio *folio)
atomic_inc(&dcpage_flushes);
#endif
data0 = 0;
- pg_addr = folio_address(folio);
+ pg_addr = page_address(page);
if (tlb_type == spitfire) {
data0 = ((u64)&xcall_flush_dcache_page_spitfire);
if (folio_flush_mapping(folio) != NULL)
@@ -1007,22 +1018,40 @@ void flush_dcache_folio_all(struct mm_struct *mm, struct folio *folio)
#endif
}
if (data0) {
- unsigned int i, nr = folio_nr_pages(folio);
-
- for (i = 0; i < nr; i++) {
- xcall_deliver(data0, __pa(pg_addr),
- (u64) pg_addr, cpu_online_mask);
+ xcall_deliver(data0, __pa(pg_addr),
+ (u64)pg_addr, cpu_online_mask);
#ifdef CONFIG_DEBUG_DCFLUSH
- atomic_inc(&dcpage_flushes_xcall);
+ atomic_inc(&dcpage_flushes_xcall);
#endif
- pg_addr += PAGE_SIZE;
- }
}
- __local_flush_dcache_folio(folio);
+#ifdef DCACHE_ALIASING_POSSIBLE
+ __flush_dcache_page(pg_addr,
+ tlb_type == spitfire && folio_flush_mapping(folio));
+#else
+ if (tlb_type == spitfire && folio_flush_mapping(folio))
+ __flush_icache_page(__pa(pg_addr));
+#endif
preempt_enable();
}
+#ifdef DCACHE_ALIASING_POSSIBLE
+void flush_dcache_all(void)
+{
+ unsigned long size, line_size;
+
+ if (tlb_type == hypervisor)
+ return;
+
+ preempt_disable();
+ size = local_cpu_data().dcache_size;
+ line_size = local_cpu_data().dcache_line_size;
+ smp_cross_call(&xcall_flush_dcache_all, 0, size, line_size);
+ __flush_dcache_all(size, line_size);
+ preempt_enable();
+}
+#endif
+
#ifdef CONFIG_KGDB
void kgdb_roundup_cpus(void)
{
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index 96fe8763d70c..46779bb27e77 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -159,11 +159,13 @@ linux_sparc_ni_syscall:
linux_syscall_trace32:
call syscall_trace_enter
add %sp, PTREGS_OFF, %o0
- brnz,pn %o0, 3f
- mov -ENOSYS, %o0
+ /* A negative return means the syscall was denied and the
+ * return value is already set in pt_regs.
+ */
+ brlz,pn %o0, linux_syscall_skip
/* Syscall tracing can modify the registers. */
- ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
+ ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
sethi %hi(sys_call_table32), %l7
ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0
or %l7, %lo(sys_call_table32), %l7
@@ -189,11 +191,13 @@ linux_syscall_trace32:
linux_syscall_trace:
call syscall_trace_enter
add %sp, PTREGS_OFF, %o0
- brnz,pn %o0, 3f
- mov -ENOSYS, %o0
+ /* A negative return means the syscall was denied and the
+ * return value is already set in pt_regs.
+ */
+ brlz,pn %o0, linux_syscall_skip
/* Syscall tracing can modify the registers. */
- ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
+ ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
sethi %hi(sys_call_table64), %l7
ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0
or %l7, %lo(sys_call_table64), %l7
@@ -307,3 +311,15 @@ linux_syscall_trace2:
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
ba,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
+
+ /* The syscall was denied at entry by ptrace or seccomp. The
+ * return value and the carry bit are already set in pt_regs;
+ * advance past the trap instruction and run the syscall exit
+ * work without storing a new return value. We can only get
+ * here from the entry trace stubs, so the thread flags in %l0
+ * are known to be non-zero.
+ */
+linux_syscall_skip:
+ ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
+ ba,pt %xcc, linux_syscall_trace2
+ add %l1, 0x4, %l2 ! npc = npc+4
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index b1c54ab4b15b..4547cadf388b 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -146,7 +146,7 @@ static int tick_add_compare(unsigned long adj)
: "=r" (new_tick));
new_tick &= ~TICKCMP_IRQ_BIT;
- return ((long)(new_tick - (orig_tick+adj))) > 0L;
+ return ((long)(new_tick - (orig_tick+adj))) >= 0L;
}
static unsigned long tick_add_tick(unsigned long adj)
@@ -277,7 +277,7 @@ static int stick_add_compare(unsigned long adj)
: "=r" (new_tick));
new_tick &= ~TICKCMP_IRQ_BIT;
- return ((long)(new_tick - (orig_tick+adj))) > 0L;
+ return ((long)(new_tick - (orig_tick+adj))) >= 0L;
}
static unsigned long stick_get_frequency(void)
@@ -411,7 +411,7 @@ static int hbtick_add_compare(unsigned long adj)
val2 = __hbird_read_stick() & ~TICKCMP_IRQ_BIT;
- return ((long)(val2 - val)) > 0L;
+ return ((long)(val2 - val)) >= 0L;
}
static unsigned long hbtick_get_frequency(void)
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index eaed39ce8938..a70d5b124a80 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -144,6 +144,26 @@ tsb_miss_page_table_walk_sun4v_fastpath:
bne,pt %xcc, 60f
nop
+ /* If this fault came from a window spill or fill (TL > 1),
+ * we cannot build a trap stack and call hugetlb_setup() from
+ * here. Route it through tsb_do_fault instead, so that
+ * do_sparc64_fault() runs and its huge-TSB grow check
+ * allocates the TSB before the access is replayed.
+ *
+ * This must be decided before the register bank switch below:
+ * %g3 (the fault code) and %g5 (now the PTE) live in the TLB
+ * miss handler's globals and do not survive it. Consuming
+ * them after the switch, as this path used to when it went to
+ * winfix_trampoline directly, records a stale %g3 as the
+ * fault code and a stale %g5 as the fault address, and the
+ * task is then killed with a SIGSEGV at a garbage address.
+ * tsb_do_fault re-fetches both from the MMU after switching.
+ */
+ rdpr %tl, %g7
+ cmp %g7, 1
+ bgu,pn %xcc, tsb_do_fault
+ nop
+
661: rdpr %pstate, %g5
wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
.section .sun4v_2insn_patch, "ax"
@@ -152,10 +172,6 @@ tsb_miss_page_table_walk_sun4v_fastpath:
nop
.previous
- rdpr %tl, %g7
- cmp %g7, 1
- bne,pn %xcc, winfix_trampoline
- mov %g3, %g4
ba,pt %xcc, etrap
rd %pc, %g7
call hugetlb_setup
diff --git a/arch/sparc/kernel/urtt_fill.S b/arch/sparc/kernel/urtt_fill.S
index e4cee7be5cd0..1ec67df9b59e 100644
--- a/arch/sparc/kernel/urtt_fill.S
+++ b/arch/sparc/kernel/urtt_fill.S
@@ -1,4 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#include <asm/asi.h>
#include <asm/thread_info.h>
#include <asm/trap_block.h>
#include <asm/spitfire.h>
@@ -32,6 +33,15 @@ user_rtt_fill_fixup_common:
sethi %hi(KERNBASE), %g1
flush %g1
+ /* Restore the kernel's ASI_AIUS invariant, which etrap
+ * would have re-established had we passed through it.
+ * rtrap set %asi to ASI_AIUP for the window fill, and
+ * the primary context is now the kernel's, so a leftover
+ * ASI_AIUP would make %asi-based user accesses (put_user,
+ * get_user) translate in the kernel context.
+ */
+ wr %g0, ASI_AIUS, %asi
+
mov %g4, %l4
mov %g5, %l5
brnz,pn %g3, 1f
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
index 86a831ebd8c8..4b23b4b14e99 100644
--- a/arch/sparc/mm/fault_32.c
+++ b/arch/sparc/mm/fault_32.c
@@ -232,15 +232,17 @@ no_context:
const struct exception_table_entry *entry;
entry = search_exception_tables(regs->pc);
+ if (entry) {
#ifdef DEBUG_EXCEPTIONS
- printk("Exception: PC<%08lx> faddr<%08lx>\n",
- regs->pc, address);
- printk("EX_TABLE: insn<%08lx> fixup<%08x>\n",
- regs->pc, entry->fixup);
+ printk("Exception: PC<%08lx> faddr<%08lx>\n",
+ regs->pc, address);
+ printk("EX_TABLE: insn<%08lx> fixup<%08x>\n",
+ regs->pc, entry->fixup);
#endif
- regs->pc = entry->fixup;
- regs->npc = regs->pc + 4;
- return;
+ regs->pc = entry->fixup;
+ regs->npc = regs->pc + 4;
+ return;
+ }
}
unhandled_fault(address, tsk, regs);
@@ -276,21 +278,21 @@ vmalloc_fault:
pmd_t *pmd, *pmd_k;
pgd = tsk->active_mm->pgd + offset;
+ p4d = p4d_offset(pgd, address);
+ pud = pud_offset(p4d, address);
+
pgd_k = init_mm.pgd + offset;
+ p4d_k = p4d_offset(pgd_k, address);
+ pud_k = pud_offset(p4d_k, address);
- if (!pgd_present(*pgd)) {
- if (!pgd_present(*pgd_k))
+ if (!pud_present(*pud)) {
+ if (!pud_present(*pud_k))
goto bad_area_nosemaphore;
- pgd_val(*pgd) = pgd_val(*pgd_k);
+ pud_val(*pud) = pud_val(*pud_k);
return;
}
- p4d = p4d_offset(pgd, address);
- pud = pud_offset(p4d, address);
pmd = pmd_offset(pud, address);
-
- p4d_k = p4d_offset(pgd_k, address);
- pud_k = pud_offset(p4d_k, address);
pmd_k = pmd_offset(pud_k, address);
if (pmd_present(*pmd) || !pmd_present(*pmd_k))
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index e326caf708c6..c37b24f757f4 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -165,6 +165,15 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
if (fault_code & FAULT_CODE_ITLB) {
addr = regs->tpc;
+ } else if (fault_code & FAULT_CODE_WINFIXUP) {
+ /* The fault came from a register window spill or fill, so
+ * the instruction at regs->tpc is the one being resumed,
+ * not the access that faulted. Decoding it would fabricate
+ * an address out of unrelated register contents; the fault
+ * time provided address is the real one, even if it only
+ * has page granularity.
+ */
+ addr = fault_addr;
} else {
/* If we were able to probe the faulting instruction, use it
* to compute a precise fault address. Otherwise use the fault
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index e0e66f91ceeb..2f693b70dbd8 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
@@ -24,7 +23,6 @@
#include <linux/highmem.h>
#include <linux/memblock.h>
#include <linux/pagemap.h>
-#include <linux/poison.h>
#include <linux/gfp.h>
#include <asm/sections.h>
@@ -37,68 +35,11 @@
#include "mm_32.h"
-static unsigned long *sparc_valid_addr_bitmap;
-
-unsigned long phys_base;
-EXPORT_SYMBOL(phys_base);
-
-unsigned long pfn_base;
-EXPORT_SYMBOL(pfn_base);
-
-struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
-
/* Initial ramdisk setup */
extern unsigned int sparc_ramdisk_image;
extern unsigned int sparc_ramdisk_size;
-unsigned long highstart_pfn, highend_pfn;
-
-unsigned long last_valid_pfn;
-
-unsigned long calc_highpages(void)
-{
- int i;
- int nr = 0;
-
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
- unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
-
- if (end_pfn <= max_low_pfn)
- continue;
-
- if (start_pfn < max_low_pfn)
- start_pfn = max_low_pfn;
-
- nr += end_pfn - start_pfn;
- }
-
- return nr;
-}
-
-static unsigned long calc_max_low_pfn(void)
-{
- int i;
- unsigned long tmp = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
- unsigned long curr_pfn, last_pfn;
-
- last_pfn = (sp_banks[0].base_addr + sp_banks[0].num_bytes) >> PAGE_SHIFT;
- for (i = 1; sp_banks[i].num_bytes != 0; i++) {
- curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
-
- if (curr_pfn >= tmp) {
- if (last_pfn < tmp)
- tmp = last_pfn;
- break;
- }
-
- last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
- }
-
- return tmp;
-}
-
-static void __init find_ramdisk(unsigned long end_of_phys_memory)
+void __init find_ramdisk(unsigned long end_of_phys_memory)
{
#ifdef CONFIG_BLK_DEV_INITRD
unsigned long size;
@@ -128,80 +69,6 @@ static void __init find_ramdisk(unsigned long end_of_phys_memory)
#endif
}
-unsigned long __init bootmem_init(unsigned long *pages_avail)
-{
- unsigned long start_pfn, bytes_avail, size;
- unsigned long end_of_phys_memory = 0;
- unsigned long high_pages = 0;
- int i;
-
- memblock_set_bottom_up(true);
- memblock_allow_resize();
-
- bytes_avail = 0UL;
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- end_of_phys_memory = sp_banks[i].base_addr +
- sp_banks[i].num_bytes;
- bytes_avail += sp_banks[i].num_bytes;
- if (cmdline_memory_size) {
- if (bytes_avail > cmdline_memory_size) {
- unsigned long slack = bytes_avail - cmdline_memory_size;
-
- bytes_avail -= slack;
- end_of_phys_memory -= slack;
-
- sp_banks[i].num_bytes -= slack;
- if (sp_banks[i].num_bytes == 0) {
- sp_banks[i].base_addr = 0xdeadbeef;
- } else {
- memblock_add(sp_banks[i].base_addr,
- sp_banks[i].num_bytes);
- sp_banks[i+1].num_bytes = 0;
- sp_banks[i+1].base_addr = 0xdeadbeef;
- }
- break;
- }
- }
- memblock_add(sp_banks[i].base_addr, sp_banks[i].num_bytes);
- }
-
- /* Start with page aligned address of last symbol in kernel
- * image.
- */
- start_pfn = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end));
-
- /* Now shift down to get the real physical page frame number. */
- start_pfn >>= PAGE_SHIFT;
-
- max_pfn = end_of_phys_memory >> PAGE_SHIFT;
-
- max_low_pfn = max_pfn;
- highstart_pfn = highend_pfn = max_pfn;
-
- if (max_low_pfn > pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT)) {
- highstart_pfn = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
- max_low_pfn = calc_max_low_pfn();
- high_pages = calc_highpages();
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
- high_pages >> (20 - PAGE_SHIFT));
- }
-
- find_ramdisk(end_of_phys_memory);
-
- /* Reserve the kernel text/data/bss. */
- size = (start_pfn << PAGE_SHIFT) - phys_base;
- memblock_reserve(phys_base, size);
- memblock_add(phys_base, size);
-
- size = memblock_phys_mem_size() - memblock_reserved_size();
- *pages_avail = (size >> PAGE_SHIFT) - high_pages;
-
- /* Only allow low memory to be allocated via memblock allocation */
- memblock_set_current_limit(max_low_pfn << PAGE_SHIFT);
-
- return max_pfn;
-}
-
/*
* paging_init() sets up the page tables: We call the MMU specific
* init routine based upon the Sun model type on the Sparc.
@@ -215,27 +82,8 @@ void __init paging_init(void)
device_scan();
}
-static void __init taint_real_pages(void)
-{
- int i;
-
- for (i = 0; sp_banks[i].num_bytes; i++) {
- unsigned long start, end;
-
- start = sp_banks[i].base_addr;
- end = start + sp_banks[i].num_bytes;
-
- while (start < end) {
- set_bit(start >> 20, sparc_valid_addr_bitmap);
- start += PAGE_SIZE;
- }
- }
-}
-
void __init arch_mm_preinit(void)
{
- int i;
-
if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
prom_printf("BUG: fixmap and pkmap areas overlap\n");
prom_printf("pkbase: 0x%lx pkend: 0x%lx fixstart 0x%lx\n",
@@ -245,19 +93,6 @@ void __init arch_mm_preinit(void)
prom_printf("Please mail sparclinux@vger.kernel.org.\n");
prom_halt();
}
-
- i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5);
- i += 1;
- sparc_valid_addr_bitmap = (unsigned long *)
- memblock_alloc(i << 2, SMP_CACHE_BYTES);
-
- if (sparc_valid_addr_bitmap == NULL) {
- prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
- prom_halt();
- }
- memset(sparc_valid_addr_bitmap, 0, i << 2);
-
- taint_real_pages();
}
void sparc_flush_page_to_ram(struct page *page)
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 9bbccb5d23a8..6a0ba9a01a21 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -27,6 +27,7 @@
#include <linux/percpu.h>
#include <linux/mmzone.h>
#include <linux/gfp.h>
+#include <linux/vmalloc.h>
#include <asm/head.h>
#include <asm/page.h>
@@ -214,6 +215,39 @@ inline void flush_dcache_folio_impl(struct folio *folio)
#endif
}
+#ifndef CONFIG_SMP
+void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
+{
+ struct folio *folio = page_folio(page);
+
+ if (tlb_type == hypervisor)
+ return;
+
+#ifdef CONFIG_DEBUG_DCFLUSH
+ atomic_inc(&dcpage_flushes);
+#endif
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+ __flush_dcache_page(page_address(page),
+ tlb_type == spitfire && folio_flush_mapping(folio));
+#else
+ if (tlb_type == spitfire && folio_flush_mapping(folio))
+ __flush_icache_page(page_to_phys(page));
+#endif
+}
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+void flush_dcache_all(void)
+{
+ if (tlb_type == hypervisor)
+ return;
+
+ __flush_dcache_all(local_cpu_data().dcache_size,
+ local_cpu_data().dcache_line_size);
+}
+#endif
+#endif /* !CONFIG_SMP */
+
#define PG_dcache_dirty PG_arch_1
#define PG_dcache_cpu_shift 32UL
#define PG_dcache_cpu_mask \
@@ -3050,6 +3084,37 @@ arch_initcall(report_memory);
#define do_flush_tlb_kernel_range __flush_tlb_kernel_range
#endif
+/*
+ * The L1 D-cache is indexed with VA bit 13, so lines loaded through a
+ * vmalloc address outlive the mapping. Stores through a mapping of the
+ * other colour do not update them, and a later load through their colour
+ * returns stale data. Flush at unmap so vmalloc's lines do not follow
+ * the page back to the allocator, and at map time since anonymous user
+ * pages are freed without a flush (see tlb_batch_add()). Past the
+ * D-cache size, one whole-cache flush is cheaper than a cross call per
+ * page.
+ */
+void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+#ifdef DCACHE_ALIASING_POSSIBLE
+ /* The vmemmap has no aliases and is mapped before cross calls work. */
+ if (tlb_type == hypervisor || !is_vmalloc_or_module_addr((void *)start))
+ return;
+
+ if (end - start > cpu_data(raw_smp_processor_id()).dcache_size) {
+ flush_dcache_all();
+ return;
+ }
+
+ for (; start < end; start += PAGE_SIZE) {
+ struct page *page = vmalloc_to_page((void *)start);
+
+ if (page)
+ flush_dcache_page_all(NULL, page);
+ }
+#endif
+}
+
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
if (start < HI_OBP_ADDRESS && end > LOW_OBP_ADDRESS) {
diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c
index 1dc9b3d70eda..a43c5ffbbbe5 100644
--- a/arch/sparc/mm/leon_mm.c
+++ b/arch/sparc/mm/leon_mm.c
@@ -11,6 +11,7 @@
*/
#include <linux/kernel.h>
+#include <linux/memblock.h>
#include <linux/mm.h>
#include <asm/asi.h>
#include <asm/leon.h>
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 1c277ab3cdb8..337987e021d4 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -59,8 +59,6 @@ int vac_line_size;
extern struct resource sparc_iomap;
-extern unsigned long last_valid_pfn;
-
static pgd_t *srmmu_swapper_pg_dir;
const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
@@ -226,25 +224,13 @@ void srmmu_free_nocache(void *addr, int size)
static void srmmu_early_allocate_ptable_skeleton(unsigned long start,
unsigned long end);
-/* Return how much physical memory we have. */
-static unsigned long __init probe_memory(void)
-{
- unsigned long total = 0;
- int i;
-
- for (i = 0; sp_banks[i].num_bytes; i++)
- total += sp_banks[i].num_bytes;
-
- return total;
-}
-
/*
* Reserve nocache dynamically proportionally to the amount of
* system RAM. -- Tomas Szepe <szepe@pinerecords.com>, June 2002
*/
static void __init srmmu_nocache_calcsize(void)
{
- unsigned long sysmemavail = probe_memory() / 1024;
+ unsigned long sysmemavail = memblock_phys_mem_size() / 1024;
int srmmu_nocache_npages;
srmmu_nocache_npages =
@@ -279,7 +265,6 @@ static void __init srmmu_nocache_init(void)
srmmu_nocache_pool = memblock_alloc_or_panic(srmmu_nocache_size,
SRMMU_NOCACHE_ALIGN_MAX);
- memset(srmmu_nocache_pool, 0, srmmu_nocache_size);
srmmu_nocache_bitmap =
memblock_alloc_or_panic(BITS_TO_LONGS(bitmap_bits) * sizeof(long),
@@ -839,39 +824,34 @@ static void __init do_large_mapping(unsigned long vaddr, unsigned long phys_base
*__nocache_fix(pgdp) = __pgd(big_pte);
}
-/* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE. */
-static unsigned long __init map_spbank(unsigned long vbase, int sp_entry)
-{
- unsigned long pstart = (sp_banks[sp_entry].base_addr & PGDIR_MASK);
- unsigned long vstart = (vbase & PGDIR_MASK);
- unsigned long vend = PGDIR_ALIGN(vbase + sp_banks[sp_entry].num_bytes);
- /* Map "low" memory only */
- const unsigned long min_vaddr = PAGE_OFFSET;
- const unsigned long max_vaddr = PAGE_OFFSET + SRMMU_MAXMEM;
-
- if (vstart < min_vaddr || vstart >= max_vaddr)
- return vstart;
-
- if (vend > max_vaddr || vend < min_vaddr)
- vend = max_vaddr;
-
- while (vstart < vend) {
- do_large_mapping(vstart, pstart);
- vstart += PGDIR_SIZE; pstart += PGDIR_SIZE;
- }
- return vstart;
-}
-
static void __init map_kernel(void)
{
- int i;
+ phys_addr_t start, end;
+ u64 i;
if (phys_base > 0) {
do_large_mapping(PAGE_OFFSET, phys_base);
}
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- map_spbank((unsigned long)__va(sp_banks[i].base_addr), i);
+ for_each_mem_range(i, &start, &end) {
+ unsigned long vbase = (unsigned long)__va(start);
+ unsigned long pstart = start & PGDIR_MASK;
+ unsigned long vstart = vbase & PGDIR_MASK;
+ unsigned long vend = PGDIR_ALIGN(vbase + end - start);
+ const unsigned long min_vaddr = PAGE_OFFSET;
+ const unsigned long max_vaddr = PAGE_OFFSET + SRMMU_MAXMEM;
+
+ /* Map low memory only. */
+ if (vstart < min_vaddr || vstart >= max_vaddr)
+ continue;
+ if (vend > max_vaddr || vend < min_vaddr)
+ vend = max_vaddr;
+
+ while (vstart < vend) {
+ do_large_mapping(vstart, pstart);
+ vstart += PGDIR_SIZE;
+ pstart += PGDIR_SIZE;
+ }
}
}
@@ -881,7 +861,7 @@ void __init arch_zone_limits_init(unsigned long *max_zone_pfns)
{
max_zone_pfns[ZONE_DMA] = max_low_pfn;
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
- max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
+ max_zone_pfns[ZONE_HIGHMEM] = max_pfn;
}
void __init srmmu_paging_init(void)
@@ -894,7 +874,6 @@ void __init srmmu_paging_init(void)
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- unsigned long pages_avail;
init_mm.context = (unsigned long) NO_CONTEXT;
sparc_iomap.start = SUN4M_IOBASE_VADDR; /* 16MB of IOSPACE on all sun4m's. */
@@ -920,9 +899,6 @@ void __init srmmu_paging_init(void)
prom_halt();
}
- pages_avail = 0;
- last_valid_pfn = bootmem_init(&pages_avail);
-
srmmu_nocache_calcsize();
srmmu_nocache_init();
srmmu_inherit_prom_mappings(0xfe400000, (LINUX_OPPROM_ENDVM - PAGE_SIZE));
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 6d9dd5eb1328..1221814ca0e1 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -144,7 +144,7 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
paddr = (unsigned long) page_address(page);
if ((paddr ^ vaddr) & (1 << 13))
- flush_dcache_folio_all(mm, folio);
+ flush_dcache_page_all(mm, page);
}
no_cache_flush:
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
index 70e658d107e0..ff190670a235 100644
--- a/arch/sparc/mm/ultra.S
+++ b/arch/sparc/mm/ultra.S
@@ -242,6 +242,20 @@ __flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
retl
nop
+ /* Zeroing every D-cache tag invalidates the whole cache on
+ * Spitfire and Cheetah alike.
+ */
+ .align 32
+ .globl __flush_dcache_all
+__flush_dcache_all: /* %o0=D-cache size, %o1=D-cache line size */
+1: subcc %o0, %o1, %o0
+ stxa %g0, [%o0] ASI_DCACHE_TAG
+ membar #Sync
+ bne,pt %icc, 1b
+ nop
+ retl
+ nop
+
#endif /* DCACHE_ALIASING_POSSIBLE */
.previous
@@ -801,6 +815,17 @@ xcall_flush_dcache_page_cheetah: /* %g1 == physical page address */
nop
retry
nop
+
+ .align 32
+ .globl xcall_flush_dcache_all
+xcall_flush_dcache_all: /* %g1 == D-cache size, %g7 == D-cache line size */
+1: subcc %g1, %g7, %g1
+ stxa %g0, [%g1] ASI_DCACHE_TAG
+ membar #Sync
+ bne,pt %icc, 1b
+ nop
+ retry
+ nop
#endif /* DCACHE_ALIASING_POSSIBLE */
.globl xcall_flush_dcache_page_spitfire
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index 48f062de7a7f..8b4e251bbba2 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -38,6 +38,9 @@ sun4dsmp_flush_tlb_spin:
viking_flush_page:
sethi %hi(PAGE_OFFSET), %g2
sub %o0, %g2, %g3
+ sethi %hi(phys_base), %g2
+ ld [%g2 + %lo(phys_base)], %g2
+ add %g3, %g2, %g3 ! + phys_base = physical address
srl %g3, 12, %g1 ! ppage >> 12
clr %o1 ! set counter, 0 - 127
@@ -91,6 +94,9 @@ viking_flush_page:
viking_mxcc_flush_page:
sethi %hi(PAGE_OFFSET), %g2
sub %o0, %g2, %g3
+ sethi %hi(phys_base), %g2
+ ld [%g2 + %lo(phys_base)], %g2
+ add %g3, %g2, %g3 ! + phys_base = physical address
sub %g3, -PAGE_SIZE, %g3 ! ppage + PAGE_SIZE
sethi %hi(MXCC_SRCSTREAM), %o3 ! assume %hi(MXCC_SRCSTREAM) == %hi(MXCC_DESTSTREAM)
mov 0x10, %g2 ! set cacheable bit
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index 269d6ab5ef5e..3f65bde2bb89 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -7,29 +7,22 @@
*/
#include <linux/kernel.h>
-#include <linux/sort.h>
+#include <linux/memblock.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/page.h>
-static int __init prom_meminit_v0(void)
+static void __init prom_meminit_v0(void)
{
struct linux_mlist_v0 *p;
- int index;
- index = 0;
- for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more) {
- sp_banks[index].base_addr = (unsigned long) p->start_adr;
- sp_banks[index].num_bytes = p->num_bytes;
- index++;
- }
-
- return index;
+ for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more)
+ memblock_add(p->start_adr, p->num_bytes & PAGE_MASK);
}
-static int __init prom_meminit_v2(void)
+static void __init prom_meminit_v2(void)
{
struct linux_prom_registers reg[64];
phandle node;
@@ -39,50 +32,24 @@ static int __init prom_meminit_v2(void)
size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
num_ents = size / sizeof(struct linux_prom_registers);
- for (i = 0; i < num_ents; i++) {
- sp_banks[i].base_addr = reg[i].phys_addr;
- sp_banks[i].num_bytes = reg[i].reg_size;
- }
-
- return num_ents;
-}
-
-static int sp_banks_cmp(const void *a, const void *b)
-{
- const struct sparc_phys_banks *x = a, *y = b;
-
- if (x->base_addr > y->base_addr)
- return 1;
- if (x->base_addr < y->base_addr)
- return -1;
- return 0;
+ for (i = 0; i < num_ents; i++)
+ memblock_add(reg[i].phys_addr, reg[i].reg_size & PAGE_MASK);
}
/* Initialize the memory lists based upon the prom version. */
void __init prom_meminit(void)
{
- int i, num_ents = 0;
-
switch (prom_vers) {
case PROM_V0:
- num_ents = prom_meminit_v0();
+ prom_meminit_v0();
break;
case PROM_V2:
case PROM_V3:
- num_ents = prom_meminit_v2();
+ prom_meminit_v2();
break;
default:
break;
}
- sort(sp_banks, num_ents, sizeof(struct sparc_phys_banks),
- sp_banks_cmp, NULL);
-
- /* Sentinel. */
- sp_banks[num_ents].base_addr = 0xdeadbeef;
- sp_banks[num_ents].num_bytes = 0;
-
- for (i = 0; i < num_ents; i++)
- sp_banks[i].num_bytes &= PAGE_MASK;
}
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 66bb53bad93b..5d3f1cf00830 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -1902,6 +1902,45 @@ struct alpha_regs {
# define ARCH_REGS struct user_regs_struct
# define SYSCALL_NUM(_regs) (_regs).orig_d0
# define SYSCALL_RET(_regs) (_regs).d0
+#elif defined(__sparc__)
+# include <asm/ptrace.h>
+
+# if defined(__arch64__)
+# include <asm/pstate.h>
+# define CARRY_MASK (TSTATE_ICARRY | TSTATE_XCARRY)
+# define SPARC_CARRY_REG(_regs) ((_regs).tstate)
+# else
+# include <asm/psr.h>
+# define CARRY_MASK PSR_C
+# define SPARC_CARRY_REG(_regs) ((_regs).psr)
+# endif
+
+/*
+ * PTRACE_GETREGS{64}/PTRACE_SETREGS{64} transfer the uapi struct pt_regs,
+ * but in the historical layout that omits %g0: the blob starts at %g1,
+ * so every u_regs index is one lower than the register number suggests.
+ */
+# define ARCH_REGS struct pt_regs
+# define SYSCALL_NUM(_regs) (_regs).u_regs[0] /* %g1 */
+# define SYSCALL_RET(_regs) (_regs).u_regs[7] /* %o0 */
+/*
+ * A syscall error is signaled by the carry bit in tstate (SPARC64) or
+ * psr (SPARC32), with the errno held in %o0 as a positive value;
+ * the carry can only be written reliably once the syscall has been
+ * skipped or has run.
+ */
+# define SYSCALL_RET_SET(_regs, _val) \
+ do { \
+ typeof(_val) _result = (_val); \
+ if (_result < 0) { \
+ SYSCALL_RET(_regs) = -_result; \
+ SPARC_CARRY_REG(_regs) |= CARRY_MASK; \
+ } else { \
+ SYSCALL_RET(_regs) = _result; \
+ SPARC_CARRY_REG(_regs) &= ~CARRY_MASK; \
+ } \
+ } while (0)
+# define SYSCALL_RET_SET_ON_PTRACE_EXIT
#else
# error "Do not know how to find your architecture's registers and syscalls"
#endif
@@ -1969,6 +2008,19 @@ const bool ptrace_entry_set_syscall_ret =
#if defined(__x86_64__) || defined(__i386__) || defined(__mips__) || defined(__mc68000__)
# define ARCH_GETREGS(_regs) ptrace(PTRACE_GETREGS, tracee, 0, &(_regs))
# define ARCH_SETREGS(_regs) ptrace(PTRACE_SETREGS, tracee, 0, &(_regs))
+#elif defined(__sparc__)
+# if defined(__arch64__)
+/*
+ * The NT_PRSTATUS regset appends the register window, which struct
+ * pt_regs does not carry; the sparc-specific requests transfer
+ * struct pt_regs directly (and take the buffer in addr).
+ */
+# define ARCH_GETREGS(_regs) ptrace(PTRACE_GETREGS64, tracee, &(_regs), 0)
+# define ARCH_SETREGS(_regs) ptrace(PTRACE_SETREGS64, tracee, &(_regs), 0)
+# else
+# define ARCH_GETREGS(_regs) ptrace(PTRACE_GETREGS, tracee, &(_regs), 0)
+# define ARCH_SETREGS(_regs) ptrace(PTRACE_SETREGS, tracee, &(_regs), 0)
+# endif
#else
# define ARCH_GETREGS(_regs) ({ \
struct iovec __v; \