<commit_before>use std::fmt::{Display, Formatter, Result};
use std::result::Result as StdResult;
use std::rc::Rc;

use vec_map::VecMap;

use Arg;
use args::{AnyArg, DispOrder};
use args::settings::{ArgFlags, ArgSettings};

#[allow(missing_debug_implementations)]
#[doc(hidden)]
pub struct PosBuilder<'n, 'e> {
    pub name: &'n str,
    pub help: Option<&'e str>,
    pub requires: Option<Vec<&'e str>>,
    pub blacklist: Option<Vec<&'e str>>,
    pub possible_vals: Option<Vec<&'e str>>,
    pub index: u64,
    pub num_vals: Option<u64>,
    pub max_vals: Option<u64>,
    pub min_vals: Option<u64>,
    pub val_names: Option<VecMap<&'e str>>,
    pub validator: Option<Rc<Fn(String) -> StdResult<(), String>>>,
    pub overrides: Option<Vec<&'e str>>,
    pub settings: ArgFlags,
    pub val_delim: Option<char>,
    pub default_val: Option<&'n str>,
    pub disp_ord: usize,
    pub r_unless: Option<Vec<&'e str>>,
}

impl<'n, 'e> Default for PosBuilder<'n, 'e> {
    fn default() -> Self {
        PosBuilder {
            name: "",
            help: None,
            requires: None,
            blacklist: None,
            possible_vals: None,
            index: 0,
            num_vals: None,
            min_vals: None,
            max_vals: None,
            val_names: None,
            validator: None,
            overrides: None,
            settings: ArgFlags::new(),
            val_delim: Some(','),
            default_val: None,
            disp_ord: 999,
            r_unless: None,
        }
    }
}

impl<'n, 'e> PosBuilder<'n, 'e> {
    pub fn new(name: &'n str, idx: u64) -> Self {
        PosBuilder {
            name: name,
            index: idx,
            ..Default::default()
        }
    }

    pub fn from_arg(a: &Arg<'n, 'e>, idx: u64, reqs: &mut Vec<&'e str>) -> Self {
        debug_assert!(a.short.is_none() || a.long.is_none(),
                      format!("Argument \"{}\" has conflicting requirements, both index() and \
                      short(), or long(), were supplied",
                              a.name));

        // Create the Positional Argument Builder with each HashSet = None to only
        // allocate
        // those that require it
        let mut pb = PosBuilder {
            name: a.name,
            index: idx,
            num_vals: a.num_vals,
            min_vals: a.min_vals,
            max_vals: a.max_vals,
            val_names: a.val_names.clone(),
            blacklist: a.blacklist.clone(),
            overrides: a.overrides.clone(),
            requires: a.requires.clone(),
            possible_vals: a.possible_vals.clone(),
            help: a.help,
            val_delim: a.val_delim,
            settings: a.settings,
            default_val: a.default_val,
            disp_ord: a.disp_ord,
            r_unless: a.r_unless.clone(),
            ..Default::default()
        };
        if a.max_vals.is_some() || a.min_vals.is_some() ||
           (a.num_vals.is_some() && a.num_vals.unwrap() > 1) {
            pb.settings.set(ArgSettings::Multiple);
        }
        if let Some(ref p) = a.validator {
            pb.validator = Some(p.clone());
        }
        // If the arg is required, add all it's requirements to master required list
        if a.is_set(ArgSettings::Required) {
            if let Some(ref areqs) = a.requires {
                for r in areqs {
                    reqs.push(*r);
                }
            }
        }
        pb
    }
}

impl<'n, 'e> Display for PosBuilder<'n, 'e> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        if self.settings.is_set(ArgSettings::Required) {
            if let Some(ref names) = self.val_names {
                try!(write!(f,
                            "{}",
                            names.values()
                                 .map(|n| format!("<{}>", n))
                                 .collect::<Vec<_>>()
                                 .join(" ")));
            } else {
                try!(write!(f, "<{}>", self.name));
            }
        } else {
            if let Some(ref names) = self.val_names {
                try!(write!(f,
                            "{}",
                            names.values()
                                 .map(|n| format!("[{}]", n))
                                 .collect::<Vec<_>>()
                                 .join(" ")));
            } else {
                try!(write!(f, "[{}]", self.name));
            }
        }
        if self.settings.is_set(ArgSettings::Multiple) && self.val_names.is_none() {
            try!(write!(f, "..."));
        }

        Ok(())
    }
}

impl<'n, 'e> Clone for PosBuilder<'n, 'e> {
    fn clone(&self) -> Self {
        PosBuilder {
            name: self.name,
            help: self.help,
            blacklist: self.blacklist.clone(),
            overrides: self.overrides.clone(),
            requires: self.requires.clone(),
            settings: self.settings,
            disp_ord: self.disp_ord,
            num_vals: self.num_vals,
            min_vals: self.min_vals,
            max_vals: self.max_vals,
            val_names: self.val_names.clone(),
            val_delim: self.val_delim,
            possible_vals: self.possible_vals.clone(),
            default_val: self.default_val,
            validator: self.validator.clone(),
            r_unless: self.r_unless.clone(),
            index: self.index,
        }
    }
}

impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
    fn name(&self) -> &'n str {
        self.name
    }
    fn overrides(&self) -> Option<&[&'e str]> {
        self.overrides.as_ref().map(|o| &o[..])
    }
    fn requires(&self) -> Option<&[&'e str]> {
        self.requires.as_ref().map(|o| &o[..])
    }
    fn blacklist(&self) -> Option<&[&'e str]> {
        self.blacklist.as_ref().map(|o| &o[..])
    }
    fn required_unless(&self) -> Option<&[&'e str]> {
        self.r_unless.as_ref().map(|o| &o[..])
    }
    fn val_names(&self) -> Option<&VecMap<&'e str>> {
        self.val_names.as_ref()
    }
    fn is_set(&self, s: ArgSettings) -> bool {
        self.settings.is_set(s)
    }
    fn set(&mut self, s: ArgSettings) {
        self.settings.set(s)
    }
    fn has_switch(&self) -> bool {
        false
    }
    fn max_vals(&self) -> Option<u64> {
        self.max_vals
    }
    fn num_vals(&self) -> Option<u64> {
        self.num_vals
    }
    fn possible_vals(&self) -> Option<&[&'e str]> {
        self.possible_vals.as_ref().map(|o| &o[..])
    }
    fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
        self.validator.as_ref()
    }
    fn min_vals(&self) -> Option<u64> {
        self.min_vals
    }
    fn short(&self) -> Option<char> {
        None
    }
    fn long(&self) -> Option<&'e str> {
        None
    }
    fn val_delim(&self) -> Option<char> {
        self.val_delim
    }
    fn takes_value(&self) -> bool {
        true
    }
    fn help(&self) -> Option<&'e str> {
        self.help
    }
    fn default_val(&self) -> Option<&'n str> {
        self.default_val
    }
    fn longest_filter(&self) -> bool {
        true
    }
}

impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> {
    fn disp_ord(&self) -> usize {
        self.disp_ord
    }
}

#[cfg(test)]
mod test {
    use super::PosBuilder;
    use args::settings::ArgSettings;
    use vec_map::VecMap;

    #[test]
    fn display_mult() {
        let mut p = PosBuilder::new("pos", 1);
        p.settings.set(ArgSettings::Multiple);

        assert_eq!(&*format!("{}", p), "[pos]...");
    }

    #[test]
    fn display_required() {
        let mut p2 = PosBuilder::new("pos", 1);
        p2.settings.set(ArgSettings::Required);

        assert_eq!(&*format!("{}", p2), "<pos>");
    }

    #[test]
    fn display_val_names() {
        let mut p2 = PosBuilder::new("pos", 1);
        let mut vm = VecMap::new();
        vm.insert(0, "file1");
        vm.insert(1, "file2");
        p2.val_names = Some(vm);

        assert_eq!(&*format!("{}", p2), "[file1] [file2]");
    }

    #[test]
    fn display_val_names_req() {
        let mut p2 = PosBuilder::new("pos", 1);
        p2.settings.set(ArgSettings::Required);
        let mut vm = VecMap::new();
        vm.insert(0, "file1");
        vm.insert(1, "file2");
        p2.val_names = Some(vm);

        assert_eq!(&*format!("{}", p2), "<file1> <file2>");
    }
}
<commit_msg>imp(Help): moves positionals to standard <> formatting<commit_after>use std::fmt::{Display, Formatter, Result};
use std::result::Result as StdResult;
use std::rc::Rc;

use vec_map::VecMap;

use Arg;
use args::{AnyArg, DispOrder};
use args::settings::{ArgFlags, ArgSettings};

#[allow(missing_debug_implementations)]
#[doc(hidden)]
pub struct PosBuilder<'n, 'e> {
    pub name: &'n str,
    pub help: Option<&'e str>,
    pub requires: Option<Vec<&'e str>>,
    pub blacklist: Option<Vec<&'e str>>,
    pub possible_vals: Option<Vec<&'e str>>,
    pub index: u64,
    pub num_vals: Option<u64>,
    pub max_vals: Option<u64>,
    pub min_vals: Option<u64>,
    pub val_names: Option<VecMap<&'e str>>,
    pub validator: Option<Rc<Fn(String) -> StdResult<(), String>>>,
    pub overrides: Option<Vec<&'e str>>,
    pub settings: ArgFlags,
    pub val_delim: Option<char>,
    pub default_val: Option<&'n str>,
    pub disp_ord: usize,
    pub r_unless: Option<Vec<&'e str>>,
}

impl<'n, 'e> Default for PosBuilder<'n, 'e> {
    fn default() -> Self {
        PosBuilder {
            name: "",
            help: None,
            requires: None,
            blacklist: None,
            possible_vals: None,
            index: 0,
            num_vals: None,
            min_vals: None,
            max_vals: None,
            val_names: None,
            validator: None,
            overrides: None,
            settings: ArgFlags::new(),
            val_delim: Some(','),
            default_val: None,
            disp_ord: 999,
            r_unless: None,
        }
    }
}

impl<'n, 'e> PosBuilder<'n, 'e> {
    pub fn new(name: &'n str, idx: u64) -> Self {
        PosBuilder {
            name: name,
            index: idx,
            ..Default::default()
        }
    }

    pub fn from_arg(a: &Arg<'n, 'e>, idx: u64, reqs: &mut Vec<&'e str>) -> Self {
        debug_assert!(a.short.is_none() || a.long.is_none(),
                      format!("Argument \"{}\" has conflicting requirements, both index() and \
                      short(), or long(), were supplied",
                              a.name));

        // Create the Positional Argument Builder with each HashSet = None to only
        // allocate
        // those that require it
        let mut pb = PosBuilder {
            name: a.name,
            index: idx,
            num_vals: a.num_vals,
            min_vals: a.min_vals,
            max_vals: a.max_vals,
            val_names: a.val_names.clone(),
            blacklist: a.blacklist.clone(),
            overrides: a.overrides.clone(),
            requires: a.requires.clone(),
            possible_vals: a.possible_vals.clone(),
            help: a.help,
            val_delim: a.val_delim,
            settings: a.settings,
            default_val: a.default_val,
            disp_ord: a.disp_ord,
            r_unless: a.r_unless.clone(),
            ..Default::default()
        };
        if a.max_vals.is_some() || a.min_vals.is_some() ||
           (a.num_vals.is_some() && a.num_vals.unwrap() > 1) {
            pb.settings.set(ArgSettings::Multiple);
        }
        if let Some(ref p) = a.validator {
            pb.validator = Some(p.clone());
        }
        // If the arg is required, add all it's requirements to master required list
        if a.is_set(ArgSettings::Required) {
            if let Some(ref areqs) = a.requires {
                for r in areqs {
                    reqs.push(*r);
                }
            }
        }
        pb
    }
}

impl<'n, 'e> Display for PosBuilder<'n, 'e> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        // if self.settings.is_set(ArgSettings::Required) {
            if let Some(ref names) = self.val_names {
                try!(write!(f,
                            "{}",
                            names.values()
                                 .map(|n| format!("<{}>", n))
                                 .collect::<Vec<_>>()
                                 .join(" ")));
            } else {
                try!(write!(f, "<{}>", self.name));
            }
        // } else {
        //     if let Some(ref names) = self.val_names {
        //         try!(write!(f,
        //                     "{}",
        //                     names.values()
        //                          .map(|n| format!("[{}]", n))
        //                          .collect::<Vec<_>>()
        //                          .join(" ")));
        //     } else {
        //         try!(write!(f, "[{}]", self.name));
        //     }
        // }
        if self.settings.is_set(ArgSettings::Multiple) && self.val_names.is_none() {
            try!(write!(f, "..."));
        }

        Ok(())
    }
}

impl<'n, 'e> Clone for PosBuilder<'n, 'e> {
    fn clone(&self) -> Self {
        PosBuilder {
            name: self.name,
            help: self.help,
            blacklist: self.blacklist.clone(),
            overrides: self.overrides.clone(),
            requires: self.requires.clone(),
            settings: self.settings,
            disp_ord: self.disp_ord,
            num_vals: self.num_vals,
            min_vals: self.min_vals,
            max_vals: self.max_vals,
            val_names: self.val_names.clone(),
            val_delim: self.val_delim,
            possible_vals: self.possible_vals.clone(),
            default_val: self.default_val,
            validator: self.validator.clone(),
            r_unless: self.r_unless.clone(),
            index: self.index,
        }
    }
}

impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
    fn name(&self) -> &'n str {
        self.name
    }
    fn overrides(&self) -> Option<&[&'e str]> {
        self.overrides.as_ref().map(|o| &o[..])
    }
    fn requires(&self) -> Option<&[&'e str]> {
        self.requires.as_ref().map(|o| &o[..])
    }
    fn blacklist(&self) -> Option<&[&'e str]> {
        self.blacklist.as_ref().map(|o| &o[..])
    }
    fn required_unless(&self) -> Option<&[&'e str]> {
        self.r_unless.as_ref().map(|o| &o[..])
    }
    fn val_names(&self) -> Option<&VecMap<&'e str>> {
        self.val_names.as_ref()
    }
    fn is_set(&self, s: ArgSettings) -> bool {
        self.settings.is_set(s)
    }
    fn set(&mut self, s: ArgSettings) {
        self.settings.set(s)
    }
    fn has_switch(&self) -> bool {
        false
    }
    fn max_vals(&self) -> Option<u64> {
        self.max_vals
    }
    fn num_vals(&self) -> Option<u64> {
        self.num_vals
    }
    fn possible_vals(&self) -> Option<&[&'e str]> {
        self.possible_vals.as_ref().map(|o| &o[..])
    }
    fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
        self.validator.as_ref()
    }
    fn min_vals(&self) -> Option<u64> {
        self.min_vals
    }
    fn short(&self) -> Option<char> {
        None
    }
    fn long(&self) -> Option<&'e str> {
        None
    }
    fn val_delim(&self) -> Option<char> {
        self.val_delim
    }
    fn takes_value(&self) -> bool {
        true
    }
    fn help(&self) -> Option<&'e str> {
        self.help
    }
    fn default_val(&self) -> Option<&'n str> {
        self.default_val
    }
    fn longest_filter(&self) -> bool {
        true
    }
}

impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> {
    fn disp_ord(&self) -> usize {
        self.disp_ord
    }
}

#[cfg(test)]
mod test {
    use super::PosBuilder;
    use args::settings::ArgSettings;
    use vec_map::VecMap;

    #[test]
    fn display_mult() {
        let mut p = PosBuilder::new("pos", 1);
        p.settings.set(ArgSettings::Multiple);

        assert_eq!(&*format!("{}", p), "<pos>...");
    }

    #[test]
    fn display_required() {
        let mut p2 = PosBuilder::new("pos", 1);
        p2.settings.set(ArgSettings::Required);

        assert_eq!(&*format!("{}", p2), "<pos>");
    }

    #[test]
    fn display_val_names() {
        let mut p2 = PosBuilder::new("pos", 1);
        let mut vm = VecMap::new();
        vm.insert(0, "file1");
        vm.insert(1, "file2");
        p2.val_names = Some(vm);

        assert_eq!(&*format!("{}", p2), "<file1> <file2>");
    }

    #[test]
    fn display_val_names_req() {
        let mut p2 = PosBuilder::new("pos", 1);
        p2.settings.set(ArgSettings::Required);
        let mut vm = VecMap::new();
        vm.insert(0, "file1");
        vm.insert(1, "file2");
        p2.val_names = Some(vm);

        assert_eq!(&*format!("{}", p2), "<file1> <file2>");
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2022 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use crate::mm::{
    encrypted_mapper::{EncryptedPageTable, MemoryEncryption, PhysOffset},
    Mapper, PageTableFlags, Translator, ENCRYPTED_BIT_POSITION,
};
use lazy_static::lazy_static;
use sev_guest::{
    ghcb::{Ghcb, GhcbProtocol},
    io::{GhcbIoFactory, PortFactoryWrapper},
    msr::{
        change_snp_page_state, get_sev_status, register_ghcb_location, PageAssignment,
        RegisterGhcbGpaRequest, SevStatus, SnpPageStateChangeRequest,
    },
};
use spinning_top::Spinlock;
use x86_64::{
    addr::VirtAddr,
    registers::control::Cr3,
    structures::paging::{
        mapper::PageTableFrameMapping, MappedPageTable, Page, PageSize, PhysFrame, Size2MiB,
        Size4KiB,
    },
};

/// A wrapper to ensure that the GHCB is alone in a 2MiB page.
///
/// We use 2MiB pages during early boot, so we must make sure there are no other kernel data
/// structures located in the page so that we can safely share the page with the hypervisor without
/// leaking other data.
#[derive(Debug)]
#[repr(C, align(2097152))]
struct GhcbAlignmentWrapper {
    ghcb: Ghcb,
}

static_assertions::assert_eq_size!(GhcbAlignmentWrapper, [u8; Size2MiB::SIZE as usize]);

static mut GHCB_WRAPPER: GhcbAlignmentWrapper = GhcbAlignmentWrapper { ghcb: Ghcb::new() };

pub fn get_ghcb_port_factory() -> PortFactoryWrapper {
    PortFactoryWrapper::Ghcb(GhcbIoFactory::new(&GHCB_PROTOCOL))
}

// TODO(#3403): Stop initializing lazily once we have an equivalent to `std::sync::OnceLock`.
lazy_static! {
    static ref GHCB_PROTOCOL: Spinlock<GhcbProtocol<'static, Ghcb>> = {
        let sev_status = get_sev_status().unwrap_or(SevStatus::empty());
        Spinlock::new(init_ghcb_early(sev_status.contains(SevStatus::SNP_ACTIVE)))
    };
}

/// Shares the page containing the GHCB with the hypervisor again.
///
/// This should be called as soon as the kernel memory has been initialised, as that would have
/// caused the page to be marked as encrypted.
pub fn reshare_ghcb<M: Mapper<Size2MiB>>(mapper: &mut M) {
    let ghcb_page = get_ghcb_page();
    // Safety: we only change the encrypted flag, all other flags for the GHCB pages are as they
    // were set during the kernel memory initialisation.
    unsafe {
        match mapper.update_flags(
            ghcb_page,
            PageTableFlags::PRESENT
                | PageTableFlags::WRITABLE
                | PageTableFlags::GLOBAL
                | PageTableFlags::NO_EXECUTE,
        ) {
            Ok(mapper_flush) => mapper_flush.flush(),
            Err(error) => panic!("Couldn't update page table flags for GHCB: {:?}", error),
        };
    }
}

/// Initializes the GHCB and shares it with the hypervisor during early boot.
fn init_ghcb_early(snp_enabled: bool) -> GhcbProtocol<'static, Ghcb> {
    // Safety: This is called only during early boot, so there is only a single execution context.
    let ghcb = unsafe { &mut GHCB_WRAPPER.ghcb };
    ghcb.reset();

    let ghcb_page = get_ghcb_page();
    let mut mapper = get_identity_mapped_encrypted_page_table();
    if snp_enabled {
        // It is OK to crash if we cannot find the physical frame that contains the GHCB.
        let ghcb_frame = PhysFrame::<Size2MiB>::from_start_address(
            mapper
                .translate_virtual(ghcb_page.start_address())
                .expect("Couldn't find the physical address for the GHCB"),
        )
        .expect("The GHCB physical address is not correctly aligned");

        mark_frame_shared_in_rmp(&ghcb_frame);

        let ghcb_location_request =
            RegisterGhcbGpaRequest::new(ghcb_frame.start_address().as_u64() as usize)
                .expect("Invalid address for GHCB location");
        register_ghcb_location(ghcb_location_request)
            .expect("Couldn't register the GHCB address with the hypervisor");
    }

    // Safety: we only remove the encrypted bit as the initial pages created by the stage 0 firmware
    // are only marked as present and writable, and possibly encrypted.
    unsafe {
        match mapper.update_flags(
            ghcb_page,
            PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
        ) {
            Ok(mapper_flush) => mapper_flush.flush(),
            Err(error) => panic!("Couldn't update page table flags for GHCB: {:?}", error),
        };
    }

    GhcbProtocol::new(ghcb, |virt_addr: VirtAddr| {
        mapper.translate_virtual(virt_addr)
    })
}

/// Gets a mapper that understands encrypted pages and assumes an identity mapping.
///
/// This must only be used during early boot when the identity-mapped page tables created by the
/// stage 0 firmware is still active, and only if SEV, SEV-ES or SEV-SNP is active.
fn get_identity_mapped_encrypted_page_table<'a>(
) -> EncryptedPageTable<MappedPageTable<'a, PhysOffset>> {
    // We assume an identity mapping, so the offset is zero.
    let offset = VirtAddr::new(0);
    // We assume that this will only be used if memory encryption is enabled.
    let encryption = MemoryEncryption::Encrypted(ENCRYPTED_BIT_POSITION);
    let offset_mapper = PhysOffset::new(offset, encryption);
    // Find the level 4 page table that is currently in use.
    let (l4_frame, _) = Cr3::read();
    // Safety: we have fetched the address of the currently used PML4 table from CR3, so this is a
    // valid address pointing to a valid page table.
    let pml4 = unsafe { &mut *offset_mapper.frame_to_pointer(l4_frame) };
    EncryptedPageTable::new(pml4, offset, encryption)
}

/// Marks a 2MiB physical frame as shared in the SEV-SNP reverse-map table (RMP).
fn mark_frame_shared_in_rmp(frame: &PhysFrame<Size2MiB>) {
    let raw_address = frame.start_address().as_u64();
    // Since we don't have the GHCB set up already we need to use the MSR protocol to mark every
    // individual 4KiB area in the 2MiB page as shared.
    for i in 0..512 {
        let request = SnpPageStateChangeRequest::new(
            (raw_address + i * Size4KiB::SIZE) as usize,
            PageAssignment::Shared,
        )
        .expect("Invalid page address");
        change_snp_page_state(request).expect("Couldn't change page state");
    }
}

/// Gets the 2MiB memory page that contains the GHCB.
fn get_ghcb_page() -> Page<Size2MiB> {
    // Safety: the reference to a mutable static is safe, as we only use it to calculate a virtual
    // address and don't dereference it.
    let ghcb_pointer = unsafe { &GHCB_WRAPPER as *const GhcbAlignmentWrapper };
    let ghcb_address = VirtAddr::from_ptr(ghcb_pointer);
    Page::<Size2MiB>::from_start_address(ghcb_address)
        .expect("Invalid start address for GHCB page.")
}
<commit_msg>SEV-ES: reshare GHCB using 4K page size, not 2M<commit_after>//
// Copyright 2022 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use crate::mm::{
    encrypted_mapper::{EncryptedPageTable, MemoryEncryption, PhysOffset},
    Mapper, PageTableFlags, Translator, ENCRYPTED_BIT_POSITION,
};
use lazy_static::lazy_static;
use sev_guest::{
    ghcb::{Ghcb, GhcbProtocol},
    io::{GhcbIoFactory, PortFactoryWrapper},
    msr::{
        change_snp_page_state, get_sev_status, register_ghcb_location, PageAssignment,
        RegisterGhcbGpaRequest, SevStatus, SnpPageStateChangeRequest,
    },
};
use spinning_top::Spinlock;
use x86_64::{
    addr::VirtAddr,
    registers::control::Cr3,
    structures::paging::{
        mapper::PageTableFrameMapping, MappedPageTable, Page, PageSize, PhysFrame, Size2MiB,
        Size4KiB,
    },
};

/// A wrapper to ensure that the GHCB is alone in a 2MiB page.
///
/// We use 2MiB pages during early boot, so we must make sure there are no other kernel data
/// structures located in the page so that we can safely share the page with the hypervisor without
/// leaking other data.
#[derive(Debug)]
#[repr(C, align(2097152))]
struct GhcbAlignmentWrapper {
    ghcb: Ghcb,
}

static_assertions::assert_eq_size!(GhcbAlignmentWrapper, [u8; Size2MiB::SIZE as usize]);

static mut GHCB_WRAPPER: GhcbAlignmentWrapper = GhcbAlignmentWrapper { ghcb: Ghcb::new() };

pub fn get_ghcb_port_factory() -> PortFactoryWrapper {
    PortFactoryWrapper::Ghcb(GhcbIoFactory::new(&GHCB_PROTOCOL))
}

// TODO(#3403): Stop initializing lazily once we have an equivalent to `std::sync::OnceLock`.
lazy_static! {
    static ref GHCB_PROTOCOL: Spinlock<GhcbProtocol<'static, Ghcb>> = {
        let sev_status = get_sev_status().unwrap_or(SevStatus::empty());
        Spinlock::new(init_ghcb_early(sev_status.contains(SevStatus::SNP_ACTIVE)))
    };
}

/// Shares the page containing the GHCB with the hypervisor again.
///
/// This should be called as soon as the kernel memory has been initialised, as that would have
/// caused the page to be marked as encrypted.
pub fn reshare_ghcb<M: Mapper<Size4KiB>>(mapper: &mut M) {
    let ghcb_page = get_ghcb_page();
    // Safety: we only change the encrypted flag, all other flags for the GHCB pages are as they
    // were set during the kernel memory initialisation.
    unsafe {
        match mapper.update_flags(
            // Turn the 2M page into a 4K page. This unwrap will not fail, as 2M pages are
            // 4K-aligned by definition.
            Page::from_start_address(ghcb_page.start_address()).unwrap(),
            PageTableFlags::PRESENT
                | PageTableFlags::WRITABLE
                | PageTableFlags::GLOBAL
                | PageTableFlags::NO_EXECUTE,
        ) {
            Ok(mapper_flush) => mapper_flush.flush(),
            Err(error) => panic!("Couldn't update page table flags for GHCB: {:?}", error),
        };
    }
}

/// Initializes the GHCB and shares it with the hypervisor during early boot.
fn init_ghcb_early(snp_enabled: bool) -> GhcbProtocol<'static, Ghcb> {
    // Safety: This is called only during early boot, so there is only a single execution context.
    let ghcb = unsafe { &mut GHCB_WRAPPER.ghcb };
    ghcb.reset();

    let ghcb_page = get_ghcb_page();
    let mut mapper = get_identity_mapped_encrypted_page_table();
    if snp_enabled {
        // It is OK to crash if we cannot find the physical frame that contains the GHCB.
        let ghcb_frame = PhysFrame::<Size2MiB>::from_start_address(
            mapper
                .translate_virtual(ghcb_page.start_address())
                .expect("Couldn't find the physical address for the GHCB"),
        )
        .expect("The GHCB physical address is not correctly aligned");

        mark_frame_shared_in_rmp(&ghcb_frame);

        let ghcb_location_request =
            RegisterGhcbGpaRequest::new(ghcb_frame.start_address().as_u64() as usize)
                .expect("Invalid address for GHCB location");
        register_ghcb_location(ghcb_location_request)
            .expect("Couldn't register the GHCB address with the hypervisor");
    }

    // Safety: we only remove the encrypted bit as the initial pages created by the stage 0 firmware
    // are only marked as present and writable, and possibly encrypted.
    unsafe {
        match mapper.update_flags(
            ghcb_page,
            PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
        ) {
            Ok(mapper_flush) => mapper_flush.flush(),
            Err(error) => panic!("Couldn't update page table flags for GHCB: {:?}", error),
        };
    }

    GhcbProtocol::new(ghcb, |virt_addr: VirtAddr| {
        mapper.translate_virtual(virt_addr)
    })
}

/// Gets a mapper that understands encrypted pages and assumes an identity mapping.
///
/// This must only be used during early boot when the identity-mapped page tables created by the
/// stage 0 firmware is still active, and only if SEV, SEV-ES or SEV-SNP is active.
fn get_identity_mapped_encrypted_page_table<'a>(
) -> EncryptedPageTable<MappedPageTable<'a, PhysOffset>> {
    // We assume an identity mapping, so the offset is zero.
    let offset = VirtAddr::new(0);
    // We assume that this will only be used if memory encryption is enabled.
    let encryption = MemoryEncryption::Encrypted(ENCRYPTED_BIT_POSITION);
    let offset_mapper = PhysOffset::new(offset, encryption);
    // Find the level 4 page table that is currently in use.
    let (l4_frame, _) = Cr3::read();
    // Safety: we have fetched the address of the currently used PML4 table from CR3, so this is a
    // valid address pointing to a valid page table.
    let pml4 = unsafe { &mut *offset_mapper.frame_to_pointer(l4_frame) };
    EncryptedPageTable::new(pml4, offset, encryption)
}

/// Marks a 2MiB physical frame as shared in the SEV-SNP reverse-map table (RMP).
fn mark_frame_shared_in_rmp(frame: &PhysFrame<Size2MiB>) {
    let raw_address = frame.start_address().as_u64();
    // Since we don't have the GHCB set up already we need to use the MSR protocol to mark every
    // individual 4KiB area in the 2MiB page as shared.
    for i in 0..512 {
        let request = SnpPageStateChangeRequest::new(
            (raw_address + i * Size4KiB::SIZE) as usize,
            PageAssignment::Shared,
        )
        .expect("Invalid page address");
        change_snp_page_state(request).expect("Couldn't change page state");
    }
}

/// Gets the 2MiB memory page that contains the GHCB.
fn get_ghcb_page() -> Page<Size2MiB> {
    // Safety: the reference to a mutable static is safe, as we only use it to calculate a virtual
    // address and don't dereference it.
    let ghcb_pointer = unsafe { &GHCB_WRAPPER as *const GhcbAlignmentWrapper };
    let ghcb_address = VirtAddr::from_ptr(ghcb_pointer);
    Page::<Size2MiB>::from_start_address(ghcb_address)
        .expect("Invalid start address for GHCB page.")
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Common functionality for the x86 and x86_64 Interrupt Descriptor Table.

use core::fmt;
use core::fmt::Write;

use super::super::{DTablePtr, DTable};
use io::term::CONSOLE;

use vga::Color;

pub type Handler = unsafe extern "C" fn() -> ();
pub const IDT_ENTRIES: usize = 256;

/// x86 interrupt gate types.
///
/// Bit-and this with the attribute half-byte to produce the
/// `type_attr` field for a `Gate`
#[repr(u8)]
#[derive(Copy,Clone,Debug)]
pub enum GateType { Absent    = 0b0000_0000
                  , Interrupt = 0b1000_1110
                  , Call      = 0b1000_1100
                  , Trap      = 0b1000_1111
                  }

impl fmt::Display for GateType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self { &GateType::Absent    => write!(f, "Absent")
                   , &GateType::Interrupt => write!(f, "Interrupt")
                   , &GateType::Call      => write!(f, "Call")
                   , &GateType::Trap      => write!(f, "Trap")
                   }
    }
}
//
// #[derive(Debug)]
// pub struct ExceptionDescr { pub description: &'static str
//                           , pub mnemonic: &'static str
//                         //   , pub
// }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: &'static [&'static str]
    = &[ "Divide-by-zero Error"
       , "Debug"
       , "Non-maskable Interrupt"
       , "Breakpoint"
       , "Overflow"
       , "Bound Range Exceeded"
       , "Invalid Opcode"
       , "Device Not Available"
       , "Double Fault"
       , "Coprocessor Segment Overrun"
       , "Invalid TSS"
       , "Segment Not Present"
       , "Stack-Segment Fault"
       , "General Protection Fault"
       , "Page Fault"
       , "Reserved"
       , "x87 Floating-Point Exception"
       , "Alignment Check"
       , "Machine Check"
       , "SIMD Floating-Point Exception"
       , "Virtualization Exception"
       ];

pub trait Gate {
    fn from_handler(handler: Handler) -> Self;
    unsafe fn from_raw(handler: *const u8) -> Self;
}

// /// This is the format that `lidt` expects for the pointer to the IDT.
// /// ...apparently.
// #[repr(C, packed)]
// pub struct IdtPtr<I>
// where I: Idt { pub limit: u16
//              , pub base: *const I
//              }
//
// pub trait IdtPtrOps {
//     unsafe fn load(&self);
// }

pub trait InterruptContext {
    type Registers;

    fn err_no(&self) -> u32;
    fn int_id(&self) -> u32;
    fn registers(&self) -> Self::Registers;

    #[inline]
    unsafe fn exception(&self) -> &str {
        EXCEPTIONS[self.int_id() as usize]
    }

}

pub trait Idt: Sized {
    type Ctx: InterruptContext;
    type GateSize: Gate;
    type PtrSize;

    /// Get the IDT pointer struct to pass to `lidt`
    fn get_ptr(&self) -> DTablePtr<Self::PtrSize>;
    //
    // /// This is just a wrapper for prettiness reasons.
    // #[inline]
    // unsafe fn load(&self) {
    //     self.get_ptr()
    //         .load()
    // }

    /// Enable interrupts
    unsafe fn enable_interrupts() { asm!("sti") }
    /// Disable interrupts
    unsafe fn disable_interrupts() { asm!("cli") }

    /// Add a new interrupt gate pointing to the given handler
    fn add_gate(&mut self, idx: usize, handler: Handler);

    unsafe fn handle_cpu_exception(state: &Self::Ctx) -> ! {
        // TODO: we can handle various types of CPU exception differently
        // TODO: make some nice debugging dumps
        write!( CONSOLE.lock()
                       .set_colors(Color::White, Color::Blue)
                       .clear()
              , "CPU EXCEPTION {:#04x}: {}"
              , state.err_no()
              , EXCEPTIONS[state.err_no() as usize]);

        loop { }
    }

    unsafe extern "C" fn handle_interrupt(state: &Self::Ctx);
}
<commit_msg>CPU exception formatter prints lots of debug info now<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Common functionality for the x86 and x86_64 Interrupt Descriptor Table.

use core::fmt;
use core::fmt::Write;

use super::super::{DTablePtr, DTable};
use io::term::CONSOLE;

use vga::Color;

pub type Handler = unsafe extern "C" fn() -> ();
pub const IDT_ENTRIES: usize = 256;

/// x86 interrupt gate types.
///
/// Bit-and this with the attribute half-byte to produce the
/// `type_attr` field for a `Gate`
#[repr(u8)]
#[derive(Copy,Clone,Debug)]
pub enum GateType { Absent    = 0b0000_0000
                  , Interrupt = 0b1000_1110
                  , Call      = 0b1000_1100
                  , Trap      = 0b1000_1111
                  }

impl fmt::Display for GateType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self { &GateType::Absent    => write!(f, "Absent")
                   , &GateType::Interrupt => write!(f, "Interrupt")
                   , &GateType::Call      => write!(f, "Call")
                   , &GateType::Trap      => write!(f, "Trap")
                   }
    }
}

#[derive(Debug)]
pub struct ExceptionInfo { pub name: &'static str
                         , pub mnemonic: &'static str
                         , pub irq_type: &'static str
                         , pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; 20]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

pub trait Gate {
    fn from_handler(handler: Handler) -> Self;
    unsafe fn from_raw(handler: *const u8) -> Self;
}

// /// This is the format that `lidt` expects for the pointer to the IDT.
// /// ...apparently.
// #[repr(C, packed)]
// pub struct IdtPtr<I>
// where I: Idt { pub limit: u16
//              , pub base: *const I
//              }
//
// pub trait IdtPtrOps {
//     unsafe fn load(&self);
// }

pub trait InterruptContext {
    type Registers;

    fn err_no(&self) -> u32;
    fn int_id(&self) -> u32;
    fn registers(&self) -> Self::Registers;

    #[inline]
    fn exception(&self) -> &ExceptionInfo {
        &EXCEPTIONS[self.int_id() as usize]
    }

}

pub trait Idt: Sized {
    type Ctx: InterruptContext;
    type GateSize: Gate;
    type PtrSize;

    /// Get the IDT pointer struct to pass to `lidt`
    fn get_ptr(&self) -> DTablePtr<Self::PtrSize>;
    //
    // /// This is just a wrapper for prettiness reasons.
    // #[inline]
    // unsafe fn load(&self) {
    //     self.get_ptr()
    //         .load()
    // }

    /// Enable interrupts
    unsafe fn enable_interrupts() { asm!("sti") }
    /// Disable interrupts
    unsafe fn disable_interrupts() { asm!("cli") }

    /// Add a new interrupt gate pointing to the given handler
    fn add_gate(&mut self, idx: usize, handler: Handler);

    unsafe fn handle_cpu_exception(state: &Self::Ctx) -> ! {
        // TODO: we can handle various types of CPU exception differently
        // TODO: make some nice debugging dumps
        let ex_info = state.exception();
        write!( CONSOLE.lock()
                       .set_colors(Color::White, Color::Blue)
                       .clear()
              , "CPU EXCEPTION {}: {}\n\
                 {} on vector {} with error code {:#x}\n\
                 Source: {}."
              , ex_info.mnemonic, ex_info.name
              , ex_info.irq_type, state.int_id(), state.err_no()
              , ex_info.source );

        loop { }
    }

    unsafe extern "C" fn handle_interrupt(state: &Self::Ctx);
}
<|endoftext|>


<commit_before>use crate::minimax::{Minimax, MinimaxConfig, MinimaxMovesSorting, MinimaxType};
use env_logger;
use oppai_field::construct_field::construct_field;
use oppai_field::player::Player;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const SEED: [u8; 16] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53];

const MINIMAX_CONFIG_NEGASCOUT: MinimaxConfig = MinimaxConfig {
  threads_count: 1,
  minimax_type: MinimaxType::NegaScout,
  minimax_moves_sorting: MinimaxMovesSorting::TrajectoriesCount,
  hash_table_size: 1_000,
  rebuild_trajectories: false,
};

const MINIMAX_CONFIG_MTDF: MinimaxConfig = MinimaxConfig {
  threads_count: 1,
  minimax_type: MinimaxType::MTDF,
  minimax_moves_sorting: MinimaxMovesSorting::TrajectoriesCount,
  hash_table_size: 1_000,
  rebuild_trajectories: false,
};

#[test]
fn find_best_move() {
  env_logger::try_init().ok();
  // 8 is the minimum depth value to detect correct move in this test.
  // With depth 7 after 3 moves we might have this position:
  // ........
  // .....a..
  // ...a....
  // ..AaAAa.
  // ...Aaa?.
  // ..A.A?..
  // ........
  // ........
  // Question marks here indicate trajectory that will be excluded because
  // it doesn't intersect any other trajectory with length 2.
  // Without this trajectory black player won't be able to find the escape.
  // So red player will think that he wins with move (5, 1).
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ........
    ........
    ...a....
    ..AaA...
    ...Aaa..
    ..A.A...
    ........
    ........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 2)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 2)));
}
<commit_msg>Add tests for minimax.<commit_after>use crate::minimax::{Minimax, MinimaxConfig, MinimaxMovesSorting, MinimaxType};
use env_logger;
use oppai_field::construct_field::construct_field;
use oppai_field::player::Player;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const SEED: [u8; 16] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53];

const MINIMAX_CONFIG_NEGASCOUT: MinimaxConfig = MinimaxConfig {
  threads_count: 1,
  minimax_type: MinimaxType::NegaScout,
  minimax_moves_sorting: MinimaxMovesSorting::TrajectoriesCount,
  hash_table_size: 10_000,
  rebuild_trajectories: false,
};

const MINIMAX_CONFIG_MTDF: MinimaxConfig = MinimaxConfig {
  threads_count: 1,
  minimax_type: MinimaxType::MTDF,
  minimax_moves_sorting: MinimaxMovesSorting::TrajectoriesCount,
  hash_table_size: 10_000,
  rebuild_trajectories: false,
};

#[test]
fn find_best_move_1() {
  env_logger::try_init().ok();
  // 8 is the minimum depth value to detect correct move in this test.
  // With depth 7 after 3 moves we might have this position:
  // ........
  // .....a..
  // ...a....
  // ..AaAAa.
  // ...Aaa?.
  // ..A.A?..
  // ........
  // ........
  // Question marks here indicate trajectory that will be excluded because
  // it doesn't intersect any other trajectory with length 2.
  // Without this trajectory black player won't be able to find the escape.
  // So red player will think that he wins with move (5, 1).
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ........
    ........
    ...a....
    ..AaA...
    ...Aaa..
    ..A.A...
    ........
    ........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 2)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 2)));
}

#[test]
fn find_best_move_2() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ........
    ........
    ...a.a..
    ...AAa..
    ...aAa..
    ....Aa..
    ...aaA..
    ........
    ........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(2, 3)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(2, 3)));
}

#[test]
fn find_best_move_3() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ........
    ........
    ...a....
    ..aA.a..
    ..aAA...
    ..aa....
    ........
    ........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 5)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 5)));
}

#[test]
fn find_best_move_4() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    .........
    ....a....
    .........
    ...Aa.A..
    ..A...A..
    ..AaaaA..
    ...AAAa..
    ......a..
    .........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
}

#[test]
fn find_best_move_5() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ...........
    ....aaa....
    ..AAa.A.A..
    .A.aAA...A.
    ...a.......
    ...a..a....
    ....aa.....
    ...........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(6, 3)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(6, 3)));
}

#[test]
fn find_best_move_6() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ............
    ............
    ..A.a.......
    ...Aa..aa...
    ...aAaaaAA..
    ...aAAaA....
    ...a.A......
    ............
    ............
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(7, 6)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(7, 6)));
}

#[test]
#[ignore]
fn find_best_move_7() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ............
    .......aa...
    .a...AaA.a..
    ..a.A.A.Aa..
    ..a..A.A.a..
    ...aaaaaa...
    ............
    ............
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 10);
  assert_eq!(pos, Some(field.to_pos(4, 1)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 10);
  assert_eq!(pos, Some(field.to_pos(4, 1)));
}

#[test]
fn find_best_move_8() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ............
    ............
    .......AA...
    .....AAaaa..
    .....Aa.....
    ..A.Aa.a....
    ...Aa.A..a..
    ..Aa.a......
    ..Aa.a..A...
    ...AAAAA....
    ............
    ............
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(6, 7)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(6, 7)));
}

#[test]
#[ignore]
fn find_best_move_9() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ...........
    ...........
    ...aA...a..
    ..aA...a...
    ..aAA.a....
    ..aAAAAa...
    ..aaAaaA...
    ..AAaaAA...
    ....a......
    ...AaA.....
    ....A......
    ...........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 10);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 10);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
}

#[test]
fn find_best_move_10() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ..........
    ..........
    ....aaaA..
    .....AAa..
    ..A..A.a..
    ...A..a...
    ....A.a...
    .....Aa...
    ....Aa.a..
    ....Aa....
    ..........
    ..........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 6)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 6)));
}

#[test]
#[ignore]
fn find_best_move_11() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ...........
    ...........
    ..A........
    ..A........
    ..A...Aaa..
    ...AaaaA...
    ....AAA....
    ...........
    ...........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 12);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 12);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
}

#[test]
fn find_best_move_12() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ...........
    ...........
    ...a..a....
    ...AA.aAA..
    ...a.AAa...
    ...aaAaa...
    ..AAAa.....
    .....a.....
    ...........
    ...........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 3)));
}

#[test]
fn find_best_move_13() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    .........
    .........
    ...AA.A..
    ...Aaa...
    ...Aa.A..
    ..aaAA...
    ....aa...
    .........
    .........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(6, 5)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(6, 5)));
}

#[test]
fn find_best_move_14() {
  env_logger::try_init().ok();
  let mut rng = XorShiftRng::from_seed(SEED);
  let mut field = construct_field(
    &mut rng,
    "
    ..........
    ..........
    ...aa.....
    ..a..a....
    ..a...a...
    ..aAA.Aa..
    ..Aa..Aa..
    .....A.a..
    ...AA..a..
    ......a...
    ..........
    ..........
    ",
  );
  let minimax = Minimax::new(MINIMAX_CONFIG_NEGASCOUT);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(4, 7)));
  let minimax = Minimax::new(MINIMAX_CONFIG_MTDF);
  let pos = minimax.minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(4, 7)));
}
<|endoftext|>


<commit_before>pub type clock_t = c_long;
pub type time_t = c_long;
pub type suseconds_t = c_long;
pub type ino_t = u64;
pub type off_t = i64;
pub type blkcnt_t = i64;

pub type blksize_t = c_long;
pub type fsblkcnt_t = ::c_ulonglong;
pub type fsfilcnt_t = ::c_ulonglong;
pub type rlim_t = ::c_ulonglong;

s! {
    pub struct sigaction {
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        pub sa_flags: ::c_int,
        _restorer: *mut ::c_void,
    }

    pub struct siginfo_t {
        pub si_signo: ::c_int,
        pub si_errno: ::c_int,
        pub si_code: ::c_int,
        pub _pad: [::c_int; 29],
        _align: [usize; 0],
    }

    pub struct ipc_perm {
        pub __ipc_perm_key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::mode_t,
        pub __seq: ::c_int,
        __unused1: ::c_long,
        __unused2: ::c_long
    }

    pub struct termios {
        pub c_iflag: ::tcflag_t,
        pub c_oflag: ::tcflag_t,
        pub c_cflag: ::tcflag_t,
        pub c_lflag: ::tcflag_t,
        pub c_line: ::cc_t,
        pub c_cc: [::cc_t; ::NCCS],
        pub __c_ispeed: ::speed_t,
        pub __c_ospeed: ::speed_t,
    }

    pub struct flock {
        pub l_type: ::c_short,
        pub l_whence: ::c_short,
        pub l_start: ::off_t,
        pub l_len: ::off_t,
        pub l_pid: ::pid_t,
    }

    pub struct sysinfo {
        pub uptime: ::c_ulong,
        pub loads: [::c_ulong; 3],
        pub totalram: ::c_ulong,
        pub freeram: ::c_ulong,
        pub sharedram: ::c_ulong,
        pub bufferram: ::c_ulong,
        pub totalswap: ::c_ulong,
        pub freeswap: ::c_ulong,
        pub procs: ::c_ushort,
        pub pad: ::c_ushort,
        pub totalhigh: ::c_ulong,
        pub freehigh: ::c_ulong,
        pub mem_unit: ::c_uint,
        pub __reserved: [::c_char; 256],
    }
}

pub const BUFSIZ: ::c_uint = 1024;
pub const TMP_MAX: ::c_uint = 10000;
pub const FOPEN_MAX: ::c_uint = 1000;
pub const POSIX_MADV_DONTNEED: ::c_int = 0;
pub const O_ACCMODE: ::c_int = 0o10000003;
pub const O_NDELAY: ::c_int = O_NONBLOCK;
pub const RUSAGE_CHILDREN: ::c_int = 1;
pub const NI_MAXHOST: ::socklen_t = 255;
pub const PTHREAD_STACK_MIN: ::size_t = 2048;

pub const RLIM_INFINITY: ::rlim_t = !0;
pub const RLIMIT_RTTIME: ::c_int = 15;
pub const RLIMIT_NLIMITS: ::c_int = 16;

pub const MAP_ANONYMOUS: ::c_int = MAP_ANON;

pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15;
pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16;
pub const TCP_THIN_DUPACK: ::c_int = 17;
pub const TCP_USER_TIMEOUT: ::c_int = 18;
pub const TCP_REPAIR: ::c_int = 19;
pub const TCP_REPAIR_QUEUE: ::c_int = 20;
pub const TCP_QUEUE_SEQ: ::c_int = 21;
pub const TCP_REPAIR_OPTIONS: ::c_int = 22;
pub const TCP_FASTOPEN: ::c_int = 23;
pub const TCP_TIMESTAMP: ::c_int = 24;

pub const SIGUNUSED: ::c_int = ::SIGSYS;

pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01;
pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02;

pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4;
pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4;

pub const CPU_SETSIZE: ::c_int = 128;

pub const QFMT_VFS_V1: ::c_int = 4;

pub const PTRACE_TRACEME: ::c_int = 0;
pub const PTRACE_PEEKTEXT: ::c_int = 1;
pub const PTRACE_PEEKDATA: ::c_int = 2;
pub const PTRACE_PEEKUSER: ::c_int = 3;
pub const PTRACE_POKETEXT: ::c_int = 4;
pub const PTRACE_POKEDATA: ::c_int = 5;
pub const PTRACE_POKEUSER: ::c_int = 6;
pub const PTRACE_CONT: ::c_int = 7;
pub const PTRACE_KILL: ::c_int = 8;
pub const PTRACE_SINGLESTEP: ::c_int = 9;
pub const PTRACE_ATTACH: ::c_int = 16;
pub const PTRACE_DETACH: ::c_int = 17;
pub const PTRACE_SYSCALL: ::c_int = 24;
pub const PTRACE_SETOPTIONS: ::c_int = 0x4200;
pub const PTRACE_GETEVENTMSG: ::c_int = 0x4201;
pub const PTRACE_GETSIGINFO: ::c_int = 0x4202;
pub const PTRACE_SETSIGINFO: ::c_int = 0x4203;
pub const PTRACE_GETREGSET: ::c_int = 0x4204;
pub const PTRACE_SETREGSET: ::c_int = 0x4205;
pub const PTRACE_SEIZE: ::c_int = 0x4206;
pub const PTRACE_INTERRUPT: ::c_int = 0x4207;
pub const PTRACE_LISTEN: ::c_int = 0x4208;
pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209;

pub const MADV_DODUMP: ::c_int = 17;
pub const MADV_DONTDUMP: ::c_int = 16;

pub const EPOLLWAKEUP: ::c_int = 0x20000000;

pub const MADV_HUGEPAGE: ::c_int = 14;
pub const MADV_NOHUGEPAGE: ::c_int = 15;

pub const PTRACE_GETFPREGS: ::c_uint = 14;
pub const PTRACE_SETFPREGS: ::c_uint = 15;
pub const PTRACE_GETFPXREGS: ::c_uint = 18;
pub const PTRACE_SETFPXREGS: ::c_uint = 19;
pub const PTRACE_GETREGS: ::c_uint = 12;
pub const PTRACE_SETREGS: ::c_uint = 13;

pub const EFD_NONBLOCK: ::c_int = ::O_NONBLOCK;

pub const SFD_NONBLOCK: ::c_int = ::O_NONBLOCK;

pub const TCSANOW: ::c_int = 0;
pub const TCSADRAIN: ::c_int = 1;
pub const TCSAFLUSH: ::c_int = 2;

pub const TIOCINQ: ::c_int = ::FIONREAD;

pub const RTLD_GLOBAL: ::c_int = 0x100;
pub const RTLD_NOLOAD: ::c_int = 0x4;

// TODO(#247) Temporarily musl-specific (available since musl 0.9.12 / Linux
// kernel 3.10).  See also notbsd/mod.rs
pub const CLOCK_SGI_CYCLE: ::clockid_t = 10;
pub const CLOCK_TAI: ::clockid_t = 11;

extern {
    pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int;
    pub fn ptrace(request: ::c_int, ...) -> ::c_long;
    pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int;
    pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64"))] {
        mod b64;
        pub use self::b64::*;
    } else if #[cfg(any(target_arch = "x86",
                        target_arch = "mips",
                        target_arch = "arm",
                        target_arch = "asmjs"))] {
        mod b32;
        pub use self::b32::*;
    } else { }
}
<commit_msg>Added Ptrace option parameters<commit_after>pub type clock_t = c_long;
pub type time_t = c_long;
pub type suseconds_t = c_long;
pub type ino_t = u64;
pub type off_t = i64;
pub type blkcnt_t = i64;

pub type blksize_t = c_long;
pub type fsblkcnt_t = ::c_ulonglong;
pub type fsfilcnt_t = ::c_ulonglong;
pub type rlim_t = ::c_ulonglong;

s! {
    pub struct sigaction {
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        pub sa_flags: ::c_int,
        _restorer: *mut ::c_void,
    }

    pub struct siginfo_t {
        pub si_signo: ::c_int,
        pub si_errno: ::c_int,
        pub si_code: ::c_int,
        pub _pad: [::c_int; 29],
        _align: [usize; 0],
    }

    pub struct ipc_perm {
        pub __ipc_perm_key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::mode_t,
        pub __seq: ::c_int,
        __unused1: ::c_long,
        __unused2: ::c_long
    }

    pub struct termios {
        pub c_iflag: ::tcflag_t,
        pub c_oflag: ::tcflag_t,
        pub c_cflag: ::tcflag_t,
        pub c_lflag: ::tcflag_t,
        pub c_line: ::cc_t,
        pub c_cc: [::cc_t; ::NCCS],
        pub __c_ispeed: ::speed_t,
        pub __c_ospeed: ::speed_t,
    }

    pub struct flock {
        pub l_type: ::c_short,
        pub l_whence: ::c_short,
        pub l_start: ::off_t,
        pub l_len: ::off_t,
        pub l_pid: ::pid_t,
    }

    pub struct sysinfo {
        pub uptime: ::c_ulong,
        pub loads: [::c_ulong; 3],
        pub totalram: ::c_ulong,
        pub freeram: ::c_ulong,
        pub sharedram: ::c_ulong,
        pub bufferram: ::c_ulong,
        pub totalswap: ::c_ulong,
        pub freeswap: ::c_ulong,
        pub procs: ::c_ushort,
        pub pad: ::c_ushort,
        pub totalhigh: ::c_ulong,
        pub freehigh: ::c_ulong,
        pub mem_unit: ::c_uint,
        pub __reserved: [::c_char; 256],
    }
}

pub const BUFSIZ: ::c_uint = 1024;
pub const TMP_MAX: ::c_uint = 10000;
pub const FOPEN_MAX: ::c_uint = 1000;
pub const POSIX_MADV_DONTNEED: ::c_int = 0;
pub const O_ACCMODE: ::c_int = 0o10000003;
pub const O_NDELAY: ::c_int = O_NONBLOCK;
pub const RUSAGE_CHILDREN: ::c_int = 1;
pub const NI_MAXHOST: ::socklen_t = 255;
pub const PTHREAD_STACK_MIN: ::size_t = 2048;

pub const RLIM_INFINITY: ::rlim_t = !0;
pub const RLIMIT_RTTIME: ::c_int = 15;
pub const RLIMIT_NLIMITS: ::c_int = 16;

pub const MAP_ANONYMOUS: ::c_int = MAP_ANON;

pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15;
pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16;
pub const TCP_THIN_DUPACK: ::c_int = 17;
pub const TCP_USER_TIMEOUT: ::c_int = 18;
pub const TCP_REPAIR: ::c_int = 19;
pub const TCP_REPAIR_QUEUE: ::c_int = 20;
pub const TCP_QUEUE_SEQ: ::c_int = 21;
pub const TCP_REPAIR_OPTIONS: ::c_int = 22;
pub const TCP_FASTOPEN: ::c_int = 23;
pub const TCP_TIMESTAMP: ::c_int = 24;

pub const SIGUNUSED: ::c_int = ::SIGSYS;

pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01;
pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02;

pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4;
pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4;

pub const CPU_SETSIZE: ::c_int = 128;

pub const QFMT_VFS_V1: ::c_int = 4;

pub const PTRACE_TRACEME: ::c_int = 0;
pub const PTRACE_PEEKTEXT: ::c_int = 1;
pub const PTRACE_PEEKDATA: ::c_int = 2;
pub const PTRACE_PEEKUSER: ::c_int = 3;
pub const PTRACE_POKETEXT: ::c_int = 4;
pub const PTRACE_POKEDATA: ::c_int = 5;
pub const PTRACE_POKEUSER: ::c_int = 6;
pub const PTRACE_CONT: ::c_int = 7;
pub const PTRACE_KILL: ::c_int = 8;
pub const PTRACE_SINGLESTEP: ::c_int = 9;
pub const PTRACE_ATTACH: ::c_int = 16;
pub const PTRACE_DETACH: ::c_int = 17;
pub const PTRACE_SYSCALL: ::c_int = 24;
pub const PTRACE_SETOPTIONS: ::c_int = 0x4200;
pub const PTRACE_GETEVENTMSG: ::c_int = 0x4201;
pub const PTRACE_GETSIGINFO: ::c_int = 0x4202;
pub const PTRACE_SETSIGINFO: ::c_int = 0x4203;
pub const PTRACE_GETREGSET: ::c_int = 0x4204;
pub const PTRACE_SETREGSET: ::c_int = 0x4205;
pub const PTRACE_SEIZE: ::c_int = 0x4206;
pub const PTRACE_INTERRUPT: ::c_int = 0x4207;
pub const PTRACE_LISTEN: ::c_int = 0x4208;
pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209;

pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209;
pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209;
pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209;

pub const PTRACE_O_EXITKILL: ::c_int = 1048576;
pub const PTRACE_O_TRACECLONE: ::c_int = 8;
pub const PTRACE_O_TRACEEXEC: ::c_int = 16;
pub const PTRACE_O_TRACEEXIT: ::c_int = 64;
pub const PTRACE_O_TRACEFORK: ::c_int = 2;
pub const PTRACE_O_TRACESYSGOOD: ::c_int = 1;
pub const PTRACE_O_TRACEVFORK: ::c_int = 4;
pub const PTRACE_O_TRACEVFORKDONE: ::c_int = 32;
pub const PTRACE_O_SUSPEND_SECCOMP: ::c_int = 2097152;

pub const MADV_DODUMP: ::c_int = 17;
pub const MADV_DONTDUMP: ::c_int = 16;

pub const EPOLLWAKEUP: ::c_int = 0x20000000;

pub const MADV_HUGEPAGE: ::c_int = 14;
pub const MADV_NOHUGEPAGE: ::c_int = 15;

pub const PTRACE_GETFPREGS: ::c_uint = 14;
pub const PTRACE_SETFPREGS: ::c_uint = 15;
pub const PTRACE_GETFPXREGS: ::c_uint = 18;
pub const PTRACE_SETFPXREGS: ::c_uint = 19;
pub const PTRACE_GETREGS: ::c_uint = 12;
pub const PTRACE_SETREGS: ::c_uint = 13;

pub const EFD_NONBLOCK: ::c_int = ::O_NONBLOCK;

pub const SFD_NONBLOCK: ::c_int = ::O_NONBLOCK;

pub const TCSANOW: ::c_int = 0;
pub const TCSADRAIN: ::c_int = 1;
pub const TCSAFLUSH: ::c_int = 2;

pub const TIOCINQ: ::c_int = ::FIONREAD;

pub const RTLD_GLOBAL: ::c_int = 0x100;
pub const RTLD_NOLOAD: ::c_int = 0x4;

// TODO(#247) Temporarily musl-specific (available since musl 0.9.12 / Linux
// kernel 3.10).  See also notbsd/mod.rs
pub const CLOCK_SGI_CYCLE: ::clockid_t = 10;
pub const CLOCK_TAI: ::clockid_t = 11;

extern {
    pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int;
    pub fn ptrace(request: ::c_int, ...) -> ::c_long;
    pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int;
    pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64"))] {
        mod b64;
        pub use self::b64::*;
    } else if #[cfg(any(target_arch = "x86",
                        target_arch = "mips",
                        target_arch = "arm",
                        target_arch = "asmjs"))] {
        mod b32;
        pub use self::b32::*;
    } else { }
}
<|endoftext|>


<commit_before>// spell-checker:ignore (URL) appspot

use crate::numeric::*;

pub(crate) trait Basis {
    const BASIS: &'static [u64];
}

impl Basis for Montgomery<u64> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 64b integers;
    //  discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
}

impl Basis for Montgomery<u32> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
    //  discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[
        4230279247111683200,
        14694767155120705706,
        16641139526367750375,
    ];
}

#[derive(Eq, PartialEq)]
pub(crate) enum Result {
    Prime,
    Pseudoprime,
    Composite(u64),
}

impl Result {
    pub(crate) fn is_prime(&self) -> bool {
        *self == Result::Prime
    }
}

// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
// (some) dividers; it will fail to factor strong pseudoprimes.
#[allow(clippy::many_single_char_names)]
pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
    use self::Result::*;

    let n = m.modulus();
    if n < 2 {
        return Pseudoprime;
    }
    if n % 2 == 0 {
        return if n == 2 { Prime } else { Composite(2) };
    }

    // n-1 = r 2ⁱ
    let i = (n - 1).trailing_zeros();
    let r = (n - 1) >> i;

    let one = m.one();
    let minus_one = m.minus_one();

    for _a in A::BASIS.iter() {
        let _a = _a % n;
        if _a == 0 {
            break;
        }

        let a = m.from_u64(_a);

        // x = a^r mod n
        let mut x = m.pow(a, r);

        {
            // y = ((x²)²...)² i times = x ^ (2ⁱ) = a ^ (r 2ⁱ) = x ^ (n - 1)
            let mut y = x;
            for _ in 0..i {
                y = m.mul(y, y)
            }
            if y != one {
                return Pseudoprime;
            };
        }

        if x == one || x == minus_one {
            continue;
        }

        loop {
            let y = m.mul(x, x);
            if y == one {
                return Composite(gcd(m.to_u64(x) - 1, m.modulus()));
            }
            if y == minus_one {
                // This basis element is not a witness of `n` being composite.
                // Keep looking.
                break;
            }
            x = y;
        }
    }

    Prime
}

// Used by build.rs' tests and debug assertions
#[allow(dead_code)]
pub(crate) fn is_prime(n: u64) -> bool {
    if n % 2 == 0 {
        n == 2
    } else {
        test::<Montgomery<u64>>(Montgomery::new(n)).is_prime()
    }
}

#[cfg(test)]
mod tests {
    use super::is_prime;
    const LARGEST_U64_PRIME: u64 = 0xFFFFFFFFFFFFFFC5;

    #[test]
    fn largest_prime() {
        assert!(is_prime(LARGEST_U64_PRIME));
    }

    #[test]
    fn largest_composites() {
        for i in LARGEST_U64_PRIME + 1..=u64::MAX {
            assert!(!is_prime(i), "2⁶⁴ - {} reported prime", u64::MAX - i + 1);
        }
    }

    #[test]
    fn first_primes() {
        use crate::table::{NEXT_PRIME, P_INVS_U64};
        for (p, _, _) in P_INVS_U64.iter() {
            assert!(is_prime(*p), "{} reported composite", p);
        }
        assert!(is_prime(NEXT_PRIME));
    }

    #[test]
    fn issue_1556() {
        // 10 425 511 = 2441 × 4271
        assert!(!is_prime(10_425_511));
    }

    #[test]
    fn small_composites() {
        use crate::table::P_INVS_U64;

        for i in 0..P_INVS_U64.len() {
            let (p, _, _) = P_INVS_U64[i];
            for (q, _, _) in &P_INVS_U64[0..i] {
                let n = p * q;
                assert!(!is_prime(n), "{} = {} × {} reported prime", n, p, q);
            }
        }
    }
}
<commit_msg>factor::miller_rabin::tests: Refactor<commit_after>// spell-checker:ignore (URL) appspot

use crate::numeric::*;

pub(crate) trait Basis {
    const BASIS: &'static [u64];
}

impl Basis for Montgomery<u64> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 64b integers;
    //  discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
}

impl Basis for Montgomery<u32> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
    //  discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[
        4230279247111683200,
        14694767155120705706,
        16641139526367750375,
    ];
}

#[derive(Eq, PartialEq)]
pub(crate) enum Result {
    Prime,
    Pseudoprime,
    Composite(u64),
}

impl Result {
    pub(crate) fn is_prime(&self) -> bool {
        *self == Result::Prime
    }
}

// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
// (some) dividers; it will fail to factor strong pseudoprimes.
#[allow(clippy::many_single_char_names)]
pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
    use self::Result::*;

    let n = m.modulus();
    if n < 2 {
        return Pseudoprime;
    }
    if n % 2 == 0 {
        return if n == 2 { Prime } else { Composite(2) };
    }

    // n-1 = r 2ⁱ
    let i = (n - 1).trailing_zeros();
    let r = (n - 1) >> i;

    let one = m.one();
    let minus_one = m.minus_one();

    for _a in A::BASIS.iter() {
        let _a = _a % n;
        if _a == 0 {
            break;
        }

        let a = m.from_u64(_a);

        // x = a^r mod n
        let mut x = m.pow(a, r);

        {
            // y = ((x²)²...)² i times = x ^ (2ⁱ) = a ^ (r 2ⁱ) = x ^ (n - 1)
            let mut y = x;
            for _ in 0..i {
                y = m.mul(y, y)
            }
            if y != one {
                return Pseudoprime;
            };
        }

        if x == one || x == minus_one {
            continue;
        }

        loop {
            let y = m.mul(x, x);
            if y == one {
                return Composite(gcd(m.to_u64(x) - 1, m.modulus()));
            }
            if y == minus_one {
                // This basis element is not a witness of `n` being composite.
                // Keep looking.
                break;
            }
            x = y;
        }
    }

    Prime
}

// Used by build.rs' tests and debug assertions
#[allow(dead_code)]
pub(crate) fn is_prime(n: u64) -> bool {
    if n % 2 == 0 {
        n == 2
    } else {
        test::<Montgomery<u64>>(Montgomery::new(n)).is_prime()
    }
}

#[cfg(test)]
mod tests {
    use super::is_prime;
    const LARGEST_U64_PRIME: u64 = 0xFFFFFFFFFFFFFFC5;

    fn primes() -> impl Iterator<Item = u64> {
        use crate::table::{NEXT_PRIME, P_INVS_U64};
        use std::iter::once;
        once(2)
            .chain(P_INVS_U64.iter().map(|(p, _, _)| *p))
            .chain(once(NEXT_PRIME))
    }

    #[test]
    fn largest_prime() {
        assert!(is_prime(LARGEST_U64_PRIME));
    }

    #[test]
    fn largest_composites() {
        for i in LARGEST_U64_PRIME + 1..=u64::MAX {
            assert!(!is_prime(i), "2⁶⁴ - {} reported prime", u64::MAX - i + 1);
        }
    }

    #[test]
    fn first_primes() {
        for p in primes() {
            assert!(is_prime(p), "{} reported composite", p);
        }
    }

    #[test]
    fn issue_1556() {
        // 10 425 511 = 2441 × 4271
        assert!(!is_prime(10_425_511));
    }

    #[test]
    fn small_composites() {
        for p in primes() {
            for q in primes().take_while(|q| *q <= p) {
                let n = p * q;
                assert!(!is_prime(n), "{} = {} × {} reported prime", n, p, q);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::parser::{FileHeaderParser, Parser, ParserError};
use storage::file_id::*;

use std::fs::File as FSFile;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: &'static str, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            if kname != n {
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    header  : FileHeaderData,
    data    : String,
    id      : FileID,
}

impl File {

    pub fn new() -> File {
        File {
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_header(h: FileHeaderData) -> File {
        File {
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_data(d: String) -> File {
        File {
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_content(h: FileHeaderData, d: String) -> File {
        File {
            header: h,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        Uuid::new_v4().to_hyphenated_string()
    }
}

<commit_msg>Add getter methods for File object contents<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::parser::{FileHeaderParser, Parser, ParserError};
use storage::file_id::*;

use std::fs::File as FSFile;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: &'static str, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            if kname != n {
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    header  : FileHeaderData,
    data    : String,
    id      : FileID,
}

impl File {

    pub fn new() -> File {
        File {
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_header(h: FileHeaderData) -> File {
        File {
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_data(d: String) -> File {
        File {
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_content(h: FileHeaderData, d: String) -> File {
        File {
            header: h,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header, self.data)
    }

    pub fn id(&self) -> FileID {
        self.id
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        Uuid::new_v4().to_hyphenated_string()
    }
}

<|endoftext|>