blob: 7eb1ff7ae5a8df94ceb90028ad853518d141f7b3 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// For GDT details see arch/x86/include/asm/segment.h
use kvm_sys::kvm_segment;
/// Constructor for a conventional segment GDT (or LDT) entry. Derived from the kernel's segment.h.
pub fn gdt_entry(flags: u16, base: u32, limit: u32) -> u64 {
((((base as u64) & 0xff000000u64) << (56 - 24))
| (((flags as u64) & 0x0000f0ffu64) << 40)
| (((limit as u64) & 0x000f0000u64) << (48 - 16))
| (((base as u64) & 0x00ffffffu64) << 16)
| ((limit as u64) & 0x0000ffffu64))
}
fn get_base(entry: u64) -> u64 {
((((entry) & 0xFF00000000000000) >> 32)
| (((entry) & 0x000000FF00000000) >> 16)
| (((entry) & 0x00000000FFFF0000) >> 16))
}
fn get_limit(entry: u64) -> u32 {
((((entry) & 0x000F000000000000) >> 32) | ((entry) & 0x000000000000FFFF)) as u32
}
fn get_g(entry: u64) -> u8 {
((entry & 0x0080000000000000) >> 55) as u8
}
fn get_db(entry: u64) -> u8 {
((entry & 0x0040000000000000) >> 54) as u8
}
fn get_l(entry: u64) -> u8 {
((entry & 0x0020000000000000) >> 53) as u8
}
fn get_avl(entry: u64) -> u8 {
((entry & 0x0010000000000000) >> 52) as u8
}
fn get_p(entry: u64) -> u8 {
((entry & 0x0000800000000000) >> 47) as u8
}
fn get_dpl(entry: u64) -> u8 {
((entry & 0x0000600000000000) >> 45) as u8
}
fn get_s(entry: u64) -> u8 {
((entry & 0x0000100000000000) >> 44) as u8
}
fn get_type(entry: u64) -> u8 {
((entry & 0x00000F0000000000) >> 40) as u8
}
/// Automatically build the kvm struct for SET_SREGS from the kernel bit fields.
///
/// # Arguments
///
/// * `entry` - The gdt entry.
/// * `table_index` - Index of the entry in the gdt table.
pub fn kvm_segment_from_gdt(entry: u64, table_index: u8) -> kvm_segment {
kvm_segment {
base: get_base(entry),
limit: get_limit(entry),
selector: (table_index * 8) as u16,
type_: get_type(entry),
present: get_p(entry),
dpl: get_dpl(entry),
db: get_db(entry),
s: get_s(entry),
l: get_l(entry),
g: get_g(entry),
avl: get_avl(entry),
padding: 0,
unusable: match get_p(entry) {
0 => 1,
_ => 0,
},
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn field_parse() {
let gdt = gdt_entry(0xA09B, 0x100000, 0xfffff);
let seg = kvm_segment_from_gdt(gdt, 0);
// 0xA09B
// 'A'
assert_eq!(0x1, seg.g);
assert_eq!(0x0, seg.db);
assert_eq!(0x1, seg.l);
assert_eq!(0x0, seg.avl);
// '9'
assert_eq!(0x1, seg.present);
assert_eq!(0x0, seg.dpl);
assert_eq!(0x1, seg.s);
// 'B'
assert_eq!(0xB, seg.type_);
// base and limit
assert_eq!(0x100000, seg.base);
assert_eq!(0xfffff, seg.limit);
assert_eq!(0x0, seg.unusable);
}
}