diff --git a/base/setup/usetup/console.c b/base/setup/usetup/console.c index ec73f382216..6e647d8bfde 100644 --- a/base/setup/usetup/console.c +++ b/base/setup/usetup/console.c @@ -47,11 +47,12 @@ BOOL WINAPI AllocConsole(VOID) { + NTSTATUS Status; UNICODE_STRING ScreenName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen"); UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0"); OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; + ULONG Enable; /* Open the screen */ InitializeObjectAttributes(&ObjectAttributes, @@ -68,6 +69,24 @@ AllocConsole(VOID) if (!NT_SUCCESS(Status)) return FALSE; + /* Enable it */ + Enable = TRUE; + Status = NtDeviceIoControlFile(StdOutput, + NULL, + NULL, + NULL, + &IoStatusBlock, + IOCTL_CONSOLE_RESET_SCREEN, + &Enable, + sizeof(Enable), + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + NtClose(StdOutput); + return FALSE; + } + /* Open the keyboard */ InitializeObjectAttributes(&ObjectAttributes, &KeyboardName, @@ -81,7 +100,10 @@ AllocConsole(VOID) FILE_OPEN, 0); if (!NT_SUCCESS(Status)) + { + NtClose(StdOutput); return FALSE; + } /* Reset the queue state */ InputQueueEmpty = TRUE; diff --git a/drivers/setup/blue/blue.c b/drivers/setup/blue/blue.c index 56a115fffd4..e9accab60e8 100644 --- a/drivers/setup/blue/blue.c +++ b/drivers/setup/blue/blue.c @@ -5,6 +5,7 @@ * COPYRIGHT: Copyright 1999 Boudewijn Dekker * Copyright 1999-2019 Eric Kohl * Copyright 2006 Filip Navara + * Copyright 2019 Hermes Belusca-Maito */ /* INCLUDES ******************************************************************/ @@ -25,6 +26,10 @@ typedef struct _DEVICE_EXTENSION { PUCHAR VideoMemory; /* Pointer to video memory */ + SIZE_T VideoMemorySize; + BOOLEAN Enabled; + PUCHAR ScreenBuffer; /* Pointer to screenbuffer */ + SIZE_T ScreenBufferSize; ULONG CursorSize; INT CursorVisible; USHORT CharAttribute; @@ -32,6 +37,8 @@ typedef struct _DEVICE_EXTENSION UCHAR ScanLines; /* Height of a text line */ USHORT Rows; /* Number of rows */ USHORT Columns; /* Number of columns */ + USHORT CursorX, CursorY; /* Cursor position */ + ULONG CodePage; /* Specifies the font associated to this code page */ } DEVICE_EXTENSION, *PDEVICE_EXTENSION; typedef struct _VGA_REGISTERS @@ -79,6 +86,218 @@ static const UCHAR DefaultPalette[] = 0xFF, 0xFF, 0xFF }; +/* INBV MANAGEMENT FUNCTIONS **************************************************/ + +static BOOLEAN +ScrResetScreen( + _In_ PDEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN FullReset, + _In_ BOOLEAN Enable); + +static PDEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL; +static HANDLE InbvThreadHandle = NULL; +static BOOLEAN InbvMonitoring = FALSE; + +/* + * Reinitialize the display to base VGA mode. + * + * Returns TRUE if it completely resets the adapter to the given character mode. + * Returns FALSE otherwise, indicating that the HAL should perform the VGA mode + * reset itself after HwVidResetHw() returns control. + * + * This callback has been registered with InbvNotifyDisplayOwnershipLost() + * and is called by InbvAcquireDisplayOwnership(), typically when the bugcheck + * code regains display access. Therefore this routine can be called at any + * IRQL, and in particular at IRQL = HIGH_LEVEL. This routine must also reside + * completely in non-paged pool, and cannot perform the following actions: + * Allocate memory, access pageable memory, use any synchronization mechanisms + * or call any routine that must execute at IRQL = DISPATCH_LEVEL or below. + */ +static BOOLEAN +NTAPI +ScrResetDisplayParametersEx( + _In_ ULONG Columns, + _In_ ULONG Rows, + _In_ BOOLEAN CalledByInbv) +{ + PDEVICE_EXTENSION DeviceExtension; + + /* Bail out early if we don't have any resettable adapter */ + if (!ResetDisplayParametersDeviceExtension) + return FALSE; // No adapter found: request HAL to perform a full reset. + + /* + * If we have been unexpectedly called via a callback from + * InbvAcquireDisplayOwnership(), start monitoring INBV. + */ + if (CalledByInbv) + InbvMonitoring = TRUE; + + DeviceExtension = ResetDisplayParametersDeviceExtension; + ASSERT(DeviceExtension); + + /* Disable the screen but don't reset all screen settings (OK at high IRQL) */ + return ScrResetScreen(DeviceExtension, FALSE, FALSE); +} + +/* This callback is registered with InbvNotifyDisplayOwnershipLost() */ +static BOOLEAN +NTAPI +ScrResetDisplayParameters( + _In_ ULONG Columns, + _In_ ULONG Rows) +{ + /* Call the extended function, specifying we were called by INBV */ + return ScrResetDisplayParametersEx(Columns, Rows, TRUE); +} + +/* + * (Adapted for ReactOS/Win2k3 from an original comment + * by Gé van Geldorp, June 2003, r4937) + * + * DISPLAY OWNERSHIP + * + * So, who owns the physical display and is allowed to write to it? + * + * In NT 5.x (Win2k/Win2k3), upon boot INBV/BootVid owns the display, unless + * /NOGUIBOOT has been specified in the boot command line. Later in the boot + * sequence, WIN32K.SYS opens the DISPLAY device. This open call ends up in + * VIDEOPRT.SYS. This component takes ownership of the display by calling + * InbvNotifyDisplayOwnershipLost() -- effectively telling INBV to release + * ownership of the display it previously had. From that moment on, the display + * is owned by that component and can be switched to graphics mode. The display + * is not supposed to return to text mode, except in case of a bugcheck. + * The bugcheck code calls InbvAcquireDisplayOwnership() so as to make INBV + * re-take display ownership, and calls back the function previously registered + * by VIDEOPRT.SYS with InbvNotifyDisplayOwnershipLost(). After the bugcheck, + * execution is halted. So, under NT, the only possible sequence of display + * modes is text mode -> graphics mode -> text mode (the latter hopefully + * happening very infrequently). + * + * In ReactOS things are a little bit different. We want to have a functional + * interactive text mode. We should be able to switch back and forth from + * text mode to graphics mode when a GUI app is started and then finished. + * Also, when the system bugchecks in graphics mode we want to switch back to + * text mode and show the bugcheck information. Last but not least, when using + * KDBG in /DEBUGPORT=SCREEN mode, breaking into the debugger would trigger a + * switch to text mode, and the user would expect that by continuing execution + * a switch back to graphics mode is done. + */ +static VOID +NTAPI +InbvMonitorThread( + _In_ PVOID Context) +{ + LARGE_INTEGER Delay; + USHORT i; + + KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); + + while (TRUE) + { + /* + * During one second, check the INBV status each 100 milliseconds, + * then revert to 1 second delay. + */ + i = 10; + Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay + while (!InbvMonitoring) + { + KeDelayExecutionThread(KernelMode, FALSE, &Delay); + + if ((i > 0) && (--i == 0)) + Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay + } + + /* + * Loop while the display is owned by INBV. We cannot do anything else + * than polling since INBV does not offer a proper notification system. + * + * During one second, check the INBV status each 100 milliseconds, + * then revert to 1 second delay. + */ + i = 10; + Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay + while (InbvCheckDisplayOwnership()) + { + KeDelayExecutionThread(KernelMode, FALSE, &Delay); + + if ((i > 0) && (--i == 0)) + Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay + } + + /* Reset the monitoring */ + InbvMonitoring = FALSE; + + /* + * Somebody released INBV display ownership, usually by invoking + * InbvNotifyDisplayOwnershipLost(). However the caller of this + * function certainly specified a different callback than ours. + * As we are going to be the only owner of the active display, + * we need to re-register our own display reset callback. + */ + InbvNotifyDisplayOwnershipLost(ScrResetDisplayParameters); + + /* Re-enable the screen, keeping the original screen settings */ + if (ResetDisplayParametersDeviceExtension) + ScrResetScreen(ResetDisplayParametersDeviceExtension, FALSE, TRUE); + } + + // FIXME: See ScrInbvCleanup(). + // PsTerminateSystemThread(STATUS_SUCCESS); +} + +static NTSTATUS +ScrInbvInitialize(VOID) +{ + /* Create the INBV monitoring thread if needed */ + if (!InbvThreadHandle) + { + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(NULL, OBJ_KERNEL_HANDLE); + + Status = PsCreateSystemThread(&InbvThreadHandle, + 0, + &ObjectAttributes, + NULL, + NULL, + InbvMonitorThread, + NULL); + if (!NT_SUCCESS(Status)) + InbvThreadHandle = NULL; + } + + /* Re-register the display reset callback with INBV */ + InbvNotifyDisplayOwnershipLost(ScrResetDisplayParameters); + + return STATUS_SUCCESS; +} + +static NTSTATUS +ScrInbvCleanup(VOID) +{ + // HANDLE ThreadHandle; + + // ResetDisplayParametersDeviceExtension = NULL; + InbvNotifyDisplayOwnershipLost(NULL); + ScrResetDisplayParametersEx(80, 50, FALSE); + // or InbvAcquireDisplayOwnership(); ? + +#if 0 + // TODO: Find the best way to communicate the request. + /* Signal the INBV monitoring thread and wait for it to terminate */ + ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL); + if (ThreadHandle) + { + KeWaitForSingleObject(&ThreadHandle, Executive, KernelMode, FALSE, NULL); + /* Close its handle */ + ObCloseHandle(ThreadHandle, KernelMode); + } +#endif + + return STATUS_SUCCESS; +} + /* FUNCTIONS **************************************************************/ static VOID @@ -135,15 +354,66 @@ ScrSetRegisters(const VGA_REGISTERS *Registers) WRITE_PORT_UCHAR(PELMASK, 0xff); } +static VOID +FASTCALL +ScrSetCursor( + _In_ PDEVICE_EXTENSION DeviceExtension) +{ + ULONG Offset; + + if (!DeviceExtension->VideoMemory) + return; + + Offset = (DeviceExtension->CursorY * DeviceExtension->Columns) + DeviceExtension->CursorX; + + _disable(); + WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); + WRITE_PORT_UCHAR(CRTC_DATA, Offset); + WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); + WRITE_PORT_UCHAR(CRTC_DATA, Offset >> 8); + _enable(); +} + +static VOID +FASTCALL +ScrSetCursorShape( + _In_ PDEVICE_EXTENSION DeviceExtension) +{ + ULONG size, height; + UCHAR data, value; + + if (!DeviceExtension->VideoMemory) + return; + + height = DeviceExtension->ScanLines; + data = (DeviceExtension->CursorVisible) ? 0x00 : 0x20; + + size = (DeviceExtension->CursorSize * height) / 100; + if (size < 1) + size = 1; + + data |= (UCHAR)(height - size); + + _disable(); + WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART); + WRITE_PORT_UCHAR(CRTC_DATA, data); + WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND); + value = READ_PORT_UCHAR(CRTC_DATA) & 0xE0; + WRITE_PORT_UCHAR(CRTC_DATA, value | (height - 1)); + _enable(); +} + static VOID FASTCALL ScrAcquireOwnership( _In_ PDEVICE_EXTENSION DeviceExtension) { - ULONG offset; UCHAR data, value; + ULONG offset; ULONG Index; + _disable(); + ScrSetRegisters(&VidpMode3Regs); /* Disable screen and enable palette access */ @@ -162,12 +432,6 @@ ScrAcquireOwnership( READ_PORT_UCHAR(STATUS); WRITE_PORT_UCHAR(ATTRIB, 0x20); - /* Get current output position */ - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); - offset = READ_PORT_UCHAR(CRTC_DATA); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); - offset += (READ_PORT_UCHAR(CRTC_DATA) << 8); - /* Switch blinking characters off */ READ_PORT_UCHAR(ATTRC_INPST1); value = READ_PORT_UCHAR(ATTRC_WRITEREG); @@ -190,7 +454,14 @@ ScrAcquireOwnership( WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_SCANLINES); DeviceExtension->ScanLines = (READ_PORT_UCHAR(CRTC_DATA) & 0x1F) + 1; + /* Retrieve the current output cursor position */ + WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); + offset = READ_PORT_UCHAR(CRTC_DATA); + WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); + offset += (READ_PORT_UCHAR(CRTC_DATA) << 8); + /* Show blinking cursor */ + // FIXME: cursor block? Call ScrSetCursorShape() instead? WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART); WRITE_PORT_UCHAR(CRTC_DATA, (DeviceExtension->ScanLines - 1) & 0x1F); WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND); @@ -198,15 +469,19 @@ ScrAcquireOwnership( WRITE_PORT_UCHAR(CRTC_DATA, data | ((DeviceExtension->ScanLines - 1) & 0x1F)); - /* Calculate number of text rows */ - DeviceExtension->Rows = - DeviceExtension->Rows / DeviceExtension->ScanLines; -#ifdef BOCHS_30ROWS - DeviceExtension->Rows = 30; -#endif + _enable(); - /* Upload a default font for the default codepage 437 */ - ScrLoadFontTable(437); + /* Calculate number of text rows */ + DeviceExtension->Rows = DeviceExtension->Rows / DeviceExtension->ScanLines; + + /* Set the cursor position, clipping it to the screen */ + DeviceExtension->CursorX = (USHORT)(offset % DeviceExtension->Columns); + DeviceExtension->CursorY = (USHORT)(offset / DeviceExtension->Columns); + // DeviceExtension->CursorX = min(max(DeviceExtension->CursorX, 0), DeviceExtension->Columns - 1); + DeviceExtension->CursorY = min(max(DeviceExtension->CursorY, 0), DeviceExtension->Rows - 1); + + /* Upload a default font for the current codepage */ + ScrLoadFontTable(DeviceExtension->CodePage); DPRINT("%d Columns %d Rows %d Scanlines\n", DeviceExtension->Columns, @@ -214,6 +489,172 @@ ScrAcquireOwnership( DeviceExtension->ScanLines); } +static BOOLEAN +ScrResetScreen( + _In_ PDEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN FullReset, + _In_ BOOLEAN Enable) +{ +#define FOREGROUND_LIGHTGRAY (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) + + PHYSICAL_ADDRESS BaseAddress; + + /* Allow resets to the same state only for full resets */ + if (!FullReset && (Enable == DeviceExtension->Enabled)) + return FALSE; // STATUS_INVALID_PARAMETER; STATUS_INVALID_DEVICE_REQUEST; + + if (FullReset) + { + DeviceExtension->CursorSize = 5; /* FIXME: value correct?? */ + DeviceExtension->CursorVisible = TRUE; + + /* More initialization */ + DeviceExtension->CharAttribute = BACKGROUND_BLUE | FOREGROUND_LIGHTGRAY; + DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT | + ENABLE_WRAP_AT_EOL_OUTPUT; + DeviceExtension->CodePage = 437; /* Use default codepage */ + } + + if (Enable) + { + ScrAcquireOwnership(DeviceExtension); + + if (FullReset) + { + /* + * Fully reset the screen and all its settings. + */ + + /* Unmap any previously mapped video memory */ + if (DeviceExtension->VideoMemory) + { + ASSERT(DeviceExtension->VideoMemorySize != 0); + MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize); + } + DeviceExtension->VideoMemory = NULL; + DeviceExtension->VideoMemorySize = 0; + + /* Free any previously allocated backup screenbuffer */ + if (DeviceExtension->ScreenBuffer) + { + ASSERT(DeviceExtension->ScreenBufferSize != 0); + ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE); + } + DeviceExtension->ScreenBuffer = NULL; + DeviceExtension->ScreenBufferSize = 0; + + /* Get a pointer to the video memory */ + DeviceExtension->VideoMemorySize = DeviceExtension->Rows * DeviceExtension->Columns * 2; + if (DeviceExtension->VideoMemorySize == 0) + return FALSE; // STATUS_INVALID_VIEW_SIZE; STATUS_MAPPED_FILE_SIZE_ZERO; + + /* Map the video memory */ + BaseAddress.QuadPart = VIDMEM_BASE; + DeviceExtension->VideoMemory = + (PUCHAR)MmMapIoSpace(BaseAddress, DeviceExtension->VideoMemorySize, MmNonCached); + if (!DeviceExtension->VideoMemory) + { + DeviceExtension->VideoMemorySize = 0; + return FALSE; // STATUS_NONE_MAPPED; STATUS_NOT_MAPPED_VIEW; STATUS_CONFLICTING_ADDRESSES; + } + + /* Initialize the backup screenbuffer in non-paged pool (must be accessible at high IRQL) */ + DeviceExtension->ScreenBufferSize = DeviceExtension->VideoMemorySize; + DeviceExtension->ScreenBuffer = + (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ScreenBufferSize, TAG_BLUE); + if (!DeviceExtension->ScreenBuffer) + { + DPRINT1("Could not allocate screenbuffer, ignore...\n"); + DeviceExtension->ScreenBufferSize = 0; + } + + /* (Re-)initialize INBV */ + ScrInbvInitialize(); + } + else + { + /* + * Restore the previously disabled screen. + */ + + /* Restore the snapshot of the video memory from the backup screenbuffer */ + if (DeviceExtension->ScreenBuffer) + { + ASSERT(DeviceExtension->VideoMemory); + ASSERT(DeviceExtension->ScreenBuffer); + ASSERT(DeviceExtension->ScreenBufferSize != 0); + ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize); + + RtlCopyMemory(DeviceExtension->VideoMemory, + DeviceExtension->ScreenBuffer, + DeviceExtension->VideoMemorySize); + } + + /* Restore the cursor state */ + ScrSetCursor(DeviceExtension); + ScrSetCursorShape(DeviceExtension); + } + DeviceExtension->Enabled = TRUE; + } + else + { + DeviceExtension->Enabled = FALSE; + if (FullReset) + { + /* + * Fully disable the screen and reset all its settings. + */ + + /* Clean INBV up */ + ScrInbvCleanup(); + + /* Unmap any previously mapped video memory */ + if (DeviceExtension->VideoMemory) + { + ASSERT(DeviceExtension->VideoMemorySize != 0); + MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize); + } + DeviceExtension->VideoMemory = NULL; + DeviceExtension->VideoMemorySize = 0; + + /* Free any previously allocated backup screenbuffer */ + if (DeviceExtension->ScreenBuffer) + { + ASSERT(DeviceExtension->ScreenBufferSize != 0); + ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE); + } + DeviceExtension->ScreenBuffer = NULL; + DeviceExtension->ScreenBufferSize = 0; + + /* Store dummy values */ + DeviceExtension->Columns = 1; + DeviceExtension->Rows = 1; + DeviceExtension->ScanLines = 1; + } + else + { + /* + * Partially disable the screen such that it can be restored later. + */ + + /* Take a snapshot of the video memory into the backup screenbuffer */ + if (DeviceExtension->ScreenBuffer) + { + ASSERT(DeviceExtension->VideoMemory); + ASSERT(DeviceExtension->ScreenBuffer); + ASSERT(DeviceExtension->ScreenBufferSize != 0); + ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize); + + RtlCopyMemory(DeviceExtension->ScreenBuffer, + DeviceExtension->VideoMemory, + DeviceExtension->VideoMemorySize); + } + } + } + + return TRUE; // STATUS_SUCCESS; +} + static DRIVER_DISPATCH ScrCreate; static NTSTATUS NTAPI @@ -221,44 +662,10 @@ ScrCreate( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { -#define FOREGROUND_LIGHTGRAY (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) - - PDEVICE_EXTENSION DeviceExtension; - PHYSICAL_ADDRESS BaseAddress; - NTSTATUS Status; - - DeviceExtension = DeviceObject->DeviceExtension; - - if (!InbvCheckDisplayOwnership()) - { - ScrAcquireOwnership(DeviceExtension); - - /* Get a pointer to the video memory */ - BaseAddress.QuadPart = VIDMEM_BASE; - DeviceExtension->VideoMemory = - (PUCHAR)MmMapIoSpace(BaseAddress, DeviceExtension->Rows * DeviceExtension->Columns * 2, MmNonCached); - } - else - { - /* Store dummy values */ - DeviceExtension->Columns = 1; - DeviceExtension->Rows = 1; - DeviceExtension->ScanLines = 1; - } - - DeviceExtension->CursorSize = 5; /* FIXME: value correct?? */ - DeviceExtension->CursorVisible = TRUE; - - /* More initialization */ - DeviceExtension->CharAttribute = BACKGROUND_BLUE | FOREGROUND_LIGHTGRAY; - DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT | - ENABLE_WRAP_AT_EOL_OUTPUT; - - Status = STATUS_SUCCESS; - - Irp->IoStatus.Status = Status; + // Irp->IoStatus.Information = FILE_OPENED; + Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + return STATUS_SUCCESS; } static DRIVER_DISPATCH ScrWrite; @@ -268,9 +675,9 @@ ScrWrite( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { + NTSTATUS Status; PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; - NTSTATUS Status; PCHAR pch = Irp->UserBuffer; PUCHAR vidmem; ULONG i; @@ -279,9 +686,9 @@ ScrWrite( USHORT rows, columns; BOOLEAN processed = !!(DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT); - if (InbvCheckDisplayOwnership()) + if (!DeviceExtension->Enabled || !DeviceExtension->VideoMemory) { - /* Display is in graphics mode, we're not allowed to touch it */ + /* Display is not enabled, we're not allowed to touch it */ Status = STATUS_SUCCESS; Irp->IoStatus.Status = Status; @@ -293,24 +700,26 @@ ScrWrite( vidmem = DeviceExtension->VideoMemory; rows = DeviceExtension->Rows; columns = DeviceExtension->Columns; + cursorx = DeviceExtension->CursorX; + cursory = DeviceExtension->CursorY; - _disable(); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); - offset = READ_PORT_UCHAR(CRTC_DATA)<<8; - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); - offset += READ_PORT_UCHAR(CRTC_DATA); - _enable(); - - cursory = (USHORT)(offset / columns); - cursorx = (USHORT)(offset % columns); if (!processed) { /* Raw output mode */ + + /* Calculate the offset from the cursor position */ + offset = cursorx + cursory * columns; + // FIXME: Does the buffer only contains chars? or chars + attributes? // FIXME2: Fix buffer overflow. - RtlCopyMemory(&vidmem[(cursorx * 2) + (cursory * columns * 2)], - pch, stk->Parameters.Write.Length); + RtlCopyMemory(&vidmem[offset * 2], pch, stk->Parameters.Write.Length); offset += (stk->Parameters.Write.Length / 2); + + /* Set the cursor position, clipping it to the screen */ + cursorx = (USHORT)(offset % columns); + cursory = (USHORT)(offset / columns); + // cursorx = min(max(cursorx, 0), columns - 1); + cursory = min(max(cursory, 0), rows - 1); } else { @@ -327,19 +736,18 @@ ScrWrite( } else if (cursory > 0) { - cursorx = columns - 1; cursory--; + cursorx = columns - 1; } - vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' '; - vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute; + offset = cursorx + cursory * columns; + vidmem[offset * 2] = ' '; + vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; break; } case '\n': cursory++; - cursorx = 0; - break; - + /* Fall back */ case '\r': cursorx = 0; break; @@ -347,15 +755,16 @@ ScrWrite( case '\t': { offset = TAB_WIDTH - (cursorx % TAB_WIDTH); - for (j = 0; j < offset; j++) + while (offset--) { - vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' '; + vidmem[(cursorx + cursory * columns) * 2] = ' '; cursorx++; - if (cursorx >= columns) { - cursory++; cursorx = 0; + cursory++; + /* We jumped to the next line, stop there */ + break; } } break; @@ -363,13 +772,14 @@ ScrWrite( default: { - vidmem[(cursorx * 2) + (cursory * columns * 2)] = *pch; - vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute; + offset = cursorx + cursory * columns; + vidmem[offset * 2] = *pch; + vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; cursorx++; if (cursorx >= columns) { - cursory++; cursorx = 0; + cursory++; } break; } @@ -393,22 +803,20 @@ ScrWrite( cursory = rows - 1; for (j = 0; j < columns; j++) { - vidmem[(j * 2) + (cursory * columns * 2)] = ' '; - vidmem[(j * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute; + offset = j + cursory * columns; + vidmem[offset * 2] = ' '; + vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; } } } - - /* Set the cursor position */ - offset = (cursory * columns) + cursorx; } - _disable(); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); - WRITE_PORT_UCHAR(CRTC_DATA, offset); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); - offset >>= 8; - WRITE_PORT_UCHAR(CRTC_DATA, offset); - _enable(); + + /* Set the cursor position */ + ASSERT((0 <= cursorx) && (cursorx < DeviceExtension->Columns)); + ASSERT((0 <= cursory) && (cursory < DeviceExtension->Rows)); + DeviceExtension->CursorX = cursorx; + DeviceExtension->CursorY = cursory; + ScrSetCursor(DeviceExtension); Status = STATUS_SUCCESS; @@ -432,33 +840,29 @@ ScrIoControl( DeviceExtension = DeviceObject->DeviceExtension; switch (stk->Parameters.DeviceIoControl.IoControlCode) { + case IOCTL_CONSOLE_RESET_SCREEN: + { + BOOLEAN Enable = !!*(PULONG)Irp->AssociatedIrp.SystemBuffer; + + /* Fully enable or disable the screen */ + Status = (ScrResetScreen(DeviceExtension, TRUE, Enable) + ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); + + Irp->IoStatus.Information = 0; + break; + } + case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO: { PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer; USHORT rows = DeviceExtension->Rows; USHORT columns = DeviceExtension->Columns; - ULONG offset; - - if (!InbvCheckDisplayOwnership()) - { - /* read cursor position from crtc */ - _disable(); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); - offset = READ_PORT_UCHAR(CRTC_DATA); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); - offset += (READ_PORT_UCHAR(CRTC_DATA) << 8); - _enable(); - } - else - { - offset = 0; - } pcsbi->dwSize.X = columns; pcsbi->dwSize.Y = rows; - pcsbi->dwCursorPosition.X = (SHORT)(offset % columns); - pcsbi->dwCursorPosition.Y = (SHORT)(offset / columns); + pcsbi->dwCursorPosition.X = DeviceExtension->CursorX; + pcsbi->dwCursorPosition.Y = DeviceExtension->CursorY; pcsbi->wAttributes = DeviceExtension->CharAttribute; @@ -478,7 +882,6 @@ ScrIoControl( case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO: { PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer; - ULONG Offset; if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns || pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows ) @@ -490,18 +893,13 @@ ScrIoControl( DeviceExtension->CharAttribute = pcsbi->wAttributes; - Offset = (pcsbi->dwCursorPosition.Y * DeviceExtension->Columns) + - pcsbi->dwCursorPosition.X; - - if (!InbvCheckDisplayOwnership()) - { - _disable(); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); - WRITE_PORT_UCHAR(CRTC_DATA, Offset); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); - WRITE_PORT_UCHAR(CRTC_DATA, Offset >> 8); - _enable(); - } + /* Set the cursor position */ + ASSERT((0 <= pcsbi->dwCursorPosition.X) && (pcsbi->dwCursorPosition.X < DeviceExtension->Columns)); + ASSERT((0 <= pcsbi->dwCursorPosition.Y) && (pcsbi->dwCursorPosition.Y < DeviceExtension->Rows)); + DeviceExtension->CursorX = pcsbi->dwCursorPosition.X; + DeviceExtension->CursorY = pcsbi->dwCursorPosition.Y; + if (DeviceExtension->Enabled) + ScrSetCursor(DeviceExtension); Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; @@ -523,31 +921,11 @@ ScrIoControl( case IOCTL_CONSOLE_SET_CURSOR_INFO: { PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer; - UCHAR data, value; - ULONG size, height; DeviceExtension->CursorSize = pcci->dwSize; DeviceExtension->CursorVisible = pcci->bVisible; - - if (!InbvCheckDisplayOwnership()) - { - height = DeviceExtension->ScanLines; - data = (pcci->bVisible) ? 0x00 : 0x20; - - size = (pcci->dwSize * height) / 100; - if (size < 1) - size = 1; - - data |= (UCHAR)(height - size); - - _disable(); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART); - WRITE_PORT_UCHAR(CRTC_DATA, data); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND); - value = READ_PORT_UCHAR(CRTC_DATA) & 0xE0; - WRITE_PORT_UCHAR(CRTC_DATA, value | (height - 1)); - _enable(); - } + if (DeviceExtension->Enabled) + ScrSetCursorShape(DeviceExtension); Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; @@ -580,7 +958,7 @@ ScrIoControl( { POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer; PUCHAR vidmem; - int offset; + ULONG offset; ULONG dwCount; ULONG nMaxLength = Buf->nLength; @@ -593,11 +971,10 @@ ScrIoControl( break; } - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { vidmem = DeviceExtension->VideoMemory; - offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) + - (Buf->dwCoord.X * 2) + 1; + offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1; nMaxLength = min(nMaxLength, (DeviceExtension->Rows - Buf->dwCoord.Y) @@ -621,7 +998,7 @@ ScrIoControl( POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer; PUSHORT pAttr = (PUSHORT)MmGetSystemAddressForMdl(Irp->MdlAddress); PUCHAR vidmem; - int offset; + ULONG offset; ULONG dwCount; ULONG nMaxLength; @@ -634,11 +1011,10 @@ ScrIoControl( break; } - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { vidmem = DeviceExtension->VideoMemory; - offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) + - (Buf->dwCoord.X * 2) + 1; + offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1; nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength, (DeviceExtension->Rows - Buf->dwCoord.Y) @@ -666,7 +1042,7 @@ ScrIoControl( PCOORD pCoord = (PCOORD)MmGetSystemAddressForMdl(Irp->MdlAddress); PCHAR pAttr = (PCHAR)(pCoord + 1); PUCHAR vidmem; - int offset; + ULONG offset; ULONG dwCount; ULONG nMaxLength; @@ -678,11 +1054,10 @@ ScrIoControl( break; } - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { vidmem = DeviceExtension->VideoMemory; - offset = (pCoord->Y * DeviceExtension->Columns * 2) + - (pCoord->X * 2) + 1; + offset = (pCoord->X + pCoord->Y * DeviceExtension->Columns) * 2 + 1; nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD), (DeviceExtension->Rows - pCoord->Y) @@ -709,7 +1084,7 @@ ScrIoControl( { POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer; PUCHAR vidmem; - int offset; + ULONG offset; ULONG dwCount; ULONG nMaxLength = Buf->nLength; @@ -722,11 +1097,10 @@ ScrIoControl( break; } - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { vidmem = DeviceExtension->VideoMemory; - offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) + - (Buf->dwCoord.X * 2); + offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2; nMaxLength = min(nMaxLength, (DeviceExtension->Rows - Buf->dwCoord.Y) @@ -750,7 +1124,7 @@ ScrIoControl( POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer; PCHAR pChar = (PCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress); PUCHAR vidmem; - int offset; + ULONG offset; ULONG dwCount; ULONG nMaxLength; @@ -763,11 +1137,10 @@ ScrIoControl( break; } - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { vidmem = DeviceExtension->VideoMemory; - offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) + - (Buf->dwCoord.X * 2); + offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2; nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength, (DeviceExtension->Rows - Buf->dwCoord.Y) @@ -795,7 +1168,7 @@ ScrIoControl( PCOORD pCoord = (PCOORD)MmGetSystemAddressForMdl(Irp->MdlAddress); PCHAR pChar = (PCHAR)(pCoord + 1); PUCHAR vidmem; - int offset; + ULONG offset; ULONG dwCount; ULONG nMaxLength; @@ -807,11 +1180,10 @@ ScrIoControl( break; } - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { vidmem = DeviceExtension->VideoMemory; - offset = (pCoord->Y * DeviceExtension->Columns * 2) + - (pCoord->X * 2); + offset = (pCoord->X + pCoord->Y * DeviceExtension->Columns) * 2; nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD), (DeviceExtension->Rows - pCoord->Y) @@ -832,15 +1204,15 @@ ScrIoControl( { PCONSOLE_DRAW ConsoleDraw; PUCHAR Src, Dest; - UINT32 SrcDelta, DestDelta, i, Offset; + UINT32 SrcDelta, DestDelta, i; - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { ConsoleDraw = (PCONSOLE_DRAW) MmGetSystemAddressForMdl(Irp->MdlAddress); Src = (PUCHAR) (ConsoleDraw + 1); SrcDelta = ConsoleDraw->SizeX * 2; Dest = DeviceExtension->VideoMemory + - (ConsoleDraw->Y * DeviceExtension->Columns + ConsoleDraw->X) * 2; + (ConsoleDraw->X + ConsoleDraw->Y * DeviceExtension->Columns) * 2; DestDelta = DeviceExtension->Columns * 2; for (i = 0; i < ConsoleDraw->SizeY; i++) @@ -849,18 +1221,14 @@ ScrIoControl( Src += SrcDelta; Dest += DestDelta; } - - Offset = (ConsoleDraw->CursorY * DeviceExtension->Columns) + - ConsoleDraw->CursorX; - - _disable(); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); - WRITE_PORT_UCHAR(CRTC_DATA, Offset); - WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); - WRITE_PORT_UCHAR(CRTC_DATA, Offset >> 8); - _enable(); } + /* Set the cursor position, clipping it to the screen */ + DeviceExtension->CursorX = min(max(ConsoleDraw->CursorX, 0), DeviceExtension->Columns - 1); + DeviceExtension->CursorY = min(max(ConsoleDraw->CursorY, 0), DeviceExtension->Rows - 1); + if (DeviceExtension->Enabled) + ScrSetCursor(DeviceExtension); + Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; break; @@ -869,8 +1237,9 @@ ScrIoControl( case IOCTL_CONSOLE_LOADFONT: { ULONG CodePage = *(PULONG)Irp->AssociatedIrp.SystemBuffer; + DeviceExtension->CodePage = CodePage; - if (!InbvCheckDisplayOwnership()) + if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) { /* Upload a font for the codepage if needed */ ScrLoadFontTable(CodePage); @@ -953,9 +1322,16 @@ DriverEntry( Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); if (NT_SUCCESS(Status)) + { + /* By default disable the screen */ + ResetDisplayParametersDeviceExtension = DeviceObject->DeviceExtension; + ScrResetScreen(DeviceObject->DeviceExtension, TRUE, FALSE); DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + } else + { IoDeleteDevice(DeviceObject); + } return Status; } diff --git a/sdk/include/reactos/drivers/blue/ntddblue.h b/sdk/include/reactos/drivers/blue/ntddblue.h index 50ef34d2365..5c6df7bfff7 100644 --- a/sdk/include/reactos/drivers/blue/ntddblue.h +++ b/sdk/include/reactos/drivers/blue/ntddblue.h @@ -1,6 +1,8 @@ #ifndef _NTDDBLUE_H_INCLUDED_ #define _NTDDBLUE_H_INCLUDED_ +#define IOCTL_CONSOLE_RESET_SCREEN CTL_CODE(FILE_DEVICE_SCREEN, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS) + #define IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO CTL_CODE(FILE_DEVICE_SCREEN, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO CTL_CODE(FILE_DEVICE_SCREEN, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_CONSOLE_GET_CURSOR_INFO CTL_CODE(FILE_DEVICE_SCREEN, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS) diff --git a/win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c b/win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c index e66203ad7b8..e4874b10df6 100644 --- a/win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c +++ b/win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c @@ -375,7 +375,7 @@ TuiConsoleThread(PVOID Param) static BOOL TuiInit(DWORD OemCP) { - BOOL Ret = FALSE; + BOOL Success; CONSOLE_SCREEN_BUFFER_INFO ScrInfo; DWORD BytesReturned; WNDCLASSEXW wc; @@ -388,6 +388,7 @@ TuiInit(DWORD OemCP) /* * Initialize the TUI front-end: * - load the console driver, + * - open BlueScreen device and enable it, * - set default screen attributes, * - grab the console size. */ @@ -404,6 +405,16 @@ TuiInit(DWORD OemCP) return FALSE; } + Success = TRUE; + if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_RESET_SCREEN, + &Success, sizeof(Success), NULL, 0, + &BytesReturned, NULL)) + { + DPRINT1("Failed to enable the screen.\n"); + CloseHandle(ConsoleDeviceHandle); + return FALSE; + } + if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT, &OemCP, sizeof(OemCP), NULL, 0, &BytesReturned, NULL)) @@ -416,7 +427,7 @@ TuiInit(DWORD OemCP) &TextAttribute, sizeof(TextAttribute), NULL, 0, &BytesReturned, NULL)) { - DPRINT1("Failed to set text attribute\n"); + DPRINT1("Failed to set text attribute.\n"); } ActiveConsole = NULL; @@ -426,8 +437,8 @@ TuiInit(DWORD OemCP) if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL)) { - DPRINT1("Failed to get console info\n"); - Ret = FALSE; + DPRINT1("Failed to get console info.\n"); + Success = FALSE; goto Quit; } PhysicalConsoleSize = ScrInfo.dwSize; @@ -443,23 +454,23 @@ TuiInit(DWORD OemCP) ConsoleClassAtom = RegisterClassExW(&wc); if (ConsoleClassAtom == 0) { - DPRINT1("Failed to register TUI console wndproc\n"); - Ret = FALSE; + DPRINT1("Failed to register TUI console wndproc.\n"); + Success = FALSE; } else { - Ret = TRUE; + Success = TRUE; } Quit: - if (!Ret) + if (!Success) { DeleteCriticalSection(&ActiveVirtConsLock); CloseHandle(ConsoleDeviceHandle); } - ConsInitialized = Ret; - return Ret; + ConsInitialized = Success; + return Success; }