vmi_arch_amd64/segment/mod.rs
1mod descriptor;
2pub use self::descriptor::SegmentDescriptor;
3
4mod selector;
5pub use self::selector::{DescriptorTable, Selector};
6
7/// Determines the type of segment descriptor.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum DescriptorType {
10 /// The descriptor is for a system segment.
11 System,
12
13 /// The descriptor is for a code or data segment.
14 CodeOrData,
15}
16
17/// Determines the default length for effective addresses and operands
18/// referenced by instructions in the segment.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum OperationSize {
21 /// 16-bit addresses and 16-bit or 8-bit operands are assumed.
22 Default,
23
24 /// 32-bit addresses and 32-bit or 8-bit operands are assumed.
25 Big,
26}
27
28/// Determines the scaling of the segment limit field.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Granularity {
31 /// The segment limit is interpreted in byte units.
32 Byte,
33
34 /// The segment limit is interpreted in 4-KByte units.
35 Page4K,
36}
37
38/// The access rights of a segment descriptor.
39#[derive(Default, Clone, Copy, PartialEq, Eq)]
40pub struct SegmentAccess(pub u32);
41
42impl SegmentAccess {
43 /// Indicates the segment or gate type and specifies the kinds of access
44 /// that can be made to the segment and the direction of growth. The
45 /// interpretation of this field depends on whether the descriptor type
46 /// flag specifies an application (code or data) descriptor or a system
47 /// descriptor. The encoding of the type field is different for code,
48 /// data, and system descriptors.
49 pub fn typ(self) -> u8 {
50 (self.0 & 0b1111) as _
51 }
52
53 /// Specifies whether the segment descriptor is for a system segment (S flag
54 /// is clear) or a code or data segment (S flag is set).
55 pub fn descriptor_type(self) -> DescriptorType {
56 if (self.0 >> 4) & 1 == 0 {
57 DescriptorType::System
58 }
59 else {
60 DescriptorType::CodeOrData
61 }
62 }
63
64 /// Specifies the privilege level of the segment. The privilege level can
65 /// range from 0 to 3, with 0 being the most privileged level. The DPL
66 /// is used to control access to the segment. See Section 5.5, “Privilege
67 /// Levels”, for a description of the relationship of the DPL to the CPL of
68 /// the executing code segment and the RPL of a segment selector.
69 pub fn descriptor_privilege_level(self) -> u8 {
70 ((self.0 >> 5) & 0b11) as _
71 }
72
73 /// Indicates whether the segment is present in memory (set) or not present
74 /// (clear). If this flag is clear, the processor generates a
75 /// segment-not-present exception (#NP) when a segment selector that
76 /// points to the segment descriptor is loaded into a segment register.
77 /// Memory management software can use this flag to control which
78 /// segments are actually loaded into physical memory at a given
79 /// time. It offers a control in addition to paging for managing virtual
80 /// memory.
81 pub fn present(self) -> bool {
82 (self.0 >> 7) & 1 != 0
83 }
84
85 /// This bit is available for use by system software.
86 pub fn available_bit(self) -> bool {
87 (self.0 >> 8) & 1 != 0
88 }
89
90 /// In IA-32e mode, bit 21 of the second doubleword of the segment
91 /// descriptor indicates whether a code segment contains native 64-bit
92 /// code. A value of 1 indicates instructions in this code segment
93 /// are executed in 64-bit mode. A value of 0 indicates the instructions in
94 /// this code segment are executed in compatibility mode. If L-bit is
95 /// set, then D-bit must be cleared. When not in IA-32e mode
96 /// or for non-code segments, bit 21 is reserved and should always be set to
97 /// 0.
98 pub fn long_mode(self) -> bool {
99 (self.0 >> 9) & 1 != 0
100 }
101
102 /// Performs different functions depending on whether the segment descriptor
103 /// is an executable code segment, an expand-down data segment, or a
104 /// stack segment. (This flag should always be set to 1 for 32-bit code
105 /// and data segments and to 0 for 16-bit code and data segments.)
106 ///
107 /// - Executable code segment. The flag is called the D flag and it
108 /// indicates the default length for effective addresses and operands
109 /// referenced by instructions in the segment. If the flag is set, 32-bit
110 /// addresses and 32-bit or 8-bit operands are assumed; if it is clear,
111 /// 16-bit addresses and 16-bit or 8-bit operands are assumed. The
112 /// instruction prefix 66H can be used to select an operand size other
113 /// than the default, and the prefix 67H can be used select an address
114 /// size other than the default.
115 ///
116 /// - Stack segment (data segment pointed to by the SS register). The flag
117 /// is called the B (big) flag and it specifies the size of the stack
118 /// pointer used for implicit stack operations (such as pushes, pops, and
119 /// calls). If the flag is set, a 32-bit stack pointer is used, which is
120 /// stored in the 32-bit ESP register; if the flag is clear, a 16-bit
121 /// stack pointer is used, which is stored in the 16- bit SP register. If
122 /// the stack segment is set up to be an expand-down data segment
123 /// (described in the next paragraph), the B flag also specifies the upper
124 /// bound of the stack segment.
125 ///
126 /// - Expand-down data segment. The flag is called the B flag and it
127 /// specifies the upper bound of the segment. If the flag is set, the
128 /// upper bound is FFFFFFFFH (4 GBytes); if the flag is clear, the upper
129 /// bound is FFFFH (64 KBytes).
130 pub fn operation_size(self) -> OperationSize {
131 if (self.0 >> 10) & 1 == 0 {
132 OperationSize::Default
133 }
134 else {
135 OperationSize::Big
136 }
137 }
138
139 /// Determines the scaling of the segment limit field. When the granularity
140 /// flag is clear, the segment limit is interpreted in byte units; when
141 /// flag is set, the segment limit is interpreted in 4-KByte units.
142 /// (This flag does not affect the granularity of the base address; it is
143 /// always byte granular.) When the granularity flag is set, the twelve
144 /// least significant bits of an offset are not tested when checking the
145 /// offset against the segment limit. For example, when the granularity flag
146 /// is set, a limit of 0 results in valid offsets from 0 to 4095.
147 pub fn granularity(self) -> Granularity {
148 if (self.0 >> 11) & 1 == 0 {
149 Granularity::Byte
150 }
151 else {
152 Granularity::Page4K
153 }
154 }
155}
156
157impl From<u32> for SegmentAccess {
158 fn from(value: u32) -> Self {
159 Self(value)
160 }
161}
162
163impl From<SegmentAccess> for u32 {
164 fn from(value: SegmentAccess) -> Self {
165 value.0
166 }
167}
168
169impl std::fmt::Debug for SegmentAccess {
170 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
171 f.debug_struct("Segment")
172 .field("type", &self.typ())
173 .field("descriptor_type", &self.descriptor_type())
174 .field(
175 "descriptor_privilege_level",
176 &self.descriptor_privilege_level(),
177 )
178 .field("present", &self.present())
179 .field("available_bit", &self.available_bit())
180 .field("long_mode", &self.long_mode())
181 .field("operation_size", &self.operation_size())
182 .field("granularity", &self.granularity())
183 .finish()
184 }
185}