^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/mm/copypage-v4wb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1995-1999 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/highmem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * ARMv4 optimised copy_user_highpage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * We flush the destination cache lines just before we write the data into the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * corresponding address. Since the Dcache is read-allocate, this removes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Dcache aliasing issue. The writes will be forwarded to the write buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * and merged as appropriate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * instruction. If your processor does not supply this, you have to write your
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * own copy_user_highpage that does the right thing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static void v4wb_copy_user_page(void *kto, const void *kfrom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) asm volatile ("\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) .syntax unified\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) ldmia %1!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) 1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) stmia %0!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) stmia %0!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ldmia %1!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) stmia %0!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ldmia %1!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) subs %2, %2, #1 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) stmia %0!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ldmiane %1!, {r3, r4, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) bne 1b @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) mcr p15, 0, %1, c7, c10, 4 @ 1 drain WB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) : "2" (PAGE_SIZE / 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) : "r3", "r4", "ip", "lr");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) void v4wb_copy_user_highpage(struct page *to, struct page *from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned long vaddr, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) void *kto, *kfrom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) kto = kmap_atomic(to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) kfrom = kmap_atomic(from);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) flush_cache_page(vma, vaddr, page_to_pfn(from));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) v4wb_copy_user_page(kto, kfrom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) kunmap_atomic(kfrom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) kunmap_atomic(kto);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * ARMv4 optimised clear_user_page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Same story as above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) void *ptr, *kaddr = kmap_atomic(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) asm volatile("\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) mov r1, %2 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) mov r2, #0 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) mov r3, #0 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) mov ip, #0 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mov lr, #0 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) 1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) stmia %0!, {r2, r3, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) stmia %0!, {r2, r3, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) stmia %0!, {r2, r3, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) stmia %0!, {r2, r3, ip, lr} @ 4\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) subs r1, r1, #1 @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) bne 1b @ 1\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) : "=r" (ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) : "0" (kaddr), "I" (PAGE_SIZE / 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) : "r1", "r2", "r3", "ip", "lr");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) kunmap_atomic(kaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct cpu_user_fns v4wb_user_fns __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .cpu_clear_user_highpage = v4wb_clear_user_highpage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .cpu_copy_user_highpage = v4wb_copy_user_highpage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) };