123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- devinfo.c
- Abstract:
- This module implements support for device information requests.
- Author:
- Evan Green 9-Apr-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include "iop.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines a device information entry.
- Members:
- ListEntry - Stores pointers to the next and previous information entries in
- the global list.
- Uuid - Stores the universally unique identifier of the device information
- type.
- DeviceId - Stores the device ID of the device that registered the
- information.
- Device - Stores a pointer to the device that registered the information.
- --*/
- typedef struct _DEVICE_INFORMATION_ENTRY {
- LIST_ENTRY ListEntry;
- UUID Uuid;
- DEVICE_ID DeviceId;
- PDEVICE Device;
- } DEVICE_INFORMATION_ENTRY, *PDEVICE_INFORMATION_ENTRY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- UINTN IoNextDeviceId;
- LIST_ENTRY IoDeviceInformationList;
- PSHARED_EXCLUSIVE_LOCK IoDeviceInformationLock;
- //
- // ------------------------------------------------------------------ Functions
- //
- KERNEL_API
- KSTATUS
- IoLocateDeviceInformation (
- PUUID Uuid,
- PDEVICE Device,
- PDEVICE_ID DeviceId,
- PDEVICE_INFORMATION_RESULT Results,
- PULONG ResultCount
- )
- /*++
- Routine Description:
- This routine returns instances of devices enumerating information. Callers
- can get all devices enumerating the given information type, or all
- information types enumerated by a given device. This routine must be called
- at low level.
- Arguments:
- Uuid - Supplies an optional pointer to the information identifier to
- filter on. If NULL, any information type will match.
- Device - Supplies an optional pointer to the device to match against. If
- NULL (and the device ID parameter is NULL), then any device will match.
- DeviceId - Supplies an optional pointer to the device ID to match against.
- If NULL (and the device ID parameter is NULL), then any device will
- match.
- Results - Supplies a pointer to a caller allocated buffer where the
- results will be returned.
- ResultCount - Supplies a pointer that upon input contains the size of the
- buffer in information result elements. On output, returns the number
- of elements in the query, even if the provided buffer was too small.
- Do note however that the number of results can change between two
- successive searches.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_BUFFER_TOO_SMALL if the provided buffer was not large enough to
- contain all the results. The result count will contain the required number
- of elements to contain the results.
- --*/
- {
- ULONG BufferSize;
- PLIST_ENTRY CurrentEntry;
- PDEVICE_INFORMATION_ENTRY Entry;
- ULONG MatchCount;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- BufferSize = *ResultCount;
- ASSERT((BufferSize == 0) || (Results != NULL));
- MatchCount = 0;
- //
- // Loop through and look for elements that match.
- //
- KeAcquireSharedExclusiveLockShared(IoDeviceInformationLock);
- CurrentEntry = IoDeviceInformationList.Next;
- while (CurrentEntry != &IoDeviceInformationList) {
- Entry = LIST_VALUE(CurrentEntry, DEVICE_INFORMATION_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Skip anything that doesn't match.
- //
- if (Device != NULL) {
- if (Entry->Device != Device) {
- continue;
- }
- }
- if (DeviceId != NULL) {
- if (Entry->DeviceId != *DeviceId) {
- continue;
- }
- }
- if (Uuid != NULL) {
- if (RtlAreUuidsEqual(Uuid, &(Entry->Uuid)) == FALSE) {
- continue;
- }
- }
- //
- // This matches. Copy it into the results if there's space.
- //
- if (MatchCount < BufferSize) {
- RtlCopyMemory(&(Results->Uuid), &(Entry->Uuid), sizeof(UUID));
- Results->DeviceId = Entry->DeviceId;
- Results += 1;
- }
- MatchCount += 1;
- }
- KeReleaseSharedExclusiveLockShared(IoDeviceInformationLock);
- Status = STATUS_SUCCESS;
- if (MatchCount > BufferSize) {
- Status = STATUS_BUFFER_TOO_SMALL;
- }
- *ResultCount = MatchCount;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoGetSetDeviceInformation (
- DEVICE_ID DeviceId,
- PUUID Uuid,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets device information.
- Arguments:
- DeviceId - Supplies the device ID of the device to get or set information
- for.
- Uuid - Supplies a pointer to the identifier of the device information type
- to get or set.
- Data - Supplies a pointer to the data buffer that either contains the
- information to set or will contain the information to get on success.
- DataSize - Supplies a pointer that on input contains the size of the
- data buffer. On output contains the actual size of the data.
- Set - Supplies a boolean indicating whether to get information (FALSE) or
- set information (TRUE).
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PDEVICE Device;
- PDEVICE_INFORMATION_ENTRY Entry;
- SYSTEM_CONTROL_DEVICE_INFORMATION Request;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Loop through and find the information entry to convert from a device ID
- // back to a device.
- //
- Device = NULL;
- KeAcquireSharedExclusiveLockShared(IoDeviceInformationLock);
- CurrentEntry = IoDeviceInformationList.Next;
- while (CurrentEntry != &IoDeviceInformationList) {
- Entry = LIST_VALUE(CurrentEntry, DEVICE_INFORMATION_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->DeviceId == DeviceId) {
- Device = Entry->Device;
- break;
- }
- }
- KeReleaseSharedExclusiveLockShared(IoDeviceInformationLock);
- if (Device == NULL) {
- *DataSize = 0;
- return STATUS_NO_INTERFACE;
- }
- RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_DEVICE_INFORMATION));
- RtlCopyMemory(&(Request.Uuid), Uuid, sizeof(UUID));
- Request.Data = Data;
- Request.DataSize = *DataSize;
- Request.Set = Set;
- Status = IopSendSystemControlIrp(Device,
- IrpMinorSystemControlDeviceInformation,
- &Request);
- *DataSize = Request.DataSize;
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoRegisterDeviceInformation (
- PDEVICE Device,
- PUUID Uuid,
- BOOL Register
- )
- /*++
- Routine Description:
- This routine registers or deregisters a device to respond to information
- requests of the given universally unique identifier. This routine must be
- called at low level.
- Arguments:
- Device - Supplies a pointer to the device.
- Uuid - Supplies a pointer to the device information identifier.
- Register - Supplies a boolean indcating if the device is registering (TRUE)
- or de-registering (FALSE) for the information type.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES on allocation failure.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PDEVICE_INFORMATION_ENTRY Entry;
- PDEVICE_INFORMATION_ENTRY ExistingEntry;
- PDEVICE_INFORMATION_ENTRY NewEntry;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ExistingEntry = NULL;
- NewEntry = NULL;
- Status = STATUS_SUCCESS;
- //
- // Allocate and initialize the entry before acquiring the lock.
- //
- if (Register != FALSE) {
- NewEntry = MmAllocatePagedPool(sizeof(DEVICE_INFORMATION_ENTRY),
- DEVICE_INFORMATION_ALLOCATION_TAG);
- if (NewEntry == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto RegisterDeviceInformationEnd;
- }
- NewEntry->ListEntry.Next = NULL;
- RtlCopyMemory(&(NewEntry->Uuid), Uuid, sizeof(UUID));
- NewEntry->Device = Device;
- NewEntry->DeviceId = Device->DeviceId;
- }
- //
- // Look for an existing entry matching the device and UUID.
- //
- KeAcquireSharedExclusiveLockExclusive(IoDeviceInformationLock);
- CurrentEntry = IoDeviceInformationList.Next;
- while (CurrentEntry != &IoDeviceInformationList) {
- Entry = LIST_VALUE(CurrentEntry, DEVICE_INFORMATION_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((Entry->Device == Device) &&
- (RtlAreUuidsEqual(&(Entry->Uuid), Uuid) != FALSE)) {
- ExistingEntry = Entry;
- break;
- }
- }
- //
- // If there was an existing entry, remove and free it if necessary.
- //
- if (ExistingEntry != NULL) {
- if (Register == FALSE) {
- LIST_REMOVE(&(ExistingEntry->ListEntry));
- ExistingEntry->ListEntry.Next = NULL;
- //
- // The entry exists and the caller is trying to register it again.
- // Clear out the pointer so it's not freed at the end of this routine.
- //
- } else {
- ExistingEntry = NULL;
- }
- //
- // There was no previous entry, add the new one if needed.
- //
- } else {
- if (Register != FALSE) {
- INSERT_AFTER(&(NewEntry->ListEntry), &IoDeviceInformationList);
- NewEntry = NULL;
- }
- }
- RegisterDeviceInformationEnd:
- KeReleaseSharedExclusiveLockExclusive(IoDeviceInformationLock);
- if (ExistingEntry != NULL) {
- ASSERT(ExistingEntry->ListEntry.Next == NULL);
- MmFreePagedPool(ExistingEntry);
- }
- if (NewEntry != NULL) {
- ASSERT(NewEntry->ListEntry.Next == NULL);
- MmFreePagedPool(NewEntry);
- }
- return Status;
- }
- VOID
- IoSysLocateDeviceInformation (
- ULONG SystemCallNumber,
- PVOID SystemCallParameter,
- PTRAP_FRAME TrapFrame,
- PULONG ResultSize
- )
- /*++
- Routine Description:
- This routine implements the user mode system call for locating device
- information registrations by UUID or device ID.
- Arguments:
- SystemCallNumber - Supplies the system call number that was requested.
- SystemCallParameter - Supplies a pointer to the parameters supplied with
- the system call. This structure will be a stack-local copy of the
- actual parameters passed from user-mode.
- TrapFrame - Supplies a pointer to the trap frame generated by this jump
- from user mode to kernel mode.
- ResultSize - Supplies a pointer where the system call routine returns the
- size of the parameter structure to be copied back to user mode. The
- value returned here must be no larger than the original parameter
- structure size. The default is the original size of the parameters.
- Return Value:
- None.
- --*/
- {
- UINTN AllocationSize;
- ULONG CopyCount;
- KSTATUS CopyStatus;
- PDEVICE_ID DeviceIdPointer;
- PSYSTEM_CALL_LOCATE_DEVICE_INFORMATION Request;
- PDEVICE_INFORMATION_RESULT Results;
- KSTATUS Status;
- PUUID UuidPointer;
- ASSERT(SystemCallNumber == SystemCallLocateDeviceInformation);
- CopyCount = 0;
- Request = SystemCallParameter;
- //
- // Create a paged pool buffer to hold the results.
- //
- Results = NULL;
- if (Request->ResultCount != 0) {
- CopyCount = Request->ResultCount;
- AllocationSize = sizeof(DEVICE_INFORMATION_RESULT) * CopyCount;
- Results = MmAllocatePagedPool(
- AllocationSize,
- DEVICE_INFORMATION_REQUEST_ALLOCATION_TAG);
- if (Results == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SysLocateDeviceInformationEnd;
- }
- }
- DeviceIdPointer = NULL;
- UuidPointer = NULL;
- if (Request->ByDeviceId != FALSE) {
- DeviceIdPointer = &(Request->DeviceId);
- }
- if (Request->ByUuid != FALSE) {
- UuidPointer = &(Request->Uuid);
- }
- Status = IoLocateDeviceInformation(UuidPointer,
- NULL,
- DeviceIdPointer,
- Results,
- &(Request->ResultCount));
- //
- // Copy the results back into user mode.
- //
- if (Request->ResultCount < CopyCount) {
- CopyCount = Request->ResultCount;
- }
- if (CopyCount != 0) {
- CopyStatus = MmCopyToUserMode(
- Request->Results,
- Results,
- CopyCount * sizeof(DEVICE_INFORMATION_RESULT));
- if ((KSUCCESS(Status)) && (!KSUCCESS(CopyStatus))) {
- Status = CopyStatus;
- }
- }
- SysLocateDeviceInformationEnd:
- Request->Status = Status;
- if (Results != NULL) {
- MmFreePagedPool(Results);
- }
- return;
- }
- VOID
- IoSysGetSetDeviceInformation (
- ULONG SystemCallNumber,
- PVOID SystemCallParameter,
- PTRAP_FRAME TrapFrame,
- PULONG ResultSize
- )
- /*++
- Routine Description:
- This routine implements the user mode system call for getting and setting
- device information.
- Arguments:
- SystemCallNumber - Supplies the system call number that was requested.
- SystemCallParameter - Supplies a pointer to the parameters supplied with
- the system call. This structure will be a stack-local copy of the
- actual parameters passed from user-mode.
- TrapFrame - Supplies a pointer to the trap frame generated by this jump
- from user mode to kernel mode.
- ResultSize - Supplies a pointer where the system call routine returns the
- size of the parameter structure to be copied back to user mode. The
- value returned here must be no larger than the original parameter
- structure size. The default is the original size of the parameters.
- Return Value:
- None.
- --*/
- {
- PVOID Buffer;
- UINTN CopySize;
- KSTATUS CopyStatus;
- PSYSTEM_CALL_GET_SET_DEVICE_INFORMATION Request;
- KSTATUS Status;
- ASSERT(SystemCallNumber == SystemCallGetSetDeviceInformation);
- Buffer = NULL;
- Request = SystemCallParameter;
- //
- // Create a paged pool buffer to hold the data.
- //
- CopySize = 0;
- if (Request->DataSize != 0) {
- Buffer = MmAllocatePagedPool(
- Request->DataSize,
- DEVICE_INFORMATION_REQUEST_ALLOCATION_TAG);
- if (Buffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SysGetSetDeviceInformationEnd;
- }
- CopySize = Request->DataSize;
- //
- // Copy the data into the kernel mode buffer.
- //
- Status = MmCopyFromUserMode(Buffer,
- Request->Data,
- Request->DataSize);
- if (!KSUCCESS(Status)) {
- goto SysGetSetDeviceInformationEnd;
- }
- }
- Status = IoGetSetDeviceInformation(Request->DeviceId,
- &(Request->Uuid),
- Buffer,
- &(Request->DataSize),
- Request->Set);
- //
- // Copy the data back into user mode, even on set operations.
- //
- if (CopySize > Request->DataSize) {
- CopySize = Request->DataSize;
- }
- if (CopySize != 0) {
- CopyStatus = MmCopyToUserMode(Request->Data, Buffer, CopySize);
- if ((KSUCCESS(Status)) && (!KSUCCESS(CopyStatus))) {
- Status = CopyStatus;
- }
- }
- SysGetSetDeviceInformationEnd:
- if (Buffer != NULL) {
- MmFreePagedPool(Buffer);
- }
- Request->Status = Status;
- return;
- }
- DEVICE_ID
- IopGetNextDeviceId (
- VOID
- )
- /*++
- Routine Description:
- This routine allocates and returns a device ID.
- Arguments:
- None.
- Return Value:
- Returns a unique device ID number.
- --*/
- {
- DEVICE_ID DeviceId;
- DeviceId = RtlAtomicAdd(&IoNextDeviceId, 1);
- return DeviceId;
- }
- KSTATUS
- IopInitializeDeviceInformationSupport (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes device information support.
- Arguments:
- None.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- IoNextDeviceId = OBJECT_MANAGER_DEVICE_ID + 1;
- INITIALIZE_LIST_HEAD(&IoDeviceInformationList);
- IoDeviceInformationLock = KeCreateSharedExclusiveLock();
- if (IoDeviceInformationLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceInformationSupportEnd;
- }
- Status = STATUS_SUCCESS;
- InitializeDeviceInformationSupportEnd:
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|