From ef0d280232659714c53cb060a14c1557666ff6b9 Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Mon, 13 Sep 2010 20:36:49 +0000 Subject: [PATCH] Patch by Anton Yarotsky: [FREELDR]: Implement support for /redirect=comX (usebiossettings not yet supported) and /redirectbaudrate. Uses cportlib. Tested, serial output works and kernel reports "Headless support is not yet implemented". Future revisions should support ACPI SRT for PCI-based serial ports on server systems. svn path=/trunk/; revision=48768 --- reactos/boot/freeldr/freeldr/freeldr.rbuild | 1 + .../boot/freeldr/freeldr/freeldr_base.rbuild | 1 + reactos/boot/freeldr/freeldr/setupldr.rbuild | 1 + .../boot/freeldr/freeldr/windows/headless.c | 313 ++++++++++++++++++ reactos/boot/freeldr/freeldr/windows/winldr.c | 8 + 5 files changed, 324 insertions(+) create mode 100644 reactos/boot/freeldr/freeldr/windows/headless.c diff --git a/reactos/boot/freeldr/freeldr/freeldr.rbuild b/reactos/boot/freeldr/freeldr/freeldr.rbuild index 8e70ac92fd8..4eb97602a8e 100644 --- a/reactos/boot/freeldr/freeldr/freeldr.rbuild +++ b/reactos/boot/freeldr/freeldr/freeldr.rbuild @@ -32,5 +32,6 @@ cmlib rtl libcntpr + cportlib diff --git a/reactos/boot/freeldr/freeldr/freeldr_base.rbuild b/reactos/boot/freeldr/freeldr/freeldr_base.rbuild index a8b784baf9b..db584d44e22 100644 --- a/reactos/boot/freeldr/freeldr/freeldr_base.rbuild +++ b/reactos/boot/freeldr/freeldr/freeldr_base.rbuild @@ -75,6 +75,7 @@ winldr.c wlmemory.c wlregistry.c + headless.c freeldr.c debug.c diff --git a/reactos/boot/freeldr/freeldr/setupldr.rbuild b/reactos/boot/freeldr/freeldr/setupldr.rbuild index 6d1c25e550d..fec2e8be1ea 100644 --- a/reactos/boot/freeldr/freeldr/setupldr.rbuild +++ b/reactos/boot/freeldr/freeldr/setupldr.rbuild @@ -14,6 +14,7 @@ setupldr_main rossym cmlib + cportlib rtl libcntpr diff --git a/reactos/boot/freeldr/freeldr/windows/headless.c b/reactos/boot/freeldr/freeldr/windows/headless.c new file mode 100644 index 00000000000..5e5d66d7607 --- /dev/null +++ b/reactos/boot/freeldr/freeldr/windows/headless.c @@ -0,0 +1,313 @@ +/* + * PROJECT: ReactOS Boot Loader + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: boot/freeldr/windows/headless.c + * PURPOSE: Provides support for Windows Emergency Management Services + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#include + +/* Note: Move these to some smbios.h header */ +#define SYSID_TYPE_UUID "_UUID_" +#define SYSID_UUID_DATA_SIZE 16 +#include +typedef struct _SYSID_UUID_ENTRY +{ + UCHAR Type[6]; + UCHAR Checksum; + USHORT Length; + UCHAR UUID[SYSID_UUID_DATA_SIZE]; +} SYSID_UUID_ENTRY, *PSYSID_UUID_ENTRY; +#include + +/* GLOBALS ********************************************************************/ + +HEADLESS_LOADER_BLOCK LoaderRedirectionInformation; +BOOLEAN WinLdrTerminalConnected; +ULONG WinLdrTerminalDeviceId; +ULONG WinLdrTerminalDelay; + +CPPORT Port[4] = +{ + {NULL, 0, TRUE}, + {NULL, 0, TRUE}, + {NULL, 0, TRUE}, + {NULL, 0, TRUE} +}; + +/* FUNCTIONS ******************************************************************/ + +VOID +WinLdrLoadGUID(OUT PGUID SystemGuid) +{ + PSYSID_UUID_ENTRY CurrentAddress; + + CurrentAddress = (PSYSID_UUID_ENTRY)0xE0000; + while (CurrentAddress < (PSYSID_UUID_ENTRY)0x100000) + { + if (RtlCompareMemory(&CurrentAddress->Type, SYSID_TYPE_UUID, 6) == 6) + { + RtlCopyMemory(SystemGuid, &CurrentAddress->UUID, SYSID_UUID_DATA_SIZE); + return; + } + CurrentAddress = (PSYSID_UUID_ENTRY)((ULONG_PTR)CurrentAddress + 1); + } + + RtlZeroMemory(SystemGuid, SYSID_UUID_DATA_SIZE); +} + +BOOLEAN +WinLdrPortInitialize(IN ULONG BaudRate, + IN ULONG PortNumber, + IN PUCHAR PortAddress, + IN BOOLEAN TerminalConnected, + OUT PULONG PortId) +{ + /* Set default baud rate */ + if (BaudRate == 0) BaudRate = 19200; + + /* Check if port or address given */ + if (PortNumber) + { + /* Pick correct address for port */ + if (!PortAddress) + { + switch (PortNumber) + { + case 1: + PortAddress = (PUCHAR)0x3F8; + break; + + case 2: + PortAddress = (PUCHAR)0x2F8; + break; + + case 3: + PortAddress = (PUCHAR)0x3E8; + break; + + default: + PortNumber = 4; + PortAddress = (PUCHAR)0x2E8; + } + } + } + else + { + /* Pick correct port for address */ + PortAddress = (PUCHAR)0x2F8; + if (CpDoesPortExist(PortAddress)) + { + PortNumber = 2; + } + else + { + PortAddress = (PUCHAR)0x3F8; + if (!CpDoesPortExist(PortAddress)) return FALSE; + PortNumber = 1; + } + } + + /* Not yet supported */ + ASSERT(LoaderRedirectionInformation.IsMMIODevice == FALSE); + + /* Check if port exists */ + if ((CpDoesPortExist(PortAddress)) || (CpDoesPortExist(PortAddress))) + { + /* Initialize port for first time, or re-initialize if specified */ + if (((TerminalConnected) && (Port[PortNumber - 1].Address)) || + !(Port[PortNumber - 1].Address)) + { + /* Initialize the port, return it */ + CpInitialize(&Port[PortNumber - 1], PortAddress, BaudRate); + *PortId = PortNumber - 1; + return TRUE; + } + } + + return FALSE; +} + +VOID +WinLdrPortPutByte(IN ULONG PortId, + IN UCHAR Data) +{ + CpPutByte(&Port[PortId], Data); +} + +BOOLEAN +WinLdrPortGetByte(IN ULONG PortId, + OUT PUCHAR Data) +{ + return CpGetByte(&Port[PortId], Data, TRUE, FALSE) == CP_GET_SUCCESS; +} + +BOOLEAN +WinLdrPortPollOnly(IN ULONG PortId) +{ + UCHAR Dummy; + + return CpGetByte(&Port[PortId], &Dummy, FALSE, TRUE) == CP_GET_SUCCESS; +} + +VOID +WinLdrEnableFifo(IN ULONG PortId, + IN BOOLEAN Enable) +{ + CpEnableFifo(Port[PortId].Address, Enable); +} + +VOID +WinLdrInitializeHeadlessPort(VOID) +{ + ULONG PortNumber, BaudRate; + PUCHAR PortAddress; + PCHAR AnsiReset = "\x1B[m"; + ULONG i; + + PortNumber = LoaderRedirectionInformation.PortNumber; + PortAddress = LoaderRedirectionInformation.PortAddress; + BaudRate = LoaderRedirectionInformation.BaudRate; + + /* Pick a port address */ + if (PortNumber) + { + if (!PortAddress) + { + switch (PortNumber) + { + case 2: + LoaderRedirectionInformation.PortAddress = (PUCHAR)0x2F8; + break; + + case 3: + LoaderRedirectionInformation.PortAddress = (PUCHAR)0x3E8; + break; + + case 4: + LoaderRedirectionInformation.PortAddress = (PUCHAR)0x2E8; + break; + + default: + LoaderRedirectionInformation.PortAddress = (PUCHAR)0x3F8; + break; + } + } + } + else + { + /* No number, so no EMS */ + WinLdrTerminalConnected = FALSE; + return; + } + + /* Call arch code to initialize the port */ + PortAddress = LoaderRedirectionInformation.PortAddress; + WinLdrTerminalConnected = WinLdrPortInitialize( + BaudRate, + PortNumber, + PortAddress, + WinLdrTerminalConnected, + &WinLdrTerminalDeviceId); + + if (WinLdrTerminalConnected) + { + /* Port seems usable, set it up and get the BIOS GUID */ + WinLdrEnableFifo(WinLdrTerminalDeviceId, TRUE); + + WinLdrLoadGUID(&LoaderRedirectionInformation.SystemGUID); + + /* Calculate delay in us based on the baud, assume 9600 if none given */ + if (!BaudRate) + { + BaudRate = 9600; + LoaderRedirectionInformation.BaudRate = BaudRate; + } + + WinLdrTerminalDelay = (10 * 1000 * 1000) / (BaudRate / 10) / 6; + + /* Sent an ANSI reset sequence to get the terminal up and running */ + for (i = 0; i < strlen(AnsiReset); i++) + { + WinLdrPortPutByte(WinLdrTerminalDeviceId, AnsiReset[i]); + StallExecutionProcessor(WinLdrTerminalDelay); + } + } + else + { + /* The port was bogus, so don't give any information to the kernel */ + RtlZeroMemory(&LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK)); + } +} + +VOID +WinLdrSetupEms(IN PCHAR BootOptions) +{ + PCHAR RedirectPort; + + /* Use a direction port if one was given, or use ACPI to detect one instead */ + RedirectPort = strstr(BootOptions, "/redirect="); + + if (RedirectPort) + { + RedirectPort = strstr(RedirectPort, "com"); + if (RedirectPort) + { + RedirectPort += sizeof("com") - 1; + LoaderRedirectionInformation.PortNumber = atoi(RedirectPort); + } + else + { + RedirectPort = strstr(RedirectPort, "usebiossettings"); + if (RedirectPort) + { + UiDrawStatusText("ACPI SRT Table Not Supported..."); + } + else + { + LoaderRedirectionInformation.PortAddress = (PUCHAR)strtoul(RedirectPort, 0, 16); + if (LoaderRedirectionInformation.PortAddress) + { + LoaderRedirectionInformation.PortNumber = 3; + } + } + } + } + + /* Use a direction baudrate if one was given */ + RedirectPort = strstr(BootOptions, "/redirectbaudrate="); + if (RedirectPort) + { + if (strstr(RedirectPort, "115200")) + { + LoaderRedirectionInformation.BaudRate = 115200; + } + else if (strstr(RedirectPort, "57600")) + { + LoaderRedirectionInformation.BaudRate = 57600; + } + else if (strstr(RedirectPort, "19200")) + { + LoaderRedirectionInformation.BaudRate = 19200; + } + else + { + LoaderRedirectionInformation.BaudRate = 9600; + } + } + + /* Enable headless support if parameters were found */ + if (LoaderRedirectionInformation.PortNumber) + { + if (!LoaderRedirectionInformation.BaudRate) + { + LoaderRedirectionInformation.BaudRate = 9600; + } + + WinLdrInitializeHeadlessPort(); + } +} diff --git a/reactos/boot/freeldr/freeldr/windows/winldr.c b/reactos/boot/freeldr/freeldr/windows/winldr.c index c068517dd2b..bc13b86e1e1 100644 --- a/reactos/boot/freeldr/freeldr/windows/winldr.c +++ b/reactos/boot/freeldr/freeldr/windows/winldr.c @@ -513,6 +513,10 @@ LoadAndBootWindows(PCSTR OperatingSystemName, /* Allocate and minimalistic-initialize LPB */ AllocateAndInitLPB(&LoaderBlock); + + /* Setup redirection support */ + extern void WinLdrSetupEms(IN PCHAR BootOptions); + WinLdrSetupEms(BootOptions); /* Detect hardware */ UseRealHeap = TRUE; @@ -597,6 +601,10 @@ LoadAndBootWindows(PCSTR OperatingSystemName, /* Save final value of LoaderPagesSpanned */ LoaderBlockVA->Extension->LoaderPagesSpanned = LoaderPagesSpanned; + + /* Set headless block pointer */ + extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation; + LoaderBlockVA->Extension->HeadlessLoaderBlock = PaToVa(&LoaderRedirectionInformation); DPRINTM(DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", KiSystemStartup, LoaderBlockVA);