UCHAR ProcessorID;
} SYSTEM_PROCESSOR, *PSYSTEM_PROCESSOR;
+typedef struct _SYSTEM_WATCHDOG {
+ ULONG Id;
+ ULONG Seconds;
+} SYSTEM_WATCHDOG, *PSYSTEM_WATCHDOG;
+
typedef struct _SYSTEM_CONTEXT {
LONG References;
PACPI_MADT Madt;
PVOID ProcessorChangeHandle;
PHYSICAL_ADDRESS MaximumPhysicalAddress;
BOOLEAN RealTimeIsUniversal;
+ SYSTEM_WATCHDOG Watchdog;
} SYSTEM_CONTEXT, *PSYSTEM_CONTEXT;
static SYSTEM_CONTEXT SystemContext;
return Context->RealTimeIsUniversal;
}
+XEN_API
+NTSTATUS
+SystemSetWatchdog(
+ IN ULONG Seconds
+ )
+{
+ PSYSTEM_CONTEXT Context = &SystemContext;
+ ULONG Id = Context->Watchdog.Id;
+ NTSTATUS status;
+
+ status = STATUS_INVALID_PARAMETER;
+ if (Seconds == 0)
+ goto fail1;
+
+ status = SchedWatchdog(&Id, Seconds);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ if (Context->Watchdog.Id == 0 || Context->Watchdog.Seconds != Seconds)
+ Info("%u: %us\n", Id, Seconds);
+
+ Context->Watchdog.Id = Id;
+ Context->Watchdog.Seconds = Seconds;
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+XEN_API
+VOID
+SystemStopWatchdog(
+ VOID
+ )
+{
+ PSYSTEM_CONTEXT Context = &SystemContext;
+ NTSTATUS status;
+
+ if (Context->Watchdog.Id == 0)
+ return;
+
+ status = SchedWatchdog(&Context->Watchdog.Id, 0);
+ ASSERT(NT_SUCCESS(status));
+
+ Info("%u\n", Context->Watchdog.Id);
+
+ Context->Watchdog.Id = 0;
+ Context->Watchdog.Seconds = 0;
+}
+
VOID
SystemTeardown(
VOID
ULONG Cpu;
PXENBUS_EVTCHN_CHANNEL Channel;
LARGE_INTEGER TimeStamp;
+ ULONG Count;
} XENBUS_VIRQ, *PXENBUS_VIRQ;
struct _XENBUS_FDO {
PXENBUS_RANGE_SET RangeSet;
LIST_ENTRY InterruptList;
+ ULONG Watchdog;
+
LIST_ENTRY VirqList;
+ HIGH_LOCK VirqLock;
+
PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
PXENBUS_DEBUG_CALLBACK DebugCallback;
PLOG_DISPOSITION LogDisposition;
(ULONG)(Cursor - FdoOutBuffer));
}
+static FORCEINLINE BOOLEAN
+__FdoVirqPatWatchdog(
+ IN PXENBUS_VIRQ Virq
+ )
+{
+ PXENBUS_FDO Fdo = Virq->Fdo;
+ ULONG Cpu;
+ ULONG Count;
+ BOOLEAN Pat;
+ KIRQL Irql;
+ PLIST_ENTRY ListEntry;
+
+ AcquireHighLock(&Fdo->VirqLock, &Irql);
+
+ Cpu = Virq->Cpu;
+ Count = Virq->Count++;
+ Pat = TRUE;
+
+ if (Virq->Count == 0) // wrapped
+ goto out;
+
+ for (ListEntry = Fdo->VirqList.Flink;
+ ListEntry != &Fdo->VirqList;
+ ListEntry = ListEntry->Flink) {
+ Virq = CONTAINING_RECORD(ListEntry, XENBUS_VIRQ, ListEntry);
+
+ if (Virq->Type != VIRQ_TIMER || Virq->Cpu == Cpu)
+ continue;
+
+ if (Virq->Count <= Count)
+ Pat = FALSE;
+ }
+
+out:
+ ReleaseHighLock(&Fdo->VirqLock, Irql);
+
+ return Pat;
+}
+
static
_Function_class_(KSERVICE_ROUTINE)
_IRQL_requires_(HIGH_LEVEL)
break;
case VIRQ_TIMER:
+ if (__FdoVirqPatWatchdog(Virq))
+ SystemSetWatchdog(Fdo->Watchdog);
+
break;
default:
return TRUE;
}
-#define XENBUS_TIMER_PERIOD 10
-
static FORCEINLINE NTSTATUS
__FdoVirqCreate(
IN PXENBUS_FDO Fdo,
)
{
PROCESSOR_NUMBER ProcNumber;
+ unsigned int vcpu_id;
NTSTATUS status;
*Virq = __FdoAllocate(sizeof (XENBUS_VIRQ));
ProcNumber.Group, ProcNumber.Number);
if (Type == VIRQ_TIMER) {
- unsigned int vcpu_id;
LARGE_INTEGER Period;
status = SystemVirtualCpuIndex(Cpu, &vcpu_id);
ASSERT(NT_SUCCESS(status));
- Period.QuadPart = TIME_S(XENBUS_TIMER_PERIOD);
+ BUG_ON(Fdo->Watchdog == 0);
+ Period.QuadPart = TIME_S(Fdo->Watchdog / 2);
- (VOID) VcpuSetPeriodicTimer(vcpu_id, &Period);
+ status = VcpuSetPeriodicTimer(vcpu_id, &Period);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = SystemSetWatchdog(Fdo->Watchdog);
+ if (!NT_SUCCESS(status))
+ goto fail4;
}
(VOID) XENBUS_EVTCHN(Unmask,
return STATUS_SUCCESS;
+fail4:
+ Error("fail4\n");
+
+ (VOID) VcpuSetPeriodicTimer(vcpu_id, NULL);
+
+fail3:
+ Error("fail3\n");
+
+ XENBUS_EVTCHN(Close,
+ &Fdo->EvtchnInterface,
+ (*Virq)->Channel);
+
fail2:
Error("fail2\n");
- __FdoFree(Virq);
+ __FdoFree(*Virq);
fail1:
Error("fail1 (%08x)\n", status);
if (Virq->Type == VIRQ_TIMER) {
unsigned int vcpu_id;
NTSTATUS status;
+
+ SystemStopWatchdog();
status = SystemVirtualCpuIndex(Virq->Cpu, &vcpu_id);
ASSERT(NT_SUCCESS(status));
NTSTATUS status;
InitializeListHead(&Fdo->VirqList);
+ InitializeHighLock(&Fdo->VirqLock);
status = __FdoVirqCreate(Fdo, VIRQ_DEBUG, 0, &Virq);
if (!NT_SUCCESS(status))
InsertTailList(&Fdo->VirqList, &Virq->ListEntry);
+ if (Fdo->Watchdog == 0)
+ goto done;
+
Count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
for (Index = 0; Index < Count; Index++) {
InsertTailList(&Fdo->VirqList, &Virq->ListEntry);
}
+done:
return STATUS_SUCCESS;
fail2:
Fdo->Buffer = NULL;
}
-static BOOLEAN
-FdoIsBalloonEnabled(
+static NTSTATUS
+FdoBalloonInitialize(
IN PXENBUS_FDO Fdo
)
{
BOOLEAN Enabled;
NTSTATUS status;
- UNREFERENCED_PARAMETER(Fdo);
-
Enabled = TRUE;
status = RegistryQuerySystemStartOption(Key, &Option);
RegistryFreeSzValue(Option);
done:
- return Enabled;
+ return Enabled ?
+ BalloonInitialize(Fdo, &Fdo->BalloonContext) :
+ STATUS_SUCCESS;
+}
+
+static VOID
+FdoBalloonTeardown(
+ IN PXENBUS_FDO Fdo
+ )
+{
+ if (Fdo->BalloonContext == NULL)
+ return;
+
+ BalloonTeardown(Fdo->BalloonContext);
+ Fdo->BalloonContext = NULL;
+}
+
+static VOID
+FdoSetWatchdog(
+ IN PXENBUS_FDO Fdo
+ )
+{
+ CHAR Key[] = "XEN:WATCHDOG=";
+ PANSI_STRING Option;
+ ULONG Value;
+ NTSTATUS status;
+
+ status = RegistryQuerySystemStartOption(Key, &Option);
+ if (!NT_SUCCESS(status))
+ return;
+
+ Value = strtoul(Option->Buffer + sizeof (Key) - 1, NULL, 0);
+
+ RegistryFreeSzValue(Option);
+
+ if (Value && Value < 10) {
+ Warning("%u < 10 (ROUNDING UP)\n");
+
+ Value = 10;
+ }
+
+ Fdo->Watchdog = Value;
+
+ if (Fdo->Watchdog != 0)
+ Info("WATCHDOG ENABLED (%us)\n", Fdo->Watchdog);
+ else
+ Info("WATCHDOG DISABLED\n");
}
NTSTATUS
if (!NT_SUCCESS(status))
goto fail19;
- if (FdoIsBalloonEnabled(Fdo)) {
- status = BalloonInitialize(Fdo, &Fdo->BalloonContext);
- if (!NT_SUCCESS(status))
- goto fail20;
- }
+ status = FdoBalloonInitialize(Fdo);
+ if (!NT_SUCCESS(status))
+ goto fail20;
status = DebugGetInterface(__FdoGetDebugContext(Fdo),
XENBUS_DEBUG_INTERFACE_VERSION_MAX,
(VOID) FdoSetFriendlyName(Fdo, Header.DeviceID);
+ FdoSetWatchdog(Fdo);
+
Info("%p (%s) %s\n",
FunctionDeviceObject,
__FdoGetName(Fdo),
RtlZeroMemory(&Fdo->DebugInterface,
sizeof (XENBUS_DEBUG_INTERFACE));
- if (Fdo->BalloonContext != NULL) {
- BalloonTeardown(Fdo->BalloonContext);
- Fdo->BalloonContext = NULL;
- }
+ FdoBalloonTeardown(Fdo);
UnplugTeardown(Fdo->UnplugContext);
Fdo->UnplugContext = NULL;