10aea86a2SCatalin Marinas/* 20aea86a2SCatalin Marinas * Copyright (C) 2012 ARM Ltd. 30aea86a2SCatalin Marinas * 40aea86a2SCatalin Marinas * This program is free software; you can redistribute it and/or modify 50aea86a2SCatalin Marinas * it under the terms of the GNU General Public License version 2 as 60aea86a2SCatalin Marinas * published by the Free Software Foundation. 70aea86a2SCatalin Marinas * 80aea86a2SCatalin Marinas * This program is distributed in the hope that it will be useful, 90aea86a2SCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of 100aea86a2SCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 110aea86a2SCatalin Marinas * GNU General Public License for more details. 120aea86a2SCatalin Marinas * 130aea86a2SCatalin Marinas * You should have received a copy of the GNU General Public License 140aea86a2SCatalin Marinas * along with this program. If not, see <http://www.gnu.org/licenses/>. 150aea86a2SCatalin Marinas */ 160aea86a2SCatalin Marinas 170aea86a2SCatalin Marinas#include <linux/linkage.h> 18338d4f49SJames Morse 19338d4f49SJames Morse#include <asm/alternative.h> 200aea86a2SCatalin Marinas#include <asm/assembler.h> 21338d4f49SJames Morse#include <asm/cpufeature.h> 22338d4f49SJames Morse#include <asm/sysreg.h> 230aea86a2SCatalin Marinas 240aea86a2SCatalin Marinas/* 250aea86a2SCatalin Marinas * Copy from user space to a kernel buffer (alignment handled by the hardware) 260aea86a2SCatalin Marinas * 270aea86a2SCatalin Marinas * Parameters: 280aea86a2SCatalin Marinas * x0 - to 290aea86a2SCatalin Marinas * x1 - from 300aea86a2SCatalin Marinas * x2 - n 310aea86a2SCatalin Marinas * Returns: 320aea86a2SCatalin Marinas * x0 - bytes not copied 330aea86a2SCatalin Marinas */ 340aea86a2SCatalin MarinasENTRY(__copy_from_user) 35338d4f49SJames MorseALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ 36338d4f49SJames Morse CONFIG_ARM64_PAN) 3723e94994SWill Deacon add x5, x1, x2 // upper user buffer boundary 3823e94994SWill Deacon subs x2, x2, #16 3923e94994SWill Deacon b.mi 1f 4023e94994SWill Deacon0: 4123e94994SWill DeaconUSER(9f, ldp x3, x4, [x1], #16) 4223e94994SWill Deacon subs x2, x2, #16 4323e94994SWill Deacon stp x3, x4, [x0], #16 4423e94994SWill Deacon b.pl 0b 4523e94994SWill Deacon1: adds x2, x2, #8 460aea86a2SCatalin Marinas b.mi 2f 470aea86a2SCatalin MarinasUSER(9f, ldr x3, [x1], #8 ) 4823e94994SWill Deacon sub x2, x2, #8 490aea86a2SCatalin Marinas str x3, [x0], #8 500aea86a2SCatalin Marinas2: adds x2, x2, #4 510aea86a2SCatalin Marinas b.mi 3f 520aea86a2SCatalin MarinasUSER(9f, ldr w3, [x1], #4 ) 530aea86a2SCatalin Marinas sub x2, x2, #4 540aea86a2SCatalin Marinas str w3, [x0], #4 550aea86a2SCatalin Marinas3: adds x2, x2, #2 560aea86a2SCatalin Marinas b.mi 4f 570aea86a2SCatalin MarinasUSER(9f, ldrh w3, [x1], #2 ) 580aea86a2SCatalin Marinas sub x2, x2, #2 590aea86a2SCatalin Marinas strh w3, [x0], #2 600aea86a2SCatalin Marinas4: adds x2, x2, #1 610aea86a2SCatalin Marinas b.mi 5f 620aea86a2SCatalin MarinasUSER(9f, ldrb w3, [x1] ) 630aea86a2SCatalin Marinas strb w3, [x0] 640aea86a2SCatalin Marinas5: mov x0, #0 65338d4f49SJames MorseALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ 66338d4f49SJames Morse CONFIG_ARM64_PAN) 670aea86a2SCatalin Marinas ret 680aea86a2SCatalin MarinasENDPROC(__copy_from_user) 690aea86a2SCatalin Marinas 700aea86a2SCatalin Marinas .section .fixup,"ax" 710aea86a2SCatalin Marinas .align 2 7223e94994SWill Deacon9: sub x2, x5, x1 730aea86a2SCatalin Marinas mov x3, x2 740aea86a2SCatalin Marinas10: strb wzr, [x0], #1 // zero remaining buffer space 750aea86a2SCatalin Marinas subs x3, x3, #1 760aea86a2SCatalin Marinas b.ne 10b 770aea86a2SCatalin Marinas mov x0, x2 // bytes not copied 780aea86a2SCatalin Marinas ret 790aea86a2SCatalin Marinas .previous 80