Skip to content

Commit 6c26bd7

Browse files
committed
Make physical Ps2Controller instantiable
1 parent b9e2545 commit 6c26bd7

File tree

2 files changed

+74
-44
lines changed

2 files changed

+74
-44
lines changed

mythril/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub enum Error {
8282
InvalidValue(String),
8383
InvalidDevice(String),
8484
NotImplemented(String),
85+
DeviceError(String),
8586
}
8687

8788
impl<T: TryFromPrimitive> From<TryFromPrimitiveError<T>> for Error {

mythril/src/physdev/keyboard.rs

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
use crate::error::Result;
1+
#![deny(missing_docs)]
2+
3+
//! # Physical PS2 Support
4+
//!
5+
//! This module provides support for interacting with a physical
6+
//! PS2 keyboard controller.
7+
8+
use crate::error::{Error, Result};
29
use bitflags::bitflags;
310
use x86::io::{inb, outb};
411

@@ -7,7 +14,7 @@ const PS2_STATUS_PORT: u16 = 0x64;
714
const PS2_COMMAND_PORT: u16 = 0x64;
815

916
bitflags! {
10-
pub struct Ps2StatusFlags: u8 {
17+
struct Ps2StatusFlags: u8 {
1118
const OUTPUT_BUFFER_FULL = 1 << 0;
1219
const INPUT_BUFFER_FULL = 1 << 1;
1320
const SELF_TEST_PASS = 1 << 2;
@@ -20,7 +27,7 @@ bitflags! {
2027
}
2128

2229
bitflags! {
23-
pub struct Ps2ConfigurationFlags: u8 {
30+
struct Ps2ConfigurationFlags: u8 {
2431
const FIRST_PORT_INTERRUPT = 1 << 0;
2532
const SECOND_PORT_INTERRUPT = 1 << 1;
2633
const SYSTEM_POST = 1 << 2;
@@ -48,101 +55,123 @@ enum Command {
4855
WriteSecond = 0xD4,
4956
}
5057

58+
/// A representation of a physical PS2 keyboard controller
59+
///
60+
/// Note that currently only one instance of this type should be created.
5161
pub struct Ps2Controller;
62+
5263
impl Ps2Controller {
53-
pub fn init() -> Result<()> {
64+
/// Create a new `Ps2Controller` and prepare the controller
65+
pub fn init() -> Result<Self> {
5466
// See https://wiki.osdev.org/%228042%22_PS/2_Controller#Initialising_the_PS.2F2_Controller
55-
Self::flush_read("init start");
56-
Self::write_command_port(Command::DisableFirst);
57-
Self::write_command_port(Command::DisableSecond);
58-
Self::flush_read("disable");
67+
let mut controller = Ps2Controller {};
68+
controller.flush_read("init start");
69+
controller.write_command_port(Command::DisableFirst);
70+
controller.write_command_port(Command::DisableSecond);
71+
controller.flush_read("disable");
5972

6073
{
61-
let mut config = Self::read_configuration();
74+
let mut config = controller.read_configuration();
6275
config.insert(Ps2ConfigurationFlags::FIRST_PORT_CLOCK_DISABLED);
6376
config.insert(Ps2ConfigurationFlags::SECOND_PORT_CLOCK_DISABLED);
6477
config.remove(Ps2ConfigurationFlags::FIRST_PORT_TRANSLATION);
6578
config.remove(Ps2ConfigurationFlags::FIRST_PORT_INTERRUPT);
6679
config.remove(Ps2ConfigurationFlags::SECOND_PORT_INTERRUPT);
67-
Self::write_configuration(config);
80+
controller.write_configuration(config);
81+
}
82+
83+
controller.write_command_port(Command::TestController);
84+
85+
if controller.read_data_port() != 0x55 {
86+
return Err(Error::DeviceError(
87+
"Failed to init Ps2Controller".into(),
88+
));
6889
}
6990

70-
Self::write_command_port(Command::TestController);
71-
//TODO: these should return error
72-
assert_eq!(Self::read_data_port(), 0x55);
91+
controller.write_command_port(Command::EnableFirst);
92+
controller.write_command_port(Command::EnableSecond);
93+
controller.flush_read("enable");
7394

74-
Self::write_command_port(Command::EnableFirst);
75-
Self::write_command_port(Command::EnableSecond);
76-
Self::flush_read("enable");
95+
controller.write_data_port(0xff);
7796

78-
Self::write_data_port(0xff);
79-
//TODO: these should return error
80-
assert_eq!(Self::read_data_port(), 0xFA);
81-
assert_eq!(Self::read_data_port(), 0xAA);
97+
if controller.read_data_port() != 0xFA {
98+
return Err(Error::DeviceError(
99+
"Failed to init Ps2Controller".into(),
100+
));
101+
}
102+
if controller.read_data_port() != 0xAA {
103+
return Err(Error::DeviceError(
104+
"Failed to init Ps2Controller".into(),
105+
));
106+
}
82107

83-
Self::flush_read("defaults");
108+
controller.flush_read("defaults");
84109

85110
{
86-
let mut config = Self::read_configuration();
111+
let mut config = controller.read_configuration();
87112
config.remove(Ps2ConfigurationFlags::FIRST_PORT_CLOCK_DISABLED);
88113
config.remove(Ps2ConfigurationFlags::SECOND_PORT_CLOCK_DISABLED);
89114
config.insert(Ps2ConfigurationFlags::FIRST_PORT_TRANSLATION);
90115
config.insert(Ps2ConfigurationFlags::FIRST_PORT_INTERRUPT);
91116
config.insert(Ps2ConfigurationFlags::SECOND_PORT_INTERRUPT);
92-
Self::write_configuration(config);
117+
controller.write_configuration(config);
93118
}
94119

95-
Self::flush_read("init finished");
96-
Ok(())
120+
controller.flush_read("init finished");
121+
Ok(controller)
97122
}
98123

99-
fn flush_read(message: &str) {
100-
while Self::read_status_port()
124+
fn flush_read(&mut self, message: &str) {
125+
while self
126+
.read_status_port()
101127
.contains(Ps2StatusFlags::OUTPUT_BUFFER_FULL)
102128
{
103-
info!("ps2: flush {}: {:X}", message, Self::read_data_port())
129+
info!("ps2: flush {}: {:X}", message, self.read_data_port())
104130
}
105131
}
106132

107-
fn read_data_port() -> u8 {
108-
Self::wait_read();
133+
/// Read a pending byte of data from the controller
134+
pub fn read_data_port(&mut self) -> u8 {
135+
self.wait_read();
109136
unsafe { inb(PS2_DATA_PORT) }
110137
}
111138

112-
fn write_data_port(data: u8) {
113-
Self::wait_write();
139+
fn write_data_port(&mut self, data: u8) {
140+
self.wait_write();
114141
unsafe {
115142
outb(PS2_DATA_PORT, data);
116143
}
117144
}
118145

119-
fn read_status_port() -> Ps2StatusFlags {
146+
fn read_status_port(&mut self) -> Ps2StatusFlags {
120147
Ps2StatusFlags::from_bits_truncate(unsafe { inb(PS2_STATUS_PORT) })
121148
}
122149

123-
fn read_configuration() -> Ps2ConfigurationFlags {
124-
Self::write_command_port(Command::ReadConfig);
125-
Ps2ConfigurationFlags::from_bits_truncate(Self::read_data_port())
150+
fn read_configuration(&mut self) -> Ps2ConfigurationFlags {
151+
self.write_command_port(Command::ReadConfig);
152+
Ps2ConfigurationFlags::from_bits_truncate(self.read_data_port())
126153
}
127154

128-
fn write_configuration(config: Ps2ConfigurationFlags) {
129-
Self::write_command_port(Command::WriteConfig);
130-
Self::write_data_port(config.bits())
155+
fn write_configuration(&mut self, config: Ps2ConfigurationFlags) {
156+
self.write_command_port(Command::WriteConfig);
157+
self.write_data_port(config.bits())
131158
}
132159

133-
fn wait_read() {
134-
while !Self::read_status_port()
160+
fn wait_read(&mut self) {
161+
while !self
162+
.read_status_port()
135163
.contains(Ps2StatusFlags::OUTPUT_BUFFER_FULL)
136164
{}
137165
}
138166

139-
fn wait_write() {
140-
while Self::read_status_port()
167+
fn wait_write(&mut self) {
168+
while self
169+
.read_status_port()
141170
.contains(Ps2StatusFlags::INPUT_BUFFER_FULL)
142171
{}
143172
}
144173

145-
fn write_command_port(cmd: Command) {
174+
fn write_command_port(&mut self, cmd: Command) {
146175
unsafe {
147176
outb(PS2_COMMAND_PORT, cmd as u8);
148177
}

0 commit comments

Comments
 (0)