Skip to content

Commit

Permalink
Adds UefiHidDxe driver - written in Rust, provides input report handl…
Browse files Browse the repository at this point in the history
…ing for HidIo pointer devices.

Note: does not yet support HID keyboards. This is planned future work.

- [x] Impacts functionality?
Adds new input support functionality.
- [ ] Impacts security?
- [ ] Breaking change?
- [ ] Includes tests?
- [x] Includes documentation?
  - includes standard RustDocs.

Pointer verified in preboot console (UEFI setup menu and Bitlocker Recovery).

Assuming a project is setup to build rust modules generally, integration of the new stack is accomplished by:
- Remove UsbMouseAbsolutePointerDxe
- Add UsbHidDxe and UefiHidDxe to the build
  • Loading branch information
joschock authored and TaylorBeebe committed Oct 13, 2023
1 parent 27ca9e6 commit 82177d1
Show file tree
Hide file tree
Showing 9 changed files with 1,045 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
members = [
"HidPkg/Crates/AbsolutePointer",
"HidPkg/Crates/HidIo",
"HidPkg/UefiHidDxe",
"MsCorePkg/HelloWorldRustDxe"
]

# Add packages that generate libraries here
[workspace.dependencies]
RustAdvancedLoggerDxe = {path = "AdvLoggerPkg/Crates/RustAdvancedLoggerDxe"}
RustBootServicesAllocatorDxe = {path = "MsCorePkg/Crates/RustBootServicesAllocatorDxe"}
HidIo = {path = "HidPkg/Crates/HidIo"}
AbsolutePointer = {path = "HidPkg/Crates/AbsolutePointer"}

hidparser = {git = "https://github.com/microsoft/mu_rust_hid.git", branch = "main"}

r-efi = "4.0.0"
rustversion = "1.0.14"
spin = "0.9.8"
memoffset = "0.9.0"
1 change: 1 addition & 0 deletions HidPkg/HidPkg.dsc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
HidPkg/UsbKbHidDxe/UsbKbHidDxe.inf
HidPkg/UsbMouseHidDxe/UsbMouseHidDxe.inf
HidPkg/UsbHidDxe/UsbHidDxe.inf
HidPkg/UefiHidDxe/UefiHidDxe.inf

[BuildOptions]
#force deprecated interfaces off
Expand Down
24 changes: 24 additions & 0 deletions HidPkg/UefiHidDxe/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
[package]
name = "UefiHidDxe"
version = "0.1.0"
edition = "2021"
authors = ["Microsoft"]

[[bin]]
name = "UefiHidDxe"
path = "src/main.rs"
test = false

[dependencies]
AbsolutePointer = {workspace=true}
HidIo = {workspace=true}
hidparser = {workspace=true}
memoffset = {workspace=true}
r-efi = {workspace=true}
rustversion = {workspace=true}
RustBootServicesAllocatorDxe = {workspace=true}
RustAdvancedLoggerDxe = {workspace=true}
22 changes: 22 additions & 0 deletions HidPkg/UefiHidDxe/UefiHidDxe.inf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
### @file
#
# UEFI HID - this driver consumes lower-level HID device support via the HidIo
# protocol abstraction and produces the UEFI spec input protocols for console support.
#
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
###

[Defines]
INF_VERSION = 1.27
BASE_NAME = UefiHidDxe
FILE_GUID = 90DC0565-643C-4119-A4F4-2B4EA198FB07
MODULE_TYPE = DXE_DRIVER
RUST_MODULE = TRUE

[Sources]
Cargo.toml

[Depex]
TRUE
149 changes: 149 additions & 0 deletions HidPkg/UefiHidDxe/src/driver_binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//! Driver binding support for HID input driver.
//!
//! This module manages the UEFI Driver Binding for the HID input driver.
//!
//! ## License
//!
//! Copyright (c) Microsoft Corporation. All rights reserved.
//! SPDX-License-Identifier: BSD-2-Clause-Patent
//!
use core::ffi::c_void;

use alloc::boxed::Box;
use r_efi::{
efi,
protocols::{device_path, driver_binding},
};
use rust_advanced_logger_dxe::{debugln, DEBUG_ERROR, DEBUG_INFO};

use crate::{hid, BOOT_SERVICES};

/// Initialize and install driver binding for this driver.
///
/// Installs this drivers driver binding on the given image handle.
pub fn initialize_driver_binding(image_handle: efi::Handle) -> Result<(), efi::Status> {
let boot_services = unsafe { BOOT_SERVICES.as_mut().ok_or(efi::Status::NOT_READY)? };

let mut driver_binding_handle = image_handle;
let driver_binding_ptr = Box::into_raw(Box::new(driver_binding::Protocol {
supported: uefi_hid_driver_binding_supported,
start: uefi_hid_driver_binding_start,
stop: uefi_hid_driver_binding_stop,
version: 1,
image_handle: driver_binding_handle,
driver_binding_handle: driver_binding_handle,
}));

let status = (boot_services.install_protocol_interface)(
core::ptr::addr_of_mut!(driver_binding_handle),
&driver_binding::PROTOCOL_GUID as *const efi::Guid as *mut efi::Guid,
efi::NATIVE_INTERFACE,
driver_binding_ptr as *mut c_void,
);

if status.is_error() {
return Err(status);
}

Ok(())
}

// Checks whether the given controller supports HidIo. Implements driver_binding::supported.
extern "efiapi" fn uefi_hid_driver_binding_supported(
this: *mut driver_binding::Protocol,
controller: efi::Handle,
_remaining_device_path: *mut device_path::Protocol,
) -> efi::Status {
// retrieve a reference to boot services.
// Safety: BOOT_SERVICES must have been initialized to point to the UEFI Boot Services table.
let boot_services = unsafe {
match BOOT_SERVICES.as_mut() {
Some(boot_services) => boot_services,
None => return efi::Status::NOT_READY,
}
};

// retrieve a reference to the driver binding.
// Safety: the driver binding pointer passed here must point to the binding installed in initialize_driver_binding.
let driver_binding = unsafe {
match this.as_mut() {
Some(driver_binding) => driver_binding,
None => return efi::Status::INVALID_PARAMETER,
}
};

// Check to see if this controller is supported by attempting to open HidIo on it.
let mut hid_io_ptr: *mut hid_io::protocol::Protocol = core::ptr::null_mut();
let status = (boot_services.open_protocol)(
controller,
&hid_io::protocol::GUID as *const efi::Guid as *mut efi::Guid,
core::ptr::addr_of_mut!(hid_io_ptr) as *mut *mut c_void,
driver_binding.driver_binding_handle,
controller,
efi::OPEN_PROTOCOL_BY_DRIVER,
);

// if HidIo could not be opened then it is either in use or not present.
if status.is_error() {
return status;
}

// HidIo is available, so this controller is supported. Further checking that requires actual device interaction is
// done in uefi_hid_driver_binding_start. close the protocol used for the supported test and exit with success.
let status = (boot_services.close_protocol)(
controller,
&hid_io::protocol::GUID as *const efi::Guid as *mut efi::Guid,
driver_binding.driver_binding_handle,
controller,
);
if status.is_error() {
debugln!(DEBUG_ERROR, "Unexpected error from CloseProtocol: {:?}", status); //message, but no further action to handle.
}

efi::Status::SUCCESS
}

// Start this driver managing given handle. Implements driver_binding::start.
extern "efiapi" fn uefi_hid_driver_binding_start(
this: *mut driver_binding::Protocol,
controller: efi::Handle,
_remaining_device_path: *mut device_path::Protocol,
) -> efi::Status {
// retrieve a reference to the driver binding.
// Safety: the driver binding pointer passed here must point to the binding installed in initialize_driver_binding.
let driver_binding = unsafe {
match this.as_mut() {
Some(driver_binding) => driver_binding,
None => return efi::Status::INVALID_PARAMETER,
}
};

// initialize the hid stack
let status = hid::initialize(controller, driver_binding);
if let Err(status) = status {
debugln!(DEBUG_INFO, "[hid::driver_binding_start] failed to initialize hid: {:x?}", status);
return status;
}

efi::Status::SUCCESS
}

// Stops this driver from managing the given handle. Implements driver_binding::stop.
extern "efiapi" fn uefi_hid_driver_binding_stop(
this: *mut driver_binding::Protocol,
controller: efi::Handle,
_num_children: usize,
_child_handle_buffer: *mut efi::Handle,
) -> efi::Status {
let driver_binding = unsafe { this.as_mut().expect("driver binding pointer is bad in uefi_hid_driver_binding_stop") };

//destroy the hid stack.
let status = hid::destroy(controller, driver_binding);
if let Err(status) = status {
debugln!(DEBUG_INFO, "[hid::driver_binding_stop] failed to destroy hid: {:x?}", status);
return status;
}

efi::Status::SUCCESS
}
Loading

0 comments on commit 82177d1

Please sign in to comment.