x86_64/instructions/
segmentation.rs1pub use crate::registers::segmentation::{Segment, Segment64, CS, DS, ES, FS, GS, SS};
4use crate::{
5 registers::model_specific::{FsBase, GsBase, Msr},
6 structures::gdt::SegmentSelector,
7 VirtAddr,
8};
9use core::arch::asm;
10
11macro_rules! get_reg_impl {
12 ($name:literal) => {
13 #[inline]
14 fn get_reg() -> SegmentSelector {
15 let segment: u16;
16 unsafe {
17 asm!(concat!("mov {0:x}, ", $name), out(reg) segment, options(nomem, nostack, preserves_flags));
18 }
19 SegmentSelector(segment)
20 }
21 };
22}
23
24macro_rules! segment_impl {
25 ($type:ty, $name:literal) => {
26 impl Segment for $type {
27 get_reg_impl!($name);
28
29 #[inline]
30 unsafe fn set_reg(sel: SegmentSelector) {
31 unsafe {
32 asm!(concat!("mov ", $name, ", {0:x}"), in(reg) sel.0, options(nostack, preserves_flags));
33 }
34 }
35 }
36 };
37}
38
39macro_rules! segment64_impl {
40 ($type:ty, $name:literal, $base:ty) => {
41 impl Segment64 for $type {
42 const BASE: Msr = <$base>::MSR;
43 #[inline]
44 fn read_base() -> VirtAddr {
45 unsafe {
46 let val: u64;
47 asm!(concat!("rd", $name, "base {}"), out(reg) val, options(nomem, nostack, preserves_flags));
48 VirtAddr::new_unsafe(val)
49 }
50 }
51
52 #[inline]
53 unsafe fn write_base(base: VirtAddr) {
54 unsafe{
55 asm!(concat!("wr", $name, "base {}"), in(reg) base.as_u64(), options(nostack, preserves_flags));
56 }
57 }
58 }
59 };
60}
61
62impl Segment for CS {
63 get_reg_impl!("cs");
64
65 #[inline]
74 unsafe fn set_reg(sel: SegmentSelector) {
75 unsafe {
76 asm!(
77 "push {sel}",
78 "lea {tmp}, [55f + rip]",
79 "push {tmp}",
80 "retfq",
81 "55:",
82 sel = in(reg) u64::from(sel.0),
83 tmp = lateout(reg) _,
84 options(preserves_flags),
85 );
86 }
87 }
88}
89
90segment_impl!(SS, "ss");
91segment_impl!(DS, "ds");
92segment_impl!(ES, "es");
93segment_impl!(FS, "fs");
94segment64_impl!(FS, "fs", FsBase);
95segment_impl!(GS, "gs");
96segment64_impl!(GS, "gs", GsBase);
97
98impl GS {
99 #[inline]
106 pub unsafe fn swap() {
107 unsafe {
108 asm!("swapgs", options(nostack, preserves_flags));
109 }
110 }
111}