Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

510 lines
15 KiB

  1. /*++
  2. Copyright (c) 1991 - 2001 Microsoft Corporation
  3. Module Name:
  4. ## # ## ## ##### ### ## ## #### ##### #####
  5. ### # ## ## ## ## ### ### ### ## # ## ## ## ##
  6. #### # ## ## ## ## ## ## ######## ## ## ## ## ##
  7. # #### #### ##### ## ## # ### ## ## ## ## ## ##
  8. # ### #### #### ####### # # ## ## ##### #####
  9. # ## ## ## ## ## ## # ## ## ## # ## ##
  10. # # ## ## ## ## ## # ## ## #### ## ##
  11. Abstract:
  12. This module contains functions specfic to the
  13. NVRAM device. The logic in this module is not
  14. hardware specific, but is logic that is common
  15. to all hardware implementations.
  16. Author:
  17. Wesley Witt (wesw) 1-Oct-2001
  18. Environment:
  19. Kernel mode only.
  20. Notes:
  21. This is a map that shows how the NVRAM is used by the
  22. server appliance driver and application layers. This
  23. diagram shows and NVRAM configuration of 32 DWORDs of
  24. NVRAM, but less is acceptable. Regardless of the NVRAM
  25. size, the boot counters and boot times are always
  26. stored at the end of the NVRAM array. The upper layers
  27. are then free to be used by the application layers.
  28. |------------------------------|
  29. | [00-00] |
  30. |------------------------------|
  31. | [01-04] |
  32. |------------------------------|
  33. | [02-08] |
  34. |------------------------------|
  35. | [03-0c] |
  36. |------------------------------|
  37. | [04-10] |
  38. |------------------------------|
  39. | [05-14] |
  40. |------------------------------|
  41. | [06-18] |
  42. |------------------------------|
  43. | [07-1c] |
  44. |------------------------------|
  45. | [08-20] |
  46. |------------------------------|
  47. | [09-24] |
  48. |------------------------------|
  49. | [0a-28] |
  50. |------------------------------|
  51. | [0b-2c] |
  52. |------------------------------|
  53. | [0c-30] |
  54. |------------------------------|
  55. | [0d-34] |
  56. |------------------------------|
  57. | [0e-38] |
  58. |------------------------------|
  59. | [0f-3c] |
  60. |------------------------------|
  61. | [10-40] |
  62. |------------------------------|
  63. | [11-44] |
  64. |------------------------------|
  65. | [12-48] |
  66. |------------------------------|
  67. | [13-4c] |
  68. |------------------------------|
  69. | [14-50] Shutdown time #1 |
  70. |------------------------------|
  71. | [16-58] Shutdown time #2 |
  72. |------------------------------|
  73. | [18-60] Shutdown time #3 |
  74. |------------------------------|
  75. | [1a-68] Shutdown time #4 |
  76. |------------------------------|
  77. | [1c-70] Boot Counter #1 |
  78. |------------------------------|
  79. | [1d-74] Boot Counter #2 |
  80. |------------------------------|
  81. | [1e-78] Boot Counter #3 |
  82. |------------------------------|
  83. | [1f-7c] Boot Counter #4 |
  84. |------------------------------|
  85. --*/
  86. #include "internal.h"
  87. NTSTATUS
  88. SaNvramStartDevice(
  89. IN PNVRAM_DEVICE_EXTENSION DeviceExtension
  90. )
  91. /*++
  92. Routine Description:
  93. This is the NVRAM specific code for processing
  94. the PNP start device request. The NVRAM driver's
  95. capabilities are queried, the primary OS is queried,
  96. all the NVRAM data is read, and the reboot status
  97. is determined.
  98. Arguments:
  99. DeviceExtension - NVRAM device extension
  100. Return Value:
  101. NT status code.
  102. --*/
  103. {
  104. NTSTATUS Status;
  105. ULONG InterfaceVersion;
  106. ULONG FirstAvailableSlot;
  107. ULONG FirstBootCounterSlot;
  108. ULONG FullNvramSize;
  109. __try {
  110. //
  111. // Read our parameters from the registry
  112. //
  113. Status = SaPortReadNumericRegistryValue(
  114. DeviceExtension->MiniPortDeviceExtension,
  115. L"PrimaryOS",
  116. &DeviceExtension->PrimaryOS
  117. );
  118. if (!NT_SUCCESS(Status)) {
  119. REPORT_ERROR( DeviceExtension->DeviceType, "Missing the PrimaryOS registry parameter, assuming primary\n", Status );
  120. DeviceExtension->PrimaryOS = TRUE;
  121. }
  122. //
  123. // Get the mini-port's interface version
  124. //
  125. Status = CallMiniPortDriverDeviceControl(
  126. DeviceExtension,
  127. DeviceExtension->DeviceObject,
  128. IOCTL_SA_GET_VERSION,
  129. NULL,
  130. 0,
  131. &InterfaceVersion,
  132. sizeof(ULONG)
  133. );
  134. if (!NT_SUCCESS(Status)) {
  135. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to query the NVRAM driver interface version\n", Status );
  136. }
  137. if (InterfaceVersion > SA_INTERFACE_VERSION) {
  138. Status = STATUS_NOINTERFACE;
  139. ERROR_RETURN( DeviceExtension->DeviceType, "Incompatible NVRAM interface version\n", Status );
  140. }
  141. //
  142. // Get the mini-port's device capabilities
  143. //
  144. DeviceExtension->DeviceCaps.SizeOfStruct = sizeof(SA_NVRAM_CAPS);
  145. Status = CallMiniPortDriverDeviceControl(
  146. DeviceExtension,
  147. DeviceExtension->DeviceObject,
  148. IOCTL_SA_GET_CAPABILITIES,
  149. NULL,
  150. 0,
  151. &DeviceExtension->DeviceCaps,
  152. sizeof(SA_NVRAM_CAPS)
  153. );
  154. if (!NT_SUCCESS(Status)) {
  155. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to query the NVRAM driver capabilities\n", Status );
  156. }
  157. //
  158. // Compute the persistent slot numbers
  159. //
  160. FirstAvailableSlot = DeviceExtension->DeviceCaps.NvramSize;
  161. FirstBootCounterSlot = DeviceExtension->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS;
  162. DeviceExtension->SlotPowerCycle = FirstAvailableSlot;
  163. DeviceExtension->SlotShutDownTime = FirstAvailableSlot - 2;
  164. DeviceExtension->SlotBootCounter = FirstBootCounterSlot;
  165. //
  166. // Read the NVRAM data
  167. //
  168. FullNvramSize = (DeviceExtension->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS + NVRAM_RESERVED_BOOTCOUNTER_SLOTS) * sizeof(ULONG);
  169. DeviceExtension->NvramData = (PULONG) ExAllocatePool( PagedPool, FullNvramSize );
  170. if (DeviceExtension->NvramData == NULL) {
  171. Status = STATUS_INSUFFICIENT_RESOURCES;
  172. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool\n", Status );
  173. }
  174. Status = CallMiniPortDriverReadWrite(
  175. DeviceExtension,
  176. DeviceExtension->DeviceObject,
  177. FALSE,
  178. DeviceExtension->NvramData,
  179. FullNvramSize,
  180. 0
  181. );
  182. if (!NT_SUCCESS(Status)) {
  183. ERROR_RETURN( DeviceExtension->DeviceType, "Failed to read the NVRAM boot counters\n", Status );
  184. }
  185. DebugPrint(( DeviceExtension->DeviceType, SAPORT_DEBUG_INFO_LEVEL, "Boot counters [%08x] [%08x] [%08x] [%08x]\n",
  186. DeviceExtension->NvramData[FirstBootCounterSlot+0],
  187. DeviceExtension->NvramData[FirstBootCounterSlot+1],
  188. DeviceExtension->NvramData[FirstBootCounterSlot+2],
  189. DeviceExtension->NvramData[FirstBootCounterSlot+3] ));
  190. Status = STATUS_SUCCESS;
  191. } __finally {
  192. if (!NT_SUCCESS(Status)) {
  193. if (DeviceExtension->NvramData) {
  194. ExFreePool( DeviceExtension->NvramData );
  195. }
  196. }
  197. }
  198. return STATUS_SUCCESS;
  199. }
  200. NTSTATUS
  201. SaNvramDeviceInitialization(
  202. IN PSAPORT_DRIVER_EXTENSION DriverExtension
  203. )
  204. /*++
  205. Routine Description:
  206. This is the NVRAM specific code for driver initialization.
  207. This function is called by SaPortInitialize, which is called by
  208. the NVRAM driver's DriverEntry function.
  209. Arguments:
  210. DriverExtension - Driver extension structure
  211. Return Value:
  212. NT status code.
  213. --*/
  214. {
  215. return STATUS_SUCCESS;
  216. }
  217. NTSTATUS
  218. SaNvramIoValidation(
  219. IN PNVRAM_DEVICE_EXTENSION DeviceExtension,
  220. IN PIRP Irp,
  221. PIO_STACK_LOCATION IrpSp
  222. )
  223. /*++
  224. Routine Description:
  225. This is the NVRAM specific code for processing
  226. all I/O validation for reads and writes.
  227. Arguments:
  228. DeviceExtension - NVRAM device extension
  229. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  230. IrpSp - Irp stack pointer
  231. Return Value:
  232. NT status code.
  233. --*/
  234. {
  235. ULONG ByteOffset;
  236. ULONG Length;
  237. if (IrpSp->MajorFunction == IRP_MJ_READ) {
  238. ByteOffset = (ULONG)IrpSp->Parameters.Read.ByteOffset.QuadPart;
  239. Length = (ULONG)IrpSp->Parameters.Read.Length;
  240. } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
  241. ByteOffset = (ULONG)IrpSp->Parameters.Write.ByteOffset.QuadPart;
  242. Length = (ULONG)IrpSp->Parameters.Write.Length;
  243. } else {
  244. REPORT_ERROR( DeviceExtension->DeviceType, "Invalid I/O request", STATUS_INVALID_PARAMETER_1 );
  245. return STATUS_INVALID_PARAMETER_1;
  246. }
  247. if (((ByteOffset + Length) / sizeof(ULONG)) > DeviceExtension->DeviceCaps.NvramSize) {
  248. REPORT_ERROR( DeviceExtension->DeviceType, "I/O length too large", STATUS_INVALID_PARAMETER_2 );
  249. return STATUS_INVALID_PARAMETER_2;
  250. }
  251. return STATUS_SUCCESS;
  252. }
  253. NTSTATUS
  254. SaNvramShutdownNotification(
  255. IN PNVRAM_DEVICE_EXTENSION DeviceExtension,
  256. IN PIRP Irp,
  257. PIO_STACK_LOCATION IrpSp
  258. )
  259. /*++
  260. Routine Description:
  261. This is the NVRAM specific code for processing
  262. the system shutdown notification. Here we need to
  263. record the shutdown timestam to the appropriate
  264. NVRAM slot.
  265. Arguments:
  266. DeviceExtension - Display device extension
  267. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  268. IrpSp - Irp stack pointer
  269. Return Value:
  270. NT status code.
  271. --*/
  272. {
  273. NTSTATUS Status;
  274. LARGE_INTEGER CurrentTime;
  275. KeQuerySystemTime( &CurrentTime );
  276. Status = CallMiniPortDriverReadWrite(
  277. DeviceExtension,
  278. DeviceExtension->DeviceObject,
  279. TRUE,
  280. &CurrentTime.QuadPart,
  281. sizeof(LONGLONG),
  282. DeviceExtension->SlotShutDownTime * sizeof(ULONG)
  283. );
  284. if (!NT_SUCCESS(Status)) {
  285. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to write the shutdown timestamp to NVRAM", Status );
  286. return Status;
  287. }
  288. return STATUS_SUCCESS;
  289. }
  290. DECLARE_IOCTL_HANDLER( HandleNvramReadBootCounter )
  291. /*++
  292. Routine Description:
  293. This routine handles the read boot counter IOCTL for the
  294. NVRAM miniport driver.
  295. Arguments:
  296. DeviceObject - The device object for the target device.
  297. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  298. DeviceExtension - Pointer to the main port driver device extension.
  299. InputBuffer - Pointer to the user's input buffer
  300. InputBufferLength - Length in bytes of the input buffer
  301. OutputBuffer - Pointer to the user's output buffer
  302. OutputBufferLength - Length in bytes of the output buffer
  303. Return Value:
  304. NT status code.
  305. --*/
  306. {
  307. NTSTATUS Status;
  308. PSA_NVRAM_BOOT_COUNTER NvramBootCounter = (PSA_NVRAM_BOOT_COUNTER) OutputBuffer;
  309. ULONG NvramValue;
  310. if (OutputBufferLength != sizeof(SA_NVRAM_BOOT_COUNTER)) {
  311. REPORT_ERROR( DeviceExtension->DeviceType, "Output buffer != sizeof(SA_NVRAM_BOOT_COUNTER)", STATUS_INVALID_BUFFER_SIZE );
  312. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  313. }
  314. if (NvramBootCounter->SizeOfStruct != sizeof(SA_NVRAM_BOOT_COUNTER)) {
  315. REPORT_ERROR( DeviceExtension->DeviceType, "SA_NVRAM_BOOT_COUNTER structure wrong size", STATUS_INVALID_PARAMETER_1 );
  316. return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_1, 0 );
  317. }
  318. if (NvramBootCounter->Number == 0 || NvramBootCounter->Number > NVRAM_RESERVED_BOOTCOUNTER_SLOTS) {
  319. REPORT_ERROR( DeviceExtension->DeviceType, "Requested boot counter number is out of range (0>=4)", STATUS_INVALID_PARAMETER_2 );
  320. return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_2, 0 );
  321. }
  322. Status = CallMiniPortDriverReadWrite(
  323. DeviceExtension,
  324. DeviceExtension->DeviceObject,
  325. FALSE,
  326. &NvramValue,
  327. sizeof(ULONG),
  328. (((PNVRAM_DEVICE_EXTENSION)DeviceExtension)->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS + (NvramBootCounter->Number - 1)) * sizeof(ULONG)
  329. );
  330. if (NT_SUCCESS(Status)) {
  331. NvramBootCounter->Value = NvramValue & 0xf;
  332. NvramBootCounter->DeviceId = NvramValue >> 16;
  333. } else {
  334. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to read boot counter from NVRAM", Status );
  335. }
  336. return CompleteRequest( Irp, Status, sizeof(ULONG) );
  337. }
  338. DECLARE_IOCTL_HANDLER( HandleNvramWriteBootCounter )
  339. /*++
  340. Routine Description:
  341. This routine handles the write boot counter IOCTL for the
  342. NVRAM miniport driver.
  343. Arguments:
  344. DeviceObject - The device object for the target device.
  345. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  346. DeviceExtension - Pointer to the main port driver device extension.
  347. InputBuffer - Pointer to the user's input buffer
  348. InputBufferLength - Length in bytes of the input buffer
  349. OutputBuffer - Pointer to the user's output buffer
  350. OutputBufferLength - Length in bytes of the output buffer
  351. Return Value:
  352. NT status code.
  353. --*/
  354. {
  355. NTSTATUS Status;
  356. PSA_NVRAM_BOOT_COUNTER NvramBootCounter = (PSA_NVRAM_BOOT_COUNTER) InputBuffer;
  357. ULONG NewValue;
  358. if (InputBufferLength != sizeof(SA_NVRAM_BOOT_COUNTER)) {
  359. REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(SA_NVRAM_BOOT_COUNTER)", STATUS_INVALID_BUFFER_SIZE );
  360. return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
  361. }
  362. if (NvramBootCounter->SizeOfStruct != sizeof(SA_NVRAM_BOOT_COUNTER)) {
  363. REPORT_ERROR( DeviceExtension->DeviceType, "SA_NVRAM_BOOT_COUNTER structure wrong size", STATUS_INVALID_PARAMETER_1 );
  364. return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_1, 0 );
  365. }
  366. if (NvramBootCounter->Number == 0 || NvramBootCounter->Number > NVRAM_RESERVED_BOOTCOUNTER_SLOTS) {
  367. REPORT_ERROR( DeviceExtension->DeviceType, "Requested boot counter number is out of range (0>=4)", STATUS_INVALID_PARAMETER_2 );
  368. return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_2, 0 );
  369. }
  370. NewValue = (NvramBootCounter->DeviceId << 16) | (NvramBootCounter->Value & 0xf);
  371. Status = CallMiniPortDriverReadWrite(
  372. DeviceExtension,
  373. DeviceExtension->DeviceObject,
  374. TRUE,
  375. &NewValue,
  376. sizeof(ULONG),
  377. (((PNVRAM_DEVICE_EXTENSION)DeviceExtension)->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS + (NvramBootCounter->Number - 1)) * sizeof(ULONG)
  378. );
  379. if (!NT_SUCCESS(Status)) {
  380. REPORT_ERROR( DeviceExtension->DeviceType, "Failed to write boot counter from NVRAM", Status );
  381. }
  382. return CompleteRequest( Irp, Status, sizeof(ULONG) );
  383. }