devinfo.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. devinfo.c
  5. Abstract:
  6. This module implements support for device information requests.
  7. Author:
  8. Evan Green 9-Apr-2014
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "iop.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // ------------------------------------------------------ Data Type Definitions
  22. //
  23. /*++
  24. Structure Description:
  25. This structure defines a device information entry.
  26. Members:
  27. ListEntry - Stores pointers to the next and previous information entries in
  28. the global list.
  29. Uuid - Stores the universally unique identifier of the device information
  30. type.
  31. DeviceId - Stores the device ID of the device that registered the
  32. information.
  33. Device - Stores a pointer to the device that registered the information.
  34. --*/
  35. typedef struct _DEVICE_INFORMATION_ENTRY {
  36. LIST_ENTRY ListEntry;
  37. UUID Uuid;
  38. DEVICE_ID DeviceId;
  39. PDEVICE Device;
  40. } DEVICE_INFORMATION_ENTRY, *PDEVICE_INFORMATION_ENTRY;
  41. //
  42. // ----------------------------------------------- Internal Function Prototypes
  43. //
  44. //
  45. // -------------------------------------------------------------------- Globals
  46. //
  47. UINTN IoNextDeviceId;
  48. LIST_ENTRY IoDeviceInformationList;
  49. PSHARED_EXCLUSIVE_LOCK IoDeviceInformationLock;
  50. //
  51. // ------------------------------------------------------------------ Functions
  52. //
  53. KERNEL_API
  54. KSTATUS
  55. IoLocateDeviceInformation (
  56. PUUID Uuid,
  57. PDEVICE Device,
  58. PDEVICE_ID DeviceId,
  59. PDEVICE_INFORMATION_RESULT Results,
  60. PULONG ResultCount
  61. )
  62. /*++
  63. Routine Description:
  64. This routine returns instances of devices enumerating information. Callers
  65. can get all devices enumerating the given information type, or all
  66. information types enumerated by a given device. This routine must be called
  67. at low level.
  68. Arguments:
  69. Uuid - Supplies an optional pointer to the information identifier to
  70. filter on. If NULL, any information type will match.
  71. Device - Supplies an optional pointer to the device to match against. If
  72. NULL (and the device ID parameter is NULL), then any device will match.
  73. DeviceId - Supplies an optional pointer to the device ID to match against.
  74. If NULL (and the device ID parameter is NULL), then any device will
  75. match.
  76. Results - Supplies a pointer to a caller allocated buffer where the
  77. results will be returned.
  78. ResultCount - Supplies a pointer that upon input contains the size of the
  79. buffer in information result elements. On output, returns the number
  80. of elements in the query, even if the provided buffer was too small.
  81. Do note however that the number of results can change between two
  82. successive searches.
  83. Return Value:
  84. STATUS_SUCCESS on success.
  85. STATUS_BUFFER_TOO_SMALL if the provided buffer was not large enough to
  86. contain all the results. The result count will contain the required number
  87. of elements to contain the results.
  88. --*/
  89. {
  90. ULONG BufferSize;
  91. PLIST_ENTRY CurrentEntry;
  92. PDEVICE_INFORMATION_ENTRY Entry;
  93. ULONG MatchCount;
  94. KSTATUS Status;
  95. ASSERT(KeGetRunLevel() == RunLevelLow);
  96. BufferSize = *ResultCount;
  97. ASSERT((BufferSize == 0) || (Results != NULL));
  98. MatchCount = 0;
  99. //
  100. // Loop through and look for elements that match.
  101. //
  102. KeAcquireSharedExclusiveLockShared(IoDeviceInformationLock);
  103. CurrentEntry = IoDeviceInformationList.Next;
  104. while (CurrentEntry != &IoDeviceInformationList) {
  105. Entry = LIST_VALUE(CurrentEntry, DEVICE_INFORMATION_ENTRY, ListEntry);
  106. CurrentEntry = CurrentEntry->Next;
  107. //
  108. // Skip anything that doesn't match.
  109. //
  110. if (Device != NULL) {
  111. if (Entry->Device != Device) {
  112. continue;
  113. }
  114. }
  115. if (DeviceId != NULL) {
  116. if (Entry->DeviceId != *DeviceId) {
  117. continue;
  118. }
  119. }
  120. if (Uuid != NULL) {
  121. if (RtlAreUuidsEqual(Uuid, &(Entry->Uuid)) == FALSE) {
  122. continue;
  123. }
  124. }
  125. //
  126. // This matches. Copy it into the results if there's space.
  127. //
  128. if (MatchCount < BufferSize) {
  129. RtlCopyMemory(&(Results->Uuid), &(Entry->Uuid), sizeof(UUID));
  130. Results->DeviceId = Entry->DeviceId;
  131. Results += 1;
  132. }
  133. MatchCount += 1;
  134. }
  135. KeReleaseSharedExclusiveLockShared(IoDeviceInformationLock);
  136. Status = STATUS_SUCCESS;
  137. if (MatchCount > BufferSize) {
  138. Status = STATUS_BUFFER_TOO_SMALL;
  139. }
  140. *ResultCount = MatchCount;
  141. return Status;
  142. }
  143. KERNEL_API
  144. KSTATUS
  145. IoGetSetDeviceInformation (
  146. DEVICE_ID DeviceId,
  147. PUUID Uuid,
  148. PVOID Data,
  149. PUINTN DataSize,
  150. BOOL Set
  151. )
  152. /*++
  153. Routine Description:
  154. This routine gets or sets device information.
  155. Arguments:
  156. DeviceId - Supplies the device ID of the device to get or set information
  157. for.
  158. Uuid - Supplies a pointer to the identifier of the device information type
  159. to get or set.
  160. Data - Supplies a pointer to the data buffer that either contains the
  161. information to set or will contain the information to get on success.
  162. DataSize - Supplies a pointer that on input contains the size of the
  163. data buffer. On output contains the actual size of the data.
  164. Set - Supplies a boolean indicating whether to get information (FALSE) or
  165. set information (TRUE).
  166. Return Value:
  167. Status code.
  168. --*/
  169. {
  170. PLIST_ENTRY CurrentEntry;
  171. PDEVICE Device;
  172. PDEVICE_INFORMATION_ENTRY Entry;
  173. SYSTEM_CONTROL_DEVICE_INFORMATION Request;
  174. KSTATUS Status;
  175. ASSERT(KeGetRunLevel() == RunLevelLow);
  176. //
  177. // Loop through and find the information entry to convert from a device ID
  178. // back to a device.
  179. //
  180. Device = NULL;
  181. KeAcquireSharedExclusiveLockShared(IoDeviceInformationLock);
  182. CurrentEntry = IoDeviceInformationList.Next;
  183. while (CurrentEntry != &IoDeviceInformationList) {
  184. Entry = LIST_VALUE(CurrentEntry, DEVICE_INFORMATION_ENTRY, ListEntry);
  185. CurrentEntry = CurrentEntry->Next;
  186. if (Entry->DeviceId == DeviceId) {
  187. Device = Entry->Device;
  188. break;
  189. }
  190. }
  191. KeReleaseSharedExclusiveLockShared(IoDeviceInformationLock);
  192. if (Device == NULL) {
  193. *DataSize = 0;
  194. return STATUS_NO_INTERFACE;
  195. }
  196. RtlZeroMemory(&Request, sizeof(SYSTEM_CONTROL_DEVICE_INFORMATION));
  197. RtlCopyMemory(&(Request.Uuid), Uuid, sizeof(UUID));
  198. Request.Data = Data;
  199. Request.DataSize = *DataSize;
  200. Request.Set = Set;
  201. Status = IopSendSystemControlIrp(Device,
  202. IrpMinorSystemControlDeviceInformation,
  203. &Request);
  204. *DataSize = Request.DataSize;
  205. return Status;
  206. }
  207. KERNEL_API
  208. KSTATUS
  209. IoRegisterDeviceInformation (
  210. PDEVICE Device,
  211. PUUID Uuid,
  212. BOOL Register
  213. )
  214. /*++
  215. Routine Description:
  216. This routine registers or deregisters a device to respond to information
  217. requests of the given universally unique identifier. This routine must be
  218. called at low level.
  219. Arguments:
  220. Device - Supplies a pointer to the device.
  221. Uuid - Supplies a pointer to the device information identifier.
  222. Register - Supplies a boolean indcating if the device is registering (TRUE)
  223. or de-registering (FALSE) for the information type.
  224. Return Value:
  225. STATUS_SUCCESS on success.
  226. STATUS_INSUFFICIENT_RESOURCES on allocation failure.
  227. --*/
  228. {
  229. PLIST_ENTRY CurrentEntry;
  230. PDEVICE_INFORMATION_ENTRY Entry;
  231. PDEVICE_INFORMATION_ENTRY ExistingEntry;
  232. PDEVICE_INFORMATION_ENTRY NewEntry;
  233. KSTATUS Status;
  234. ASSERT(KeGetRunLevel() == RunLevelLow);
  235. ExistingEntry = NULL;
  236. NewEntry = NULL;
  237. Status = STATUS_SUCCESS;
  238. //
  239. // Allocate and initialize the entry before acquiring the lock.
  240. //
  241. if (Register != FALSE) {
  242. NewEntry = MmAllocatePagedPool(sizeof(DEVICE_INFORMATION_ENTRY),
  243. DEVICE_INFORMATION_ALLOCATION_TAG);
  244. if (NewEntry == NULL) {
  245. Status = STATUS_INSUFFICIENT_RESOURCES;
  246. goto RegisterDeviceInformationEnd;
  247. }
  248. NewEntry->ListEntry.Next = NULL;
  249. RtlCopyMemory(&(NewEntry->Uuid), Uuid, sizeof(UUID));
  250. NewEntry->Device = Device;
  251. NewEntry->DeviceId = Device->DeviceId;
  252. }
  253. //
  254. // Look for an existing entry matching the device and UUID.
  255. //
  256. KeAcquireSharedExclusiveLockExclusive(IoDeviceInformationLock);
  257. CurrentEntry = IoDeviceInformationList.Next;
  258. while (CurrentEntry != &IoDeviceInformationList) {
  259. Entry = LIST_VALUE(CurrentEntry, DEVICE_INFORMATION_ENTRY, ListEntry);
  260. CurrentEntry = CurrentEntry->Next;
  261. if ((Entry->Device == Device) &&
  262. (RtlAreUuidsEqual(&(Entry->Uuid), Uuid) != FALSE)) {
  263. ExistingEntry = Entry;
  264. break;
  265. }
  266. }
  267. //
  268. // If there was an existing entry, remove and free it if necessary.
  269. //
  270. if (ExistingEntry != NULL) {
  271. if (Register == FALSE) {
  272. LIST_REMOVE(&(ExistingEntry->ListEntry));
  273. ExistingEntry->ListEntry.Next = NULL;
  274. //
  275. // The entry exists and the caller is trying to register it again.
  276. // Clear out the pointer so it's not freed at the end of this routine.
  277. //
  278. } else {
  279. ExistingEntry = NULL;
  280. }
  281. //
  282. // There was no previous entry, add the new one if needed.
  283. //
  284. } else {
  285. if (Register != FALSE) {
  286. INSERT_AFTER(&(NewEntry->ListEntry), &IoDeviceInformationList);
  287. NewEntry = NULL;
  288. }
  289. }
  290. RegisterDeviceInformationEnd:
  291. KeReleaseSharedExclusiveLockExclusive(IoDeviceInformationLock);
  292. if (ExistingEntry != NULL) {
  293. ASSERT(ExistingEntry->ListEntry.Next == NULL);
  294. MmFreePagedPool(ExistingEntry);
  295. }
  296. if (NewEntry != NULL) {
  297. ASSERT(NewEntry->ListEntry.Next == NULL);
  298. MmFreePagedPool(NewEntry);
  299. }
  300. return Status;
  301. }
  302. VOID
  303. IoSysLocateDeviceInformation (
  304. ULONG SystemCallNumber,
  305. PVOID SystemCallParameter,
  306. PTRAP_FRAME TrapFrame,
  307. PULONG ResultSize
  308. )
  309. /*++
  310. Routine Description:
  311. This routine implements the user mode system call for locating device
  312. information registrations by UUID or device ID.
  313. Arguments:
  314. SystemCallNumber - Supplies the system call number that was requested.
  315. SystemCallParameter - Supplies a pointer to the parameters supplied with
  316. the system call. This structure will be a stack-local copy of the
  317. actual parameters passed from user-mode.
  318. TrapFrame - Supplies a pointer to the trap frame generated by this jump
  319. from user mode to kernel mode.
  320. ResultSize - Supplies a pointer where the system call routine returns the
  321. size of the parameter structure to be copied back to user mode. The
  322. value returned here must be no larger than the original parameter
  323. structure size. The default is the original size of the parameters.
  324. Return Value:
  325. None.
  326. --*/
  327. {
  328. UINTN AllocationSize;
  329. ULONG CopyCount;
  330. KSTATUS CopyStatus;
  331. PDEVICE_ID DeviceIdPointer;
  332. PSYSTEM_CALL_LOCATE_DEVICE_INFORMATION Request;
  333. PDEVICE_INFORMATION_RESULT Results;
  334. KSTATUS Status;
  335. PUUID UuidPointer;
  336. ASSERT(SystemCallNumber == SystemCallLocateDeviceInformation);
  337. CopyCount = 0;
  338. Request = SystemCallParameter;
  339. //
  340. // Create a paged pool buffer to hold the results.
  341. //
  342. Results = NULL;
  343. if (Request->ResultCount != 0) {
  344. CopyCount = Request->ResultCount;
  345. AllocationSize = sizeof(DEVICE_INFORMATION_RESULT) * CopyCount;
  346. Results = MmAllocatePagedPool(
  347. AllocationSize,
  348. DEVICE_INFORMATION_REQUEST_ALLOCATION_TAG);
  349. if (Results == NULL) {
  350. Status = STATUS_INSUFFICIENT_RESOURCES;
  351. goto SysLocateDeviceInformationEnd;
  352. }
  353. }
  354. DeviceIdPointer = NULL;
  355. UuidPointer = NULL;
  356. if (Request->ByDeviceId != FALSE) {
  357. DeviceIdPointer = &(Request->DeviceId);
  358. }
  359. if (Request->ByUuid != FALSE) {
  360. UuidPointer = &(Request->Uuid);
  361. }
  362. Status = IoLocateDeviceInformation(UuidPointer,
  363. NULL,
  364. DeviceIdPointer,
  365. Results,
  366. &(Request->ResultCount));
  367. //
  368. // Copy the results back into user mode.
  369. //
  370. if (Request->ResultCount < CopyCount) {
  371. CopyCount = Request->ResultCount;
  372. }
  373. if (CopyCount != 0) {
  374. CopyStatus = MmCopyToUserMode(
  375. Request->Results,
  376. Results,
  377. CopyCount * sizeof(DEVICE_INFORMATION_RESULT));
  378. if ((KSUCCESS(Status)) && (!KSUCCESS(CopyStatus))) {
  379. Status = CopyStatus;
  380. }
  381. }
  382. SysLocateDeviceInformationEnd:
  383. Request->Status = Status;
  384. if (Results != NULL) {
  385. MmFreePagedPool(Results);
  386. }
  387. return;
  388. }
  389. VOID
  390. IoSysGetSetDeviceInformation (
  391. ULONG SystemCallNumber,
  392. PVOID SystemCallParameter,
  393. PTRAP_FRAME TrapFrame,
  394. PULONG ResultSize
  395. )
  396. /*++
  397. Routine Description:
  398. This routine implements the user mode system call for getting and setting
  399. device information.
  400. Arguments:
  401. SystemCallNumber - Supplies the system call number that was requested.
  402. SystemCallParameter - Supplies a pointer to the parameters supplied with
  403. the system call. This structure will be a stack-local copy of the
  404. actual parameters passed from user-mode.
  405. TrapFrame - Supplies a pointer to the trap frame generated by this jump
  406. from user mode to kernel mode.
  407. ResultSize - Supplies a pointer where the system call routine returns the
  408. size of the parameter structure to be copied back to user mode. The
  409. value returned here must be no larger than the original parameter
  410. structure size. The default is the original size of the parameters.
  411. Return Value:
  412. None.
  413. --*/
  414. {
  415. PVOID Buffer;
  416. UINTN CopySize;
  417. KSTATUS CopyStatus;
  418. PSYSTEM_CALL_GET_SET_DEVICE_INFORMATION Request;
  419. KSTATUS Status;
  420. ASSERT(SystemCallNumber == SystemCallGetSetDeviceInformation);
  421. Buffer = NULL;
  422. Request = SystemCallParameter;
  423. //
  424. // Create a paged pool buffer to hold the data.
  425. //
  426. CopySize = 0;
  427. if (Request->DataSize != 0) {
  428. Buffer = MmAllocatePagedPool(
  429. Request->DataSize,
  430. DEVICE_INFORMATION_REQUEST_ALLOCATION_TAG);
  431. if (Buffer == NULL) {
  432. Status = STATUS_INSUFFICIENT_RESOURCES;
  433. goto SysGetSetDeviceInformationEnd;
  434. }
  435. CopySize = Request->DataSize;
  436. //
  437. // Copy the data into the kernel mode buffer.
  438. //
  439. Status = MmCopyFromUserMode(Buffer,
  440. Request->Data,
  441. Request->DataSize);
  442. if (!KSUCCESS(Status)) {
  443. goto SysGetSetDeviceInformationEnd;
  444. }
  445. }
  446. Status = IoGetSetDeviceInformation(Request->DeviceId,
  447. &(Request->Uuid),
  448. Buffer,
  449. &(Request->DataSize),
  450. Request->Set);
  451. //
  452. // Copy the data back into user mode, even on set operations.
  453. //
  454. if (CopySize > Request->DataSize) {
  455. CopySize = Request->DataSize;
  456. }
  457. if (CopySize != 0) {
  458. CopyStatus = MmCopyToUserMode(Request->Data, Buffer, CopySize);
  459. if ((KSUCCESS(Status)) && (!KSUCCESS(CopyStatus))) {
  460. Status = CopyStatus;
  461. }
  462. }
  463. SysGetSetDeviceInformationEnd:
  464. if (Buffer != NULL) {
  465. MmFreePagedPool(Buffer);
  466. }
  467. Request->Status = Status;
  468. return;
  469. }
  470. DEVICE_ID
  471. IopGetNextDeviceId (
  472. VOID
  473. )
  474. /*++
  475. Routine Description:
  476. This routine allocates and returns a device ID.
  477. Arguments:
  478. None.
  479. Return Value:
  480. Returns a unique device ID number.
  481. --*/
  482. {
  483. DEVICE_ID DeviceId;
  484. DeviceId = RtlAtomicAdd(&IoNextDeviceId, 1);
  485. return DeviceId;
  486. }
  487. KSTATUS
  488. IopInitializeDeviceInformationSupport (
  489. VOID
  490. )
  491. /*++
  492. Routine Description:
  493. This routine initializes device information support.
  494. Arguments:
  495. None.
  496. Return Value:
  497. Status code.
  498. --*/
  499. {
  500. KSTATUS Status;
  501. IoNextDeviceId = OBJECT_MANAGER_DEVICE_ID + 1;
  502. INITIALIZE_LIST_HEAD(&IoDeviceInformationList);
  503. IoDeviceInformationLock = KeCreateSharedExclusiveLock();
  504. if (IoDeviceInformationLock == NULL) {
  505. Status = STATUS_INSUFFICIENT_RESOURCES;
  506. goto InitializeDeviceInformationSupportEnd;
  507. }
  508. Status = STATUS_SUCCESS;
  509. InitializeDeviceInformationSupportEnd:
  510. return Status;
  511. }
  512. //
  513. // --------------------------------------------------------- Internal Functions
  514. //