linux/arch/arm/mm/copypage-v6.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mm/copypage-v6.c
   3 *
   4 *  Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/init.h>
  11#include <linux/spinlock.h>
  12#include <linux/mm.h>
  13
  14#include <asm/page.h>
  15#include <asm/pgtable.h>
  16#include <asm/shmparam.h>
  17#include <asm/tlbflush.h>
  18#include <asm/cacheflush.h>
  19#include <asm/cachetype.h>
  20
  21#include "mm.h"
  22
  23#if SHMLBA > 16384
  24#error FIX ME
  25#endif
  26
  27#define from_address    (0xffff8000)
  28#define to_address      (0xffffc000)
  29
  30static DEFINE_SPINLOCK(v6_lock);
  31
  32/*
  33 * Copy the user page.  No aliasing to deal with so we can just
  34 * attack the kernel's existing mapping of these pages.
  35 */
  36static void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr)
  37{
  38        copy_page(kto, kfrom);
  39}
  40
  41/*
  42 * Clear the user page.  No aliasing to deal with so we can just
  43 * attack the kernel's existing mapping of this page.
  44 */
  45static void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr)
  46{
  47        clear_page(kaddr);
  48}
  49
  50/*
  51 * Copy the page, taking account of the cache colour.
  52 */
  53static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr)
  54{
  55        unsigned int offset = CACHE_COLOUR(vaddr);
  56        unsigned long from, to;
  57        struct page *page = virt_to_page(kfrom);
  58
  59        if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
  60                __flush_dcache_page(page_mapping(page), page);
  61
  62        /*
  63         * Discard data in the kernel mapping for the new page.
  64         * FIXME: needs this MCRR to be supported.
  65         */
  66        __asm__("mcrr   p15, 0, %1, %0, c6      @ 0xec401f06"
  67           :
  68           : "r" (kto),
  69             "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
  70           : "cc");
  71
  72        /*
  73         * Now copy the page using the same cache colour as the
  74         * pages ultimate destination.
  75         */
  76        spin_lock(&v6_lock);
  77
  78        set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL), 0);
  79        set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL), 0);
  80
  81        from = from_address + (offset << PAGE_SHIFT);
  82        to   = to_address + (offset << PAGE_SHIFT);
  83
  84        flush_tlb_kernel_page(from);
  85        flush_tlb_kernel_page(to);
  86
  87        copy_page((void *)to, (void *)from);
  88
  89        spin_unlock(&v6_lock);
  90}
  91
  92/*
  93 * Clear the user page.  We need to deal with the aliasing issues,
  94 * so remap the kernel page into the same cache colour as the user
  95 * page.
  96 */
  97static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
  98{
  99        unsigned int offset = CACHE_COLOUR(vaddr);
 100        unsigned long to = to_address + (offset << PAGE_SHIFT);
 101
 102        /*
 103         * Discard data in the kernel mapping for the new page
 104         * FIXME: needs this MCRR to be supported.
 105         */
 106        __asm__("mcrr   p15, 0, %1, %0, c6      @ 0xec401f06"
 107           :
 108           : "r" (kaddr),
 109             "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES)
 110           : "cc");
 111
 112        /*
 113         * Now clear the page using the same cache colour as
 114         * the pages ultimate destination.
 115         */
 116        spin_lock(&v6_lock);
 117
 118        set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL), 0);
 119        flush_tlb_kernel_page(to);
 120        clear_page((void *)to);
 121
 122        spin_unlock(&v6_lock);
 123}
 124
 125struct cpu_user_fns v6_user_fns __initdata = {
 126        .cpu_clear_user_page    = v6_clear_user_page_nonaliasing,
 127        .cpu_copy_user_page     = v6_copy_user_page_nonaliasing,
 128};
 129
 130static int __init v6_userpage_init(void)
 131{
 132        if (cache_is_vipt_aliasing()) {
 133                cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
 134                cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
 135        }
 136
 137        return 0;
 138}
 139
 140core_initcall(v6_userpage_init);
 141
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.