xref: /netbsd-src/sys/arch/ia64/ia64/support.S (revision ca08b3e761e6fc5454aa5d028935f5d82d92ea3d)
1/*	$NetBSD: support.S,v 1.10 2020/06/30 16:20:01 maxv Exp $	*/
2
3/*-
4 * Copyright (c) 1998 Doug Rabson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31/*-
32 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
33 * All rights reserved.
34 *
35 * Author: Chris G. Demetriou
36 *
37 * Permission to use, copy, modify and distribute this software and
38 * its documentation is hereby granted, provided that both the copyright
39 * notice and this permission notice appear in all copies of the
40 * software, derivative works or modified versions, and any portions
41 * thereof, and that both notices appear in supporting documentation.
42 *
43 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
44 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
45 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 *
47 * Carnegie Mellon requests users of this software to return to
48 *
49 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
50 *  School of Computer Science
51 *  Carnegie Mellon University
52 *  Pittsburgh PA 15213-3890
53 *
54 * any improvements or extensions that they make and grant Carnegie the
55 * rights to redistribute these changes.
56 */
57
58#include <machine/asm.h>
59
60#include "assym.h"
61
62.text
63
64/*
65 * ia64_change_mode:	change mode to/from physical mode
66 *
67 * Arguments:
68 *	r14	psr for desired mode
69 *
70 * Modifies:
71 *	r15-r19	scratch
72 *	ar.bsp	tranlated to new mode
73 */
74ENTRY_NOPROFILE(ia64_change_mode, 0)
75	rsm	psr.i | psr.ic
76	mov	r19=ar.rsc		// save rsc while we change mode
77	tbit.nz	p6,p7=r14,17		// physical or virtual ?
78	;;
79	mov	ar.rsc=0		// turn off RSE
80(p6)	mov	r15=7			// RR base for virtual addresses
81(p7)	mov	r15=0			// RR base for physical addresses
82	flushrs				// no dirty registers please
83	srlz.i
84	;;
85	mov	r16=ar.bsp
86	mov	r17=rp
87	mov	r18=ar.rnat
88	;;
89	dep	r16=r15,r16,61,3	// new address of ar.bsp
90	dep	r17=r15,r17,61,3	// new address of rp
91	dep	sp=r15,sp,61,3		// new address of sp
92	;;
93	mov	ar.bspstore=r16
94	mov	rp=r17
95	;;
961:	mov	r16=ip
97	mov	ar.rnat=r18
98	mov	cr.ipsr=r14		// psr for new mode
99	;;
100	add	r16=2f-1b,r16		// address to rfi to
101	;;
102	dep	r16=r15,r16,61,3	// new mode address for rfi
103	;;
104	mov	cr.iip=r16		// setup for rfi
105	mov	cr.ifs=r0
106	;;
107	rfi
108
1092:	mov	ar.rsc=r19		// restore ar.rsc
110	br.ret.sptk.few rp		// now in new mode
111END(ia64_change_mode)
112
113/*
114 * ia64_physical_mode:	change mode to physical mode
115 *
116 * Return:
117 *	ret0	psr to restore
118 *
119 * Modifies:
120 *	r15-r18	scratch
121 *	ar.bsp	tranlated to physical mode
122 *	psr.i	cleared
123 */
124ENTRY(ia64_physical_mode, 0)
125	mov	r14=psr
126	mov	ret0=psr
127	movl	r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH)
128	movl	r16=IA64_PSR_BN
129	;;
130	andcm	r14=r14,r15		// clear various xT bits
131	;;
132	or	r14=r14,r16		// make sure BN=1
133	or	ret0=ret0,r16		// make sure BN=1
134
135	br.cond.sptk.many ia64_change_mode
136END(ia64_physical_mode)
137
138/*
139 * ia64_call_efi_physical:	call an EFI procedure in physical mode
140 *
141 * Arguments:
142 *	in0		Address of EFI procedure descriptor
143 *	in1-in5		Arguments to EFI procedure
144 *
145 * Return:
146 *	ret0-ret3	return values from EFI
147 *
148 */
149ENTRY(ia64_call_efi_physical, 6)
150	.prologue
151	.regstk	6,4,5,0
152	.save	ar.pfs,loc0
153	alloc	loc0=ar.pfs,6,4,5,0
154	;;
155	.save	rp,loc1
156	mov	loc1=rp
157	;;
158	.body
159	br.call.sptk.many rp=ia64_physical_mode
160	;;
161	mov	loc2=r8			// psr to restore mode
162	mov	loc3=gp			// save kernel gp
163	ld8	r14=[in0],8		// function address
164	;;
165	mov	out0=in1
166	mov	out1=in2
167	mov	out2=in3
168	mov	out3=in4
169	mov	out4=in5
170	ld8	gp=[in0]		// function gp value
171	;;
172	mov	b6=r14
173	;;
174	br.call.sptk.many rp=b6		// call EFI procedure
175	mov	gp=loc3			// restore kernel gp
176	;;
177	mov	r14=loc2		// psr to restore mode
178	br.call.sptk.many rp=ia64_change_mode
179	;;
180	mov	rp=loc1
181	mov	ar.pfs=loc0
182	;;
183	br.ret.sptk.many rp
184END(ia64_call_efi_physical)
185
186/**************************************************************************/
187
188ENTRY(fusufault, 0)
189{	.mib
190	st8.rel		[r15]=r0		// Clear onfault.
191	add		ret0=-1,r0
192	br.ret.sptk	rp
193	;;
194}
195END(fusufault)
196
197/*
198 * casuptr(intptr_t *p, intptr_t old, intptr_t new)
199 *	Perform a compare-exchange in user space.
200 */
201ENTRY(casuptr, 3)
202{	.mlx
203	add		r15=PC_CURLWP,r13
204	movl		r14=VM_MAX_ADDRESS
205	;;
206}
207{	.mib
208	ld8		r15=[r15]		// r15 = curthread
209	cmp.geu		p6,p0=in0,r14
210(p6)	br.dpnt.few	1f
211	;;
212}
213{	.mlx
214	add		r15=L_PCB,r15
215	movl		r14=fusufault
216	;;
217}
218{	.mmi
219	ld8		r15=[r15]		// r15 = PCB
220	;;
221	mov		ar.ccv=in1
222	add		r15=PCB_ONFAULT,r15
223	;;
224}
225{	.mmi
226	st8		[r15]=r14		// Set onfault
227	;;
228	cmpxchg8.rel	ret0=[in0],in2,ar.ccv
229	nop		0
230	;;
231}
232{	.mfb
233	st8.rel		[r15]=r0		// Clear onfault
234	nop		0
235	br.ret.sptk	rp
236	;;
237}
2381:
239{	.mfb
240	add		ret0=-1,r0
241	nop		0
242	br.ret.sptk	rp
243	;;
244}
245END(casuptr)
246
247/**************************************************************************/
248
249ENTRY(ufetchstore_fault, 0)
250{	.mfb
251	st8.rel		[r15]=r0	/* curpcb->pcb_onfault = NULL */
252	nop		0		/* ret0 already has error */
253	br.ret.sptk	rp
254	;;
255}
256END(ufetchstore_fault)
257
258#define	UFETCH(load_insn, store_insn)					  \
259{	.mlx								 ;\
260	add		r15=PC_CURLWP,r13				 ;\
261	movl		r14=VM_MAX_ADDRESS				;;\
262}									 ;\
263{	.mib								 ;\
264	ld8		r15=[r15]	/* r15 = curlwp */		 ;\
265	cmp.geu		p6,p0=in0,r14					 ;\
266(p6)	br.dpnt.few	1f						;;\
267}									 ;\
268{	.mlx								 ;\
269	add		r15=L_PCB,r15					 ;\
270	movl		r14=ufetchstore_fault				;;\
271}									 ;\
272{	.mmi								 ;\
273	ld8		r15=[r15]	/*r15 = curlwp->l_pcb */	;;\
274	nop		0						 ;\
275	add		r15=PCB_ONFAULT,r15				;;\
276}									 ;\
277{	.mmi								 ;\
278	st8		[r15]=r14	/* curpcb->pcb_onfault = */	;;\
279					/*     ufetchstore_fault */	  \
280	mf								 ;\
281	nop		0						;;\
282}									 ;\
283{	.mmi								 ;\
284	load_insn	r14=[in0]	/* r14 = *uaddr */		;;\
285	st8.rel		[r15]=r0	/* curpcb->pcb_onfault = NULL */ ;\
286	nop		0						;;\
287}									 ;\
288{	.mib								 ;\
289	store_insn	[in1]=r14	/* *valp = r14 */		 ;\
290	mov		ret0=r0		/* ret0 = 0 (success!) */	 ;\
291	br.ret.sptk	rp						;;\
292}									 ;\
2931:									  \
294{	.mfb								 ;\
295	mov		ret0=EFAULT	/* return EFAULT */		 ;\
296	nop		0						 ;\
297	br.ret.sptk	rp						;;\
298}
299
300/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */
301ENTRY(_ufetch_8, 2)
302	UFETCH(ld1, st1)
303END(_ufetch_8)
304
305/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */
306ENTRY(_ufetch_16, 2)
307	UFETCH(ld2, st2)
308END(_ufetch_16)
309
310/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */
311ENTRY(_ufetch_32, 2)
312	UFETCH(ld4, st4)
313END(_ufetch_32)
314
315/* LINTSTUB: int _ufetch_64(const uint64_t *uaddr, uint64_t *valp); */
316ENTRY(_ufetch_64, 2)
317	UFETCH(ld8, st8)
318END(_ufetch_64)
319
320#define	USTORE(store_insn)						  \
321{	.mlx								 ;\
322	add		r15=PC_CURLWP,r13				 ;\
323	movl		r14=VM_MAX_ADDRESS				;;\
324}									 ;\
325{	.mib								 ;\
326	ld8		r15=[r15]	/* r15 = curlwp */		 ;\
327	cmp.geu		p6,p0=in0,r14					 ;\
328(p6)	br.dpnt.few	1f						;;\
329}									 ;\
330{	.mlx								 ;\
331	add		r15=L_PCB,r15					 ;\
332	movl		r14=ufetchstore_fault				;;\
333}									 ;\
334{	.mmi								 ;\
335	ld8		r15=[r15]	/*r15 = curlwp->l_pcb */	;;\
336	nop		0						 ;\
337	add		r15=PCB_ONFAULT,r15				;;\
338}									 ;\
339{	.mmi								 ;\
340	st8		[r15]=r14	/* curpcb->pcb_onfault = */	;;\
341					/*     ufetchstore_fault */	  \
342	store_insn	[in0]=in1	/* *uaddr = val */		 ;\
343	nop		0						;;\
344}									 ;\
345{	.mib								 ;\
346	st8.rel		[r15]=r0	/* curpcb->pcb_onfault = NULL */ ;\
347	mov		ret0=r0		/* ret0 = 0 (success!) */	 ;\
348	br.ret.sptk	rp						;;\
349}									 ;\
3501:									  \
351{	.mfb								 ;\
352	mov		ret0=EFAULT	/* return EFAULT */		 ;\
353	nop		0						 ;\
354	br.ret.sptk	rp						;;\
355}
356
357/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */
358ENTRY(_ustore_8, 2)
359	USTORE(st1.rel)
360END(_ustore_8)
361
362/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */
363ENTRY(_ustore_16, 2)
364	USTORE(st2.rel)
365END(_ustore_16)
366
367/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */
368ENTRY(_ustore_32, 2)
369	USTORE(st4.rel)
370END(_ustore_32)
371
372/* LINTSTUB: int _ustore_64(uint64_t *uaddr, uint64_t val); */
373ENTRY(_ustore_64, 2)
374	USTORE(st8.rel)
375END(_ustore_64)
376
377/**************************************************************************/
378
379/*
380 * XXX XXX XXX: Should be removed?
381 */
382ENTRY(ia64_copystr, 4)
383	mov	r14=in2			// r14 = i = len
384	cmp.eq	p6,p0=r0,in2
385(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
386
3871:	ld1	r15=[in0],1		// read one byte
388	;;
389	st1	[in1]=r15,1		// write that byte
390	add	in2=-1,in2		// len--
391	;;
392	cmp.eq	p6,p0=r0,r15
393	cmp.ne	p7,p0=r0,in2
394	;;
395(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
396(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
397
3982:	cmp.eq	p6,p0=r0,in3
399(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
400	sub	r14=r14,in2		// *lenp = (i - len)
401	;;
402	st8	[in3]=r14
403
4043:	cmp.eq	p6,p0=r0,r15
405(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
406
407	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
408	br.ret.sptk.few rp
409
4104:	mov	ret0=0			// return 0.
411	br.ret.sptk.few rp
412END(ia64_copystr)
413
414ENTRY(copyinstr, 4)
415	.prologue
416	.regstk	4, 3, 4, 0
417	.save	ar.pfs,loc0
418	alloc	loc0=ar.pfs,4,3,4,0
419	.save	rp,loc1
420	mov	loc1=rp
421	.body
422
423	movl	loc2=VM_MAX_ADDRESS		// make sure that src addr
424	;;
425	cmp.geu	p6,p0=in0,loc2			// is in user space.
426	;;
427(p6)	br.cond.spnt.few copyefault		// if it's not, error out.
428	movl	r14=copyerr			// set up fault handler.
429	add	r15=PC_CURLWP,r13		// find curthread
430	;;
431	ld8	r15=[r15]
432	;;
433	add	r15=L_PCB,r15			// find pcb
434	;;
435	ld8	r15=[r15]
436	;;
437	add	loc2=PCB_ONFAULT,r15
438	;;
439	st8	[loc2]=r14
440	;;
441	mov	out0=in0
442	mov	out1=in1
443	mov	out2=in2
444	mov	out3=in3
445	;;
446	br.call.sptk.few rp=ia64_copystr	// do the copy.
447	st8	[loc2]=r0			// kill the fault handler.
448	mov	ar.pfs=loc0			// restore ar.pfs
449	mov	rp=loc1				// restore ra.
450	br.ret.sptk.few rp			// ret0 left over from copystr
451END(copyinstr)
452
453ENTRY(copyoutstr, 4)
454	.prologue
455	.regstk	4, 3, 4, 0
456	.save	ar.pfs,loc0
457	alloc	loc0=ar.pfs,4,3,4,0
458	.save	rp,loc1
459	mov	loc1=rp
460	.body
461
462	movl	loc2=VM_MAX_ADDRESS		// make sure that dest addr
463	;;
464	cmp.geu	p6,p0=in1,loc2			// is in user space.
465	;;
466(p6)	br.cond.spnt.few copyefault		// if it's not, error out.
467	movl	r14=copyerr			// set up fault handler.
468	add	r15=PC_CURLWP,r13		// find curthread
469	;;
470	ld8	r15=[r15]
471	;;
472	add	r15=L_PCB,r15			// find pcb
473	;;
474	ld8	r15=[r15]
475	;;
476	add	loc2=PCB_ONFAULT,r15
477	;;
478	st8	[loc2]=r14
479	;;
480	mov	out0=in0
481	mov	out1=in1
482	mov	out2=in2
483	mov	out3=in3
484	;;
485	br.call.sptk.few rp=ia64_copystr	// do the copy.
486	st8	[loc2]=r0			// kill the fault handler.
487	mov	ar.pfs=loc0			// restore ar.pfs
488	mov	rp=loc1				// restore ra.
489	br.ret.sptk.few rp			// ret0 left over from copystr
490END(copyoutstr)
491
492/*
493 * int kcopy(const void *from, void *to, size_t len);
494 * Copy len bytes, abort on fault.
495 */
496
497ENTRY(kcopy, 3)
498	.prologue
499	.regstk	3, 3, 3, 0
500	.save	ar.pfs,loc0
501	alloc	loc0=ar.pfs,3,3,3,0
502	.save	rp,loc1
503	mov	loc1=rp
504	.body
505
506	movl	r14=copyerr			// set up fault handler.
507	add	r15=PC_CURLWP,r13		// find curthread
508	;;
509	ld8	r15=[r15]
510	;;
511	add	r15=L_PCB,r15			// find pcb
512	;;
513	ld8	r15=[r15]
514	;;
515	add	loc2=PCB_ONFAULT,r15
516	;;
517	st8	[loc2]=r14
518	;;
519	mov	out0=in0
520	mov	out1=in1
521	mov	out2=in2
522	mov	ret0=r0				// XXX netbsd kcopy same as freebsd?
523	;;
524	br.call.sptk.few rp=bcopy		// do the copy.
525	st8	[loc2]=r0			// kill the fault handler.
526	mov	ar.pfs=loc0			// restore ar.pfs
527	mov	rp=loc1				// restore ra.
528	br.ret.sptk.few rp
529END(kcopy)
530
531ENTRY(copyin, 3)
532	.prologue
533	.regstk	3, 3, 3, 0
534	.save	ar.pfs,loc0
535	alloc	loc0=ar.pfs,3,3,3,0
536	.save	rp,loc1
537	mov	loc1=rp
538	.body
539
540	movl	loc2=VM_MAX_ADDRESS		// make sure that src addr
541	;;
542	cmp.geu	p6,p0=in0,loc2			// is in user space.
543	;;
544(p6)	br.cond.spnt.few copyefault		// if it's not, error out.
545	movl	r14=copyerr			// set up fault handler.
546	add	r15=PC_CURLWP,r13		// find curthread
547	;;
548	ld8	r15=[r15]
549	;;
550	add	r15=L_PCB,r15			// find pcb
551	;;
552	ld8	r15=[r15]
553	;;
554	add	loc2=PCB_ONFAULT,r15
555	;;
556	st8	[loc2]=r14
557	;;
558	mov	out0=in0
559	mov	out1=in1
560	mov	out2=in2
561	mov	ret0=r0				// return zero for copy{in,out}
562	;;
563	br.call.sptk.few rp=bcopy		// do the copy.
564	st8	[loc2]=r0			// kill the fault handler.
565	mov	ar.pfs=loc0			// restore ar.pfs
566	mov	rp=loc1				// restore ra.
567	br.ret.sptk.few rp
568END(copyin)
569
570ENTRY(copyout, 3)
571	.prologue
572	.regstk	3, 3, 3, 0
573	.save	ar.pfs,loc0
574	alloc	loc0=ar.pfs,3,3,3,0
575	.save	rp,loc1
576	mov	loc1=rp
577	.body
578
579	movl	loc2=VM_MAX_ADDRESS		// make sure that dest addr
580	;;
581	cmp.geu	p6,p0=in1,loc2			// is in user space.
582	;;
583(p6)	br.cond.spnt.few copyefault		// if it's not, error out.
584	movl	r14=copyerr			// set up fault handler.
585	add	r15=PC_CURLWP,r13		// find curthread
586	;;
587	ld8	r15=[r15]
588	;;
589	add	r15=L_PCB,r15			// find pcb
590	;;
591	ld8	r15=[r15]
592	;;
593	add	loc2=PCB_ONFAULT,r15
594	;;
595	st8	[loc2]=r14
596	;;
597	mov	out0=in0
598	mov	out1=in1
599	mov	out2=in2
600	mov	ret0=r0				// return zero for copy{in,out}
601	;;
602	br.call.sptk.few rp=bcopy		// do the copy.
603	st8	[loc2]=r0			// kill the fault handler.
604	mov	ar.pfs=loc0			// restore ar.pfs
605	mov	rp=loc1				// restore ra.
606	br.ret.sptk.few rp
607END(copyout)
608
609ENTRY(copyerr, 0)
610	add	r14=PC_CURLWP,r13 ;;		// find curthread
611	ld8	r14=[r14] ;;
612	add	r14=L_PCB,r14 ;;		// curthread->td_addr
613	ld8	r14=[r14] ;;
614	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
615	st8	[r14]=r0			// reset fault handler
616
617	br.ret.sptk.few rp
618END(copyerr)
619
620ENTRY(copyefault, 0)
621	add	r14=PC_CURLWP,r13 ;;		// find curthread
622	ld8	r14=[r14] ;;
623	add	r14=L_PCB,r14 ;;		// curthread->td_addr
624	ld8	r14=[r14] ;;
625	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
626	st8	[r14]=r0			// reset fault handler
627
628	mov	ret0=EFAULT			// return EFAULT
629	br.ret.sptk.few rp
630END(copyefault)
631
632#if defined(GPROF)
633/*
634 * Important registers:
635 *      r8      structure return address
636 *      rp      our return address
637 *      in0     caller's ar.pfs
638 *      in1     caller's gp
639 *      in2     caller's rp
640 *      in3     GOT entry
641 *      ar.pfs  our pfs
642 */
643ENTRY_NOPROFILE(_mcount, 4)
644	alloc		loc0 = ar.pfs, 4, 3, 2, 0
645	mov		loc1 = r8
646	mov		loc2 = rp
647	;;
648	mov		out0 = in2
649	mov		out1 = rp
650	br.call.sptk	rp = __mcount
651	;;
6521:
653	mov		gp = in1
654	mov		r14 = ip
655	mov		b7 = loc2
656	;;
657	add		r14 = 2f - 1b, r14
658	mov		ar.pfs = loc0
659	mov		rp = in2
660	;;
661	mov		b7 = r14
662	mov		b6 = loc2
663	mov		r8 = loc1
664	mov		r14 = in0
665	br.ret.sptk	b7
666	;;
6672:
668	mov		ar.pfs = r14
669	br.sptk		b6
670	;;
671END(_mcount)
672#endif
673