summaryrefslogtreecommitdiff
path: root/na/arch/riscv/uaccess/uaccess_memcpy.S
blob: 615680def2d6de20bff415d349f9dcb2a08bbdef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */

#include <arch/extable.h>

/*
 * extern "C" int __uaccess_memcpy(void* dst, const void* src, uint64 len);
 *
 * a0: dst
 * a1: src
 * a2: len
 * Returns: 0 on success, -EFAULT (-14) on page fault.
 */
.global __uaccess_memcpy
.type __uaccess_memcpy, @function
__uaccess_memcpy:
    /* If len == 0, return 0 */
    beqz a2, .Lmemcpy_done

    /* Enable SUM (Supervisor User Memory) bit: sstatus.SUM is bit 18 */
    li t0, (1 << 18)
    csrs sstatus, t0

.Lmemcpy_loop:
    /* Load byte from src */
1:  lb t1, 0(a1)
    /* Store byte to dst */
2:  sb t1, 0(a0)

    addi a0, a0, 1
    addi a1, a1, 1
    addi a2, a2, -1
    bnez a2, .Lmemcpy_loop

.Lmemcpy_done:
    /* Disable SUM */
    li t0, (1 << 18)
    csrc sstatus, t0
    li a0, 0
    ret

.Lmemcpy_fault:
    /* Fixup routine on fault */
    /* Disable SUM */
    li t0, (1 << 18)
    csrc sstatus, t0
    li a0, -14 /* -EFAULT */
    ret

/* Exception table entries */
EXTABLE(1b, .Lmemcpy_fault)
EXTABLE(2b, .Lmemcpy_fault)


/*
 * extern "C" int64 __uaccess_strncpy(char* dst, const char* src, uint64 max_len);
 *
 * a0: dst
 * a1: src
 * a2: max_len
 * Returns: number of bytes copied (excluding null), or -EFAULT (-14) on page fault.
 */
.global __uaccess_strncpy
.type __uaccess_strncpy, @function
__uaccess_strncpy:
    /* If max_len == 0, return 0 */
    beqz a2, .Lstrncpy_done_zero

    /* Enable SUM */
    li t0, (1 << 18)
    csrs sstatus, t0

    /* t2 will store the length copied */
    li t2, 0

.Lstrncpy_loop:
    /* Load byte from src */
3:  lb t1, 0(a1)
    /* Store byte to dst */
4:  sb t1, 0(a0)

    /* If it was the null terminator, we're done */
    beqz t1, .Lstrncpy_done

    addi a0, a0, 1
    addi a1, a1, 1
    addi t2, t2, 1
    addi a2, a2, -1
    bnez a2, .Lstrncpy_loop

    /* Reached max_len without finding null */
    /* We must null-terminate at max_len - 1 as per typical strncpy_from_user semantics */
    addi a0, a0, -1
    sb zero, 0(a0)
    addi t2, t2, -1 /* length of string without the forced null terminator */

.Lstrncpy_done:
    /* Disable SUM */
    li t0, (1 << 18)
    csrc sstatus, t0
    mv a0, t2
    ret

.Lstrncpy_done_zero:
    li a0, 0
    ret

.Lstrncpy_fault:
    /* Fixup routine on fault */
    li t0, (1 << 18)
    csrc sstatus, t0
    li a0, -14 /* -EFAULT */
    ret

/* Exception table entries */
EXTABLE(3b, .Lstrncpy_fault)
EXTABLE(4b, .Lstrncpy_fault)