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
#[repr(C)]
#[derive(Debug)]
pub struct Regs {
    pub r15: u64,
    pub r14: u64,
    pub r13: u64,
    pub r12: u64,
    pub r11: u64,
    pub r10: u64,
    pub r9: u64,
    pub r8: u64,
    pub rsi: u64,
    pub rdi: u64,
    pub rbp: u64,
    pub rdx: u64,
    pub rcx: u64,
    pub rbx: u64,
    pub rax: u64,
    pub _alignment: u64,
    pub error: u64,
    pub rip: u64,
    pub cs: u64,
    pub rflags: u64,
    pub rsp: u64,
    pub ss: u64
}

#[repr(C, packed)]
#[derive(Default)]
pub struct Tss {
    pub reserved1: u32,
    pub rsp0: u64,
    pub rsp1: u64,
    pub rsp2: u64,
    pub reserved2: u64,
    pub ist1: u64,
    pub ist2: u64,
    pub ist3: u64,
    pub ist4: u64,
    pub ist5: u64,
    pub ist6: u64,
    pub ist7: u64,
    pub reserved3: u64,
    pub iopm_len: u16,
    pub reserved4: u16
}

#[repr(C, packed)]
#[derive(Default)]
pub struct DescriptorExtra {
    pub limit_low: u16,
    pub base_low: u16,
    pub base_mid: u8,
    pub access: u8,
    pub limit_high_and_flags: u8,
    pub base_high: u8,
    pub base_extra: u32,
    pub reserved: u32
}

#[repr(C, packed)]
#[derive(Default)]
pub struct InterruptDescriptor {
    pub offset_low: u16,
    pub selector: u16,
    pub reserved1: u8,
    pub type_attr: u8,
    pub offset_high: u16,
    pub offset_extra: u32,
    pub reserved2: u32
}

#[repr(C, packed)]
pub struct Dtr {
    pub limit: u16,
    pub base: u64
}

pub const IA32_STAR: u32 = 0xC0000081;
pub const IA32_LSTAR: u32 = 0xC0000082;
pub const IA32_SFMASK: u32 = 0xC0000084;

extern {
    pub fn lidt(ptr: &Dtr); // I don't know why I can't get lidt to work via inline asm
}

pub fn invlpg<T>(ptr: *const T) {
    unsafe { asm!("invlpg ($0)" :: "r"(ptr) : "memory" : "volatile") }
}

pub unsafe fn sysret<T, U>(rip: *const T, rsp: *const U, rflags: u64) -> ! {
    asm!("cli ; mov $0, %rsp ; sysretq" :: "r"(rsp), "{rcx}" (rip), "{r11}" (rflags) :: "volatile");
    unreachable!()
}

pub unsafe fn wrmsr(reg: u32, value: u64) {
    let value_hi = (value >> 32) as u32;
    let value_lo = value as u32;
    asm!("wrmsr" :: "{edx}" (value_hi), "{eax}" (value_lo), "{ecx}" (reg) :: "volatile");
}

pub fn read_cr2<T>() -> *mut T {
    let cr2;
    unsafe { asm!("mov %cr2, $0" : "=r"(cr2)) };
    cr2
}

pub fn read_cr3() -> usize {
    let cr3;
    unsafe { asm!("mov %cr3, $0" : "=r"(cr3)) };
    cr3
}

pub unsafe fn write_cr3(addr: usize) {
    asm!("mov $0, %cr3" :: "r"(addr) : "memory" : "volatile");
}

pub unsafe fn int(num: u8) {
    asm!("int $0" :: "N"(num) : "memory");
}

pub unsafe fn ltr(selector: u16) {
    asm!("ltr $0" :: "r"(selector) :: "volatile");
}

pub unsafe fn sti() {
    asm!("sti" :::: "volatile");
}

pub fn interrupts_enabled() -> bool {
    let rflags: usize;
    unsafe { asm!("pushfq ; pop $0" : "=r"(rflags)) };
    (rflags & (1 << 9)) != 0
}

pub fn wait_for_interrupt() {
    unsafe { asm!("hlt") }
}

pub fn current_frame() -> *const usize {
    let rbp;
    unsafe { asm!("mov %rbp, $0" : "=r"(rbp)) };
    rbp
}

pub unsafe fn outb(port: u16, val: u8) {
    asm!("outb %al, %dx" : : "{dx}" (port), "{al}" (val) : : "volatile");
}

pub unsafe fn inb(port: u16) -> u8 {
	let ret;
	asm!("inb %dx, %al" : "={al}" (ret) : "{dx}" (port) : : "volatile");
	ret
}

pub unsafe fn outw(port: u16, val: u16) {
    asm!("outw %ax, %dx" : : "{dx}" (port), "{ax}" (val) : : "volatile");
}

pub unsafe fn inw(port: u16) -> u16 {
	let ret;
	asm!("inw %dx, %ax" : "={ax}" (ret) : "{dx}" (port) : : "volatile");
	ret
}

pub unsafe fn inl(port: u16) -> u32 {
	let ret;
	asm!("inl %dx, %eax" : "={eax}" (ret) : "{dx}" (port) : : "volatile");
	ret
}

pub unsafe fn outl(port: u16, val: u32) {
    asm!("outl %eax, %dx" : : "{dx}" (port), "{eax}" (val) : : "volatile");
}