1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
#![allow(non_upper_case_globals)]
pub mod control_regs;
bitflags! {
pub flags Flags: usize {
const CarryFlag = 1 << 0,
const ParityFlag = 1 << 2,
const AdjustFlag = 1 << 4,
const ZeroFlag = 1 << 6,
const SignFlag = 1 << 7,
const TrapFlag = 1 << 8,
const InterruptFlag = 1 << 9,
const DirectionFlag = 1 << 10,
const OverflowFlag = 1 << 11,
const Iopl1 = 1 << 12,
const Iopl2 = 1 << 13,
const NestedTaskFlag = 1 << 14,
const ResumeFlag = 1 << 16,
const Virtual8086Flag = 1 << 17,
const AlignmentFlag = 1 << 18,
const VirtualInterruptFlag = 1 << 19,
const VirtualInterruptPending = 1 << 20,
const CpuIdFlag = 1 << 21
}
}
bitflags!(
pub flags Features: u64 {
const Fpu = 1 << 0,
const Virtual8086 = 1 << 1,
const DebugExtension = 1 << 2,
const PageSizeExtension = 1 << 3,
const TimeStampCounter = 1 << 4,
const ModelSpecificRegister = 1 << 5,
const PhysicalAddressExtension = 1 << 6,
const MachineCheckException = 1 << 7,
const Cx8 = 1 << 8, // CMPXCHG8
const Apic = 1 << 9,
const SysEnter = 1 << 11,
const MemoryTypeRange = 1 << 12,
const PageGlobal = 1 << 13,
const MachineCheckArchitecture = 1 << 14,
const CMov = 1 << 15,
const PageAttributeTable = 1 << 16,
const PageSizeExtension36 = 1 << 17,
const ProcessorSerial = 1 << 18,
const CacheFlush = 1 << 19,
const DebugStore = 1 << 21,
const Acpi = 1 << 22,
const Mmx = 1 << 23,
const FxSave = 1 << 24,
const Sse = 1 << 25,
const Sse2 = 1 << 26,
const SelfSnoop = 1 << 27,
const HyperThreading = 1 << 28,
const ThermalMonitor = 1 << 29,
const Ia64 = 1 << 30,
const PendingBreak = 1 << 31,
const Sse3 = 1 << (32 + 0),
const PclMulQdq = 1 << (32 + 1), // what
const DebugStore64 = 1 << (32 + 2),
const Monitor = 1 << (32 + 3),
const CplDebugStore = 1 << (32 + 4),
const Vmx = 1 << (32 + 5),
const SaferMode = 1 << (32 + 6),
const EnhancedSpeedStep = 1 << (32 + 7),
const ThermalMonitor2 = 1 << (32 + 8),
const Ssse3 = 1 << (32 + 9),
const L1ContextId = 1 << (32 + 10),
const Fma = 1 << (32 + 12),
const Cx16 = 1 << (32 + 13), // CMPXCHG16B
const Xtpr = 1 << (32 + 14), // I have no idea what this is
const PerformanceMonitor = 1 << (32 + 15),
const ProcessContextId = 1 << (32 + 17),
const DirectCache = 1 << (32 + 18),
const Sse41 = 1 << (32 + 19),
const Sse42 = 1 << (32 + 20),
const X2Apic = 1 << (32 + 21),
const MovBe = 1 << (32 + 22),
const PopulationCount = 1 << (32 + 23),
const TscDeadline = 1 << (32 + 24),
const AesNi = 1 << (32 + 25),
const XSave = 1 << (32 + 26),
const OsXSave = 1 << (32 + 27),
const Avx = 1 << (32 + 28),
const HalfPrecision = 1 << (32 + 29),
const HwRandom = 1 << (32 + 30)
}
);
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Exception {
DivisionByZero = 0,
Debug = 1,
Nmi = 2,
Breakpoint = 3,
Overflow = 4,
Bounds = 5,
InvalidOpcode = 6,
NotAvailable = 7,
DoubleFault = 8,
CoprocessorSegment = 9,
Tss = 10,
NotPresent = 11,
StackSegment = 12,
GeneralProtection = 13,
PageFault = 14,
Fpu = 16,
Alignment = 17,
MachineCheck = 18,
Simd = 19,
Virtualization = 20,
Security = 30
}
impl Exception {
pub fn from_code(code: u32) -> Option<Exception> {
Some(match code {
0 => Exception::DivisionByZero,
1 => Exception::Debug,
2 => Exception::Nmi,
3 => Exception::Breakpoint,
4 => Exception::Overflow,
5 => Exception::Bounds,
6 => Exception::InvalidOpcode,
7 => Exception::NotAvailable,
8 => Exception::DoubleFault,
9 => Exception::CoprocessorSegment,
10 => Exception::Tss,
11 => Exception::NotPresent,
12 => Exception::StackSegment,
13 => Exception::GeneralProtection,
14 => Exception::PageFault,
16 => Exception::Fpu,
17 => Exception::Alignment,
18 => Exception::MachineCheck,
19 => Exception::Simd,
20 => Exception::Virtualization,
30 => Exception::Security,
_ => return None
})
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Msr {
ApicBase = 0x1B
}
#[inline(always)]
pub fn cpuid(function: u32) -> (u32, u32, u32, u32) {
unsafe {
let (eax, ebx, ecx, edx): (u32, u32, u32, u32);
asm!("cpuid" : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx) : "{eax}"(function));
(eax, ebx, ecx, edx)
}
}
#[inline(always)]
pub fn supports() -> Features {
let (_, _, feature_ecx, feature_edx) = cpuid(1);
Features {
bits: ((feature_ecx as u64) << 32) | (feature_edx as u64)
}
}
#[inline(always)]
pub unsafe fn read_msr(msr: Msr) -> u64 {
let (r1, r2): (u32, u32);
asm!("rdmsr" : "={eax}"(r1), "={edx}"(r2) : "{ecx}"(msr as u32) :: "intel");
r1 as u64 | ((r2 as u64) << 32)
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PrivilegeLevel {
Ring0 = 0,
Ring1 = 1,
Ring2 = 2,
Ring3 = 3,
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(C, packed)]
pub struct SegmentSelector {
data: u16
}
impl SegmentSelector {
#[inline(always)]
pub fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
SegmentSelector {
data: index << 3 | rpl as u16
}
}
pub fn bits(&self) -> u16 {
self.data
}
}
#[inline(always)]
pub unsafe fn set_tr(selector: SegmentSelector) {
asm!("ltr $0" :: "r"(selector.bits()) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn set_ss(selector: SegmentSelector) {
asm!("mov ss, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn set_ds(selector: SegmentSelector) {
asm!("mov ds, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn set_es(selector: SegmentSelector) {
asm!("mov es, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn set_gs(selector: SegmentSelector) {
asm!("mov gs, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn set_fs(selector: SegmentSelector) {
asm!("mov fs, $0" :: "r"(selector.bits()) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn set_cs(selector: SegmentSelector) {
asm!("push $0;
push $$1f
lret;
1:" :: "ri"(selector.bits() as usize) :: "volatile");
}
#[inline(always)]
pub unsafe fn enable_interrupts() {
asm!("sti" :::: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn disable_interrupts() {
asm!("cli" :::: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn halt() {
asm!("hlt" :::: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn out8(port: u16, value: u8) {
asm!("out $0, $1" :: "{dx}"(port), "{al}"(value) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn out16(port: u16, value: u16) {
asm!("out $0, $1" :: "{dx}"(port), "{ax}"(value) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn out32(port: u16, value: u32) {
asm!("out $0, $1" :: "{dx}"(port), "{eax}"(value) :: "volatile", "intel");
}
#[inline(always)]
pub unsafe fn outs8(port: u16, buf: &[u8]) {
asm!("rep outsb dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
#[inline(always)]
pub unsafe fn outs16(port: u16, buf: &[u16]) {
asm!("rep outsw dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
#[inline(always)]
pub unsafe fn outs32(port: u16, buf: &[u32]) {
asm!("rep outsd dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
#[inline(always)]
pub unsafe fn in8(port: u16) -> u8 {
let r: u8;
asm!("in $0, $1" : "={al}"(r) : "{dx}"(port) :: "intel");
r
}
#[inline(always)]
pub unsafe fn in16(port: u16) -> u16 {
let r: u16;
asm!("in $0, $1" : "={ax}"(r) : "{dx}"(port) :: "intel");
r
}
#[inline(always)]
pub unsafe fn in32(port: u16) -> u32 {
let r: u32;
asm!("in $0, $1" : "={eax}"(r) : "{dx}"(port) :: "intel");
r
}
#[inline(always)]
pub unsafe fn ins8(port: u16, buf: &mut [u8]) {
asm!("rep insb [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
#[inline(always)]
pub unsafe fn ins16(port: u16, buf: &mut [u16]) {
asm!("rep insw [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
#[inline(always)]
pub unsafe fn ins32(port: u16, buf: &mut [u32]) {
asm!("rep insd [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel");
}
|