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
use x86_64::structures::gdt::SegmentSelector;
use x86_64::{PhysAddr, VirtAddr};

#[derive(Debug, Clone, Copy, Default)]
#[repr(packed)]
pub struct Context {
    pub cr3: usize,
    pub r15: usize,
    pub r14: usize,
    pub r13: usize,

    pub r12: usize,
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,

    pub r8: usize,
    pub rbp: usize,
    pub rsi: usize,
    pub rdi: usize,

    pub rdx: usize,
    pub rcx: usize,
    pub rbx: usize,
    pub rax: usize,

    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,
    pub rsp: usize,
    pub ss: usize,
}

impl Context {
    pub fn init(
        &mut self,
        entry_point: usize,
        stack_end_address: VirtAddr,
        page_table_address: PhysAddr,
        segment_selectors: (SegmentSelector, SegmentSelector),
    ) {
        self.rflags = 0x200;
        self.rip = entry_point;
        self.rsp = stack_end_address.as_u64() as usize;
        self.cr3 = page_table_address.as_u64() as usize;

        let (code_selector, data_selector) = segment_selectors;
        self.cs = code_selector.0 as usize;
        self.ss = data_selector.0 as usize;
    }

    #[inline]
    pub fn address(&self) -> VirtAddr {
        VirtAddr::new(self as *const Context as u64)
    }

    #[inline]
    pub fn from_address(address: VirtAddr) -> Context {
        unsafe { *&mut *(address.as_u64() as *mut Context) }
    }
}

#[macro_export]
macro_rules! push_context {
    () => {
        concat!(
            r#"
			push rax
            push rbx
            push rcx
            push rdx
            push rdi
            push rsi
            push rbp
            push r8
            push r9
            push r10
            push r11
            push r12
            push r13
            push r14
            push r15
            mov r15, cr3
            push r15
			"#,
        )
    };
}

#[macro_export]
macro_rules! pop_context {
    () => {
        concat!(
            r#"
			pop r15
            mov cr3, r15
            pop r15
            pop r14
            pop r13
            pop r12
            pop r11
            pop r10
            pop r9
            pop r8
            pop rbp
            pop rsi
            pop rdi
            pop rdx
            pop rcx
            pop rbx
            pop rax
			"#
        )
    };
}