CORE-13332. PcMemGetBiosMemoryMap(): Update ACPI (Extended Attributes) support. ...
authorSerge Gautherie <32623169+SergeGautherie@users.noreply.github.com>
Wed, 27 Dec 2017 10:09:20 +0000 (11:09 +0100)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Wed, 27 Dec 2017 10:09:20 +0000 (11:09 +0100)
[FREELDR] Update ACPI (Extended Attributes) support in PcMemGetBiosMemoryMap()
CORE-13332

* PcMemGetBiosMemoryMap(): Add Extended Attributes set and check for entry validity and default handling of unexpected case.

* pcbios.h: Rename superceded BIOS_MEMORY_MAP.Reserved. Adapt existing code to new ACPI 6.2-A definitions.

* pcbios.h: Update BIOS_MEMORY_TYPE and BIOS_MEMORY_MAP to ACPI 6.2-A from 1.0+.

* PcMemGetBiosMemoryMap(): Misc fixes, no functional changes.
*Create PcMemCheckUsableMemorySize(), to split unrelated code out.
*Fix a copypasta in 2 output strings from ba9a1c3abba3b795a55186f289704ec8eeaf1cb9.
*Improve output readability of TRACE("ECX ...", ...).
*Move a TRACE("\n").
*Improve code style a bit.

boot/freeldr/freeldr/arch/i386/pcmem.c
boot/freeldr/freeldr/include/arch/pc/pcbios.h

index 9b0997e..5741a84 100644 (file)
@@ -1,6 +1,9 @@
 /*
  *  FreeLoader
  *
+ * Copyright ... ... (See below.)
+ * Copyright 2017 Serge Gautherie
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -145,7 +148,8 @@ GetExtendedMemoryConfiguration(ULONG* pMemoryAtOneMB /* in KB */, ULONG* pMemory
     return FALSE;
 }
 
-static ULONG
+static
+ULONG
 PcMemGetConventionalMemorySize(VOID)
 {
     REGS Regs;
@@ -203,18 +207,11 @@ GetEbdaLocation(
 }
 
 static
-ULONG
-PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
+VOID
+PcMemCheckUsableMemorySize(VOID)
 {
-    REGS Regs;
-    ULONGLONG RealBaseAddress, EndAddress, RealSize;
-    TYPE_OF_MEMORY MemoryType;
     ULONG Size, RequiredSize;
 
-    ASSERT(PcBiosMapCount == 0);
-
-    TRACE("PcMemGetBiosMemoryMap()\n");
-
     /* Make sure the usable memory is large enough. To do this we check the 16
        bit value at address 0x413 inside the BDA, which gives us the usable size
        in KB */
@@ -231,6 +228,19 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi
             "If you see this, please report to the ReactOS team!",
             Size, RequiredSize);
     }
+}
+
+static
+ULONG
+PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
+{
+    REGS Regs;
+    ULONGLONG RealBaseAddress, EndAddress, RealSize;
+    TYPE_OF_MEMORY MemoryType;
+
+    ASSERT(PcBiosMapCount == 0);
+
+    TRACE("PcMemGetBiosMemoryMap()\n");
 
     /* Int 15h AX=E820h
      * Newer BIOSes - GET SYSTEM MEMORY MAP
@@ -254,6 +264,10 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi
 
     while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
     {
+        /* ACPI 3.0/4.0: Set Extended Attributes to enabled/valid by default, in case entry has no E.A.. */
+        ((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributesAsULONG = 0;
+        ((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributes.Enabled_Reserved = 1;
+
         /* Setup the registers for the BIOS call */
         Regs.x.eax = 0x0000E820;
         Regs.x.edx = 0x534D4150; /* ('SMAP') */
@@ -267,7 +281,7 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi
         TRACE("Int15h AX=E820h\n");
         TRACE("EAX = 0x%lx\n", Regs.x.eax);
         TRACE("EBX = 0x%lx\n", Regs.x.ebx);
-        TRACE("ECX = 0x%lx\n", Regs.x.ecx);
+        TRACE("ECX = %lu\n", Regs.x.ecx);
         TRACE("CF set = %s\n", (Regs.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
 
         /* If the BIOS didn't return 'SMAP' in EAX then
@@ -316,14 +330,23 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi
             break;
         }
 
+        if (((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributes.Enabled_Reserved == 0)
+        {
+            WARN("Discard disabled/invalid entry. (would-be-PcBiosMapCount = %lu)\n",
+                 PcBiosMapCount);
+            /* This unlikely case was correct between ACPI 3.0 and 4.0, so assume all is fine.
+             * Unless we would be ready to drop ACPI 3.0 compatibility.
+             */
+            goto nextRange;
+        }
+
         /* Copy data to global buffer */
-        RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, Regs.x.ecx);
+        RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, sizeof(BIOS_MEMORY_MAP));
 
         TRACE("BaseAddress: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
         TRACE("Length: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].Length);
         TRACE("Type: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Type);
-        TRACE("Reserved: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Reserved);
-        TRACE("\n");
+        TRACE("ExtendedAttributesAsULONG: 0x%08lx\n", PcBiosMemoryMap[PcBiosMapCount].ExtendedAttributesAsULONG);
 
         if (PcBiosMemoryMap[PcBiosMapCount].Length == 0)
         {
@@ -364,9 +387,13 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi
         else
         {
             if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryReserved)
+            {
                 MemoryType = LoaderFirmwarePermanent;
+            }
             else
+            {
                 MemoryType = LoaderSpecialMemory;
+            }
 
             /* Align down base of memory area */
             RealBaseAddress = ULONGLONG_ALIGN_DOWN_BY(
@@ -411,6 +438,8 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi
         PcBiosMapCount++;
 
 nextRange:
+        TRACE("\n");
+
         /* If the continuation value is zero,
          * then this was the last entry, so we're done. */
         if (Regs.x.ebx == 0x00000000)
@@ -422,9 +451,9 @@ nextRange:
     /* Check whether there would be more entries to process. */
     if (PcBiosMapCount >= MAX_BIOS_DESCRIPTORS && Regs.x.ebx != 0x00000000)
     {
-        ERR("PcBiosMapCount is already full! (PcBiosMapCount = %lu (>= %lu), PcMapCount = %lu)\n",
+        ERR("PcBiosMemoryMap is already full! (PcBiosMapCount = %lu (>= %lu), PcMapCount = %lu)\n",
             PcBiosMapCount, MAX_BIOS_DESCRIPTORS, PcMapCount);
-        // NotWantedForPublicBuilds: ASSERTMSG("PcBiosMapCount is already full!", FALSE);
+        // NotWantedForPublicBuilds: ASSERTMSG("PcBiosMemoryMap is already full!", FALSE);
         /* We keep retrieved entries, but ignore next entries.
          * We assume these entries are good to use as is. If they are not, we are in trouble...
          *
@@ -507,6 +536,8 @@ PcMemGetMemoryMap(ULONG *MemoryMapSize)
 
     TRACE("PcMemGetMemoryMap()\n");
 
+    PcMemCheckUsableMemorySize();
+
     EntryCount = PcMemGetBiosMemoryMap(PcMemoryMap, MAX_BIOS_DESCRIPTORS);
 
     /* If the BIOS didn't provide a memory map, synthesize one */
index b60df0b..826a168 100644 (file)
@@ -5,22 +5,55 @@
 
 typedef enum
 {
-    BiosMemoryUsable=1,
-    BiosMemoryReserved,
-    BiosMemoryAcpiReclaim,
-    BiosMemoryAcpiNvs
+    // ACPI 1.0.
+    BiosMemoryUsable        =  1,
+    BiosMemoryReserved      =  2,
+    BiosMemoryAcpiReclaim   =  3,
+    BiosMemoryAcpiNvs       =  4,
+    // ACPI 3.0.
+    BiosMemoryUnusable      =  5,
+    // ACPI 4.0.
+    BiosMemoryDisabled      =  6,
+    // ACPI 6.0.
+    BiosMemoryPersistent    =  7,
+    BiosMemoryUndefined08   =  8,
+    BiosMemoryUndefined09   =  9,
+    BiosMemoryUndefined10   = 10,
+    BiosMemoryUndefined11   = 11,
+    BiosMemoryOemDefined12  = 12
+    // BiosMemoryUndefinedNN   = 13-0xEFFFFFFF
+    // BiosMemoryOemDefinedNN  = 0xF0000000-0xFFFFFFFF
 } BIOS_MEMORY_TYPE;
 
 typedef struct
 {
-    ULONGLONG        BaseAddress;
-    ULONGLONG        Length;
-    ULONG        Type;
-    ULONG        Reserved;
+    // ACPI 1.0.
+    ULONGLONG   BaseAddress;
+    ULONGLONG   Length;
+    ULONG       Type;
+    // ACPI 3.0.
+    union
+    {
+        ULONG   ExtendedAttributesAsULONG;
+
+        struct
+        {
+            // Bit 0. ACPI 3.0. As of ACPI 4.0, became "Reserved -> must be 1".
+            ULONG Enabled_Reserved : 1;
+            // Bit 1. ACPI 3.0. As of ACPI 6.1, became "Unimplemented -> Deprecated".
+            ULONG NonVolatile_Deprecated : 1;
+            // Bit 2. ACPI 4.0. As of ACPI 6.1, became "Unimplemented -> Deprecated".
+            ULONG SlowAccess_Deprecated : 1;
+            // Bit 3. ACPI 4.0. ACPI 5.0-A added "Used only on PC-AT BIOS" (not UEFI).
+            ULONG ErrorLog : 1;
+            // Bits 4-31. ACPI 3.0.
+            ULONG Reserved : 28;
+        } ExtendedAttributes;
+    };
 } BIOS_MEMORY_MAP, *PBIOS_MEMORY_MAP;
 
 /* Int 15h AX=E820h Entry minimal size. */
-C_ASSERT(FIELD_OFFSET(BIOS_MEMORY_MAP, Reserved) == 20);
+C_ASSERT(FIELD_OFFSET(BIOS_MEMORY_MAP, ExtendedAttributes) == 20);
 /* Int 15h AX=E820h Entry maximal size. */
 C_ASSERT(sizeof(BIOS_MEMORY_MAP) == 24);