libpci: ecam: Fix scanning of Extended BIOS Data Area for ACPI RSDP

At physical address 0x40E (part of BDA) is stored indirect 16-bit paragraph
offset to the EBDA, and not the EBDA itself. Fix it.

ACPI code in linux kernel checks if the EBDA offset in BDA is above
physical address 0x400. Do the same check here. It is for detection if EBDA
is present as it does not have to be on the old computers or in some
virtualised environments.
diff --git a/lib/ecam.c b/lib/ecam.c
index 7f73d51..fdeec07 100644
--- a/lib/ecam.c
+++ b/lib/ecam.c
@@ -221,9 +221,11 @@
 #if defined(__amd64__) || defined(__i386__)
   struct ecam_access *eacc = a->backend_data;
   struct physmem *physmem = eacc->physmem;
+  long pagesize = eacc->pagesize;
   u64 rsdp_addr;
   u64 addr;
   void *map;
+  u64 ebda;
 #endif
   size_t len;
   FILE *f;
@@ -305,23 +307,39 @@
       rsdp_addr = 0;
 
       /* Scan first kB of Extended BIOS Data Area */
-      a->debug("scanning first kB of EBDA...");
-      map = physmem_map(physmem, 0, 0x40E + 1024, 0);
+      a->debug("reading EBDA location from BDA...");
+      map = physmem_map(physmem, 0, 0x40E + 2, 0);
       if (map != (void *)-1)
         {
-          for (addr = 0x40E; addr < 0x40E + 1024; addr += 16)
+          ebda = (u64)physmem_readw((unsigned char *)map + 0x40E) << 4;
+          if (physmem_unmap(physmem, map, 0x40E + 2) != 0)
+            a->debug("unmapping of BDA failed: %s...", strerror(errno));
+          if (ebda >= 0x400)
             {
-              if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr)))
+              a->debug("scanning first kB of EBDA at 0x%" PCI_U64_FMT_X "...", ebda);
+              map = physmem_map(physmem, ebda & ~(pagesize-1), 1024 + (ebda & (pagesize-1)), 0);
+              if (map != (void *)-1)
                 {
-                  rsdp_addr = addr;
-                  break;
+                  for (addr = ebda & (pagesize-1); addr < (ebda & (pagesize-1)) + 1024; addr += 16)
+                    {
+                      if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr)))
+                        {
+                          rsdp_addr = (ebda & ~(pagesize-1)) + addr;
+                          break;
+                        }
+                    }
+                  if (physmem_unmap(physmem, map, 1024 + (ebda & (pagesize-1))) != 0)
+                    a->debug("unmapping of EBDA failed: %s...", strerror(errno));
                 }
+              else
+                a->debug("mapping of EBDA failed: %s...", strerror(errno));
             }
-          if (physmem_unmap(physmem, map, 0x40E + 1024) != 0)
-            a->debug("unmapping of EBDA failed: %s...", strerror(errno));
+          else
+            a->debug("EBDA location 0x%" PCI_U64_FMT_X " is insane...", ebda);
         }
       else
-        a->debug("mapping of EBDA failed: %s...", strerror(errno));
+        a->debug("mapping of BDA failed: %s...", strerror(errno));
+
 
       if (rsdp_addr)
         return rsdp_addr;