<commit_before>extern crate gluon_language_server;
extern crate languageserver_types;

extern crate jsonrpc_core;
#[macro_use]
extern crate pretty_assertions;
extern crate serde;
extern crate serde_json;
extern crate url;

mod support;

use std::io::Write;

use url::Url;

use languageserver_types::{CompletionItem, CompletionItemKind, DidChangeTextDocumentParams,
                           Position, Range, TextDocumentContentChangeEvent,
                           TextDocumentIdentifier, TextDocumentPositionParams,
                           VersionedTextDocumentIdentifier};

use gluon_language_server::CompletionData;

fn completion<W: ?Sized>(stdin: &mut W, id: u64, uri: &str, position: Position)
where
    W: Write,
{
    let hover = support::method_call(
        "textDocument/completion",
        id,
        TextDocumentPositionParams {
            text_document: TextDocumentIdentifier {
                uri: support::test_url(uri),
            },
            position: position,
        },
    );

    support::write_message(stdin, hover).unwrap();
}

fn did_change<W: ?Sized>(stdin: &mut W, uri: &str, range: Range, text: &str)
where
    W: Write,
{
    let hover = support::notification(
        "textDocument/didChange",
        DidChangeTextDocumentParams {
            text_document: VersionedTextDocumentIdentifier {
                uri: support::test_url(uri),
                version: 1,
            },
            content_changes: vec![
                TextDocumentContentChangeEvent {
                    range: Some(range),
                    range_length: None,
                    text: text.to_string(),
                },
            ],
        },
    );

    support::write_message(stdin, hover).unwrap();
}

fn resolve<W: ?Sized>(stdin: &mut W, id: u64, item: &CompletionItem)
where
    W: Write,
{
    let hover = support::method_call("completionItem/resolve", id, item);

    support::write_message(stdin, hover).unwrap();
}

fn remove_completion_data(mut completions: Vec<CompletionItem>) -> Vec<CompletionItem> {
    for item in &mut completions {
        item.data.take();
    }
    completions
}

#[test]
fn local_completion() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        let text = r#"
let test = 2
let test1 = ""
te
"#;
        support::did_open(stdin, "test", text);

        completion(
            stdin,
            1,
            "test",
            Position {
                line: 3,
                character: 2,
            },
        )
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "test".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("Int".into()),
                ..CompletionItem::default()
            },
            CompletionItem {
                label: "test1".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("String".into()),
                ..CompletionItem::default()
            },
        ]
    );
}

#[test]
fn prelude_completion() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        support::did_open(stdin, "test", "no");

        completion(
            stdin,
            1,
            "test",
            Position {
                line: 0,
                character: 1,
            },
        )
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "not".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("std.types.Bool -> std.types.Bool".into()),
                ..CompletionItem::default()
            },
        ]
    );
}

#[test]
fn resolve_completion() {
    let completion = CompletionItem {
        label: "test".into(),
        kind: Some(CompletionItemKind::Variable),
        detail: Some("Int".into()),
        data: Some(
            serde_json::to_value(CompletionData {
                text_document_uri: support::test_url("test"),
                position: Position {
                    character: 2,
                    line: 4,
                },
            }).unwrap(),
        ),
        ..CompletionItem::default()
    };
    let actual: CompletionItem = support::send_rpc(|stdin| {
        let text = r#"
/// doc
let test = 2
let test1 = ""
te
"#;
        support::did_open(stdin, "test", text);

        resolve(stdin, 1, &completion);
    });
    assert_eq!(
        actual,
        CompletionItem {
            documentation: Some("doc".to_string()),
            ..completion
        }
    );
}

#[test]
fn url_encoded_path() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        let text = r#"
let r = { abc = 1 }
r.
"#;
        let uri: Url = "file:///C%3A/examples/test.glu".parse().unwrap();
        support::did_open_uri(stdin, uri.clone(), text);

        let hover = support::method_call(
            "textDocument/completion",
            1,
            TextDocumentPositionParams {
                text_document: TextDocumentIdentifier { uri: uri },
                position: Position {
                    line: 3,
                    character: 2,
                },
            },
        );

        support::write_message(stdin, hover).unwrap();
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "abc".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("Int".into()),
                ..CompletionItem::default()
            },
        ]
    );
}

#[test]
fn local_completion_with_update() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        let text = r#"
let test = 2
let test1 = ""
test2
"#;
        support::did_open(stdin, "test", text);

        did_change(
            stdin,
            "test",
            Range {
                start: Position {
                    line: 3,
                    character: 2,
                },
                end: Position {
                    line: 3,
                    character: 5,
                },
            },
            "st1",
        );

        // FIXME Don't rely on sleep to give the change a chance to propagate
        ::std::thread::sleep(::std::time::Duration::from_secs(3));

        completion(
            stdin,
            1,
            "test",
            Position {
                line: 3,
                character: 2,
            },
        )
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "test1".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("String".into()),
                ..CompletionItem::default()
            },
        ]
    );
}
<commit_msg>Increase the sleep time for travis<commit_after>extern crate gluon_language_server;
extern crate languageserver_types;

extern crate jsonrpc_core;
#[macro_use]
extern crate pretty_assertions;
extern crate serde;
extern crate serde_json;
extern crate url;

mod support;

use std::io::Write;

use url::Url;

use languageserver_types::{CompletionItem, CompletionItemKind, DidChangeTextDocumentParams,
                           Position, Range, TextDocumentContentChangeEvent,
                           TextDocumentIdentifier, TextDocumentPositionParams,
                           VersionedTextDocumentIdentifier};

use gluon_language_server::CompletionData;

fn completion<W: ?Sized>(stdin: &mut W, id: u64, uri: &str, position: Position)
where
    W: Write,
{
    let hover = support::method_call(
        "textDocument/completion",
        id,
        TextDocumentPositionParams {
            text_document: TextDocumentIdentifier {
                uri: support::test_url(uri),
            },
            position: position,
        },
    );

    support::write_message(stdin, hover).unwrap();
}

fn did_change<W: ?Sized>(stdin: &mut W, uri: &str, range: Range, text: &str)
where
    W: Write,
{
    let hover = support::notification(
        "textDocument/didChange",
        DidChangeTextDocumentParams {
            text_document: VersionedTextDocumentIdentifier {
                uri: support::test_url(uri),
                version: 1,
            },
            content_changes: vec![
                TextDocumentContentChangeEvent {
                    range: Some(range),
                    range_length: None,
                    text: text.to_string(),
                },
            ],
        },
    );

    support::write_message(stdin, hover).unwrap();
}

fn resolve<W: ?Sized>(stdin: &mut W, id: u64, item: &CompletionItem)
where
    W: Write,
{
    let hover = support::method_call("completionItem/resolve", id, item);

    support::write_message(stdin, hover).unwrap();
}

fn remove_completion_data(mut completions: Vec<CompletionItem>) -> Vec<CompletionItem> {
    for item in &mut completions {
        item.data.take();
    }
    completions
}

#[test]
fn local_completion() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        let text = r#"
let test = 2
let test1 = ""
te
"#;
        support::did_open(stdin, "test", text);

        completion(
            stdin,
            1,
            "test",
            Position {
                line: 3,
                character: 2,
            },
        )
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "test".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("Int".into()),
                ..CompletionItem::default()
            },
            CompletionItem {
                label: "test1".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("String".into()),
                ..CompletionItem::default()
            },
        ]
    );
}

#[test]
fn prelude_completion() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        support::did_open(stdin, "test", "no");

        completion(
            stdin,
            1,
            "test",
            Position {
                line: 0,
                character: 1,
            },
        )
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "not".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("std.types.Bool -> std.types.Bool".into()),
                ..CompletionItem::default()
            },
        ]
    );
}

#[test]
fn resolve_completion() {
    let completion = CompletionItem {
        label: "test".into(),
        kind: Some(CompletionItemKind::Variable),
        detail: Some("Int".into()),
        data: Some(
            serde_json::to_value(CompletionData {
                text_document_uri: support::test_url("test"),
                position: Position {
                    character: 2,
                    line: 4,
                },
            }).unwrap(),
        ),
        ..CompletionItem::default()
    };
    let actual: CompletionItem = support::send_rpc(|stdin| {
        let text = r#"
/// doc
let test = 2
let test1 = ""
te
"#;
        support::did_open(stdin, "test", text);

        resolve(stdin, 1, &completion);
    });
    assert_eq!(
        actual,
        CompletionItem {
            documentation: Some("doc".to_string()),
            ..completion
        }
    );
}

#[test]
fn url_encoded_path() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        let text = r#"
let r = { abc = 1 }
r.
"#;
        let uri: Url = "file:///C%3A/examples/test.glu".parse().unwrap();
        support::did_open_uri(stdin, uri.clone(), text);

        let hover = support::method_call(
            "textDocument/completion",
            1,
            TextDocumentPositionParams {
                text_document: TextDocumentIdentifier { uri: uri },
                position: Position {
                    line: 3,
                    character: 2,
                },
            },
        );

        support::write_message(stdin, hover).unwrap();
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "abc".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("Int".into()),
                ..CompletionItem::default()
            },
        ]
    );
}

#[test]
fn local_completion_with_update() {
    let completions: Vec<CompletionItem> = support::send_rpc(|stdin| {
        let text = r#"
let test = 2
let test1 = ""
test2
"#;
        support::did_open(stdin, "test", text);

        did_change(
            stdin,
            "test",
            Range {
                start: Position {
                    line: 3,
                    character: 2,
                },
                end: Position {
                    line: 3,
                    character: 5,
                },
            },
            "st1",
        );

        // FIXME Don't rely on sleep to give the change a chance to propagate
        ::std::thread::sleep(::std::time::Duration::from_secs(5));

        completion(
            stdin,
            1,
            "test",
            Position {
                line: 3,
                character: 2,
            },
        )
    });
    let completions = remove_completion_data(completions);
    assert_eq!(
        completions,
        vec![
            CompletionItem {
                label: "test1".into(),
                kind: Some(CompletionItemKind::Variable),
                detail: Some("String".into()),
                ..CompletionItem::default()
            },
        ]
    );
}
<|endoftext|>


<commit_before>// Copyright 2019 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.

use super::{INTERRUPT_STATUS_CONFIG_CHANGED, INTERRUPT_STATUS_USED_RING};
use crate::pci::MsixConfig;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use sync::Mutex;
use sys_util::EventFd;

pub struct Interrupt {
    interrupt_status: Arc<AtomicUsize>,
    interrupt_evt: EventFd,
    interrupt_resample_evt: EventFd,
    msix_config: Option<Arc<Mutex<MsixConfig>>>,
}

impl Interrupt {
    pub fn new(
        interrupt_status: Arc<AtomicUsize>,
        interrupt_evt: EventFd,
        interrupt_resample_evt: EventFd,
        msix_config: Option<Arc<Mutex<MsixConfig>>>,
    ) -> Interrupt {
        Interrupt {
            interrupt_status,
            interrupt_evt,
            interrupt_resample_evt,
            msix_config,
        }
    }

    /// Virtqueue Interrupts From The Device
    ///
    /// If MSI-X is enabled in this device, MSI-X interrupt is preferred.
    /// Write to the irqfd to VMM to deliver virtual interrupt to the guest
    pub fn signal_used_queue(&self, vector: u16) {
        // Don't need to set ISR for MSI-X interrupts
        if let Some(msix_config) = &self.msix_config {
            let mut msix_config = msix_config.lock();
            if msix_config.enabled() {
                msix_config.trigger(vector);
                return;
            }
        }

        // Don't need to inject the interrupt if the guest hasn't processed it.
        if self
            .interrupt_status
            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst)
            & INTERRUPT_STATUS_USED_RING as usize
            == 0
        {
            // Set BIT0 in ISR and write to irqfd to inject INTx interrupt
            self.interrupt_status
                .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
            self.interrupt_evt.write(1).unwrap();
        }
    }

    /// Notification of Device Configuration Changes
    /// Set BIT1 in ISR and write to irqfd
    pub fn signal_config_changed(&self) {
        self.interrupt_status
            .fetch_or(INTERRUPT_STATUS_CONFIG_CHANGED as usize, Ordering::SeqCst);
        self.interrupt_evt.write(1).unwrap();
    }

    /// Handle interrupt resampling event
    pub fn interrupt_resample(&self) {
        let _ = self.interrupt_resample_evt.read();
        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
            self.interrupt_evt.write(1).unwrap();
        }
    }

    /// Return the reference of interrupt_resample_evt
    /// To keep the interface clean, this member is private.
    pub fn get_resample_evt(&self) -> &EventFd {
        &self.interrupt_resample_evt
    }
}
<commit_msg>devices: virtio: simplify interrupt status update<commit_after>// Copyright 2019 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.

use super::{INTERRUPT_STATUS_CONFIG_CHANGED, INTERRUPT_STATUS_USED_RING};
use crate::pci::MsixConfig;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use sync::Mutex;
use sys_util::EventFd;

pub struct Interrupt {
    interrupt_status: Arc<AtomicUsize>,
    interrupt_evt: EventFd,
    interrupt_resample_evt: EventFd,
    msix_config: Option<Arc<Mutex<MsixConfig>>>,
}

impl Interrupt {
    pub fn new(
        interrupt_status: Arc<AtomicUsize>,
        interrupt_evt: EventFd,
        interrupt_resample_evt: EventFd,
        msix_config: Option<Arc<Mutex<MsixConfig>>>,
    ) -> Interrupt {
        Interrupt {
            interrupt_status,
            interrupt_evt,
            interrupt_resample_evt,
            msix_config,
        }
    }

    /// Virtqueue Interrupts From The Device
    ///
    /// If MSI-X is enabled in this device, MSI-X interrupt is preferred.
    /// Write to the irqfd to VMM to deliver virtual interrupt to the guest
    pub fn signal_used_queue(&self, vector: u16) {
        // Don't need to set ISR for MSI-X interrupts
        if let Some(msix_config) = &self.msix_config {
            let mut msix_config = msix_config.lock();
            if msix_config.enabled() {
                msix_config.trigger(vector);
                return;
            }
        }

        // Set BIT0 in ISR and inject the interrupt if it was not already pending.
        // Don't need to inject the interrupt if the guest hasn't processed it.
        if self
            .interrupt_status
            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst)
            == 0
        {
            // Write to irqfd to inject INTx interrupt
            self.interrupt_evt.write(1).unwrap();
        }
    }

    /// Notification of Device Configuration Changes
    /// Set BIT1 in ISR and write to irqfd
    pub fn signal_config_changed(&self) {
        self.interrupt_status
            .fetch_or(INTERRUPT_STATUS_CONFIG_CHANGED as usize, Ordering::SeqCst);
        self.interrupt_evt.write(1).unwrap();
    }

    /// Handle interrupt resampling event
    pub fn interrupt_resample(&self) {
        let _ = self.interrupt_resample_evt.read();
        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
            self.interrupt_evt.write(1).unwrap();
        }
    }

    /// Return the reference of interrupt_resample_evt
    /// To keep the interface clean, this member is private.
    pub fn get_resample_evt(&self) -> &EventFd {
        &self.interrupt_resample_evt
    }
}
<|endoftext|>


<commit_before>/**
 * 15.3 Do syntax
 * http://static.rust-lang.org/doc/master/tutorial.html#do-syntax
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
// The do expression makes it easier to call functions that take procedures as arguments.

// A function that takes a procedure as argument:
fn call_it(op: proc(v: int)) {
	    op(10)
}

fn main() {
	// As a caller, if we use a closure to provide the final operator argument, we can write it in a way that has a pleasant, block-like structure.
	call_it(proc(n) {
		    println(n.to_str());
	});

	// This is such a useful pattern that Rust has a special form of function call for these functions.
	do call_it() |n| {
		    println(n.to_str());
	}

}
<commit_msg>tutorial-15_3-do.rs : add each example<commit_after>/**
 * 15.3 Do syntax
 * http://static.rust-lang.org/doc/master/tutorial.html#do-syntax
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
// The do expression makes it easier to call functions that take procedures as arguments.

// A function that takes a procedure as argument:
fn call_it(op: proc(v: int)) {
	op(10)
}

fn each(v: &[int], op: |v: &int|) {
	let mut n = 0;
	while n < v.len() {
		op(&v[n]);
		n += 1;
	}
}

fn main() {
	// As a caller, if we use a closure to provide the final operator argument, we can write it in a way that has a pleasant, block-like structure.
	call_it(proc(n) {
		println(n.to_str());
	});
	each([1, 2, 3], |n: &int| {
		println(n.to_str());
	});

	// This is such a useful pattern that Rust has a special form of function call for these functions.
	do call_it() |n| {
		println(n.to_str());
	}
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

fn char_for_scancode(scancode: u8, shift: bool) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        if shift {
            character = SCANCODES[scancode as usize][1];
        } else {
            character = SCANCODES[scancode as usize][0];
        }
    }
    character
}

static SCANCODES: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<commit_msg>char_for_scancode has been refactored, with SCANCODES modification<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    if scancode >= 58 {
        '\x00'
    }
    let character =
        match layout {
            0 => SCANCODES_EN[scancode as usize],
            1 => SCANCODES_FR[scancode as usize],
        };
    if shift {
        character = characters[1]
    } else {
        character = characters[scancode as usize][0]
    }
}

static SCANCODES: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

use drivers::kb_layouts::layouts;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    /// Default: English
    layout: layouts::Layout,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: layouts::Layout::FRENCH,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: layouts::char_for_scancode(scancode & 0x7F, shift, &self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout =
            match layout {
                0 => layouts::Layout::ENGLISH,
                1 => layouts::Layout::FRENCH,
                _ => layouts::Layout::ENGLISH
            }
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}
<commit_msg>ENGLISH layout (default)<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

use drivers::kb_layouts::layouts;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    /// Default: English
    layout: layouts::Layout,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: layouts::Layout::ENGLISH,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: layouts::char_for_scancode(scancode & 0x7F, shift, &self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout =
            match layout {
                0 => layouts::Layout::ENGLISH,
                1 => layouts::Layout::FRENCH,
                _ => layouts::Layout::ENGLISH
            }
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This crate provides Serde's two derive macros.
//!
//! ```rust
//! # #[macro_use]
//! # extern crate serde_derive;
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html

#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.83")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cyclomatic_complexity,
        enum_variant_names,
        needless_pass_by_value,
        redundant_field_names,
        too_many_arguments,
        trivially_copy_pass_by_ref,
        used_underscore_binding,
    )
)]
// Whitelisted clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cast_possible_truncation,
        doc_markdown,
        enum_glob_use,
        filter_map,
        indexing_slicing,
        items_after_statements,
        match_same_arms,
        similar_names,
        single_match_else,
        stutter,
        unseparated_literal_suffix,
        use_self,
    )
)]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "512"]

#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;

extern crate proc_macro;
extern crate proc_macro2;

mod internals;

use proc_macro::TokenStream;
use syn::DeriveInput;

#[macro_use]
mod bound;
#[macro_use]
mod fragment;

mod de;
mod dummy;
mod pretend;
mod ser;
mod try;

#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    ser::expand_derive_serialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    de::expand_derive_deserialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
    let compile_errors = errors.iter().map(syn::Error::to_compile_error);
    quote!(#(#compile_errors)*)
}
<commit_msg>Update name of stutter lint in serde_derive<commit_after>//! This crate provides Serde's two derive macros.
//!
//! ```rust
//! # #[macro_use]
//! # extern crate serde_derive;
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html

#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.83")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cyclomatic_complexity,
        enum_variant_names,
        needless_pass_by_value,
        redundant_field_names,
        too_many_arguments,
        trivially_copy_pass_by_ref,
        used_underscore_binding,
    )
)]
// Whitelisted clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cast_possible_truncation,
        doc_markdown,
        enum_glob_use,
        filter_map,
        indexing_slicing,
        items_after_statements,
        match_same_arms,
        module_name_repetitions,
        similar_names,
        single_match_else,
        unseparated_literal_suffix,
        use_self,
    )
)]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "512"]

#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;

extern crate proc_macro;
extern crate proc_macro2;

mod internals;

use proc_macro::TokenStream;
use syn::DeriveInput;

#[macro_use]
mod bound;
#[macro_use]
mod fragment;

mod de;
mod dummy;
mod pretend;
mod ser;
mod try;

#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    ser::expand_derive_serialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    de::expand_derive_deserialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
    let compile_errors = errors.iter().map(syn::Error::to_compile_error);
    quote!(#(#compile_errors)*)
}
<|endoftext|>


<commit_before>use il;
use engine::*;
use error::*;
use executor;
use std::collections::BTreeMap;
use std::rc::Rc;
use translator::TranslationMemory;

/// An engine for maintaining a symbolic state, performing operations over that
/// state, and querying that state.
#[derive(Deserialize, Serialize)]
pub struct SymbolicEngine {
    scalars: BTreeMap<String, il::Expression>,
    memory: SymbolicMemory,
    constraints: Vec<il::Expression>,
    #[serde(skip)]
    solver: Rc<Solver>
}

impl SymbolicEngine {
    /// Create a new `SymbolicEngine`
    pub fn new(memory: SymbolicMemory) -> SymbolicEngine {
        SymbolicEngine {
            scalars: BTreeMap::new(),
            memory: memory,
            constraints: Vec::new(),
            solver: Rc::new(Solver::new().unwrap())
        }
    }

    /// Get the `SymbolicMemory` backing this engine.
    pub fn memory(&self) -> &SymbolicMemory {
        &self.memory
    }

    /// Get a mutable reference to the `SymbolicMemory` backing this reference.
    pub fn memory_mut(&mut self) -> &mut SymbolicMemory {
        &mut self.memory
    }

    pub fn constraints(&self) -> &Vec<il::Expression> {
        &self.constraints
    }

    /// Add constraint to this state.
    ///
    /// This constraint must be equal to 0x1:1, or a 1-bit value of 1, for the
    /// state to be satisfiable. This is the result of Falcon IL comparison
    /// expressions.
    ///
    /// It is an error to add a constraint that is unsatisfiable in the engine's
    /// current state.
    pub fn add_constraint(&mut self, mut constraint: il::Expression)
        -> Result<()> {

        constraint = self.symbolize_expression(&constraint)?;
        if all_constants(&constraint) {
            // If we have a constant constraint which is always 0, add a constant
            // constraint which is always 0.
            if executor::constants_expression(&constraint)?.value() != 1 {
                self.constraints.push(il::Expression::cmpeq(
                    il::expr_const(0, 1),
                    il::expr_const(1, 1)
                )?);
            }
        }
        else {
            self.constraints.push(constraint);
        }

        Ok(())
    }

    /// Set a symbolic scalar
    pub fn set_scalar<S>(&mut self, name: S, value: il::Expression)
        where S: Into<String> {
        self.scalars.insert(name.into(), value);
    }

    /// Get the symbolic value of a scalar
    pub fn get_scalar(&self, name: &str) -> Option<&il::Expression> {
        self.scalars.get(name)
    }

    /// Replace scalars in the expression with those in the engine's current
    /// scalar to expression mapping, and if all scalars are currently constant,
    /// evaluate to constant and return that. Otherwise, return expression with
    /// symbolic values
    pub fn symbolize_and_eval(&self, expression: &il::Expression)
        -> Result<il::Expression> {

        let expression = self.symbolize_expression(expression)?;
        if all_constants(&expression) {
            let constant = executor::constants_expression(&expression)?;
            Ok(il::Expression::Constant(constant))
        }
        else {
            Ok(expression)
        }
    }

    /// Forks the state of the symbolic engine. In future iterations, this will
    /// allow for Copy-On-Write optimizations.
    pub fn fork(&self) -> SymbolicEngine {
        SymbolicEngine {
            scalars: self.scalars.clone(),
            memory: self.memory.clone(),
            constraints: self.constraints.clone(),
            solver: self.solver.clone()
        }
    }

    /// Takes a regular IL expression, and replaces scalars with their
    /// expression values using the engine's internal scalar store.
    pub fn symbolize_expression(&self, expression: &il::Expression)
        -> Result<il::Expression> {

        Ok(match *expression {
            il::Expression::Scalar(ref scalar) => {
                if self.scalars.contains_key(scalar.name()) {
                    self.scalars[scalar.name()].clone()
                }
                else {
                    il::Expression::Scalar(scalar.clone())
                }
            }
            il::Expression::Constant(_) => expression.clone(),
            il::Expression::Add(ref lhs, ref rhs) =>
                il::Expression::add(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Sub(ref lhs, ref rhs) =>
                il::Expression::sub(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Mul(ref lhs, ref rhs) =>
                il::Expression::mul(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Divu(ref lhs, ref rhs) =>
                il::Expression::divu(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::Modu(ref lhs, ref rhs) =>
                il::Expression::modu(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::Divs(ref lhs, ref rhs) =>
                il::Expression::divs(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::Mods(ref lhs, ref rhs) =>
                il::Expression::mods(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::And(ref lhs, ref rhs) =>
                il::Expression::and(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Or(ref lhs, ref rhs) =>
                il::Expression::or(self.symbolize_expression(lhs)?,
                                   self.symbolize_expression(rhs)?)?,
            il::Expression::Xor(ref lhs, ref rhs) =>
                il::Expression::xor(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Shl(ref lhs, ref rhs) =>
                il::Expression::shl(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Shr(ref lhs, ref rhs) =>
                il::Expression::shr(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Cmpeq(ref lhs, ref rhs) =>
                il::Expression::cmpeq(self.symbolize_expression(lhs)?,
                                      self.symbolize_expression(rhs)?)?,
            il::Expression::Cmpneq(ref lhs, ref rhs) =>
                il::Expression::cmpneq(self.symbolize_expression(lhs)?,
                                       self.symbolize_expression(rhs)?)?,
            il::Expression::Cmplts(ref lhs, ref rhs) =>
                il::Expression::cmplts(self.symbolize_expression(lhs)?,
                                       self.symbolize_expression(rhs)?)?,
            il::Expression::Cmpltu(ref lhs, ref rhs) =>
                il::Expression::cmpltu(self.symbolize_expression(lhs)?,
                                       self.symbolize_expression(rhs)?)?,
            il::Expression::Zext(bits, ref src) =>
                il::Expression::zext(bits, self.symbolize_expression(src)?)?,
            il::Expression::Sext(bits, ref src) =>
                il::Expression::sext(bits, self.symbolize_expression(src)?)?,
            il::Expression::Trun(bits, ref src) =>
                il::Expression::trun(bits, self.symbolize_expression(src)?)?
        })
    }

    /// Evaluates an expression in the solver. If constraints are given, enforces
    /// these extra constraints.
    pub fn eval(
        &mut self,
        expr: &il::Expression,
        constraints: Option<Vec<il::Expression>>
    ) -> Result<Option<il::Constant>> {

        // Create one vec of constraints
        let constraints = match constraints {
            Some(constraints) => {
                let mut c = Vec::new();
                for constraint in constraints {
                    let constraint = self.symbolize_expression(&constraint)?;
                    if all_constants(&constraint) {
                        if executor::constants_expression(&constraint)?.value() == 0 {
                            return Ok(None)
                        }
                    }
                    else {
                        c.push(constraint);
                    }
                }
                c.append(&mut self.constraints.clone());
                c
            },
            None => self.constraints.clone()
        };

        let expr = self.symbolize_expression(expr)?;

        if all_constants(&expr) {
            return Ok(Some(executor::constants_expression(&expr)?));
        }

        Rc::make_mut(&mut self.solver).solve(&expr, constraints)
    }

    /// Loads a single byte from memory. This byte must have a concrete value.
    pub fn load_only_concrete(&self, address: u64) -> Result<Option<u8>> {
        let byte = self.memory.load(address, 8)?;
        let byte = match byte {
            Some(byte) => byte,
            None => return Ok(None)
        };

        if all_constants(&byte) {
            let value = executor::constants_expression(&byte)?;
            Ok(Some(value.value() as u8))
        }
        else {
            Ok(None)
        }
    }

    /// Gets the value of a scalar, but only if the scalar has a concrete value
    pub fn get_scalar_only_concrete(&self, name: &str) -> Result<Option<il::Constant>> {
        let expr = match self.get_scalar(name) {
            Some(expr) => expr,
            None => bail!("scalar {} does not exist", name)
        };

        if !all_constants(expr) {
            Ok(None)
        }
        else {
            Ok(Some(executor::constants_expression(expr)?))
        }
    }

    /// Determine whether the constraints of this state are satisfiable
    pub fn sat(&mut self, constraints: Option<Vec<il::Expression>>) -> Result<bool> {
        // An expression that will always evaluate to true
        let expression = il::Expression::cmpeq(
            il::expr_const(1, 1),
            il::expr_const(1, 1)
        ).unwrap();
        if self.eval(&expression, constraints)?.is_some() {
            Ok(true)
        }
        else {
            Ok(false)
        }
    }

    /// Execute an IL operation over the engine, updating state.
    pub fn execute(mut self, operation: &il::Operation)
        -> Result<Vec<SymbolicSuccessor>> {

        Ok(match *operation {
            il::Operation::Assign { ref dst, ref src } => {
                let src = self.symbolize_and_eval(src)?;
                self.set_scalar(dst.name(), src);
                vec![SymbolicSuccessor::new(self, SuccessorType::FallThrough)]
            },
            il::Operation::Store { ref index, ref src, .. } => {
                let src = self.symbolize_and_eval(src)?;
                let index = self.eval(index, None)?;
                if let Some(index) = index {
                    self.memory.store(index.value(), src)?;
                    vec![SymbolicSuccessor::new(self, SuccessorType::FallThrough)]
                }
                else {
                    Vec::new()
                }
            },
            il::Operation::Load { ref dst, ref index, .. } => {
                let index_ = self.eval(index, None)?;
                if let Some(index) = index_ {
                    let value = self.memory.load(index.value(), dst.bits())?;
                    match value {
                        Some(v) => {
                            self.scalars.insert(dst.name().to_string(), v.clone());
                            vec![SymbolicSuccessor::new(self, SuccessorType::FallThrough)]
                        },
                        None => {
                            trace!("Got invalid concretized load address 0x{:x}", index.value());
                            Vec::new()
                        }
                    }
                }
                else {
                    trace!("Could not resolve load address {}", index);
                    Vec::new()
                }
            },
            il::Operation::Brc { ref target, ref condition } => {
                let mut successors = Vec::new();
                // Is it possible for this case not to be taken?
                let null_case = il::Expression::cmpeq(condition.clone(), il::expr_const(0, 1))?;
                let r = self.eval(&null_case, Some(vec![null_case.clone()]))?;
                if r.is_some() {
                    let mut engine = self.fork();
                    engine.add_constraint(null_case)?;
                    let successor = SymbolicSuccessor::new(engine, SuccessorType::FallThrough);
                    successors.push(successor);
                }
                // This is the true case
                let r = self.eval(&condition, Some(vec![condition.clone()]))?;
                if r.is_some() {
                    let t = self.eval(target, Some(vec![condition.clone()]))?;
                    if let Some(target) = t {
                        let mut engine = self.fork();
                        engine.add_constraint(condition.clone())?;
                        let successor = SymbolicSuccessor::new(
                            engine,
                            SuccessorType::Branch(target.value())
                        );
                        successors.push(successor);
                    }
                }
                successors
            },
            il::Operation::Phi { .. } => {
                panic!("Phi unimplemented");
            },
            il::Operation::Raise { ref expr } => {
                vec![SymbolicSuccessor::new(
                    self,
                    SuccessorType::Raise(expr.clone())
                )]
            }
        })
    }
}

impl TranslationMemory for SymbolicEngine {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.load_only_concrete(address).unwrap()
    }
}

impl Clone for SymbolicEngine {
    fn clone(&self) -> SymbolicEngine {
        self.fork()
    }
}

/// Return true if an expression is all constants.
///
/// If an expression is all constants, we can evaluate the expression
/// concretely and return its constant value).
pub fn all_constants(expr: &il::Expression) -> bool {
    match *expr {
        il::Expression::Scalar(_) => false,
        il::Expression::Constant(_) => true,
        il::Expression::Add(ref lhs, ref rhs) |
        il::Expression::Sub(ref lhs, ref rhs) |
        il::Expression::Mul(ref lhs, ref rhs) |
        il::Expression::Divu(ref lhs, ref rhs) |
        il::Expression::Modu(ref lhs, ref rhs) |
        il::Expression::Divs(ref lhs, ref rhs) |
        il::Expression::Mods(ref lhs, ref rhs) |
        il::Expression::And(ref lhs, ref rhs) |
        il::Expression::Or(ref lhs, ref rhs) |
        il::Expression::Xor(ref lhs, ref rhs) |
        il::Expression::Shl(ref lhs, ref rhs) |
        il::Expression::Shr(ref lhs, ref rhs) |
        il::Expression::Cmpeq(ref lhs, ref rhs) |
        il::Expression::Cmpneq(ref lhs, ref rhs) |
        il::Expression::Cmplts(ref lhs, ref rhs) |
        il::Expression::Cmpltu(ref lhs, ref rhs) =>
            all_constants(lhs) && all_constants(rhs),
        il::Expression::Zext(_, ref src) |
        il::Expression::Sext(_, ref src) |
        il::Expression::Trun(_, ref src) =>
            all_constants(src)
    }
}<commit_msg>goodbye SymbolicEngine::fork()<commit_after>use il;
use engine::*;
use error::*;
use executor;
use std::collections::BTreeMap;
use std::rc::Rc;
use translator::TranslationMemory;

/// An engine for maintaining a symbolic state, performing operations over that
/// state, and querying that state.
#[derive(Clone, Deserialize, Serialize)]
pub struct SymbolicEngine {
    scalars: BTreeMap<String, il::Expression>,
    memory: SymbolicMemory,
    constraints: Vec<il::Expression>,
    #[serde(skip)]
    solver: Rc<Solver>
}

impl SymbolicEngine {
    /// Create a new `SymbolicEngine`
    pub fn new(memory: SymbolicMemory) -> SymbolicEngine {
        SymbolicEngine {
            scalars: BTreeMap::new(),
            memory: memory,
            constraints: Vec::new(),
            solver: Rc::new(Solver::new().unwrap())
        }
    }

    /// Get the `SymbolicMemory` backing this engine.
    pub fn memory(&self) -> &SymbolicMemory {
        &self.memory
    }

    /// Get a mutable reference to the `SymbolicMemory` backing this reference.
    pub fn memory_mut(&mut self) -> &mut SymbolicMemory {
        &mut self.memory
    }

    pub fn constraints(&self) -> &Vec<il::Expression> {
        &self.constraints
    }

    /// Add constraint to this state.
    ///
    /// This constraint must be equal to 0x1:1, or a 1-bit value of 1, for the
    /// state to be satisfiable. This is the result of Falcon IL comparison
    /// expressions.
    ///
    /// It is an error to add a constraint that is unsatisfiable in the engine's
    /// current state.
    pub fn add_constraint(&mut self, mut constraint: il::Expression)
        -> Result<()> {

        constraint = self.symbolize_expression(&constraint)?;
        if all_constants(&constraint) {
            // If we have a constant constraint which is always 0, add a constant
            // constraint which is always 0.
            if executor::constants_expression(&constraint)?.value() != 1 {
                self.constraints.push(il::Expression::cmpeq(
                    il::expr_const(0, 1),
                    il::expr_const(1, 1)
                )?);
            }
        }
        else {
            self.constraints.push(constraint);
        }

        Ok(())
    }

    /// Set a symbolic scalar
    pub fn set_scalar<S>(&mut self, name: S, value: il::Expression)
        where S: Into<String> {
        self.scalars.insert(name.into(), value);
    }

    /// Get the symbolic value of a scalar
    pub fn get_scalar(&self, name: &str) -> Option<&il::Expression> {
        self.scalars.get(name)
    }

    /// Replace scalars in the expression with those in the engine's current
    /// scalar to expression mapping, and if all scalars are currently constant,
    /// evaluate to constant and return that. Otherwise, return expression with
    /// symbolic values
    pub fn symbolize_and_eval(&self, expression: &il::Expression)
        -> Result<il::Expression> {

        let expression = self.symbolize_expression(expression)?;
        if all_constants(&expression) {
            let constant = executor::constants_expression(&expression)?;
            Ok(il::Expression::Constant(constant))
        }
        else {
            Ok(expression)
        }
    }

    /// Takes a regular IL expression, and replaces scalars with their
    /// expression values using the engine's internal scalar store.
    pub fn symbolize_expression(&self, expression: &il::Expression)
        -> Result<il::Expression> {

        Ok(match *expression {
            il::Expression::Scalar(ref scalar) => {
                if self.scalars.contains_key(scalar.name()) {
                    self.scalars[scalar.name()].clone()
                }
                else {
                    il::Expression::Scalar(scalar.clone())
                }
            }
            il::Expression::Constant(_) => expression.clone(),
            il::Expression::Add(ref lhs, ref rhs) =>
                il::Expression::add(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Sub(ref lhs, ref rhs) =>
                il::Expression::sub(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Mul(ref lhs, ref rhs) =>
                il::Expression::mul(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Divu(ref lhs, ref rhs) =>
                il::Expression::divu(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::Modu(ref lhs, ref rhs) =>
                il::Expression::modu(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::Divs(ref lhs, ref rhs) =>
                il::Expression::divs(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::Mods(ref lhs, ref rhs) =>
                il::Expression::mods(self.symbolize_expression(lhs)?,
                                     self.symbolize_expression(rhs)?)?,
            il::Expression::And(ref lhs, ref rhs) =>
                il::Expression::and(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Or(ref lhs, ref rhs) =>
                il::Expression::or(self.symbolize_expression(lhs)?,
                                   self.symbolize_expression(rhs)?)?,
            il::Expression::Xor(ref lhs, ref rhs) =>
                il::Expression::xor(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Shl(ref lhs, ref rhs) =>
                il::Expression::shl(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Shr(ref lhs, ref rhs) =>
                il::Expression::shr(self.symbolize_expression(lhs)?,
                                    self.symbolize_expression(rhs)?)?,
            il::Expression::Cmpeq(ref lhs, ref rhs) =>
                il::Expression::cmpeq(self.symbolize_expression(lhs)?,
                                      self.symbolize_expression(rhs)?)?,
            il::Expression::Cmpneq(ref lhs, ref rhs) =>
                il::Expression::cmpneq(self.symbolize_expression(lhs)?,
                                       self.symbolize_expression(rhs)?)?,
            il::Expression::Cmplts(ref lhs, ref rhs) =>
                il::Expression::cmplts(self.symbolize_expression(lhs)?,
                                       self.symbolize_expression(rhs)?)?,
            il::Expression::Cmpltu(ref lhs, ref rhs) =>
                il::Expression::cmpltu(self.symbolize_expression(lhs)?,
                                       self.symbolize_expression(rhs)?)?,
            il::Expression::Zext(bits, ref src) =>
                il::Expression::zext(bits, self.symbolize_expression(src)?)?,
            il::Expression::Sext(bits, ref src) =>
                il::Expression::sext(bits, self.symbolize_expression(src)?)?,
            il::Expression::Trun(bits, ref src) =>
                il::Expression::trun(bits, self.symbolize_expression(src)?)?
        })
    }

    /// Evaluates an expression in the solver. If constraints are given, enforces
    /// these extra constraints.
    pub fn eval(
        &mut self,
        expr: &il::Expression,
        constraints: Option<Vec<il::Expression>>
    ) -> Result<Option<il::Constant>> {

        // Create one vec of constraints
        let constraints = match constraints {
            Some(constraints) => {
                let mut c = Vec::new();
                for constraint in constraints {
                    let constraint = self.symbolize_expression(&constraint)?;
                    if all_constants(&constraint) {
                        if executor::constants_expression(&constraint)?.value() == 0 {
                            return Ok(None)
                        }
                    }
                    else {
                        c.push(constraint);
                    }
                }
                c.append(&mut self.constraints.clone());
                c
            },
            None => self.constraints.clone()
        };

        let expr = self.symbolize_expression(expr)?;

        if all_constants(&expr) {
            return Ok(Some(executor::constants_expression(&expr)?));
        }

        Rc::make_mut(&mut self.solver).solve(&expr, constraints)
    }

    /// Loads a single byte from memory. This byte must have a concrete value.
    pub fn load_only_concrete(&self, address: u64) -> Result<Option<u8>> {
        let byte = self.memory.load(address, 8)?;
        let byte = match byte {
            Some(byte) => byte,
            None => return Ok(None)
        };

        if all_constants(&byte) {
            let value = executor::constants_expression(&byte)?;
            Ok(Some(value.value() as u8))
        }
        else {
            Ok(None)
        }
    }

    /// Gets the value of a scalar, but only if the scalar has a concrete value
    pub fn get_scalar_only_concrete(&self, name: &str) -> Result<Option<il::Constant>> {
        let expr = match self.get_scalar(name) {
            Some(expr) => expr,
            None => bail!("scalar {} does not exist", name)
        };

        if !all_constants(expr) {
            Ok(None)
        }
        else {
            Ok(Some(executor::constants_expression(expr)?))
        }
    }

    /// Determine whether the constraints of this state are satisfiable
    pub fn sat(&mut self, constraints: Option<Vec<il::Expression>>) -> Result<bool> {
        // An expression that will always evaluate to true
        let expression = il::Expression::cmpeq(
            il::expr_const(1, 1),
            il::expr_const(1, 1)
        ).unwrap();
        if self.eval(&expression, constraints)?.is_some() {
            Ok(true)
        }
        else {
            Ok(false)
        }
    }

    /// Execute an IL operation over the engine, updating state.
    pub fn execute(mut self, operation: &il::Operation)
        -> Result<Vec<SymbolicSuccessor>> {

        Ok(match *operation {
            il::Operation::Assign { ref dst, ref src } => {
                let src = self.symbolize_and_eval(src)?;
                self.set_scalar(dst.name(), src);
                vec![SymbolicSuccessor::new(self, SuccessorType::FallThrough)]
            },
            il::Operation::Store { ref index, ref src, .. } => {
                let src = self.symbolize_and_eval(src)?;
                let index = self.eval(index, None)?;
                if let Some(index) = index {
                    self.memory.store(index.value(), src)?;
                    vec![SymbolicSuccessor::new(self, SuccessorType::FallThrough)]
                }
                else {
                    Vec::new()
                }
            },
            il::Operation::Load { ref dst, ref index, .. } => {
                let index_ = self.eval(index, None)?;
                if let Some(index) = index_ {
                    let value = self.memory.load(index.value(), dst.bits())?;
                    match value {
                        Some(v) => {
                            self.scalars.insert(dst.name().to_string(), v.clone());
                            vec![SymbolicSuccessor::new(self, SuccessorType::FallThrough)]
                        },
                        None => {
                            trace!("Got invalid concretized load address 0x{:x}", index.value());
                            Vec::new()
                        }
                    }
                }
                else {
                    trace!("Could not resolve load address {}", index);
                    Vec::new()
                }
            },
            il::Operation::Brc { ref target, ref condition } => {
                let mut successors = Vec::new();
                // Is it possible for this case not to be taken?
                let null_case = il::Expression::cmpeq(condition.clone(), il::expr_const(0, 1))?;
                let r = self.eval(&null_case, Some(vec![null_case.clone()]))?;
                if r.is_some() {
                    let mut engine = self.clone();
                    engine.add_constraint(null_case)?;
                    let successor = SymbolicSuccessor::new(engine, SuccessorType::FallThrough);
                    successors.push(successor);
                }
                // This is the true case
                let r = self.eval(&condition, Some(vec![condition.clone()]))?;
                if r.is_some() {
                    let t = self.eval(target, Some(vec![condition.clone()]))?;
                    if let Some(target) = t {
                        let mut engine = self.clone();
                        engine.add_constraint(condition.clone())?;
                        let successor = SymbolicSuccessor::new(
                            engine,
                            SuccessorType::Branch(target.value())
                        );
                        successors.push(successor);
                    }
                }
                successors
            },
            il::Operation::Phi { .. } => {
                panic!("Phi unimplemented");
            },
            il::Operation::Raise { ref expr } => {
                vec![SymbolicSuccessor::new(
                    self,
                    SuccessorType::Raise(expr.clone())
                )]
            }
        })
    }
}

impl TranslationMemory for SymbolicEngine {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.load_only_concrete(address).unwrap()
    }
}

/// Return true if an expression is all constants.
///
/// If an expression is all constants, we can evaluate the expression
/// concretely and return its constant value).
pub fn all_constants(expr: &il::Expression) -> bool {
    match *expr {
        il::Expression::Scalar(_) => false,
        il::Expression::Constant(_) => true,
        il::Expression::Add(ref lhs, ref rhs) |
        il::Expression::Sub(ref lhs, ref rhs) |
        il::Expression::Mul(ref lhs, ref rhs) |
        il::Expression::Divu(ref lhs, ref rhs) |
        il::Expression::Modu(ref lhs, ref rhs) |
        il::Expression::Divs(ref lhs, ref rhs) |
        il::Expression::Mods(ref lhs, ref rhs) |
        il::Expression::And(ref lhs, ref rhs) |
        il::Expression::Or(ref lhs, ref rhs) |
        il::Expression::Xor(ref lhs, ref rhs) |
        il::Expression::Shl(ref lhs, ref rhs) |
        il::Expression::Shr(ref lhs, ref rhs) |
        il::Expression::Cmpeq(ref lhs, ref rhs) |
        il::Expression::Cmpneq(ref lhs, ref rhs) |
        il::Expression::Cmplts(ref lhs, ref rhs) |
        il::Expression::Cmpltu(ref lhs, ref rhs) =>
            all_constants(lhs) && all_constants(rhs),
        il::Expression::Zext(_, ref src) |
        il::Expression::Sext(_, ref src) |
        il::Expression::Trun(_, ref src) =>
            all_constants(src)
    }
}<|endoftext|>