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
//! `x86_64` flags and bitfields.

/* Rflags Register */

/// Carry flag.
pub const RFLAGS_CF: u64 = 1 << 0;
/// Parity flag.
pub const RFLAGS_PF: u64 = 1 << 2;
/// Adjust flag.
pub const RFLAGS_AF: u64 = 1 << 4;
/// Zero flag.
pub const RFLAGS_ZF: u64 = 1 << 6;
/// Sign flag.
pub const RFLAGS_SF: u64 = 1 << 7;
/// Sign flag.
pub const RFLAGS_IF: u64 = 1 << 9;
/// Direction flag.
pub const RFLAGS_DF: u64 = 1 << 10;
/// Overflow flag.
pub const RFLAGS_OF: u64 = 1 << 11;
/// I/O privilege level.
pub const RFLAGS_IOPL: u64 = 0b11 << 12;
/// Alignment check.
pub const RFLAGS_AC: u64 = 1 << 18;

pub const fn rflags_cf(r: u64) -> u64   { (r & RFLAGS_CF)   >> 0 }
pub const fn rflags_pf(r: u64) -> u64   { (r & RFLAGS_PF)   >> 2 }
pub const fn rflags_af(r: u64) -> u64   { (r & RFLAGS_AF)   >> 4 }
pub const fn rflags_zf(r: u64) -> u64   { (r & RFLAGS_ZF)   >> 6 }
pub const fn rflags_sf(r: u64) -> u64   { (r & RFLAGS_SF)   >> 7 }
pub const fn rflags_if(r: u64) -> u64   { (r & RFLAGS_IF)   >> 9 }
pub const fn rflags_df(r: u64) -> u64   { (r & RFLAGS_DF)   >> 10 }
pub const fn rflags_of(r: u64) -> u64   { (r & RFLAGS_OF)   >> 11 }
pub const fn rflags_iopl(r: u64) -> u64 { (r & RFLAGS_IOPL) >> 12 }
pub const fn rflags_ac(r: u64) -> u64   { (r & RFLAGS_AC)   >> 18 }

/* Segment Selector */

/// Requested privilege level.
///
/// Privilege level of the segment selector, where `0` is the most privileged mode and `3` the
/// least.
pub const SEG_SELECTOR_RPL : u16 = 0b11 << 0;
/// Table indicator.
///
/// | TI | Table |
/// |----|-------|
/// | 0  | GDT   |
/// | 1  | LDT   |
pub const SEG_SELECTOR_TI : u16 = 1 << 2;
/// Table index.
///
/// Index into the `GDT` or `LDT` table to select the segment descriptor. `GDT.base + 8 * index`
/// gives the address of the segment descriptor (times `8` because every segment descriptor is `8
/// byte`).
pub const SEG_SELECTOR_INDEX : u16 = 0x1fff << 3;

pub const fn seg_selector_rpl(s : u16) -> u16   { (s & SEG_SELECTOR_RPL)   >> 0 }
pub const fn seg_selector_ti(s : u16) -> u16    { (s & SEG_SELECTOR_TI)    >> 2 }
pub const fn seg_selector_index(s : u16) -> u16 { (s & SEG_SELECTOR_INDEX) >> 3 }

/* Control Register CR0 (operation mode & state of the processor) */

/// Protection Enable.
///
/// Enables `protected mode` when set and `real-address mode` when cleared. This enables
/// `segment-level protection` not paging.
pub const CR0_PE: u64 = 1 << 0;
/// Monitor Coprocessor.
pub const CR0_MP: u64 = 1 << 1;
/// Emulation.
///
/// When set indicates the process does not have a FPU. FPU instructions will generate an exception
/// that software can emulate the instruction.
pub const CR0_EM: u64 = 1 << 2;
/// Task Switched.
pub const CR0_TS: u64 = 1 << 3;
/// Extension Type.
pub const CR0_ET: u64 = 1 << 4;
/// Numeric Error.
pub const CR0_NE: u64 = 1 << 5;
/// Write Protect.
///
/// When set supervisor-level procedures can't write to read-only pages.
pub const CR0_WP: u64 = 1 << 16;
/// Alignment Mask.
///
/// Enables alignment check for `CPL=3`, check is only done if the [AC
/// bit](crate::x86_64::RFLAGS_AC) of the `rflags` register ist set.
pub const CR0_AM: u64 = 1 << 18;
/// Not Write-Torugh.
pub const CR0_NW: u64 = 1 << 29;
/// Cachine disable.
pub const CR0_CD: u64 = 1 << 30;
/// Paging.
///
/// Enables paging when set, requires [CR0_PE](crate::x86_64::CR0_PE) to be set as well.
pub const CR0_PG: u64 = 1 << 31;

/* Control Register CR3 (paging information)
 *
 * Holds the physical base address of the first paging structure. The 12 lower bytes of the base
 * address are assumed to be 0 and hence the first paging structure must be aligned to a 4K
 * boundary.
 */

/// Mask for physical base address of paging structure.
pub const CR3_PAGE_BASE_MASK: u64 = 0xffff_ffff_ffff_0000;

/// Page-level Write-Through.
pub const CR3_PWT: u64 = 1 << 3;
/// Page-level Cache Disable.
pub const CR3_PCD: u64 = 1 << 4;

/* Control Register CR4 (flags for arch extenstions processor capabilities) */

/// Physical Address Extenstion.
///
/// When set enables paging to produce physicall addresses with more than 32 bits. Required before
/// entering `long mode`.
pub const CR4_PAE: u64 = 1 << 5;
/// 57-bit Linear Addresses.
///
/// When set in `long mode` enables `5-level` paging to translate `57-bit` linear addresses. When
/// cleared use `4-level` paging to translate `48-bit` linear addresses.
pub const CR4_LA57: u64 = 1 << 5;

/* Extended Feature Enable Register (EFER) */

/// Extended Feature Enable Register MSR number.
///
/// MSR number used with the [`rdmsr`][msr] and [`wrmsr`][msr] instructions to read/write the
/// `EFER` model specific register.
///
/// [msr]: https://johannst.github.io/notes/arch/x86_64.html#model-specific-register-msr
pub const MSR_EFER: u64 = 0xc000_0080;

/// Long Mode Enable.
///
/// When set enables long mode operations.
pub const EFER_LME: u64 = 1 << 8;
/// Long Mode Active (readonly).
///
/// When set indicates long mode is active.
pub const EFER_LMA: u64 = 1 << 10;

/* Paging */

/// Page entry present.
pub const PAGE_ENTRY_PRESENT : u64 = 1 << 0;
/// Page region read/write.
///
/// If set, region reference by paging entry is writeable.
pub const PAGE_RENTRY_RW : u64 = 1 << 1;