1// Copyright 2016 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include <asm.h>
8#include <err.h>
9
10lr .req x30
11dst .req x0
12src .req x1
13len .req x2
14fault_return_ptr .req x3
15temp .req x15
16
17// NOTE! We know here that the memcpy code doesn't touch these registers,
18// so we can use them to save values.  But they are call-clobbered in the
19// C ABI, so we don't need a stack frame.
20saved_fault_return_ptr .req x16
21saved_lr .req x17
22
23// zx_status_t _arm64_user_copy(void *dst, const void *src, size_t len, void **fault_return)
24.section .text._arm64_user_copy,"ax"
25.balign 64 // Align to cache line.  This code fits in one cache line.
26FUNCTION(_arm64_user_copy)
27
28    adr temp, .Lfault_from_user
29
30    mov saved_fault_return_ptr, fault_return_ptr
31    .cfi_register fault_return_ptr, saved_fault_return_ptr
32    mov saved_lr, lr
33    .cfi_register lr, saved_lr
34
35    // Just call our normal memcpy.  The caller has ensured that the
36    // address range is in the user portion of the address space.
37    // While fault_return_ptr is set, userspace data faults will be
38    // redirected to .Lfault_from_user, below.
39    //
40    // NOTE! We make important assumptions here about what the memcpy
41    // code does: it never moves the stack pointer, and it never touches
42    // the registers we're using for saved_fault_return_ptr and saved_lr.
43    str temp, [fault_return_ptr]
44    bl memcpy
45    mov x0, #ZX_OK
46
47.Luser_copy_return:
48    str xzr, [saved_fault_return_ptr]
49    mov lr, saved_lr
50    .cfi_same_value lr
51    ret
52END_FUNCTION(_arm64_user_copy)
53
54.section .text.cold._arm64_user_copy,"ax"
55.Lfault_from_user:
56    .cfi_startproc
57    .cfi_register fault_return_ptr, saved_fault_return_ptr
58    .cfi_register lr, saved_lr
59    mov x0, #ZX_ERR_INVALID_ARGS
60    b .Luser_copy_return
61    .cfi_endproc
62