18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/lib/copypage-armv4mc.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995-2005 Russell King 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This handles the mini data cache, as found on SA11x0 and XScale 88c2ecf20Sopenharmony_ci * processors. When we copy a user page page, we map it in such a way 98c2ecf20Sopenharmony_ci * that accesses to this page will not touch the main data cache, but 108c2ecf20Sopenharmony_ci * will be cached in the mini data cache. This prevents us thrashing 118c2ecf20Sopenharmony_ci * the main data cache on page faults. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/highmem.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 188c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "mm.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ 238c2ecf20Sopenharmony_ci L_PTE_MT_MINICACHE) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(minicache_lock); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * ARMv4 mini-dcache optimised copy_user_highpage 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * We flush the destination cache lines just before we write the data into the 318c2ecf20Sopenharmony_ci * corresponding address. Since the Dcache is read-allocate, this removes the 328c2ecf20Sopenharmony_ci * Dcache aliasing issue. The writes will be forwarded to the write buffer, 338c2ecf20Sopenharmony_ci * and merged as appropriate. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Note: We rely on all ARMv4 processors implementing the "invalidate D line" 368c2ecf20Sopenharmony_ci * instruction. If your processor does not supply this, you have to write your 378c2ecf20Sopenharmony_ci * own copy_user_highpage that does the right thing. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistatic void mc_copy_user_page(void *from, void *to) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci int tmp; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci asm volatile ("\ 448c2ecf20Sopenharmony_ci .syntax unified\n\ 458c2ecf20Sopenharmony_ci ldmia %0!, {r2, r3, ip, lr} @ 4\n\ 468c2ecf20Sopenharmony_ci1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ 478c2ecf20Sopenharmony_ci stmia %1!, {r2, r3, ip, lr} @ 4\n\ 488c2ecf20Sopenharmony_ci ldmia %0!, {r2, r3, ip, lr} @ 4+1\n\ 498c2ecf20Sopenharmony_ci stmia %1!, {r2, r3, ip, lr} @ 4\n\ 508c2ecf20Sopenharmony_ci ldmia %0!, {r2, r3, ip, lr} @ 4\n\ 518c2ecf20Sopenharmony_ci mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ 528c2ecf20Sopenharmony_ci stmia %1!, {r2, r3, ip, lr} @ 4\n\ 538c2ecf20Sopenharmony_ci ldmia %0!, {r2, r3, ip, lr} @ 4\n\ 548c2ecf20Sopenharmony_ci subs %2, %2, #1 @ 1\n\ 558c2ecf20Sopenharmony_ci stmia %1!, {r2, r3, ip, lr} @ 4\n\ 568c2ecf20Sopenharmony_ci ldmiane %0!, {r2, r3, ip, lr} @ 4\n\ 578c2ecf20Sopenharmony_ci bne 1b @ " 588c2ecf20Sopenharmony_ci : "+&r" (from), "+&r" (to), "=&r" (tmp) 598c2ecf20Sopenharmony_ci : "2" (PAGE_SIZE / 64) 608c2ecf20Sopenharmony_ci : "r2", "r3", "ip", "lr"); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_civoid v4_mc_copy_user_highpage(struct page *to, struct page *from, 648c2ecf20Sopenharmony_ci unsigned long vaddr, struct vm_area_struct *vma) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci void *kto = kmap_atomic(to); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!test_and_set_bit(PG_dcache_clean, &from->flags)) 698c2ecf20Sopenharmony_ci __flush_dcache_page(page_mapping_file(from), from); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci raw_spin_lock(&minicache_lock); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci raw_spin_unlock(&minicache_lock); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci kunmap_atomic(kto); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * ARMv4 optimised clear_user_page 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_civoid v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci void *ptr, *kaddr = kmap_atomic(page); 888c2ecf20Sopenharmony_ci asm volatile("\ 898c2ecf20Sopenharmony_ci mov r1, %2 @ 1\n\ 908c2ecf20Sopenharmony_ci mov r2, #0 @ 1\n\ 918c2ecf20Sopenharmony_ci mov r3, #0 @ 1\n\ 928c2ecf20Sopenharmony_ci mov ip, #0 @ 1\n\ 938c2ecf20Sopenharmony_ci mov lr, #0 @ 1\n\ 948c2ecf20Sopenharmony_ci1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\ 958c2ecf20Sopenharmony_ci stmia %0!, {r2, r3, ip, lr} @ 4\n\ 968c2ecf20Sopenharmony_ci stmia %0!, {r2, r3, ip, lr} @ 4\n\ 978c2ecf20Sopenharmony_ci mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\ 988c2ecf20Sopenharmony_ci stmia %0!, {r2, r3, ip, lr} @ 4\n\ 998c2ecf20Sopenharmony_ci stmia %0!, {r2, r3, ip, lr} @ 4\n\ 1008c2ecf20Sopenharmony_ci subs r1, r1, #1 @ 1\n\ 1018c2ecf20Sopenharmony_ci bne 1b @ 1" 1028c2ecf20Sopenharmony_ci : "=r" (ptr) 1038c2ecf20Sopenharmony_ci : "0" (kaddr), "I" (PAGE_SIZE / 64) 1048c2ecf20Sopenharmony_ci : "r1", "r2", "r3", "ip", "lr"); 1058c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistruct cpu_user_fns v4_mc_user_fns __initdata = { 1098c2ecf20Sopenharmony_ci .cpu_clear_user_highpage = v4_mc_clear_user_highpage, 1108c2ecf20Sopenharmony_ci .cpu_copy_user_highpage = v4_mc_copy_user_highpage, 1118c2ecf20Sopenharmony_ci}; 112