diff --git a/reactos/boot/bootdata/hivesys.inf b/reactos/boot/bootdata/hivesys.inf index b027a70a8ce..5c5f94e0b4e 100644 --- a/reactos/boot/bootdata/hivesys.inf +++ b/reactos/boot/bootdata/hivesys.inf @@ -1149,6 +1149,8 @@ HKLM,"SYSTEM\CurrentControlSet\Control\SecurityProviders\SaslProfiles",,0x000000 ; Service groups HKLM,"SYSTEM\CurrentControlSet\Control\ServiceGroupOrder","List",0x00010000, \ + "System Reserved", \ + "EMS", \ "Boot Bus Extender", \ "System Bus Extender", \ "SCSI Miniport", \ @@ -1342,6 +1344,13 @@ HKLM,"SYSTEM\CurrentControlSet\Services\DHCP","Start",0x00010001,0x00000002 HKLM,"SYSTEM\CurrentControlSet\Services\DHCP","Type",0x00010001,0x00000020 HKLM,"SYSTEM\CurrentControlSet\Services\DHCP\Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dhcpcsvc.dll" +; EMS Serial Administration Console Driver +HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","ErrorControl",0x00010001,0x00000000 +HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","Group",0x00000000,"EMS" +HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","ImagePath",0x00020000,"system32\drivers\sacdrv.sys" +HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","Start",0x00010001,0x00000000 +HKLM,"SYSTEM\CurrentControlSet\Services\NMIDebug","Type",0x00010001,0x00000001 + ; Event logging service HKLM,"SYSTEM\CurrentControlSet\Services\EventLog",,0x00000010 HKLM,"SYSTEM\CurrentControlSet\Services\EventLog","DisplayName",0x00000000,"Event Logger" diff --git a/reactos/boot/bootdata/txtsetup.sif b/reactos/boot/bootdata/txtsetup.sif index b34c51ef883..d2675d94f39 100644 --- a/reactos/boot/bootdata/txtsetup.sif +++ b/reactos/boot/bootdata/txtsetup.sif @@ -18,6 +18,7 @@ FreeSysPartDiskSpace=350 [SourceDisksFiles] acpi.sys=,,,,,,,,,,,,4 nmidebug.sys=,,,,,,x,,,,,,4 +sacdrv.sys=,,,,,,x,,,,,,4 uniata.sys=,,,,,,x,,,,,,4 buslogic.sys=,,,,,,x,,,,,,4 blue.sys=,,,,,,x,,,,,,4 diff --git a/reactos/drivers/CMakeLists.txt b/reactos/drivers/CMakeLists.txt index fcfaa9396d8..be7f2a02b76 100644 --- a/reactos/drivers/CMakeLists.txt +++ b/reactos/drivers/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(input) add_subdirectory(ksfilter) add_subdirectory(network) add_subdirectory(parallel) +add_subdirectory(sac) add_subdirectory(serial) add_subdirectory(setup) add_subdirectory(storage) diff --git a/reactos/drivers/sac/CMakeLists.txt b/reactos/drivers/sac/CMakeLists.txt new file mode 100644 index 00000000000..987710ae04a --- /dev/null +++ b/reactos/drivers/sac/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(driver) diff --git a/reactos/drivers/sac/driver/CMakeLists.txt b/reactos/drivers/sac/driver/CMakeLists.txt new file mode 100644 index 00000000000..187402740c5 --- /dev/null +++ b/reactos/drivers/sac/driver/CMakeLists.txt @@ -0,0 +1,19 @@ + +list(APPEND SOURCE + chanmgr.c + channel.c + cmdchan.c + concmd.c + conmgr.c + data.c + dispatch.c + init.c + memory.c + rawchan.c + util.c + vtutf8chan.c) + +add_library(sacdrv SHARED ${SOURCE} sacdrv.rc) +set_module_type(sacdrv kernelmodedriver) +add_importlibs(sacdrv ntoskrnl hal) +add_cd_file(TARGET sacdrv DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/sac/driver/chanmgr.c b/reactos/drivers/sac/driver/chanmgr.c index 1a655d92c02..bf65042a3ee 100644 --- a/reactos/drivers/sac/driver/chanmgr.c +++ b/reactos/drivers/sac/driver/chanmgr.c @@ -1,176 +1,717 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/chanmgr.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/chanmgr.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +SAC_CHANNEL_LOCK ChannelCreateLock; +BOOLEAN ChannelCreateEnabled; +PSAC_CHANNEL ChannelArray[SAC_MAX_CHANNELS]; +LONG ChannelRefCount[SAC_MAX_CHANNELS]; +LONG ChannelReaped[SAC_MAX_CHANNELS]; +SAC_CHANNEL_LOCK ChannelSlotLock[SAC_MAX_CHANNELS]; +LONG CurrentChannelRefCount; +KMUTEX CurrentChannelLock; -NTSTATUS -ChanMgrInitialize( - VOID - ) +/* FUNCTIONS *****************************************************************/ + +#define MAX_REF_COUNT 100 + +#define CHANNEL_SLOT_IS_IN_USE(x) (ChannelRefCount[(x)] > 0) + +FORCEINLINE +PSAC_CHANNEL +ChannelFromIndex(IN ULONG Index) { - return STATUS_NOT_IMPLEMENTED; + return ChannelArray[Index]; } -NTSTATUS -ChanMgrGetChannelIndex( - IN PSAC_CHANNEL Channel, - IN PULONG ChannelIndex - ) +FORCEINLINE +LONG +ChannelGetReferenceCount(IN LONG Index) { - return STATUS_NOT_IMPLEMENTED; + return ChannelRefCount[Index]; } -NTSTATUS -ChanMgrReleaseChannel( - IN PSAC_CHANNEL Channel - ) +FORCEINLINE +LONG +ChannelReferenceByIndex(IN LONG Index) { - return STATUS_NOT_IMPLEMENTED; + if (ChannelGetReferenceCount(Index) > 0) + { + ASSERT(ChannelRefCount[Index] <= MAX_REF_COUNT); + ASSERT(ChannelRefCount[Index] >= 1); + _InterlockedIncrement(&ChannelRefCount[Index]); + ASSERT(ChannelRefCount[Index] <= MAX_REF_COUNT); + ASSERT(ChannelRefCount[Index] >= 2); + } + + return ChannelGetReferenceCount(Index); } -NTSTATUS -ChanMgrGetByHandle( - IN PSAC_CHANNEL_ID ChannelId, - OUT PSAC_CHANNEL pChannel - ) +FORCEINLINE +LONG +ChannelReferenceByIndexWithLock(IN LONG Index) { - return STATUS_NOT_IMPLEMENTED; + LONG RefCount; + + ChannelSlotLock(Index); + RefCount = ChannelReferenceByIndex(Index); + ChannelSlotUnlock(Index); + return RefCount; } -NTSTATUS -ChanMgrGetByHandleAndFileObject( - IN PSAC_CHANNEL_ID ChannelId, - IN PFILE_OBJECT FileObject, - OUT PSAC_CHANNEL pChannel - ) +FORCEINLINE +LONG +ChannelDereferenceByIndex(IN LONG Index) { - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChanMgrGetChannelByName( - IN PWCHAR Name, - OUT PSAC_CHANNEL pChannel - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChanMgrGetByIndex( - IN ULONG TargetIndex, - IN PSAC_CHANNEL *TargetChannel - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChanMgrGetNextActiveChannel( - IN PSAC_CHANNEL CurrentChannel, - IN PULONG TargetIndex, - OUT PSAC_CHANNEL *TargetChannel - ) -{ - return STATUS_NOT_IMPLEMENTED; + ASSERT(ChannelGetReferenceCount(Index) <= MAX_REF_COUNT); + ASSERT(ChannelGetReferenceCount(Index) > 1); + _InterlockedDecrement(&ChannelRefCount[Index]); + ASSERT(ChannelGetReferenceCount(Index) >= 1); + return ChannelGetReferenceCount(Index); } +FORCEINLINE VOID -ChanMgrChannelDestroy( - IN PSAC_CHANNEL Channel - ) +ChannelDereferenceByIndexWithLock(IN LONG Index) { + ChannelSlotLock(Index); + ChannelDereferenceByIndex(Index); + ChannelSlotUnlock(Index); +} +FORCEINLINE +VOID +ChannelDereferenceToZeroByIndex(IN LONG Index) +{ + ASSERT(ChannelGetReferenceCount(Index) == 1); + ASSERT(ChannelIsActive(ChannelFromIndex(Index)) == FALSE); + _InterlockedExchange(&ChannelRefCount[Index], 0); +} + +FORCEINLINE +VOID +ChannelReferenceToOneByIndex(IN LONG Index) +{ + ASSERT(ChannelGetReferenceCount(Index) == 0); + _InterlockedExchange(&ChannelRefCount[Index], 1); +} + +FORCEINLINE +VOID +ChannelReferenceToOneByIndexWithLock(IN LONG Index) +{ + ChannelSlotLock(Index); + ASSERT(ChannelGetReferenceCount((Index)) == 1); + _InterlockedExchange(&ChannelRefCount[Index], 1); + ChannelSlotUnlock(Index); } NTSTATUS -ChanMgrCloseChannel( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChanMgrInitialize(VOID) { - return STATUS_NOT_IMPLEMENTED; + ULONG i; + + /* Initialize the channel lock */ + SacInitializeLock(&ChannelCreateLock); + ChannelCreateEnabled = TRUE; + + /* Loop through the channel arrays */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* Clear and initialize their locks */ + ChannelArray[i] = NULL; + SacInitializeLock(&ChannelSlotLock[i]); + + /* Clear their statuses and reference counts */ + _InterlockedExchange(&ChannelRefCount[i], 0); + _InterlockedExchange(&ChannelReaped[i], 1); + } + + /* All good */ + return STATUS_SUCCESS; } NTSTATUS -ChanMgrReapChannel( - IN ULONG ChannelIndex - ) +NTAPI +ChanMgrShutdown(VOID) { - return STATUS_NOT_IMPLEMENTED; + /* FIXME: TODO */ + return STATUS_NOT_IMPLEMENTED; } NTSTATUS -ChanMgrReapChannels( - VOID - ) +NTAPI +ChanMgrGetChannelByName(IN PWCHAR Name, + OUT PSAC_CHANNEL* Channel) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status, Status1; + ULONG i; + PSAC_CHANNEL CurrentChannel; + PWCHAR ChannelName; + BOOLEAN Found; + CHECK_PARAMETER1(Name); + CHECK_PARAMETER2(Channel); + + /* Assume failure */ + *Channel = NULL; + Status = STATUS_NOT_FOUND; + + /* Loop through all channels */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* Reference this one and check if it's valid */ + if (ChannelReferenceByIndexWithLock(i) > 0) + { + /* All good, grab it */ + CurrentChannel = ChannelFromIndex(i); + ASSERT(CurrentChannel != NULL); + + /* Get its name */ + Status1 = ChannelGetName(CurrentChannel, &ChannelName); + ASSERT(NT_SUCCESS(Status1)); + + /* Check if this is the name that was passed in */ + Found = wcsicmp(Name, ChannelName); + SacFreePool(ChannelName); + if (Found) + { + /* We found it, return it (with a reference held) */ + *Channel = CurrentChannel; + return STATUS_SUCCESS; + } + + /* Not the one we want, dereference this one and keep going */ + ChannelDereferenceByIndexWithLock(i); + } + } + + /* No channels with this name were found */ + return Status; } NTSTATUS -ChanMgrGetChannelCount( - OUT PULONG ChannelCount - ) +NTAPI +ChanMgrGetByHandle(IN SAC_CHANNEL_ID ChannelId, + OUT PSAC_CHANNEL* TargetChannel) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + ULONG i; + PSAC_CHANNEL Channel; + CHECK_PARAMETER2(TargetChannel); + + /* Assume failure */ + *TargetChannel = NULL; + Status = STATUS_NOT_FOUND; + + /* Loop through all channels */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* Reference this one and check if it's valid */ + if (ChannelReferenceByIndexWithLock(i) > 0) + { + /* All good, grab it */ + Channel = ChannelFromIndex(i); + ASSERT(Channel != NULL); + + /* Check if the channel ID matches */ + if (ChannelIsEqual(Channel, &ChannelId)) + { + /* We found it, return it (with a reference held) */ + *TargetChannel = Channel; + return STATUS_SUCCESS; + } + + /* Not the one we want, dereference this one and keep going */ + ChannelDereferenceByIndexWithLock(i); + } + } + + /* No channels with this ID were found */ + return Status; } NTSTATUS -ChanMgrIsFull( - OUT PBOOLEAN IsFull - ) +NTAPI +ChanMgrReleaseChannel(IN PSAC_CHANNEL Channel) { - return STATUS_NOT_IMPLEMENTED; -} + LONG Index; + ULONG RefCount; + PSAC_CHANNEL ThisChannel; + CHECK_PARAMETER(Channel); -NTSTATUS -ChanMgrShutdown( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; + /* Get the index of the channel */ + Index = ChannelGetIndex(Channel); + + /* Drop a reference -- there should still be at least the keepalive left */ + ChannelSlotLock(Index); + RefCount = ChannelDereferenceByIndex(Index); + ASSERT(RefCount > 0); + + /* Do we only have the keep-alive left, and the channel is dead? */ + if ((RefCount == 1) && !(ChannelIsActive(Channel))) + { + /* Check if the ??? flag is set, or if there's no output data */ + ThisChannel = ChannelFromIndex(Index); + if (!(ThisChannel->Flags & 1)) + { + /* Nope, we can wipe the references and get rid of it */ + ChannelDereferenceToZeroByIndex(Index); + } + else if (!ThisChannel->ChannelHasNewOBufferData) + { + /* No data, we can wipe the references and get rid of it */ + ChannelDereferenceToZeroByIndex(Index); + } + } + + /* We're done, we can unlock the slot now */ + ChannelSlotUnlock(Index); + return STATUS_SUCCESS; } BOOLEAN -ChanMgrIsUniqueName( - IN PWCHAR ChannelName - ) +NTAPI +ChanMgrIsUniqueName(IN PWCHAR ChannelName) { - return FALSE; + NTSTATUS Status; + BOOLEAN IsUnique = FALSE; + PSAC_CHANNEL Channel; + + /* Check if a channel with this name already exists */ + Status = ChanMgrGetChannelByName(ChannelName, &Channel); + if (Status == STATUS_NOT_FOUND) IsUnique = TRUE; + + /* If one did, dereference it, all we wanted was to check uniqueness */ + if (NT_SUCCESS(Status)) ChanMgrReleaseChannel(Channel); + + /* Return if one was found or not */ + return IsUnique; } NTSTATUS -ChanMgrGenerateUniqueCmdName( - IN PWCHAR ChannelName - ) +NTAPI +ChanMgrReapChannel(IN ULONG ChannelIndex) { - return STATUS_NOT_IMPLEMENTED; + /* FIXME: TODO */ + return STATUS_NOT_IMPLEMENTED; } NTSTATUS -ChanMgrCreateChannel( - OUT PSAC_CHANNEL *Channel, - IN PSAC_CHANNEL_ATTRIBUTES Attributes - ) +NTAPI +ChanMgrReapChannels(VOID) { - return STATUS_NOT_IMPLEMENTED; + ULONG i; + NTSTATUS Status = STATUS_SUCCESS; + + /* Loop all the channels */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* Lock this index and see if the channel was reaped */ + ChannelSlotLock(i); + if (!ChannelReaped[i]) + { + /* It was not reaped yet, so a channel should still be here */ + ASSERT(ChannelFromIndex(i) != NULL); + if (ChannelGetReferenceCount(i) <= 0) + { + /* The channel has no more references, so clear the buffer flags */ + _InterlockedExchange(&ChannelArray[i]->ChannelHasNewIBufferData, 0); + _InterlockedExchange(&ChannelArray[i]->ChannelHasNewOBufferData, 0); + + /* And reap it */ + Status = ChanMgrReapChannel(i); + } + } + + /* Release the lock, and move on unless reaping failed */ + ChannelSlotUnlock(i); + if (!NT_SUCCESS(Status)) break; + } + + /* Return reaping status */ + return Status; } NTSTATUS -ChanMgrCloseChannelsWithFileObject( - IN PFILE_OBJECT FileObject - ) +NTAPI +ChanMgrCreateChannel(OUT PSAC_CHANNEL *Channel, + IN PSAC_CHANNEL_ATTRIBUTES Attributes) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + PSAC_CHANNEL NewChannel; + SAC_CHANNEL_ID ChanId; + ULONG i; + CHECK_PARAMETER(Channel); + CHECK_PARAMETER2(Attributes); + + /* No other channel create attempts can happen */ + ChannelLockCreates(); + + /* Is the channel manager initialized? */ + if (ChannelCreateEnabled) + { + /* Nope, bail out */ + Status = STATUS_UNSUCCESSFUL; + goto ReturnStatus; + } + + /* Reap any zombie channels */ + Status = ChanMgrReapChannels(); + if (!NT_SUCCESS(Status)) + { + /* Bail out on error */ + Status = STATUS_UNSUCCESSFUL; + goto ReturnStatus; + } + + /* Check if we already have a channel with this name */ + if (!ChanMgrIsUniqueName(Attributes->NameBuffer)) + { + /* We do, fail */ + Status = STATUS_DUPLICATE_NAME; + goto ReturnStatus; + } + + /* Allocate this channel */ + NewChannel = SacAllocatePool(sizeof(SAC_CHANNEL), CHANNEL_BLOCK_TAG); + CHECK_PARAMETER_WITH_STATUS(NewChannel, STATUS_NO_MEMORY); // bug + RtlZeroMemory(NewChannel, sizeof(SAC_CHANNEL)); + + /* Loop channel slots */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* Find a free spot for it */ + if (ChannelReaped[i]) + { + /* Free slot found, attempt to use it */ + ASSERT(!CHANNEL_SLOT_IS_IN_USE(i)); + _InterlockedCompareExchangePointer((void* volatile*)&ChannelArray[i], NewChannel, NULL); + if (ChannelArray[i] == NewChannel) break; + } + } + + /* Did we not find a single free slot? */ + if (i == SAC_MAX_CHANNELS) + { + /* Bail out */ + Status = STATUS_UNSUCCESSFUL; + goto ReturnStatus; + } + + /* Create an ID for this channel */ + RtlZeroMemory(&ChanId, sizeof(ChanId)); + Status = ExUuidCreate(&ChanId.ChannelGuid); + if (!NT_SUCCESS(Status)) + { + /* Bail out if we couldn't */ + SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to get GUID\n"); + goto ReturnStatus; + } + + /* Now create the channel proper */ + Status = ChannelCreate(NewChannel, Attributes, ChanId); + if (NT_SUCCESS(Status)) + { + /* Set the channel index */ + _InterlockedExchange(&NewChannel->Index, i); + + /* Add the initial reference to the channel */ + ChannelReferenceToOneByIndexWithLock(i); + + /* Return it to the caller */ + *Channel = NewChannel; + + /* This slot is now occupied */ + ASSERT(ChannelReaped[i] == 1); + _InterlockedExchange(&ChannelReaped[i], 0); + } + else + { + /* We couldn't create it, free the buffer */ + SacFreePool(NewChannel); + } + +ReturnStatus: + /* Return whatever the operation status was */ + ChannelUnlockCreates(); + return Status; +} + +NTSTATUS +NTAPI +ChanMgrGetByHandleAndFileObject(IN SAC_CHANNEL_ID ChannelId, + IN PFILE_OBJECT FileObject, + OUT PSAC_CHANNEL* TargetChannel) +{ + NTSTATUS Status; + PSAC_CHANNEL FoundChannel; + + /* Lookup the channel by ID first */ + Status = ChanMgrGetByHandle(ChannelId, &FoundChannel); + if (NT_SUCCESS(Status)) + { + /* We found it, now check if the file object matches */ + if (FoundChannel->FileObject == FileObject) + { + /* Yep, return success */ + *TargetChannel = FoundChannel; + } + else + { + /* Nope, drop the reference on the channel */ + ChanMgrReleaseChannel(FoundChannel); + + /* And return failure */ + *TargetChannel = NULL; + Status = STATUS_NOT_FOUND; + } + } + + /* Return if we found it or not */ + return Status; +} + +NTSTATUS +NTAPI +ChanMgrGetChannelIndex(IN PSAC_CHANNEL Channel, + IN PLONG ChannelIndex) +{ + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(ChannelIndex); + + /* Just return the index of the channel */ + *ChannelIndex = ChannelGetIndex(Channel); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChanMgrGetByIndex(IN LONG TargetIndex, + IN PSAC_CHANNEL* TargetChannel) +{ + NTSTATUS Status; + CHECK_PARAMETER1(TargetIndex < SAC_MAX_CHANNELS); + CHECK_PARAMETER2(TargetChannel); + + /* Assume failure */ + *TargetChannel = NULL; + Status = STATUS_NOT_FOUND; + + /* Reference this one and check if it's valid */ + if (ChannelReferenceByIndexWithLock(TargetIndex) > 0) + { + /* We found it, return it (with a reference held) */ + *TargetChannel = ChannelFromIndex(TargetIndex); + return STATUS_SUCCESS; + } + + /* No channels with this ID were found */ + return Status; +} + +NTSTATUS +NTAPI +ChanMgrGetNextActiveChannel(IN PSAC_CHANNEL CurrentChannel, + IN PULONG TargetIndex, + OUT PSAC_CHANNEL *TargetChannel) +{ + NTSTATUS Status; + ULONG i; + LONG ChannelIndex, StartIndex; + PSAC_CHANNEL FoundChannel; + BOOLEAN ChannelFound; + CHECK_PARAMETER1(CurrentChannel); + CHECK_PARAMETER2(TargetIndex); + CHECK_PARAMETER3(TargetChannel); + + /* Get the current channel index */ + Status = ChanMgrGetChannelIndex(CurrentChannel, &ChannelIndex); + if (!NT_SUCCESS(Status)) return Status; + + /* Assume failure */ + ChannelFound = FALSE; + + /* Loop through all the possible active channels */ + StartIndex = (ChannelIndex + 1) % SAC_MAX_CHANNELS; + for (i = StartIndex; i != StartIndex; i = (i + 1) % SAC_MAX_CHANNELS) + { + /* Get the channel and see if it exists*/ + Status = ChanMgrGetByIndex(i, &FoundChannel); + if (Status != STATUS_NOT_FOUND) + { + /* Bail out if we failed for some reason */ + if (!NT_SUCCESS(Status)) return Status; + + /* It exists -- is it active? Or, does it have output data? */ + if ((ChannelIsActive(FoundChannel)) || + (!(ChannelIsActive(FoundChannel)) && + (FoundChannel->ChannelHasNewOBufferData))) + { + /* It's active or has output data, return with it */ + ChannelFound = TRUE; + break; + } + + /* Drop the reference on this channel and try the next one */ + Status = ChanMgrReleaseChannel(FoundChannel); + if (!NT_SUCCESS(Status)) return Status; + } + } + + /* Check if we successfully found a channel */ + if ((NT_SUCCESS(Status)) && (ChannelFound)) + { + /* Return it and its indexed. Remember we still hold the reference */ + *TargetIndex = i; + *TargetChannel = FoundChannel; + } + + /* All done */ + return Status; +} + +NTSTATUS +NTAPI +ChanMgrChannelDestroy(IN PSAC_CHANNEL Channel) +{ + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER(ChannelGetReferenceCount(Channel->Index) > 0); + + /* Destroy the channel */ + return Channel->ChannelDestroy(Channel); +} + +NTSTATUS +NTAPI +ChanMgrCloseChannel(IN PSAC_CHANNEL Channel) +{ + NTSTATUS Status; + CHECK_PARAMETER(Channel); + + /* Check if the channel is active */ + if (ChannelIsActive(Channel)) + { + /* Yep, close it */ + Status = ChannelClose(Channel); + } + else + { + /* Nothing to do */ + Status = STATUS_ALREADY_DISCONNECTED; + } + + /* Handle the channel close */ + ConMgrHandleEvent(TRUE, Channel, &Status); + return Status; +} + +NTSTATUS +NTAPI +ChanMgrGetChannelCount(OUT PULONG ChannelCount) +{ + ULONG i; + PSAC_CHANNEL Channel; + NTSTATUS Status; + CHECK_PARAMETER(ChannelCount); + + /* Assume no channels */ + *ChannelCount = 0; + + /* Loop every channel */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* See if this one exists */ + Status = ChanMgrGetByIndex(i, &Channel); + if (Status != STATUS_NOT_FOUND) + { + /* Sanity checks*/ + ASSERT(NT_SUCCESS(Status)); + ASSERT(Channel != NULL); + + /* It exists -- is it active? Or, does it have output data? */ + if ((ChannelIsActive(Channel)) || + (!(ChannelIsActive(Channel)) && + (Channel->ChannelHasNewOBufferData))) + { + /* It's active or has output data, increase the count */ + ++*ChannelCount; + break; + } + + /* Drop the reference on this channel and try the next one */ + Status = ChanMgrReleaseChannel(Channel); + if (!NT_SUCCESS(Status)) return Status; + } + else + { + /* Channel doesn't exist, nothing wrong with that, keep going */ + Status = STATUS_SUCCESS; + } + } + + /* We should always succeed if we get here */ + ASSERT(NT_SUCCESS(Status)); + return Status; +} + +NTSTATUS +NTAPI +ChanMgrIsFull(OUT PBOOLEAN IsFull) +{ + NTSTATUS Status; + ULONG Count; + + /* Count the channels */ + Status = ChanMgrGetChannelCount(&Count); + CHECK_PARAMETER(Status == STATUS_SUCCESS); + + /* Return if we hit the limit */ + *IsFull = (Count == SAC_MAX_CHANNELS); + return Status; +} + +NTSTATUS +NTAPI +ChanMgrCloseChannelsWithFileObject(IN PFILE_OBJECT FileObject) +{ + PSAC_CHANNEL Channel; + ULONG i; + NTSTATUS Status; + CHECK_PARAMETER1(FileObject); + + /* Loop all channels */ + for (i = 0; i < SAC_MAX_CHANNELS; i++) + { + /* Try to get this one */ + Status = ChanMgrGetByIndex(i, &Channel); + if (!NT_SUCCESS(Status)) break; + + /* Check if the FO matches, if so, close the channel */ + if (Channel->FileObject == FileObject) ChanMgrCloseChannel(Channel); + + /* Drop the reference and try the next channel(s) */ + Status = ChanMgrReleaseChannel(Channel); + if (!NT_SUCCESS(Status)) break; + } + + /* All done */ + return Status; +} + +NTSTATUS +NTAPI +ChanMgrGenerateUniqueCmdName(IN PWCHAR ChannelName) +{ + return STATUS_NOT_IMPLEMENTED; } diff --git a/reactos/drivers/sac/driver/channel.c b/reactos/drivers/sac/driver/channel.c index 154097ebec0..0ee165d7066 100644 --- a/reactos/drivers/sac/driver/channel.c +++ b/reactos/drivers/sac/driver/channel.c @@ -1,318 +1,568 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/channel.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/channel.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +/* FUNCTIONS *****************************************************************/ BOOLEAN -ChannelIsValidType( - IN SAC_CHANNEL_TYPE ChannelType - ) +NTAPI +ChannelIsValidType(IN SAC_CHANNEL_TYPE ChannelType) { - return ((ChannelType >= VtUtf8) && (ChannelType <= Raw)); + /* Check if the type is valid */ + return ((ChannelType >= VtUtf8) && (ChannelType <= Raw)); } BOOLEAN -ChannelIsEqual( - IN PSAC_CHANNEL Channel, - IN PSAC_CHANNEL_ID ChannelId - ) +NTAPI +ChannelIsEqual(IN PSAC_CHANNEL Channel, + IN PSAC_CHANNEL_ID ChannelId) { - return IsEqualGUIDAligned( - &Channel->ChannelId.ChannelGuid, - &ChannelId->ChannelGuid); + /* Check if the GUIDs match */ + return IsEqualGUIDAligned(&Channel->ChannelId.ChannelGuid, + &ChannelId->ChannelGuid); } NTSTATUS -ChannelInitializeVTable( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelDereferenceHandles(IN PSAC_CHANNEL Channel) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER(Channel); + + /* Clear the data event */ + if (Channel->HasNewDataEvent) + { + ChannelUninitializeEvent(Channel, + HasNewDataEvent, + SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT); + } + + /* Clear the close event */ + if (Channel->CloseEvent) + { + ChannelUninitializeEvent(Channel, + CloseEvent, + SAC_CHANNEL_FLAG_CLOSE_EVENT); + } + + /* Clear the lock event */ + if (Channel->LockEvent) + { + ChannelUninitializeEvent(Channel, + LockEvent, + SAC_CHANNEL_FLAG_LOCK_EVENT); + } + + /* Clear the redraw event */ + if (Channel->RedrawEvent) + { + ChannelUninitializeEvent(Channel, + RedrawEvent, + SAC_CHANNEL_FLAG_REDRAW_EVENT); + } + + /* All done */ + return STATUS_SUCCESS; } NTSTATUS -ChannelDereferenceHandles( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelDestroy(IN PSAC_CHANNEL Channel) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER(Channel); + + /* Same thing as dereferencing all the handles */ + return ChannelDereferenceHandles(Channel); } NTSTATUS -ChannelDestroy( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelOWrite(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize) { - CHECK_PARAMETER(Channel); - - return ChannelDereferenceHandles(Channel); + NTSTATUS Status; + CHECK_PARAMETER3(BufferSize < SAC_OBUFFER_SIZE); + + /* While holding the output lock, write to the output buffer */ + ChannelLockOBuffer(Channel); + Status = Channel->ChannelOutputWrite(Channel, Buffer, BufferSize); + ChannelUnlockOBuffer(Channel); + return Status; } NTSTATUS -ChannelOWrite( - IN PSAC_CHANNEL Channel, - IN PWCHAR Buffer, - IN ULONG BufferSize - ) +NTAPI +ChannelOFlush(IN PSAC_CHANNEL Channel) { - NTSTATUS Status; - - CHECK_PARAMETER3(BufferSize < SAC_OBUFFER_SIZE); + NTSTATUS Status; - ChannelLockOBuffer(Channel); - - Status = Channel->OBufferWrite(Channel, Buffer, BufferSize); - - ChannelUnlockOBuffer(Channel); - - return Status; + /* While holding the output lock, flush to the output buffer */ + ChannelLockOBuffer(Channel); + Status = Channel->ChannelOutputFlush(Channel); + ChannelUnlockOBuffer(Channel); + return Status; } NTSTATUS -ChannelOFlush( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelIWrite(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize) { - NTSTATUS Status; - - ChannelLockOBuffer(Channel); + NTSTATUS Status; - Status = Channel->OBufferFlush(Channel); - - ChannelUnlockOBuffer(Channel); - - return Status; + /* Write into the input buffer while holding the lock */ + ChannelLockIBuffer(Channel); + Status = Channel->ChannelInputWrite(Channel, Buffer, BufferSize); + ChannelUnlockIBuffer(Channel); + return Status; } NTSTATUS -ChannelIWrite( - IN PSAC_CHANNEL Channel, - IN PWCHAR Buffer, - IN ULONG BufferSize - ) +NTAPI +ChannelIRead(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + IN OUT PULONG ResultBufferSize) { - NTSTATUS Status; + NTSTATUS Status; - ChannelLockIBuffer(Channel); - - Status = Channel->IBufferWrite(Channel, Buffer, BufferSize); - - ChannelUnlockIBuffer(Channel); - - return Status; + /* Read the input buffer while holding the lock */ + ChannelLockIBuffer(Channel); + Status = Channel->ChannelInputRead(Channel, + Buffer, + BufferSize, + ResultBufferSize); + ChannelUnlockIBuffer(Channel); + return Status; } -ULONG -ChannelIRead( - IN PSAC_CHANNEL Channel, - PWCHAR Buffer, - ULONG BufferSize, - OUT PULONG ResultBufferSize - ) +UCHAR +NTAPI +ChannelIReadLast(IN PSAC_CHANNEL Channel) { - NTSTATUS Status; - - ChannelLockIBuffer(Channel); + UCHAR LastChar; - Status = Channel->IBufferRead(Channel, Buffer, BufferSize, ResultBufferSize); - - ChannelUnlockIBuffer(Channel); - - return Status; -} - -NTSTATUS -ChannelIReadLast( - IN PSAC_CHANNEL Channel - ) -{ - NTSTATUS Status; - - ChannelLockIBuffer(Channel); - - Status = Channel->IBufferReadLast(Channel); - - ChannelUnlockIBuffer(Channel); - - return Status; + /* Read the last character while holding the lock */ + ChannelLockIBuffer(Channel); + LastChar = Channel->ChannelInputReadLast(Channel); + ChannelUnlockIBuffer(Channel); + return LastChar; } ULONG -ChannelIBufferLength( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelIBufferLength(IN PSAC_CHANNEL Channel) { - NTSTATUS Length; + ULONG Length; - ChannelLockOBuffer(Channel); - - Length = Channel->IBufferLength(Channel); - - ChannelUnlockOBuffer(Channel); - - return Length; -} - -NTSTATUS -ChannelGetName( - IN PSAC_CHANNEL Channel, - OUT PWCHAR *Name - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChannelSetName( - IN PSAC_CHANNEL Channel, - IN PWCHAR Name - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChannelGetDescription( - IN PSAC_CHANNEL Channel, - OUT PWCHAR *Description - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChannelSetDescription( - IN PSAC_CHANNEL Channel, - IN PWCHAR Description - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChannelSetStatus( - IN PSAC_CHANNEL Channel, - IN SAC_CHANNEL_STATUS ChannelStatus - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChannelGetStatus( - IN PSAC_CHANNEL Channel, - OUT PSAC_CHANNEL_STATUS ChannelStatus - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ChannelGetApplicationType( - IN PSAC_CHANNEL Channel, - OUT PGUID ApplicationType - ) -{ - return STATUS_NOT_IMPLEMENTED; + /* Get the input buffer length while holding the lock */ + ChannelLockOBuffer(Channel); + Length = Channel->ChannelInputBufferLength(Channel); + ChannelUnlockOBuffer(Channel); + return Length; } NTSTATUS NTAPI -ChannelSetLockEvent( - IN PSAC_CHANNEL Channel - ) +ChannelSetRedrawEvent(IN PSAC_CHANNEL Channel) { - NTSTATUS Status; - - ChannelSetEvent(Channel, LockEvent); - - return Status; + NTSTATUS Status; + + /* Set the event */ + ChannelSetEvent(Channel, RedrawEvent); + return Status; } NTSTATUS NTAPI -ChannelSetRedrawEvent( - IN PSAC_CHANNEL Channel - ) +ChannelSetLockEvent(IN PSAC_CHANNEL Channel) { - NTSTATUS Status; + NTSTATUS Status; - ChannelSetEvent(Channel, RedrawEvent); - - return Status; + /* Set the event */ + ChannelSetEvent(Channel, LockEvent); + return Status; } NTSTATUS -ChannelClearRedrawEvent( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelClearRedrawEvent(IN PSAC_CHANNEL Channel) { - NTSTATUS Status; - - ChannelClearEvent(Channel, RedrawEvent); - - return Status; + NTSTATUS Status; + + /* Clear the event */ + ChannelClearEvent(Channel, RedrawEvent); + return Status; } NTSTATUS -ChannelHasRedrawEvent( - IN PSAC_CHANNEL Channel, - OUT PBOOLEAN Present - ) +NTAPI +ChannelHasRedrawEvent(IN PSAC_CHANNEL Channel, + OUT PBOOLEAN Present) { - CHECK_PARAMETER1(Channel); - CHECK_PARAMETER2(Present); - - *Present = Channel->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT; - - return STATUS_SUCCESS; + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Present); + + /* Return if the flag is set */ + *Present = Channel->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT; + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChannelGetStatus(IN PSAC_CHANNEL Channel, + OUT PSAC_CHANNEL_STATUS ChannelStatus) +{ + CHECK_PARAMETER1(Channel); + + /* Read the status while holding the attribute lock */ + ChannelLockAttributes(Channel); + *ChannelStatus = Channel->ChannelStatus; + ChannelUnlockAttributes(Channel); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChannelSetStatus(IN PSAC_CHANNEL Channel, + IN SAC_CHANNEL_STATUS ChannelStatus) +{ + CHECK_PARAMETER1(Channel); + + /* Read the status while holding the attribute lock */ + ChannelLockAttributes(Channel); + Channel->ChannelStatus = ChannelStatus; + ChannelUnlockAttributes(Channel); + return STATUS_SUCCESS; } BOOLEAN -ChannelIsActive( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelIsActive(IN PSAC_CHANNEL Channel) { - SAC_CHANNEL_STATUS ChannelStatus; + SAC_CHANNEL_STATUS ChannelStatus; + BOOLEAN IsActive; - if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus))) return FALSE; + /* Get the status */ + if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus))) + { + /* We couldn't even do that, assume it's inactive */ + IsActive = FALSE; + } + else + { + /* Check if the status shows activity */ + IsActive = (ChannelStatus == Active); + } - return (ChannelStatus == Active); + /* Return the state */ + return IsActive; } BOOLEAN -ChannelIsClosed( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelIsClosed(IN PSAC_CHANNEL Channel) { - return FALSE; + SAC_CHANNEL_STATUS ChannelStatus; + BOOLEAN IsClosed; + + /* Get the status */ + if (!NT_SUCCESS(ChannelGetStatus(Channel, &ChannelStatus))) + { + /* We couldn't even do that, assume it's inactive */ + IsClosed = FALSE; + } + else + { + /* Check if the status shows activity */ + IsClosed = ((ChannelStatus == Inactive) && + (Channel->ChannelHasNewOBufferData)); + } + + /* Return the state */ + return IsClosed; } NTSTATUS -ChannelCreate( - IN PSAC_CHANNEL Channel, - IN PSAC_CHANNEL_ATTRIBUTES Attributes, - IN SAC_CHANNEL_ID ChannelId - ) +NTAPI +ChannelGetName(IN PSAC_CHANNEL Channel, + OUT PWCHAR *Name) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Name); + + /* Allocate space to hold the name */ + *Name = SacAllocatePool(sizeof(Channel->NameBuffer), GLOBAL_BLOCK_TAG); + CHECK_ALLOCATION(*Name); + + /* Lock the attributes while we copy the name */ + ChannelLockAttributes(Channel); + + /* Copy the name and null-terminate it */ + ASSERT(((wcslen(Channel->NameBuffer) + 1) * sizeof(WCHAR)) <= ((64 + 1) * sizeof(WCHAR))); + wcsncpy(*Name, Channel->NameBuffer, RTL_NUMBER_OF(Channel->NameBuffer)); // bug + (*Name)[SAC_CHANNEL_NAME_SIZE] = UNICODE_NULL; + + /* Release the lock and return */ + ChannelUnlockAttributes(Channel); + return STATUS_SUCCESS; } NTSTATUS -ChannelClose( - IN PSAC_CHANNEL Channel - ) +NTAPI +ChannelSetName(IN PSAC_CHANNEL Channel, + IN PWCHAR Name) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Name); + + /* Lock the attributes while we copy the name */ + ChannelLockAttributes(Channel); + + /* Copy the name and null-terminate it */ + ASSERT(((wcslen(Name) + 1) * sizeof(WCHAR)) <= ((64 + 1) * sizeof(WCHAR))); + wcsncpy(Channel->NameBuffer, Name, RTL_NUMBER_OF(Channel->NameBuffer)); // bug + Channel->NameBuffer[SAC_CHANNEL_NAME_SIZE] = UNICODE_NULL; + + /* Release the lock and return */ + ChannelUnlockAttributes(Channel); + return STATUS_SUCCESS; } + +NTSTATUS +NTAPI +ChannelGetDescription(IN PSAC_CHANNEL Channel, + IN PWCHAR* Description) +{ + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Description); + + /* Allocate space to hold the description */ + *Description = SacAllocatePool(sizeof(Channel->DescriptionBuffer), GLOBAL_BLOCK_TAG); + CHECK_ALLOCATION(*Description); + + /* Lock the attributes while we copy the name */ + ChannelLockAttributes(Channel); + + /* Copy the name and null-terminate it */ + ASSERT(((wcslen(Channel->DescriptionBuffer) + 1) * sizeof(WCHAR)) <= ((256 + 1) * sizeof(WCHAR))); + wcsncpy(*Description, Channel->DescriptionBuffer, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug + (*Description)[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL; + + /* Release the lock and return */ + ChannelUnlockAttributes(Channel); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChannelSetDescription(IN PSAC_CHANNEL Channel, + IN PWCHAR Description) +{ + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Description); + + /* Lock the attributes while we copy the name */ + ChannelLockAttributes(Channel); + + /* Copy the name and null-terminate it */ + ASSERT(((wcslen(Description) + 1) * sizeof(WCHAR)) <= ((64 + 1) * sizeof(WCHAR))); + wcsncpy(Channel->DescriptionBuffer, Description, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug + Channel->DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL; + + /* Release the lock and return */ + ChannelUnlockAttributes(Channel); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChannelGetApplicationType(IN PSAC_CHANNEL Channel, + OUT PGUID ApplicationType) +{ + CHECK_PARAMETER1(Channel); + + /* Read the application type GUID */ + ChannelLockAttributes(Channel); + *ApplicationType = Channel->ApplicationType; + ChannelUnlockAttributes(Channel); + + /* Always return success */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChannelInitializeVTable(IN PSAC_CHANNEL Channel) +{ + /* What kind of channel is this? */ + switch (Channel->ChannelType) + { + case VtUtf8: + /* FIXME: TODO */ + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; + + case Cmd: + /* FIXME: TODO */ + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; + + case Raw: + + /* Setup the calls for a raw channel */ + Channel->ChannelCreate = RawChannelCreate; + Channel->ChannelDestroy = RawChannelDestroy; + Channel->ChannelOutputFlush = RawChannelOFlush; + Channel->ChannelOutputEcho = RawChannelOEcho; + Channel->ChannelOutputWrite = RawChannelOWrite; + Channel->ChannelOutputRead = RawChannelORead; + Channel->ChannelInputWrite = RawChannelIWrite; + Channel->ChannelInputRead = RawChannelIRead; + Channel->ChannelInputReadLast = RawChannelIReadLast; + Channel->ChannelInputBufferIsFull = RawChannelIBufferIsFull; + Channel->ChannelInputBufferLength = RawChannelIBufferLength; + break; + + default: + /* Unsupported channel type */ + return STATUS_INVALID_PARAMETER; + } + + /* If we got here, the channel was supported */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ChannelCreate(IN PSAC_CHANNEL Channel, + IN PSAC_CHANNEL_ATTRIBUTES Attributes, + IN SAC_CHANNEL_ID ChannelId) +{ + NTSTATUS Status; + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Attributes); + + /* If a close event is being passed in, it must exist, and vice-versa */ + if (Attributes->Flag & SAC_CHANNEL_FLAG_CLOSE_EVENT) + { + CHECK_PARAMETER(Attributes->CloseEvent != NULL); + } + else + { + CHECK_PARAMETER(Attributes->CloseEvent == NULL); + } + + /* If a new data event is being passed in, it must exist, and vice-versa */ + if (Attributes->Flag & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) + { + CHECK_PARAMETER(Attributes->HasNewDataEvent != NULL); + } + else + { + CHECK_PARAMETER(Attributes->HasNewDataEvent == NULL); + } + + /* If a lock event is being passed in, it must exist, and vice-versa */ + if (Attributes->Flag & SAC_CHANNEL_FLAG_LOCK_EVENT) + { + CHECK_PARAMETER(Attributes->LockEvent != NULL); + } + else + { + CHECK_PARAMETER(Attributes->LockEvent == NULL); + } + + /* If a redraw event is being passed in, it must exist, and vice-versa */ + if (Attributes->Flag & SAC_CHANNEL_FLAG_REDRAW_EVENT) + { + CHECK_PARAMETER(Attributes->RedrawEvent != NULL); + } + else + { + CHECK_PARAMETER(Attributes->RedrawEvent == NULL); + } + + /* Initialize the channel structure */ + RtlZeroMemory(Channel, sizeof(SAC_CHANNEL)); + Channel->ChannelId = ChannelId; + Channel->ChannelType = Attributes->ChannelType; + Channel->Flags = Attributes->Flag; + if (Attributes->Flag & SAC_CHANNEL_FLAG_APPLICATION) + { + Channel->ApplicationType = Attributes->ChannelId; + } + + /* Initialize all the locks and events */ + SacInitializeLock(&Channel->ChannelAttributeLock); + SacInitializeLock(&Channel->ChannelOBufferLock); + SacInitializeLock(&Channel->ChannelIBufferLock); + ChannelInitializeEvent(Channel, Attributes, CloseEvent); + ChannelInitializeEvent(Channel, Attributes, HasNewDataEvent); + ChannelInitializeEvent(Channel, Attributes, LockEvent); + ChannelInitializeEvent(Channel, Attributes, RedrawEvent); + + /* Set the name and description */ + ChannelSetName(Channel, Attributes->NameBuffer); + ChannelSetDescription(Channel, Attributes->DescriptionBuffer); + + /* Initialize the function table for the type of channel this is */ + Status = ChannelInitializeVTable(Channel); + if (!NT_SUCCESS(Status)) + { + /* This is critical */ + SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to initialize vtable\n"); + goto FailChannel; + } + + /* Now call the channel specific type constructor */ + Status = Channel->ChannelCreate(Channel); + if (!NT_SUCCESS(Status)) + { + /* This is critical */ + SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed channel specific initialization\n"); + goto FailChannel; + } + + /* Finally, mark the channel as active */ + ChannelSetStatus(Channel, Active); + return STATUS_SUCCESS; + +FailChannel: + /* Destroy the channel and return the failure code */ + Channel->ChannelDestroy(Channel); + return Status; +} + +NTSTATUS +NTAPI +ChannelClose(IN PSAC_CHANNEL Channel) +{ + NTSTATUS Status; + CHECK_PARAMETER(Channel); + + /* Set the channel inactive */ + ChannelSetStatus(Channel, Inactive); + + /* Set the close event */ + if (Channel->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) + { + ChannelSetEvent(Channel, CloseEvent); + } + + /* Close all the handles */ + Status = ChannelDereferenceHandles(Channel); + return Status; +} + diff --git a/reactos/drivers/sac/driver/concmd.c b/reactos/drivers/sac/driver/concmd.c index 42b87ca2795..76d6edbfe47 100644 --- a/reactos/drivers/sac/driver/concmd.c +++ b/reactos/drivers/sac/driver/concmd.c @@ -1,18 +1,75 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/concmd.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/concmd.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +PWCHAR GlobalBuffer; +ULONG GlobalBufferSize; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +DoRebootCommand(IN BOOLEAN Reboot) +{ + LARGE_INTEGER Timeout, TickCount; + NTSTATUS Status; + KEVENT Event; + SAC_DBG(1, "SAC DoRebootCommand: Entering.\n"); + + /* Get the current time now, and setup a timeout in 1 second */ + KeQueryTickCount(&TickCount); + Timeout.QuadPart = TickCount.QuadPart / (10000000 / KeQueryTimeIncrement()); + + /* Check if the timeout is small enough */ + if (Timeout.QuadPart < 60 ) + { + /* Show the prompt */ + ConMgrSimpleEventMessage(Reboot ? + SAC_RESTART_PROMPT : SAC_SHUTDOWN_PROMPT, + TRUE); + + /* Do the wait */ + KeInitializeEvent(&Event, SynchronizationEvent, 0); + Timeout.QuadPart = -10000000 * (60 - Timeout.LowPart); + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout); + } + + /* Do a shutdown or a reboot, based on the request */ + Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff); + + /* Check if anyone in the command channel already allocated this */ + if (!GlobalBuffer) + { + /* Allocate it */ + GlobalBuffer = SacAllocatePool(PAGE_SIZE, GLOBAL_BLOCK_TAG); + if (!GlobalBuffer) + { + /* We need the global buffer, bail out without it*/ + SacPutSimpleMessage(SAC_OUT_OF_MEMORY_PROMPT); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting (1).\n"); + return; + } + + /* Set the size of the buffer */ + GlobalBufferSize = PAGE_SIZE; + } + + /* We came back from a reboot, this doesn't make sense, tell the user */ + SacPutSimpleMessage(Reboot ? SAC_RESTART_FAIL_PROMPT : SAC_SHUTDOWN_FAIL_PROMPT); + swprintf(GlobalBuffer, GetMessage(SAC_FAIL_PROMPT), Status); + SacPutString(GlobalBuffer); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting.\n"); +} NTSTATUS GetTListInfo( @@ -122,14 +179,6 @@ DoLimitMemoryCommand( } -VOID -DoRebootCommand( - IN BOOLEAN Reboot - ) -{ - -} - VOID DoCrashCommand( VOID diff --git a/reactos/drivers/sac/driver/conmgr.c b/reactos/drivers/sac/driver/conmgr.c index a01819394af..b012cad03f7 100644 --- a/reactos/drivers/sac/driver/conmgr.c +++ b/reactos/drivers/sac/driver/conmgr.c @@ -1,191 +1,541 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/conmgr.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/conmgr.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +DEFINE_GUID(PRIMARY_SAC_CHANNEL_APPLICATION_GUID, + 0x63D02270, + 0x8AA4, + 0x11D5, + 0xBC, 0xCF, 0x80, 0x6D, 0x61, 0x72, 0x69, 0x6F); -NTSTATUS -ConMgrShutdown( - VOID) +LONG CurrentChannelRefCount; +KMUTEX CurrentChannelLock; + +PSAC_CHANNEL CurrentChannel; +PSAC_CHANNEL SacChannel; + +ULONG ExecutePostConsumerCommand; +PSAC_CHANNEL ExecutePostConsumerCommandData; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +ConMgrSerialPortConsumer(VOID) { - return STATUS_NOT_IMPLEMENTED; -} + NTSTATUS Status; + CHAR Char; + SAC_DBG(0x2000, "SAC TimerDpcRoutine: Entering.\n"); //bug -NTSTATUS -ConMgrDisplayFastChannelSwitchingInterface( - IN PSAC_CHANNEL Channel - ) -{ - return STATUS_NOT_IMPLEMENTED; -} + /* Acquire the manager lock and make sure a channel is selected */ + SacAcquireMutexLock(); + ASSERT(CurrentChannel); -NTSTATUS -ConMgrSetCurrentChannel( - IN PSAC_CHANNEL Channel - ) -{ - return STATUS_NOT_IMPLEMENTED; -} + /* Read whatever came off the serial port */ + for (Status = SerialBufferGetChar(&Char); + NT_SUCCESS(Status); + Status = SerialBufferGetChar(&Char)) + { + /* If nothing came through, bail out */ + if (Status == STATUS_NO_DATA_DETECTED) break; + } -NTSTATUS -ConMgrDisplayCurrentChannel( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ConMgrAdvanceCurrentChannel( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -BOOLEAN -ConMgrIsWriteEnabled( - IN PSAC_CHANNEL Channel - ) -{ - return FALSE; + /* We're done, release the lock */ + SacReleaseMutexLock(); + SAC_DBG(0x2000, "SAC TimerDpcRoutine: Exiting.\n"); //bug } VOID -SacPutString( - IN PWCHAR String - ) +NTAPI +ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension) { + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n"); -} + /* Enter the main loop */ + while (TRUE) + { + /* Wait for something to do */ + KeWaitForSingleObject(&DeviceExtension->Event, + Executive, + KernelMode, + FALSE, + NULL); -BOOLEAN -SacPutSimpleMessage( - IN ULONG MessageIndex - ) -{ - return FALSE; -} + /* Consume data off the serial port */ + ConMgrSerialPortConsumer(); + switch (ExecutePostConsumerCommand) + { + case 1: + /* A reboot was sent, do it */ + DoRebootCommand(FALSE); + break; -NTSTATUS -ConMgrChannelOWrite( - IN PSAC_CHANNEL Channel, - IN PVOID WriteBuffer - ) -{ - return STATUS_NOT_IMPLEMENTED; -} + case 2: + /* A close was sent, do it */ + ChanMgrCloseChannel(ExecutePostConsumerCommandData); + ChanMgrReleaseChannel(ExecutePostConsumerCommandData); + break; -NTSTATUS -ConMgrGetChannelCloseMessage( - IN PSAC_CHANNEL Channel, - IN NTSTATUS CloseStatus, - OUT PWCHAR OutputBuffer - ) -{ - return STATUS_NOT_IMPLEMENTED; -} + case 3: + /* A shutdown was sent, do it */ + DoRebootCommand(TRUE); + break; + } -NTSTATUS -ConMgrWriteData( - IN PSAC_CHANNEL Channel, - IN PVOID Buffer, - IN ULONG BufferLength - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ConMgrFlushData( - IN PSAC_CHANNEL Channel - ) -{ - return FALSE; -} - -BOOLEAN -ConMgrIsSacChannel( - IN PSAC_CHANNEL Channel - ) -{ - return FALSE; -} - -NTSTATUS -ConMgrInitialize( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ConMgrResetCurrentChannel( - IN BOOLEAN KeepChannel - ) -{ - return STATUS_NOT_IMPLEMENTED; + /* Clear the serial port consumer state */ + ExecutePostConsumerCommand = 0; + ExecutePostConsumerCommandData = NULL; + } } VOID -ConMgrProcessInputLine( - VOID - ) -{ - -} - -VOID -ConMgrEventMessage( - IN PWCHAR EventMessage, - IN BOOLEAN LockHeld - ) +NTAPI +SacPutString(IN PWCHAR String) { + NTSTATUS Status; + /* Write the string on the main SAC channel */ + Status = ChannelOWrite(SacChannel, + (PCHAR)String, + wcslen(String) * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC XmlMgrSacPutString: OWrite failed\n"); + } } BOOLEAN -ConMgrSimpleEventMessage( - IN ULONG MessageIndex, - IN BOOLEAN LockHeld - ) +NTAPI +SacPutSimpleMessage(IN ULONG MessageIndex) { - return FALSE; + PWCHAR MessageBuffer; + BOOLEAN Result; + + /* Get the message */ + MessageBuffer = GetMessage(MessageIndex); + if (MessageBuffer) + { + /* Output it */ + SacPutString(MessageBuffer); + Result = TRUE; + } + else + { + Result = FALSE; + } + + /* All done */ + return Result; } NTSTATUS -ConMgrChannelClose( - IN PSAC_CHANNEL Channel - ) +NTAPI +ConMgrDisplayCurrentChannel(VOID) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + BOOLEAN HasRedraw; + + /* Make sure the lock is held */ + SacAssertMutexLockHeld(); + + /* Check if we can redraw */ + Status = ChannelHasRedrawEvent(CurrentChannel, &HasRedraw); + if (NT_SUCCESS(Status)) + { + /* Enable writes */ + _InterlockedExchange(&CurrentChannel->WriteEnabled, 1); + if (HasRedraw) + { + /* If we can redraw, set the event */ + ChannelSetRedrawEvent(CurrentChannel); + } + + /* Flush the output */ + Status = ChannelOFlush(CurrentChannel); + } + + /* All done, return the status */ + return Status; } NTSTATUS -ConMgrHandleEvent( - IN ULONG EventCode, - IN PSAC_CHANNEL Channel, - OUT PVOID Data - ) +NTAPI +ConMgrWriteData(IN PSAC_CHANNEL Channel, + IN PVOID Buffer, + IN ULONG BufferLength) { - return STATUS_NOT_IMPLEMENTED; + ULONG i; + NTSTATUS Status; + LARGE_INTEGER Interval; + + /* Loop up to 32 times */ + for (i = 0; i < 32; i++) + { + /* Attempt sending the data */ + Status = HeadlessDispatch(HeadlessCmdPutData, Buffer, BufferLength, NULL, NULL); + if (Status != STATUS_UNSUCCESSFUL) break; + + /* Sending the data on the port failed, wait a second... */ + Interval.HighPart = -1; + Interval.LowPart = -100000; + KeDelayExecutionThread(KernelMode, FALSE, &Interval); + } + + /* After 32 attempts it should really have worked... */ + ASSERT(NT_SUCCESS(Status)); + return Status; +} + +NTSTATUS +NTAPI +ConMgrFlushData(IN PSAC_CHANNEL Channel) +{ + /* Nothing to do */ + return STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +ConMgrIsSacChannel(IN PSAC_CHANNEL Channel) +{ + /* Check which channel is active */ + return Channel == SacChannel; +} + +BOOLEAN +NTAPI +ConMgrIsWriteEnabled(IN PSAC_CHANNEL Channel) +{ + /* If the current channel is active, allow writes */ + return ChannelIsEqual(Channel, &CurrentChannel->ChannelId); +} + +NTSTATUS +NTAPI +ConMgrInitialize(VOID) +{ + PWCHAR pcwch; + PSAC_CHANNEL FoundChannel; + SAC_CHANNEL_ATTRIBUTES SacChannelAttributes; + NTSTATUS Status; + + /* Initialize the connection manager lock */ + SacInitializeMutexLock(); + SacAcquireMutexLock(); + + /* Setup the attributes for the raw SAC channel */ + RtlZeroMemory(&SacChannelAttributes, sizeof(SacChannelAttributes)); + SacChannelAttributes.ChannelType = Raw; + + /* Get the right name for it */ + pcwch = GetMessage(SAC_CHANNEL_NAME); + ASSERT(pcwch); + wcsncpy(SacChannelAttributes.NameBuffer, pcwch, SAC_CHANNEL_NAME_SIZE); + SacChannelAttributes.NameBuffer[SAC_CHANNEL_NAME_SIZE] = ANSI_NULL; + + /* Get the right description for it */ + pcwch = GetMessage(SAC_CHANNEL_DESCRIPTION); + ASSERT(pcwch); + wcsncpy(SacChannelAttributes.DescriptionBuffer, pcwch, SAC_CHANNEL_DESCRIPTION_SIZE); + SacChannelAttributes.DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = ANSI_NULL; + + /* Set all the right flags */ + SacChannelAttributes.Flag = SAC_CHANNEL_FLAG_APPLICATION | SAC_CHANNEL_FLAG_INTERNAL; + SacChannelAttributes.CloseEvent = NULL; + SacChannelAttributes.HasNewDataEvent = NULL; + SacChannelAttributes.LockEvent = NULL; + SacChannelAttributes.RedrawEvent = NULL; + SacChannelAttributes.ChannelId = PRIMARY_SAC_CHANNEL_APPLICATION_GUID; + + /* Now create it */ + Status = ChanMgrCreateChannel(&SacChannel, &SacChannelAttributes); + if (NT_SUCCESS(Status)) + { + /* Try to get it back */ + Status = ChanMgrGetByHandle(SacChannel->ChannelId, &FoundChannel); + if (NT_SUCCESS(Status)) + { + /* Set it as the current and SAC channel */ + SacChannel = CurrentChannel = FoundChannel; + + /* Diasable writes for now and clear the display */ + _InterlockedExchange(&FoundChannel->WriteEnabled, FALSE); + Status = HeadlessDispatch(HeadlessCmdClearDisplay, NULL, 0, NULL, NULL); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC ConMgrInitialize: Failed dispatch\n"); + } + + /* Display the initial prompt */ + SacPutSimpleMessage(SAC_NEWLINE); + SacPutSimpleMessage(SAC_INIT_STATUS); + SacPutSimpleMessage(SAC_NEWLINE); + SacPutSimpleMessage(SAC_PROMPT); + + /* Display the current channel */ + ConMgrDisplayCurrentChannel(); + } + } + + /* Release the channel lock */ + SacReleaseMutexLock(); + return STATUS_SUCCESS; } VOID -ConMgrWorkerProcessEvents( - IN PSAC_CHANNEL Channel - ) +NTAPI +ConMgrEventMessage(IN PWCHAR EventMessage, + IN BOOLEAN LockHeld) { + /* Acquire the current channel lock if needed */ + if (!LockHeld) SacAcquireMutexLock(); + /* Send out the event message */ + SacPutSimpleMessage(2); + SacPutString(EventMessage); + SacPutSimpleMessage(3); + + /* Release the current channel lock if needed */ + if (!LockHeld) SacReleaseMutexLock(); } + +BOOLEAN +NTAPI +ConMgrSimpleEventMessage(IN ULONG MessageIndex, + IN BOOLEAN LockHeld) +{ + PWCHAR MessageBuffer; + BOOLEAN Result; + + /* Get the message to send out */ + MessageBuffer = GetMessage(MessageIndex); + if (MessageBuffer) + { + /* Send it */ + ConMgrEventMessage(MessageBuffer, LockHeld); + Result = TRUE; + } + else + { + /* It doesn't exist, fail */ + Result = FALSE; + } + + /* Return if the message was sent or not */ + return Result; +} + +NTSTATUS +NTAPI +ConMgrDisplayFastChannelSwitchingInterface(IN PSAC_CHANNEL Channel) +{ + /* FIXME: TODO */ + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +ConMgrSetCurrentChannel(IN PSAC_CHANNEL Channel) +{ + NTSTATUS Status; + BOOLEAN HasRedrawEvent; + + /* Make sure the lock is held */ + SacAssertMutexLockHeld(); + + /* Check if we have a redraw event */ + Status = ChannelHasRedrawEvent(CurrentChannel, &HasRedrawEvent); + if (!NT_SUCCESS(Status)) return Status; + + /* Clear it */ + if (HasRedrawEvent) ChannelClearRedrawEvent(CurrentChannel); + + /* Disable writes on the current channel */ + _InterlockedExchange(&CurrentChannel->WriteEnabled, 0); + + /* Release the current channel */ + Status = ChanMgrReleaseChannel(CurrentChannel); + if (!NT_SUCCESS(Status)) return Status; + + /* Set the new channel and also disable writes on it */ + CurrentChannel = Channel; + _InterlockedExchange(&Channel->WriteEnabled, 0); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ConMgrResetCurrentChannel(IN BOOLEAN KeepChannel) +{ + NTSTATUS Status; + PSAC_CHANNEL Channel; + + /* Make sure the lock is held */ + SacAssertMutexLockHeld(); + + /* Get the current SAC channel */ + Status = ChanMgrGetByHandle(SacChannel->ChannelId, &Channel); + if (NT_SUCCESS(Status)) + { + /* Set this as the current SAC channel*/ + SacChannel = Channel; + Status = ConMgrSetCurrentChannel(Channel); + if (NT_SUCCESS(Status)) + { + /* Check if the caller wants to switch or not */ + if (KeepChannel) + { + /* Nope, keep the same channel */ + Status = ConMgrDisplayCurrentChannel(); + } + else + { + /* Yep, show the switching interface */ + Status = ConMgrDisplayFastChannelSwitchingInterface(CurrentChannel); + } + } + } + + /* All done */ + return Status; +} + +NTSTATUS +NTAPI +ConMgrChannelClose(IN PSAC_CHANNEL Channel) +{ + NTSTATUS Status = STATUS_SUCCESS; + + /* Check if we're in the right channel */ + if (ConMgrIsWriteEnabled(Channel)) + { + /* Yep, reset it */ + Status = ConMgrResetCurrentChannel(FALSE); + ASSERT(NT_SUCCESS(Status)); + } + + /* All done */ + return Status; +} + +NTSTATUS +NTAPI +ConMgrShutdown(VOID) +{ + NTSTATUS Status; + + /* Check if we have a SAC channel */ + if (SacChannel) + { + /* Close it */ + Status = ChannelClose(SacChannel); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC ConMgrShutdown: failed closing SAC channel.\n"); + } + + /* No longer have one */ + SacChannel = NULL; + } + + /* Check if we have a current channel */ + if (CurrentChannel) + { + /* Release it */ + Status = ChanMgrReleaseChannel(CurrentChannel); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC ConMgrShutdown: failed releasing current channel\n"); + } + + /* No longer have one */ + CurrentChannel = NULL; + } + + /* All done */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ConMgrAdvanceCurrentChannel(VOID) +{ + NTSTATUS Status; + ULONG Index; + PSAC_CHANNEL Channel; + + /* Should always be called with the lock held */ + SacAssertMutexLockHeld(); + + /* Get the next active channel */ + Status = ChanMgrGetNextActiveChannel(CurrentChannel, &Index, &Channel); + if (NT_SUCCESS(Status)) + { + /* Set it as the new channel */ + Status = ConMgrSetCurrentChannel(Channel); + if (NT_SUCCESS(Status)) + { + /* Let the user switch to it */ + Status = ConMgrDisplayFastChannelSwitchingInterface(Channel); + } + } + + /* All done */ + return Status; +} + +NTSTATUS +NTAPI +ConMgrChannelOWrite(IN PSAC_CHANNEL Channel, + IN PVOID WriteBuffer) +{ + NTSTATUS Status; + + /* Do the write with the lock held */ + SacAcquireMutexLock(); + Status = STATUS_NOT_IMPLEMENTED;// ChannelOWrite(Channel, WriteBuffer + 24, *(WriteBuffer + 20)); + SacReleaseMutexLock(); + + /* Return back to the caller */ + ASSERT(NT_SUCCESS(Status) || Status == STATUS_NOT_FOUND); + return Status; +} + +NTSTATUS +NTAPI +ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel, + IN NTSTATUS CloseStatus, + OUT PWCHAR OutputBuffer) +{ + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +NTAPI +ConMgrProcessInputLine(VOID) +{ + ASSERT(FALSE); +} + +NTSTATUS +NTAPI +ConMgrHandleEvent(IN ULONG EventCode, + IN PSAC_CHANNEL Channel, + OUT PVOID Data) +{ + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + diff --git a/reactos/drivers/sac/driver/data.c b/reactos/drivers/sac/driver/data.c index 42ebd90662d..eee9ce0c7a7 100644 --- a/reactos/drivers/sac/driver/data.c +++ b/reactos/drivers/sac/driver/data.c @@ -1,58 +1,502 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/data.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/data.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -ULONG SACDebug; +ULONG SACDebug = 0xFFFFFFFF; +BOOLEAN CommandConsoleLaunchingEnabled; +BOOLEAN GlobalDataInitialized; +KMUTEX SACCMDEventInfoMutex; +BOOLEAN IoctlSubmitted; +ULONG ProcessingType; +PKEVENT SACEvent; +HANDLE SACEventHandle; -/* FUNCTIONS ******************************************************************/ +/* FUNCTIONS *****************************************************************/ VOID -FreeGlobalData( - VOID - ) +NTAPI +WorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension) { - + /* Call the worker function */ + return ConMgrWorkerProcessEvents(DeviceExtension); } VOID -FreeDeviceData( - IN PDEVICE_OBJECT DeviceObject - ) +NTAPI +WorkerThreadStartUp(IN PVOID Context) { - + /* Call the worker function */ + WorkerProcessEvents((PSAC_DEVICE_EXTENSION)Context); } NTSTATUS -WorkerThreadStartUp( - IN PVOID Context - ) +NTAPI +BuildDeviceAcl(OUT PACL* Dacl) { - return STATUS_NOT_IMPLEMENTED; + /* TODO */ + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +CreateDeviceSecurityDescriptor(IN PDEVICE_OBJECT *DeviceObject) +{ + NTSTATUS Status; + PSECURITY_DESCRIPTOR SecurityDescriptor; + BOOLEAN MemoryAllocated = FALSE; + PACL Dacl = NULL; + PVOID ObjectSecurityDescriptor = NULL; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Entering.\n"); + + /* Get the current SD of the device object */ + Status = ObGetObjectSecurity(*DeviceObject, &SecurityDescriptor, &MemoryAllocated); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC: Unable to get security descriptor, error: %x\n", Status); + NT_ASSERT(MemoryAllocated == FALSE); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status); + return Status; + } + + /* Build a DACL for it */ + Status = BuildDeviceAcl(&Dacl); + if (Status >= 0) + { + ASSERT(FALSE); + } + else + { + SAC_DBG(SAC_DBG_INIT, "SAC CreateDeviceSecurityDescriptor : Unable to create Raw ACL, error : %x\n", Status); + goto CleanupPath; + } + +CleanupPath: + /* Release the SD we queried */ + ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated); + + /* Free anything else we may have allocated */ + if (ObjectSecurityDescriptor) ExFreePool(ObjectSecurityDescriptor); + if (Dacl) SacFreePool(Dacl); + + /* All done */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status); + return Status; +} + +VOID +NTAPI +FreeGlobalData(VOID) +{ + UNICODE_STRING SymbolicLink; + SAC_DBG(1, "SAC FreeGlobalData: Entering.\n"); + + /* Only free if we allocated */ + if (GlobalDataInitialized) + { + /* Close the SAC event if we had created one */ + if (SACEvent) + { + ZwClose(SACEventHandle); + SACEvent = NULL; + } + + /* Destroy the cached messages */ + TearDownGlobalMessageTable(); + + /* Delete the Win32 symbolic link */ + RtlInitUnicodeString(&SymbolicLink, L"\\DosDevices\\SAC"); + IoDeleteSymbolicLink(&SymbolicLink); + + /* Tear down connections */ + ConMgrShutdown(); + + /* Tear down channels */ + ChanMgrShutdown(); + + /* Free the serial port buffer */ + if (SerialPortBuffer) SacFreePool(SerialPortBuffer); + + /* Free cached machine information */ + FreeMachineInformation(); + + /* Cleanup the custom heap allocator */ + FreeMemoryManagement(); + + /* We're back to a virgin state */ + GlobalDataInitialized = FALSE; + } + + /* All done */ + SAC_DBG(1, "SAC FreeGlobalData: Exiting.\n"); +} + +VOID +NTAPI +FreeDeviceData(IN PDEVICE_OBJECT DeviceObject) +{ + PSAC_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + KIRQL OldIrql; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Entering.\n"); + + /* Get the device extension and see how far we had gotten */ + DeviceExtension = (PSAC_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + if ((GlobalDataInitialized) && (DeviceExtension->Initialized)) + { + /* Attempt to rundown while holding the lock */ + KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql); + while (DeviceExtension->RundownInProgress) + { + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Waiting....\n"); + + /* Initiate and wait for rundown */ + KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0); + KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql); + Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent, + Executive, + KernelMode, + FALSE, + NULL); + ASSERT(Status == STATUS_SUCCESS); + + /* Re-acquire the lock and check if rundown is done */ + KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql); + } + } + + /* Now set the rundown flag while we cancel the timer */ + DeviceExtension->RundownInProgress = TRUE; + KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql); + + /* Cancel it */ + KeCancelTimer(&DeviceExtension->Timer); + + /* Reacquire the lock*/ + KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql); + DeviceExtension->RundownInProgress = FALSE; + + /* Now do the last rundown attempt, we should be the only ones here */ + KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0); + KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql); + KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, 0); + Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent, + Executive, + KernelMode, + FALSE, + NULL); + ASSERT(Status == STATUS_SUCCESS); + + /* We no longer care about shutdown */ + IoUnregisterShutdownNotification(DeviceObject); + + /* We are now fully uninitialized */ + KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql); + DeviceExtension->Initialized = FALSE; + KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Exiting.\n"); } BOOLEAN -InitializeDeviceData( - IN PDEVICE_OBJECT DeviceObject - ) +NTAPI +InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject) { - return FALSE; + PSAC_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; + BOOLEAN EnableData; + ULONG PriorityValue; + NTSTATUS Status; + LARGE_INTEGER DueTime; + PWCHAR Message; + PAGED_CODE(); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); + + /* If we already did this, bail out */ + if (DeviceExtension->Initialized) goto SuccessExit; + + /* Setup the DO flags */ + DeviceObject->Flags |= DO_DIRECT_IO; + DeviceObject->StackSize = 16; + + /* Setup the device extension */ + DeviceExtension->DeviceObject = DeviceObject; + DeviceExtension->PriorityBoost = IO_SERIAL_INCREMENT; + DeviceExtension->PriorityFail = 0; + DeviceExtension->RundownInProgress = 0; + + /* Initialize locks, events, timers, DPCs, etc... */ + KeInitializeTimer(&DeviceExtension->Timer); + KeInitializeDpc(&DeviceExtension->Dpc, TimerDpcRoutine, DeviceExtension); + KeInitializeSpinLock(&DeviceExtension->Lock); + KeInitializeEvent(&DeviceExtension->Event, SynchronizationEvent, 0); + InitializeListHead(&DeviceExtension->List); + + /* Attempt to enable HDL support */ + EnableData = TRUE; + Status = HeadlessDispatch(HeadlessCmdEnableTerminal, + &EnableData, + sizeof(EnableData), + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + /* Bail out if we couldn't even get this far */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (1) with status FALSE\n"); + return FALSE; + } + + /* Remember which process we started in */ + DeviceExtension->Process = IoGetCurrentProcess(); + + /* Protect the device against non-admins */ + Status = CreateDeviceSecurityDescriptor(&DeviceExtension->DeviceObject); + if (!NT_SUCCESS(Status)) + { + /* Write down why we failed */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (2) with status FALSE\n"); + + /* Disable the HDL terminal on failure */ + EnableData = FALSE; + Status = HeadlessDispatch(HeadlessCmdEnableTerminal, + &EnableData, + sizeof(EnableData), + NULL, + NULL); + if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n"); + + /* Bail out */ + return FALSE; + } + + /* Create the worker thread */ + Status = PsCreateSystemThread(&DeviceExtension->WorkerThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + NULL, + WorkerThreadStartUp, + DeviceExtension); + if (!NT_SUCCESS(Status)) + { + /* Write down why we failed */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (3) with status FALSE\n"); + + /* Disable the HDL terminal on failure */ + EnableData = FALSE; + Status = HeadlessDispatch(HeadlessCmdEnableTerminal, + &EnableData, + sizeof(EnableData), + NULL, + NULL); + if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n"); + + /* Bail out */ + return FALSE; + } + + /* Set the priority of our thread to highest */ + PriorityValue = HIGH_PRIORITY; + Status = NtSetInformationThread(DeviceExtension->WorkerThreadHandle, + ThreadPriority, + &PriorityValue, + sizeof(PriorityValue)); + if (!NT_SUCCESS(Status)) + { + /* For debugging, write down why we failed */ + SAC_DBG(1, "Exiting (6) with status FALSE\n"); + DeviceExtension->PriorityFail = TRUE; + + /* Initialize rundown and wait for the thread to do it */ + KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0); + KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, 0); + Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent, + Executive, + KernelMode, + FALSE, + NULL); + ASSERT(Status == STATUS_SUCCESS); + + /* Disable the HDL terminal on failure */ + EnableData = FALSE; + Status = HeadlessDispatch(HeadlessCmdEnableTerminal, + &EnableData, + sizeof(EnableData), + NULL, + 0); + if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n"); + + /* Bail out */ + return FALSE; + } + + /* The first "packet" is the machine information in XML... */ + Status = TranslateMachineInformationXML(&Message, NULL); + if (NT_SUCCESS(Status)) + { + /* Go ahead and send it */ + UTF8EncodeAndSend(L"\r\n"); + UTF8EncodeAndSend(Message); + + /* Free the temporary buffer */ + SacFreePool(Message); + } + + /* Finally, initialize the I/O Manager */ + Status = ConMgrInitialize(); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Set the timer. Once this is done, the device is initialized */ + DueTime.QuadPart = -4000; + KeSetTimerEx(&DeviceExtension->Timer, DueTime, 4, &DeviceExtension->Dpc); + DeviceExtension->Initialized = TRUE; + +SuccessExit: + /* Success path -- everything worked */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n"); + return TRUE; } BOOLEAN -InitializeGlobalData( - IN PUNICODE_STRING RegistryPath, - IN PDRIVER_OBJECT DriverObject - ) +NTAPI +InitializeGlobalData(IN PUNICODE_STRING RegistryPath, + IN PDRIVER_OBJECT DriverObject) { - return FALSE; + NTSTATUS Status; + UNICODE_STRING LinkName; + UNICODE_STRING DeviceName; + UNICODE_STRING EventName; + PAGED_CODE(); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); + + /* If we already did this, bail out */ + if (!GlobalDataInitialized) goto SuccessExit; + + /* Setup the symbolic link for Win32 support */ + RtlInitUnicodeString(&LinkName, L"\\DosDevices\\SAC"); + RtlInitUnicodeString(&DeviceName, L"\\Device\\SAC"); + Status = IoCreateSymbolicLink(&LinkName, &DeviceName); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Initialize the internal heap manager */ + if (!InitializeMemoryManagement()) + { + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status FALSE\n"); + return FALSE; + } + + /* Preload the messages in memory */ + Status = PreloadGlobalMessageTable(DriverObject->DriverStart); + if (!NT_SUCCESS(Status)) + { + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_INIT, "unable to pre-load message table: %X\n", Status); + return FALSE; + } + + /* Check if the administrator enabled this */ + Status = GetCommandConsoleLaunchingPermission(&CommandConsoleLaunchingEnabled); + if (!NT_SUCCESS(Status)) + { + /* Is it enabled? */ + if (CommandConsoleLaunchingEnabled) + { + /* Set the service start type to the correct value */ + Status = ImposeSacCmdServiceStartTypePolicy(); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "failed ImposeSacCmdServiceStartTypePolicy: %X\n", Status); + } + } + + /* We're going to keep going with the default */ + SAC_DBG(SAC_DBG_INIT, "failed GetCommandConsoleLaunchingPermission: %X\n", Status); + } + + /* Allocate the UTF-8 Conversion Buffer */ + Utf8ConversionBuffer = SacAllocatePool(Utf8ConversionBufferSize, GLOBAL_BLOCK_TAG); + if (!Utf8ConversionBuffer) + { + /* Handle failure case */ + TearDownGlobalMessageTable(); + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_INIT, "unable to allocate memory for UTF8 translation\n"); + return FALSE; + } + + /* Initialize the channel manager */ + Status = ChanMgrInitialize(); + if (!NT_SUCCESS(Status)) + { + /* Handle failure case */ + SacFreePool(Utf8ConversionBuffer); + TearDownGlobalMessageTable(); + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_INIT, "Failed to create SAC Channel\n"); + return FALSE; + } + + /* Allocate the serial port buffer */ + SerialPortBuffer = SacAllocatePool(SAC_SERIAL_PORT_BUFFER_SIZE, GLOBAL_BLOCK_TAG); + if (!SerialPortBuffer) + { + /* Handle failure case */ + SacFreePool(Utf8ConversionBuffer); + TearDownGlobalMessageTable(); + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_INIT, "Failed to allocate Serial Port Buffer\n"); + return FALSE; + } + + /* Zero it out */ + RtlZeroMemory(SerialPortBuffer, SAC_SERIAL_PORT_BUFFER_SIZE); + + /* Initialize command events. After this, driver data is good to go */ + KeInitializeMutex(&SACCMDEventInfoMutex, FALSE); + InitializeCmdEventInfo(); + GlobalDataInitialized = TRUE; + ProcessingType = 0; + IoctlSubmitted = 0; + + /* Create the SAC event */ + RtlInitUnicodeString(&EventName, L"\\SACEvent"); + SACEvent = IoCreateSynchronizationEvent(&EventName, &SACEventHandle); + if (!SACEvent) + { + /* Handle failure case */ + SacFreePool(Utf8ConversionBuffer); + TearDownGlobalMessageTable(); + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with event NULL\n"); + return FALSE; + } + + /* Cache machine information */ + InitializeMachineInformation(); + + /* Register it */ + Status = RegisterBlueScreenMachineInformation(); + if (!NT_SUCCESS(Status)) + { + /* Handle failure case */ + SacFreePool(Utf8ConversionBuffer); + TearDownGlobalMessageTable(); + IoDeleteSymbolicLink(&LinkName); + SAC_DBG(SAC_DBG_INIT, "Failed to register blue screen machine info\n"); + return FALSE; + } + +SuccessExit: + /* Success path -- everything worked */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n"); + return TRUE; } + diff --git a/reactos/drivers/sac/driver/dispatch.c b/reactos/drivers/sac/driver/dispatch.c index 58ffaca4115..1af10f57d50 100644 --- a/reactos/drivers/sac/driver/dispatch.c +++ b/reactos/drivers/sac/driver/dispatch.c @@ -1,88 +1,90 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/dispatch.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/dispatch.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +/* FUNCTIONS *****************************************************************/ NTSTATUS NTAPI -DispatchDeviceControl( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ) +DispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - return STATUS_NOT_IMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } NTSTATUS -DispatchShutdownControl( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ) +NTAPI +DispatchShutdownControl(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - return STATUS_NOT_IMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } NTSTATUS -DispatchCreate( - IN PSAC_DEVICE_EXTENSION DeviceExtension, - IN PIRP Irp - ) +NTAPI +DispatchCreate(IN PSAC_DEVICE_EXTENSION DeviceExtension, + IN PIRP Irp) { - return STATUS_NOT_IMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } NTSTATUS -DispatchClose( - IN PSAC_DEVICE_EXTENSION DeviceExtension, - IN PIRP Irp - ) +NTAPI +DispatchClose(IN PSAC_DEVICE_EXTENSION DeviceExtension, + IN PIRP Irp) { - return STATUS_NOT_IMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } NTSTATUS -Dispatch( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ) +NTAPI +Dispatch(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -WorkerProcessEvents( - IN PSAC_CHANNEL Channel - ) -{ - return STATUS_NOT_IMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } VOID -TimerDpcRoutine( - IN PKDPC Dpc, - IN PVOID DeferredContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2 - ) +NTAPI +TimerDpcRoutine(IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) { } VOID -UnloadHandler( - IN PDRIVER_OBJECT DriverObject - ) +NTAPI +UnloadHandler(IN PDRIVER_OBJECT DriverObject) { + PDEVICE_OBJECT DeviceObject, NextDevice; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC UnloadHandler: Entering.\n"); + /* Go overy ever device part of the driver */ + DeviceObject = DriverObject->DeviceObject; + while (DeviceObject) + { + /* Free and delete the information about this device */ + NextDevice = DeviceObject->NextDevice; + FreeDeviceData(DeviceObject); + IoDeleteDevice(DeviceObject); + + /* Move on to the next one */ + DeviceObject = NextDevice; + } + + /* Free the driver data and exit */ + FreeGlobalData(); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC UnloadHandler: Exiting.\n"); } diff --git a/reactos/drivers/sac/driver/init.c b/reactos/drivers/sac/driver/init.c index 0542d1091da..e0f0a4588a5 100644 --- a/reactos/drivers/sac/driver/init.c +++ b/reactos/drivers/sac/driver/init.c @@ -1,94 +1,94 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/init.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/init.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +/* FUNCTIONS *****************************************************************/ NTSTATUS NTAPI -DriverEntry( - IN PDRIVER_OBJECT DriverObject, - IN PUNICODE_STRING RegistryPath - ) +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) { - HEADLESS_RSP_QUERY_INFO HeadlessInformation; - ULONG InfoSize; - NTSTATUS Status; - UNICODE_STRING DriverName; - PDEVICE_OBJECT DeviceObject; - PSAC_DEVICE_EXTENSION DeviceExtension; - PAGED_CODE(); + HEADLESS_RSP_QUERY_INFO HeadlessInformation; + ULONG InfoSize = sizeof(HeadlessInformation); + NTSTATUS Status; + UNICODE_STRING DriverName; + PDEVICE_OBJECT DeviceObject; + PSAC_DEVICE_EXTENSION DeviceExtension; + PAGED_CODE(); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); + /* Check if EMS is enabled in the kernel */ + HeadlessDispatch(HeadlessCmdQueryInformation, + NULL, + 0, + &HeadlessInformation, + &InfoSize); + if ((HeadlessInformation.Serial.TerminalType != HeadlessUndefinedPortType) && + ((HeadlessInformation.Serial.TerminalType != HeadlessSerialPort) || + (HeadlessInformation.Serial.TerminalAttached))) + { + /* It is, so create the device */ + RtlInitUnicodeString(&DriverName, L"\\Device\\SAC"); + Status = IoCreateDevice(DriverObject, + sizeof(SAC_DEVICE_EXTENSION), + &DriverName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + FALSE, + &DeviceObject); + if (NT_SUCCESS(Status)) + { + /* Setup the device extension */ + DeviceExtension = DeviceObject->DeviceExtension; + DeviceExtension->Initialized = FALSE; - HeadlessDispatch( - HeadlessCmdQueryInformation, - NULL, - 0, - &HeadlessInformation, - &InfoSize - ); - if ((HeadlessInformation.Serial.TerminalType != HeadlessUndefinedPortType) && - ((HeadlessInformation.Serial.TerminalType != HeadlessSerialPort) || - (HeadlessInformation.Serial.TerminalAttached))) - { - RtlInitUnicodeString(&DriverName, L"\\Device\\SAC"); + /* Initialize the driver object */ + RtlFillMemoryUlong(DriverObject->MajorFunction, + RTL_NUMBER_OF(DriverObject->MajorFunction), + (ULONG_PTR)Dispatch); + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl; + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = DispatchShutdownControl; + DriverObject->FastIoDispatch = NULL; + DriverObject->DriverUnload = UnloadHandler; - Status = IoCreateDevice( - DriverObject, - sizeof(SAC_DEVICE_EXTENSION), - &DriverName, - FILE_DEVICE_UNKNOWN, - FILE_DEVICE_SECURE_OPEN, - FALSE, - &DeviceObject - ); - if (NT_SUCCESS(Status)) - { - DeviceExtension = DeviceObject->DeviceExtension; - DeviceExtension->Initialized = FALSE; + /* Initialize driver data */ + if (InitializeGlobalData(RegistryPath, DriverObject)) + { + /* Initialize device data */ + if (InitializeDeviceData(DeviceObject)) + { + /* We're all good, register a shutdown notification */ + IoRegisterShutdownNotification(DeviceObject); + return Status; + } + } - RtlFillMemoryUlong( - DriverObject->MajorFunction, - sizeof(DriverObject->MajorFunction) / sizeof(PVOID), - (ULONG_PTR)Dispatch); - DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = - DispatchDeviceControl; - DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = - DispatchShutdownControl; - DriverObject->FastIoDispatch = NULL; - DriverObject->DriverUnload = UnloadHandler; + /* One of the initializations failed, bail out */ + Status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + /* Print a debug statement if enabled */ + SAC_DBG(SAC_DBG_INIT, "unable to create device object: %X\n", Status); + } - if (InitializeGlobalData(RegistryPath, DriverObject)) - { - if (InitializeDeviceData(DeviceObject)) - { - IoRegisterShutdownNotification(DeviceObject); - return Status; - } - } + /* Free any data we may have allocated and exit with failure */ + FreeGlobalData(); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status 0x%x\n", Status); + return Status; + } - Status = STATUS_INSUFFICIENT_RESOURCES; - } - else - { - SAC_DBG(SAC_DBG_INIT, "unable to create device object: %X\n", Status); - } - - FreeGlobalData(); - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status 0x%x\n", Status); - return Status; - } - - return STATUS_PORT_DISCONNECTED; + /* EMS is not enabled */ + return STATUS_PORT_DISCONNECTED; } diff --git a/reactos/drivers/sac/driver/memory.c b/reactos/drivers/sac/driver/memory.c index fb77febccf6..6dfe2f1625e 100644 --- a/reactos/drivers/sac/driver/memory.c +++ b/reactos/drivers/sac/driver/memory.c @@ -1,108 +1,112 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/memory.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/memory.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ LONG TotalFrees, TotalBytesFreed, TotalAllocations, TotalBytesAllocated; KSPIN_LOCK MemoryLock; PSAC_MEMORY_LIST GlobalMemoryList; -/* FUNCTIONS ******************************************************************/ +/* FUNCTIONS *****************************************************************/ BOOLEAN +NTAPI InitializeMemoryManagement(VOID) { - PSAC_MEMORY_ENTRY Entry; + PSAC_MEMORY_ENTRY Entry; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); + /* Allocate a nonpaged heap for us to use */ + GlobalMemoryList = ExAllocatePoolWithTagPriority(NonPagedPool, + SAC_MEMORY_LIST_SIZE, + INITIAL_BLOCK_TAG, + HighPoolPriority); + if (GlobalMemoryList) + { + /* Initialize a lock for it */ + KeInitializeSpinLock(&MemoryLock); - GlobalMemoryList = ExAllocatePoolWithTagPriority( - NonPagedPool, - SAC_MEMORY_LIST_SIZE, - INITIAL_BLOCK_TAG, - HighPoolPriority); - if (GlobalMemoryList) - { - KeInitializeSpinLock(&MemoryLock); + /* Initialize the head of the list */ + GlobalMemoryList->Signature = GLOBAL_MEMORY_SIGNATURE; + GlobalMemoryList->LocalDescriptor = (PSAC_MEMORY_ENTRY)(GlobalMemoryList + 1); + GlobalMemoryList->Size = SAC_MEMORY_LIST_SIZE - sizeof(SAC_MEMORY_LIST); + GlobalMemoryList->Next = NULL; - GlobalMemoryList->Signature = GLOBAL_MEMORY_SIGNATURE; - GlobalMemoryList->LocalDescriptor = - (PSAC_MEMORY_ENTRY)(GlobalMemoryList + 1); - GlobalMemoryList->Size = SAC_MEMORY_LIST_SIZE - sizeof(SAC_MEMORY_LIST); + /* Initialize the first free entry */ + Entry = GlobalMemoryList->LocalDescriptor; + Entry->Signature = LOCAL_MEMORY_SIGNATURE; + Entry->Tag = FREE_POOL_TAG; + Entry->Size = GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY); - Entry = GlobalMemoryList->LocalDescriptor; - Entry->Signature = LOCAL_MEMORY_SIGNATURE; - Entry->Tag = FREE_POOL_TAG; - Entry->Size = GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY); + /* All done */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with TRUE.\n"); + return TRUE; + } - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with TRUE.\n"); - return TRUE; - } - - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with FALSE. No pool.\n"); - return FALSE; + /* No pool available to manage our heap */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with FALSE. No pool.\n"); + return FALSE; } VOID -FreeMemoryManagement( - VOID - ) +NTAPI +FreeMemoryManagement(VOID) { - PSAC_MEMORY_LIST Next; - KIRQL OldIrql; + PSAC_MEMORY_LIST Next; + KIRQL OldIrql; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); + /* Acquire the memory lock while freeing the list(s) */ + KeAcquireSpinLock(&MemoryLock, &OldIrql); + while (GlobalMemoryList) + { + ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); - KeAcquireSpinLock(&MemoryLock, &OldIrql); - while (GlobalMemoryList) - { - ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); + /* While outisde of the lock, save the next list and free this one */ + KeReleaseSpinLock(&MemoryLock, OldIrql); + Next = GlobalMemoryList->Next; + ExFreePoolWithTag(GlobalMemoryList, 0); - KeReleaseSpinLock(&MemoryLock, OldIrql); + /* Reacquire the lock and see if there was another list to free */ + KeAcquireSpinLock(&MemoryLock, &OldIrql); + GlobalMemoryList = Next; + } - Next = GlobalMemoryList->Next; - - ExFreePoolWithTag(GlobalMemoryList, 0); - - KeAcquireSpinLock(&MemoryLock, &OldIrql); - GlobalMemoryList = Next; - } - - KeReleaseSpinLock(&MemoryLock, OldIrql); - SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting\n"); + /* All done */ + KeReleaseSpinLock(&MemoryLock, OldIrql); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting\n"); } PVOID -MyAllocatePool( - IN SIZE_T PoolSize, - IN ULONG Tag, - IN PCHAR File, - IN ULONG Line - ) +NTAPI +MyAllocatePool(IN SIZE_T PoolSize, + IN ULONG Tag, + IN PCHAR File, + IN ULONG Line) { - KIRQL OldIrql; - PSAC_MEMORY_LIST GlobalDescriptor, NewDescriptor; - PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor; - ULONG GlobalSize, ActualSize; - PVOID Buffer; + KIRQL OldIrql; + PSAC_MEMORY_LIST GlobalDescriptor, NewDescriptor; + PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor; + ULONG GlobalSize, ActualSize; + PVOID Buffer; + ASSERT("Tag != FREE_POOL_TAG"); + SAC_DBG(SAC_DBG_MM, "Entering.\n"); - ASSERT("Tag != FREE_POOL_TAG"); + /* Acquire the memory allocation lock and align the size request */ + KeAcquireSpinLock(&MemoryLock, &OldIrql);; + PoolSize = ALIGN_UP(PoolSize, ULONGLONG); - SAC_DBG(SAC_DBG_MM, "Entering.\n"); - - OldIrql = KfAcquireSpinLock(&MemoryLock); - PoolSize = ALIGN_UP(PoolSize, ULONGLONG); - - GlobalDescriptor = GlobalMemoryList; +#if _USE_SAC_HEAP_ALLOCATOR_ + GlobalDescriptor = GlobalMemoryList; KeAcquireSpinLock(&MemoryLock, &OldIrql); while (GlobalDescriptor) { @@ -189,43 +193,60 @@ MyAllocatePool( LocalDescriptor->Size = PoolSize; } } +#else + /* Shut the compiler up */ + NewDescriptor = GlobalDescriptor = NULL; + GlobalSize = (ULONG)NewDescriptor; + ActualSize = GlobalSize; + NextDescriptor = (PVOID)ActualSize; + NewDescriptor = (PVOID)NextDescriptor; - LocalDescriptor->Tag = Tag; - KeReleaseSpinLock(&MemoryLock, OldIrql); + /* Use the NT pool allocator */ + LocalDescriptor = ExAllocatePoolWithTag(NonPagedPool, + PoolSize + sizeof(*LocalDescriptor), + Tag); + LocalDescriptor->Size = PoolSize; +#endif + /* Set the tag, and release the lock */ + LocalDescriptor->Tag = Tag; + KeReleaseSpinLock(&MemoryLock, OldIrql); - InterlockedIncrement(&TotalAllocations); - InterlockedExchangeAdd(&TotalBytesAllocated, LocalDescriptor->Size); - SAC_DBG(1, "Returning block 0x%X.\n", LocalDescriptor); + /* Update our performance counters */ + InterlockedIncrement(&TotalAllocations); + InterlockedExchangeAdd(&TotalBytesAllocated, LocalDescriptor->Size); - Buffer = LocalDescriptor + 1; - RtlZeroMemory(Buffer, PoolSize); - return Buffer; + /* Return the buffer and zero it */ + SAC_DBG(SAC_DBG_MM, "Returning block 0x%X.\n", LocalDescriptor); + Buffer = LocalDescriptor + 1; + RtlZeroMemory(Buffer, PoolSize); + return Buffer; } VOID -MyFreePool( - IN PVOID *Block - ) +NTAPI +MyFreePool(IN PVOID *Block) { - PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor; - PSAC_MEMORY_ENTRY ThisDescriptor, FoundDescriptor; - ULONG GlobalSize, LocalSize; - PSAC_MEMORY_LIST GlobalDescriptor; - KIRQL OldIrql; + PSAC_MEMORY_ENTRY NextDescriptor; + PSAC_MEMORY_ENTRY ThisDescriptor, FoundDescriptor; + PSAC_MEMORY_ENTRY LocalDescriptor = (PVOID)((ULONG_PTR)(*Block) - sizeof(SAC_MEMORY_ENTRY)); + ULONG GlobalSize, LocalSize; + PSAC_MEMORY_LIST GlobalDescriptor; + KIRQL OldIrql; + SAC_DBG(SAC_DBG_MM, "Entering with block 0x%X.\n", LocalDescriptor); - LocalDescriptor = (PVOID)((ULONG_PTR)(*Block) - sizeof(SAC_MEMORY_ENTRY)); + /* Make sure this was a valid entry */ + ASSERT(LocalDescriptor->Size > 0); + ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); - SAC_DBG(SAC_DBG_MM, "Entering with block 0x%X.\n", LocalDescriptor); + /* Update performance counters */ + InterlockedIncrement(&TotalFrees); + InterlockedExchangeAdd(&TotalBytesFreed, LocalDescriptor->Size); - ASSERT(LocalDescriptor->Size > 0); - ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE); + /* Acquire the memory alliocation lock */ + GlobalDescriptor = GlobalMemoryList; + KeAcquireSpinLock(&MemoryLock, &OldIrql); - InterlockedIncrement(&TotalFrees); - - InterlockedExchangeAdd(&TotalBytesFreed, LocalDescriptor->Size); - - GlobalDescriptor = GlobalMemoryList; - KeAcquireSpinLock(&MemoryLock, &OldIrql); +#if _USE_SAC_HEAP_ALLOCATOR_ while (GlobalDescriptor) { ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE); @@ -297,10 +318,22 @@ MyFreePool( FoundDescriptor->Size += (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY)); } +#else + /* Shut the compiler up */ + LocalSize = GlobalSize = 0; + ThisDescriptor = (PVOID)LocalSize; + NextDescriptor = (PVOID)GlobalSize; + GlobalDescriptor = (PVOID) ThisDescriptor; + FoundDescriptor = (PVOID)GlobalDescriptor; + GlobalDescriptor = (PVOID) NextDescriptor; + NextDescriptor = (PVOID) FoundDescriptor; - KeReleaseSpinLock(&MemoryLock, OldIrql); - *Block = NULL; + /* Use the NT pool allocator*/ + ExFreePool(LocalDescriptor); +#endif - SAC_DBG(SAC_DBG_MM, "exiting.\n"); - return; + /* Release the lock, delete the address, and return */ + KeReleaseSpinLock(&MemoryLock, OldIrql); + *Block = NULL; + SAC_DBG(SAC_DBG_MM, "exiting.\n"); } diff --git a/reactos/drivers/sac/driver/rawchan.c b/reactos/drivers/sac/driver/rawchan.c index 6a38bd0a97c..098d78dd97a 100644 --- a/reactos/drivers/sac/driver/rawchan.c +++ b/reactos/drivers/sac/driver/rawchan.c @@ -1,143 +1,373 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/rawchan.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/rawchan.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +/* FUNCTIONS *****************************************************************/ + +#define SAC_RAW_OBUFFER_SIZE 0x2000 +#define SAC_RAW_IBUFFER_SIZE 0x2000 NTSTATUS -RawChannelCreate( - IN PSAC_CHANNEL Channel - ) +NTAPI +RawChannelCreate(IN PSAC_CHANNEL Channel) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER(Channel); + + Channel->OBuffer = SacAllocatePool(SAC_RAW_OBUFFER_SIZE, GLOBAL_BLOCK_TAG); + CHECK_ALLOCATION(Channel->OBuffer); + + Channel->IBuffer = SacAllocatePool(SAC_RAW_IBUFFER_SIZE, GLOBAL_BLOCK_TAG); + CHECK_ALLOCATION(Channel->IBuffer); + + Channel->OBufferIndex = 0; + Channel->OBufferFirstGoodIndex = 0; + Channel->ChannelHasNewIBufferData = FALSE; + Channel->ChannelHasNewOBufferData = FALSE; + + return STATUS_SUCCESS; } NTSTATUS -RawChannelDestroy( - IN PSAC_CHANNEL Channel - ) +NTAPI +RawChannelDestroy(IN PSAC_CHANNEL Channel) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER(Channel); + + if (Channel->OBuffer) + { + SacFreePool(Channel->OBuffer); + } + + if (Channel->IBuffer) + { + SacFreePool(Channel->IBuffer); + } + + return ChannelDestroy(Channel); +} + +FORCEINLINE +BOOLEAN +ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel) +{ + return Channel->ChannelHasNewOBufferData; +} + +FORCEINLINE +BOOLEAN +ChannelHasNewIBufferData(IN PSAC_CHANNEL Channel) +{ + return Channel->ChannelHasNewIBufferData; } NTSTATUS -RawChannelORead( - IN PSAC_CHANNEL Channel, - IN PCHAR Buffer, - IN ULONG BufferSize, - OUT PULONG ByteCount - ) +NTAPI +RawChannelORead(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + OUT PULONG ByteCount) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + ULONG NextIndex; + + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Buffer); + CHECK_PARAMETER3(BufferSize > 0); + CHECK_PARAMETER4(ByteCount); + + *ByteCount = 0; + + if (ChannelHasNewOBufferData(Channel)) + { + Status = STATUS_SUCCESS; + + while (TRUE) + { + Buffer[(*ByteCount)++] = Channel->OBuffer[Channel->OBufferFirstGoodIndex]; + + NextIndex = (Channel->OBufferFirstGoodIndex + 1) & (SAC_OBUFFER_SIZE - 1); + Channel->OBufferFirstGoodIndex = NextIndex; + + if (NextIndex == Channel->OBufferIndex) + { + _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); + break; + } + + ASSERT(*ByteCount > 0); + + if (*ByteCount >= BufferSize) break; + } + } + else + { + Status = STATUS_NO_DATA_DETECTED; + } + + if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex) + { + ASSERT(ChannelHasNewOBufferData(Channel) == FALSE); + } + + if (ChannelHasNewOBufferData(Channel) == FALSE) + { + ASSERT(Channel->OBufferFirstGoodIndex == Channel->OBufferIndex); + } + + return Status; } NTSTATUS -RawChannelOEcho( - IN PSAC_CHANNEL Channel, - IN PWCHAR String, - IN ULONG Length - ) +NTAPI +RawChannelOEcho(IN PSAC_CHANNEL Channel, + IN PCHAR String, + IN ULONG Length) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status = STATUS_SUCCESS; + + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(String); + + if (Length) + { + Status = ConMgrWriteData(Channel, String, Length); + if (NT_SUCCESS(Status)) ConMgrFlushData(Channel); + } + + return Status; } NTSTATUS -RawChannelOWrite2( - IN PSAC_CHANNEL Channel, - IN PCHAR String, - IN ULONG Size - ) +NTAPI +RawChannelOWrite2(IN PSAC_CHANNEL Channel, + IN PCHAR String, + IN ULONG Size) { - return STATUS_NOT_IMPLEMENTED; + BOOLEAN Overflow; + ULONG i, NextIndex; + + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(String); + + Overflow = FALSE; + + for (i = 0; i < Size; i++) + { + if ((Channel->OBufferIndex == Channel->OBufferFirstGoodIndex) && + ((i) || (ChannelHasNewOBufferData(Channel)))) + { + Overflow = TRUE; + } + + ASSERT(Channel->OBufferIndex < SAC_RAW_OBUFFER_SIZE); + + Channel->OBuffer[Channel->OBufferIndex] = String[i]; + + NextIndex = (Channel->OBufferIndex + 1) & (SAC_RAW_OBUFFER_SIZE - 1); + Channel->OBufferIndex = NextIndex; + + if (Overflow) Channel->OBufferFirstGoodIndex = NextIndex; + } + + _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1); + + return STATUS_SUCCESS; } NTSTATUS -RawChannelOFlush( - IN PSAC_CHANNEL Channel - ) +NTAPI +RawChannelOFlush(IN PSAC_CHANNEL Channel) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + ULONG ByteCount; + CHAR Dummy; + CHECK_PARAMETER1(Channel); + + while (ChannelHasNewOBufferData(Channel)) + { + Status = RawChannelORead(Channel, &Dummy, sizeof(Dummy), &ByteCount); + if (!NT_SUCCESS(Status)) return Status; + + CHECK_PARAMETER_WITH_STATUS(ByteCount == 1, STATUS_UNSUCCESSFUL); + + Status = ConMgrWriteData(Channel, &Dummy, sizeof(Dummy)); + if (!NT_SUCCESS(Status)) return Status; + } + + return ConMgrFlushData(Channel); } ULONG -RawChannelGetIBufferIndex( - IN PSAC_CHANNEL Channel - ) +NTAPI +RawChannelGetIBufferIndex(IN PSAC_CHANNEL Channel) { - return 0; + ASSERT(Channel); + ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE); + + return Channel->IBufferIndex; } VOID -RawChannelSetIBufferIndex( - IN PSAC_CHANNEL Channel, - IN ULONG BufferIndex - ) +NTAPI +RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel, + IN ULONG BufferIndex) { + NTSTATUS Status; + ASSERT(Channel); + ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE); + Channel->IBufferIndex = BufferIndex; + Channel->ChannelHasNewIBufferData = BufferIndex != 0; + + if (!Channel->IBufferIndex) + { + if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) + { + ChannelClearEvent(Channel, HasNewDataEvent); + UNREFERENCED_PARAMETER(Status); + } + } } NTSTATUS -RawChannelOWrite( - IN PSAC_CHANNEL Channel, - IN PWCHAR String, - IN ULONG Length - ) +NTAPI +RawChannelOWrite(IN PSAC_CHANNEL Channel, + IN PCHAR String, + IN ULONG Length) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(String); + + if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled)) + { + return RawChannelOEcho(Channel, String, Length); + } + + return RawChannelOWrite2(Channel, String, Length); } NTSTATUS -RawChannelIRead( - IN PSAC_CHANNEL Channel, - IN PCHAR Buffer, - IN ULONG BufferSize, - IN PULONG ReturnBufferSize - ) +NTAPI +RawChannelIRead(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + IN PULONG ReturnBufferSize) { - return STATUS_NOT_IMPLEMENTED; + ULONG CopyChars; + + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Buffer); + CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE); + + *ReturnBufferSize = 0; + + if (Channel->ChannelInputBufferLength(Channel) == 0) + { + ASSERT(ChannelHasNewIBufferData(Channel) == FALSE); + } + else + { + CopyChars = Channel->ChannelInputBufferLength(Channel); + if (CopyChars > BufferSize) CopyChars = BufferSize; + ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel)); + + RtlCopyMemory(Buffer, Channel->IBuffer, CopyChars); + + RawChannelSetIBufferIndex(Channel, + RawChannelGetIBufferIndex(Channel) - CopyChars); + + if (Channel->ChannelInputBufferLength(Channel)) + { + RtlMoveMemory(Channel->IBuffer, + &Channel->IBuffer[CopyChars], + Channel->ChannelInputBufferLength(Channel)); + } + + *ReturnBufferSize = CopyChars; + } + + return STATUS_SUCCESS; } NTSTATUS -RawChannelIBufferIsFull( - IN PSAC_CHANNEL Channel, - PBOOLEAN BufferStatus - ) +NTAPI +RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel, + OUT PBOOLEAN BufferStatus) { - return STATUS_NOT_IMPLEMENTED; + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(BufferStatus); + + *BufferStatus = RawChannelGetIBufferIndex(Channel) > SAC_RAW_IBUFFER_SIZE; + return STATUS_SUCCESS; } ULONG -RawChannelIBufferLength( - IN PSAC_CHANNEL Channel - ) +NTAPI +RawChannelIBufferLength(IN PSAC_CHANNEL Channel) { - return 0; + ASSERT(Channel); + return RawChannelGetIBufferIndex(Channel); } CHAR -RawChannelIReadLast( - IN PSAC_CHANNEL Channel - ) +NTAPI +RawChannelIReadLast(IN PSAC_CHANNEL Channel) { - return 0; + UCHAR LastChar = 0; + + ASSERT(Channel); + + if (Channel->ChannelInputBufferLength(Channel)) + { + RawChannelSetIBufferIndex(Channel, RawChannelGetIBufferIndex(Channel) - 1); + + LastChar = Channel->IBuffer[RawChannelGetIBufferIndex(Channel)]; + Channel->IBuffer[RawChannelGetIBufferIndex(Channel)] = 0; + } + + return LastChar; } NTSTATUS -RawChannelIWrite( - IN PSAC_CHANNEL Channel, - IN PCHAR Buffer, - IN ULONG BufferSize - ) +NTAPI +RawChannelIWrite(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize) { - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + BOOLEAN IsFull; + ULONG Index; + + CHECK_PARAMETER1(Channel); + CHECK_PARAMETER2(Buffer); + CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE); + + Status = RawChannelIBufferIsFull(Channel, &IsFull); + if (!NT_SUCCESS(Status)) return Status; + + if (IsFull) return STATUS_UNSUCCESSFUL; + + Index = RawChannelGetIBufferIndex(Channel); + if ((SAC_RAW_IBUFFER_SIZE - Index) >= BufferSize) return STATUS_INSUFFICIENT_RESOURCES; + + RtlCopyMemory(&Channel->IBuffer[Index], Buffer, BufferSize); + + RawChannelSetIBufferIndex(Channel, BufferSize + Index); + + if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) + { + ChannelSetEvent(Channel, HasNewDataEvent); + } + + return STATUS_SUCCESS; } diff --git a/reactos/drivers/sac/driver/sacdrv.h b/reactos/drivers/sac/driver/sacdrv.h index 0936712eb61..fef618c989a 100644 --- a/reactos/drivers/sac/driver/sacdrv.h +++ b/reactos/drivers/sac/driver/sacdrv.h @@ -1,390 +1,1016 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/sacdrv.h - * PURPOSE: Header for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/sacdrv.h + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ + #include -#include +#include +#include +#include +#include +#include +#include <../../../ntoskrnl/include/internal/hdl.h> +#include +#include -#define SAC_DBG_ENTRY_EXIT 0x01 -#define SAC_DBG_INIT 0x04 -#define SAC_DBG_MM 0x1000 +/* DEFINES *******************************************************************/ -#define SAC_DBG(x, ...) \ - if (SACDebug & x) \ - { \ - DbgPrint("SAC %s: ", __FUNCTION__); \ - DbgPrint(__VA_ARGS__); \ - } +// +// SAC Heap Allocator Macros +// +#define SacAllocatePool(Length, Tag) \ + MyAllocatePool(Length, Tag, __FILE__, __LINE__) +#define SacFreePool(Pointer) \ + MyFreePool((PVOID*)(&Pointer)) -#define CHECK_PARAMETER_WITH_STATUS(Parameter, Status) \ -{ \ - ASSERT((Parameter)); \ - if (!Parameter) \ - { \ - return Status; \ - } \ +// +// SAC Debugging Macro and Constants +// +#define SAC_DBG_ENTRY_EXIT 0x01 +#define SAC_DBG_UTIL 0x02 +#define SAC_DBG_INIT 0x04 +#define SAC_DBG_MM 0x1000 +#define SAC_DBG(x, ...) \ + if (SACDebug & x) \ + { \ + DbgPrint("SAC %s: ", __FUNCTION__); \ + DbgPrint(__VA_ARGS__); \ + } + +// +// SAC Parameter Checking Macros +// +#define CHECK_PARAMETER_WITH_STATUS(Parameter, Status) \ +{ \ + ASSERT(((PVOID)(Parameter)) != NULL); \ + if (((PVOID)(Parameter)) == NULL) \ + { \ + return Status; \ + } \ } -#define CHECK_PARAMETER(x) \ - CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER) -#define CHECK_PARAMETER1(x) \ - CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_1) -#define CHECK_PARAMETER2(x) \ - CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_2) -#define CHECK_PARAMETER3(x) \ - CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_3) -#define CHECK_ALLOCATION(x) \ - CHECK_PARAMETER_WITH_STATUS(x, STATUS_OUT_OF_MEMORY) - -#define SacAllocatePool(Length, Tag) \ - MyAllocatePool(Length, Tag, __FILE__, __LINE__) +#define CHECK_PARAMETER(x) \ + CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER) +#define CHECK_PARAMETER1(x) \ + CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_1) +#define CHECK_PARAMETER2(x) \ + CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_2) +#define CHECK_PARAMETER3(x) \ + CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_3) +#define CHECK_PARAMETER4(x) \ + CHECK_PARAMETER_WITH_STATUS(x, STATUS_INVALID_PARAMETER_4) +#define CHECK_ALLOCATION(x) \ + CHECK_PARAMETER_WITH_STATUS(x, STATUS_NO_MEMORY) -#define ChannelLock(Channel, x) \ -{ \ - KeWaitForSingleObject( \ - &(Channel)->x.Lock, \ - Executive, \ - KernelMode, \ - FALSE, \ - NULL); \ - ASSERT((Channel)->x.RefCount == 0); \ - InterlockedIncrement(&(Channel)->x.RefCount); \ +// +// SAC Channel Event Macros +// +#define ChannelInitializeEvent(Channel, Attributes, x) \ +{ \ + PVOID Object, WaitObject; \ + if (Attributes->x) \ + { \ + if (!VerifyEventWaitable(Attributes->x, &Object, &WaitObject)) \ + { \ + goto FailChannel; \ + } \ + Channel->x = Attributes->x; \ + Channel->x##ObjectBody = Object; \ + Channel->x##WaitObjectBody = WaitObject; \ + } \ +} +#define ChannelUninitializeEvent(Channel, x, f) \ +{ \ + ASSERT(ChannelGetFlags(Channel) & (f)); \ + ASSERT(Channel->x##ObjectBody); \ + ASSERT(Channel->x##WaitObjectBody); \ + if (Channel->x##ObjectBody) \ + { \ + ObDereferenceObject(Channel->x##ObjectBody); \ + Channel->Flags &= ~(f); \ + Channel->x = NULL; \ + Channel->x##ObjectBody = NULL; \ + Channel->x##WaitObjectBody = NULL; \ + } \ +} +#define ChannelSetEvent(Channel, x) \ +{ \ + ASSERT(Channel->x); \ + ASSERT(Channel->x##ObjectBody); \ + ASSERT(Channel->x##WaitObjectBody); \ + if (Channel->x##WaitObjectBody) \ + { \ + KeSetEvent(Channel->x##WaitObjectBody, EVENT_INCREMENT, FALSE); \ + Status = STATUS_SUCCESS; \ + } \ + else \ + { \ + Status = STATUS_UNSUCCESSFUL; \ + } \ +} +#define ChannelClearEvent(Channel, x) \ +{ \ + ASSERT(Channel->x); \ + ASSERT(Channel->x##ObjectBody); \ + ASSERT(Channel->x##WaitObjectBody); \ + if (Channel->x##WaitObjectBody) \ + { \ + KeClearEvent(Channel->x##WaitObjectBody); \ + Status = STATUS_SUCCESS; \ + } \ + else \ + { \ + Status = STATUS_UNSUCCESSFUL; \ + } \ } -#define ChannelUnlock(Channel, x) \ -{ \ - ASSERT((Channel)->x.RefCount == 1); \ - InterlockedDecrement(&(Channel)->x.RefCount); \ - KeReleaseSemaphore( \ - &(Channel)->x.Lock, \ - SEMAPHORE_INCREMENT, \ - 1, \ - FALSE); \ -} +// +// SAC Pool Tags, taken from pooltag.txt: +// +// Rcp? - sacdrv.sys - SAC Driver (Headless) +// RcpA - sacdrv.sys - Internal memory mgr alloc block +// RcpI - sacdrv.sys - Internal memory mgr initial heap block +// RcpS - sacdrv.sys - Security related block +#define GENERIC_TAG '?pcR' +#define ALLOC_BLOCK_TAG 'ApcR' +#define INITIAL_BLOCK_TAG 'IpcR' +#define SECURITY_BLOCK_TAG 'SpcR' +#define FREE_POOL_TAG 'FpcR' +#define GLOBAL_BLOCK_TAG 'GpcR' +#define CHANNEL_BLOCK_TAG 'CpcR' +#define LOCAL_MEMORY_SIGNATURE 'SSEL' +#define GLOBAL_MEMORY_SIGNATURE 'DAEH' -#define ChannelLockOBuffer(Channel) ChannelLock(Channel, ChannelOBufferLock); -#define ChannelUnlockOBuffer(Channel) ChannelUnlock(Channel, ChannelOBufferLock); -#define ChannelLockIBuffer(Channel) ChannelLock(Channel, ChannelIBufferLock); -#define ChannelUnlockIBuffer(Channel) ChannelUnlock(Channel, ChannelIBufferLock); -#define ChannelLockAttributes(Channel) ChannelLock(Channel, ChannelAttributesLock); -#define ChannelUnlockAttributes(Channel) ChannelUnlock(Channel, ChannelAttributesLock); +// +// Size Definitions +// +#define SAC_MEMORY_LIST_SIZE (1 * 1024 * 1024) // 1MB +#define SAC_OBUFFER_SIZE (2 * 1024) // 2KB +#define SAC_CHANNEL_NAME_SIZE 64 +#define SAC_CHANNEL_DESCRIPTION_SIZE 256 +#define SAC_MAX_CHANNELS 10 +#define SAC_SERIAL_PORT_BUFFER_SIZE 1024 // 1KB +#define SAC_MAX_MESSAGES 200 -#define ChannelInitializeEvent(Channel, Attributes, x) \ -{ \ - PVOID Object, WaitObject; \ - if (Attributes->x) \ - { \ - if (!VerifyEventWaitable(Attributes->x, &Object, &WaitObject)) \ - { \ - goto FailChannel; \ - } \ - Channel->x = Attributes->x; \ - Channel->x##ObjectBody = Object; \ - Channel->x##WaitObjectBody = WaitObject; \ - } \ -} - -#define ChannelSetEvent(Channel, x) \ -{ \ - ASSERT(Channel->x); \ - ASSERT(Channel->x##ObjectBody); \ - ASSERT(Channel->x##WaitObjectBody); \ - if (Channel->x) \ - { \ - KeSetEvent(Channel->x, EVENT_INCREMENT, FALSE); \ - Status = STATUS_SUCCESS; \ - } \ - else \ - { \ - Status = STATUS_UNSUCCESSFUL; \ - } \ -} - -#define ChannelClearEvent(Channel, x) \ -{ \ - ASSERT(Channel->x); \ - ASSERT(Channel->x##ObjectBody); \ - ASSERT(Channel->x##WaitObjectBody); \ - if (Channel->x) \ - { \ - KeClearEvent(Channel->x); \ - Status = STATUS_SUCCESS; \ - } \ - else \ - { \ - Status = STATUS_UNSUCCESSFUL; \ - } \ -} - -//Rcp? - sacdrv.sys - SAC Driver (Headless) -//RcpA - sacdrv.sys - Internal memory mgr alloc block -//RcpI - sacdrv.sys - Internal memory mgr initial heap block -//RcpS - sacdrv.sys - Security related block -#define GENERIC_TAG '?pcR' -#define ALLOC_BLOCK_TAG 'ApcR' -#define INITIAL_BLOCK_TAG 'IpcR' -#define SECURITY_BLOCK_TAG 'SpcR' -#define FREE_POOL_TAG 'FpcR' - -#define LOCAL_MEMORY_SIGNATURE 'SSEL' -#define GLOBAL_MEMORY_SIGNATURE 'DAEH' - -#define SAC_MEMORY_LIST_SIZE (1 * 1024 * 1024) - -#define SAC_OBUFFER_SIZE (2 * 1024) - -#define SAC_CHANNEL_FLAG_CLOSE_EVENT 0x2 -#define SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT 0x4 -#define SAC_CHANNEL_FLAG_LOCK_EVENT 0x8 -#define SAC_CHANNEL_FLAG_REDRAW_EVENT 0x10 - -typedef struct _SAC_MEMORY_ENTRY -{ - ULONG Signature; - ULONG Tag; - ULONG Size; -} SAC_MEMORY_ENTRY, *PSAC_MEMORY_ENTRY; - -typedef struct _SAC_MEMORY_LIST -{ - ULONG Signature; - PSAC_MEMORY_ENTRY LocalDescriptor; - ULONG Size; - struct _SAC_MEMORY_LIST* Next; -} SAC_MEMORY_LIST, *PSAC_MEMORY_LIST; - -typedef enum _SAC_CHANNEL_TYPE -{ - VtUtf8, - Cmd, - Raw -} SAC_CHANNEL_TYPE; - -typedef enum _SAC_CHANNEL_STATUS -{ - Inactive, - Active -} SAC_CHANNEL_STATUS, *PSAC_CHANNEL_STATUS; - -typedef struct _SAC_CHANNEL_ID -{ - GUID ChannelGuid; - ULONG ChannelId; -} SAC_CHANNEL_ID, *PSAC_CHANNEL_ID; - -typedef struct _SAC_CHANNEL_LOCK -{ - LONG RefCount; - KSEMAPHORE Lock; -} SAC_CHANNEL_LOCK, *PSAC_CHANNEL_LOCK; +// +// Channel flags +// +#define SAC_CHANNEL_FLAG_INTERNAL 0x1 +#define SAC_CHANNEL_FLAG_CLOSE_EVENT 0x2 +#define SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT 0x4 +#define SAC_CHANNEL_FLAG_LOCK_EVENT 0x8 +#define SAC_CHANNEL_FLAG_REDRAW_EVENT 0x10 +#define SAC_CHANNEL_FLAG_APPLICATION 0x20 +// +// Forward definitions +// struct _SAC_CHANNEL; +// +// Structures used by the SAC Heap Allocator +// +typedef struct _SAC_MEMORY_ENTRY +{ + ULONG Signature; + ULONG Tag; + ULONG Size; +} SAC_MEMORY_ENTRY, *PSAC_MEMORY_ENTRY; +typedef struct _SAC_MEMORY_LIST +{ + ULONG Signature; + PSAC_MEMORY_ENTRY LocalDescriptor; + ULONG Size; + struct _SAC_MEMORY_LIST* Next; +} SAC_MEMORY_LIST, *PSAC_MEMORY_LIST; + +typedef struct _SAC_MESSAGE_ENTRY +{ + ULONG Index; + PWCHAR Buffer; +} SAC_MESSAGE_ENTRY, *PSAC_MESSAGE_ENTRY; + +// +// SAC supports 3 different channel output types +// +typedef enum _SAC_CHANNEL_TYPE +{ + VtUtf8, + Cmd, + Raw +} SAC_CHANNEL_TYPE; + +// +// A SAC channel can be active or inactive +// +typedef enum _SAC_CHANNEL_STATUS +{ + Inactive, + Active +} SAC_CHANNEL_STATUS, *PSAC_CHANNEL_STATUS; + +// +// A SAC channel identifier +// +typedef struct _SAC_CHANNEL_ID +{ + GUID ChannelGuid; + ULONG ChannelId; +} SAC_CHANNEL_ID, *PSAC_CHANNEL_ID; + +// +// Reference-counted SAC channel semaphore lock +// +typedef struct _SAC_CHANNEL_LOCK +{ + LONG RefCount; + KSEMAPHORE Lock; +} SAC_CHANNEL_LOCK, *PSAC_CHANNEL_LOCK; + +// +// Channel callbacks +// typedef NTSTATUS -(*PSAC_CHANNEL_CREATE)( - IN struct _SAC_CHANNEL* Channel - ); +(NTAPI *PSAC_CHANNEL_CREATE)( + IN struct _SAC_CHANNEL* Channel +); typedef NTSTATUS -(*PSAC_CHANNEL_DESTROY)( - IN struct _SAC_CHANNEL* Channel - ); +(NTAPI *PSAC_CHANNEL_DESTROY)( + IN struct _SAC_CHANNEL* Channel +); typedef NTSTATUS -(*PSAC_CHANNEL_OREAD)( - IN struct _SAC_CHANNEL* Channel, - IN PCHAR Buffer, - IN ULONG BufferSize, - OUT PULONG ByteCount - ); +(NTAPI *PSAC_CHANNEL_OREAD)( + IN struct _SAC_CHANNEL* Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + OUT PULONG ByteCount +); typedef NTSTATUS -(*PSAC_CHANNEL_OECHO)( - IN struct _SAC_CHANNEL* Channel, - IN PWCHAR String, - IN ULONG Length - ); +(NTAPI *PSAC_CHANNEL_OECHO)( + IN struct _SAC_CHANNEL* Channel, + IN PCHAR String, + IN ULONG Length +); typedef NTSTATUS -(*PSAC_CHANNEL_OFLUSH)( - IN struct _SAC_CHANNEL* Channel - ); +(NTAPI *PSAC_CHANNEL_OFLUSH)( + IN struct _SAC_CHANNEL* Channel +); typedef NTSTATUS -(*PSAC_CHANNEL_OWRITE)( - IN struct _SAC_CHANNEL* Channel, - IN PWCHAR String, - IN ULONG Length - ); +(NTAPI *PSAC_CHANNEL_OWRITE)( + IN struct _SAC_CHANNEL* Channel, + IN PCHAR String, + IN ULONG Length +); typedef NTSTATUS -(*PSAC_CHANNEL_IREAD)( - IN struct _SAC_CHANNEL* Channel, - IN PWCHAR Buffer, - IN ULONG BufferSize, - IN PULONG ReturnBufferSize - ); +(NTAPI *PSAC_CHANNEL_IREAD)( + IN struct _SAC_CHANNEL* Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + IN PULONG ReturnBufferSize +); typedef NTSTATUS -(*PSAC_CHANNEL_IBUFFER_FULL)( - IN struct _SAC_CHANNEL* Channel, - OUT PBOOLEAN BufferStatus - ); +(NTAPI *PSAC_CHANNEL_IBUFFER_FULL)( + IN struct _SAC_CHANNEL* Channel, + OUT PBOOLEAN BufferStatus +); typedef -NTSTATUS -(*PSAC_CHANNEL_IBUFFER_LENGTH)( - IN struct _SAC_CHANNEL* Channel - ); +ULONG +(NTAPI *PSAC_CHANNEL_IBUFFER_LENGTH)( + IN struct _SAC_CHANNEL* Channel +); typedef CHAR -(*PSAC_CHANNEL_IREAD_LAST)( - IN struct _SAC_CHANNEL* Channel - ); +(NTAPI *PSAC_CHANNEL_IREAD_LAST)( + IN struct _SAC_CHANNEL* Channel +); typedef NTSTATUS -(*PSAC_CHANNEL_IWRITE)( - IN struct _SAC_CHANNEL* Channel, - IN PCHAR Buffer, - IN ULONG BufferSize - ); +(NTAPI *PSAC_CHANNEL_IWRITE)( + IN struct _SAC_CHANNEL* Channel, + IN PCHAR Buffer, + IN ULONG BufferSize +); +// +// A channel and its attributes +// typedef struct _SAC_CHANNEL { - ULONG Index; - SAC_CHANNEL_ID ChannelId; - HANDLE CloseEvent; - PVOID CloseEventObjectBody; - PKEVENT CloseEventWaitObjectBody; - HANDLE HasNewDataEvent; - PVOID HasNewDataEventObjectBody; - PKEVENT HasNewDataEventWaitObjectBody; - HANDLE LockEvent; - PVOID LockEventObjectBody; - PKEVENT LockEventWaitObjectBody; - HANDLE RedrawEvent; - PVOID RedrawEventObjectBody; - PKEVENT RedrawEventWaitObjectBody; - PFILE_OBJECT FileObject; - SAC_CHANNEL_TYPE ChannelType; - SAC_CHANNEL_STATUS ChannelStatus; - WCHAR NameBuffer[64 + 1]; - WCHAR DescriptionBuffer[256 + 1]; - ULONG Flags; - GUID ApplicationType; - BOOLEAN WriteEnabled; - ULONG IBufferIndex; - PVOID IBuffer; - BOOLEAN ChannelHasNewIBufferData; - UCHAR CursorRow; - UCHAR CursorCol; - UCHAR CursorY; - UCHAR CursorX; - UCHAR CursorVisible; - PVOID OBuffer; - ULONG OBufferIndex; - ULONG OBufferFirstGoodIndex; - BOOLEAN ChannelHasNewOBufferData; - PSAC_CHANNEL_CREATE ChannelCreate; - PSAC_CHANNEL_DESTROY ChannelDestroy; - PSAC_CHANNEL_OFLUSH OBufferFlush; - PSAC_CHANNEL_OECHO OBufferEcho; - PSAC_CHANNEL_OWRITE OBufferWrite; - PSAC_CHANNEL_OREAD OBufferRead; - PSAC_CHANNEL_OWRITE IBufferWrite; - PSAC_CHANNEL_IREAD IBufferRead; - PSAC_CHANNEL_IREAD_LAST IBufferReadLast; - PSAC_CHANNEL_IBUFFER_FULL IBufferIsFull; - PSAC_CHANNEL_IBUFFER_LENGTH IBufferLength; - SAC_CHANNEL_LOCK ChannelAttributeLock; - SAC_CHANNEL_LOCK ChannelOBufferLock; - SAC_CHANNEL_LOCK ChannelIBufferLock; + LONG Index; + SAC_CHANNEL_ID ChannelId; + HANDLE CloseEvent; + PVOID CloseEventObjectBody; + PKEVENT CloseEventWaitObjectBody; + HANDLE HasNewDataEvent; + PVOID HasNewDataEventObjectBody; + PKEVENT HasNewDataEventWaitObjectBody; + HANDLE LockEvent; + PVOID LockEventObjectBody; + PKEVENT LockEventWaitObjectBody; + HANDLE RedrawEvent; + PVOID RedrawEventObjectBody; + PKEVENT RedrawEventWaitObjectBody; + PFILE_OBJECT FileObject; + SAC_CHANNEL_TYPE ChannelType; + SAC_CHANNEL_STATUS ChannelStatus; + WCHAR NameBuffer[SAC_CHANNEL_NAME_SIZE + 1]; + WCHAR DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE + 1]; + ULONG Flags; + GUID ApplicationType; + LONG WriteEnabled; + ULONG IBufferIndex; + PCHAR IBuffer; + LONG ChannelHasNewIBufferData; + UCHAR CursorRow; + UCHAR CursorCol; + UCHAR CursorY; + UCHAR CursorX; + UCHAR CursorVisible; + PCHAR OBuffer; + ULONG OBufferIndex; + ULONG OBufferFirstGoodIndex; + LONG ChannelHasNewOBufferData; + PSAC_CHANNEL_CREATE ChannelCreate; + PSAC_CHANNEL_DESTROY ChannelDestroy; + PSAC_CHANNEL_OFLUSH ChannelOutputFlush; + PSAC_CHANNEL_OECHO ChannelOutputEcho; + PSAC_CHANNEL_OWRITE ChannelOutputWrite; + PSAC_CHANNEL_OREAD ChannelOutputRead; + PSAC_CHANNEL_IWRITE ChannelInputWrite; + PSAC_CHANNEL_IREAD ChannelInputRead; + PSAC_CHANNEL_IREAD_LAST ChannelInputReadLast; + PSAC_CHANNEL_IBUFFER_FULL ChannelInputBufferIsFull; + PSAC_CHANNEL_IBUFFER_LENGTH ChannelInputBufferLength; + SAC_CHANNEL_LOCK ChannelAttributeLock; + SAC_CHANNEL_LOCK ChannelOBufferLock; + SAC_CHANNEL_LOCK ChannelIBufferLock; } SAC_CHANNEL, *PSAC_CHANNEL; -typedef struct _SAC_DEVICE_EXTENSION -{ - PDEVICE_OBJECT DeviceObject; - BOOLEAN Initialized; - BOOLEAN Rundown; - BOOLEAN PriorityFail; - KPRIORITY PriorityBoost; - PEPROCESS Process; - KSPIN_LOCK Lock; - KEVENT RundownEvent; - KEVENT Event; - HANDLE WorkerThreadHandle; - KEVENT WorkerThreadEvent; - KTIMER Timer; - KDPC Dpc; - LIST_ENTRY List; -} SAC_DEVICE_EXTENSION, *PSAC_DEVICE_EXTENSION; - typedef struct _SAC_CHANNEL_ATTRIBUTES { - SAC_CHANNEL_TYPE ChannelType; - WCHAR NameBuffer[64 + 1]; - WCHAR DescriptionBuffer[256 + 1]; - ULONG Flag; - PKEVENT CloseEvent; - PKEVENT HasNewDataEvent; - PKEVENT LockEvent; - PKEVENT RedrawEvent; - GUID ChannelId; + SAC_CHANNEL_TYPE ChannelType; + WCHAR NameBuffer[64 + 1]; + WCHAR DescriptionBuffer[256 + 1]; + ULONG Flag; + HANDLE CloseEvent; + HANDLE HasNewDataEvent; + HANDLE LockEvent; + HANDLE RedrawEvent; + GUID ChannelId; } SAC_CHANNEL_ATTRIBUTES, *PSAC_CHANNEL_ATTRIBUTES; +// +// Cached Machine Information +// +typedef struct _SAC_MACHINE_INFO +{ + PWCHAR MachineName; + PWCHAR MachineGuid; + PWCHAR ProcessorArchitecture; + PWCHAR MajorVersion; + PWCHAR BuildNumber; + PWCHAR ProductType; + PWCHAR ServicePack; +} SAC_MACHINE_INFO, *PSAC_MACHINE_INFO; + +// +// The device extension for the SAC +// +typedef struct _SAC_DEVICE_EXTENSION +{ + PDEVICE_OBJECT DeviceObject; + BOOLEAN Initialized; + BOOLEAN Rundown; + BOOLEAN PriorityFail; + BOOLEAN RundownInProgress; + KPRIORITY PriorityBoost; + PEPROCESS Process; + KSPIN_LOCK Lock; + KEVENT RundownEvent; + KEVENT Event; + HANDLE WorkerThreadHandle; + KEVENT WorkerThreadEvent; + KTIMER Timer; + KDPC Dpc; + LIST_ENTRY List; +} SAC_DEVICE_EXTENSION, *PSAC_DEVICE_EXTENSION; + +// +// Dispatch Routines +// NTSTATUS +NTAPI Dispatch( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp ); NTSTATUS NTAPI DispatchDeviceControl( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp ); NTSTATUS +NTAPI DispatchShutdownControl( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp ); VOID +NTAPI UnloadHandler( - IN PDRIVER_OBJECT DriverObject + IN PDRIVER_OBJECT DriverObject +); + +// +// Initialization and shutdown routines +// +VOID +NTAPI +FreeGlobalData( + VOID ); VOID -FreeGlobalData( - VOID +NTAPI +FreeDeviceData( + IN PDEVICE_OBJECT DeviceObject ); BOOLEAN +NTAPI InitializeDeviceData( - IN PDEVICE_OBJECT DeviceObject + IN PDEVICE_OBJECT DeviceObject ); BOOLEAN +NTAPI InitializeGlobalData( - IN PUNICODE_STRING RegistryPath, - IN PDRIVER_OBJECT DriverObject + IN PUNICODE_STRING RegistryPath, + IN PDRIVER_OBJECT DriverObject ); -extern ULONG SACDebug; +BOOLEAN +NTAPI +InitializeMemoryManagement( + VOID +); +VOID +NTAPI +FreeMemoryManagement( + VOID +); + +VOID +NTAPI +InitializeCmdEventInfo( + VOID +); + +VOID +NTAPI +InitializeMachineInformation( + VOID +); + +NTSTATUS +NTAPI +PreloadGlobalMessageTable( + IN PVOID ImageBase +); + +NTSTATUS +NTAPI +TearDownGlobalMessageTable( + VOID +); + +NTSTATUS +NTAPI +GetCommandConsoleLaunchingPermission( + OUT PBOOLEAN Permission +); + +NTSTATUS +NTAPI +ImposeSacCmdServiceStartTypePolicy( + VOID +); + +NTSTATUS +NTAPI +RegisterBlueScreenMachineInformation( + VOID +); + +VOID +NTAPI +FreeMachineInformation( + VOID +); + +// +// DPC, Timer, Thread Callbacks +// +VOID +NTAPI +TimerDpcRoutine( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 +); + +// +// Custom SAC Heap Allocator Routines +// +PVOID +NTAPI +MyAllocatePool( + IN SIZE_T PoolSize, + IN ULONG Tag, + IN PCHAR File, + IN ULONG Line +); + +VOID +NTAPI +MyFreePool( + IN PVOID *Block +); + +// +// Connection Manager Routines +// +NTSTATUS +NTAPI +ConMgrInitialize( + VOID +); + +VOID +NTAPI +ConMgrWorkerProcessEvents( + IN PSAC_DEVICE_EXTENSION DeviceExtension +); + +NTSTATUS +NTAPI +ConMgrShutdown( + VOID +); + +BOOLEAN +NTAPI +ConMgrSimpleEventMessage( + IN ULONG MessageIndex, + IN BOOLEAN LockHeld +); + +BOOLEAN +NTAPI +SacPutSimpleMessage( + IN ULONG MessageIndex +); + +VOID +NTAPI +SacPutString( + IN PWCHAR String +); + +NTSTATUS +NTAPI +ConMgrWriteData( + IN PSAC_CHANNEL Channel, + IN PVOID Buffer, + IN ULONG BufferLength +); + +NTSTATUS +NTAPI +ConMgrFlushData( + IN PSAC_CHANNEL Channel +); + +BOOLEAN +NTAPI +ConMgrIsWriteEnabled( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ConMgrHandleEvent( + IN ULONG EventCode, + IN PSAC_CHANNEL Channel, + OUT PVOID Data +); + +// +// Channel Manager Routines +// +NTSTATUS +NTAPI +ChanMgrInitialize( + VOID +); + +NTSTATUS +NTAPI +ChanMgrShutdown( + VOID +); + +NTSTATUS +NTAPI +ChanMgrCreateChannel( + OUT PSAC_CHANNEL *Channel, + IN PSAC_CHANNEL_ATTRIBUTES Attributes +); + +NTSTATUS +NTAPI +ChanMgrGetByHandle( + IN SAC_CHANNEL_ID ChannelId, + OUT PSAC_CHANNEL* TargetChannel +); + +NTSTATUS +NTAPI +ChanMgrReleaseChannel( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ChanMgrGetNextActiveChannel( + IN PSAC_CHANNEL CurrentChannel, + IN PULONG TargetIndex, + OUT PSAC_CHANNEL *TargetChannel +); + +NTSTATUS +NTAPI +ChanMgrCloseChannel( + IN PSAC_CHANNEL Channel +); + +// +// Channel Routines +// +NTSTATUS +NTAPI +ChannelClose( + IN PSAC_CHANNEL Channel +); + +BOOLEAN +NTAPI +ChannelIsEqual( + IN PSAC_CHANNEL Channel, + IN PSAC_CHANNEL_ID ChannelId +); + +NTSTATUS +NTAPI +ChannelOWrite( + IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize +); + +NTSTATUS +NTAPI +ChannelOFlush( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ChannelSetRedrawEvent( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ChannelClearRedrawEvent( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ChannelHasRedrawEvent( + IN PSAC_CHANNEL Channel, + OUT PBOOLEAN Present +); + +BOOLEAN +NTAPI +ChannelIsActive( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ChannelGetName( + IN PSAC_CHANNEL Channel, + OUT PWCHAR *Name +); + +BOOLEAN +NTAPI +ChannelIsEqual( + IN PSAC_CHANNEL Channel, + IN PSAC_CHANNEL_ID ChannelId +); + +NTSTATUS +NTAPI +ChannelCreate( + IN PSAC_CHANNEL Channel, + IN PSAC_CHANNEL_ATTRIBUTES Attributes, + IN SAC_CHANNEL_ID ChannelId +); + +NTSTATUS +NTAPI +ChannelDestroy( + IN PSAC_CHANNEL Channel +); + +// +// RAW Channel Table +// +NTSTATUS +NTAPI +RawChannelCreate( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +RawChannelDestroy( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +RawChannelORead( + IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + OUT PULONG ByteCount +); + +NTSTATUS +NTAPI +RawChannelOEcho( + IN PSAC_CHANNEL Channel, + IN PCHAR String, + IN ULONG Length +); + +NTSTATUS +NTAPI +RawChannelOFlush( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +RawChannelOWrite( + IN PSAC_CHANNEL Channel, + IN PCHAR String, + IN ULONG Length +); + +NTSTATUS +NTAPI +RawChannelIRead( + IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + IN PULONG ReturnBufferSize +); + +NTSTATUS +NTAPI +RawChannelIBufferIsFull( + IN PSAC_CHANNEL Channel, + OUT PBOOLEAN BufferStatus +); + +ULONG +NTAPI +RawChannelIBufferLength( + IN PSAC_CHANNEL Channel +); + +CHAR +NTAPI +RawChannelIReadLast( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +RawChannelIWrite( + IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize +); + +// +// Helper Routines +// +NTSTATUS +NTAPI +SerialBufferGetChar( + OUT PCHAR Char +); + +NTSTATUS +NTAPI +UTF8EncodeAndSend( + IN PWCHAR String +); + +NTSTATUS +NTAPI +TranslateMachineInformationXML( + IN PWCHAR *Buffer, + IN PWCHAR ExtraData +); + +PWCHAR +NTAPI +GetMessage( + IN ULONG MessageIndex +); + +BOOLEAN +NTAPI +VerifyEventWaitable( + IN HANDLE Handle, + OUT PVOID *WaitObject, + OUT PVOID *ActualWaitObject +); + +// +// SAC Command Functions +// +VOID +NTAPI +DoRebootCommand( + IN BOOLEAN Reboot +); + +// +// External data +// +extern ULONG SACDebug; +extern PSAC_MESSAGE_ENTRY GlobalMessageTable; +extern KMUTEX CurrentChannelLock; +extern LONG CurrentChannelRefCount; +extern PCHAR SerialPortBuffer; +extern PCHAR Utf8ConversionBuffer; +extern ULONG Utf8ConversionBufferSize; + +// +// Function to initailize a SAC Semaphore Lock +// +FORCEINLINE +VOID +SacInitializeLock(IN PSAC_CHANNEL_LOCK Lock) +{ + KeInitializeSemaphore(&Lock->Lock, 1, 1); +} + +// +// Function to acquire a SAC Semaphore Lock +// +FORCEINLINE +VOID +SacAcquireLock(IN PSAC_CHANNEL_LOCK Lock) +{ + KeWaitForSingleObject(&Lock->Lock, Executive, KernelMode, FALSE, NULL); + ASSERT(Lock->RefCount == 0); + _InterlockedIncrement(&Lock->RefCount); +} + +// +// Function to release a SAC Semaphore Lock +// +FORCEINLINE +VOID +SacReleaseLock(IN PSAC_CHANNEL_LOCK Lock) +{ + ASSERT(Lock->RefCount == 1); + _InterlockedDecrement(&Lock->RefCount); + KeReleaseSemaphore(&Lock->Lock, SEMAPHORE_INCREMENT, 1, FALSE); +} + +// +// Function to check if the SAC Mutex Lock is held +// +FORCEINLINE +VOID +SacAssertMutexLockHeld(VOID) +{ + ASSERT(CurrentChannelRefCount == 1); + ASSERT(KeReadStateMutex(&CurrentChannelLock) == 0); +} + +// +// Function to check if the SAC Mutex Lock is held +// +FORCEINLINE +VOID +SacInitializeMutexLock(VOID) +{ + KeInitializeMutex(&CurrentChannelLock, 0); + CurrentChannelRefCount = 0; +} + +// +// Function to acquire the SAC Mutex Lock +// +FORCEINLINE +VOID +SacAcquireMutexLock(VOID) +{ + KeWaitForSingleObject(&CurrentChannelLock, Executive, KernelMode, FALSE, NULL); + ASSERT(CurrentChannelRefCount == 0); + _InterlockedIncrement(&CurrentChannelRefCount); +} + +// +// Function to release the SAC Mutex Lock +// +FORCEINLINE +VOID +SacReleaseMutexLock(VOID) +{ + ASSERT(CurrentChannelRefCount == 1); + _InterlockedDecrement(&CurrentChannelRefCount); + KeReleaseMutex(&CurrentChannelLock, FALSE); +} + +// +// Locking Macros +// +#define ChannelLockCreates() SacAcquireLock(&ChannelCreateLock); +#define ChannelUnlockCreates() SacReleaseLock(&ChannelCreateLock); +#define ChannelLockOBuffer(x) SacAcquireLock(&x->ChannelOBufferLock); +#define ChannelUnlockOBuffer(x) SacReleaseLock(&x->ChannelOBufferLock); +#define ChannelLockIBuffer(x) SacAcquireLock(&x->ChannelIBufferLock); +#define ChannelUnlockIBuffer(x) SacReleaseLock(&x->ChannelIBufferLock); +#define ChannelLockAttributes(x) SacAcquireLock(&x->ChannelAttributeLock); +#define ChannelUnlockAttributes(x) SacReleaseLock(&x->ChannelAttributeLock); +#define ChannelSlotLock(x) SacAcquireLock(&ChannelSlotLock[x]); +#define ChannelSlotUnlock(x) SacReleaseLock(&ChannelSlotLock[x]); + +// +// Channel Accessors +// +FORCEINLINE +ULONG +ChannelGetFlags(IN PSAC_CHANNEL Channel) +{ + return Channel->Flags; +} + +FORCEINLINE +LONG +ChannelGetIndex(IN PSAC_CHANNEL Channel) +{ + /* Return the index of the channel */ + return Channel->Index; +} diff --git a/reactos/drivers/sac/driver/sacdrv.rc b/reactos/drivers/sac/driver/sacdrv.rc index ceb819a9005..1c1e27d36ec 100644 --- a/reactos/drivers/sac/driver/sacdrv.rc +++ b/reactos/drivers/sac/driver/sacdrv.rc @@ -1,5 +1,5 @@ /* - * PROJECT: ReactOS Boot Loader + * PROJECT: ReactOS Drivers * LICENSE: BSD - See COPYING.ARM in the top level directory * FILE: drivers/base/sac/driver/sacdrv.rc * PURPOSE: Resource File for EMS SAC Driver diff --git a/reactos/drivers/sac/driver/util.c b/reactos/drivers/sac/driver/util.c index b40f058c592..f536915e23f 100644 --- a/reactos/drivers/sac/driver/util.c +++ b/reactos/drivers/sac/driver/util.c @@ -1,18 +1,759 @@ /* - * PROJECT: ReactOS Boot Loader - * LICENSE: BSD - See COPYING.ARM in the top level directory - * FILE: drivers/sac/driver/util.c - * PURPOSE: Driver for the Server Administration Console (SAC) for EMS - * PROGRAMMERS: ReactOS Portable Systems Group + * PROJECT: ReactOS Drivers + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: drivers/sac/driver/util.c + * PURPOSE: Driver for the Server Administration Console (SAC) for EMS + * PROGRAMMERS: ReactOS Portable Systems Group */ -/* INCLUDES *******************************************************************/ +/* INCLUDES ******************************************************************/ #include "sacdrv.h" -/* GLOBALS ********************************************************************/ +/* GLOBALS *******************************************************************/ -/* FUNCTIONS ******************************************************************/ +PCHAR Utf8ConversionBuffer; +ULONG Utf8ConversionBufferSize; +PSAC_MACHINE_INFO MachineInformation; +PVOID RequestSacCmdEventObjectBody; +PKEVENT RequestSacCmdEventWaitObjectBody; +PVOID RequestSacCmdSuccessEventObjectBody; +PKEVENT RequestSacCmdSuccessEventWaitObjectBody; +PVOID RequestSacCmdFailureEventObjectBody; +PKEVENT RequestSacCmdFailureEventWaitObjectBody; +PFILE_OBJECT ServiceProcessFileObject; +BOOLEAN HaveUserModeServiceCmdEventInfo; + +PSAC_MESSAGE_ENTRY GlobalMessageTable; +ULONG GlobalMessageTableCount; + +LONG SerialPortConsumerIndex, SerialPortProducerIndex; +PCHAR SerialPortBuffer; + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +SacTranslateUnicodeToUtf8(IN PWCHAR SourceBuffer, + IN ULONG SourceBufferLength, + OUT PCHAR DestinationBuffer, + IN ULONG DestinationBufferSize, + OUT PULONG UTF8Count, + OUT PULONG ProcessedCount) +{ + ASSERT(FALSE); + return FALSE; +} + +PWCHAR +NTAPI +GetMessage(IN ULONG MessageIndex) +{ + PSAC_MESSAGE_ENTRY MessageEntry; + ULONG i; + PWCHAR MessageData = NULL; + + /* Loop all cached messages */ + for (i = 0; i < GlobalMessageTableCount; i++) + { + /* Check if this one matches the index */ + MessageEntry = &GlobalMessageTable[i]; + if (MessageEntry->Index == MessageIndex) + { + /* It does, return the buffer */ + MessageData = MessageEntry->Buffer; + break; + } + } + + /* We should always find it */ + if (!MessageData) ASSERT(FALSE); + return MessageData; +} + +NTSTATUS +NTAPI +UTF8EncodeAndSend(IN PWCHAR String) +{ + ULONG ProcessedCount, Utf8Count, i; + NTSTATUS Status = STATUS_SUCCESS; + + /* Call the translator routine */ + if (SacTranslateUnicodeToUtf8(String, + wcslen(String), + Utf8ConversionBuffer, + Utf8ConversionBufferSize, + &Utf8Count, + &ProcessedCount)) + { + /* Loop every character */ + for (i = 0; i < Utf8Count; i++) + { + /* Send it to the terminal */ + Status = HeadlessDispatch(HeadlessCmdPutData, + &Utf8ConversionBuffer[i], + sizeof(Utf8ConversionBuffer[i]), + NULL, + NULL); + if (!NT_SUCCESS(Status)) break; + } + } + else + { + /* Conversion failed */ + Status = STATUS_UNSUCCESSFUL; + } + + /* All done */ + return Status; +} + +VOID +NTAPI +SacFormatMessage(IN PWCHAR FormattedString, + IN PWCHAR MessageString, + IN ULONG MessageSize) +{ + /* FIXME: For now don't format anything */ + wcsncpy(FormattedString, MessageString, MessageSize / sizeof(WCHAR)); +} + +NTSTATUS +NTAPI +PreloadGlobalMessageTable(IN PVOID ImageBase) +{ + NTSTATUS Status; + ULONG MessageId, TotalLength, TextSize, i; + PWCHAR StringBuffer; + PMESSAGE_RESOURCE_ENTRY MessageEntry; + PAGED_CODE(); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC PreloadGlobalMessageTable: Entering.\n"); + + /* Nothing to do if we already have a table */ + if (GlobalMessageTable) goto Exit; + + /* Loop through up to 200 messages */ + for (MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++) + { + /* Find this message ID in the string table*/ + Status = RtlFindMessage(ImageBase, + 11, + LANG_NEUTRAL, + MessageId, + &MessageEntry); + if (NT_SUCCESS(Status)) + { + /* Make sure it's Unicode */ + ASSERT(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE); + + /* Remove the space taken up by the OS header, and add our own */ + TotalLength += MessageEntry->Length - + FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) + + sizeof(SAC_MESSAGE_ENTRY); + + /* One more in the table */ + GlobalMessageTableCount++; + } + } + + /* We should've found at least one message... */ + if (!TotalLength) + { + /* Bail out otherwise */ + SAC_DBG(SAC_DBG_INIT, "SAC PreloadGlobalMessageTable: No Messages.\n"); + Status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + /* Allocate space for the buffers and headers */ + GlobalMessageTable = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG); + if (!GlobalMessageTable) + { + /* Bail out if we couldn't allocate it */ + Status = STATUS_NO_MEMORY; + goto Exit; + } + + /* All the buffers are going to be at the end of the table */ + StringBuffer = (PWCHAR)(&GlobalMessageTable[GlobalMessageTableCount]); + + /* Now loop over our entries again */ + for (i = 0, MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++) + { + /* Make sure the message is still there...! */ + Status = RtlFindMessage(ImageBase, + 11, + LANG_NEUTRAL, + MessageId, + &MessageEntry); + if (NT_SUCCESS(Status)) + { + /* Write the entry in the message table*/ + GlobalMessageTable[i].Index = MessageId; + GlobalMessageTable[i].Buffer = StringBuffer; + + /* The structure includes the size of the header, elide it */ + TextSize = MessageEntry->Length - + FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text); + + /* Format the message into the entry. It should be same or smaller */ + SacFormatMessage(StringBuffer, (PWCHAR)MessageEntry->Text, TextSize); + ASSERT((ULONG)(wcslen(StringBuffer)*sizeof(WCHAR)) <= TextSize); + + /* Move to the next buffer space */ + StringBuffer += TextSize; + + /* Move to the next entry, make sure the status is full success */ + i++; + Status = STATUS_SUCCESS; + } + } + +Exit: + /* All done, return the status code */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting with status 0x%0x\n", Status); + return Status; +} + +NTSTATUS +NTAPI +TearDownGlobalMessageTable(VOID) +{ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Entering.\n"); + + /* Free the table if one existed */ + if (GlobalMessageTable) SacFreePool(GlobalMessageTable); + + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting\n"); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +TranslateMachineInformationXML(IN PWCHAR *Buffer, + IN PWCHAR ExtraData) +{ + NTSTATUS Status; + ULONG Size; + PWCHAR p; + CHECK_PARAMETER1(Buffer); + + Status = STATUS_SUCCESS; + Size = wcslen(L"\r\n"); + + if (MachineInformation->MachineName) + { + Size += wcslen(MachineInformation->MachineName); + Size += wcslen(L"%s\r\n"); + } + + if (MachineInformation->MachineGuid) + { + Size += wcslen(MachineInformation->MachineGuid); + Size += wcslen(L"%s\r\n"); + } + + if (MachineInformation->ProcessorArchitecture) + { + Size += wcslen(MachineInformation->ProcessorArchitecture); + Size += wcslen(L"%s\r\n"); + } + + if (MachineInformation->MajorVersion) + { + Size += wcslen(MachineInformation->MajorVersion); + Size += wcslen(L"%s\r\n"); + } + + if (MachineInformation->BuildNumber) + { + Size += wcslen(MachineInformation->BuildNumber); + Size += wcslen(L"%s\r\n"); + } + + if (MachineInformation->ProductType) + { + Size += wcslen(MachineInformation->ProductType); + Size += wcslen(L"%s\r\n"); + } + + if (MachineInformation->ServicePack) + { + Size += wcslen(MachineInformation->ServicePack); + Size += wcslen(L"%s\r\n"); + } + + if (ExtraData) Size += wcslen(ExtraData); + + Size += wcslen(L"\r\n"); + + p = (PWCHAR)SacAllocatePool((Size + sizeof(ANSI_NULL)) * sizeof(WCHAR), GLOBAL_BLOCK_TAG); + + *Buffer = p; + if (!p) return STATUS_NO_MEMORY; + + Size = wcslen(L"\r\n"); + wcscpy(p, L"\r\n"); + + p += Size; + + if (MachineInformation->MachineName) + { + p += swprintf(p, L"%s\r\n", MachineInformation->MachineName); + } + + if (MachineInformation->MachineGuid) + { + p += swprintf(p, L"%s\r\n", MachineInformation->MachineGuid); + } + + if (MachineInformation->ProcessorArchitecture) + { + p += swprintf(p, L"%s\r\n", MachineInformation->ProcessorArchitecture); + } + + if (MachineInformation->MajorVersion) + { + p += swprintf(p, L"%s\r\n", MachineInformation->MajorVersion); + } + + if (MachineInformation->BuildNumber) + { + p += swprintf(p, L"%s\r\n", MachineInformation->BuildNumber); + } + + if (MachineInformation->ProductType) + { + p += swprintf(p, L"%s\r\n", MachineInformation->ProductType); + } + + if (MachineInformation->ServicePack) + { + p += swprintf(p, L"%s\r\n", MachineInformation->ServicePack); + } + + if (ExtraData) + { + Size = wcslen(ExtraData); + wcscpy(p, ExtraData); + p += Size; + } + + wcscpy(p, L"\r\n"); + ASSERT((((ULONG) wcslen(*Buffer) + 1) * sizeof(WCHAR)) <= Size); + return Status; +} + +VOID +NTAPI +InitializeMachineInformation(VOID) +{ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Entering.\n"); + + /* FIXME: TODO */ + MachineInformation = NULL; + ASSERT(FALSE); + + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Exiting with error.\n"); +} + +NTSTATUS +NTAPI +GetRegistryValueBuffer(IN PCWSTR KeyName, + IN PWCHAR ValueName, + IN PKEY_VALUE_PARTIAL_INFORMATION* Buffer) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DestinationString; + HANDLE Handle; + SIZE_T ResultLength = 0; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: Entering.\n"); + CHECK_PARAMETER1(KeyName); + CHECK_PARAMETER2(ValueName); + + /* Open the specified key */ + RtlInitUnicodeString(&DestinationString, KeyName); + InitializeObjectAttributes(&ObjectAttributes, + &DestinationString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenKey(&Handle, + KEY_WRITE | SYNCHRONIZE | KEY_READ, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* Bail out on failure */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwOpenKey: %X.\n", Status); + return Status; + } + + /* Query the size of the key */ + RtlInitUnicodeString(&DestinationString, ValueName); + Status = ZwQueryValueKey(Handle, + &DestinationString, + KeyValuePartialInformation, + NULL, + 0, + &ResultLength); + if (!ResultLength) return Status; + + /* Allocate the buffer for the partial info structure and our integer data */ + ResultLength += sizeof(ULONG); + *Buffer = SacAllocatePool(ResultLength, GLOBAL_BLOCK_TAG); + if (!*Buffer) + { + SAC_DBG(1, "SAC GetRegistryValueBuffer: failed allocation\n"); + return Status; + } + + /* Now read the data */ + Status = ZwQueryValueKey(Handle, + &DestinationString, + KeyValuePartialInformation, + *Buffer, + ResultLength, + &ResultLength); + if (!NT_SUCCESS(Status)) + { + /* Free the buffer if we couldn't read the data */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwQueryValueKey: %X.\n", Status); + SacFreePool(*Buffer); + } + + /* Return the result */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n"); + return Status; +} + +NTSTATUS +NTAPI +SetRegistryValue(IN PCWSTR KeyName, + IN PWCHAR ValueName, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DestinationString; + HANDLE Handle; + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Entering.\n"); + CHECK_PARAMETER1(KeyName); + CHECK_PARAMETER2(ValueName); + CHECK_PARAMETER4(Data); + + /* Open the specified key */ + RtlInitUnicodeString(&DestinationString, KeyName); + InitializeObjectAttributes(&ObjectAttributes, + &DestinationString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenKey(&Handle, + KEY_WRITE | SYNCHRONIZE | KEY_READ, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* Bail out on failure */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status); + return Status; + } + + /* Set the specified value */ + RtlInitUnicodeString(&DestinationString, ValueName); + Status = ZwSetValueKey(Handle, &DestinationString, 0, Type, Data, DataSize); + if (!NT_SUCCESS(Status)) + { + /* Print error on failure */ + SAC_DBG(1, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status); + } + + /* Close the handle and exit */ + NtClose(Handle); + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n"); + return Status; +} + +NTSTATUS +NTAPI +CopyRegistryValueData(IN PULONG* Buffer, + IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + CHECK_PARAMETER1(Buffer); + CHECK_PARAMETER2(PartialInfo); + + /* Allocate space for registry data */ + *Buffer = SacAllocatePool(PartialInfo->DataLength, GLOBAL_BLOCK_TAG); + if (*Buffer) + { + /* Copy the data into the buffer */ + RtlCopyMemory(*Buffer, PartialInfo->Data, PartialInfo->DataLength); + } + else + { + /* Set the correct error code */ + SAC_DBG(SAC_DBG_UTIL, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n"); + Status = STATUS_NO_MEMORY; + } + + /* Return the result */ + return Status; +} + +NTSTATUS +NTAPI +GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission) +{ + NTSTATUS Status; + PKEY_VALUE_PARTIAL_INFORMATION Dummy; + + /* Assume success and read the key */ + *Permission = TRUE; + Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv", + L"DisableCmdSessions", + &Dummy); + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + { + /* The default is success */ + Status = STATUS_SUCCESS; + } + else + { + /* Only if the key is present and set, do we disable permission */ + if (NT_SUCCESS(Status)) *Permission = FALSE; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +ImposeSacCmdServiceStartTypePolicy(VOID) +{ + NTSTATUS Status; + PKEY_VALUE_PARTIAL_INFORMATION Buffer = NULL; + PULONG Data; + + /* Read the service start type*/ + Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr", + L"Start", + &Buffer); + if (!NT_SUCCESS(Status)) return Status; + + /* If there's no start type, fail, as this is unusual */ + if (!Buffer) return STATUS_UNSUCCESSFUL; + + /* Read the value */ + Status = CopyRegistryValueData(&Data, Buffer); + SacFreePool(Buffer); + if (!NT_SUCCESS(Status)) return Status; + + /* Check what the current start type is */ + switch (*Data) + { + /* It's boot, system, or disabled */ + case 1: + case 2: + case 4: + /* Leave it as is */ + return Status; + + case 3: + + /* It's set to automatic, set it to system instead */ + *Data = 2; + Status = SetRegistryValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr", + L"Start", + REG_DWORD, + Data, + sizeof(ULONG)); + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status); + } + break; + + default: + ASSERT(FALSE); + } + + return Status; +} + +VOID +NTAPI +InitializeCmdEventInfo(VOID) +{ + /* Check if we were already initailized */ + if (HaveUserModeServiceCmdEventInfo) + { + /* Full state expected */ + ASSERT(RequestSacCmdEventObjectBody); + ASSERT(RequestSacCmdSuccessEventObjectBody); + ASSERT(RequestSacCmdFailureEventObjectBody); + + /* Dereference each wait object in turn */ + if (RequestSacCmdEventObjectBody) + { + ObDereferenceObject(RequestSacCmdEventObjectBody); + } + + if (RequestSacCmdSuccessEventObjectBody) + { + ObDereferenceObject(RequestSacCmdSuccessEventObjectBody); + } + + if (RequestSacCmdFailureEventObjectBody) + { + ObDereferenceObject(RequestSacCmdFailureEventObjectBody); + } + } + + /* Claer everything */ + RequestSacCmdEventObjectBody = NULL; + RequestSacCmdEventWaitObjectBody = NULL; + RequestSacCmdSuccessEventObjectBody = NULL; + RequestSacCmdSuccessEventWaitObjectBody = NULL; + RequestSacCmdFailureEventObjectBody = NULL; + RequestSacCmdFailureEventWaitObjectBody = NULL; + ServiceProcessFileObject = NULL; + + /* Reset state */ + HaveUserModeServiceCmdEventInfo = FALSE; +} + +NTSTATUS +NTAPI +RegisterBlueScreenMachineInformation(VOID) +{ + PWCHAR XmlBuffer; + PHEADLESS_BLUE_SCREEN_DATA BsBuffer; + ULONG Length, HeaderLength, TotalLength; + NTSTATUS Status; + ULONG i; + + /* Create the XML buffer and make sure it's OK */ + Status = TranslateMachineInformationXML(&XmlBuffer, NULL); + CHECK_PARAMETER_WITH_STATUS(NT_SUCCESS(Status), Status); + CHECK_PARAMETER_WITH_STATUS(XmlBuffer, STATUS_UNSUCCESSFUL); + + /* Compute the sizes and allocate a buffer for it */ + Length = wcslen(XmlBuffer); + HeaderLength = strlen("MACHINEINFO"); + TotalLength = HeaderLength + + Length + + sizeof(*BsBuffer) + + 2 * sizeof(ANSI_NULL); + BsBuffer = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG); + CHECK_PARAMETER_WITH_STATUS(BsBuffer, STATUS_NO_MEMORY); + + /* Copy the XML property name */ + strcpy((PCHAR)BsBuffer->XMLData, "MACHINEINFO"); + BsBuffer->Property = (PUCHAR)HeaderLength + sizeof(ANSI_NULL); + + /* Copy the data and NULL-terminate it */ + for (i = 0; i < Length; i++) + { + BsBuffer->XMLData[HeaderLength + sizeof(ANSI_NULL) + i] = XmlBuffer[i]; + } + BsBuffer->XMLData[HeaderLength + sizeof(ANSI_NULL) + i] = ANSI_NULL; + + /* Let the OS save the buffer for later */ + Status = HeadlessDispatch(HeadlessCmdSetBlueScreenData, + BsBuffer, + TotalLength, + NULL, + NULL); + + /* Failure or not, we don't need this anymore */ + SacFreePool(BsBuffer); + SacFreePool(XmlBuffer); + + /* Return the result */ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information: Exiting.\n"); + return Status; +} + +VOID +NTAPI +FreeMachineInformation(VOID) +{ + ASSERT(MachineInformation); + + /* Free every cached string of machine information */ + if (MachineInformation->MachineName) SacFreePool(MachineInformation); + if (MachineInformation->MachineGuid) SacFreePool(MachineInformation->MachineGuid); + if (MachineInformation->ProcessorArchitecture) SacFreePool(MachineInformation->ProcessorArchitecture); + if (MachineInformation->MajorVersion) SacFreePool(MachineInformation->MajorVersion); + if (MachineInformation->BuildNumber) SacFreePool(MachineInformation->BuildNumber); + if (MachineInformation->ProductType) SacFreePool(MachineInformation->ProductType); + if (MachineInformation->ServicePack) SacFreePool(MachineInformation->ServicePack); +} + +BOOLEAN +NTAPI +VerifyEventWaitable(IN HANDLE Handle, + OUT PVOID *WaitObject, + OUT PVOID *ActualWaitObject) +{ + PVOID Object; + NTSTATUS Status; + POBJECT_TYPE ObjectType; + + /* Reference the object */ + Status = ObReferenceObjectByHandle(Handle, + EVENT_ALL_ACCESS, + NULL, + KernelMode, + &Object, + NULL); + *WaitObject = Object; + if (!NT_SUCCESS(Status)) + { + SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status); + return FALSE; + } + + /* Check if the object itself is NOT being used */ + ObjectType = OBJECT_TO_OBJECT_HEADER(Object)->Type; + if (ObjectType->TypeInfo.UseDefaultObject == FALSE) + { + /* Get the actual object that's being used for the wait */ + *ActualWaitObject = (PVOID)((ULONG_PTR)Object + + (ULONG_PTR)ObjectType->DefaultObject); + return TRUE; + } + + /* Drop the reference we took */ + SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: event object not waitable!\n"); + ObDereferenceObject(*WaitObject); + return FALSE; +} + +NTSTATUS +NTAPI +SerialBufferGetChar(OUT PCHAR Char) +{ + /* Check if nothing's been produced yet */ + if (SerialPortConsumerIndex == SerialPortProducerIndex) + { + return STATUS_NO_DATA_DETECTED; + } + + /* Consume the produced character and clear it*/ + *Char = SerialPortBuffer[SerialPortConsumerIndex]; + SerialPortBuffer[SerialPortConsumerIndex] = ANSI_NULL; + + /* Advance the index and return success */ + _InterlockedExchange(&SerialPortConsumerIndex, + (SerialPortConsumerIndex + 1) & + (SAC_SERIAL_PORT_BUFFER_SIZE - 1)); + return STATUS_SUCCESS; +} ULONG ConvertAnsiToUnicode( @@ -32,24 +773,6 @@ IsCmdEventRegistrationProcess( return FALSE; } -VOID -InitializeCmdEventInfo( - VOID - ) -{ - -} - -BOOLEAN -VerifyEventWaitable( - IN PVOID Object, - OUT PVOID *WaitObject, - OUT PVOID *ActualWaitObject - ) -{ - return FALSE; -} - NTSTATUS InvokeUserModeService( VOID @@ -58,32 +781,6 @@ InvokeUserModeService( return STATUS_NOT_IMPLEMENTED; } -VOID -SacFormatMessage( - IN PWCHAR FormattedString, - IN PWCHAR MessageString, - IN ULONG MessageSize - ) -{ - -} - -NTSTATUS -TearDownGlobalMessageTable( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -PWCHAR -GetMessage( - IN ULONG MessageIndex - ) -{ - return NULL; -} - BOOLEAN SacTranslateUtf8ToUnicode( IN CHAR Utf8Char, @@ -94,50 +791,6 @@ SacTranslateUtf8ToUnicode( return FALSE; } -BOOLEAN -SacTranslateUnicodeToUtf8( - IN PWCHAR SourceBuffer, - IN ULONG SourceBufferLength, - OUT PCHAR DestinationBuffer, - IN ULONG DestinationBufferSize, - IN ULONG UTF8Count, - OUT PULONG ProcessedCount - ) -{ - return FALSE; -} - -NTSTATUS -GetRegistryValueBuffer( - IN PCWSTR KeyName, - IN PWCHAR ValueName, - IN PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -SetRegistryValue( - IN PCWSTR KeyName, - IN PWCHAR ValueName, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -CopyRegistryValueData( - IN PVOID Dest, - IN PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - NTSTATUS TranslateMachineInformationText( IN PWCHAR Buffer) @@ -145,55 +798,6 @@ TranslateMachineInformationText( return STATUS_NOT_IMPLEMENTED; } -NTSTATUS -TranslateMachineInformationXML( - IN PWCHAR Buffer, - IN PWCHAR ExtraData - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -RegisterBlueScreenMachineInformation( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -VOID -FreeMachineInformation( - VOID - ) -{ - -} - -NTSTATUS -SerialBufferGetChar( - OUT PCHAR Char - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -GetCommandConsoleLaunchingPermission( - OUT PBOOLEAN Permission - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -ImposeSacCmdServiceStartTypePolicy( - VOID - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - NTSTATUS CopyAndInsertStringAtInterval( IN PWCHAR SourceStr, @@ -229,11 +833,3 @@ UnregisterSacCmdEvent( { return STATUS_NOT_IMPLEMENTED; } - -NTSTATUS -UTF8EncodeAndSend( - IN PWCHAR String - ) -{ - return STATUS_NOT_IMPLEMENTED; -} diff --git a/reactos/include/reactos/mc/CMakeLists.txt b/reactos/include/reactos/mc/CMakeLists.txt index 1e62d5fe576..8037a7c2575 100644 --- a/reactos/include/reactos/mc/CMakeLists.txt +++ b/reactos/include/reactos/mc/CMakeLists.txt @@ -7,7 +7,8 @@ list(APPEND UNICODE_SOURCE neteventmsg.mc ntiologc.mc ntstatus.mc - pciclass.mc) + pciclass.mc + sacmsg.mc) add_message_headers(ANSI ${ANSI_SOURCE}) # FIXME: this needs testing before switching to unicode diff --git a/reactos/include/reactos/mc/sacmsg.mc b/reactos/include/reactos/mc/sacmsg.mc index dce4a07f41f..4d3052c3d42 100644 --- a/reactos/include/reactos/mc/sacmsg.mc +++ b/reactos/include/reactos/mc/sacmsg.mc @@ -1,17 +1,17 @@ MessageId=1 -SymbolicName=SACDRV_1 +SymbolicName=SAC_INIT_STATUS Language=English Computer is booting, SAC started and initialized.\n\nUse the \"ch -?\" command for information about using channels.\nUse the \"?\" command for general help. . MessageId=2 -SymbolicName=SACDRV_2 +SymbolicName=SAC_NEWLINE Language=English . MessageId=3 -SymbolicName=SACDRV_3 +SymbolicName=SAC_PROMPT Language=English SAC>%0 . @@ -59,9 +59,9 @@ Paging is now OFF. . MessageId=11 -SymbolicName=SACDRV_11 +SymbolicName=SAC_OUT_OF_MEMORY_PROMPT Language=English -Paging is now OFF. +THIS LOOKS LIKE A BUG??? . MessageId=12 @@ -173,7 +173,7 @@ lock Lock access to Command Prompt channels. . MessageId=48 -SymbolicName=SACDRV_48 +SymbolicName=SAC_FAIL_PROMPT Language=English Failed with status 0x%%X. . @@ -269,13 +269,13 @@ SAC cannot raise the process priority any higher. . MessageId=65 -SymbolicName=SACDRV_65 +SymbolicName=SAC_SHUTDOWN_FAIL_PROMPT Language=English SAC failed to shutdown the system. . MessageId=66 -SymbolicName=SACDRV_66 +SymbolicName=SAC_RESTART_FAIL_PROMPT Language=English SAC failed to restart the system. . @@ -551,19 +551,19 @@ ch Channel management commands. Use ch -? for more help. . MessageId=113 -SymbolicName=SACDRV_113 +SymbolicName=SAC_RESTART_TIME_PROMPT Language=English Time since last reboot: %%d:%%02d:%%02d . MessageId=114 -SymbolicName=SACDRV_114 +SymbolicName=SAC_RESTART_PROMPT Language=English SAC preparing to restart the system. . MessageId=115 -SymbolicName=SACDRV_115 +SymbolicName=SAC_SHUTDOWN_PROMPT Language=English SAC preparing to shutdown the system. . @@ -641,13 +641,13 @@ Error: There is no channel present at the specified index. . MessageId=144 -SymbolicName=SACDRV_144 +SymbolicName=SAC_CHANNEL_NAME Language=English SAC%0 . MessageId=145 -SymbolicName=SACDRV_145 +SymbolicName=SAC_CHANNEL_DESCRIPTION Language=English Special Administration Console%0 .