OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2010 The Native Client Authors. All rights reserved. | 2 * Copyright 2010 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can | 3 * Use of this source code is governed by a BSD-style license that can |
4 * be found in the LICENSE file. | 4 * be found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* | 7 /* |
8 * nccopycode.c | 8 * nccopycode.c |
9 * Copies two code streams in a thread-safe way | 9 * Copies two code streams in a thread-safe way |
10 * | 10 * |
11 */ | 11 */ |
12 | 12 |
13 #include "native_client/src/include/portability.h" | 13 #include "native_client/src/include/portability.h" |
14 | 14 |
15 #if NACL_WINDOWS == 1 | 15 #if NACL_WINDOWS == 1 |
16 #include <windows.h> | 16 #include <windows.h> |
17 #else | 17 #else |
18 #include <sys/mman.h> | 18 #include <sys/mman.h> |
19 #endif | 19 #endif |
20 | 20 |
21 #include <stdio.h> | 21 #include <stdio.h> |
22 #include <stdlib.h> | 22 #include <stdlib.h> |
23 #include <errno.h> | 23 #include <errno.h> |
24 #include <string.h> | 24 #include <string.h> |
25 #include <assert.h> | 25 #include <assert.h> |
26 #include "native_client/src/shared/platform/nacl_check.h" | |
27 #if NACL_TARGET_SUBARCH == 32 | |
26 #include "native_client/src/trusted/validator_x86/ncdecode.h" | 28 #include "native_client/src/trusted/validator_x86/ncdecode.h" |
27 #include "native_client/src/trusted/validator_x86/ncvalidate.h" | 29 #include "native_client/src/trusted/validator_x86/ncvalidate.h" |
28 #include "native_client/src/shared/platform/nacl_check.h" | 30 #elif NACL_TARGET_SUBARCH == 64 |
31 #include "native_client/src/trusted/validator_x86/nc_inst_iter.h" | |
32 #include "native_client/src/trusted/validator_x86/nc_segment.h" | |
33 #include "native_client/src/trusted/validator_x86/nc_inst_state_internal.h" | |
34 #else | |
35 #error "Unknown Platform" | |
36 #endif | |
29 | 37 |
30 /* x86 HALT opcode */ | 38 /* x86 HALT opcode */ |
31 static const uint8_t kNaClFullStop = 0xf4; | 39 static const uint8_t kNaClFullStop = 0xf4; |
32 | 40 |
33 /* | 41 /* |
34 * Max size of aligned writes we may issue to code without syncing. | 42 * Max size of aligned writes we may issue to code without syncing. |
35 * 8 is a safe value according to: | 43 * 8 is a safe value according to: |
36 * [1] Advance Micro Devices Inc. AMD64 Architecture Program- | 44 * [1] Advance Micro Devices Inc. AMD64 Architecture Program- |
37 * mers Manual Volume 1: Application Programming, 2009. | 45 * mers Manual Volume 1: Application Programming, 2009. |
38 * [2] Intel Inc. Intel 64 and IA-32 Architectures Software Developers | 46 * [2] Intel Inc. Intel 64 and IA-32 Architectures Software Developers |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 prot = (prot == prot_a ? prot_b : prot_a); | 159 prot = (prot == prot_a ? prot_b : prot_a); |
152 rv = mprotect(g_squashybuffer, size, prot); | 160 rv = mprotect(g_squashybuffer, size, prot); |
153 CHECK(rv == 0); | 161 CHECK(rv == 0); |
154 #endif | 162 #endif |
155 } | 163 } |
156 | 164 |
157 /* | 165 /* |
158 * Copy a single instruction, avoiding the possibility of other threads | 166 * Copy a single instruction, avoiding the possibility of other threads |
159 * executing a partially changed instruction. | 167 * executing a partially changed instruction. |
160 */ | 168 */ |
161 void CopyInstruction(const struct NCDecoderState *mstate_old, | 169 void CopyInstructionInternal(uint8_t *dst, |
162 const struct NCDecoderState *mstate_new) { | 170 uint8_t *src, |
163 uint8_t* dst = mstate_old->inst.maddr; | 171 uint8_t sz) { |
164 uint8_t* src = mstate_new->inst.maddr; | |
165 int sz = mstate_old->inst.length; | |
166 intptr_t offset = 0; | 172 intptr_t offset = 0; |
167 CHECK(mstate_new->inst.length == mstate_old->inst.length); | 173 uint8_t *firstbyte_p = dst; |
168 | 174 |
169 while (sz > 0 && dst[0] == src[0]) { | 175 while (sz > 0 && dst[0] == src[0]) { |
170 /* scroll to first changed byte */ | 176 /* scroll to first changed byte */ |
171 dst++, src++, sz--; | 177 dst++, src++, sz--; |
172 } | 178 } |
173 | 179 |
174 if (sz == 0) { | 180 if (sz == 0) { |
175 /* instructions are identical, we are done */ | 181 /* instructions are identical, we are done */ |
176 return; | 182 return; |
177 } | 183 } |
178 | 184 |
179 while (sz > 0 && dst[sz-1] == src[sz-1]) { | 185 while (sz > 0 && dst[sz-1] == src[sz-1]) { |
180 /* trim identical bytes at end */ | 186 /* trim identical bytes at end */ |
181 sz--; | 187 sz--; |
182 } | 188 } |
183 | 189 |
184 if (sz == 1) { | 190 if (sz == 1) { |
185 /* we assume a 1-byte change it atomic */ | 191 /* we assume a 1-byte change is atomic */ |
186 *dst = *src; | 192 *dst = *src; |
187 } else if (IsTrustedWrite(dst, sz, 4, &offset)) { | 193 } else if (IsTrustedWrite(dst, sz, 4, &offset)) { |
188 uint8_t tmp[4]; | 194 uint8_t tmp[4]; |
189 memcpy(tmp, dst-offset, sizeof tmp); | 195 memcpy(tmp, dst-offset, sizeof tmp); |
190 memcpy(tmp+offset, src, sz); | 196 memcpy(tmp+offset, src, sz); |
191 onestore_memmove4(dst-offset, tmp); | 197 onestore_memmove4(dst-offset, tmp); |
192 } else if (IsTrustedWrite(dst, sz, 8, &offset)) { | 198 } else if (IsTrustedWrite(dst, sz, 8, &offset)) { |
193 uint8_t tmp[8]; | 199 uint8_t tmp[8]; |
194 memcpy(tmp, dst-offset, sizeof tmp); | 200 memcpy(tmp, dst-offset, sizeof tmp); |
195 memcpy(tmp+offset, src, sz); | 201 memcpy(tmp+offset, src, sz); |
196 onestore_memmove8(dst-offset, tmp); | 202 onestore_memmove8(dst-offset, tmp); |
197 } else { | 203 } else { |
198 /* the slow path, first flip first byte to halt*/ | 204 /* the slow path, first flip first byte to halt*/ |
199 uint8_t firstbyte = mstate_old->inst.maddr[0]; | 205 uint8_t firstbyte = firstbyte_p[0]; |
200 mstate_old->inst.maddr[0] = kNaClFullStop; | 206 firstbyte_p[0] = kNaClFullStop; |
201 | 207 |
202 SerializeAllProcessors(); | 208 SerializeAllProcessors(); |
203 | 209 |
204 /* copy the rest of instruction */ | 210 /* copy the rest of instruction */ |
205 if (dst == mstate_old->inst.maddr) { | 211 if (dst == firstbyte_p) { |
206 /* but not the first byte! */ | 212 /* but not the first byte! */ |
207 firstbyte = *src; | 213 firstbyte = *src; |
208 dst++, src++, sz--; | 214 dst++, src++, sz--; |
209 } | 215 } |
210 memcpy(dst, src, sz); | 216 memcpy(dst, src, sz); |
211 | 217 |
212 SerializeAllProcessors(); | 218 SerializeAllProcessors(); |
213 | 219 |
214 /* flip first byte back */ | 220 /* flip first byte back */ |
215 mstate_old->inst.maddr[0] = firstbyte; | 221 firstbyte_p[0] = firstbyte; |
216 } | 222 } |
217 } | 223 } |
218 | 224 |
225 #if NACL_TARGET_SUBARCH == 32 | |
226 | |
227 /* | |
228 * Copy a single instruction, avoiding the possibility of other threads | |
229 * executing a partially changed instruction. | |
230 */ | |
231 void CopyInstruction(const struct NCDecoderState *mstate_old, | |
232 const struct NCDecoderState *mstate_new) { | |
233 CHECK(mstate_new->inst.length == mstate_old->inst.length); | |
234 | |
235 CopyInstructionInternal(mstate_old->inst.maddr, | |
236 mstate_new->inst.maddr, | |
237 mstate_old->inst.length); | |
238 } | |
239 | |
219 int NCCopyCode(uint8_t *dst, uint8_t *src, NaClPcAddress vbase, | 240 int NCCopyCode(uint8_t *dst, uint8_t *src, NaClPcAddress vbase, |
220 size_t sz, int bundle_size) { | 241 size_t sz, int bundle_size) { |
221 struct NCValidatorState *vstate; | 242 struct NCValidatorState *vstate; |
222 vstate = NCValidateInit(vbase, vbase+sz, bundle_size); | 243 vstate = NCValidateInit(vbase, vbase+sz, bundle_size); |
223 CHECK(NULL != vstate); | 244 CHECK(NULL != vstate); |
224 NCDecodeSegmentPair(dst, src, vbase, sz, vstate, CopyInstruction); | 245 NCDecodeSegmentPair(dst, src, vbase, sz, vstate, CopyInstruction); |
225 NCValidateFreeState(&vstate); | 246 NCValidateFreeState(&vstate); |
226 return 0; | 247 return 0; |
227 } | 248 } |
228 | 249 |
250 #elif NACL_TARGET_SUBARCH == 64 | |
251 | |
252 int NaClCopyCodeIter(uint8_t *dst, uint8_t *src, | |
253 NaClPcAddress vbase, size_t size) { | |
254 NaClSegment segment_old, segment_new; | |
255 NaClInstIter *iter_old, *iter_new; | |
256 NaClInstState *istate_old, *istate_new; | |
257 | |
258 NaClSegmentInitialize(dst, vbase, size, &segment_old); | |
259 NaClSegmentInitialize(src, vbase, size, &segment_new); | |
260 | |
261 iter_old = NaClInstIterCreate(&segment_old); | |
262 iter_new = NaClInstIterCreate(&segment_new); | |
263 while (NaClInstIterHasNext(iter_old) && | |
264 NaClInstIterHasNext(iter_new)) { | |
265 istate_old = NaClInstIterGetState(iter_old); | |
bsy
2010/12/15 04:06:50
does this get pseudo-atomic sequences as a single
elijahtaylor (use chromium)
2010/12/15 21:26:37
Comment added to clarify what we're doing.
On 201
| |
266 istate_new = NaClInstIterGetState(iter_new); | |
267 if (istate_old->length != istate_new->length || | |
268 istate_new->vpc != istate_old->vpc) { | |
269 NaClLog(LOG_ERROR, | |
270 "Segment replacement: copied instructions misaligned\n"); | |
bsy
2010/12/15 04:06:50
is this precondition violation that should never h
elijahtaylor (use chromium)
2010/12/15 21:26:37
Changed to LOG_FATAL and commented as this should
| |
271 return 1; | |
272 } | |
273 CopyInstructionInternal(istate_old->mpc, | |
bsy
2010/12/15 04:06:50
add a comment here that replacing all affected ins
elijahtaylor (use chromium)
2010/12/15 21:26:37
Done.
On 2010/12/15 04:06:50, bsy wrote:
| |
274 istate_new->mpc, | |
275 istate_old->length); | |
276 NaClInstIterAdvance(iter_old); | |
277 NaClInstIterAdvance(iter_new); | |
278 } | |
279 | |
280 CHECK(!NaClInstIterHasNext(iter_old) && !NaClInstIterHasNext(iter_new)); | |
281 | |
282 NaClInstIterDestroy(iter_old); | |
283 NaClInstIterDestroy(iter_new); | |
284 return 0; | |
285 } | |
286 | |
287 #else | |
288 #error "Unknown Platform" | |
289 #endif | |
290 | |
OLD | NEW |