1 4;;; -*- Mode: LISP; Syntax: Common-Lisp; Base: 10; Package: x86 -*-
3 ;;; **********************************************************************
4 ;;; This code was written as part of the CMU Common Lisp project at
5 ;;; Carnegie Mellon University, and has been placed in the public domain.
6 ;;; If you want to use this code or any part of CMU Common Lisp, please contact
7 ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
10 "$Header: src/compiler/x86/system.lisp $")
12 ;;; **********************************************************************
14 ;;; x86 VM definitions of various system hacking operations.
16 ;;; Written by William Lott.
18 ;;; Debugged by Paul F. Werkowski Spring/Summer 1995.
19 ;;; Enhancements/debugging by Douglas T. Crosher 1996,1997,1998,1999.
23 (intl:textdomain "cmucl-x86-vm")
26 ;;;; Type frobbing VOPs
28 (define-vop (get-lowtag)
29 (:translate get-lowtag)
31 (:args (object :scs (any-reg descriptor-reg control-stack)
33 (:results (result :scs (unsigned-reg)))
34 (:result-types positive-fixnum)
37 (inst and result lowtag-mask)))
39 (define-vop (get-type)
42 (:args (object :scs (descriptor-reg)))
43 (:temporary (:sc unsigned-reg :offset eax-offset :to (:result 0)) eax)
44 (:results (result :scs (unsigned-reg)))
45 (:result-types positive-fixnum)
48 (inst and al-tn lowtag-mask)
49 (inst cmp al-tn other-pointer-type)
50 (inst jmp :e other-ptr)
51 (inst cmp al-tn function-pointer-type)
52 (inst jmp :e function-ptr)
54 ;; pick off structures and list pointers
62 ;; must be an other immediate
67 (load-type al-tn object (- vm:function-pointer-type))
71 (load-type al-tn object (- vm:other-pointer-type))
74 (inst movzx result al-tn)))
76 (define-vop (function-subtype)
77 (:translate function-subtype)
79 (:args (function :scs (descriptor-reg)))
80 (:temporary (:sc byte-reg :from (:eval 0) :to (:eval 1)) temp)
81 (:results (result :scs (unsigned-reg)))
82 (:result-types positive-fixnum)
84 (load-type temp function (- vm:function-pointer-type))
85 (inst movzx result temp)))
87 (define-vop (set-function-subtype)
88 (:translate (setf function-subtype))
90 (:args (type :scs (unsigned-reg) :target eax)
91 (function :scs (descriptor-reg)))
92 (:arg-types positive-fixnum *)
93 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
94 :to (:result 0) :target result)
96 (:results (result :scs (unsigned-reg)))
97 (:result-types positive-fixnum)
101 (make-ea :byte :base function :disp (- function-pointer-type))
105 (define-vop (get-header-data)
106 (:translate get-header-data)
108 (:args (x :scs (descriptor-reg)))
109 (:results (res :scs (unsigned-reg)))
110 (:result-types positive-fixnum)
112 (loadw res x 0 other-pointer-type)
113 (inst shr res type-bits)))
115 (define-vop (get-closure-length)
116 (:translate get-closure-length)
118 (:args (x :scs (descriptor-reg)))
119 (:results (res :scs (unsigned-reg)))
120 (:result-types positive-fixnum)
122 (loadw res x 0 function-pointer-type)
123 (inst shr res type-bits)))
125 (define-vop (set-header-data)
126 (:translate set-header-data)
128 (:args (x :scs (descriptor-reg) :target res :to (:result 0))
129 (data :scs (any-reg) :target eax))
130 (:arg-types * positive-fixnum)
131 (:results (res :scs (descriptor-reg)))
132 (:temporary (:sc unsigned-reg :offset eax-offset
133 :from (:argument 1) :to (:result 0)) eax)
136 (inst shl eax (- type-bits 2))
137 (inst mov al-tn (make-ea :byte :base x :disp (- other-pointer-type)))
138 (storew eax x 0 other-pointer-type)
141 (define-vop (make-fixnum)
142 (:args (ptr :scs (any-reg descriptor-reg) :target res))
143 (:results (res :scs (any-reg descriptor-reg)))
146 ;; Some code (the hash table code) depends on this returning a
147 ;; positive number so make sure it does.
152 (define-vop (make-other-immediate-type)
153 (:args (val :scs (any-reg descriptor-reg) :target res)
154 (type :scs (unsigned-reg immediate)))
155 (:results (res :scs (any-reg descriptor-reg) :from (:argument 0)))
158 (inst shl res (- type-bits 2))
159 (inst or res (sc-case type
161 (immediate (tn-value type))))))
166 (define-vop (dynamic-space-free-pointer)
167 (:results (int :scs (sap-reg)))
168 (:result-types system-area-pointer)
169 (:translate dynamic-space-free-pointer)
172 (load-symbol-value int *allocation-pointer*)))
174 (define-vop (binding-stack-pointer-sap)
175 (:results (int :scs (sap-reg)))
176 (:result-types system-area-pointer)
177 (:translate binding-stack-pointer-sap)
180 (load-symbol-value int *binding-stack-pointer*)))
182 (defknown (setf binding-stack-pointer-sap)
183 (system-area-pointer) system-area-pointer ())
185 (define-vop (set-binding-stack-pointer-sap)
186 (:args (new-value :scs (sap-reg) :target int))
187 (:arg-types system-area-pointer)
188 (:results (int :scs (sap-reg)))
189 (:result-types system-area-pointer)
190 (:translate (setf binding-stack-pointer-sap))
193 (store-symbol-value new-value *binding-stack-pointer*)
194 (move int new-value)))
196 (define-vop (control-stack-pointer-sap)
197 (:results (int :scs (sap-reg)))
198 (:result-types system-area-pointer)
199 (:translate control-stack-pointer-sap)
205 ;;;; Code object frobbing.
207 (define-vop (code-instructions)
208 (:translate code-instructions)
210 (:args (code :scs (descriptor-reg) :to (:result 0)))
211 (:results (sap :scs (sap-reg) :from (:argument 0)))
212 (:result-types system-area-pointer)
214 (loadw sap code 0 other-pointer-type)
215 (inst shr sap type-bits)
216 (inst lea sap (make-ea :byte :base code :index sap :scale 4
217 :disp (- other-pointer-type)))))
219 (define-vop (compute-function)
220 (:args (code :scs (descriptor-reg) :to (:result 0))
221 (offset :scs (signed-reg unsigned-reg) :to (:result 0)))
222 (:arg-types * positive-fixnum)
223 (:results (func :scs (descriptor-reg) :from (:argument 0)))
225 (loadw func code 0 other-pointer-type)
226 (inst shr func type-bits)
228 (make-ea :byte :base offset :index func :scale 4
229 :disp (- function-pointer-type other-pointer-type)))
230 (inst add func code)))
232 (defknown %function-self (function) function (flushable))
234 (define-vop (%function-self)
236 (:translate %function-self)
237 (:args (function :scs (descriptor-reg)))
238 (:results (result :scs (descriptor-reg)))
240 (loadw result function function-self-slot function-pointer-type)
242 (make-ea :byte :base result
243 :disp (- function-pointer-type
244 (* function-code-offset word-bytes))))))
246 ;;; Closure function slot is a pointer to raw code on X86 instead of
247 ;;; a pointer to the code function object itself. This VOP is used
248 ;;; to reference the function object given the closure object.
249 (def-source-transform %closure-function (closure)
250 `(%function-self ,closure))
252 (def-source-transform %funcallable-instance-function (fin)
253 `(%function-self ,fin))
255 (defknown (setf %function-self) (function function) function (unsafe))
257 (define-vop (%set-function-self)
259 (:translate (setf %function-self))
260 (:args (new-self :scs (descriptor-reg) :target result :to :result)
261 (function :scs (descriptor-reg) :to :result))
262 (:temporary (:sc any-reg :from (:argument 0) :to :result) temp)
263 (:results (result :scs (descriptor-reg)))
266 (make-ea :byte :base new-self
267 :disp (- (ash function-code-offset word-shift)
268 function-pointer-type)))
269 (storew temp function function-self-slot function-pointer-type)
270 (move result new-self)))
272 ;; Would have really liked to use a source-transform for this, but they
273 ;; don't work with setf functions.
275 (defknown ((setf %funcallable-instance-function)) (function function) function
277 (deftransform (setf %funcallable-instance-function) ((value fin))
278 '(setf (%function-self fin) value))
282 ;;;; Other random VOPs.
284 (defknown unix::do-pending-interrupt () (values))
285 (define-vop (unix::do-pending-interrupt)
287 (:translate unix::do-pending-interrupt)
289 (inst break pending-interrupt-trap)))
293 (inst break halt-trap)))
295 (defknown float-wait () (values))
296 (define-vop (float-wait)
298 (:translate float-wait)
300 (:save-p :compute-only)
302 (note-next-instruction vop :internal-error)
305 ;;;; Dynamic vop count collection support
307 (define-vop (count-me)
308 (:args (count-vector :scs (descriptor-reg)))
311 (inst inc (make-ea :dword :base count-vector
312 :disp (- (* (+ vector-data-offset index) word-bytes)
313 other-pointer-type)))))
317 (defknown lisp::%scrub-control-stack () (values))
319 ;;; Scrub the control stack.
321 ;;; On the x86 port the stack grows downwards, and to support grow on
322 ;;; demand stacks the stack must be decreased as it is scrubbed.
324 (define-vop (%scrub-control-stack)
326 (:translate lisp::%scrub-control-stack)
329 (:temporary (:sc unsigned-reg) count)
330 (:temporary (:sc any-reg) stack-save zero)
332 (inst mov stack-save esp-tn)
338 (inst mov count 2048)
342 (inst jmp :nz SCRUB-LOOP)
343 ;; Look for a clear stack unit.
344 (inst mov count 2048)
347 (inst cmp (make-ea :dword :base esp-tn) zero)
350 (inst jmp :nz LOOK-LOOP)
351 ;; Done, restore the stack pointer.
352 (inst mov esp-tn stack-save)))
355 ;;;; Primitive multi-thread support.
357 (export 'control-stack-fork)
358 (defknown control-stack-fork ((simple-array (unsigned-byte 32) (*)) t)
361 (define-vop (control-stack-fork)
363 (:translate control-stack-fork)
364 (:args (save-stack :scs (descriptor-reg) :to :result)
365 (inherit :scs (descriptor-reg)))
366 (:arg-types simple-array-unsigned-byte-32 *)
367 (:results (child :scs (descriptor-reg)))
369 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
370 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
371 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
374 (inst cmp inherit nil-value)
375 (inst jmp :e FRESH-STACK)
377 ;; Child inherits the stack of the parent.
379 ;; Setup the return context.
380 (inst push (make-fixup nil :code-object return))
383 (inst xor index index)
384 ;; First the stack-pointer.
385 (inst mov (make-ea :dword :base save-stack :index index :scale 4
386 :disp (- (* vm:vector-data-offset vm:word-bytes)
387 vm:other-pointer-type))
390 (load-foreign-data-symbol stack "control_stack_end")
391 (inst mov stack (make-ea :dword :base stack))
392 (inst jmp-short LOOP)
395 ;; Child has a fresh control stack.
397 ;; Setup the return context.
398 (inst push (make-fixup nil :code-object return))
399 (load-foreign-data-symbol stack "control_stack_end")
400 (inst mov stack (make-ea :dword :base stack))
401 ;; New FP is the Top of the stack.
404 (inst xor index index)
405 ;; First save the adjusted stack-pointer.
406 (inst sub stack ebp-tn)
407 (inst add stack esp-tn)
408 (inst mov (make-ea :dword :base save-stack :index index :scale 4
409 :disp (- (* vm:vector-data-offset vm:word-bytes)
410 vm:other-pointer-type))
412 ;; Save the current frame, replacing the OCFP and RA by 0.
413 (inst mov (make-ea :dword :base save-stack :index index :scale 4
414 :disp (- (* (+ vm:vector-data-offset 1) vm:word-bytes)
415 vm:other-pointer-type))
417 ;; Save 0 for the OCFP.
418 (inst mov (make-ea :dword :base save-stack :index index :scale 4
419 :disp (- (* (+ vm:vector-data-offset 2) vm:word-bytes)
420 vm:other-pointer-type))
423 ;; Copy the remainder of the frame, skiping the OCFP and RA which
425 (inst lea stack (make-ea :byte :base ebp-tn :disp -8))
428 (inst cmp stack esp-tn)
429 (inst jmp :le stack-save-done)
431 (inst mov temp (make-ea :dword :base stack))
432 (inst mov (make-ea :dword :base save-stack :index index :scale 4
433 :disp (- (* vm:vector-data-offset vm:word-bytes)
434 vm:other-pointer-type))
437 (inst jmp-short LOOP)
440 ;; Stack already clean if it reaches here. Parent returns NIL.
441 (inst mov child nil-value)
442 (inst jmp-short DONE)
448 (load-symbol child t)
451 (export 'control-stack-resume)
452 (defknown control-stack-resume ((simple-array (unsigned-byte 32) (*))
453 (simple-array (unsigned-byte 32) (*)))
456 (define-vop (control-stack-resume)
458 (:translate control-stack-resume)
459 (:args (save-stack :scs (descriptor-reg) :to :result)
460 (new-stack :scs (descriptor-reg) :to :result))
461 (:arg-types simple-array-unsigned-byte-32 simple-array-unsigned-byte-32)
462 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
463 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
464 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
467 ;; Setup the return context.
468 (inst push (make-fixup nil :code-object RETURN))
471 (inst xor index index)
472 ;; First the stack-pointer.
473 (inst mov (make-ea :dword :base save-stack :index index :scale 4
474 :disp (- (* vm:vector-data-offset vm:word-bytes)
475 vm:other-pointer-type))
478 (load-foreign-data-symbol stack "control_stack_end")
479 (inst mov stack (make-ea :dword :base stack))
481 (inst cmp stack esp-tn)
482 (inst jmp :le STACK-SAVE-DONE)
484 (inst mov temp (make-ea :dword :base stack))
485 (inst mov (make-ea :dword :base save-stack :index index :scale 4
486 :disp (- (* vm:vector-data-offset vm:word-bytes)
487 vm:other-pointer-type))
490 (inst jmp-short LOOP)
496 ;; Restore the new-stack.
497 (inst xor index index)
498 ;; First the stack-pointer.
500 (make-ea :dword :base new-stack :index index :scale 4
501 :disp (- (* vm:vector-data-offset vm:word-bytes)
502 vm:other-pointer-type)))
504 (load-foreign-data-symbol stack "control_stack_end")
505 (inst mov stack (make-ea :dword :base stack))
507 (inst cmp stack esp-tn)
508 (inst jmp :le STACK-RESTORE-DONE)
510 (inst mov temp (make-ea :dword :base new-stack :index index :scale 4
511 :disp (- (* vm:vector-data-offset vm:word-bytes)
512 vm:other-pointer-type)))
513 (inst mov (make-ea :dword :base stack) temp)
515 (inst jmp-short LOOP2)
517 ;; Pop the frame pointer, and resume at the return address.
521 ;; Original thread resumes, stack has been cleaned up.
525 (export 'control-stack-return)
526 (defknown control-stack-return ((simple-array (unsigned-byte 32) (*)))
529 (define-vop (control-stack-return)
531 (:translate control-stack-return)
532 (:args (new-stack :scs (descriptor-reg) :to :result))
533 (:arg-types simple-array-unsigned-byte-32)
534 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) index)
535 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) stack)
536 (:temporary (:sc unsigned-reg :from (:eval 0) :to (:eval 1)) temp)
539 ;; Restore the new-stack.
540 (inst xor index index)
541 ;; First the stack-pointer.
543 (make-ea :dword :base new-stack :index index :scale 4
544 :disp (- (* vm:vector-data-offset vm:word-bytes)
545 vm:other-pointer-type)))
547 (load-foreign-data-symbol stack "control_stack_end")
548 (inst mov stack (make-ea :dword :base stack))
550 (inst cmp stack esp-tn)
551 (inst jmp :le STACK-RESTORE-DONE)
553 (inst mov temp (make-ea :dword :base new-stack :index index :scale 4
554 :disp (- (* vm:vector-data-offset vm:word-bytes)
555 vm:other-pointer-type)))
556 (inst mov (make-ea :dword :base stack) temp)
558 (inst jmp-short LOOP)
560 ;; Pop the frame pointer, and resume at the return address.
565 ;; the RDTSC instruction (present on Pentium processors and
566 ;; successors) allows you to access the time-stamp counter, a 64-bit
567 ;; model-specific register that counts executed cycles. The
568 ;; instruction returns the low cycle count in EAX and high cycle count
571 ;; In order to obtain more significant results on out-of-order
572 ;; processors (such as the Pentium II and later), we issue a
573 ;; serializing CPUID instruction before reading the cycle counter.
574 ;; This instruction is used for its side effect of emptying the
575 ;; processor pipeline, to ensure that the RDTSC instruction is
576 ;; executed once all pending instructions have been completed.
578 ;; Note that cache effects mean that the cycle count can vary for
579 ;; different executions of the same code (it counts cycles, not
580 ;; retired instructions). Furthermore, the results are per-processor
581 ;; and not per-process, so are unreliable on multiprocessor machines
582 ;; where processes can migrate between processors.
584 ;; This method of obtaining a cycle count has the advantage of being
585 ;; very fast (around 20 cycles), and of not requiring a system call.
586 ;; However, you need to know your processor's clock speed to translate
587 ;; this into real execution time.
589 (defknown read-cycle-counter () (values (unsigned-byte 32) (unsigned-byte 32)) ())
591 (define-vop (read-cycle-counter)
592 (:translate read-cycle-counter)
593 (:guard (backend-featurep :pentium))
596 (:results (lo :scs (unsigned-reg))
597 (hi :scs (unsigned-reg)))
598 (:result-types unsigned-num unsigned-num)
599 (:temporary (:sc unsigned-reg :offset eax-offset :target lo) eax)
600 (:temporary (:sc unsigned-reg :offset edx-offset :target hi) edx)
601 ;; CPUID writes to eax, ebx, ecx, and edx. We need temporaries for
602 ;; ebx and ecx so we don't destroy any live uses of ebx and ecx.
603 (:temporary (:sc unsigned-reg :offset ebx-offset
604 :from (:eval 0) :to (:result 1))
606 (:temporary (:sc unsigned-reg :offset ecx-offset
607 :from (:eval 0) :to (:result 2))
618 (defun read-cycle-counter ()
619 (read-cycle-counter))
621 (defknown cpuid ((unsigned-byte 32))
622 (values (unsigned-byte 32)
631 (:args (level :scs (unsigned-reg) :to (:eval 0)))
632 (:arg-types unsigned-num)
633 (:results (a :scs (unsigned-reg))
634 (b :scs (unsigned-reg))
635 (c :scs (unsigned-reg))
636 (d :scs (unsigned-reg)))
637 (:result-types unsigned-num unsigned-num unsigned-num unsigned-num)
638 ;; Not sure about these :from/:to values.
639 (:temporary (:sc unsigned-reg :offset eax-offset
640 :from (:eval 0) :to (:result 0))
642 (:temporary (:sc unsigned-reg :offset ebx-offset
643 :from (:eval 0) :to (:result 1))
645 (:temporary (:sc unsigned-reg :offset ecx-offset
646 :from (:eval 0) :to (:result 2))
648 (:temporary (:sc unsigned-reg :offset edx-offset
649 :from (:eval 0) :to (:result 3))
651 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 0)) eax-stack)
652 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 1)) ebx-stack)
653 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 2)) ecx-stack)
654 (:temporary (:sc unsigned-stack :from (:eval 0) :to (:result 3)) edx-stack)
658 ;; Don't know where a, b, c, d are, so we save the results of
659 ;; cpuid to the stack and then copy the stack values to the result
660 ;; registers. But we can skip this if the result registers match
661 ;; the output registers of the cpuid instruction.
662 (unless (and (location= eax a)
673 (move d edx-stack))))
677 (declare (type (unsigned-byte 32) level))