|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
26: *
27: * File: machdep/i386/fault_copy.c
28: * Author: Bruce Martin, NeXT Computer, Inc.
29: *
30: * This file contains machine dependent code for kernel user copy
31: * on NeXT i386-based products. Currently tuned for the i486.
32: *
33: * HISTORY
34: * Oct-1-92 Bruce Martin ([email protected])
35: * Created.
36: */
37:
38: #import <mach/mach_types.h>
39: #import <sys/errno.h>
40:
41: #define MIN_TO_ALIGN 16
42: #define UNROLL 4
43:
44: /*
45: * Bytes to be moved by an unrolled loop
46: */
47: #define LOOP_STRIDE(type) (UNROLL * sizeof(type))
48:
49: /*
50: * Len modulo LOOP_STRIDE
51: */
52: #define MODULO_LOOP_UNROLL(len, type) \
53: ((len) & (LOOP_STRIDE(type) - 1) & ~(sizeof(type) - 1))
54:
55: /*
56: * Convert a void * into a unsigned int so arithmetic can be done
57: * (Technically, the gnu C compiler is tolerant of arithmetic
58: * on void *, but ansi isn't; so we do this.)
59: */
60: #define UNS(voidp) ((unsigned int)(voidp))
61:
62: /*
63: * Number of bytes addr is past an integer alignment
64: */
65: #define BYTES_PAST_INT_ALIGNMENT(voidp) (UNS(voidp) & (sizeof(int) - 1))
66:
67:
68: /*
69: * Convert a 'void * + offset' into a char, short, or int reference
70: * based at that address.
71: */
72: #define CHAR(voidp, offset) (*(char *)(UNS(voidp) + (offset)))
73: #define SHORT(voidp, offset) (*(short *)(UNS(voidp) + (offset)))
74: #define INT(voidp, offset) (*(int *)(UNS(voidp) + (offset)))
75:
76: #if defined(NX_CURRENT_COMPILER_RELEASE) && (NX_CURRENT_COMPILER_RELEASE < 320)
77: #define SIREG "e"
78: #else
79: #define SIREG "S"
80: #endif
81:
82:
83:
84: /*
85: * Maintain the recover field in the thread_t structure
86: */
87: static inline void
88: set_recover(int (*vector)())
89: {
90: current_thread()->recover = (vm_offset_t)vector;
91: return;
92: }
93:
94: static inline void
95: clear_recover()
96: {
97: current_thread()->recover = 0;
98: }
99:
100:
101:
102: /*
103: * Inline assembler macros used to build the copy routines
104: *
105: * The first set of routines move a single character or word.
106: */
107: static inline void
108: _char_move_out(char *dst, char val)
109: {
110: asm volatile (
111: "movb %0, %%fs:%1"
112: : /* no outputs */
113: : "q" (val), "m" (*dst));
114: }
115:
116: static inline void
117: _short_move_out(short *dst, short val)
118: {
119: asm volatile (
120: "movw %0, %%fs:%1"
121: : /* no outputs */
122: : "q" (val), "m" (*dst));
123: }
124:
125: static inline void
126: _word_move_out(int *dst, int val)
127: {
128: asm volatile (
129: "movl %0, %%fs:%1"
130: : /* no outputs */
131: : "r" (val), "m" (*dst));
132: }
133:
134: static inline char
135: _char_move_in(char *src)
136: {
137: char val;
138: asm volatile (
139: "movb %%fs:(%1), %0"
140: : "=q" (val)
141: : "r" (src));
142: return val;
143: }
144:
145: static inline int
146: _word_move_in(int *src)
147: {
148: int val;
149: asm volatile (
150: "movl %%fs:(%1), %0"
151: : "=r" (val)
152: : "r" (src));
153: return val;
154: }
155:
156:
157:
158: /*
159: * This set of routines move multiple words or characters
160: */
161: static inline void
162: _fwd_char_copy(void *dst, const void *src, int len)
163: {
164: asm("rep; movsb"
165: : /* no outputs */
166: : "&c" (len), "D" (dst), SIREG (src)
167: : "ecx", "esi", "edi");
168: }
169:
170: static inline void
171: _fwd_char_copy_in(void *dst, const void *src, int len)
172: {
173: asm("rep; movsb %%fs:(%%esi), (%%edi)"
174: : /* no outputs */
175: : "&c" (len), "D" (dst), SIREG (src)
176: : "ecx", "esi", "edi");
177: }
178:
179: /* NOTE: we can't use rep;movsb because of segment override restrictions */
180: static inline void
181: _fwd_char_copy_out(void *dst, const void *src, int len)
182: {
183: if (len & 0x1) {
184: _char_move_out(dst, CHAR(src, 0));
185: UNS(dst) += sizeof(char);
186: UNS(src) += sizeof(char);
187: }
188: if (len & 0x2) {
189: _short_move_out(dst, SHORT(src, 0));
190: UNS(dst) += sizeof(short);
191: UNS(src) += sizeof(short);
192: }
193: len >>= 2;
194: while (len--) {
195: _word_move_out(dst, INT(src, 0));
196: UNS(dst) += sizeof(int);
197: UNS(src) += sizeof(int);
198: }
199: }
200:
201:
202: static inline void
203: _bkwd_char_copy(void *dst, const void *src, int len)
204: {
205: /* NOTE: assumes DF flag is set */
206: UNS(src)--;
207: UNS(dst)--;
208: asm("rep; movsb"
209: : /* no outputs */
210: : "&c" (len), "D" (dst), SIREG (src)
211: : "ecx", "esi", "edi");
212: }
213:
214:
215: static inline void
216: _fwd_int_copy(void *dst, const void *src, int len)
217: {
218: asm("rep; movsl"
219: : /* no outputs */
220: : "&c" (len>>2), "D" (dst), SIREG (src)
221: : "ecx", "esi", "edi");
222: }
223:
224: static inline void
225: _fwd_int_copy_in(void *dst, const void *src, int len)
226: {
227: asm("rep; movsl %%fs:(%%esi), (%%edi)"
228: : /* no outputs */
229: : "&c" (len>>2), "D" (dst), SIREG (src)
230: : "ecx", "esi", "edi");
231: }
232:
233: /* NOTE: can't use rep;movsl because of segment override restrictions. */
234: static inline void
235: _fwd_int_copy_out(void *dst, const void *src, int len)
236: {
237: int alignment;
238: alignment = MODULO_LOOP_UNROLL(len, int);
239: UNS(src) += alignment - LOOP_STRIDE(int);
240: UNS(dst) += alignment - LOOP_STRIDE(int);
241: switch (alignment) {
242: do {
243: UNS(src) += LOOP_STRIDE(int);
244: UNS(dst) += LOOP_STRIDE(int);
245: _word_move_out(&((int *)dst)[0], INT(src, 0));
246: case 12: _word_move_out(&((int *)dst)[1], INT(src, 4));
247: case 8: _word_move_out(&((int *)dst)[2], INT(src, 8));
248: case 4: _word_move_out(&((int *)dst)[3], INT(src, 12));
249: case 0:
250: /*
251: INT(dst, 0) = INT(src, 0);
252: case 12: INT(dst, 4) = INT(src, 4);
253: case 8: INT(dst, 8) = INT(src, 8);
254: case 4: INT(dst, 12) = INT(src, 12);
255: case 0:
256: */
257: len -= LOOP_STRIDE(int);
258: } while (len >= 0);
259: }
260: }
261:
262: static inline void
263: _bkwd_int_copy(void *dst, const void *src, int len)
264: {
265: /* NOTE: assumes DF flag is set */
266: UNS(dst) -= sizeof(int);
267: UNS(src) -= sizeof(int);
268: asm("rep; movsl"
269: : /* no outputs */
270: : "&c" (len>>2), "D" (dst), SIREG (src)
271: : "ecx", "esi", "edi");
272: }
273:
274:
275:
276:
277:
278:
279: /*
280: * Copy count bytes from %fs:(src) to (dst)
281: */
282: inline
283: int copyin(char *src, char *dst, vm_size_t count)
284: {
285: int len = count;
286: int need_to_move;
287:
288: set_recover(&&do_fault);
289:
290: /* Always do a forward copy */
291:
292: if (len < MIN_TO_ALIGN) {
293: _fwd_char_copy_in(dst, src, len);
294: return 0;
295: }
296:
297: if (need_to_move = BYTES_PAST_INT_ALIGNMENT(src)) {
298: need_to_move = sizeof(int) - need_to_move;
299: _fwd_char_copy_in(dst, src, need_to_move);
300: len -= need_to_move;
301: UNS(dst) += need_to_move;
302: UNS(src) += need_to_move;
303: }
304:
305: _fwd_int_copy_in(dst, src, len);
306:
307: if (need_to_move = (len & 3)) {
308: UNS(src) += (len & ~3);
309: UNS(dst) += (len & ~3);
310: switch(need_to_move) {
311: case 3: dst[2] = _char_move_in(&src[2]);
312: case 2: dst[1] = _char_move_in(&src[1]);
313: case 1: dst[0] = _char_move_in(&src[0]);
314: }
315: }
316: clear_recover();
317: return 0;
318:
319: do_fault:
320: clear_recover();
321: return EFAULT;
322: }
323:
324: int copyinmsg(char *src, char *dst, vm_size_t count)
325: {
326: return copyin(src, dst, count);
327: }
328:
329: /*
330: * Copy count bytes from (src) to (dst)
331: */
332: int copywithin(char *src, char *dst, vm_size_t count)
333: {
334: int len = count;
335: int need_to_move;
336:
337: set_recover(&&do_fault);
338:
339: /* Always do a forward copy */
340:
341: if (len < MIN_TO_ALIGN) {
342: _fwd_char_copy(dst, src, len);
343: return 0;
344: }
345:
346: if (need_to_move = BYTES_PAST_INT_ALIGNMENT(src)) {
347: need_to_move = sizeof(int) - need_to_move;
348: _fwd_char_copy(dst, src, need_to_move);
349: len -= need_to_move;
350: UNS(dst) += need_to_move;
351: UNS(src) += need_to_move;
352: }
353:
354: _fwd_int_copy(dst, src, len);
355:
356: if (need_to_move = (len & 3)) {
357: UNS(src) += (len & ~3);
358: UNS(dst) += (len & ~3);
359: switch(need_to_move) {
360: case 3: dst[2] = src[2];
361: case 2: dst[1] = src[1];
362: case 1: dst[0] = src[0];
363: }
364: }
365: clear_recover();
366: return 0;
367:
368: do_fault:
369: clear_recover();
370: return EFAULT;
371: }
372:
373:
374: /*
375: * Copy count bytes from (src) to %fs:(dst)
376: */
377: inline
378: int copyout(char *src, char *dst, vm_size_t count)
379: {
380: int len = count;
381: int need_to_move;
382:
383: set_recover(&&do_fault);
384:
385: /* Always do a forward copy */
386:
387: if (len < MIN_TO_ALIGN) {
388: _fwd_char_copy_out(dst, src, len);
389: return 0;
390: }
391:
392: if (need_to_move = BYTES_PAST_INT_ALIGNMENT(src)) {
393: need_to_move = sizeof(int) - need_to_move;
394: _fwd_char_copy_out(dst, src, need_to_move);
395: len -= need_to_move;
396: UNS(dst) += need_to_move;
397: UNS(src) += need_to_move;
398: }
399:
400: _fwd_int_copy_out(dst, src, len);
401:
402: if (need_to_move = (len & 3)) {
403: UNS(src) += (len & ~3);
404: UNS(dst) += (len & ~3);
405: switch(need_to_move) {
406: case 3: _char_move_out(&dst[2], src[2]);
407: case 2: _char_move_out(&dst[1], src[1]);
408: case 1: _char_move_out(&dst[0], src[0]);
409: }
410: }
411: clear_recover();
412: return 0;
413:
414: do_fault:
415: clear_recover();
416: return EFAULT;
417: }
418:
419: int copyoutmsg(char *src, char *dst, vm_size_t count)
420: {
421: return copyout(src, dst, count);
422: }
423:
424:
425: /*
426: * copy up to max bytes from src to dst. Return number of bytes copied in len.
427: */
428: int copystr(const char *src, char *dst, int max, int *len)
429: {
430: int i = max;
431:
432: set_recover(&&do_fault);
433: while (i-- > 0) {
434: if (!(*dst++ = *src++))
435: break;
436: }
437:
438: if (len)
439: *len = max - i;
440: clear_recover();
441: return 0;
442:
443: do_fault:
444: clear_recover();
445: return EFAULT;
446: }
447:
448:
449: /*
450: * Same as copystr, but moves bytes from %fs:src to dst
451: */
452: int copyinstr(char *src, char *dst, int max, int *len)
453: {
454: int i = max;
455:
456: set_recover(&&do_fault);
457: while (i-- > 0) {
458: char c;
459: c = dst[0] = _char_move_in(src);
460: dst++;
461: src++;
462: if (!c)
463: break;
464: }
465:
466: if (len)
467: *len = max - i;
468: clear_recover();
469: return 0;
470:
471: do_fault:
472: clear_recover();
473: return EFAULT;
474: }
475:
476:
477: /*
478: * Same as copystr, but moves bytes from src to %fs:dst
479: */
480: int copyoutstr(char *src, char *dst, int max, int *len)
481: {
482: int i = max;
483:
484: set_recover(&&do_fault);
485: while (i-- > 0) {
486: char c;
487: c = *src;
488: _char_move_out(dst, c);
489: dst++;
490: src++;
491: if (!c)
492: break;
493: }
494:
495: if (len)
496: *len = max - i;
497: clear_recover();
498: return 0;
499:
500: do_fault:
501: clear_recover();
502: return EFAULT;
503: }
504:
505:
506:
507:
508: int fuword(int *addr)
509: {
510: int val;
511: set_recover(&&do_fault);
512: val = _word_move_in(addr);
513: clear_recover();
514: return val;
515:
516: do_fault:
517: clear_recover();
518: return -1;
519: }
520:
521:
522: char fubyte(char *addr)
523: {
524: int val;
525:
526: set_recover(&&do_fault);
527: val = _char_move_in(addr);
528: clear_recover();
529: return val;
530:
531: do_fault:
532: clear_recover();
533: return -1;
534: }
535:
536:
537: char fuibyte(char *addr)
538: {
539: int val;
540:
541: set_recover(&&do_fault);
542: val = _char_move_in(addr);
543: clear_recover();
544: return val;
545:
546: do_fault:
547: clear_recover();
548: return -1;
549: }
550:
551:
552:
553: int suword(int *addr, int val)
554: {
555: set_recover(&&do_fault);
556: _word_move_out(addr, val);
557: clear_recover();
558: return 0;
559:
560: do_fault:
561: clear_recover();
562: return -1;
563: }
564:
565:
566: int subyte(char *addr, char val)
567: {
568: set_recover(&&do_fault);
569: _char_move_out(addr, val);
570: clear_recover();
571: return 0;
572:
573: do_fault:
574: clear_recover();
575: return -1;
576: }
577:
578:
579: int
580: suibyte(char *addr, char val)
581: {
582: set_recover(&&do_fault);
583: _char_move_out(addr, val);
584: clear_recover();
585: return 0;
586:
587: do_fault:
588: clear_recover();
589: return -1;
590: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.