diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-30 11:31:01 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-30 11:31:01 +0000 |
| commit | 4e40f1ef79584fe42f420c809fe80fcf23a4d1ba (patch) | |
| tree | aef4a33470000d8a53cb18e730c8a9fe022db9c8 | |
| parent | d2d6acfbd25859ba59489875e228ee4739af0590 (diff) | |
| parent | d957b367d560c4a74637d400ca4e0e63bbdfbcd1 (diff) | |
| download | linux-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
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; \ |
