|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25:
26: #include <debug.h>
27: #include <ppc/asm.h>
28: #include <ppc/proc_reg.h>
29: #include <mach/ppc/vm_param.h>
30: #include <assym.s>
31: #include <sys/errno.h>
32:
33: /*
34: * void pmap_zero_page(vm_offset_t pa)
35: *
36: * zero a page of physical memory.
37: */
38:
39: #if DEBUG
40: /* C debug stub in pmap.c calls this */
41: ENTRY(pmap_zero_page_assembler, TAG_NO_FRAME_USED)
42: #else
43: ENTRY(pmap_zero_page, TAG_NO_FRAME_USED)
44: #endif /* DEBUG */
45:
46: mfmsr r6 /* Get the MSR */
47: rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1 /* Turn off DR */
48: rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Disable interruptions
49: li r4,PPC_PGBYTES-CACHE_LINE_SIZE /* Point to the end of the page */
50: mtmsr r7 /* Set MSR to DR off */
51: isync /* Ensure data translations are off */
52:
53:
54: .L_phys_zero_loop:
55: subic. r5,r4,CACHE_LINE_SIZE /* Point to the next one */
56: dcbz r4, r3 /* Clear the whole thing to 0s */
57: subi r4,r5,CACHE_LINE_SIZE /* Point to the next one */
58: dcbz r5, r3 /* Clear the next to zeros */
59: bgt+ .L_phys_zero_loop /* Keep going until we do the page... */
60:
61: sync /* Make sure they're all done */
62: li r4,PPC_PGBYTES-CACHE_LINE_SIZE /* Point to the end of the page */
63:
64: .L_inst_inval_loop:
65: subic. r5,r4,CACHE_LINE_SIZE /* Point to the next one */
66: icbi r4, r3 /* Clear the whole thing to 0s */
67: subi r4,r5,CACHE_LINE_SIZE /* Point to the next one */
68: icbi r5, r3 /* Clear the next to zeros */
69: bgt+ .L_inst_inval_loop /* Keep going until we do the page... */
70:
71: sync /* Make sure they're all done */
72:
73: mtmsr r6 /* Restore original translations */
74: isync /* Ensure data translations are on */
75:
76: blr
77:
78: /* void
79: * phys_copy(src, dst, bytecount)
80: * vm_offset_t src;
81: * vm_offset_t dst;
82: * int bytecount
83: *
84: * This routine will copy bytecount bytes from physical address src to physical
85: * address dst.
86: */
87:
88: ENTRY(phys_copy, TAG_NO_FRAME_USED)
89:
90: /* Switch off data translations */
91: mfmsr r6
92: rlwinm r7, r6, 0, MSR_DR_BIT+1, MSR_DR_BIT-1
93: rlwinm r7, r7, 0, MSR_EE_BIT+1, MSR_EE_BIT-1
94: mtmsr r7
95: isync /* Ensure data translations are off */
96:
97: subi r3, r3, 4
98: subi r4, r4, 4
99:
100: cmpwi r5, 3
101: ble- .L_phys_copy_bytes
102: .L_phys_copy_loop:
103: lwz r0, 4(r3)
104: addi r3, r3, 4
105: subi r5, r5, 4
106: stw r0, 4(r4)
107: addi r4, r4, 4
108: cmpwi r5, 3
109: bgt+ .L_phys_copy_loop
110:
111: /* If no leftover bytes, we're done now */
112: cmpwi r5, 0
113: beq+ .L_phys_copy_done
114:
115: .L_phys_copy_bytes:
116: addi r3, r3, 3
117: addi r4, r4, 3
118: .L_phys_copy_byte_loop:
119: lbz r0, 1(r3)
120: addi r3, r3, 1
121: subi r5, r5, 1
122: stb r0, 1(r4)
123: addi r4, r4, 1
124: cmpwi r5, 0
125: bne+ .L_phys_copy_byte_loop
126:
127: .L_phys_copy_done:
128: mtmsr r6 /* Restore original translations */
129: isync /* Ensure data translations are off */
130:
131: blr
132:
133: /* void
134: * pmap_copy_page(src, dst)
135: * vm_offset_t src;
136: * vm_offset_t dst;
137: *
138: * This routine will copy the physical page src to physical page dst
139: *
140: * This routine assumes that the src and dst are page aligned and that the
141: * destination is cached.
142: *
143: * We also must assume that noone will be executing within the destination
144: * page. We also assume that this will be used for paging
145: *
146: */
147:
148: #if DEBUG
149: /* if debug, we have a little piece of C around this
150: * in pmap.c that gives some trace ability
151: */
152: ENTRY(pmap_copy_page_assembler, TAG_NO_FRAME_USED)
153: #else
154: ENTRY(pmap_copy_page, TAG_NO_FRAME_USED)
155: #endif /* DEBUG */
156:
157: #if 0
158: mfpvr r9 ; Get the PVR
159: rlwinm r9,r9,16,16,31 ; Isolate the PPC processor
160: cmplwi r9,PROCESSOR_VERSION_Max ; Do we have Altivec?
161: beq+ wegotaltivec ; Yeah...
162: #endif
163:
164: mfmsr r9 ; Get the MSR
165: stwu r1,-(FM_SIZE+32)(r1) ; Make a frame for us
166: rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Disable interruptions
167: ori r7,r7,lo16(MASK(MSR_FP)) ; Turn on the FPU
168: mtmsr r7 ; Disable rupts and enable FPU
169: isync
170:
171: stfd f0,FM_SIZE+0(r1) ; Save an FP register
172: rlwinm r7,r7,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear the DDAT bit
173: stfd f1,FM_SIZE+8(r1) ; Save an FP register
174: addi r6,r3,PPC_PGBYTES ; Point to the start of the next page
175: stfd f2,FM_SIZE+16(r1) ; Save an FP register
176: mr r8,r4 ; Save the destination
177: stfd f3,FM_SIZE+24(r1) ; Save an FP register
178:
179: mtmsr r7 ; Set the new MSR
180: isync ; Ensure data translations are off
181:
182: dcbt br0, r3 /* Start in first input line */
183: li r5, CACHE_LINE_SIZE /* Get the line size */
184:
185: .L_pmap_copy_page_loop:
186: dcbz 0, r4 /* Allocate a line for the output */
187: lfd f0, 0(r3) /* Get first 8 */
188: lfd f1, 8(r3) /* Get second 8 */
189: lfd f2, 16(r3) /* Get third 8 */
190: stfd f0, 0(r4) /* Put first 8 */
191: dcbt r5, r3 /* Start next line coming in */
192: lfd f3, 24(r3) /* Get fourth 8 */
193: stfd f1, 8(r4) /* Put second 8 */
194: addi r3,r3,CACHE_LINE_SIZE /* Point to the next line in */
195: stfd f2, 16(r4) /* Put third 8 */
196: cmplw cr0,r3,r6 /* See if we're finished yet */
197: stfd f3, 24(r4) /* Put fourth 8 */
198: dcbst br0,r4 /* Force it out */
199: addi r4,r4,CACHE_LINE_SIZE /* Point to the next line out */
200: blt+ .L_pmap_copy_page_loop /* Copy the whole page */
201:
202: sync /* Make sure they're all done */
203: li r4,PPC_PGBYTES-CACHE_LINE_SIZE /* Point to the end of the page */
204:
205: invalinst:
206: subic. r5,r4,CACHE_LINE_SIZE /* Point to the next one */
207: icbi r4, r8 /* Trash the i-cache */
208: subi r4,r5,CACHE_LINE_SIZE /* Point to the next one */
209: icbi r5, r8 /* Trash the i-cache */
210: bgt+ invalinst /* Keep going until we do the page... */
211:
212: rlwimi r7,r9,0,MSR_DR_BIT,MSR_DR_BIT ; Set DDAT if on
213: sync ; Make sure all invalidates done
214:
215: mtmsr r7 ; Set DDAT correctly
216: isync
217:
218: lfd f0,FM_SIZE+0(r1) ; Restore an FP register
219: lfd f1,FM_SIZE+8(r1) ; Restore an FP register
220: lfd f2,FM_SIZE+16(r1) ; Restore an FP register
221: lfd f3,FM_SIZE+24(r1) ; Restore an FP register
222:
223: lwz r1,0(r1) ; Pop up the stack
224:
225: mtmsr r9 ; Turn off FPU now and maybe rupts back on
226: isync
227: blr
228:
229: #if 1
230: ;
231: ; This is not very optimal. We just do it here for a test of
232: ; Altivec in the kernel.
233: ;
234: wegotaltivec:
235: mfmsr r9 ; Get the MSR
236: lis r8,hi16(0xC0000000) ; Make sure we keep the first 2 vector registers
237: rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Disable interruptions
238: lis r6,lo16(2*256+128) ; Specify 128 blocks of 2 vectors each
239: rlwinm r7,r7,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear the DDAT bit
240: ori r6,r6,32 ; Set a 32-byte stride
241: mtsprg 256,r8 ; Set VRSave
242: mtmsr r7 ; Disable rupts and turn xlate off
243: isync
244:
245: dstt r3,r6,3 ; Stream in the page
246: addi r11,r3,4096 ; Point to the next page
247: li r10,16 ; Get vector size
248:
249: avmovepg: lvxl v0,br0,r3 ; Get first half of line
250: dcba br0,r4 ; Allocate output
251: lvxl v1,r10,r3 ; Get second half of line
252: stvxl v0,br0,r4 ; Save first half of line
253: addi r3,r3,32 ; Point to the next line
254: icbi br0,r4 ; Make the icache go away also
255: stvxl v1,r10,r4 ; Save second half of line
256: cmplw r3,r11 ; Have we reached the next page?
257: dcbst br0,r4 ; Make sure the line is on its way out
258: addi r4,r4,32 ; Point to the next line
259: blt+ avmovepg ; Move the next line...
260:
261: li r8,0 ; Clear this
262: sync ; Make sure all the memory stuff is done
263: mtsprg 256,r8 ; Show we are not using VRs any more
264: mtmsr r9 ; Translation and interruptions back on
265: isync
266: blr
267: #endif
268:
269:
270:
271:
272: /*
273: * int
274: * copyin(src, dst, count)
275: * vm_offset_t src;
276: * vm_offset_t dst;
277: * int count;
278: *
279: */
280:
281: ENTRY2(copyin, copyinmsg, TAG_NO_FRAME_USED)
282:
283: /* Preamble allowing us to call a sub-function */
284: mflr r0
285: stw r0,FM_LR_SAVE(r1)
286: stwu r1,-(FM_SIZE+16)(r1)
287:
288: mfmsr r0 /* Get the MSR */
289: rlwinm r6,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */
290: mtmsr r6 /* Disable 'rupts */
291:
292: mfsprg r6,0 /* Get the per_proc */
293: lwz r6,PP_CPU_DATA(r6)
294: cmpli cr0,r5,0
295: lwz r10,CPU_ACTIVE_THREAD(r6)
296: mtmsr r0 /* Set 'rupts back */
297: ble- cr0,.L_copyinout_trivial
298:
299: /* we know we have a valid copyin to do now */
300: /* Set up thread_recover in case we hit an illegal address */
301:
302: lwz r8,THREAD_TOP_ACT(r10)
303: lis r11,hi16(.L_copyinout_error)
304: lis r7,SEG_REG_PROT>>16 /* Top byte of SR value */
305: lwz r8,ACT_VMMAP(r8)
306: ori r11,r11,lo16(.L_copyinout_error)
307: add r9,r3,r5 /* Get the end of the source */
308: lwz r8,VMMAP_PMAP(r8)
309: subi r9,r9,1 /* Make sure we don't go too far */
310: rlwimi r7,r3,24,8,11 /* Insert seg number */
311: stw r11,THREAD_RECOVER(r10)
312: xor r9,r9,r3 /* Smoosh 'em together */
313: lwz r8,PMAP_SPACE(r8)
314: rlwinm r3,r3,0,4,31
315: rlwimi r7,r8,0,12,31 /* Insert space */
316: oris r3,r3,(SR_COPYIN_NUM << (28-16)) /* Set the copyin segment as the source */
317: rlwinm. r9,r9,0,1,3 /* Top nybble equal? */
318: mtsr SR_COPYIN,r7
319: isync
320:
321: #if 0
322: lis r0,HIGH_ADDR(EXT(dbgRegsCall)) /* (TEST/DEBUG) */
323: ori r0,r0,LOW_ADDR(EXT(dbgRegsCall)) /* (TEST/DEBUG) */
324: sc /* (TEST/DEBUG) */
325: #endif
326:
327: /* For optimisation, we check if the copyin lies on a segment
328: * boundary. If it doesn't, we can use a simple copy. If it
329: * does, we split it into two separate copies in some C code.
330: */
331:
332: bne- .L_call_copyin_multiple /* Nope, we went past the segment boundary... */
333:
334: bl EXT(bcopy)
335:
336: /* Now that copyin is done, we don't need a recovery point */
337: mfmsr r7 /* Get the MSR */
338: rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */
339: mtmsr r6 /* Disable 'rupts */
340:
341: mfsprg r6,0 /* Get the per_proc */
342:
343: lwz r6,PP_CPU_DATA(r6)
344: addi r1,r1,FM_SIZE+16
345: lwz r10,CPU_ACTIVE_THREAD(r6)
346: mtmsr r7 ; Restore interrupts
347: li r3,0
348: lwz r0,FM_LR_SAVE(r1)
349: stw r3,THREAD_RECOVER(r10) /* Clear recovery */
350: mtlr r0
351: blr
352:
353: /* we get here via the exception handler if an illegal
354: * user memory reference was made.
355: */
356: .L_copyinout_error:
357:
358: /* Now that copyin is done, we don't need a recovery point */
359:
360: mfmsr r7 /* Get the MSR */
361: rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */
362: mtmsr r6 /* Disable 'rupts */
363:
364: mfsprg r6,0 /* Get the per_proc */
365:
366: lwz r6,PP_CPU_DATA(r6)
367: addi r1,r1,FM_SIZE+16
368: lwz r10,CPU_ACTIVE_THREAD(r6)
369: mtmsr r7 ; Restore interrupts
370: li r4,0
371: lwz r0,FM_LR_SAVE(r1)
372: stw r4,THREAD_RECOVER(r10) /* Clear recovery */
373: mtlr r0
374: li r3,EFAULT ; Indicate error (EFAULT)
375: blr
376:
377: .L_copyinout_trivial:
378: /* The copyin/out was for either 0 bytes or a negative
379: * number of bytes, return an appropriate value (0 == SUCCESS).
380: * cr0 still contains result of comparison of len with 0.
381: */
382: li r3, 0
383: beq+ cr0, .L_copyinout_negative
384: li r3, 1
385: .L_copyinout_negative:
386:
387: /* unwind the stack */
388: addi r1, r1, FM_SIZE+16
389: lwz r0, FM_LR_SAVE(r1)
390: mtlr r0
391:
392: blr
393:
394: .L_call_copyin_multiple:
395:
396: /* unwind the stack */
397: addi r1, r1, FM_SIZE+16
398: lwz r0, FM_LR_SAVE(r1)
399: mtlr r0
400:
401: b EXT(copyin_multiple) /* not a call - a jump! */
402:
403: /*
404: * int
405: * copyout(src, dst, count)
406: * vm_offset_t src;
407: * vm_offset_t dst;
408: * int count;
409: *
410: */
411:
412: ENTRY2(copyout, copyoutmsg, TAG_NO_FRAME_USED)
413:
414: /* Preamble allowing us to call a sub-function */
415:
416: mflr r0
417: stw r0,FM_LR_SAVE(r1)
418: stwu r1,-(FM_SIZE+16)(r1)
419:
420: #if 0
421: stw r3,FM_SIZE+0(r1) /* (TEST/DEBUG) */
422: stw r4,FM_SIZE+4(r1) /* (TEST/DEBUG) */
423: stw r5,FM_SIZE+8(r1) /* (TEST/DEBUG) */
424: mr r6,r0 /* (TEST/DEBUG) */
425:
426: bl EXT(tracecopyout) /* (TEST/DEBUG) */
427:
428: lwz r3,FM_SIZE+0(r1) /* (TEST/DEBUG) */
429: lwz r4,FM_SIZE+4(r1) /* (TEST/DEBUG) */
430: lwz r5,FM_SIZE+8(r1) /* (TEST/DEBUG) */
431: #endif
432:
433: mfmsr r7 /* Get the MSR */
434: rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */
435: mtmsr r6 /* Disable 'rupts */
436:
437: mfsprg r6,0 /* Get the per_proc */
438:
439: lwz r6,PP_CPU_DATA(r6)
440: cmpli cr0,r5,0
441: lwz r10,CPU_ACTIVE_THREAD(r6)
442: mtmsr r7 /* Restore 'rupts */
443: ble- cr0,.L_copyinout_trivial
444: /* we know we have a valid copyout to do now */
445: /* Set up thread_recover in case we hit an illegal address */
446:
447:
448: lwz r8,THREAD_TOP_ACT(r10)
449: lis r11,HIGH_ADDR(.L_copyinout_error)
450: lis r7,SEG_REG_PROT>>16 /* Top byte of SR value */
451: lwz r8,ACT_VMMAP(r8)
452: ori r11,r11,LOW_ADDR(.L_copyinout_error)
453: add r9,r4,r5 /* Get the end of the destination */
454: lwz r8,VMMAP_PMAP(r8)
455: rlwimi r7,r4,24,8,11 /* Insert seg number */
456: subi r9,r9,1 /* Make sure we don't go too far */
457: stw r11,THREAD_RECOVER(r10)
458: xor r9,r9,r4 /* Smoosh 'em together */
459: lwz r8,PMAP_SPACE(r8)
460: rlwinm r4,r4,0,4,31
461: rlwimi r7,r8,0,12,31 /* Insert space */
462: oris r4,r4,(SR_COPYIN_NUM << (28-16)) /* Set the copyin segment as the source */
463: rlwinm. r9,r9,0,1,3 /* Top nybble equal? */
464: mtsr SR_COPYIN,r7
465: isync
466:
467:
468: /* For optimisation, we check if the copyout lies on a segment
469: * boundary. If it doesn't, we can use a simple copy. If it
470: * does, we split it into two separate copies in some C code.
471: */
472:
473: bne- .L_call_copyout_multiple /* Nope, we went past the segment boundary... */
474:
475: bl EXT(bcopy)
476:
477: /* Now that copyout is done, we don't need a recovery point */
478: mfmsr r7 /* Get the MSR */
479: rlwinm r6,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */
480: mtmsr r6 /* Disable 'rupts */
481:
482: mfsprg r6,0 /* Get the per_proc */
483:
484: lwz r6,PP_CPU_DATA(r6)
485: addi r1,r1,FM_SIZE+16
486: lwz r10,CPU_ACTIVE_THREAD(r6)
487: mtmsr r7 ; Restore interrupts
488: li r3,0
489: lwz r0,FM_LR_SAVE(r1)
490: stw r3,THREAD_RECOVER(r10) /* Clear recovery */
491: mtlr r0
492: blr
493:
494: .L_call_copyout_multiple:
495: /* unwind the stack */
496: addi r1, r1, FM_SIZE+16
497: lwz r0, FM_LR_SAVE(r1)
498: mtlr r0
499:
500: b EXT(copyout_multiple) /* not a call - a jump! */
501:
502: /*
503: * boolean_t
504: * copyinstr(src, dst, count, maxcount)
505: * vm_offset_t src;
506: * vm_offset_t dst;
507: * vm_size_t maxcount;
508: * vm_size_t* count;
509: *
510: * Set *count to the number of bytes copied
511: *
512: * If dst == NULL, don't copy, just count bytes.
513: * Only currently called from klcopyinstr.
514: */
515:
516: ENTRY(copyinstr, TAG_NO_FRAME_USED)
517:
518: /* Preamble allowing us to call a sub-function */
519: mflr r0
520: stw r0,FM_LR_SAVE(r1)
521: stwu r1,-(FM_SIZE+16)(r1)
522:
523: #if 0
524: stw r3,FM_SIZE+0(r1) /* (TEST/DEBUG) */
525: stw r4,FM_SIZE+4(r1) /* (TEST/DEBUG) */
526: stw r5,FM_SIZE+8(r1) /* (TEST/DEBUG) */
527: stw r6,FM_SIZE+12(r1) /* (TEST/DEBUG) */
528: mr r7,r0 /* (TEST/DEBUG) */
529:
530: bl EXT(tracecopystr) /* (TEST/DEBUG) */
531:
532: lwz r3,FM_SIZE+0(r1) /* (TEST/DEBUG) */
533: lwz r4,FM_SIZE+4(r1) /* (TEST/DEBUG) */
534: lwz r5,FM_SIZE+8(r1) /* (TEST/DEBUG) */
535: stw r6,FM_SIZE+12(r1) /* (TEST/DEBUG) */
536: #endif
537:
538: mfmsr r0 /* Get the MSR */
539: rlwinm r7,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear 'rupts */
540: mtmsr r7 /* Disable 'rupts */
541:
542: mfsprg r7,0 /* Get the per_proc */
543: lwz r7,PP_CPU_DATA(r7)
544: cmpli cr0,r5,0
545: lwz r10,CPU_ACTIVE_THREAD(r7)
546: mtmsr r0 /* Restore 'rupts */
547: ble- cr0,.L_copyinout_trivial
548:
549: /* we know we have a valid copyin to do now */
550: /* Set up thread_recover in case we hit an illegal address */
551:
552: li r0,0
553: lwz r8,THREAD_TOP_ACT(r10)
554: stw r0,0(r6) /* Clear result length */
555: lis r11,HIGH_ADDR(.L_copyinout_error)
556: lis r7,SEG_REG_PROT>>16 /* Top byte of SR value */
557: lwz r8,ACT_VMMAP(r8)
558: ori r11,r11,LOW_ADDR(.L_copyinout_error)
559: lwz r8,VMMAP_PMAP(r8)
560: rlwimi r7,r3,24,8,11 /* Insert seg number */
561: stw r11,THREAD_RECOVER(r10)
562: lwz r8,PMAP_SPACE(r8)
563: rlwinm r3,r3,0,4,31
564: rlwimi r7,r8,0,12,31 /* Insert space */
565: oris r3,r3,(SR_COPYIN_NUM << (28-16)) /* Set the copyin segment as the source */
566:
567: /* Copy byte by byte for now - TODO NMGS speed this up with
568: * some clever (but fairly standard) logic for word copies.
569: * We don't use a copyinstr_multiple since copyinstr is called
570: * with INT_MAX in the linux server. Eugh.
571: */
572:
573: li r9,0 /* Clear byte counter */
574:
575: /* If the destination is NULL, don't do writes,
576: * just count bytes. We set CR7 outside the loop to save time
577: */
578: cmpwi cr7,r4,0 /* Is the destination null? */
579:
580: nxtseg: mtsr SR_COPYIN,r7 /* Set the source SR */
581: isync
582:
583: .L_copyinstr_loop:
584: lbz r0,0(r3) /* Get the source */
585: addic. r5,r5,-1 /* Have we gone far enough? */
586: addi r3,r3,1 /* Bump source pointer */
587:
588: cmpwi cr1,r0,0 /* Did we hit a null? */
589:
590: beq cr7,.L_copyinstr_no_store /* If we are just counting, skip the store... */
591:
592: stb r0,0(r4) /* Move to sink */
593: addi r4,r4,1 /* Advance sink pointer */
594:
595: .L_copyinstr_no_store:
596:
597: addi r9,r9,1 /* Count the character */
598: beq- cr1,.L_copyinstr_done /* We're done if we did a null... */
599: beq- cr0,L_copyinstr_toobig /* Also if we maxed the count... */
600:
601: /* Check to see if the copyin pointer has moved out of the
602: * copyin segment, if it has we must remap.
603: */
604:
605: rlwinm. r0,r3,0,4,31 /* Did we wrap around to 0? */
606: bne+ cr0,.L_copyinstr_loop /* Nope... */
607:
608: oris r3,r0,(SR_COPYIN_NUM << (28-16)) /* Reset the segment number */
609: addis r7,r7,0x0010 /* Yeah, we did, so bump the segment */
610: b nxtseg /* Keep going... */
611:
612: L_copyinstr_toobig:
613: li r3,ENAMETOOLONG
614: b L_copyinstr_return
615: .L_copyinstr_done:
616: li r3,0 /* Normal return */
617: L_copyinstr_return:
618: li r4,0 /* to clear thread_recover */
619: stw r9,0(r6) /* Set how many bytes we did */
620: stw r4,THREAD_RECOVER(r10) /* Clear recovery exit */
621:
622: addi r1, r1, FM_SIZE+16
623: lwz r0, FM_LR_SAVE(r1)
624: mtlr r0
625: blr
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.