Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion general/echo/kmdf/driver/DriverSync/src/device.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// License: MIT OR Apache-2.0

use core::time::Duration;

use wdk::{nt_success, paged_code, println};
use wdk_sys::{
call_unsafe_wdf_function_binding,
Expand Down Expand Up @@ -146,6 +148,23 @@ pub fn echo_device_create(mut device_init: &mut WDFDEVICE_INIT) -> NTSTATUS {
///
/// * `NTSTATUS` - Failures will result in the device stack being torn down.
extern "C" fn echo_evt_device_self_managed_io_start(device: WDFDEVICE) -> NTSTATUS {
/// 100ms relative time (in 100-nanosecond units). The negative sign marks
/// the value as a relative (rather than absolute) timeout.
#[allow(
clippy::cast_possible_truncation,
reason = "100ms in 100-nanosecond units is known to fit in i64"
)]
const WDF_REL_TIMEOUT_100_MS: i64 = {
const UNITS: u128 = Duration::from_millis(100).as_nanos() / 100;
const {
assert!(
UNITS <= i64::MAX as u128,
"1,000,000 should fit in i64"
);
};
-(UNITS as i64)
};

// Restart the queue and the periodic timer. We stopped them before going
// into low power state.
let queue: WDFQUEUE;
Expand All @@ -162,7 +181,7 @@ extern "C" fn echo_evt_device_self_managed_io_start(device: WDFDEVICE) -> NTSTAT
// into low power state.
unsafe { call_unsafe_wdf_function_binding!(WdfIoQueueStart, queue) };

let due_time: i64 = -(100) * (10000);
let due_time: i64 = WDF_REL_TIMEOUT_100_MS;

let _ = unsafe { (*queue_context).timer.start(due_time) };

Expand Down
10 changes: 8 additions & 2 deletions general/echo/kmdf/driver/DriverSync/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,15 @@ fn echo_print_driver_version() -> NTSTATUS {
call_unsafe_wdf_function_binding!(WdfDriverIsVersionAvailable, driver, &raw mut ver)
} > 0
{
println!("Yes, framework version is 1.0");
println!(
"Yes, framework version is {}.{}",
ver.MajorVersion, ver.MinorVersion
);
} else {
println!("No, framework version is not 1.0");
println!(
"No, framework version is not {}.{}",
ver.MajorVersion, ver.MinorVersion
);
}

STATUS_SUCCESS
Expand Down
52 changes: 40 additions & 12 deletions general/echo/kmdf/driver/DriverSync/src/queue.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// License: MIT OR Apache-2.0

use core::sync::atomic::Ordering;
use core::{sync::atomic::Ordering, time::Duration};

use wdk::{nt_success, paged_code, println, wdf};
use wdk_sys::{
Expand Down Expand Up @@ -44,11 +44,14 @@ use crate::{
WDF_TIMER_CONFIG_SIZE,
};

/// Set max write length for testing
const MAX_WRITE_LENGTH: usize = 1024 * 40;
/// Initial cancel/completion ownership count assigned to a new request. A
/// claimant takes ownership by decrementing the count down to zero.
const INITIAL_CANCEL_OWNERSHIP_COUNT: i32 = 1;

/// Set timer period in ms
const TIMER_PERIOD: u32 = 1000 * 10;
/// Total ownership count held by the timer DPC once it has claimed completion
/// of a request: the initial count plus the single increment it acquired via
/// `echo_increment_request_cancel_ownership_count`.
const TIMER_CLAIMED_OWNERSHIP_COUNT: i32 = INITIAL_CANCEL_OWNERSHIP_COUNT + 1;

/// This routine will interlock increment a value only if the current value
/// is greater then the floor value.
Expand Down Expand Up @@ -130,6 +133,22 @@ fn echo_interlocked_increment_gtzero(target: &AtomicI32) -> i32 {
/// * `NTSTATUS`
#[link_section = "PAGE"]
pub unsafe fn echo_queue_initialize(device: WDFDEVICE) -> NTSTATUS {
/// Timer period of 10 seconds in ms
#[allow(
clippy::cast_possible_truncation,
reason = "10 seconds in millisecond units is known to fit in u32"
)]
const TIMER_PERIOD_10_S: u32 = {
const MILLIS: u128 = Duration::from_secs(10).as_millis();
const {
assert!(
MILLIS <= u32::MAX as u128,
"10,000 should fit in u32"
);
};
MILLIS as u32
};

paged_code!();

let mut queue = WDF_NO_HANDLE as WDFQUEUE;
Expand Down Expand Up @@ -206,7 +225,7 @@ pub unsafe fn echo_queue_initialize(device: WDFDEVICE) -> NTSTATUS {
let mut timer_config = WDF_TIMER_CONFIG {
Size: WDF_TIMER_CONFIG_SIZE,
EvtTimerFunc: Some(echo_evt_timer_func),
Period: TIMER_PERIOD,
Period: TIMER_PERIOD_10_S,
AutomaticSerialization: u8::from(true),
TolerableDelay: 0,
..WDF_TIMER_CONFIG::default()
Expand Down Expand Up @@ -356,7 +375,8 @@ fn echo_set_current_request(request: WDFREQUEST, queue: WDFQUEUE) {
// they will interlock decrement the count. When the count reaches zero,
// ownership has been acquired and the caller may complete the request.
unsafe {
(*request_context).cancel_completion_ownership_count = AtomicI32::new(1);
(*request_context).cancel_completion_ownership_count =
AtomicI32::new(INITIAL_CANCEL_OWNERSHIP_COUNT);
}

// Defer the completion to another thread from the timer dpc
Expand Down Expand Up @@ -518,6 +538,15 @@ extern "C" fn echo_evt_io_read(queue: WDFQUEUE, request: WDFREQUEST, mut length:
///
/// * `VOID`
extern "C" fn echo_evt_io_write(queue: WDFQUEUE, request: WDFREQUEST, length: usize) {
/// Number of bytes in one kilobyte.
const BYTES_PER_KB: usize = 1024;
/// Max write length, in bytes, for testing
const MAX_WRITE_LENGTH: usize = 40 * BYTES_PER_KB;

/// Non-zero char literal (of one to four chars) for pool tag used in
/// `ExAllocatePool2`
const MEMORY_TAG: u32 = u32::from_be_bytes(*b"sam1");

let mut memory = WDF_NO_HANDLE as WDFMEMORY;
let mut status: NTSTATUS;
let queue_context = unsafe { queue_get_context(queue as WDFOBJECT) };
Expand Down Expand Up @@ -564,9 +593,8 @@ extern "C" fn echo_evt_io_write(queue: WDFQUEUE, request: WDFREQUEST, length: us
(*queue_context).length = 0;
}

// FIXME: Memory Tag
(*queue_context).buffer =
ExAllocatePool2(POOL_FLAG_NON_PAGED, length as SIZE_T, 's' as u32);
ExAllocatePool2(POOL_FLAG_NON_PAGED, length as SIZE_T, MEMORY_TAG);
if (*queue_context).buffer.is_null() {
println!(
"echo_evt_io_write Could not allocate {:?} byte buffer",
Expand Down Expand Up @@ -697,12 +725,12 @@ unsafe extern "C" fn echo_evt_timer_func(timer: WDFTIMER) {
// currently racing with it), there is no need to use an interlocked
// decrement to lower the cancel ownership count.

// 2 is the initial count we set when we initialized
// CancelCompletionOwnershipCount plus the call to
// TIMER_CLAIMED_OWNERSHIP_COUNT is the initial count we set when we
// initialized CancelCompletionOwnershipCount plus the call to
// EchoIncrementRequestCancelOwnershipCount()
(*request_context)
.cancel_completion_ownership_count
.fetch_sub(2, Ordering::SeqCst);
.fetch_sub(TIMER_CLAIMED_OWNERSHIP_COUNT, Ordering::SeqCst);
complete_request = true;
}
}
Expand Down
24 changes: 21 additions & 3 deletions general/echo/kmdf/exe/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ static NUM_ASYNCH_IO: usize = 100;
static BUFFER_SIZE: usize = 40 * 1024;

fn main() -> Result<(), Box<dyn Error>> {
/// Transfer length, in bytes, for the first synchronous write/read test.
const SYNC_TEST_SMALL_LENGTH: u32 = 512;
/// Transfer length, in bytes, for the second synchronous write/read test.
const SYNC_TEST_LARGE_LENGTH: u32 = 30 * 1024;

let argument_vector: Vec<String> = env::args().collect();
let argument_count = argument_vector.len();

Expand Down Expand Up @@ -155,9 +160,9 @@ Exit the app anytime by pressing Ctrl-C

h.join().unwrap().unwrap();
} else {
perform_write_read_test(h_device, 512)?;
perform_write_read_test(h_device, SYNC_TEST_SMALL_LENGTH)?;

perform_write_read_test(h_device, 30 * 1024)?;
perform_write_read_test(h_device, SYNC_TEST_LARGE_LENGTH)?;
}

Ok(())
Expand Down Expand Up @@ -292,6 +297,14 @@ fn async_io(thread_parameter: u32) -> Result<(), Box<dyn Error + Send + Sync>> {
// function warning
#[allow(clippy::too_many_lines)]
fn async_io_work(io_type: u32) -> Result<(), Box<dyn Error>> {
/// Completion key associated with the device handle on the I/O completion
/// port.
const COMPLETION_PORT_KEY: usize = 1;
/// Number of concurrent threads allowed to run for the I/O completion port.
/// Zero lets the system allow as many concurrent threads as there are
/// processors.
const COMPLETION_PORT_CONCURRENT_THREADS: u32 = 0;

let globals = GLOBAL_DATA.read()?;

let h_device: HANDLE;
Expand Down Expand Up @@ -334,7 +347,12 @@ fn async_io_work(io_type: u32) -> Result<(), Box<dyn Error>> {
// Call Win32 API FFI CreateIoCompletionPort to get handle for completing async
// requests
unsafe {
h_completion_port = CreateIoCompletionPort(h_device, std::ptr::null_mut(), 1, 0);
h_completion_port = CreateIoCompletionPort(
h_device,
std::ptr::null_mut(),
COMPLETION_PORT_KEY,
COMPLETION_PORT_CONCURRENT_THREADS,
);
}

if h_completion_port.is_null() {
Expand Down
Loading