1
- //! Functions to read and write control registers.
1
+ //! Functions to read and write model specific registers.
2
2
3
+ use crate :: registers:: rflags:: RFlags ;
4
+ use crate :: structures:: gdt:: SegmentSelector ;
5
+ use crate :: PrivilegeLevel ;
6
+ use bit_field:: BitField ;
3
7
use bitflags:: bitflags;
8
+ use core:: convert:: TryInto ;
4
9
5
10
/// A model specific register.
6
11
#[ derive( Debug ) ]
@@ -29,6 +34,18 @@ pub struct GsBase;
29
34
#[ derive( Debug ) ]
30
35
pub struct KernelGsBase ;
31
36
37
+ /// Syscall Register: STAR
38
+ #[ derive( Debug ) ]
39
+ pub struct Star ;
40
+
41
+ /// Syscall Register: LSTAR
42
+ #[ derive( Debug ) ]
43
+ pub struct LStar ;
44
+
45
+ /// Syscall Register: SFMASK
46
+ #[ derive( Debug ) ]
47
+ pub struct SFMask ;
48
+
32
49
impl Efer {
33
50
/// The underlying model specific register.
34
51
pub const MSR : Msr = Msr ( 0xC0000080 ) ;
@@ -49,6 +66,21 @@ impl KernelGsBase {
49
66
pub const MSR : Msr = Msr ( 0xC000_0102 ) ;
50
67
}
51
68
69
+ impl Star {
70
+ /// The underlying model specific register.
71
+ pub const MSR : Msr = Msr ( 0xC000_0081 ) ;
72
+ }
73
+
74
+ impl LStar {
75
+ /// The underlying model specific register.
76
+ pub const MSR : Msr = Msr ( 0xC000_0082 ) ;
77
+ }
78
+
79
+ impl SFMask {
80
+ /// The underlying model specific register.
81
+ pub const MSR : Msr = Msr ( 0xC000_0084 ) ;
82
+ }
83
+
52
84
bitflags ! {
53
85
/// Flags of the Extended Feature Enable Register.
54
86
pub struct EferFlags : u64 {
@@ -172,4 +204,138 @@ mod x86_64 {
172
204
unsafe { Self :: MSR . write ( address. as_u64 ( ) ) } ;
173
205
}
174
206
}
207
+
208
+ impl Star {
209
+ /// Read the Ring 0 and Ring 3 segment bases.
210
+ /// The remaining fields are ignored because they are
211
+ /// not valid for long mode.
212
+ ///
213
+ /// # Returns
214
+ /// - Field 1 (SYSRET): The CS selector is set to this field + 16. SS.Sel is set to
215
+ /// this field + 8. Because SYSRET always returns to CPL 3, the
216
+ /// RPL bits 1:0 should be initialized to 11b.
217
+ /// - Field 2 (SYSCALL): This field is copied directly into CS.Sel. SS.Sel is set to
218
+ /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
219
+ /// 33:32 should be initialized to 00b.
220
+ pub fn read_raw ( ) -> ( u16 , u16 ) {
221
+ let msr_value = unsafe { Self :: MSR . read ( ) } ;
222
+ let sysret = msr_value. get_bits ( 48 ..64 ) ;
223
+ let syscall = msr_value. get_bits ( 32 ..48 ) ;
224
+ ( sysret. try_into ( ) . unwrap ( ) , syscall. try_into ( ) . unwrap ( ) )
225
+ }
226
+
227
+ /// Read the Ring 0 and Ring 3 segment bases.
228
+ /// Returns
229
+ /// - CS Selector SYSRET
230
+ /// - SS Selector SYSRET
231
+ /// - CS Selector SYSCALL
232
+ /// - SS Selector SYSCALL
233
+ pub fn read ( ) -> (
234
+ SegmentSelector ,
235
+ SegmentSelector ,
236
+ SegmentSelector ,
237
+ SegmentSelector ,
238
+ ) {
239
+ let raw = Self :: read_raw ( ) ;
240
+ return (
241
+ SegmentSelector ( ( raw. 0 + 16 ) . try_into ( ) . unwrap ( ) ) ,
242
+ SegmentSelector ( ( raw. 0 + 8 ) . try_into ( ) . unwrap ( ) ) ,
243
+ SegmentSelector ( ( raw. 1 ) . try_into ( ) . unwrap ( ) ) ,
244
+ SegmentSelector ( ( raw. 1 + 8 ) . try_into ( ) . unwrap ( ) ) ,
245
+ ) ;
246
+ }
247
+
248
+ /// Write the Ring 0 and Ring 3 segment bases.
249
+ /// The remaining fields are ignored because they are
250
+ /// not valid for long mode.
251
+ ///
252
+ /// # Parameters
253
+ /// - sysret: The CS selector is set to this field + 16. SS.Sel is set to
254
+ /// this field + 8. Because SYSRET always returns to CPL 3, the
255
+ /// RPL bits 1:0 should be initialized to 11b.
256
+ /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to
257
+ /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
258
+ /// 33:32 should be initialized to 00b.
259
+ ///
260
+ /// # Unsafety
261
+ /// Unsafe because this can cause system instability if passed in the
262
+ /// wrong values for the fields.
263
+ pub unsafe fn write_raw ( sysret : u16 , syscall : u16 ) {
264
+ let mut msr_value = 0u64 ;
265
+ msr_value. set_bits ( 48 ..64 , sysret. into ( ) ) ;
266
+ msr_value. set_bits ( 32 ..48 , syscall. into ( ) ) ;
267
+ Self :: MSR . write ( msr_value) ;
268
+ }
269
+
270
+ /// Write the Ring 0 and Ring 3 segment bases.
271
+ /// The remaining fields are ignored because they are
272
+ /// not valid for long mode.
273
+ /// This function will fail if the segment selectors are
274
+ /// not in the correct offset of each other or if the
275
+ /// segment selectors do not have correct privileges.
276
+ pub fn write (
277
+ cs_sysret : SegmentSelector ,
278
+ ss_sysret : SegmentSelector ,
279
+ cs_syscall : SegmentSelector ,
280
+ ss_syscall : SegmentSelector ,
281
+ ) -> Result < ( ) , & ' static str > {
282
+ if cs_sysret. 0 - 16 != ss_sysret. 0 - 8 {
283
+ return Err ( "Sysret CS and SS is not offset by 8." ) ;
284
+ }
285
+
286
+ if cs_syscall. 0 != ss_syscall. 0 - 8 {
287
+ return Err ( "Syscall CS and SS is not offset by 8." ) ;
288
+ }
289
+
290
+ if ss_sysret. rpl ( ) != PrivilegeLevel :: Ring3 {
291
+ return Err ( "Sysret's segment must be a Ring3 segment." ) ;
292
+ }
293
+
294
+ if ss_syscall. rpl ( ) != PrivilegeLevel :: Ring0 {
295
+ return Err ( "Syscall's segment must be a Ring0 segment." ) ;
296
+ }
297
+
298
+ unsafe { Self :: write_raw ( ( ss_sysret. 0 - 8 ) . into ( ) , cs_syscall. 0 . into ( ) ) } ;
299
+
300
+ Ok ( ( ) )
301
+ }
302
+ }
303
+
304
+ impl LStar {
305
+ /// Read the current LStar register.
306
+ /// This holds the target RIP of a syscall.
307
+ pub fn read ( ) -> VirtAddr {
308
+ VirtAddr :: new ( unsafe { Self :: MSR . read ( ) } )
309
+ }
310
+
311
+ /// Write a given virtual address to the LStar register.
312
+ /// This holds the target RIP of a syscall.
313
+ pub fn write ( address : VirtAddr ) {
314
+ unsafe { Self :: MSR . write ( address. as_u64 ( ) ) } ;
315
+ }
316
+ }
317
+
318
+ impl SFMask {
319
+ /// Read to the SFMask register.
320
+ /// The SFMASK register is used to specify which RFLAGS bits
321
+ /// are cleared during a SYSCALL. In long mode, SFMASK is used
322
+ /// to specify which RFLAGS bits are cleared when SYSCALL is
323
+ /// executed. If a bit in SFMASK is set to 1, the corresponding
324
+ /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
325
+ /// to 0, the corresponding rFLAGS bit is not modified.
326
+ pub fn read ( ) -> RFlags {
327
+ RFlags :: from_bits ( unsafe { Self :: MSR . read ( ) } ) . unwrap ( )
328
+ }
329
+
330
+ /// Write to the SFMask register.
331
+ /// The SFMASK register is used to specify which RFLAGS bits
332
+ /// are cleared during a SYSCALL. In long mode, SFMASK is used
333
+ /// to specify which RFLAGS bits are cleared when SYSCALL is
334
+ /// executed. If a bit in SFMASK is set to 1, the corresponding
335
+ /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
336
+ /// to 0, the corresponding rFLAGS bit is not modified.
337
+ pub fn write ( value : RFlags ) {
338
+ unsafe { Self :: MSR . write ( value. bits ( ) ) } ;
339
+ }
340
+ }
175
341
}
0 commit comments