1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2001, 2003-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway.
6 ;;;; For distribution policy, see the accompanying file COPYING.
8 ;;;; Filename: segments.lisp
10 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
11 ;;;; Created at: Thu May 8 14:25:06 2003
13 ;;;; $Id: segments.lisp,v 1.19 2007/04/13 22:41:05 ffjeld Exp $
15 ;;;;------------------------------------------------------------------
17 (provide :muerte
/segments
)
21 (defvar *initial-segment-descriptor-table
*)
23 (defun segment-register (segment-register-name)
24 "Return the value of an x86 segment register, such as :cs or :ds."
25 (declare (without-check-stack-limit))
26 (macrolet ((sreg (reg)
27 `(with-inline-assembly (:returns
:untagged-fixnum-ecx
)
30 (ecase segment-register-name
38 (defun (setf segment-register
) (value segment-register-name
)
39 "This function indiscriminately sets a segment register,
40 which is a great way to crash the machine. So know what you're doing."
41 (declare (without-check-stack-limit))
42 (check-type value
(unsigned-byte 16))
43 (macrolet ((set-sreg (reg)
44 `(with-inline-assembly (:returns
:nothing
)
45 (:compile-form
(:result-mode
:ecx
) value
)
46 (:shrl
#.movitz
::+movitz-fixnum-shift
+ :ecx
)
48 (ecase segment-register-name
54 (:cs
(without-interrupts
55 (with-inline-assembly (:returns
:nothing
)
56 (:load-lexical
(:lexical-binding value
) :untagged-fixnum-ecx
)
57 (:declare-label-set jmp-table
(jmp-target))
58 (:pushl
:ecx
) ; push selector
59 (:pushl
(:esi
(:offset movitz-funobj constant0
) 'jmp-table
))
67 "Return the location of the GDT, and the limit.
68 Error if the GDT location is not zero modulo 4."
69 (declare (without-check-stack-limit))
70 (eval-when (:compile-toplevel
)
71 (assert (= 4 movitz
:+movitz-fixnum-factor
+)))
73 (with-inline-assembly (:returns
:multiple-values
)
80 (:shrl
#.
(cl:-
16 movitz
::+movitz-fixnum-shift
+) :ebx
)
88 (defun %lgdt
(base-location limit
)
89 "Set the GDT according to base-location and limit.
90 This is the setter corresponding to the sgdt getter."
91 (declare (without-check-stack-limit))
92 (eval-when (:compile-toplevel
)
93 (assert (= 4 movitz
:+movitz-fixnum-factor
+)))
94 (check-type base-location fixnum
)
95 (check-type limit positive-fixnum
)
97 (with-inline-assembly (:returns
:eax
)
98 (:compile-form
(:result-mode
:push
) base-location
)
99 (:compile-form
(:result-mode
:push
) limit
)
100 (:shll
#.
(cl:-
16 movitz
:+movitz-fixnum-shift
+) (:esp
))
101 (:leal
(:esp
2) :ecx
)
108 (defun control-register (name)
109 (macrolet ((creg (reg)
110 `(with-inline-assembly (:returns
:untagged-fixnum-ecx
)
111 (:movcr
,reg
:ecx
))))
116 (:cr4
(creg :cr4
)))))
118 (defun control-register-lo12 (name)
119 "Return the low 12 bits of an x86 control register, such as :cr0 or :cr1."
120 (macrolet ((creg (reg)
121 `(with-inline-assembly (:returns
:untagged-fixnum-ecx
)
123 (:andl
#xfff
:ecx
))))
128 (:cr4
(creg :cr4
)))))
130 (defun control-register-hi20 (name)
131 "Return the high 20 bits of an x86 control register, such as :cr0 or :cr1."
132 (macrolet ((creg (reg)
133 `(with-inline-assembly (:returns
:ecx
)
135 (:andl
#xfffff000
:ecx
)
136 (:shrl
#.
(cl:-
12 movitz
::+movitz-fixnum-shift
+) :ecx
))))
141 (:cr4
(creg :cr4
)))))
143 (defun (setf control-register-lo12
) (value name
)
144 "Set the low 12 bits of an x86 control register, such as :cr0 or :cr1."
145 (macrolet ((set-creg (reg)
146 `(with-inline-assembly (:returns
:nothing
)
147 (:compile-form
(:result-mode
:eax
) value
)
149 (:andl
,(cl:* movitz
::+movitz-fixnum-factor
+ #xfff
) :eax
)
150 (:andl
#xfffff000
:ecx
)
151 (:shrl
,movitz
::+movitz-fixnum-shift
+ :eax
)
153 (:movcr
:ecx
,reg
))))
155 (:cr0
(set-creg :cr0
))
156 (:cr2
(set-creg :cr2
))
157 (:cr3
(set-creg :cr3
))
158 (:cr4
(set-creg :cr4
)))
161 (defun (setf control-register-hi20
) (value name
)
162 "Set the high 20 bits of an x86 control register, such as :cr0 or :cr1."
163 (macrolet ((set-creg (reg)
164 `(with-inline-assembly (:returns
:nothing
)
165 (:compile-form
(:result-mode
:eax
) value
)
167 (:shll
,(- 12 movitz
::+movitz-fixnum-shift
+) :eax
)
169 (:andl
#xfffff000
:eax
)
171 (:movcr
:ecx
,reg
))))
173 (:cr0
(set-creg :cr0
))
174 (:cr2
(set-creg :cr2
))
175 (:cr3
(set-creg :cr3
))
176 (:cr4
(set-creg :cr4
)))
181 (defun (setf global-segment-descriptor-table
) (table)
182 "Install <table> as the GDT.
183 NB! you need to ensure that the table object isn't garbage-collected."
184 (check-type table
(vector (unsigned-byte 32)))
185 (let ((limit (1- (* 4 (length table
))))
186 (base (+ 2 (+ (object-location table
)
187 (location-physical-offset)))))
191 (defun segment-descriptor-base-location (table selector
)
192 (check-type table
(and vector
(not simple-vector
)))
193 (eval-when (:compile-toplevel
)
194 (assert (= 4 movitz
::+movitz-fixnum-factor
+)))
195 ;; XXX This fails for locations above 2GB.
196 (let ((offset (+ (logand selector
#xfff8
)
197 (movitz-type-slot-offset 'movitz-basic-vector
'data
))))
198 (logior (ash (memref table
(+ 7 offset
) :type
:unsigned-byte8
)
200 (ash (memref table
(+ 4 offset
) :type
:unsigned-byte8
)
202 (ash (memref table
(+ 2 offset
) :type
:unsigned-byte16
)
205 (defun (setf segment-descriptor-base-location
) (base-location table selector
)
206 (check-type table
(and vector
(not simple-vector
)))
207 (eval-when (:compile-toplevel
)
208 (assert (= 4 movitz
::+movitz-fixnum-factor
+)))
209 (let ((offset (+ (logand #xfff8 selector
)
210 (movitz-type-slot-offset 'movitz-basic-vector
'data
))))
211 (setf (memref table
(+ 7 offset
) :type
:unsigned-byte8
)
212 (ldb (byte 8 22) base-location
))
213 (setf (memref table
(+ 4 offset
) :type
:unsigned-byte8
)
214 (ldb (byte 8 14) base-location
))
215 (setf (memref table
(+ 2 offset
) :type
:unsigned-byte16
)
216 (ash (ldb (byte 14 0) base-location
) 2))
219 (defun segment-descriptor-limit (table selector
)
220 (check-type table
(and vector
(not simple-vector
)))
221 (let ((offset (+ (logand #xfff8 selector
)
222 (movitz-type-slot-offset 'movitz-basic-vector
'data
))))
223 (dpb (memref table
(+ 6 offset
) :type
:unsigned-byte8
)
225 (memref table
(+ 0 offset
) :type
:unsigned-byte16
))))
227 (defun (setf segment-descriptor-limit
) (limit table selector
)
228 (check-type table
(and vector
(not simple-vector
)))
229 (let ((offset (+ (logand #xfff8 selector
)
230 (movitz-type-slot-offset 'movitz-basic-vector
'data
))))
231 (setf (ldb (byte 4 0) (memref table
(+ 6 offset
) :type
:unsigned-byte8
))
232 (ldb (byte 4 16) limit
))
233 (setf (memref table
(+ 0 offset
) :type
:unsigned-byte16
)
234 (ldb (byte 16 0) limit
))
237 (defun segment-descriptor-type-s-dpl-p (table selector
)
238 "Access bits 40-47 of the segment descriptor."
239 (check-type table
(and vector
(not simple-vector
)))
240 (memref table
(+ 5 (logand #xfff8 selector
)
241 (movitz-type-slot-offset 'movitz-basic-vector
'data
))
242 :type
:unsigned-byte8
))
244 (defun (setf segment-descriptor-type-s-dpl-p
) (bits table selector
)
245 "Access bits 40-47 of the segment descriptor."
246 (check-type table
(and vector
(not simple-vector
)))
247 (setf (memref table
(+ 5 (logand #xfff8 selector
)
248 (movitz-type-slot-offset 'movitz-basic-vector
'data
))
249 :type
:unsigned-byte8
)
252 (defun segment-descriptor-avl-x-db-g (table selector
)
253 "Access bits 52-55 of the segment descriptor."
254 (check-type table
(and vector
(not simple-vector
)))
256 (memref table
(+ 6 (logand #xfff8 selector
)
257 (movitz-type-slot-offset 'movitz-basic-vector
'data
))
258 :type
:unsigned-byte8
)))
260 (defun (setf segment-descriptor-avl-x-db-g
) (bits table selector
)
261 "Access bits 52-55 of the segment descriptor."
262 (check-type table
(and vector
(not simple-vector
)))
263 (setf (ldb (byte 4 4)
264 (memref table
(+ 6 (logand #xfff8 selector
)
265 (movitz-type-slot-offset 'movitz-basic-vector
'data
))
266 :type
:unsigned-byte8
))
269 (defun segment-descriptor (table selector
)
270 "Access entire segment descriptor as a 64-bit integer."
271 (check-type table
(and vector
(not simple-vector
)))
272 (let ((offset (+ (logand #xfff8 selector
)
273 (movitz-type-slot-offset 'movitz-basic-vector
'data
))))
274 (logior (ash (memref table offset
:index
1 :type
:unsigned-byte32
)
276 (ash (memref table offset
:index
0 :type
:unsigned-byte32
)
279 (defun (setf segment-descriptor
) (value table selector
)
280 "Access entire segment descriptor as a 64-bit integer."
281 (check-type table
(and vector
(not simple-vector
)))
282 (let ((offset (+ (logand #xfff8 selector
)
283 (movitz-type-slot-offset 'movitz-basic-vector
'data
))))
284 (setf (memref table offset
:index
1 :type
:unsigned-byte32
)
285 (ldb (byte 32 32) value
))
286 (setf (memref table offset
:index
0 :type
:unsigned-byte32
)
287 (ldb (byte 32 0) value
))
290 (defun dump-global-segment-table (&key table entries nofill
)
291 "Dump contents of the current global (segment) descriptor table into a vector."
292 (multiple-value-bind (gdt-base gdt-limit
)
294 (let* ((gdt-entries (/ (1+ gdt-limit
) 8))
295 (entries (or entries gdt-entries
)))
296 (check-type entries
(integer 1 8192))
297 (let ((table (or table
298 (make-array (* 2 entries
)
299 :element-type
'(unsigned-byte 32)
300 :initial-element
0))))
301 (check-type table
(vector (unsigned-byte 32)))
303 (loop for i upfrom
0 below
(* 2 gdt-entries
)
304 do
(setf (aref table i
)
305 (memref gdt-base
0 :index i
:type
:unsigned-byte32
:physicalp t
))))