| @@ -1,564 +1,566 @@ | | | @@ -1,564 +1,566 @@ |
1 | /* $NetBSD: copyout.c,v 1.7 2020/03/05 00:33:56 rin Exp $ */ | | 1 | /* $NetBSD: copyout.c,v 1.8 2020/03/05 02:02:08 rin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects | | 8 | * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects |
9 | * Agency and which was developed by Matt Thomas of 3am Software Foundry. | | 9 | * Agency and which was developed by Matt Thomas of 3am Software Foundry. |
10 | * | | 10 | * |
11 | * This material is based upon work supported by the Defense Advanced Research | | 11 | * This material is based upon work supported by the Defense Advanced Research |
12 | * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under | | 12 | * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under |
13 | * Contract No. N66001-09-C-2073. | | 13 | * Contract No. N66001-09-C-2073. |
14 | * Approved for Public Release, Distribution Unlimited | | 14 | * Approved for Public Release, Distribution Unlimited |
15 | * | | 15 | * |
16 | * Redistribution and use in source and binary forms, with or without | | 16 | * Redistribution and use in source and binary forms, with or without |
17 | * modification, are permitted provided that the following conditions | | 17 | * modification, are permitted provided that the following conditions |
18 | * are met: | | 18 | * are met: |
19 | * 1. Redistributions of source code must retain the above copyright | | 19 | * 1. Redistributions of source code must retain the above copyright |
20 | * notice, this list of conditions and the following disclaimer. | | 20 | * notice, this list of conditions and the following disclaimer. |
21 | * 2. Redistributions in binary form must reproduce the above copyright | | 21 | * 2. Redistributions in binary form must reproduce the above copyright |
22 | * notice, this list of conditions and the following disclaimer in the | | 22 | * notice, this list of conditions and the following disclaimer in the |
23 | * documentation and/or other materials provided with the distribution. | | 23 | * documentation and/or other materials provided with the distribution. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 25 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
26 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #include <sys/cdefs.h> | | 38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: copyout.c,v 1.7 2020/03/05 00:33:56 rin Exp $"); | | 39 | __KERNEL_RCSID(0, "$NetBSD: copyout.c,v 1.8 2020/03/05 02:02:08 rin Exp $"); |
40 | | | 40 | |
41 | #define __UFETCHSTORE_PRIVATE | | 41 | #define __UFETCHSTORE_PRIVATE |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/lwp.h> | | 44 | #include <sys/lwp.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | | | 46 | |
47 | #include <powerpc/pcb.h> | | 47 | #include <powerpc/pcb.h> |
48 | | | 48 | |
49 | #include <powerpc/booke/cpuvar.h> | | 49 | #include <powerpc/booke/cpuvar.h> |
50 | | | 50 | |
51 | static inline void | | 51 | static inline void |
52 | copyout_uint8(uint8_t *udaddr, uint8_t data, register_t ds_msr) | | 52 | copyout_uint8(uint8_t *udaddr, uint8_t data, register_t ds_msr) |
53 | { | | 53 | { |
54 | register_t msr; | | 54 | register_t msr; |
55 | __asm volatile( | | 55 | __asm volatile( |
56 | "mfmsr %[msr]" /* Save MSR */ | | 56 | "mfmsr %[msr]" /* Save MSR */ |
57 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 57 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
58 | "\n\t" "stb %[data],0(%[udaddr])" /* store user byte */ | | 58 | "\n\t" "stb %[data],0(%[udaddr])" /* store user byte */ |
59 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 59 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
60 | : [msr] "=&r" (msr) | | 60 | : [msr] "=&r" (msr) |
61 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); | | 61 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); |
62 | } | | 62 | } |
63 | | | 63 | |
64 | static inline void | | 64 | static inline void |
65 | copyout_uint16(uint16_t *udaddr, uint8_t data, register_t ds_msr) | | 65 | copyout_uint16(uint16_t *udaddr, uint8_t data, register_t ds_msr) |
66 | { | | 66 | { |
67 | register_t msr; | | 67 | register_t msr; |
68 | __asm volatile( | | 68 | __asm volatile( |
69 | "mfmsr %[msr]" /* Save MSR */ | | 69 | "mfmsr %[msr]" /* Save MSR */ |
70 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 70 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
71 | "\n\t" "sth %[data],0(%[udaddr])" /* store user half */ | | 71 | "\n\t" "sth %[data],0(%[udaddr])" /* store user half */ |
72 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 72 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
73 | : [msr] "=&r" (msr) | | 73 | : [msr] "=&r" (msr) |
74 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); | | 74 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); |
75 | } | | 75 | } |
76 | | | 76 | |
77 | static inline void | | 77 | static inline void |
78 | copyout_uint32(uint32_t * const udaddr, uint32_t data, register_t ds_msr) | | 78 | copyout_uint32(uint32_t * const udaddr, uint32_t data, register_t ds_msr) |
79 | { | | 79 | { |
80 | register_t msr; | | 80 | register_t msr; |
81 | __asm volatile( | | 81 | __asm volatile( |
82 | "mfmsr %[msr]" /* Save MSR */ | | 82 | "mfmsr %[msr]" /* Save MSR */ |
83 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 83 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
84 | "\n\t" "stw %[data],0(%[udaddr])" /* store user data */ | | 84 | "\n\t" "stw %[data],0(%[udaddr])" /* store user data */ |
85 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 85 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
86 | : [msr] "=&r" (msr) | | 86 | : [msr] "=&r" (msr) |
87 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); | | 87 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); |
88 | } | | 88 | } |
89 | | | 89 | |
90 | #if 0 | | 90 | #if 0 |
91 | static inline void | | 91 | static inline void |
92 | copyout_le32(uint32_t * const udaddr, uint32_t data, register_t ds_msr) | | 92 | copyout_le32(uint32_t * const udaddr, uint32_t data, register_t ds_msr) |
93 | { | | 93 | { |
94 | register_t msr; | | 94 | register_t msr; |
95 | __asm volatile( | | 95 | __asm volatile( |
96 | "mfmsr %[msr]" /* Save MSR */ | | 96 | "mfmsr %[msr]" /* Save MSR */ |
97 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 97 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
98 | "\n\t" "stwbrx %[data],0,%[udaddr]" /* store user data */ | | 98 | "\n\t" "stwbrx %[data],0,%[udaddr]" /* store user data */ |
99 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 99 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
100 | : [msr] "=&r" (msr) | | 100 | : [msr] "=&r" (msr) |
101 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); | | 101 | : [ds_msr] "r" (ds_msr), [data] "r" (data), [udaddr] "b" (udaddr)); |
102 | } | | 102 | } |
103 | | | 103 | |
104 | static inline void | | 104 | static inline void |
105 | copyout_le32_with_mask(uint32_t * const udaddr, uint32_t data, | | 105 | copyout_le32_with_mask(uint32_t * const udaddr, uint32_t data, |
106 | uint32_t mask, register_t ds_msr) | | 106 | uint32_t mask, register_t ds_msr) |
107 | { | | 107 | { |
108 | register_t msr; | | 108 | register_t msr; |
109 | uint32_t tmp; | | 109 | uint32_t tmp; |
110 | KASSERT((data & ~mask) == 0); | | 110 | KASSERT((data & ~mask) == 0); |
111 | __asm volatile( | | 111 | __asm volatile( |
112 | "mfmsr %[msr]" /* Save MSR */ | | 112 | "mfmsr %[msr]" /* Save MSR */ |
113 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 113 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
114 | "\n\t" "lwbrx %[tmp],0,%[udaddr]" /* fetch user data */ | | 114 | "\n\t" "lwbrx %[tmp],0,%[udaddr]" /* fetch user data */ |
115 | "\n\t" "andc %[tmp],%[tmp],%[mask]" /* mask out new data */ | | 115 | "\n\t" "andc %[tmp],%[tmp],%[mask]" /* mask out new data */ |
116 | "\n\t" "or %[tmp],%[tmp],%[data]" /* merge new data */ | | 116 | "\n\t" "or %[tmp],%[tmp],%[data]" /* merge new data */ |
117 | "\n\t" "stwbrx %[tmp],0,%[udaddr]" /* store user data */ | | 117 | "\n\t" "stwbrx %[tmp],0,%[udaddr]" /* store user data */ |
118 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 118 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
119 | : [msr] "=&r" (msr), [tmp] "=&r" (tmp) | | 119 | : [msr] "=&r" (msr), [tmp] "=&r" (tmp) |
120 | : [ds_msr] "r" (ds_msr), [data] "r" (data), | | 120 | : [ds_msr] "r" (ds_msr), [data] "r" (data), |
121 | [mask] "r" (mask), [udaddr] "b" (udaddr)); | | 121 | [mask] "r" (mask), [udaddr] "b" (udaddr)); |
122 | } | | 122 | } |
123 | #endif | | 123 | #endif |
124 | | | 124 | |
125 | static inline void | | 125 | static inline void |
126 | copyout_16uint8s(const uint8_t *ksaddr8, uint8_t *udaddr8, register_t ds_msr) | | 126 | copyout_16uint8s(const uint8_t *ksaddr8, uint8_t *udaddr8, register_t ds_msr) |
127 | { | | 127 | { |
128 | register_t msr; | | 128 | register_t msr; |
129 | __asm volatile( | | 129 | __asm volatile( |
130 | "mfmsr %[msr]" /* Save MSR */ | | 130 | "mfmsr %[msr]" /* Save MSR */ |
131 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 131 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
132 | "\n\t" "stb %[data0],0(%[udaddr8])" /* store user data */ | | 132 | "\n\t" "stb %[data0],0(%[udaddr8])" /* store user data */ |
133 | "\n\t" "stb %[data1],1(%[udaddr8])" /* store user data */ | | 133 | "\n\t" "stb %[data1],1(%[udaddr8])" /* store user data */ |
134 | "\n\t" "stb %[data2],2(%[udaddr8])" /* store user data */ | | 134 | "\n\t" "stb %[data2],2(%[udaddr8])" /* store user data */ |
135 | "\n\t" "stb %[data3],3(%[udaddr8])" /* store user data */ | | 135 | "\n\t" "stb %[data3],3(%[udaddr8])" /* store user data */ |
136 | "\n\t" "stb %[data4],4(%[udaddr8])" /* store user data */ | | 136 | "\n\t" "stb %[data4],4(%[udaddr8])" /* store user data */ |
137 | "\n\t" "stb %[data5],5(%[udaddr8])" /* store user data */ | | 137 | "\n\t" "stb %[data5],5(%[udaddr8])" /* store user data */ |
138 | "\n\t" "stb %[data6],6(%[udaddr8])" /* store user data */ | | 138 | "\n\t" "stb %[data6],6(%[udaddr8])" /* store user data */ |
139 | "\n\t" "stb %[data7],7(%[udaddr8])" /* store user data */ | | 139 | "\n\t" "stb %[data7],7(%[udaddr8])" /* store user data */ |
140 | "\n\t" "stb %[data8],8(%[udaddr8])" /* store user data */ | | 140 | "\n\t" "stb %[data8],8(%[udaddr8])" /* store user data */ |
141 | "\n\t" "stb %[data9],9(%[udaddr8])" /* store user data */ | | 141 | "\n\t" "stb %[data9],9(%[udaddr8])" /* store user data */ |
142 | "\n\t" "stb %[data10],10(%[udaddr8])" /* store user data */ | | 142 | "\n\t" "stb %[data10],10(%[udaddr8])" /* store user data */ |
143 | "\n\t" "stb %[data11],11(%[udaddr8])" /* store user data */ | | 143 | "\n\t" "stb %[data11],11(%[udaddr8])" /* store user data */ |
144 | "\n\t" "stb %[data12],12(%[udaddr8])" /* store user data */ | | 144 | "\n\t" "stb %[data12],12(%[udaddr8])" /* store user data */ |
145 | "\n\t" "stb %[data13],13(%[udaddr8])" /* store user data */ | | 145 | "\n\t" "stb %[data13],13(%[udaddr8])" /* store user data */ |
146 | "\n\t" "stb %[data14],14(%[udaddr8])" /* store user data */ | | 146 | "\n\t" "stb %[data14],14(%[udaddr8])" /* store user data */ |
147 | "\n\t" "stb %[data15],15(%[udaddr8])" /* store user data */ | | 147 | "\n\t" "stb %[data15],15(%[udaddr8])" /* store user data */ |
148 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 148 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
149 | : [msr] "=&r" (msr) | | 149 | : [msr] "=&r" (msr) |
150 | : [ds_msr] "r" (ds_msr), [udaddr8] "b" (udaddr8), | | 150 | : [ds_msr] "r" (ds_msr), [udaddr8] "b" (udaddr8), |
151 | [data0] "r" (ksaddr8[0]), [data1] "r" (ksaddr8[1]), | | 151 | [data0] "r" (ksaddr8[0]), [data1] "r" (ksaddr8[1]), |
152 | [data2] "r" (ksaddr8[2]), [data3] "r" (ksaddr8[3]), | | 152 | [data2] "r" (ksaddr8[2]), [data3] "r" (ksaddr8[3]), |
153 | [data4] "r" (ksaddr8[4]), [data5] "r" (ksaddr8[5]), | | 153 | [data4] "r" (ksaddr8[4]), [data5] "r" (ksaddr8[5]), |
154 | [data6] "r" (ksaddr8[6]), [data7] "r" (ksaddr8[7]), | | 154 | [data6] "r" (ksaddr8[6]), [data7] "r" (ksaddr8[7]), |
155 | [data8] "r" (ksaddr8[8]), [data9] "r" (ksaddr8[9]), | | 155 | [data8] "r" (ksaddr8[8]), [data9] "r" (ksaddr8[9]), |
156 | [data10] "r" (ksaddr8[10]), [data11] "r" (ksaddr8[11]), | | 156 | [data10] "r" (ksaddr8[10]), [data11] "r" (ksaddr8[11]), |
157 | [data12] "r" (ksaddr8[12]), [data13] "r" (ksaddr8[13]), | | 157 | [data12] "r" (ksaddr8[12]), [data13] "r" (ksaddr8[13]), |
158 | [data14] "r" (ksaddr8[14]), [data15] "r" (ksaddr8[15])); | | 158 | [data14] "r" (ksaddr8[14]), [data15] "r" (ksaddr8[15])); |
159 | } | | 159 | } |
160 | | | 160 | |
161 | static inline void | | 161 | static inline void |
162 | copyout_8uint32s(const uint32_t * const ksaddr32, uint32_t * const udaddr32, | | 162 | copyout_8uint32s(const uint32_t * const ksaddr32, uint32_t * const udaddr32, |
163 | const register_t ds_msr, const size_t line_mask) | | 163 | const register_t ds_msr, const size_t line_mask) |
164 | { | | 164 | { |
165 | register_t msr; | | 165 | register_t msr; |
166 | register_t tmp; | | 166 | register_t tmp; |
167 | __asm volatile( | | 167 | __asm volatile( |
168 | "and. %[tmp],%[line_mask],%[udaddr32]" | | 168 | "and. %[tmp],%[line_mask],%[udaddr32]" |
169 | "\n\t" "mfmsr %[msr]" /* Save MSR */ | | 169 | "\n\t" "mfmsr %[msr]" /* Save MSR */ |
170 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 170 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
171 | "\n\t" "bne 0,1f" | | 171 | "\n\t" "bne 0,1f" |
172 | "\n\t" "dcba 0,%[udaddr32]" | | 172 | "\n\t" "dcba 0,%[udaddr32]" |
173 | "\n" "1:" | | 173 | "\n" "1:" |
174 | "\n\t" "stw %[data0],0(%[udaddr32])" /* store user data */ | | 174 | "\n\t" "stw %[data0],0(%[udaddr32])" /* store user data */ |
175 | "\n\t" "stw %[data1],4(%[udaddr32])" /* store user data */ | | 175 | "\n\t" "stw %[data1],4(%[udaddr32])" /* store user data */ |
176 | "\n\t" "stw %[data2],8(%[udaddr32])" /* store user data */ | | 176 | "\n\t" "stw %[data2],8(%[udaddr32])" /* store user data */ |
177 | "\n\t" "stw %[data3],12(%[udaddr32])" /* store user data */ | | 177 | "\n\t" "stw %[data3],12(%[udaddr32])" /* store user data */ |
178 | "\n\t" "stw %[data4],16(%[udaddr32])" /* store user data */ | | 178 | "\n\t" "stw %[data4],16(%[udaddr32])" /* store user data */ |
179 | "\n\t" "stw %[data5],20(%[udaddr32])" /* store user data */ | | 179 | "\n\t" "stw %[data5],20(%[udaddr32])" /* store user data */ |
180 | "\n\t" "stw %[data6],24(%[udaddr32])" /* store user data */ | | 180 | "\n\t" "stw %[data6],24(%[udaddr32])" /* store user data */ |
181 | "\n\t" "stw %[data7],28(%[udaddr32])" /* store user data */ | | 181 | "\n\t" "stw %[data7],28(%[udaddr32])" /* store user data */ |
182 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 182 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
183 | : [msr] "=&r" (msr), [tmp] "=&r" (tmp) | | 183 | : [msr] "=&r" (msr), [tmp] "=&r" (tmp) |
184 | : [ds_msr] "r" (ds_msr), [udaddr32] "b" (udaddr32), | | 184 | : [ds_msr] "r" (ds_msr), [udaddr32] "b" (udaddr32), |
185 | [line_mask] "r" (line_mask), | | 185 | [line_mask] "r" (line_mask), |
186 | [data0] "r" (ksaddr32[0]), [data1] "r" (ksaddr32[1]), | | 186 | [data0] "r" (ksaddr32[0]), [data1] "r" (ksaddr32[1]), |
187 | [data2] "r" (ksaddr32[2]), [data3] "r" (ksaddr32[3]), | | 187 | [data2] "r" (ksaddr32[2]), [data3] "r" (ksaddr32[3]), |
188 | [data4] "r" (ksaddr32[4]), [data5] "r" (ksaddr32[5]), | | 188 | [data4] "r" (ksaddr32[4]), [data5] "r" (ksaddr32[5]), |
189 | [data6] "r" (ksaddr32[6]), [data7] "r" (ksaddr32[7]) | | 189 | [data6] "r" (ksaddr32[6]), [data7] "r" (ksaddr32[7]) |
190 | : "cr0"); | | 190 | : "cr0"); |
191 | } | | 191 | } |
192 | | | 192 | |
193 | static inline void | | 193 | static inline void |
194 | copyout_16uint32s(const uint32_t * const ksaddr32, uint32_t * const udaddr32, | | 194 | copyout_16uint32s(const uint32_t * const ksaddr32, uint32_t * const udaddr32, |
195 | const register_t ds_msr, const size_t line_mask) | | 195 | const register_t ds_msr, const size_t line_mask) |
196 | { | | 196 | { |
197 | KASSERT(((uintptr_t)udaddr32 & line_mask) == 0); | | 197 | KASSERT(((uintptr_t)udaddr32 & line_mask) == 0); |
198 | register_t msr; | | 198 | register_t msr; |
199 | register_t tmp; | | 199 | register_t tmp; |
200 | __asm volatile( | | 200 | __asm volatile( |
201 | "and. %[tmp],%[line_mask],%[udaddr32]" | | 201 | "and. %[tmp],%[line_mask],%[udaddr32]" |
202 | "\n\t" "cmplwi 2,%[line_size],32" | | 202 | "\n\t" "cmplwi 2,%[line_size],32" |
203 | "\n\t" "mfmsr %[msr]" /* Save MSR */ | | 203 | "\n\t" "mfmsr %[msr]" /* Save MSR */ |
204 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ | | 204 | "\n\t" "mtmsr %[ds_msr]; sync; isync" /* DS on */ |
205 | "\n\t" "bne 0,1f" | | 205 | "\n\t" "bne 0,1f" |
206 | "\n\t" "dcba 0,%[udaddr32]" | | 206 | "\n\t" "dcba 0,%[udaddr32]" |
207 | "\n\t" "bne 2,1f" | | 207 | "\n\t" "bne 2,1f" |
208 | "\n\t" "dcba %[line_size],%[udaddr32]" | | 208 | "\n\t" "dcba %[line_size],%[udaddr32]" |
209 | "\n" "1:" | | 209 | "\n" "1:" |
210 | "\n\t" "stw %[data0],0(%[udaddr32])" /* store user data */ | | 210 | "\n\t" "stw %[data0],0(%[udaddr32])" /* store user data */ |
211 | "\n\t" "stw %[data1],4(%[udaddr32])" /* store user data */ | | 211 | "\n\t" "stw %[data1],4(%[udaddr32])" /* store user data */ |
212 | "\n\t" "stw %[data2],8(%[udaddr32])" /* store user data */ | | 212 | "\n\t" "stw %[data2],8(%[udaddr32])" /* store user data */ |
213 | "\n\t" "stw %[data3],12(%[udaddr32])" /* store user data */ | | 213 | "\n\t" "stw %[data3],12(%[udaddr32])" /* store user data */ |
214 | "\n\t" "stw %[data4],16(%[udaddr32])" /* store user data */ | | 214 | "\n\t" "stw %[data4],16(%[udaddr32])" /* store user data */ |
215 | "\n\t" "stw %[data5],20(%[udaddr32])" /* store user data */ | | 215 | "\n\t" "stw %[data5],20(%[udaddr32])" /* store user data */ |
216 | "\n\t" "stw %[data6],24(%[udaddr32])" /* store user data */ | | 216 | "\n\t" "stw %[data6],24(%[udaddr32])" /* store user data */ |
217 | "\n\t" "stw %[data7],28(%[udaddr32])" /* store user data */ | | 217 | "\n\t" "stw %[data7],28(%[udaddr32])" /* store user data */ |
218 | "\n\t" "stw %[data8],32(%[udaddr32])" /* store user data */ | | 218 | "\n\t" "stw %[data8],32(%[udaddr32])" /* store user data */ |
219 | "\n\t" "stw %[data9],36(%[udaddr32])" /* store user data */ | | 219 | "\n\t" "stw %[data9],36(%[udaddr32])" /* store user data */ |
220 | "\n\t" "stw %[data10],40(%[udaddr32])" /* store user data */ | | 220 | "\n\t" "stw %[data10],40(%[udaddr32])" /* store user data */ |
221 | "\n\t" "stw %[data11],44(%[udaddr32])" /* store user data */ | | 221 | "\n\t" "stw %[data11],44(%[udaddr32])" /* store user data */ |
222 | "\n\t" "stw %[data12],48(%[udaddr32])" /* store user data */ | | 222 | "\n\t" "stw %[data12],48(%[udaddr32])" /* store user data */ |
223 | "\n\t" "stw %[data13],52(%[udaddr32])" /* store user data */ | | 223 | "\n\t" "stw %[data13],52(%[udaddr32])" /* store user data */ |
224 | "\n\t" "stw %[data14],56(%[udaddr32])" /* store user data */ | | 224 | "\n\t" "stw %[data14],56(%[udaddr32])" /* store user data */ |
225 | "\n\t" "stw %[data15],60(%[udaddr32])" /* store user data */ | | 225 | "\n\t" "stw %[data15],60(%[udaddr32])" /* store user data */ |
226 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ | | 226 | "\n\t" "mtmsr %[msr]; sync; isync" /* DS off */ |
227 | : [msr] "=&r" (msr), [tmp] "=&r" (tmp) | | 227 | : [msr] "=&r" (msr), [tmp] "=&r" (tmp) |
228 | : [ds_msr] "r" (ds_msr), [udaddr32] "b" (udaddr32), | | 228 | : [ds_msr] "r" (ds_msr), [udaddr32] "b" (udaddr32), |
229 | [line_size] "r" (line_mask + 1), [line_mask] "r" (line_mask), | | 229 | [line_size] "r" (line_mask + 1), [line_mask] "r" (line_mask), |
230 | [data0] "r" (ksaddr32[0]), [data1] "r" (ksaddr32[1]), | | 230 | [data0] "r" (ksaddr32[0]), [data1] "r" (ksaddr32[1]), |
231 | [data2] "r" (ksaddr32[2]), [data3] "r" (ksaddr32[3]), | | 231 | [data2] "r" (ksaddr32[2]), [data3] "r" (ksaddr32[3]), |
232 | [data4] "r" (ksaddr32[4]), [data5] "r" (ksaddr32[5]), | | 232 | [data4] "r" (ksaddr32[4]), [data5] "r" (ksaddr32[5]), |
233 | [data6] "r" (ksaddr32[6]), [data7] "r" (ksaddr32[7]), | | 233 | [data6] "r" (ksaddr32[6]), [data7] "r" (ksaddr32[7]), |
234 | [data8] "r" (ksaddr32[8]), [data9] "r" (ksaddr32[9]), | | 234 | [data8] "r" (ksaddr32[8]), [data9] "r" (ksaddr32[9]), |
235 | [data10] "r" (ksaddr32[10]), [data11] "r" (ksaddr32[11]), | | 235 | [data10] "r" (ksaddr32[10]), [data11] "r" (ksaddr32[11]), |
236 | [data12] "r" (ksaddr32[12]), [data13] "r" (ksaddr32[13]), | | 236 | [data12] "r" (ksaddr32[12]), [data13] "r" (ksaddr32[13]), |
237 | [data14] "r" (ksaddr32[14]), [data15] "r" (ksaddr32[15]) | | 237 | [data14] "r" (ksaddr32[14]), [data15] "r" (ksaddr32[15]) |
238 | : "cr0", "cr2"); | | 238 | : "cr0", "cr2"); |
239 | } | | 239 | } |
240 | | | 240 | |
241 | static inline void | | 241 | static inline void |
242 | copyout_uint8s(vaddr_t ksaddr, vaddr_t udaddr, size_t len, register_t ds_msr) | | 242 | copyout_uint8s(vaddr_t ksaddr, vaddr_t udaddr, size_t len, register_t ds_msr) |
243 | { | | 243 | { |
244 | const uint8_t *ksaddr8 = (void *)ksaddr; | | 244 | const uint8_t *ksaddr8 = (void *)ksaddr; |
245 | uint8_t *udaddr8 = (void *)udaddr; | | 245 | uint8_t *udaddr8 = (void *)udaddr; |
246 | | | 246 | |
247 | __builtin_prefetch(ksaddr8, 0, 1); | | 247 | __builtin_prefetch(ksaddr8, 0, 1); |
248 | | | 248 | |
249 | for (; len >= 16; len -= 16, ksaddr8 += 16, udaddr8 += 16) { | | 249 | for (; len >= 16; len -= 16, ksaddr8 += 16, udaddr8 += 16) { |
250 | __builtin_prefetch(ksaddr8 + 16, 0, 1); | | 250 | __builtin_prefetch(ksaddr8 + 16, 0, 1); |
251 | copyout_16uint8s(ksaddr8, udaddr8, ds_msr); | | 251 | copyout_16uint8s(ksaddr8, udaddr8, ds_msr); |
252 | } | | 252 | } |
253 | | | 253 | |
254 | while (len-- > 0) { | | 254 | while (len-- > 0) { |
255 | copyout_uint8(udaddr8++, *ksaddr8++, ds_msr); | | 255 | copyout_uint8(udaddr8++, *ksaddr8++, ds_msr); |
256 | } | | 256 | } |
257 | } | | 257 | } |
258 | | | 258 | |
259 | static inline void | | 259 | static inline void |
260 | copyout_uint32s(vaddr_t ksaddr, vaddr_t udaddr, size_t len, register_t ds_msr) | | 260 | copyout_uint32s(vaddr_t ksaddr, vaddr_t udaddr, size_t len, register_t ds_msr) |
261 | { | | 261 | { |
262 | const size_t line_size = curcpu()->ci_ci.dcache_line_size; | | 262 | const size_t line_size = curcpu()->ci_ci.dcache_line_size; |
263 | const size_t line_mask = line_size - 1; | | 263 | const size_t line_mask = line_size - 1; |
264 | const size_t udalignment = udaddr & line_mask; | | 264 | const size_t udalignment = udaddr & line_mask; |
265 | KASSERT((ksaddr & 3) == 0); | | 265 | KASSERT((ksaddr & 3) == 0); |
266 | KASSERT((udaddr & 3) == 0); | | 266 | KASSERT((udaddr & 3) == 0); |
267 | const uint32_t *ksaddr32 = (void *)ksaddr; | | 267 | const uint32_t *ksaddr32 = (void *)ksaddr; |
268 | uint32_t *udaddr32 = (void *)udaddr; | | 268 | uint32_t *udaddr32 = (void *)udaddr; |
269 | len >>= 2; | | 269 | len >>= 2; |
270 | __builtin_prefetch(ksaddr32, 0, 1); | | 270 | __builtin_prefetch(ksaddr32, 0, 1); |
271 | if (udalignment != 0 && udalignment + 4*len > line_size) { | | 271 | if (udalignment != 0 && udalignment + 4*len > line_size) { |
272 | size_t slen = (line_size - udalignment) >> 2; | | 272 | size_t slen = (line_size - udalignment) >> 2; |
273 | len -= slen; | | 273 | len -= slen; |
274 | for (; slen >= 8; ksaddr32 += 8, udaddr32 += 8, slen -= 8) { | | 274 | for (; slen >= 8; ksaddr32 += 8, udaddr32 += 8, slen -= 8) { |
275 | copyout_8uint32s(ksaddr32, udaddr32, ds_msr, line_mask); | | 275 | copyout_8uint32s(ksaddr32, udaddr32, ds_msr, line_mask); |
276 | } | | 276 | } |
277 | while (slen-- > 0) { | | 277 | while (slen-- > 0) { |
278 | copyout_uint32(udaddr32++, *ksaddr32++, ds_msr); | | 278 | copyout_uint32(udaddr32++, *ksaddr32++, ds_msr); |
279 | } | | 279 | } |
280 | if (len == 0) | | 280 | if (len == 0) |
281 | return; | | 281 | return; |
282 | } | | 282 | } |
283 | __builtin_prefetch(ksaddr32, 0, 1); | | 283 | __builtin_prefetch(ksaddr32, 0, 1); |
284 | while (len >= 16) { | | 284 | while (len >= 16) { |
285 | __builtin_prefetch(ksaddr32 + 8, 0, 1); | | 285 | __builtin_prefetch(ksaddr32 + 8, 0, 1); |
286 | __builtin_prefetch(ksaddr32 + 16, 0, 1); | | 286 | __builtin_prefetch(ksaddr32 + 16, 0, 1); |
287 | copyout_16uint32s(ksaddr32, udaddr32, ds_msr, line_mask); | | 287 | copyout_16uint32s(ksaddr32, udaddr32, ds_msr, line_mask); |
288 | ksaddr32 += 16, udaddr32 += 16, len -= 16; | | 288 | ksaddr32 += 16, udaddr32 += 16, len -= 16; |
289 | } | | 289 | } |
290 | KASSERT(len <= 16); | | 290 | KASSERT(len <= 16); |
291 | if (len >= 8) { | | 291 | if (len >= 8) { |
292 | __builtin_prefetch(ksaddr32 + 8, 0, 1); | | 292 | __builtin_prefetch(ksaddr32 + 8, 0, 1); |
293 | copyout_8uint32s(ksaddr32, udaddr32, ds_msr, line_mask); | | 293 | copyout_8uint32s(ksaddr32, udaddr32, ds_msr, line_mask); |
294 | ksaddr32 += 8, udaddr32 += 8, len -= 8; | | 294 | ksaddr32 += 8, udaddr32 += 8, len -= 8; |
295 | } | | 295 | } |
296 | while (len-- > 0) { | | 296 | while (len-- > 0) { |
297 | copyout_uint32(udaddr32++, *ksaddr32++, ds_msr); | | 297 | copyout_uint32(udaddr32++, *ksaddr32++, ds_msr); |
298 | } | | 298 | } |
299 | } | | 299 | } |
300 | | | 300 | |
301 | int | | 301 | int |
302 | _ustore_8(uint8_t *vusaddr, uint8_t val) | | 302 | _ustore_8(uint8_t *vusaddr, uint8_t val) |
303 | { | | 303 | { |
304 | struct pcb * const pcb = lwp_getpcb(curlwp); | | 304 | struct pcb * const pcb = lwp_getpcb(curlwp); |
305 | struct faultbuf env; | | 305 | struct faultbuf env; |
306 | | | 306 | |
307 | if (setfault(&env) != 0) { | | 307 | if (setfault(&env) != 0) { |
308 | pcb->pcb_onfault = NULL; | | 308 | pcb->pcb_onfault = NULL; |
309 | return EFAULT; | | 309 | return EFAULT; |
310 | } | | 310 | } |
311 | | | 311 | |
312 | copyout_uint8(vusaddr, val, mfmsr() | PSL_DS); | | 312 | copyout_uint8(vusaddr, val, mfmsr() | PSL_DS); |
313 | | | 313 | |
314 | pcb->pcb_onfault = NULL; | | 314 | pcb->pcb_onfault = NULL; |
315 | | | 315 | |
316 | return 0; | | 316 | return 0; |
317 | } | | 317 | } |
318 | | | 318 | |
319 | int | | 319 | int |
320 | _ustore_16(uint16_t *vusaddr, uint16_t val) | | 320 | _ustore_16(uint16_t *vusaddr, uint16_t val) |
321 | { | | 321 | { |
322 | struct pcb * const pcb = lwp_getpcb(curlwp); | | 322 | struct pcb * const pcb = lwp_getpcb(curlwp); |
323 | struct faultbuf env; | | 323 | struct faultbuf env; |
324 | | | 324 | |
325 | if (setfault(&env) != 0) { | | 325 | if (setfault(&env) != 0) { |
326 | pcb->pcb_onfault = NULL; | | 326 | pcb->pcb_onfault = NULL; |
327 | return EFAULT; | | 327 | return EFAULT; |
328 | } | | 328 | } |
329 | | | 329 | |
330 | copyout_uint16(vusaddr, val, mfmsr() | PSL_DS); | | 330 | copyout_uint16(vusaddr, val, mfmsr() | PSL_DS); |
331 | | | 331 | |
332 | pcb->pcb_onfault = NULL; | | 332 | pcb->pcb_onfault = NULL; |
333 | | | 333 | |
334 | return 0; | | 334 | return 0; |
335 | } | | 335 | } |
336 | | | 336 | |
337 | int | | 337 | int |
338 | _ustore_32(uint32_t *vusaddr, uint32_t val) | | 338 | _ustore_32(uint32_t *vusaddr, uint32_t val) |
339 | { | | 339 | { |
340 | struct pcb * const pcb = lwp_getpcb(curlwp); | | 340 | struct pcb * const pcb = lwp_getpcb(curlwp); |
341 | struct faultbuf env; | | 341 | struct faultbuf env; |
342 | | | 342 | |
343 | if (setfault(&env) != 0) { | | 343 | if (setfault(&env) != 0) { |
344 | pcb->pcb_onfault = NULL; | | 344 | pcb->pcb_onfault = NULL; |
345 | return EFAULT; | | 345 | return EFAULT; |
346 | } | | 346 | } |
347 | | | 347 | |
348 | copyout_uint32(vusaddr, val, mfmsr() | PSL_DS); | | 348 | copyout_uint32(vusaddr, val, mfmsr() | PSL_DS); |
349 | | | 349 | |
350 | pcb->pcb_onfault = NULL; | | 350 | pcb->pcb_onfault = NULL; |
351 | | | 351 | |
352 | return 0; | | 352 | return 0; |
353 | } | | 353 | } |
354 | | | 354 | |
355 | int | | 355 | int |
356 | copyout(const void *vksaddr, void *vudaddr, size_t len) | | 356 | copyout(const void *vksaddr, void *vudaddr, size_t len) |
357 | { | | 357 | { |
358 | struct pcb * const pcb = lwp_getpcb(curlwp); | | 358 | struct pcb * const pcb = lwp_getpcb(curlwp); |
359 | struct faultbuf env; | | 359 | struct faultbuf env; |
360 | vaddr_t udaddr = (vaddr_t) vudaddr; | | 360 | vaddr_t udaddr = (vaddr_t) vudaddr; |
361 | vaddr_t ksaddr = (vaddr_t) vksaddr; | | 361 | vaddr_t ksaddr = (vaddr_t) vksaddr; |
362 | | | 362 | |
363 | if (__predict_false(len == 0)) { | | 363 | if (__predict_false(len == 0)) { |
364 | return 0; | | 364 | return 0; |
365 | } | | 365 | } |
366 | | | 366 | |
367 | const register_t ds_msr = mfmsr() | PSL_DS; | | 367 | const register_t ds_msr = mfmsr() | PSL_DS; |
368 | | | 368 | |
369 | int rv = setfault(&env); | | 369 | int rv = setfault(&env); |
370 | if (rv != 0) { | | 370 | if (rv != 0) { |
371 | pcb->pcb_onfault = NULL; | | 371 | pcb->pcb_onfault = NULL; |
372 | return rv; | | 372 | return rv; |
373 | } | | 373 | } |
374 | | | 374 | |
375 | if (__predict_false(len < 4)) { | | 375 | if (__predict_false(len < 4)) { |
376 | copyout_uint8s(ksaddr, udaddr, len, ds_msr); | | 376 | copyout_uint8s(ksaddr, udaddr, len, ds_msr); |
377 | pcb->pcb_onfault = NULL; | | 377 | pcb->pcb_onfault = NULL; |
378 | return 0; | | 378 | return 0; |
379 | } | | 379 | } |
380 | | | 380 | |
381 | const size_t alignment = (udaddr ^ ksaddr) & 3; | | 381 | const size_t alignment = (udaddr ^ ksaddr) & 3; |
382 | if (__predict_true(alignment == 0)) { | | 382 | if (__predict_true(alignment == 0)) { |
383 | size_t slen; | | 383 | size_t slen; |
384 | if (__predict_false(ksaddr & 3)) { | | 384 | if (__predict_false(ksaddr & 3)) { |
385 | slen = 4 - (ksaddr & 3); | | 385 | slen = 4 - (ksaddr & 3); |
386 | copyout_uint8s(ksaddr, udaddr, slen, ds_msr); | | 386 | copyout_uint8s(ksaddr, udaddr, slen, ds_msr); |
387 | udaddr += slen, ksaddr += slen, len -= slen; | | 387 | udaddr += slen, ksaddr += slen, len -= slen; |
388 | } | | 388 | } |
389 | slen = len & ~3; | | 389 | slen = len & ~3; |
390 | if (__predict_true(slen >= 4)) { | | 390 | if (__predict_true(slen >= 4)) { |
391 | copyout_uint32s(ksaddr, udaddr, slen, ds_msr); | | 391 | copyout_uint32s(ksaddr, udaddr, slen, ds_msr); |
392 | udaddr += slen, ksaddr += slen, len -= slen; | | 392 | udaddr += slen, ksaddr += slen, len -= slen; |
393 | } | | 393 | } |
394 | } | | 394 | } |
395 | | | 395 | |
396 | if (len > 0) { | | 396 | if (len > 0) { |
397 | copyout_uint8s(ksaddr, udaddr, len, ds_msr); | | 397 | copyout_uint8s(ksaddr, udaddr, len, ds_msr); |
398 | } | | 398 | } |
399 | pcb->pcb_onfault = NULL; | | 399 | pcb->pcb_onfault = NULL; |
400 | return 0; | | 400 | return 0; |
401 | } | | 401 | } |
402 | | | 402 | |
403 | #if 1 | | 403 | #if 1 |
404 | int | | 404 | int |
405 | copyoutstr(const void *ksaddr, void *udaddr, size_t len, size_t *done) | | 405 | copyoutstr(const void *ksaddr, void *udaddr, size_t len, size_t *done) |
406 | { | | 406 | { |
407 | struct pcb * const pcb = lwp_getpcb(curlwp); | | 407 | struct pcb * const pcb = lwp_getpcb(curlwp); |
408 | struct faultbuf env; | | 408 | struct faultbuf env; |
409 | int rv; | | 409 | int rv; |
410 | | | 410 | |
411 | if (__predict_false(len == 0)) { | | 411 | if (__predict_false(len == 0)) { |
412 | if (done) | | 412 | if (done) |
413 | *done = 0; | | 413 | *done = 0; |
414 | return 0; | | 414 | return 0; |
415 | } | | 415 | } |
416 | | | 416 | |
417 | rv = setfault(&env); | | 417 | rv = setfault(&env); |
418 | if (rv != 0) { | | 418 | if (rv != 0) { |
419 | pcb->pcb_onfault = NULL; | | 419 | pcb->pcb_onfault = NULL; |
420 | if (done) | | 420 | if (done) |
421 | *done = 0; | | 421 | *done = 0; |
422 | return rv; | | 422 | return rv; |
423 | } | | 423 | } |
424 | | | 424 | |
425 | const register_t ds_msr = mfmsr() | PSL_DS; | | 425 | const register_t ds_msr = mfmsr() | PSL_DS; |
426 | const uint8_t *ksaddr8 = ksaddr; | | 426 | const uint8_t *ksaddr8 = ksaddr; |
427 | size_t copylen = 0; | | 427 | size_t copylen = 0; |
428 | | | 428 | |
429 | uint8_t *udaddr8 = (void *)udaddr; | | 429 | uint8_t *udaddr8 = (void *)udaddr; |
430 | | | 430 | |
431 | while (copylen++ < len) { | | 431 | while (copylen++ < len) { |
432 | const uint8_t data = *ksaddr8++; | | 432 | const uint8_t data = *ksaddr8++; |
433 | copyout_uint8(udaddr8++, data, ds_msr); | | 433 | copyout_uint8(udaddr8++, data, ds_msr); |
434 | if (data == 0) | | 434 | if (data == 0) |
435 | break; | | 435 | goto out; |
436 | } | | 436 | } |
| | | 437 | rv = ENAMETOOLONG; |
437 | | | 438 | |
| | | 439 | out: |
438 | pcb->pcb_onfault = NULL; | | 440 | pcb->pcb_onfault = NULL; |
439 | if (done) | | 441 | if (done) |
440 | *done = copylen; | | 442 | *done = copylen; |
441 | return 0; | | 443 | return rv; |
442 | } | | 444 | } |
443 | #else | | 445 | #else |
444 | /* XXX This version of copyoutstr(9) has never beeen enabled so far. */ | | 446 | /* XXX This version of copyoutstr(9) has never beeen enabled so far. */ |
445 | int | | 447 | int |
446 | copyoutstr(const void *ksaddr, void *udaddr, size_t len, size_t *lenp) | | 448 | copyoutstr(const void *ksaddr, void *udaddr, size_t len, size_t *lenp) |
447 | { | | 449 | { |
448 | struct pcb * const pcb = lwp_getpcb(curlwp); | | 450 | struct pcb * const pcb = lwp_getpcb(curlwp); |
449 | struct faultbuf env; | | 451 | struct faultbuf env; |
450 | | | 452 | |
451 | if (__predict_false(len == 0)) { | | 453 | if (__predict_false(len == 0)) { |
452 | if (lenp) | | 454 | if (lenp) |
453 | *lenp = 0; | | 455 | *lenp = 0; |
454 | return 0; | | 456 | return 0; |
455 | } | | 457 | } |
456 | | | 458 | |
457 | if (setfault(&env)) { | | 459 | if (setfault(&env)) { |
458 | pcb->pcb_onfault = NULL; | | 460 | pcb->pcb_onfault = NULL; |
459 | if (lenp) | | 461 | if (lenp) |
460 | *lenp = 0; | | 462 | *lenp = 0; |
461 | return EFAULT; | | 463 | return EFAULT; |
462 | } | | 464 | } |
463 | | | 465 | |
464 | const register_t ds_msr = mfmsr() | PSL_DS; | | 466 | const register_t ds_msr = mfmsr() | PSL_DS; |
465 | const uint8_t *ksaddr8 = ksaddr; | | 467 | const uint8_t *ksaddr8 = ksaddr; |
466 | size_t copylen = 0; | | 468 | size_t copylen = 0; |
467 | | | 469 | |
468 | uint32_t *udaddr32 = (void *)((uintptr_t)udaddr & ~3); | | 470 | uint32_t *udaddr32 = (void *)((uintptr_t)udaddr & ~3); |
469 | | | 471 | |
470 | size_t boff = (uintptr_t)udaddr & 3; | | 472 | size_t boff = (uintptr_t)udaddr & 3; |
471 | bool done = false; | | 473 | bool done = false; |
472 | size_t wlen = 0; | | 474 | size_t wlen = 0; |
473 | size_t data = 0; | | 475 | size_t data = 0; |
474 | | | 476 | |
475 | /* | | 477 | /* |
476 | * If the destination buffer doesn't start on a 32-bit boundary | | 478 | * If the destination buffer doesn't start on a 32-bit boundary |
477 | * try to partially fill in the first word. If we succeed we can | | 479 | * try to partially fill in the first word. If we succeed we can |
478 | * finish writing it while preserving the bytes on front. | | 480 | * finish writing it while preserving the bytes on front. |
479 | */ | | 481 | */ |
480 | if (boff > 0) { | | 482 | if (boff > 0) { |
481 | KASSERT(len > 0); | | 483 | KASSERT(len > 0); |
482 | do { | | 484 | do { |
483 | data = (data << 8) | *ksaddr8++; | | 485 | data = (data << 8) | *ksaddr8++; |
484 | wlen++; | | 486 | wlen++; |
485 | done = ((uint8_t)data == 0 || len == wlen); | | 487 | done = ((uint8_t)data == 0 || len == wlen); |
486 | } while (!done && boff + wlen < 4); | | 488 | } while (!done && boff + wlen < 4); |
487 | KASSERT(wlen > 0); | | 489 | KASSERT(wlen > 0); |
488 | data <<= 8 * boff; | | 490 | data <<= 8 * boff; |
489 | if (!done || boff + wlen == 4) { | | 491 | if (!done || boff + wlen == 4) { |
490 | uint32_t mask = 0xffffffff << (8 * boff); | | 492 | uint32_t mask = 0xffffffff << (8 * boff); |
491 | copyout_le32_with_mask(udaddr32++, data, mask, ds_msr); | | 493 | copyout_le32_with_mask(udaddr32++, data, mask, ds_msr); |
492 | boff = 0; | | 494 | boff = 0; |
493 | copylen = wlen; | | 495 | copylen = wlen; |
494 | wlen = 0; | | 496 | wlen = 0; |
495 | data = 0; | | 497 | data = 0; |
496 | } | | 498 | } |
497 | } | | 499 | } |
498 | | | 500 | |
499 | /* | | 501 | /* |
500 | * Now we get to the heart of the routine. Build up complete words | | 502 | * Now we get to the heart of the routine. Build up complete words |
501 | * if possible. When we have one, write it to the user's address | | 503 | * if possible. When we have one, write it to the user's address |
502 | * space and go for the next. If we ran out of space or we found the | | 504 | * space and go for the next. If we ran out of space or we found the |
503 | * end of the string, stop building. If we managed to build a complete | | 505 | * end of the string, stop building. If we managed to build a complete |
504 | * word, just write it and be happy. Otherwise we have to deal with | | 506 | * word, just write it and be happy. Otherwise we have to deal with |
505 | * the trailing bytes. | | 507 | * the trailing bytes. |
506 | */ | | 508 | */ |
507 | KASSERT(done || boff == 0); | | 509 | KASSERT(done || boff == 0); |
508 | KASSERT(done || copylen < len); | | 510 | KASSERT(done || copylen < len); |
509 | while (!done) { | | 511 | while (!done) { |
510 | KASSERT(wlen == 0); | | 512 | KASSERT(wlen == 0); |
511 | KASSERT(copylen < len); | | 513 | KASSERT(copylen < len); |
512 | do { | | 514 | do { |
513 | data = (data << 8) | *ksaddr8++; | | 515 | data = (data << 8) | *ksaddr8++; |
514 | wlen++; | | 516 | wlen++; |
515 | done = ((uint8_t)data == 0 || copylen + wlen == len); | | 517 | done = ((uint8_t)data == 0 || copylen + wlen == len); |
516 | } while (!done && wlen < 4); | | 518 | } while (!done && wlen < 4); |
517 | KASSERT(done || wlen == 4); | | 519 | KASSERT(done || wlen == 4); |
518 | if (__predict_true(wlen == 4)) { | | 520 | if (__predict_true(wlen == 4)) { |
519 | copyout_le32(udaddr32++, data, ds_msr); | | 521 | copyout_le32(udaddr32++, data, ds_msr); |
520 | data = 0; | | 522 | data = 0; |
521 | copylen += wlen; | | 523 | copylen += wlen; |
522 | wlen = 0; | | 524 | wlen = 0; |
523 | KASSERT(copylen < len || done); | | 525 | KASSERT(copylen < len || done); |
524 | } | | 526 | } |
525 | } | | 527 | } |
526 | KASSERT(wlen < 3); | | 528 | KASSERT(wlen < 3); |
527 | if (wlen) { | | 529 | if (wlen) { |
528 | /* | | 530 | /* |
529 | * Remember even though we are running big-endian we are using | | 531 | * Remember even though we are running big-endian we are using |
530 | * byte reversed load/stores so we need to deal with things as | | 532 | * byte reversed load/stores so we need to deal with things as |
531 | * little endian. | | 533 | * little endian. |
532 | * | | 534 | * |
533 | * wlen=1 boff=0: | | 535 | * wlen=1 boff=0: |
534 | * (~(~0 << 8) << 0) -> (~(0xffffff00) << 0) -> 0x000000ff | | 536 | * (~(~0 << 8) << 0) -> (~(0xffffff00) << 0) -> 0x000000ff |
535 | * wlen=1 boff=1: | | 537 | * wlen=1 boff=1: |
536 | * (~(~0 << 8) << 8) -> (~(0xffffff00) << 8) -> 0x0000ff00 | | 538 | * (~(~0 << 8) << 8) -> (~(0xffffff00) << 8) -> 0x0000ff00 |
537 | * wlen=1 boff=2: | | 539 | * wlen=1 boff=2: |
538 | * (~(~0 << 8) << 16) -> (~(0xffffff00) << 16) -> 0x00ff0000 | | 540 | * (~(~0 << 8) << 16) -> (~(0xffffff00) << 16) -> 0x00ff0000 |
539 | * wlen=1 boff=3: | | 541 | * wlen=1 boff=3: |
540 | * (~(~0 << 8) << 24) -> (~(0xffffff00) << 24) -> 0xff000000 | | 542 | * (~(~0 << 8) << 24) -> (~(0xffffff00) << 24) -> 0xff000000 |
541 | * wlen=2 boff=0: | | 543 | * wlen=2 boff=0: |
542 | * (~(~0 << 16) << 0) -> (~(0xffff0000) << 0) -> 0x0000ffff | | 544 | * (~(~0 << 16) << 0) -> (~(0xffff0000) << 0) -> 0x0000ffff |
543 | * wlen=2 boff=1: | | 545 | * wlen=2 boff=1: |
544 | * (~(~0 << 16) << 8) -> (~(0xffff0000) << 8) -> 0x00ffff00 | | 546 | * (~(~0 << 16) << 8) -> (~(0xffff0000) << 8) -> 0x00ffff00 |
545 | * wlen=2 boff=2: | | 547 | * wlen=2 boff=2: |
546 | * (~(~0 << 16) << 16) -> (~(0xffff0000) << 16) -> 0xffff0000 | | 548 | * (~(~0 << 16) << 16) -> (~(0xffff0000) << 16) -> 0xffff0000 |
547 | * wlen=3 boff=0: | | 549 | * wlen=3 boff=0: |
548 | * (~(~0 << 24) << 0) -> (~(0xff000000) << 0) -> 0x00ffffff | | 550 | * (~(~0 << 24) << 0) -> (~(0xff000000) << 0) -> 0x00ffffff |
549 | * wlen=3 boff=1: | | 551 | * wlen=3 boff=1: |
550 | * (~(~0 << 24) << 8) -> (~(0xff000000) << 8) -> 0xffffff00 | | 552 | * (~(~0 << 24) << 8) -> (~(0xff000000) << 8) -> 0xffffff00 |
551 | */ | | 553 | */ |
552 | KASSERT(boff + wlen <= 4); | | 554 | KASSERT(boff + wlen <= 4); |
553 | uint32_t mask = (~(~0 << (8 * wlen))) << (8 * boff); | | 555 | uint32_t mask = (~(~0 << (8 * wlen))) << (8 * boff); |
554 | KASSERT(mask != 0xffffffff); | | 556 | KASSERT(mask != 0xffffffff); |
555 | copyout_le32_with_mask(udaddr32, data, mask, ds_msr); | | 557 | copyout_le32_with_mask(udaddr32, data, mask, ds_msr); |
556 | copylen += wlen; | | 558 | copylen += wlen; |
557 | } | | 559 | } |
558 | | | 560 | |
559 | pcb->pcb_onfault = NULL; | | 561 | pcb->pcb_onfault = NULL; |
560 | if (lenp) | | 562 | if (lenp) |
561 | *lenp = copylen; | | 563 | *lenp = copylen; |
562 | return 0; | | 564 | return 0; |
563 | } | | 565 | } |
564 | #endif | | 566 | #endif |