x86_64/
gdt.rs

1// Copyright 2017 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// For GDT details see arch/x86/include/asm/segment.h
6
7use hypervisor::Segment;
8
9/// Constructor for a conventional segment GDT (or LDT) entry. Derived from the kernel's segment.h.
10pub fn gdt_entry(flags: u16, base: u32, limit: u32) -> u64 {
11    (((base as u64) & 0xff000000u64) << (56 - 24))
12        | (((flags as u64) & 0x0000f0ffu64) << 40)
13        | (((limit as u64) & 0x000f0000u64) << (48 - 16))
14        | (((base as u64) & 0x00ffffffu64) << 16)
15        | ((limit as u64) & 0x0000ffffu64)
16}
17
18fn get_base(entry: u64) -> u64 {
19    (((entry) & 0xFF00000000000000) >> 32)
20        | (((entry) & 0x000000FF00000000) >> 16)
21        | (((entry) & 0x00000000FFFF0000) >> 16)
22}
23
24fn get_limit(entry: u64) -> u32 {
25    ((((entry) & 0x000F000000000000) >> 32) | ((entry) & 0x000000000000FFFF)) as u32
26}
27
28fn get_g(entry: u64) -> u8 {
29    ((entry & 0x0080000000000000) >> 55) as u8
30}
31
32fn get_db(entry: u64) -> u8 {
33    ((entry & 0x0040000000000000) >> 54) as u8
34}
35
36fn get_l(entry: u64) -> u8 {
37    ((entry & 0x0020000000000000) >> 53) as u8
38}
39
40fn get_avl(entry: u64) -> u8 {
41    ((entry & 0x0010000000000000) >> 52) as u8
42}
43
44fn get_p(entry: u64) -> u8 {
45    ((entry & 0x0000800000000000) >> 47) as u8
46}
47
48fn get_dpl(entry: u64) -> u8 {
49    ((entry & 0x0000600000000000) >> 45) as u8
50}
51
52fn get_s(entry: u64) -> u8 {
53    ((entry & 0x0000100000000000) >> 44) as u8
54}
55
56fn get_type(entry: u64) -> u8 {
57    ((entry & 0x00000F0000000000) >> 40) as u8
58}
59
60/// Automatically build the hypervisor Segment struct for set_sregs from the kernel bit fields.
61///
62/// # Arguments
63///
64/// * `entry` - The gdt entry.
65/// * `table_index` - Index of the entry in the gdt table.
66pub fn segment_from_gdt(entry: u64, table_index: u8) -> Segment {
67    let g = get_g(entry);
68    let limit = get_limit(entry);
69    let limit_bytes = if g == 0 {
70        // 1-byte granularity
71        limit
72    } else {
73        // 4096-byte granularity
74        (limit * 4096) + 4095
75    };
76
77    Segment {
78        base: get_base(entry),
79        limit_bytes,
80        selector: (table_index * 8) as u16,
81        type_: get_type(entry),
82        present: get_p(entry),
83        dpl: get_dpl(entry),
84        db: get_db(entry),
85        s: get_s(entry),
86        l: get_l(entry),
87        g,
88        avl: get_avl(entry),
89    }
90}
91
92#[cfg(test)]
93mod test {
94    use super::*;
95
96    #[test]
97    fn field_parse() {
98        let gdt = gdt_entry(0xA09B, 0x100000, 0xfffff);
99        let seg = segment_from_gdt(gdt, 0);
100        // 0xA09B
101        // 'A'
102        assert_eq!(0x1, seg.g);
103        assert_eq!(0x0, seg.db);
104        assert_eq!(0x1, seg.l);
105        assert_eq!(0x0, seg.avl);
106        // '9'
107        assert_eq!(0x1, seg.present);
108        assert_eq!(0x0, seg.dpl);
109        assert_eq!(0x1, seg.s);
110        // 'B'
111        assert_eq!(0xB, seg.type_);
112        // base and limit
113        assert_eq!(0x100000, seg.base);
114        assert_eq!(0xffffffff, seg.limit_bytes);
115    }
116}