1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! I/O port functionality.

use core::arch::asm;

/// Write 8 bits to port
///
/// # Safety
/// Needs IO privileges.
#[inline]
pub unsafe fn outb(port: u16, val: u8) {
    asm!("outb %al, %dx", in("al") val, in("dx") port, options(att_syntax));
}

/// Read 8 bits from port
///
/// # Safety
/// Needs IO privileges.
#[inline]
pub unsafe fn inb(port: u16) -> u8 {
    let ret: u8;
    asm!("inb %dx, %al", in("dx") port, out("al") ret, options(att_syntax));
    ret
}

/// Write 16 bits to port
///
/// # Safety
/// Needs IO privileges.
#[inline]
pub unsafe fn outw(port: u16, val: u16) {
    asm!("outw %ax, %dx", in("ax") val, in("dx") port, options(att_syntax));
}

/// Read 16 bits from port
///
/// # Safety
/// Needs IO privileges.
#[inline]
pub unsafe fn inw(port: u16) -> u16 {
    let ret: u16;
    asm!("inw %dx, %ax", in("dx") port, out("ax") ret, options(att_syntax));
    ret
}

/// Write 32 bits to port
///
/// # Safety
/// Needs IO privileges.
#[inline]
pub unsafe fn outl(port: u16, val: u32) {
    asm!("outl %eax, %dx", in("eax") val, in("dx") port, options(att_syntax));
}

/// Read 32 bits from port
///
/// # Safety
/// Needs IO privileges.
#[inline]
pub unsafe fn inl(port: u16) -> u32 {
    let ret: u32;
    asm!("inl %dx, %eax", out("eax") ret, in("dx") port, options(att_syntax));
    ret
}

#[cfg(all(test, feature = "vmtest"))]
mod x86testing {
    use super::*;
    use x86test::*;

    #[x86test(ioport(0x0, 0xaf))]
    fn check_outb() {
        unsafe {
            outb(0x0, 0xaf);
            // hypervisor will fail here if port 0x0 doesn't see 0xaf
        }
    }

    #[x86test(ioport(0x0, 0xaf))]
    #[should_panic]
    fn check_outb_wrong_value() {
        unsafe {
            outb(0x0, 0xff);
        }
    }

    #[x86test(ioport(0x1, 0xad))]
    fn check_inb() {
        unsafe {
            kassert!(
                inb(0x1) == 0xad,
                "`inb` instruction didn't read the correct value"
            );
        }
    }

    #[x86test(ioport(0x2, 0xad))]
    #[should_panic]
    fn check_inb_wrong_port() {
        unsafe {
            kassert!(
                inb(0x1) == 0xad,
                "`inb` instruction didn't read the correct value"
            );
        }
    }

    #[x86test(ioport(0x2, 0x99))]
    fn check_outw() {
        unsafe {
            super::outw(0x2, 0x99);
            // hypervisor will fail here if port 0x2 doesn't see 0x99
        }
    }

    #[x86test(ioport(0x3, 0xfefe))]
    fn check_inw() {
        unsafe {
            kassert!(
                inw(0x3) == 0xfefe,
                "`inw` instruction didn't read the correct value"
            );
        }
    }

    #[x86test(ioport(0x5, 0xbeefaaaa))]
    fn check_outl() {
        unsafe {
            outl(0x5, 0xbeefaaaa);
            // hypervisor will fail here if port 0x5 doesn't see 0xbeefaaaa
        }
    }

    #[x86test(ioport(0x4, 0xdeadbeef))]
    fn check_inl() {
        unsafe {
            kassert!(
                inl(0x4) == 0xdeadbeef,
                "`inl` instruction didn't read the correct value"
            );
        }
    }
}