11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/arm/mm/copypage-v6.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4SLinus Torvalds * published by the Free Software Foundation. 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/spinlock.h> 121da177e4SLinus Torvalds #include <linux/mm.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <asm/page.h> 151da177e4SLinus Torvalds #include <asm/pgtable.h> 161da177e4SLinus Torvalds #include <asm/shmparam.h> 171da177e4SLinus Torvalds #include <asm/tlbflush.h> 181da177e4SLinus Torvalds #include <asm/cacheflush.h> 191da177e4SLinus Torvalds 20*1b2e2b73SRussell King #include "mm.h" 21*1b2e2b73SRussell King 221da177e4SLinus Torvalds #if SHMLBA > 16384 231da177e4SLinus Torvalds #error FIX ME 241da177e4SLinus Torvalds #endif 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #define from_address (0xffff8000) 271da177e4SLinus Torvalds #define to_address (0xffffc000) 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static DEFINE_SPINLOCK(v6_lock); 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* 321da177e4SLinus Torvalds * Copy the user page. No aliasing to deal with so we can just 331da177e4SLinus Torvalds * attack the kernel's existing mapping of these pages. 341da177e4SLinus Torvalds */ 35b4c2803cSRussell King static void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds copy_page(kto, kfrom); 381da177e4SLinus Torvalds } 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* 411da177e4SLinus Torvalds * Clear the user page. No aliasing to deal with so we can just 421da177e4SLinus Torvalds * attack the kernel's existing mapping of this page. 431da177e4SLinus Torvalds */ 44b4c2803cSRussell King static void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds clear_page(kaddr); 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds /* 501da177e4SLinus Torvalds * Copy the page, taking account of the cache colour. 511da177e4SLinus Torvalds */ 52b4c2803cSRussell King static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr) 531da177e4SLinus Torvalds { 54b8a9b66fSRussell King unsigned int offset = CACHE_COLOUR(vaddr); 551da177e4SLinus Torvalds unsigned long from, to; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * Discard data in the kernel mapping for the new page. 591da177e4SLinus Torvalds * FIXME: needs this MCRR to be supported. 601da177e4SLinus Torvalds */ 611da177e4SLinus Torvalds __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" 621da177e4SLinus Torvalds : 631da177e4SLinus Torvalds : "r" (kto), 641da177e4SLinus Torvalds "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES) 651da177e4SLinus Torvalds : "cc"); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * Now copy the page using the same cache colour as the 691da177e4SLinus Torvalds * pages ultimate destination. 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds spin_lock(&v6_lock); 721da177e4SLinus Torvalds 73b4c2803cSRussell King set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL)); 74b4c2803cSRussell King set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL)); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds from = from_address + (offset << PAGE_SHIFT); 771da177e4SLinus Torvalds to = to_address + (offset << PAGE_SHIFT); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds flush_tlb_kernel_page(from); 801da177e4SLinus Torvalds flush_tlb_kernel_page(to); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds copy_page((void *)to, (void *)from); 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds spin_unlock(&v6_lock); 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* 881da177e4SLinus Torvalds * Clear the user page. We need to deal with the aliasing issues, 891da177e4SLinus Torvalds * so remap the kernel page into the same cache colour as the user 901da177e4SLinus Torvalds * page. 911da177e4SLinus Torvalds */ 92b4c2803cSRussell King static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) 931da177e4SLinus Torvalds { 94b8a9b66fSRussell King unsigned int offset = CACHE_COLOUR(vaddr); 951da177e4SLinus Torvalds unsigned long to = to_address + (offset << PAGE_SHIFT); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* 981da177e4SLinus Torvalds * Discard data in the kernel mapping for the new page 991da177e4SLinus Torvalds * FIXME: needs this MCRR to be supported. 1001da177e4SLinus Torvalds */ 1011da177e4SLinus Torvalds __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06" 1021da177e4SLinus Torvalds : 1031da177e4SLinus Torvalds : "r" (kaddr), 1041da177e4SLinus Torvalds "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES) 1051da177e4SLinus Torvalds : "cc"); 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* 1081da177e4SLinus Torvalds * Now clear the page using the same cache colour as 1091da177e4SLinus Torvalds * the pages ultimate destination. 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds spin_lock(&v6_lock); 1121da177e4SLinus Torvalds 113b4c2803cSRussell King set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL)); 1141da177e4SLinus Torvalds flush_tlb_kernel_page(to); 1151da177e4SLinus Torvalds clear_page((void *)to); 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds spin_unlock(&v6_lock); 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds struct cpu_user_fns v6_user_fns __initdata = { 1211da177e4SLinus Torvalds .cpu_clear_user_page = v6_clear_user_page_nonaliasing, 1221da177e4SLinus Torvalds .cpu_copy_user_page = v6_copy_user_page_nonaliasing, 1231da177e4SLinus Torvalds }; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds static int __init v6_userpage_init(void) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds if (cache_is_vipt_aliasing()) { 1281da177e4SLinus Torvalds cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; 1291da177e4SLinus Torvalds cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds return 0; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 13508ee4e4cSRussell King core_initcall(v6_userpage_init); 136