x86-assem.S 12 KB
Newer Older
1
/* ### x86-assem.S -*- Mode: Asm; -*- */
ram's avatar
ram committed
2
/**
3
 * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/x86-assem.S,v 1.35 2010/12/22 02:12:52 rtoy Exp $
ram's avatar
ram committed
4
 *
5
6
 * Authors:	Paul F. Werkowski <pw@snoopy.mv.com>
 *		Douglas T. Crosher
ram's avatar
ram committed
7
8
9
10
11
12
13
 *
 * This code was written to support the port of CMU Common Lisp
 * to the Intel X86 ISA and the FreeBSD operating system. The
 * author has placed this code in the public domain September 1996.
 *
 */

14

ram's avatar
ram committed
15
16
17
18
#include "x86-validate.h"
	
#define LANGUAGE_ASSEMBLY
#include "internals.h"
19
#include "lispregs.h"
ram's avatar
ram committed
20
21

/* Minimize conditionalization for different OS naming schemes */
22
23
24
25
26
27
28
29
30
#ifdef DARWIN	
#define GNAME(var) _##var
#define FUNCDEF(x) \
	.text			; \
	.align 2,0x90		; \
	.globl GNAME(x)		; \
GNAME(x):			;
#define ENDFUNC(x)
#elif defined(SOLARIS)
ram's avatar
ram committed
31
#define GNAME(var) var
cshapiro's avatar
cshapiro committed
32
33
#define FUNCDEF(x) \
	.text			; \
34
	.align 16,0x90		; \
cshapiro's avatar
cshapiro committed
35
36
37
38
39
	.globl GNAME(x)		; \
	.type x,@function	; \
GNAME(x):			;
#define ENDFUNC(x) \
	.size GNAME(x),.-GNAME(x)
ram's avatar
ram committed
40
#else
41
#define GNAME(var) var
cshapiro's avatar
cshapiro committed
42
43
#define FUNCDEF(x) \
	.text			; \
44
	.balign 4,0x90		; \
cshapiro's avatar
cshapiro committed
45
	.globl GNAME(x)		; \
46
	.type x,@function	; \
cshapiro's avatar
cshapiro committed
47
GNAME(x):			;
48
49
#define ENDFUNC(x) \
	.size GNAME(x),.-GNAME(x)
ram's avatar
ram committed
50
51
#endif

52
53
54
55
56
57
58
#ifdef SOLARIS
#define	INT3	int $3

#else
#define INT3	int3
#endif
								
59
/* Get the right type of alignment.  Linux wants alignment in bytes. */
60
#if defined (__linux__) || defined (__FreeBSD__)
cshapiro's avatar
cshapiro committed
61
#define align_16byte    16
ram's avatar
ram committed
62
63
64
65
#else
#define	align_16byte	4	
#endif			

Raymond Toy's avatar
Raymond Toy committed
66
67
68
69
70
71
72
73
/*
 * Allocate |bytes| on the stack, and make sure the stack pointer is
 * aligned on a 16-byte boundary.  (Needed on Darwin, and harmless on 
 * others that don't need such alignment.)
 */		
#define STACK_PROLOGUE(bytes) \
	pushl	%ebp		; \
	mov	%esp, %ebp	; \
74
	subl	$bytes, %esp	; \
Raymond Toy's avatar
Raymond Toy committed
75
76
77
78
79
80
81
	andl	$-16, %esp	; 

/* Undo STACK_PROLOGUE */
#define STACK_EPILOGUE \
	movl	%ebp, %esp	; \
	popl	%ebp		; 
	
ram's avatar
ram committed
82
	.text
83
	.globl	GNAME(foreign_function_call_active)
84
	
85

ram's avatar
ram committed
86
87
88
89
90
91
92
/*
 * The C function will preserve ebx, esi, edi, and ebp across its
 * function call - ebx is used to save the return lisp address.
 *
 * Return values are in eax and maybe edx for quads, or st(0) for
 * floats.
 *
dtc's avatar
dtc committed
93
 * It should work for lisp calls C calls lisp calls C ..
ram's avatar
ram committed
94
 */
95
FUNCDEF(call_into_c)
ram's avatar
ram committed
96
97
98
99
100
101
102
103
104
105
106
	movl	$1,GNAME(foreign_function_call_active)

/* Save the return lisp address in ebx */	
	popl	%ebx

	call	*%eax		# normal callout using Lisp stack

	movl	$0,GNAME(foreign_function_call_active)
/* Return */	
	jmp	*%ebx

107
ENDFUNC(call_into_c)
ram's avatar
ram committed
108

109

dtc's avatar
dtc committed
110

ram's avatar
ram committed
111
112
/* The C conventions require that ebx, esi, edi, and ebp be preserved
	across function calls. */
113
114
/* The *alien-stack* pointer is setup on the first call_into_lisp when
   the stack changes. */
115
FUNCDEF(call_into_lisp)
ram's avatar
ram committed
116
117
118
	pushl	%ebp		# save old frame pointer
	movl	%esp,%ebp	# establish new frame

119
/* Save the NPX state */
rtoy's avatar
rtoy committed
120
	movl	%esp, %eax	# Remember the current stack pointer
121
122
123
124
125
	/*
	 * The SSE state is 512 bytes, but we need 16 more because we
	 * need 16-byte alignment.
	 */
	subl	$512+16,%esp
rtoy's avatar
rtoy committed
126
127
128
	andl	$-16, %esp	# fxsave needs 16-byte alignment
	fxsave	(%esp)		
	pushl	%eax		# Save the old stack pointer
ram's avatar
ram committed
129
130
131
132
133
134
135
/* Save C regs: ebx esi edi */
	pushl	%ebx
	pushl	%esi
	pushl	%edi
	
/* clear descriptor regs */
	xorl	%eax,%eax	# lexenv
136
137
138
139
140
	xorl	%ebx,%ebx	# available
	xorl	%ecx,%ecx	# arg count
	xorl	%edx,%edx	# first arg
	xorl	%edi,%edi	# second arg
	xorl	%esi,%esi	# third arg
ram's avatar
ram committed
141
142
143
144
145

/* no longer in function call */
	movl	%eax, GNAME(foreign_function_call_active)

	movl	%esp,%ebx	# remember current stack
146
147
	cmpl	GNAME(control_stack), %esp

148
	jbe	ChangeToLispStack
Raymond Toy's avatar
Raymond Toy committed
149
	cmpl	GNAME(control_stack_end), %esp
150
151
152
153
	jbe	OnLispStack
ChangeToLispStack:
	/* Setup the *alien-stack* pointer */
	movl	%esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
Raymond Toy's avatar
Raymond Toy committed
154
	movl	GNAME(control_stack_end), %esp		# New stack
155
OnLispStack:
ram's avatar
ram committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
	pushl	%ebx		# save entry stack on (maybe) new stack

	/* establish lisp args */
	movl	 8(%ebp),%eax	# lexenv?
	movl	12(%ebp),%ebx	# address of arg vec
	movl	16(%ebp),%ecx	# num args
	shll	$2,%ecx		# make into fixnum
	cmpl	$0,%ecx
	je	Ldone
	movl	(%ebx),%edx	# arg0
	cmpl	$4,%ecx
	je	Ldone
	movl	4(%ebx),%edi	# arg1
	cmpl	$8,%ecx
	je	Ldone
	movl	8(%ebx),%esi	# arg2
Ldone:	
dtc's avatar
dtc committed
173
	/* Registers eax, ecx, edx,edi,esi now live */
ram's avatar
ram committed
174

dtc's avatar
dtc committed
175
	/* Allocate new frame */
ram's avatar
ram committed
176
177
	mov	%esp,%ebx	# current sp marks start of new frame
	push	%ebp		# fp in save location S0
178
	sub	$8,%esp		# Ensure 3 slots are allocated, one above.
ram's avatar
ram committed
179
180
	mov	%ebx,%ebp	# switch to new frame

dtc's avatar
dtc committed
181
	/* Indirect the closure */
182
	call	*CLOSURE_FUNCTION_OFFSET(%eax)
ram's avatar
ram committed
183
184
185
186
	
	/* Multi-value return - blow off any extra values */
	mov	%ebx, %esp
	/* Single value return */	
187
188

/* Restore the stack, in case there was a stack change. */
ram's avatar
ram committed
189
190
	popl	%esp		# c-sp

dtc's avatar
dtc committed
191
/* Restore C regs: ebx esi edi */
ram's avatar
ram committed
192
193
194
195
196
	popl	%edi
	popl	%esi
	popl	%ebx

/* Restore the NPX state */
rtoy's avatar
rtoy committed
197
198
199
200
	popl	%eax		# Get the old stack pointer
	fxrstor	(%esp)		# Restore the SSE state
	movl	%eax, %esp	# Now really restore the old stack pointer
			
ram's avatar
ram committed
201
202
203
	popl	%ebp		# c-sp
	movl	%edx,%eax	# c-val
	ret
204
ENDFUNC(call_into_lisp)
205

206
/* Support for saving and restoring the NPX state from C. */
207
FUNCDEF(fpu_save)
208
209
210
	movl	4(%esp),%eax
	fnsave	(%eax)		# Save the NPX state - Resets NPX
	ret
211
ENDFUNC(fpu_save)
212

213
FUNCDEF(fpu_restore)
214
215
216
	movl	4(%esp),%eax
	frstor	(%eax)		# Restore the NPX state.
	ret
217
ENDFUNC(fpu_restore)
rtoy's avatar
rtoy committed
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

FUNCDEF(sse_save)
	movl	4(%esp),%eax
	addl	$16, %eax	# Make sure eax is on a 16-byte boundary
	and	$-16, %eax
	fxsave	(%eax)
	ret
ENDFUNC(sse_save)
		
FUNCDEF(sse_restore)
	movl	4(%esp),%eax
	addl	$16, %eax	# Make sure eax is on a 16-byte boundary
	and	$-16, %eax
	fxrstor	(%eax)
	ret
ENDFUNC(sse_restore)
234

dtc's avatar
dtc committed
235

236
#if 0
237
/*
238
239
240
241
242
243
 * These are now implemented as Lisp assembly routines.  We leave
 * these here for the time being until we're sure the assembly
 * routines are working as expected.
 */

 /*
244
 * The undefined-function trampoline.
ram's avatar
ram committed
245
 */
246
FUNCDEF(undefined_tramp)
247
	INT3
248
	.byte	trap_Error
249
        /* Number of argument bytes */
ram's avatar
ram committed
250
        .byte   2
251
252
253
	.byte	UNDEFINED_SYMBOL_ERROR
        /* SC_OFFSET(sc_DescriptorReg,reg_EAX) */
        .byte   SC_OFFSET(sc_DescriptorReg,0)
ram's avatar
ram committed
254
	ret
255
ENDFUNC(undefined_tramp)
ram's avatar
ram committed
256

257
258
259
/*
 * The closure trampoline.
 */
260
FUNCDEF(closure_tramp)
ram's avatar
ram committed
261
	movl	FDEFN_FUNCTION_OFFSET(%eax),%eax
262
	jmp	*CLOSURE_FUNCTION_OFFSET(%eax)
263
ENDFUNC(closure_tramp)
ram's avatar
ram committed
264

265
266
#endif

267
268
269
/*
 * Function-end breakpoint magic.
 */
270
FUNCDEF(function_end_breakpoint_guts)
271
272
273
274
	/* Multiple Value return
	   This MUST be a two-byte instruction.  If it isn't tracing is 
	   majorly broken. */
	jmp	1f
275
276
277
278
279
280
281
282
	/* Single value return: The eventual return will now use the
	   multiple values return convention but with a return values
	   count of one. */
	movl	%esp,%ebx	# Setup ebx - the ofp.
	subl	$4,%esp		# Allocate one stack slot for the return value
	movl	$4,%ecx		# Setup ecx for one return value.
	movl	$NIL,%edi	# Default second value
	movl	$NIL,%esi	# Default third value
283
		
284
1:	
285
286
multiple_value_return:
	
287
	.globl GNAME(function_end_breakpoint_trap)
288
GNAME(function_end_breakpoint_trap):
289
	INT3
290
	.byte 	trap_FunctionEndBreakpoint
291
	hlt			# Should never return here.
ram's avatar
ram committed
292

293
	.globl GNAME(function_end_breakpoint_end)
294
GNAME(function_end_breakpoint_end):
ram's avatar
ram committed
295

296

297
FUNCDEF(do_pending_interrupt)
298
	INT3
ram's avatar
ram committed
299
300
	.byte 	trap_PendingInterrupt
	ret
301
ENDFUNC(do_pending_interrupt)
302
303
	
#ifdef trap_DynamicSpaceOverflowError
304
FUNCDEF(do_dynamic_space_overflow_error)
305
	INT3
306
307
	.byte 	trap_DynamicSpaceOverflowError
	ret
308
ENDFUNC(do_dynamic_space_overflow_error)
309
310
311
#endif				
	
#ifdef trap_DynamicSpaceOverflowWarning
312
FUNCDEF(do_dynamic_space_overflow_warning)
313
	INT3
314
315
	.byte 	trap_DynamicSpaceOverflowWarning
	ret
316
ENDFUNC(do_dynamic_space_overflow_warning)
317
318
#endif				
	
319

320
#ifdef WANT_CGC
ram's avatar
ram committed
321
322
323
324
325
326
/* A copy function optimized for the Pentium and works ok on
 * 486 as well. This assumes (does not check) that the input
 * byte count is a multiple of 8-bytes (one lisp object).
 * This code takes advantage of pairing in the Pentium as well
 * as the 128-bit cache line.
 */
327
FUNCDEF(fastcopy16)
ram's avatar
ram committed
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
	pushl	%ebp
	movl	%esp,%ebp
	movl	8(%ebp), %edx	# dst
	movl	12(%ebp),%eax	# src
	movl	16(%ebp),%ecx	# bytes
	pushl	%ebx
	pushl	%esi
	pushl	%edi
	movl	%edx,%edi
	movl	%eax,%esi
	sarl	$3,%ecx		# number 8-byte units
	testl	$1,%ecx		# odd?
	jz	Lquad
	movl	(%esi),%eax
	movl	4(%esi),%ebx
	movl	%eax,(%edi)
	movl	%ebx,4(%edi)
	leal	8(%esi),%esi
	leal	8(%edi),%edi
Lquad:	sarl	$1,%ecx		# count 16-byte units
	jz	Lend
	movl	%ecx,%ebp	# use ebp for loop counter
	.align	align_16byte,0x90
Ltop:
	movl	  (%edi),%eax	#prefetch! MAJOR Pentium win.
	movl	  (%esi),%eax
	movl	 4(%esi),%ebx
	movl	 8(%esi),%ecx
	movl	12(%esi),%edx
	movl	%eax,  (%edi)
	movl	%ebx, 4(%edi)
	movl	%ecx, 8(%edi)
	movl	%edx,12(%edi)
	leal	16(%esi),%esi
	leal	16(%edi),%edi
	decl	%ebp
	jnz	Ltop		# non-prefixed jump saves cycles
Lend:
	popl	%edi
	popl	%esi
	popl	%ebx
	popl	%ebp
	ret
371
ENDFUNC(fastcopy16)
372
#endif
373

374

375
/*
Raymond Toy's avatar
Raymond Toy committed
376
 * alloc_overflow_sse2 must not be called from
377
378
379
380
381
382
383
 * C because it doesn't follow C conventions.
 *
 * On entry:
 * %eax = bytes to allocate
 * On exit:
 * %eax = address
 */
384
FUNCDEF(alloc_overflow_sse2)
Raymond Toy's avatar
Raymond Toy committed
385
386
387
388
389
	# Need 8*16 bytes for the xmm registers, and space to save ecx
	# and edx, space for mxcsr, a temp, and one arg to pass to alloc.
	# That's 8*16 + 5*4 = 148 bytes.  Might as well have a few
	# more so the xmm0 area is 16-byte aligned. That makes it 160
	# bytes.
390
391
392
	#
	# Stack looks like:
	#
Raymond Toy's avatar
Raymond Toy committed
393
394
395
396
397
398
399
400
401
402
	#      +160
	#      +144 -> xmm7
	#      +128 -> xmm6
	#      +112 -> xmm5
	#      +96  -> xmm4
	#      +80  -> xmm3
	#      +64  -> xmm2
	#      +48  -> xmm1
	#      +32  -> xmm0
	#      +20  -> unused
403
404
405
406
407
	#      +16  -> temp
	#      +12  -> mxcsr
	#      + 8  -> save ecx
	#      + 4  -> save edx
	#  esp + 0  -> arg for alloc
Raymond Toy's avatar
Raymond Toy committed
408
409
410
411
412
413
414
415
416
417
	STACK_PROLOGUE(160)
	movapd  %xmm0, (32 + 0*16)(%esp)
	movapd  %xmm1, (32 + 1*16)(%esp)
	movapd  %xmm2, (32 + 2*16)(%esp)
	movapd  %xmm3, (32 + 3*16)(%esp)
	movapd  %xmm4, (32 + 4*16)(%esp)
	movapd  %xmm5, (32 + 5*16)(%esp)
	movapd  %xmm6, (32 + 6*16)(%esp)
	movapd  %xmm7, (32 + 7*16)(%esp)

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
	movl	%ecx, 8(%esp)	# Save ecx and edx registers
	movl	%edx, 4(%esp)
	stmxcsr 12(%esp)	# Save MXCSR
	/* Clear the exceptions that might have occurred */
	movl	12(%esp), %edx
	and	$-64, %edx	# Clear the exceptions
	movl	%edx, 16(%esp)
	ldmxcsr 16(%esp)	# Get new mxcsr value
	movl	%eax, (%esp)	# Put size on stack for first arg to alloc()

	call	GNAME(alloc)

	movl	4(%esp), %edx	# Restore edx and ecx registers.  eax has the return value.
	movl	8(%esp), %ecx
	ldmxcsr	12(%esp)
Raymond Toy's avatar
Raymond Toy committed
433
434
435
436
437
438
439
440
441
442

	movapd  (32 + 0*16)(%esp), %xmm0
	movapd  (32 + 1*16)(%esp), %xmm1
	movapd  (32 + 2*16)(%esp), %xmm2
	movapd  (32 + 3*16)(%esp), %xmm3
	movapd  (32 + 4*16)(%esp), %xmm4
	movapd  (32 + 5*16)(%esp), %xmm5
	movapd  (32 + 6*16)(%esp), %xmm6
	movapd  (32 + 7*16)(%esp), %xmm7

443
444
445
446
	STACK_EPILOGUE
	ret
ENDFUNC(alloc_overflow_sse2)	

447
448
#ifdef LINKAGE_TABLE

moore's avatar
   
moore committed
449
450
451
452
453
454
455
/* Call into C code to resolve a linkage entry.  The initial code in the 
 * linkage entry has done a call to here; pass that return entry along as a 
 * parameter.
 *
 * We could be called from raw Lisp code or from a foreign call site, so we 
 * have to save all the registers...
 */	
456
FUNCDEF(resolve_linkage_tramp)
moore's avatar
   
moore committed
457
458
	pushl	%ebp		# save old frame pointer
	movl	%esp,%ebp	# establish new frame
cshapiro's avatar
cshapiro committed
459
460
461
462
463
464
465
466
	subl	$28, %esp
	andl	$-16, %esp
	movl	%eax, 24(%esp)
	movl	%ecx, 20(%esp)
	movl	%edx, 16(%esp)
	movl	%ebx, 12(%esp)
	movl	%esi, 8(%esp)	
	movl	%edi, 4(%esp)
moore's avatar
   
moore committed
467
468
	/* calling location (plus offset) was on top of stack */
	movl	4(%ebp), %eax
cshapiro's avatar
cshapiro committed
469
	movl	%eax, (%esp)	# push for C function
moore's avatar
   
moore committed
470
471
472
473
474
475
	call	GNAME(lazy_resolve_linkage)
	/* real address of target is in %eax.  Replace return address on stack
	 * with it.  That way we can get out of here without trashing any 
	 *registers!
	 */
	movl	%eax,4(%ebp)
cshapiro's avatar
cshapiro committed
476
477
478
479
480
481
482
	movl	4(%esp), %edi
	movl	8(%esp), %esi
	movl	12(%esp), %ebx
	movl	16(%esp), %edx
	movl	20(%esp), %ecx
	movl	24(%esp), %eax
	leave
moore's avatar
   
moore committed
483
	ret			# jump to the real target
484
ENDFUNC(resolve_linkage_tramp)
moore's avatar
   
moore committed
485
486

/*
487
 * The C-callable undefined-foreign-symbol trapping function.
moore's avatar
   
moore committed
488
 */
489
FUNCDEF(undefined_foreign_symbol_trap)
moore's avatar
   
moore committed
490
491
492
493
494
495
	/* C Calling Convention, move one arg to EAX */
        pushl %ebp
        movl %esp,%ebp
        movl 8(%ebp),%eax

	/* Now trap to Lisp */
496
	INT3
moore's avatar
   
moore committed
497
	.byte	trap_Error
498
        /* Number of argument bytes */
moore's avatar
   
moore committed
499
        .byte   2
500
501
502
	.byte	UNDEFINED_FOREIGN_SYMBOL_ERROR
        /* SC_OFFSET(sc_DescriptorReg,reg_EAX) */
        .byte   SC_OFFSET(sc_DescriptorReg,0)
moore's avatar
   
moore committed
503
504
505
506
507

	/* C Calling Convention */
	/* Doesn't matter here, but could if we'd use trap_Cerror */
	leave
	ret
508
ENDFUNC(undefined_foreign_symbol_trap)
509
510

#endif /* LINKAGE_TABLE */