Patch by Anton Yarotsky:
authorSir Richard <sir_richard@svn.reactos.org>
Mon, 13 Sep 2010 20:36:49 +0000 (20:36 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Mon, 13 Sep 2010 20:36:49 +0000 (20:36 +0000)
[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
reactos/boot/freeldr/freeldr/freeldr_base.rbuild
reactos/boot/freeldr/freeldr/setupldr.rbuild
reactos/boot/freeldr/freeldr/windows/headless.c [new file with mode: 0644]
reactos/boot/freeldr/freeldr/windows/winldr.c

index 8e70ac9..4eb9760 100644 (file)
@@ -32,5 +32,6 @@
                <library>cmlib</library>
                <library>rtl</library>
                <library>libcntpr</library>
+               <library>cportlib</library>
        </module>
 </ifnot>
index a8b784b..db584d4 100644 (file)
@@ -75,6 +75,7 @@
                <file>winldr.c</file>
                <file>wlmemory.c</file>
                <file>wlregistry.c</file>
+               <file>headless.c</file>
        </directory>
        <file>freeldr.c</file>
        <file>debug.c</file>
index 6d1c25e..fec2e8b 100644 (file)
@@ -14,6 +14,7 @@
        <library>setupldr_main</library>
        <library>rossym</library>
        <library>cmlib</library>
+       <library>cportlib</library>
        <library>rtl</library>
        <library>libcntpr</library>
 </module>
diff --git a/reactos/boot/freeldr/freeldr/windows/headless.c b/reactos/boot/freeldr/freeldr/windows/headless.c
new file mode 100644 (file)
index 0000000..5e5d66d
--- /dev/null
@@ -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 <freeldr.h>
+#include <cportlib/cportlib.h>
+
+/* Note: Move these to some smbios.h header */
+#define SYSID_TYPE_UUID "_UUID_"
+#define SYSID_UUID_DATA_SIZE 16
+#include <pshpack1.h>
+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 <poppack.h>
+
+/* 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();
+       }
+}
index c068517..bc13b86 100644 (file)
@@ -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);