Skip to content

Commit 4ebcf1e

Browse files
authored
Add User Mode registers (#119)
1 parent 99b8a0a commit 4ebcf1e

File tree

2 files changed

+172
-1
lines changed

2 files changed

+172
-1
lines changed

src/registers/model_specific.rs

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
//! Functions to read and write control registers.
1+
//! Functions to read and write model specific registers.
22
3+
use crate::registers::rflags::RFlags;
4+
use crate::structures::gdt::SegmentSelector;
5+
use crate::PrivilegeLevel;
6+
use bit_field::BitField;
37
use bitflags::bitflags;
8+
use core::convert::TryInto;
49

510
/// A model specific register.
611
#[derive(Debug)]
@@ -29,6 +34,18 @@ pub struct GsBase;
2934
#[derive(Debug)]
3035
pub struct KernelGsBase;
3136

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+
3249
impl Efer {
3350
/// The underlying model specific register.
3451
pub const MSR: Msr = Msr(0xC0000080);
@@ -49,6 +66,21 @@ impl KernelGsBase {
4966
pub const MSR: Msr = Msr(0xC000_0102);
5067
}
5168

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+
5284
bitflags! {
5385
/// Flags of the Extended Feature Enable Register.
5486
pub struct EferFlags: u64 {
@@ -172,4 +204,138 @@ mod x86_64 {
172204
unsafe { Self::MSR.write(address.as_u64()) };
173205
}
174206
}
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+
}
175341
}

src/structures/gdt.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ impl SegmentSelector {
3434
pub fn rpl(&self) -> PrivilegeLevel {
3535
PrivilegeLevel::from_u16(self.0.get_bits(0..2))
3636
}
37+
38+
/// Set the privilege level for this Segment selector.
39+
pub fn set_rpl(&mut self, rpl: PrivilegeLevel) {
40+
self.0.set_bits(0..2, rpl as u16);
41+
}
3742
}
3843

3944
impl fmt::Debug for SegmentSelector {

0 commit comments

Comments
 (0)