/*++ Copyright (c) 1991 - 2001 Microsoft Corporation Module Name: ## # ## ## ##### ### ## ## #### ##### ##### ### # ## ## ## ## ### ### ### ## # ## ## ## ## #### # ## ## ## ## ## ## ######## ## ## ## ## ## # #### #### ##### ## ## # ### ## ## ## ## ## ## # ### #### #### ####### # # ## ## ##### ##### # ## ## ## ## ## ## # ## ## ## # ## ## # # ## ## ## ## ## # ## ## #### ## ## Abstract: This module contains functions specfic to the NVRAM device. The logic in this module is not hardware specific, but is logic that is common to all hardware implementations. Author: Wesley Witt (wesw) 1-Oct-2001 Environment: Kernel mode only. Notes: This is a map that shows how the NVRAM is used by the server appliance driver and application layers. This diagram shows and NVRAM configuration of 32 DWORDs of NVRAM, but less is acceptable. Regardless of the NVRAM size, the boot counters and boot times are always stored at the end of the NVRAM array. The upper layers are then free to be used by the application layers. |------------------------------| | [00-00] | |------------------------------| | [01-04] | |------------------------------| | [02-08] | |------------------------------| | [03-0c] | |------------------------------| | [04-10] | |------------------------------| | [05-14] | |------------------------------| | [06-18] | |------------------------------| | [07-1c] | |------------------------------| | [08-20] | |------------------------------| | [09-24] | |------------------------------| | [0a-28] | |------------------------------| | [0b-2c] | |------------------------------| | [0c-30] | |------------------------------| | [0d-34] | |------------------------------| | [0e-38] | |------------------------------| | [0f-3c] | |------------------------------| | [10-40] | |------------------------------| | [11-44] | |------------------------------| | [12-48] | |------------------------------| | [13-4c] | |------------------------------| | [14-50] Shutdown time #1 | |------------------------------| | [16-58] Shutdown time #2 | |------------------------------| | [18-60] Shutdown time #3 | |------------------------------| | [1a-68] Shutdown time #4 | |------------------------------| | [1c-70] Boot Counter #1 | |------------------------------| | [1d-74] Boot Counter #2 | |------------------------------| | [1e-78] Boot Counter #3 | |------------------------------| | [1f-7c] Boot Counter #4 | |------------------------------| --*/ #include "internal.h" NTSTATUS SaNvramStartDevice( IN PNVRAM_DEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: This is the NVRAM specific code for processing the PNP start device request. The NVRAM driver's capabilities are queried, the primary OS is queried, all the NVRAM data is read, and the reboot status is determined. Arguments: DeviceExtension - NVRAM device extension Return Value: NT status code. --*/ { NTSTATUS Status; ULONG InterfaceVersion; ULONG FirstAvailableSlot; ULONG FirstBootCounterSlot; ULONG FullNvramSize; __try { // // Read our parameters from the registry // Status = SaPortReadNumericRegistryValue( DeviceExtension->MiniPortDeviceExtension, L"PrimaryOS", &DeviceExtension->PrimaryOS ); if (!NT_SUCCESS(Status)) { REPORT_ERROR( DeviceExtension->DeviceType, "Missing the PrimaryOS registry parameter, assuming primary\n", Status ); DeviceExtension->PrimaryOS = TRUE; } // // Get the mini-port's interface version // Status = CallMiniPortDriverDeviceControl( DeviceExtension, DeviceExtension->DeviceObject, IOCTL_SA_GET_VERSION, NULL, 0, &InterfaceVersion, sizeof(ULONG) ); if (!NT_SUCCESS(Status)) { ERROR_RETURN( DeviceExtension->DeviceType, "Failed to query the NVRAM driver interface version\n", Status ); } if (InterfaceVersion > SA_INTERFACE_VERSION) { Status = STATUS_NOINTERFACE; ERROR_RETURN( DeviceExtension->DeviceType, "Incompatible NVRAM interface version\n", Status ); } // // Get the mini-port's device capabilities // DeviceExtension->DeviceCaps.SizeOfStruct = sizeof(SA_NVRAM_CAPS); Status = CallMiniPortDriverDeviceControl( DeviceExtension, DeviceExtension->DeviceObject, IOCTL_SA_GET_CAPABILITIES, NULL, 0, &DeviceExtension->DeviceCaps, sizeof(SA_NVRAM_CAPS) ); if (!NT_SUCCESS(Status)) { ERROR_RETURN( DeviceExtension->DeviceType, "Failed to query the NVRAM driver capabilities\n", Status ); } // // Compute the persistent slot numbers // FirstAvailableSlot = DeviceExtension->DeviceCaps.NvramSize; FirstBootCounterSlot = DeviceExtension->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS; DeviceExtension->SlotPowerCycle = FirstAvailableSlot; DeviceExtension->SlotShutDownTime = FirstAvailableSlot - 2; DeviceExtension->SlotBootCounter = FirstBootCounterSlot; // // Read the NVRAM data // FullNvramSize = (DeviceExtension->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS + NVRAM_RESERVED_BOOTCOUNTER_SLOTS) * sizeof(ULONG); DeviceExtension->NvramData = (PULONG) ExAllocatePool( PagedPool, FullNvramSize ); if (DeviceExtension->NvramData == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; ERROR_RETURN( DeviceExtension->DeviceType, "Failed to allocate pool\n", Status ); } Status = CallMiniPortDriverReadWrite( DeviceExtension, DeviceExtension->DeviceObject, FALSE, DeviceExtension->NvramData, FullNvramSize, 0 ); if (!NT_SUCCESS(Status)) { ERROR_RETURN( DeviceExtension->DeviceType, "Failed to read the NVRAM boot counters\n", Status ); } DebugPrint(( DeviceExtension->DeviceType, SAPORT_DEBUG_INFO_LEVEL, "Boot counters [%08x] [%08x] [%08x] [%08x]\n", DeviceExtension->NvramData[FirstBootCounterSlot+0], DeviceExtension->NvramData[FirstBootCounterSlot+1], DeviceExtension->NvramData[FirstBootCounterSlot+2], DeviceExtension->NvramData[FirstBootCounterSlot+3] )); Status = STATUS_SUCCESS; } __finally { if (!NT_SUCCESS(Status)) { if (DeviceExtension->NvramData) { ExFreePool( DeviceExtension->NvramData ); } } } return STATUS_SUCCESS; } NTSTATUS SaNvramDeviceInitialization( IN PSAPORT_DRIVER_EXTENSION DriverExtension ) /*++ Routine Description: This is the NVRAM specific code for driver initialization. This function is called by SaPortInitialize, which is called by the NVRAM driver's DriverEntry function. Arguments: DriverExtension - Driver extension structure Return Value: NT status code. --*/ { return STATUS_SUCCESS; } NTSTATUS SaNvramIoValidation( IN PNVRAM_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp, PIO_STACK_LOCATION IrpSp ) /*++ Routine Description: This is the NVRAM specific code for processing all I/O validation for reads and writes. Arguments: DeviceExtension - NVRAM device extension Irp - Pointer to an IRP structure that describes the requested I/O operation. IrpSp - Irp stack pointer Return Value: NT status code. --*/ { ULONG ByteOffset; ULONG Length; if (IrpSp->MajorFunction == IRP_MJ_READ) { ByteOffset = (ULONG)IrpSp->Parameters.Read.ByteOffset.QuadPart; Length = (ULONG)IrpSp->Parameters.Read.Length; } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) { ByteOffset = (ULONG)IrpSp->Parameters.Write.ByteOffset.QuadPart; Length = (ULONG)IrpSp->Parameters.Write.Length; } else { REPORT_ERROR( DeviceExtension->DeviceType, "Invalid I/O request", STATUS_INVALID_PARAMETER_1 ); return STATUS_INVALID_PARAMETER_1; } if (((ByteOffset + Length) / sizeof(ULONG)) > DeviceExtension->DeviceCaps.NvramSize) { REPORT_ERROR( DeviceExtension->DeviceType, "I/O length too large", STATUS_INVALID_PARAMETER_2 ); return STATUS_INVALID_PARAMETER_2; } return STATUS_SUCCESS; } NTSTATUS SaNvramShutdownNotification( IN PNVRAM_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp, PIO_STACK_LOCATION IrpSp ) /*++ Routine Description: This is the NVRAM specific code for processing the system shutdown notification. Here we need to record the shutdown timestam to the appropriate NVRAM slot. Arguments: DeviceExtension - Display device extension Irp - Pointer to an IRP structure that describes the requested I/O operation. IrpSp - Irp stack pointer Return Value: NT status code. --*/ { NTSTATUS Status; LARGE_INTEGER CurrentTime; KeQuerySystemTime( &CurrentTime ); Status = CallMiniPortDriverReadWrite( DeviceExtension, DeviceExtension->DeviceObject, TRUE, &CurrentTime.QuadPart, sizeof(LONGLONG), DeviceExtension->SlotShutDownTime * sizeof(ULONG) ); if (!NT_SUCCESS(Status)) { REPORT_ERROR( DeviceExtension->DeviceType, "Failed to write the shutdown timestamp to NVRAM", Status ); return Status; } return STATUS_SUCCESS; } DECLARE_IOCTL_HANDLER( HandleNvramReadBootCounter ) /*++ Routine Description: This routine handles the read boot counter IOCTL for the NVRAM miniport driver. Arguments: DeviceObject - The device object for the target device. Irp - Pointer to an IRP structure that describes the requested I/O operation. DeviceExtension - Pointer to the main port driver device extension. InputBuffer - Pointer to the user's input buffer InputBufferLength - Length in bytes of the input buffer OutputBuffer - Pointer to the user's output buffer OutputBufferLength - Length in bytes of the output buffer Return Value: NT status code. --*/ { NTSTATUS Status; PSA_NVRAM_BOOT_COUNTER NvramBootCounter = (PSA_NVRAM_BOOT_COUNTER) OutputBuffer; ULONG NvramValue; if (OutputBufferLength != sizeof(SA_NVRAM_BOOT_COUNTER)) { REPORT_ERROR( DeviceExtension->DeviceType, "Output buffer != sizeof(SA_NVRAM_BOOT_COUNTER)", STATUS_INVALID_BUFFER_SIZE ); return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 ); } if (NvramBootCounter->SizeOfStruct != sizeof(SA_NVRAM_BOOT_COUNTER)) { REPORT_ERROR( DeviceExtension->DeviceType, "SA_NVRAM_BOOT_COUNTER structure wrong size", STATUS_INVALID_PARAMETER_1 ); return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_1, 0 ); } if (NvramBootCounter->Number == 0 || NvramBootCounter->Number > NVRAM_RESERVED_BOOTCOUNTER_SLOTS) { REPORT_ERROR( DeviceExtension->DeviceType, "Requested boot counter number is out of range (0>=4)", STATUS_INVALID_PARAMETER_2 ); return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_2, 0 ); } Status = CallMiniPortDriverReadWrite( DeviceExtension, DeviceExtension->DeviceObject, FALSE, &NvramValue, sizeof(ULONG), (((PNVRAM_DEVICE_EXTENSION)DeviceExtension)->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS + (NvramBootCounter->Number - 1)) * sizeof(ULONG) ); if (NT_SUCCESS(Status)) { NvramBootCounter->Value = NvramValue & 0xf; NvramBootCounter->DeviceId = NvramValue >> 16; } else { REPORT_ERROR( DeviceExtension->DeviceType, "Failed to read boot counter from NVRAM", Status ); } return CompleteRequest( Irp, Status, sizeof(ULONG) ); } DECLARE_IOCTL_HANDLER( HandleNvramWriteBootCounter ) /*++ Routine Description: This routine handles the write boot counter IOCTL for the NVRAM miniport driver. Arguments: DeviceObject - The device object for the target device. Irp - Pointer to an IRP structure that describes the requested I/O operation. DeviceExtension - Pointer to the main port driver device extension. InputBuffer - Pointer to the user's input buffer InputBufferLength - Length in bytes of the input buffer OutputBuffer - Pointer to the user's output buffer OutputBufferLength - Length in bytes of the output buffer Return Value: NT status code. --*/ { NTSTATUS Status; PSA_NVRAM_BOOT_COUNTER NvramBootCounter = (PSA_NVRAM_BOOT_COUNTER) InputBuffer; ULONG NewValue; if (InputBufferLength != sizeof(SA_NVRAM_BOOT_COUNTER)) { REPORT_ERROR( DeviceExtension->DeviceType, "Input buffer != sizeof(SA_NVRAM_BOOT_COUNTER)", STATUS_INVALID_BUFFER_SIZE ); return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 ); } if (NvramBootCounter->SizeOfStruct != sizeof(SA_NVRAM_BOOT_COUNTER)) { REPORT_ERROR( DeviceExtension->DeviceType, "SA_NVRAM_BOOT_COUNTER structure wrong size", STATUS_INVALID_PARAMETER_1 ); return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_1, 0 ); } if (NvramBootCounter->Number == 0 || NvramBootCounter->Number > NVRAM_RESERVED_BOOTCOUNTER_SLOTS) { REPORT_ERROR( DeviceExtension->DeviceType, "Requested boot counter number is out of range (0>=4)", STATUS_INVALID_PARAMETER_2 ); return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_2, 0 ); } NewValue = (NvramBootCounter->DeviceId << 16) | (NvramBootCounter->Value & 0xf); Status = CallMiniPortDriverReadWrite( DeviceExtension, DeviceExtension->DeviceObject, TRUE, &NewValue, sizeof(ULONG), (((PNVRAM_DEVICE_EXTENSION)DeviceExtension)->DeviceCaps.NvramSize + NVRAM_RESERVED_DRIVER_SLOTS + (NvramBootCounter->Number - 1)) * sizeof(ULONG) ); if (!NT_SUCCESS(Status)) { REPORT_ERROR( DeviceExtension->DeviceType, "Failed to write boot counter from NVRAM", Status ); } return CompleteRequest( Irp, Status, sizeof(ULONG) ); }