18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mm/copypage-v6.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 98c2ecf20Sopenharmony_ci#include <linux/mm.h> 108c2ecf20Sopenharmony_ci#include <linux/highmem.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <asm/shmparam.h> 138c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 148c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 158c2ecf20Sopenharmony_ci#include <asm/cachetype.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "mm.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#if SHMLBA > 16384 208c2ecf20Sopenharmony_ci#error FIX ME 218c2ecf20Sopenharmony_ci#endif 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(v6_lock); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Copy the user page. No aliasing to deal with so we can just 278c2ecf20Sopenharmony_ci * attack the kernel's existing mapping of these pages. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic void v6_copy_user_highpage_nonaliasing(struct page *to, 308c2ecf20Sopenharmony_ci struct page *from, unsigned long vaddr, struct vm_area_struct *vma) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci void *kto, *kfrom; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci kfrom = kmap_atomic(from); 358c2ecf20Sopenharmony_ci kto = kmap_atomic(to); 368c2ecf20Sopenharmony_ci copy_page(kto, kfrom); 378c2ecf20Sopenharmony_ci kunmap_atomic(kto); 388c2ecf20Sopenharmony_ci kunmap_atomic(kfrom); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Clear the user page. No aliasing to deal with so we can just 438c2ecf20Sopenharmony_ci * attack the kernel's existing mapping of this page. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci void *kaddr = kmap_atomic(page); 488c2ecf20Sopenharmony_ci clear_page(kaddr); 498c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * Discard data in the kernel mapping for the new page. 548c2ecf20Sopenharmony_ci * FIXME: needs this MCRR to be supported. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic void discard_old_kernel_data(void *kto) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" 598c2ecf20Sopenharmony_ci : 608c2ecf20Sopenharmony_ci : "r" (kto), 618c2ecf20Sopenharmony_ci "r" ((unsigned long)kto + PAGE_SIZE - 1) 628c2ecf20Sopenharmony_ci : "cc"); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * Copy the page, taking account of the cache colour. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic void v6_copy_user_highpage_aliasing(struct page *to, 698c2ecf20Sopenharmony_ci struct page *from, unsigned long vaddr, struct vm_area_struct *vma) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci unsigned int offset = CACHE_COLOUR(vaddr); 728c2ecf20Sopenharmony_ci unsigned long kfrom, kto; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (!test_and_set_bit(PG_dcache_clean, &from->flags)) 758c2ecf20Sopenharmony_ci __flush_dcache_page(page_mapping_file(from), from); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* FIXME: not highmem safe */ 788c2ecf20Sopenharmony_ci discard_old_kernel_data(page_address(to)); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * Now copy the page using the same cache colour as the 828c2ecf20Sopenharmony_ci * pages ultimate destination. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci raw_spin_lock(&v6_lock); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci kfrom = COPYPAGE_V6_FROM + (offset << PAGE_SHIFT); 878c2ecf20Sopenharmony_ci kto = COPYPAGE_V6_TO + (offset << PAGE_SHIFT); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci set_top_pte(kfrom, mk_pte(from, PAGE_KERNEL)); 908c2ecf20Sopenharmony_ci set_top_pte(kto, mk_pte(to, PAGE_KERNEL)); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci copy_page((void *)kto, (void *)kfrom); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci raw_spin_unlock(&v6_lock); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Clear the user page. We need to deal with the aliasing issues, 998c2ecf20Sopenharmony_ci * so remap the kernel page into the same cache colour as the user 1008c2ecf20Sopenharmony_ci * page. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci unsigned long to = COPYPAGE_V6_TO + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* FIXME: not highmem safe */ 1078c2ecf20Sopenharmony_ci discard_old_kernel_data(page_address(page)); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Now clear the page using the same cache colour as 1118c2ecf20Sopenharmony_ci * the pages ultimate destination. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci raw_spin_lock(&v6_lock); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci set_top_pte(to, mk_pte(page, PAGE_KERNEL)); 1168c2ecf20Sopenharmony_ci clear_page((void *)to); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci raw_spin_unlock(&v6_lock); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistruct cpu_user_fns v6_user_fns __initdata = { 1228c2ecf20Sopenharmony_ci .cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing, 1238c2ecf20Sopenharmony_ci .cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int __init v6_userpage_init(void) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (cache_is_vipt_aliasing()) { 1298c2ecf20Sopenharmony_ci cpu_user.cpu_clear_user_highpage = v6_clear_user_highpage_aliasing; 1308c2ecf20Sopenharmony_ci cpu_user.cpu_copy_user_highpage = v6_copy_user_highpage_aliasing; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cicore_initcall(v6_userpage_init); 137