1281494Sandrew/*- 2281494Sandrew * Copyright (c) 2015 The FreeBSD Foundation 3281494Sandrew * All rights reserved. 4281494Sandrew * 5281494Sandrew * This software was developed by Andrew Turner under 6281494Sandrew * sponsorship from the FreeBSD Foundation. 7281494Sandrew * 8281494Sandrew * Redistribution and use in source and binary forms, with or without 9281494Sandrew * modification, are permitted provided that the following conditions 10281494Sandrew * are met: 11281494Sandrew * 1. Redistributions of source code must retain the above copyright 12281494Sandrew * notice, this list of conditions and the following disclaimer. 13281494Sandrew * 2. Redistributions in binary form must reproduce the above copyright 14281494Sandrew * notice, this list of conditions and the following disclaimer in the 15281494Sandrew * documentation and/or other materials provided with the distribution. 16281494Sandrew * 17281494Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18281494Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19281494Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20281494Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21281494Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22281494Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23281494Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24281494Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25281494Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26281494Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27281494Sandrew * SUCH DAMAGE. 28281494Sandrew * 29281494Sandrew */ 30281494Sandrew 31281494Sandrew#include <machine/asm.h> 32281494Sandrew__FBSDID("$FreeBSD: stable/11/sys/arm64/arm64/copyinout.S 319202 2017-05-30 12:26:36Z andrew $"); 33281494Sandrew 34281494Sandrew#include <sys/errno.h> 35281494Sandrew 36297615Sandrew#include <machine/vmparam.h> 37297615Sandrew 38281494Sandrew#include "assym.s" 39281494Sandrew 40281494Sandrew/* 41281494Sandrew * Fault handler for the copy{in,out} functions below. 42281494Sandrew */ 43281494SandrewENTRY(copyio_fault) 44281494Sandrew SET_FAULT_HANDLER(xzr, x1) /* Clear the handler */ 45319202Sandrew EXIT_USER_ACCESS_CHECK(w0, x1) 46289454Skibcopyio_fault_nopcb: 47281494Sandrew mov x0, #EFAULT 48281494Sandrew ret 49281494SandrewEND(copyio_fault) 50281494Sandrew 51281494Sandrew/* 52281494Sandrew * Copies from a kernel to user address 53281494Sandrew * 54281494Sandrew * int copyout(const void *kaddr, void *udaddr, size_t len) 55281494Sandrew */ 56281494SandrewENTRY(copyout) 57297209Swma cbz x2, 1f 58297235Swma adds x3, x1, x2 59297235Swma b.cs copyio_fault_nopcb 60289454Skib ldr x4, =VM_MAXUSER_ADDRESS 61289454Skib cmp x3, x4 62289454Skib b.hi copyio_fault_nopcb 63281494Sandrew 64297209Swma b copycommon 65281494Sandrew 66297209Swma1: mov x0, xzr /* return 0 */ 67297209Swma ret 68281494Sandrew 69281494SandrewEND(copyout) 70281494Sandrew 71281494Sandrew/* 72281494Sandrew * Copies from a user to kernel address 73281494Sandrew * 74281494Sandrew * int copyin(const void *uaddr, void *kdaddr, size_t len) 75281494Sandrew */ 76281494SandrewENTRY(copyin) 77297209Swma cbz x2, 1f 78297235Swma adds x3, x0, x2 79297235Swma b.cs copyio_fault_nopcb 80289454Skib ldr x4, =VM_MAXUSER_ADDRESS 81289454Skib cmp x3, x4 82289454Skib b.hi copyio_fault_nopcb 83281494Sandrew 84297209Swma b copycommon 85281494Sandrew 86297209Swma1: mov x0, xzr /* return 0 */ 87297209Swma ret 88281494Sandrew 89281494SandrewEND(copyin) 90281494Sandrew 91281494Sandrew/* 92281494Sandrew * Copies a string from a user to kernel address 93281494Sandrew * 94281494Sandrew * int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) 95281494Sandrew */ 96281494SandrewENTRY(copyinstr) 97281494Sandrew mov x5, xzr /* count = 0 */ 98287596Sandrew mov w4, #1 /* If zero return faulure */ 99281494Sandrew cbz x2, 3f /* If len == 0 then skip loop */ 100281494Sandrew 101281494Sandrew adr x6, copyio_fault /* Get the handler address */ 102281494Sandrew SET_FAULT_HANDLER(x6, x7) /* Set the handler */ 103319202Sandrew ENTER_USER_ACCESS(w6, x7) 104281494Sandrew 105297235Swma ldr x7, =VM_MAXUSER_ADDRESS 106289454Skib1: cmp x0, x7 107289454Skib b.cs copyio_fault 108319202Sandrew ldtrb w4, [x0] /* Load from uaddr */ 109319202Sandrew add x0, x0, #1 /* Next char */ 110281494Sandrew strb w4, [x1], #1 /* Store in kaddr */ 111287596Sandrew add x5, x5, #1 /* count++ */ 112287596Sandrew cbz w4, 2f /* Break when NUL-terminated */ 113281494Sandrew sub x2, x2, #1 /* len-- */ 114281494Sandrew cbnz x2, 1b 115281494Sandrew 116319202Sandrew2: EXIT_USER_ACCESS(w6) 117319202Sandrew SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */ 118281494Sandrew 119319202Sandrew 120281494Sandrew3: cbz x3, 4f /* Check if done != NULL */ 121281494Sandrew str x5, [x3] /* done = count */ 122281494Sandrew 123287596Sandrew4: mov w1, #ENAMETOOLONG /* Load ENAMETOOLONG to return if failed */ 124287596Sandrew cmp w4, #0 /* Check if we saved the NUL-terminator */ 125287596Sandrew csel w0, wzr, w1, eq /* If so return success, else failure */ 126281494Sandrew ret 127281494SandrewEND(copyinstr) 128297209Swma 129297209Swma/* 130297209Swma * Local helper 131297209Swma * 132297209Swma * x0 - src pointer 133297209Swma * x1 - dst pointer 134297209Swma * x2 - size 135297209Swma * lr - the return address, so jump here instead of calling 136297209Swma * 137297209Swma * This function is optimized to minimize concurrent memory accesses. In 138297209Swma * present form it is suited for cores with a single memory prefetching 139297209Swma * unit. 140297209Swma * ARM64TODO: 141297209Swma * Consider using separate functions for each ARM64 core. Adding memory 142297209Swma * access interleaving might increase a total throughput on A57 or A72. 143297209Swma */ 144297209Swma .text 145297209Swma .align 4 146297209Swma .local copycommon 147297209Swma .type copycommon,@function 148297209Swma 149297209Swmacopycommon: 150297209Swma adr x6, copyio_fault /* Get the handler address */ 151297209Swma SET_FAULT_HANDLER(x6, x7) /* Set the handler */ 152319202Sandrew ENTER_USER_ACCESS(w6, x7) 153297209Swma 154297209Swma /* Check alignment */ 155297209Swma orr x3, x0, x1 156297209Swma ands x3, x3, 0x07 157297209Swma b.eq aligned 158297209Swma 159297209Swma /* Unaligned is byte by byte copy */ 160297209Swmabyte_by_byte: 161297209Swma ldrb w3, [x0], #0x01 162297209Swma strb w3, [x1], #0x01 163297209Swma subs x2, x2, #0x01 164297209Swma b.ne byte_by_byte 165297209Swma b ending 166297209Swma 167297209Swmaaligned: 168297209Swma cmp x2, #0x10 169297209Swma b.lt lead_out 170297209Swma cmp x2, #0x40 171297209Swma b.lt by_dwords_start 172297209Swma 173297209Swma /* Block copy */ 174297209Swma lsr x15, x2, #0x06 175297209Swmaby_blocks: 176297209Swma ldp x3, x4, [x0], #0x10 177297209Swma ldp x5, x6, [x0], #0x10 178297209Swma ldp x7, x8, [x0], #0x10 179297209Swma ldp x9, x10, [x0], #0x10 180297209Swma stp x3, x4, [x1], #0x10 181297209Swma stp x5, x6, [x1], #0x10 182297209Swma stp x7, x8, [x1], #0x10 183297209Swma stp x9, x10, [x1], #0x10 184297209Swma 185297209Swma subs x15, x15, #0x01 186297209Swma b.ne by_blocks 187297209Swma 188297209Swma and x2, x2, #0x3f 189297209Swma 190297209Swmaby_dwords_start: 191297209Swma lsr x15, x2, #0x04 192297209Swma cbz x15, lead_out 193297209Swmaby_dwords: 194297209Swma ldp x3, x4, [x0], #0x10 195297209Swma stp x3, x4, [x1], #0x10 196297209Swma subs x15, x15, #0x01 197297209Swma b.ne by_dwords 198297209Swma 199297209Swma /* Less than 16 bytes to copy */ 200297209Swmalead_out: 201297209Swma tbz x2, #0x03, last_word 202297209Swma ldr x3, [x0], #0x08 203297209Swma str x3, [x1], #0x08 204297209Swma 205297209Swmalast_word: 206297209Swma tbz x2, #0x02, last_hword 207297209Swma ldr w3, [x0], #0x04 208297209Swma str w3, [x1], #0x04 209297209Swma 210297209Swmalast_hword: 211297209Swma tbz x2, #0x01, last_byte 212297209Swma ldrh w3, [x0], #0x02 213297209Swma strh w3, [x1], #0x02 214297209Swma 215297209Swmalast_byte: 216297209Swma tbz x2, #0x00, ending 217297209Swma ldrb w3, [x0] 218297209Swma strb w3, [x1] 219297209Swma 220297209Swmaending: 221319202Sandrew EXIT_USER_ACCESS_CHECK(w6, x7) 222297209Swma SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */ 223297209Swma 224297209Swma mov x0, xzr /* return 0 */ 225297209Swma ret 226297209Swma .size copycommon, . - copycommon 227