Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsBoot.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsBoot.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsBoot.c	(revision 29125)
@@ -0,0 +1,2154 @@
+/* $Id$ */
+/** @file
+ * BdsBoot.c
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+BDS Lib functions which relate with create or process the boot option.
+
+Copyright (c) 2004 - 2009, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "InternalBdsLib.h"
+
+BOOLEAN mEnumBootDevice = FALSE;
+
+///
+/// This GUID is used for an EFI Variable that stores the front device pathes
+/// for a partial device path that starts with the HD node.
+///
+EFI_GUID  mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
+
+
+
+/**
+  Boot the legacy system with the boot option
+
+  @param  Option                 The legacy boot option which have BBS device path
+
+  @retval EFI_UNSUPPORTED        There is no legacybios protocol, do not support
+                                 legacy boot.
+  @retval EFI_STATUS             Return the status of LegacyBios->LegacyBoot ().
+
+**/
+EFI_STATUS
+BdsLibDoLegacyBoot (
+  IN  BDS_COMMON_OPTION           *Option
+  )
+{
+  EFI_STATUS                Status;
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    //
+    // If no LegacyBios protocol we do not support legacy boot
+    //
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Notes: if we separate the int 19, then we don't need to refresh BBS
+  //
+  BdsRefreshBbsTableForBoot (Option);
+
+  //
+  // Write boot to OS performance data for legacy boot.
+  //
+  PERF_CODE (
+    WriteBootToOsPerformanceData ();
+  );
+
+  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
+  return LegacyBios->LegacyBoot (
+                      LegacyBios,
+                      (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
+                      Option->LoadOptionsSize,
+                      Option->LoadOptions
+                      );
+}
+
+/**
+  Internal function to check if the input boot option is a valid EFI NV Boot####.
+
+  @param OptionToCheck  Boot option to be checked.
+
+  @retval TRUE      This boot option matches a valid EFI NV Boot####.
+  @retval FALSE     If not.
+
+**/
+BOOLEAN
+IsBootOptionValidNVVarialbe (
+  IN  BDS_COMMON_OPTION             *OptionToCheck
+  )
+{
+  LIST_ENTRY        TempList;
+  BDS_COMMON_OPTION *BootOption;
+  BOOLEAN           Valid;
+  CHAR16            OptionName[20];
+
+  Valid = FALSE;
+
+  InitializeListHead (&TempList);
+  UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
+
+  BootOption = BdsLibVariableToOption (&TempList, OptionName);
+  if (BootOption == NULL) {
+    return FALSE;
+  }
+
+  //
+  // If the Boot Option Number and Device Path matches, OptionToCheck matches a
+  // valid EFI NV Boot####.
+  //
+  if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
+      (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
+      {
+    Valid = TRUE;
+  }
+
+  FreePool (BootOption);
+
+  return Valid;
+}
+/**
+  Process the boot option follow the UEFI specification and
+  special treat the legacy boot option with BBS_DEVICE_PATH.
+
+  @param  Option                 The boot option need to be processed
+  @param  DevicePath             The device path which describe where to load the
+                                 boot image or the legacy BBS device path to boot
+                                 the legacy OS
+  @param  ExitDataSize           The size of exit data.
+  @param  ExitData               Data returned when Boot image failed.
+
+  @retval EFI_SUCCESS            Boot from the input boot option successfully.
+  @retval EFI_NOT_FOUND          If the Device Path is not found in the system
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBootViaBootOption (
+  IN  BDS_COMMON_OPTION             *Option,
+  IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
+  OUT UINTN                         *ExitDataSize,
+  OUT CHAR16                        **ExitData OPTIONAL
+  )
+{
+  EFI_STATUS                Status;
+  EFI_HANDLE                Handle;
+  EFI_HANDLE                ImageHandle;
+  EFI_DEVICE_PATH_PROTOCOL  *FilePath;
+  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+  EFI_DEVICE_PATH_PROTOCOL  *WorkingDevicePath;
+  EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
+  LIST_ENTRY                TempBootLists;
+  EFI_SECURITY_ARCH_PROTOCOL *SecurityProtocol;
+  CHAR16                    *NewFileName;
+  static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToTxt;
+
+  //
+  // Record the performance data for End of BDS
+  //
+  PERF_END(NULL, "BDS", NULL, 0);
+
+  *ExitDataSize = 0;
+  *ExitData     = NULL;
+
+  //
+  // Notes: put EFI64 ROM Shadow Solution
+  //
+  EFI64_SHADOW_ALL_LEGACY_ROM ();
+
+  //
+  // Notes: this code can be remove after the s3 script table
+  // hook on the event EVT_SIGNAL_READY_TO_BOOT or
+  // EVT_SIGNAL_LEGACY_BOOT
+  //
+  Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
+  if (!EFI_ERROR (Status)) {
+    AcpiS3Save->S3Save (AcpiS3Save, NULL);
+  }
+  //
+  // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
+  // full device path
+  //
+  WorkingDevicePath = NULL;
+  if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+      (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
+    WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
+                          (HARDDRIVE_DEVICE_PATH *)DevicePath
+                          );
+    if (WorkingDevicePath != NULL) {
+      DevicePath = WorkingDevicePath;
+    }
+  }
+  //
+  // Signal the EVT_SIGNAL_READY_TO_BOOT event
+  //
+  EfiSignalEventReadyToBoot();
+
+
+  //
+  // Set Boot Current
+  //
+  if (IsBootOptionValidNVVarialbe (Option)) {
+    //
+    // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
+    // In this case, "BootCurrent" is not created.
+    // Only create the BootCurrent variable when it points to a valid Boot#### variable.
+    //
+    DEBUG((DEBUG_INFO, "Boot: Current\n"));
+    gRT->SetVariable (
+          L"BootCurrent",
+          &gEfiGlobalVariableGuid,
+          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+          sizeof (UINT16),
+          &Option->BootCurrent
+          );
+  }
+
+  ASSERT (Option->DevicePath != NULL);
+  if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
+      (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
+    ) {
+    //
+    // Check to see if we should legacy BOOT. If yes then do the legacy boot
+    //
+    return BdsLibDoLegacyBoot (Option);
+  }
+
+  //
+  // If the boot option point to Internal FV shell, make sure it is valid
+  //
+  Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));
+  if (!EFI_ERROR(Status)) {
+    if (Option->DevicePath != NULL) {
+      FreePool(Option->DevicePath);
+    }
+    Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));
+    ASSERT(Option->DevicePath != NULL);
+    CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+    //
+    // Update the shell boot option
+    //
+    InitializeListHead (&TempBootLists);
+    BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
+
+    //
+    // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
+    //
+    FreePool (DevicePath);
+    DevicePath = Option->DevicePath;
+  }
+
+  //
+  // Measure GPT Table by SAP protocol.
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiSecurityArchProtocolGuid,
+                  NULL,
+                  (VOID**) &SecurityProtocol
+                  );
+  if (!EFI_ERROR (Status)) {
+    Status = SecurityProtocol->FileAuthenticationState (SecurityProtocol, 0, DevicePath);
+  }
+
+  DEBUG_CODE_BEGIN();
+    UINTN                     DevicePathTypeValue;
+    CHAR16                    *HiiString;
+    CHAR16                    *BootStringNumber;
+    UINTN                     BufferSize;
+
+    DevicePathTypeValue = BdsGetBootTypeFromDevicePath (Option->DevicePath);
+
+    //
+    // store number string of boot option temporary.
+    //
+    HiiString = NULL;
+    switch (DevicePathTypeValue) {
+    case BDS_EFI_ACPI_FLOPPY_BOOT:
+      HiiString = L"EFI Floppy";
+      break;
+    case BDS_EFI_MEDIA_CDROM_BOOT:
+    case BDS_EFI_MESSAGE_SATA_BOOT:
+    case BDS_EFI_MESSAGE_ATAPI_BOOT:
+      HiiString = L"EFI DVD/CDROM";
+      break;
+    case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
+      HiiString = L"EFI USB Device";
+      break;
+    case BDS_EFI_MESSAGE_SCSI_BOOT:
+      HiiString = L"EFI SCSI Device";
+      break;
+    case BDS_EFI_MESSAGE_MISC_BOOT:
+      HiiString = L"EFI Misc Device";
+      break;
+    case BDS_EFI_MESSAGE_MAC_BOOT:
+      HiiString = L"EFI Network";
+      break;
+    case BBS_DEVICE_PATH:
+      //
+      // Do nothing for legacy boot option.
+      //
+      break;
+    default:
+      DEBUG((EFI_D_INFO, "Can not find HiiString for given device path type 0x%x\n", DevicePathTypeValue));
+    }
+
+    //
+    // If found Hii description string then cat Hii string with original description.
+    //
+    if (HiiString != NULL) {
+      BootStringNumber = Option->Description;
+      BufferSize = StrSize(BootStringNumber);
+      BufferSize += StrSize(HiiString);
+      Option->Description = AllocateZeroPool(BufferSize);
+      StrCpy (Option->Description, HiiString);
+      if (StrnCmp (BootStringNumber, L"0", 1) != 0) {
+        StrCat (Option->Description, L" ");
+        StrCat (Option->Description, BootStringNumber);
+      }
+
+      FreePool (BootStringNumber);
+    }
+
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
+
+  DEBUG_CODE_END();
+  if (DevPathToTxt == NULL)
+  {
+    Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevPathToTxt);
+    ASSERT((!EFI_ERROR(Status)));
+  }
+
+  Status = gBS->LoadImage (
+                  TRUE,
+                  mBdsImageHandle,
+                  DevicePath,
+                  NULL,
+                  0,
+                  &ImageHandle
+                  );
+
+  DEBUG((DEBUG_INFO, "%a:%d LoadingImage '%s' - %r\n", __FILE__, __LINE__, DevPathToTxt->ConvertDevicePathToText(DevicePath, TRUE, FALSE), Status));
+  //
+  // If we didn't find an image directly, we need to try as if it is a removable device boot opotion
+  // and load the image according to the default boot behavior for removable device.
+  //
+  if (EFI_ERROR (Status)) {
+    //
+    // check if there is a bootable removable media could be found in this device path ,
+    // and get the bootable media handle
+    //
+    Handle = BdsLibGetBootableHandle(DevicePath, &NewFileName);
+    if (Handle == NULL) {
+       goto Done;
+    }
+    //
+    // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+    //  machinename is ia32, ia64, x64, ...
+    //
+    FilePath = FileDevicePath (Handle, NewFileName);
+    if (FilePath != NULL) {
+      DEBUG((DEBUG_INFO, "%a:%d LoadingImage FilePath:'%s'\n", __FILE__, __LINE__, DevPathToTxt->ConvertDevicePathToText(FilePath, TRUE, FALSE)));
+      Status = gBS->LoadImage (
+                      TRUE,
+                      mBdsImageHandle,
+                      FilePath,
+                      NULL,
+                      0,
+                      &ImageHandle
+                      );
+      if (EFI_ERROR (Status)) {
+        //
+        // The DevicePath failed, and it's not a valid
+        // removable media device.
+        //
+        goto Done;
+      }
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    //
+    // It there is any error from the Boot attempt exit now.
+    //
+    goto Done;
+  }
+  //
+  // Provide the image with it's load options
+  //
+  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  if (Option->LoadOptionsSize != 0) {
+    ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;
+    ImageInfo->LoadOptions      = Option->LoadOptions;
+  }
+  //
+  // Before calling the image, enable the Watchdog Timer for
+  // the 5 Minute period
+  //
+#ifndef VBOX
+  /* Some special guests don't return here */
+  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+#endif
+
+  //
+  // Write boot to OS performance data for UEFI boot
+  //
+  PERF_CODE (
+    WriteBootToOsPerformanceData ();
+  );
+
+  Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
+  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
+
+  //
+  // Clear the Watchdog Timer after the image returns
+  //
+#ifndef VBOX
+  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+#endif
+
+Done:
+  //
+  // Clear Boot Current
+  //
+  gRT->SetVariable (
+        L"BootCurrent",
+        &gEfiGlobalVariableGuid,
+        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+        0,
+        &Option->BootCurrent
+        );
+
+  return Status;
+}
+
+
+/**
+  Expand a device path that starts with a hard drive media device path node to be a
+  full device path that includes the full hardware path to the device. We need
+  to do this so it can be booted. As an optimization the front match (the part point
+  to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
+  so a connect all is not required on every boot. All successful history device path
+  which point to partition node (the front part) will be saved.
+
+  @param  HardDriveDevicePath    EFI Device Path to boot, if it starts with a hard
+                                 drive media device path.
+  @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
+          cannot be found.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsExpandPartitionPartialDevicePathToFull (
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     BlockIoHandleCount;
+  EFI_HANDLE                *BlockIoBuffer;
+  EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  UINTN                     Index;
+  UINTN                     InstanceNum;
+  EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
+  UINTN                     CachedDevicePathSize;
+  BOOLEAN                   DeviceExist;
+  BOOLEAN                   NeedAdjust;
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;
+  UINTN                     Size;
+
+  FullDevicePath = NULL;
+  //
+  // Check if there is prestore 'HDDP' variable.
+  // If exist, search the front path which point to partition node in the variable instants.
+  // If fail to find or 'HDDP' not exist, reconnect all and search in all system
+  //
+  CachedDevicePath = BdsLibGetVariableAndSize (
+                      L"HDDP",
+                      &mHdBootVariablePrivateGuid,
+                      &CachedDevicePathSize
+                      );
+
+  if (CachedDevicePath != NULL) {
+    TempNewDevicePath = CachedDevicePath;
+    DeviceExist = FALSE;
+    NeedAdjust = FALSE;
+    do {
+      //
+      // Check every instance of the variable
+      // First, check whether the instance contain the partition node, which is needed for distinguishing  multi
+      // partial partition boot option. Second, check whether the instance could be connected.
+      //
+      Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
+      if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
+        //
+        // Connect the device path instance, the device path point to hard drive media device path node
+        // e.g. ACPI() /PCI()/ATA()/Partition()
+        //
+        Status = BdsLibConnectDevicePath (Instance);
+        if (!EFI_ERROR (Status)) {
+          DeviceExist = TRUE;
+          break;
+        }
+      }
+      //
+      // Come here means the first instance is not matched
+      //
+      NeedAdjust = TRUE;
+      FreePool(Instance);
+    } while (TempNewDevicePath != NULL);
+
+    if (DeviceExist) {
+      //
+      // Find the matched device path.
+      // Append the file path information from the boot option and return the fully expanded device path.
+      //
+      DevicePath     = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
+      FullDevicePath = AppendDevicePath (Instance, DevicePath);
+
+      //
+      // Adjust the 'HDDP' instances sequence if the matched one is not first one.
+      //
+      if (NeedAdjust) {
+        //
+        // First delete the matched instance.
+        //
+        TempNewDevicePath = CachedDevicePath;
+        CachedDevicePath  = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
+        FreePool (TempNewDevicePath);
+
+        //
+        // Second, append the remaining path after the matched instance
+        //
+        TempNewDevicePath = CachedDevicePath;
+        CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
+        FreePool (TempNewDevicePath);
+        //
+        // Save the matching Device Path so we don't need to do a connect all next time
+        //
+        Status = gRT->SetVariable (
+                        L"HDDP",
+                        &mHdBootVariablePrivateGuid,
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                        GetDevicePathSize (CachedDevicePath),
+                        CachedDevicePath
+                        );
+      }
+
+      FreePool (Instance);
+      FreePool (CachedDevicePath);
+      return FullDevicePath;
+    }
+  }
+
+  //
+  // If we get here we fail to find or 'HDDP' not exist, and now we need
+  // to search all devices in the system for a matched partition
+  //
+  BdsLibConnectAllDriversToAllControllers ();
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
+  if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
+    //
+    // If there was an error or there are no device handles that support
+    // the BLOCK_IO Protocol, then return.
+    //
+    return NULL;
+  }
+  //
+  // Loop through all the device handles that support the BLOCK_IO Protocol
+  //
+  for (Index = 0; Index < BlockIoHandleCount; Index++) {
+
+    Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
+    if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
+      continue;
+    }
+
+    if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
+      //
+      // Find the matched partition device path
+      //
+      DevicePath    = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
+      FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
+
+      //
+      // Save the matched partition device path in 'HDDP' variable
+      //
+      if (CachedDevicePath != NULL) {
+        //
+        // Save the matched partition device path as first instance of 'HDDP' variable
+        //
+        if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
+          TempNewDevicePath = CachedDevicePath;
+          CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
+          FreePool(TempNewDevicePath);
+
+          TempNewDevicePath = CachedDevicePath;
+          CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
+          FreePool(TempNewDevicePath);
+        } else {
+          TempNewDevicePath = CachedDevicePath;
+          CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
+          FreePool(TempNewDevicePath);
+        }
+        //
+        // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
+        // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
+        //
+        InstanceNum = 0;
+        ASSERT (CachedDevicePath != NULL);
+        TempNewDevicePath = CachedDevicePath;
+        while (!IsDevicePathEnd (TempNewDevicePath)) {
+          TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+          //
+          // Parse one instance
+          //
+          while (!IsDevicePathEndType (TempNewDevicePath)) {
+            TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+          }
+          InstanceNum++;
+          //
+          // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
+          //
+          if (InstanceNum >= 12) {
+            SetDevicePathEndNode (TempNewDevicePath);
+            break;
+          }
+        }
+      } else {
+        CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+      }
+
+      //
+      // Save the matching Device Path so we don't need to do a connect all next time
+      //
+      Status = gRT->SetVariable (
+                      L"HDDP",
+                      &mHdBootVariablePrivateGuid,
+                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                      GetDevicePathSize (CachedDevicePath),
+                      CachedDevicePath
+                      );
+
+      break;
+    }
+  }
+
+  FreePool (CachedDevicePath);
+  if (BlockIoBuffer != NULL) {
+    FreePool (BlockIoBuffer);
+  }
+  return FullDevicePath;
+}
+
+/**
+  Check whether there is a instance in BlockIoDevicePath, which contain multi device path
+  instances, has the same partition node with HardDriveDevicePath device path
+
+  @param  BlockIoDevicePath      Multi device path instances which need to check
+  @param  HardDriveDevicePath    A device path which starts with a hard drive media
+                                 device path.
+
+  @retval TRUE                   There is a matched device path instance.
+  @retval FALSE                  There is no matched device path instance.
+
+**/
+BOOLEAN
+EFIAPI
+MatchPartitionDevicePathNode (
+  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
+  )
+{
+  HARDDRIVE_DEVICE_PATH     *TmpHdPath;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  BOOLEAN                   Match;
+  EFI_DEVICE_PATH_PROTOCOL  *BlockIoHdDevicePathNode;
+
+  if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+    return FALSE;
+  }
+
+  //
+  // Make PreviousDevicePath == the device path node before the end node
+  //
+  DevicePath              = BlockIoDevicePath;
+  BlockIoHdDevicePathNode = NULL;
+
+  //
+  // find the partition device path node
+  //
+  while (!IsDevicePathEnd (DevicePath)) {
+    if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+        (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
+        ) {
+      BlockIoHdDevicePathNode = DevicePath;
+      break;
+    }
+
+    DevicePath = NextDevicePathNode (DevicePath);
+  }
+
+  if (BlockIoHdDevicePathNode == NULL) {
+    return FALSE;
+  }
+  //
+  // See if the harddrive device path in blockio matches the orig Hard Drive Node
+  //
+  TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
+  Match = FALSE;
+
+  //
+  // Check for the match
+  //
+  if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
+      (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
+    switch (TmpHdPath->SignatureType) {
+    case SIGNATURE_TYPE_GUID:
+      Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
+      break;
+    case SIGNATURE_TYPE_MBR:
+      Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
+      break;
+    default:
+      Match = FALSE;
+      break;
+    }
+  }
+
+  return Match;
+}
+
+/**
+  Delete the boot option associated with the handle passed in.
+
+  @param  Handle                 The handle which present the device path to create
+                                 boot option
+
+  @retval EFI_SUCCESS            Delete the boot option success
+  @retval EFI_NOT_FOUND          If the Device Path is not found in the system
+  @retval EFI_OUT_OF_RESOURCES   Lack of memory resource
+  @retval Other                  Error return value from SetVariable()
+
+**/
+EFI_STATUS
+BdsLibDeleteOptionFromHandle (
+  IN  EFI_HANDLE                 Handle
+  )
+{
+  UINT16                    *BootOrder;
+  UINT8                     *BootOptionVar;
+  UINTN                     BootOrderSize;
+  UINTN                     BootOptionSize;
+  EFI_STATUS                Status;
+  UINTN                     Index;
+  UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];
+  UINTN                     DevicePathSize;
+  UINTN                     OptionDevicePathSize;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
+  UINT8                     *TempPtr;
+
+  Status        = EFI_SUCCESS;
+  BootOrder     = NULL;
+  BootOrderSize = 0;
+
+  //
+  // Check "BootOrder" variable, if no, means there is no any boot order.
+  //
+  BootOrder = BdsLibGetVariableAndSize (
+                L"BootOrder",
+                &gEfiGlobalVariableGuid,
+                &BootOrderSize
+                );
+  if (BootOrder == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Convert device handle to device path protocol instance
+  //
+  DevicePath = DevicePathFromHandle (Handle);
+  if (DevicePath == NULL) {
+    return EFI_NOT_FOUND;
+  }
+  DevicePathSize = GetDevicePathSize (DevicePath);
+
+  //
+  // Loop all boot order variable and find the matching device path
+  //
+  Index = 0;
+  while (Index < BootOrderSize / sizeof (UINT16)) {
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+    BootOptionVar = BdsLibGetVariableAndSize (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      &BootOptionSize
+                      );
+
+    if (BootOptionVar == NULL) {
+      FreePool (BootOrder);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    TempPtr = BootOptionVar;
+    TempPtr += sizeof (UINT32) + sizeof (UINT16);
+    TempPtr += StrSize ((CHAR16 *) TempPtr);
+    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+    OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
+
+    //
+    // Check whether the device path match
+    //
+    if ((OptionDevicePathSize == DevicePathSize) &&
+        (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
+      BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
+      FreePool (BootOptionVar);
+      break;
+    }
+
+    FreePool (BootOptionVar);
+    Index++;
+  }
+
+  //
+  // Adjust number of boot option for "BootOrder" variable.
+  //
+  Status = gRT->SetVariable (
+                  L"BootOrder",
+                  &gEfiGlobalVariableGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                  BootOrderSize,
+                  BootOrder
+                  );
+
+  FreePool (BootOrder);
+
+  return Status;
+}
+
+
+/**
+  Delete all invalid EFI boot options.
+
+  @retval EFI_SUCCESS            Delete all invalid boot option success
+  @retval EFI_NOT_FOUND          Variable "BootOrder" is not found
+  @retval EFI_OUT_OF_RESOURCES   Lack of memory resource
+  @retval Other                  Error return value from SetVariable()
+
+**/
+EFI_STATUS
+BdsDeleteAllInvalidEfiBootOption (
+  VOID
+  )
+{
+  UINT16                    *BootOrder;
+  UINT8                     *BootOptionVar;
+  UINTN                     BootOrderSize;
+  UINTN                     BootOptionSize;
+  EFI_STATUS                Status;
+  UINTN                     Index;
+  UINTN                     Index2;
+  UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];
+  EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
+  UINT8                     *TempPtr;
+  CHAR16                    *Description;
+
+  Status        = EFI_SUCCESS;
+  BootOrder     = NULL;
+  BootOrderSize = 0;
+
+  //
+  // Check "BootOrder" variable firstly, this variable hold the number of boot options
+  //
+  BootOrder = BdsLibGetVariableAndSize (
+                L"BootOrder",
+                &gEfiGlobalVariableGuid,
+                &BootOrderSize
+                );
+  if (NULL == BootOrder) {
+    return EFI_NOT_FOUND;
+  }
+
+  Index = 0;
+  while (Index < BootOrderSize / sizeof (UINT16)) {
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+    BootOptionVar = BdsLibGetVariableAndSize (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      &BootOptionSize
+                      );
+    if (NULL == BootOptionVar) {
+      FreePool (BootOrder);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    TempPtr = BootOptionVar;
+    TempPtr += sizeof (UINT32) + sizeof (UINT16);
+    Description = (CHAR16 *) TempPtr;
+    TempPtr += StrSize ((CHAR16 *) TempPtr);
+    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+
+    //
+    // Skip legacy boot option (BBS boot device)
+    //
+    if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
+        (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
+      FreePool (BootOptionVar);
+      Index++;
+      continue;
+    }
+
+    if (!BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
+      //
+      // Delete this invalid boot option "Boot####"
+      //
+      Status = gRT->SetVariable (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                      0,
+                      NULL
+                      );
+      //
+      // Mark this boot option in boot order as deleted
+      //
+      BootOrder[Index] = 0xffff;
+    }
+
+    FreePool (BootOptionVar);
+    Index++;
+  }
+
+  //
+  // Adjust boot order array
+  //
+  Index2 = 0;
+  for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+    if (BootOrder[Index] != 0xffff) {
+      BootOrder[Index2] = BootOrder[Index];
+      Index2 ++;
+    }
+  }
+  Status = gRT->SetVariable (
+                  L"BootOrder",
+                  &gEfiGlobalVariableGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                  Index2 * sizeof (UINT16),
+                  BootOrder
+                  );
+
+  FreePool (BootOrder);
+
+  return Status;
+}
+
+
+/**
+  For EFI boot option, BDS separate them as six types:
+  1. Network - The boot option points to the SimpleNetworkProtocol device.
+               Bds will try to automatically create this type boot option when enumerate.
+  2. Shell   - The boot option points to internal flash shell.
+               Bds will try to automatically create this type boot option when enumerate.
+  3. Removable BlockIo      - The boot option only points to the removable media
+                              device, like USB flash disk, DVD, Floppy etc.
+                              These device should contain a *removable* blockIo
+                              protocol in their device handle.
+                              Bds will try to automatically create this type boot option
+                              when enumerate.
+  4. Fixed BlockIo          - The boot option only points to a Fixed blockIo device,
+                              like HardDisk.
+                              These device should contain a *fixed* blockIo
+                              protocol in their device handle.
+                              BDS will skip fixed blockIo devices, and NOT
+                              automatically create boot option for them. But BDS
+                              will help to delete those fixed blockIo boot option,
+                              whose description rule conflict with other auto-created
+                              boot options.
+  5. Non-BlockIo Simplefile - The boot option points to a device whose handle
+                              has SimpleFileSystem Protocol, but has no blockio
+                              protocol. These devices do not offer blockIo
+                              protocol, but BDS still can get the
+                              \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
+                              Protocol.
+  6. File    - The boot option points to a file. These boot options are usually
+               created by user manually or OS loader. BDS will not delete or modify
+               these boot options.
+
+  This function will enumerate all possible boot device in the system, and
+  automatically create boot options for Network, Shell, Removable BlockIo,
+  and Non-BlockIo Simplefile devices.
+  It will only execute once of every boot.
+
+  @param  BdsBootOptionList      The header of the link list which indexed all
+                                 current boot options
+
+  @retval EFI_SUCCESS            Finished all the boot device enumerate and create
+                                 the boot option base on that boot device
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to enumerate the boot device and create the boot option list
+**/
+EFI_STATUS
+EFIAPI
+BdsLibEnumerateAllBootOption (
+  IN OUT LIST_ENTRY          *BdsBootOptionList
+  )
+{
+  EFI_STATUS                    Status;
+  UINT16                        FloppyNumber;
+  UINT16                        CdromNumber;
+  UINT16                        UsbNumber;
+  UINT16                        MiscNumber;
+  UINT16                        ScsiNumber;
+  UINT16                        NonBlockNumber;
+  UINTN                         NumberBlockIoHandles;
+  EFI_HANDLE                    *BlockIoHandles;
+  EFI_BLOCK_IO_PROTOCOL         *BlkIo;
+  UINTN                         Index;
+  UINTN                         NumberSimpleNetworkHandles;
+  EFI_HANDLE                    *SimpleNetworkHandles;
+  UINTN                         FvHandleCount;
+  EFI_HANDLE                    *FvHandleBuffer;
+  EFI_FV_FILETYPE               Type;
+  UINTN                         Size;
+  EFI_FV_FILE_ATTRIBUTES        Attributes;
+  UINT32                        AuthenticationStatus;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+  EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
+  UINTN                         DevicePathType;
+  CHAR16                        Buffer[40];
+  EFI_HANDLE                    *FileSystemHandles;
+  UINTN                         NumberFileSystemHandles;
+  BOOLEAN                       NeedDelete;
+  EFI_IMAGE_DOS_HEADER          DosHeader;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
+  CHAR16 *NewFileName;
+
+  FloppyNumber  = 0;
+  CdromNumber   = 0;
+  UsbNumber     = 0;
+  MiscNumber    = 0;
+  ScsiNumber    = 0;
+  ZeroMem (Buffer, sizeof (Buffer));
+
+  //
+  // If the boot device enumerate happened, just get the boot
+  // device from the boot order variable
+  //
+  if (mEnumBootDevice) {
+    Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
+    return Status;
+  }
+
+  //
+  // Notes: this dirty code is to get the legacy boot option from the
+  // BBS table and create to variable as the EFI boot option, it should
+  // be removed after the CSM can provide legacy boot option directly
+  //
+  REFRESH_LEGACY_BOOT_OPTIONS;
+
+  //
+  // Delete invalid boot option
+  //
+  BdsDeleteAllInvalidEfiBootOption ();
+
+  //
+  // Parse removable media
+  //
+  gBS->LocateHandleBuffer (
+        ByProtocol,
+        &gEfiBlockIoProtocolGuid,
+        NULL,
+        &NumberBlockIoHandles,
+        &BlockIoHandles
+        );
+
+  for (Index = 0; Index < NumberBlockIoHandles; Index++) {
+    Status = gBS->HandleProtocol (
+                    BlockIoHandles[Index],
+                    &gEfiBlockIoProtocolGuid,
+                    (VOID **) &BlkIo
+                    );
+    if (!EFI_ERROR (Status)) {
+    /* VBOX: For some guests we need to add non-movable devices as boot
+     *  options automatically.
+     */
+#ifndef VBOX
+      if (!BlkIo->Media->RemovableMedia) {
+        //
+        // skip the non-removable block devices
+        //
+        continue;
+      }
+#endif
+    }
+    DevicePath  = DevicePathFromHandle (BlockIoHandles[Index]);
+    DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
+
+    switch (DevicePathType) {
+    case BDS_EFI_ACPI_FLOPPY_BOOT:
+      UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", FloppyNumber);
+      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+      FloppyNumber++;
+      break;
+
+    //
+    // Assume a removable SATA device should be the DVD/CD device
+    //
+    case BDS_EFI_MESSAGE_ATAPI_BOOT:
+    case BDS_EFI_MESSAGE_SATA_BOOT:
+      UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", CdromNumber);
+      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+      CdromNumber++;
+      break;
+
+    case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
+      UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", UsbNumber);
+      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+      UsbNumber++;
+      break;
+
+    case BDS_EFI_MESSAGE_SCSI_BOOT:
+      UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", ScsiNumber);
+      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+      ScsiNumber++;
+      break;
+
+    case BDS_EFI_MEDIA_HD_BOOT:
+    case BDS_EFI_MESSAGE_MISC_BOOT:
+      UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", MiscNumber);
+      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+      MiscNumber++;
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  if (NumberBlockIoHandles != 0) {
+    FreePool (BlockIoHandles);
+  }
+
+  //
+  // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
+  //
+  NonBlockNumber = 0;
+  gBS->LocateHandleBuffer (
+        ByProtocol,
+        &gEfiSimpleFileSystemProtocolGuid,
+        NULL,
+        &NumberFileSystemHandles,
+        &FileSystemHandles
+        );
+  for (Index = 0; Index < NumberFileSystemHandles; Index++) {
+    Status = gBS->HandleProtocol (
+                    FileSystemHandles[Index],
+                    &gEfiBlockIoProtocolGuid,
+                    (VOID **) &BlkIo
+                    );
+     if (!EFI_ERROR (Status)) {
+      //
+      //  Skip if the file system handle supports a BlkIo protocol,
+      //
+      continue;
+    }
+
+    //
+    // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
+    //  machinename is ia32, ia64, x64, ...
+    //
+    Hdr.Union = &HdrData;
+    NeedDelete = TRUE;
+    Status     = BdsLibGetImageHeader (
+                   FileSystemHandles[Index],
+                   EFI_REMOVABLE_MEDIA_FILE_NAME,
+                   &DosHeader,
+                   Hdr,
+                   &NewFileName
+                   );
+    if (!EFI_ERROR (Status)
+#ifndef VBOX
+        && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+        Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
+#endif
+        ) {
+      NeedDelete = FALSE;
+    }
+      Status = BdsLibGetImageHeader (
+                 FileSystemHandles[Index],
+                 L"\\System\\Library\\CoreServices\\boot.efi",
+                 &DosHeader,
+                 Hdr,
+                 &NewFileName
+                 );
+      /* Here should be Mac Specific checks */
+      if (!EFI_ERROR (Status)) {
+            NeedDelete = FALSE;
+      }
+
+    if (NeedDelete) {
+      //
+      // No such file or the file is not a EFI application, delete this boot option
+      //
+      BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
+    } else {
+      UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber);
+      BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
+      NonBlockNumber++;
+    }
+  }
+
+  if (NumberFileSystemHandles != 0) {
+    FreePool (FileSystemHandles);
+  }
+
+  //
+  // Parse Network Boot Device
+  //
+  gBS->LocateHandleBuffer (
+        ByProtocol,
+        &gEfiSimpleNetworkProtocolGuid,
+        NULL,
+        &NumberSimpleNetworkHandles,
+        &SimpleNetworkHandles
+        );
+
+  for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) {
+    UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", Index);
+    BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer);
+  }
+
+  if (NumberSimpleNetworkHandles != 0) {
+    FreePool (SimpleNetworkHandles);
+  }
+
+  //
+  // Check if we have on flash shell
+  //
+  gBS->LocateHandleBuffer (
+        ByProtocol,
+        &gEfiFirmwareVolume2ProtocolGuid,
+        NULL,
+        &FvHandleCount,
+        &FvHandleBuffer
+        );
+  for (Index = 0; Index < FvHandleCount; Index++) {
+    gBS->HandleProtocol (
+          FvHandleBuffer[Index],
+          &gEfiFirmwareVolume2ProtocolGuid,
+          (VOID **) &Fv
+          );
+
+    Status = Fv->ReadFile (
+                  Fv,
+                  PcdGetPtr(PcdShellFile),
+                  NULL,
+                  &Size,
+                  &Type,
+                  &Attributes,
+                  &AuthenticationStatus
+                  );
+    if (EFI_ERROR (Status)) {
+      //
+      // Skip if no shell file in the FV
+      //
+      continue;
+    }
+    //
+    // Build the shell boot option
+    //
+    BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
+  }
+
+  if (FvHandleCount != 0) {
+    FreePool (FvHandleBuffer);
+  }
+  //
+  // Make sure every boot only have one time
+  // boot device enumerate
+  //
+  Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
+  mEnumBootDevice = TRUE;
+
+  return Status;
+}
+
+/**
+  Build the boot option with the handle parsed in
+
+  @param  Handle                 The handle which present the device path to create
+                                 boot option
+  @param  BdsBootOptionList      The header of the link list which indexed all
+                                 current boot options
+  @param  String                 The description of the boot option.
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromHandle (
+  IN  EFI_HANDLE                 Handle,
+  IN  LIST_ENTRY                 *BdsBootOptionList,
+  IN  CHAR16                     *String
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+
+  DevicePath = DevicePathFromHandle (Handle);
+
+  //
+  // Create and register new boot option
+  //
+  BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
+}
+
+
+/**
+  Build the on flash shell boot option with the handle parsed in.
+
+  @param  Handle                 The handle which present the device path to create
+                                 on flash shell boot option
+  @param  BdsBootOptionList      The header of the link list which indexed all
+                                 current boot options
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromShell (
+  IN EFI_HANDLE                  Handle,
+  IN OUT LIST_ENTRY              *BdsBootOptionList
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
+
+  DevicePath = DevicePathFromHandle (Handle);
+
+  //
+  // Build the shell device path
+  //
+  EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));
+
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
+
+  //
+  // Create and register the shell boot option
+  //
+  BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
+
+}
+
+/**
+  Boot from the UEFI spec defined "BootNext" variable.
+
+**/
+VOID
+EFIAPI
+BdsLibBootNext (
+  VOID
+  )
+{
+  UINT16            *BootNext;
+  UINTN             BootNextSize;
+  CHAR16            Buffer[20];
+  BDS_COMMON_OPTION *BootOption;
+  LIST_ENTRY        TempList;
+  UINTN             ExitDataSize;
+  CHAR16            *ExitData;
+
+  //
+  // Init the boot option name buffer and temp link list
+  //
+  InitializeListHead (&TempList);
+  ZeroMem (Buffer, sizeof (Buffer));
+
+  BootNext = BdsLibGetVariableAndSize (
+              L"BootNext",
+              &gEfiGlobalVariableGuid,
+              &BootNextSize
+              );
+
+  //
+  // Clear the boot next variable first
+  //
+  if (BootNext != NULL) {
+    gRT->SetVariable (
+          L"BootNext",
+          &gEfiGlobalVariableGuid,
+          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+          0,
+          BootNext
+          );
+
+    //
+    // Start to build the boot option and try to boot
+    //
+    UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
+    BootOption = BdsLibVariableToOption (&TempList, Buffer);
+    ASSERT (BootOption != NULL);
+    BdsLibConnectDevicePath (BootOption->DevicePath);
+    BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
+  }
+
+}
+
+/**
+  Return the bootable media handle.
+  First, check the device is connected
+  Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
+  Third, detect the the default boot file in the Media, and return the removable Media handle.
+
+  @param  DevicePath  Device Path to a  bootable device
+
+  @return  The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
+
+**/
+EFI_HANDLE
+EFIAPI
+BdsLibGetBootableHandle (
+  IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
+  IN OUT CHAR16 **NewFileName
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;
+  EFI_HANDLE                      Handle;
+  EFI_BLOCK_IO_PROTOCOL           *BlockIo;
+  VOID                            *Buffer;
+  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
+  UINTN                           Size;
+  UINTN                           TempSize;
+  EFI_HANDLE                      ReturnHandle;
+  EFI_HANDLE                      *SimpleFileSystemHandles;
+
+  UINTN                           NumberSimpleFileSystemHandles;
+  UINTN                           Index;
+  EFI_IMAGE_DOS_HEADER            DosHeader;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
+
+  UpdatedDevicePath = DevicePath;
+
+  //
+  // Check whether the device is connected
+  //
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
+  if (EFI_ERROR (Status)) {
+    //
+    // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
+    //
+    Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
+    if (EFI_ERROR (Status)) {
+      //
+      // Fail to find the proper BlockIo and simple file protocol, maybe because device not present,  we need to connect it firstly
+      //
+      UpdatedDevicePath = DevicePath;
+      Status            = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
+      gBS->ConnectController (Handle, NULL, NULL, TRUE);
+    }
+  } else {
+    //
+    // Get BlockIo protocol and check removable attribute
+    //
+    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+    //
+    // Issue a dummy read to the device to check for media change.
+    // When the removable media is changed, any Block IO read/write will
+    // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+    // returned. After the Block IO protocol is reinstalled, subsequent
+    // Block IO read/write will success.
+    //
+    Buffer = AllocatePool (BlockIo->Media->BlockSize);
+    if (Buffer != NULL) {
+      BlockIo->ReadBlocks (
+               BlockIo,
+               BlockIo->Media->MediaId,
+               0,
+               BlockIo->Media->BlockSize,
+               Buffer
+               );
+      FreePool(Buffer);
+    }
+  }
+
+  //
+  // Detect the the default boot file from removable Media
+  //
+
+  //
+  // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
+  // Try to locate the USB node device path first, if fail then use its previous PCI node to search
+  //
+  DupDevicePath = DuplicateDevicePath (DevicePath);
+  ASSERT (DupDevicePath != NULL);
+
+  UpdatedDevicePath = DupDevicePath;
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
+  //
+  // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
+  // Acpi()/Pci()/Usb() --> Acpi()/Pci()
+  //
+  if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
+      (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
+    //
+    // Remove the usb node, let the device path only point to PCI node
+    //
+    SetDevicePathEndNode (UpdatedDevicePath);
+    UpdatedDevicePath = DupDevicePath;
+  } else {
+    UpdatedDevicePath = DevicePath;
+  }
+
+  //
+  // Get the device path size of boot option
+  //
+  Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
+  ReturnHandle = NULL;
+  gBS->LocateHandleBuffer (
+      ByProtocol,
+      &gEfiSimpleFileSystemProtocolGuid,
+      NULL,
+      &NumberSimpleFileSystemHandles,
+      &SimpleFileSystemHandles
+      );
+  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+    //
+    // Get the device path size of SimpleFileSystem handle
+    //
+    TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+    TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
+    //
+    // Check whether the device path of boot option is part of the  SimpleFileSystem handle's device path
+    //
+    if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
+      //
+      // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+      //  machinename is ia32, ia64, x64, ...
+      //
+      Hdr.Union = &HdrData;
+      Status = BdsLibGetImageHeader (
+                 SimpleFileSystemHandles[Index],
+                 EFI_REMOVABLE_MEDIA_FILE_NAME,
+                 &DosHeader,
+                 Hdr,
+                 NewFileName
+                 );
+      if (!EFI_ERROR (Status)
+#ifndef VBOX
+        && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+        Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
+#endif
+      ) {
+        ReturnHandle = SimpleFileSystemHandles[Index];
+        break;
+      }
+      Status = BdsLibGetImageHeader (
+                 SimpleFileSystemHandles[Index],
+                 L"\\System\\Library\\CoreServices\\boot.efi",
+                 &DosHeader,
+                 Hdr,
+                 NewFileName
+                 );
+      /* Here should be Mac Specific checks */
+      if (!EFI_ERROR (Status)
+#ifndef VBOX
+        && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+        Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
+#endif
+        ) {
+        DEBUG((DEBUG_INFO, "%a:%d clear the timer \n", __FILE__, __LINE__));
+        ReturnHandle = SimpleFileSystemHandles[Index];
+        break;
+      }
+    }
+  }
+
+  FreePool(DupDevicePath);
+
+  if (SimpleFileSystemHandles != NULL) {
+    FreePool(SimpleFileSystemHandles);
+  }
+
+  return ReturnHandle;
+}
+
+/**
+  Check to see if the network cable is plugged in. If the DevicePath is not
+  connected it will be connected.
+
+  @param  DevicePath             Device Path to check
+
+  @retval TRUE                   DevicePath points to an Network that is connected
+  @retval FALSE                  DevicePath does not point to a bootable network
+
+**/
+BOOLEAN
+BdsLibNetworkBootWithMediaPresent (
+  IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;
+  EFI_HANDLE                      Handle;
+  EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;
+  BOOLEAN                         MediaPresent;
+
+  MediaPresent = FALSE;
+
+  UpdatedDevicePath = DevicePath;
+  Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
+  if (EFI_ERROR (Status)) {
+    //
+    // Device not present so see if we need to connect it
+    //
+    Status = BdsLibConnectDevicePath (DevicePath);
+    if (!EFI_ERROR (Status)) {
+      //
+      // This one should work after we did the connect
+      //
+      Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
+    }
+  }
+
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
+    if (!EFI_ERROR (Status)) {
+      if (Snp->Mode->MediaPresentSupported) {
+        if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
+          //
+          // In case some one else is using the SNP check to see if it's connected
+          //
+          MediaPresent = Snp->Mode->MediaPresent;
+        } else {
+          //
+          // No one is using SNP so we need to Start and Initialize so
+          // MediaPresent will be valid.
+          //
+          Status = Snp->Start (Snp);
+          if (!EFI_ERROR (Status)) {
+            Status = Snp->Initialize (Snp, 0, 0);
+            if (!EFI_ERROR (Status)) {
+              MediaPresent = Snp->Mode->MediaPresent;
+              Snp->Shutdown (Snp);
+            }
+            Snp->Stop (Snp);
+          }
+        }
+      } else {
+        MediaPresent = TRUE;
+      }
+    }
+  }
+
+  return MediaPresent;
+}
+
+/**
+  For a bootable Device path, return its boot type.
+
+  @param  DevicePath                      The bootable device Path to check
+
+  @retval BDS_EFI_MEDIA_HD_BOOT           If given device path contains MEDIA_DEVICE_PATH type device path node
+                                          which subtype is MEDIA_HARDDRIVE_DP
+  @retval BDS_EFI_MEDIA_CDROM_BOOT        If given device path contains MEDIA_DEVICE_PATH type device path node
+                                          which subtype is MEDIA_CDROM_DP
+  @retval BDS_EFI_ACPI_FLOPPY_BOOT        If given device path contains ACPI_DEVICE_PATH type device path node
+                                          which HID is floppy device.
+  @retval BDS_EFI_MESSAGE_ATAPI_BOOT      If given device path contains MESSAGING_DEVICE_PATH type device path node
+                                          and its last device path node's subtype is MSG_ATAPI_DP.
+  @retval BDS_EFI_MESSAGE_SCSI_BOOT       If given device path contains MESSAGING_DEVICE_PATH type device path node
+                                          and its last device path node's subtype is MSG_SCSI_DP.
+  @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+                                          and its last device path node's subtype is MSG_USB_DP.
+  @retval BDS_EFI_MESSAGE_MISC_BOOT       If the device path not contains any media device path node,  and
+                                          its last device path node point to a message device path node.
+  @retval BDS_LEGACY_BBS_BOOT             If given device path contains BBS_DEVICE_PATH type device path node.
+  @retval BDS_EFI_UNSUPPORT               An EFI Removable BlockIO device path not point to a media and message device,
+
+**/
+UINT32
+EFIAPI
+BdsGetBootTypeFromDevicePath (
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  )
+{
+  ACPI_HID_DEVICE_PATH          *Acpi;
+  EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;
+
+
+  if (NULL == DevicePath) {
+    return BDS_EFI_UNSUPPORT;
+  }
+
+  TempDevicePath = DevicePath;
+
+  while (!IsDevicePathEndType (TempDevicePath)) {
+    switch (DevicePathType (TempDevicePath)) {
+      case BBS_DEVICE_PATH:
+         return BDS_LEGACY_BBS_BOOT;
+      case MEDIA_DEVICE_PATH:
+        if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
+          return BDS_EFI_MEDIA_HD_BOOT;
+        } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
+          return BDS_EFI_MEDIA_CDROM_BOOT;
+        }
+        break;
+      case ACPI_DEVICE_PATH:
+        Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
+        if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
+          return BDS_EFI_ACPI_FLOPPY_BOOT;
+        }
+        break;
+      case MESSAGING_DEVICE_PATH:
+        //
+        // Get the last device path node
+        //
+        LastDeviceNode = NextDevicePathNode (TempDevicePath);
+        if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
+          //
+          // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
+          // skit it
+          //
+          LastDeviceNode = NextDevicePathNode (LastDeviceNode);
+        }
+        //
+        // if the device path not only point to driver device, it is not a messaging device path,
+        //
+        if (!IsDevicePathEndType (LastDeviceNode)) {
+          break;
+        }
+
+        if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) {
+          return BDS_EFI_MESSAGE_ATAPI_BOOT;
+        } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) {
+          return BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
+        } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) {
+          return BDS_EFI_MESSAGE_SCSI_BOOT;
+        } else if (DevicePathSubType(TempDevicePath) == MSG_SATA_DP) {
+          return BDS_EFI_MESSAGE_SATA_BOOT;
+        } else if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
+          return BDS_EFI_MESSAGE_MAC_BOOT;
+        }
+        return BDS_EFI_MESSAGE_MISC_BOOT;
+      default:
+        break;
+    }
+    TempDevicePath = NextDevicePathNode (TempDevicePath);
+  }
+
+  return BDS_EFI_UNSUPPORT;
+}
+
+/**
+  Check whether the Device path in a boot option point to a valid bootable device,
+  And if CheckMedia is true, check the device is ready to boot now.
+
+  @param  DevPath     the Device path in a boot option
+  @param  CheckMedia  if true, check the device is ready to boot now.
+
+  @retval TRUE        the Device path  is valid
+  @retval FALSE       the Device path  is invalid .
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,
+  IN BOOLEAN                      CheckMedia
+  )
+{
+  return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
+}
+
+/**
+  Check whether the Device path in a boot option point to a valid bootable device,
+  And if CheckMedia is true, check the device is ready to boot now.
+  If Description is not NULL and the device path point to a fixed BlockIo
+  device, check the description whether conflict with other auto-created
+  boot options.
+
+  @param  DevPath     the Device path in a boot option
+  @param  CheckMedia  if true, check the device is ready to boot now.
+  @param  Description the description in a boot option
+
+  @retval TRUE        the Device path  is valid
+  @retval FALSE       the Device path  is invalid .
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePathExt (
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,
+  IN BOOLEAN                      CheckMedia,
+  IN CHAR16                       *Description
+  )
+{
+  EFI_STATUS                Status;
+  EFI_HANDLE                Handle;
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *LastDeviceNode;
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;
+  CHAR16                    *NewFileName;
+
+  TempDevicePath = DevPath;
+  LastDeviceNode = DevPath;
+
+  //
+  // Check if it's a valid boot option for network boot device
+  // Only check if there is SimpleNetworkProtocol installed. If yes, that means
+  // there is the network card there.
+  //
+  Status = gBS->LocateDevicePath (
+                  &gEfiSimpleNetworkProtocolGuid,
+                  &TempDevicePath,
+                  &Handle
+                  );
+  if (EFI_ERROR (Status)) {
+    //
+    // Device not present so see if we need to connect it
+    //
+    TempDevicePath = DevPath;
+    BdsLibConnectDevicePath (TempDevicePath);
+    Status = gBS->LocateDevicePath (
+                    &gEfiSimpleNetworkProtocolGuid,
+                    &TempDevicePath,
+                    &Handle
+                    );
+  }
+
+  if (!EFI_ERROR (Status)) {
+    if (CheckMedia) {
+      //
+      // Test if it is ready to boot now
+      //
+      if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
+        return TRUE;
+      }
+    } else {
+      return TRUE;
+    }
+  }
+
+  //
+  // If the boot option point to a file, it is a valid EFI boot option,
+  // and assume it is ready to boot now
+  //
+  while (!IsDevicePathEnd (TempDevicePath)) {
+     LastDeviceNode = TempDevicePath;
+     TempDevicePath = NextDevicePathNode (TempDevicePath);
+  }
+  if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
+    (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
+    return TRUE;
+  }
+
+  //
+  // Check if it's a valid boot option for internal Shell
+  //
+  if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
+    //
+    // If the boot option point to Internal FV shell, make sure it is valid
+    //
+    TempDevicePath = DevPath;
+    Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, PcdGetPtr(PcdShellFile));
+    if (Status == EFI_ALREADY_STARTED) {
+      return TRUE;
+    } else {
+      if (Status == EFI_SUCCESS) {
+        FreePool (TempDevicePath);
+      }
+      return FALSE;
+    }
+  }
+
+  //
+  // If the boot option point to a blockIO device:
+  //    if it is a removable blockIo device, it is valid.
+  //    if it is a fixed blockIo device, check its description confliction.
+  //
+  TempDevicePath = DevPath;
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+  if (EFI_ERROR (Status)) {
+    //
+    // Device not present so see if we need to connect it
+    //
+    Status = BdsLibConnectDevicePath (DevPath);
+    if (!EFI_ERROR (Status)) {
+      //
+      // Try again to get the Block Io protocol after we did the connect
+      //
+      TempDevicePath = DevPath;
+      Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+    }
+  }
+
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+    if (!EFI_ERROR (Status)) {
+      if (CheckMedia) {
+        //
+        // Test if it is ready to boot now
+        //
+        if (BdsLibGetBootableHandle (DevPath, &NewFileName) != NULL) {
+          return TRUE;
+        }
+      } else {
+        return TRUE;
+      }
+    }
+  } else {
+    //
+    // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
+    //
+    Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
+    if (!EFI_ERROR (Status)) {
+      if (CheckMedia) {
+        //
+        // Test if it is ready to boot now
+        //
+        if (BdsLibGetBootableHandle (DevPath, &NewFileName) != NULL) {
+          return TRUE;
+        }
+      } else {
+        return TRUE;
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+
+/**
+  According to a file guild, check a Fv file device path is valid. If it is invalid,
+  try to return the valid device path.
+  FV address maybe changes for memory layout adjust from time to time, use this function
+  could promise the Fv file device path is right.
+
+  @param  DevicePath             on input, the Fv file device path need to check on
+                                 output, the updated valid Fv file device path
+  @param  FileGuid               the Fv file guild
+
+  @retval EFI_INVALID_PARAMETER  the input DevicePath or FileGuid is invalid
+                                 parameter
+  @retval EFI_UNSUPPORTED        the input DevicePath does not contain Fv file
+                                 guild at all
+  @retval EFI_ALREADY_STARTED    the input DevicePath has pointed to Fv file, it is
+                                 valid
+  @retval EFI_SUCCESS            has successfully updated the invalid DevicePath,
+                                 and return the updated device path in DevicePath
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateFvFileDevicePath (
+  IN  OUT EFI_DEVICE_PATH_PROTOCOL      ** DevicePath,
+  IN  EFI_GUID                          *FileGuid
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;
+  EFI_STATUS                    Status;
+  EFI_GUID                      *GuidPoint;
+  UINTN                         Index;
+  UINTN                         FvHandleCount;
+  EFI_HANDLE                    *FvHandleBuffer;
+  EFI_FV_FILETYPE               Type;
+  UINTN                         Size;
+  EFI_FV_FILE_ATTRIBUTES        Attributes;
+  UINT32                        AuthenticationStatus;
+  BOOLEAN                       FindFvFile;
+  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
+  EFI_HANDLE                    FoundFvHandle;
+  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
+
+  if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (FileGuid == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check whether the device path point to the default the input Fv file
+  //
+  TempDevicePath = *DevicePath;
+  LastDeviceNode = TempDevicePath;
+  while (!IsDevicePathEnd (TempDevicePath)) {
+     LastDeviceNode = TempDevicePath;
+     TempDevicePath = NextDevicePathNode (TempDevicePath);
+  }
+  GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
+                (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
+                );
+  if (GuidPoint == NULL) {
+    //
+    // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
+    //
+    return EFI_UNSUPPORTED;
+  }
+  if (!CompareGuid (GuidPoint, FileGuid)) {
+    //
+    // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
+    //
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check whether the input Fv file device path is valid
+  //
+  TempDevicePath = *DevicePath;
+  FoundFvHandle = NULL;
+  Status = gBS->LocateDevicePath (
+                  &gEfiFirmwareVolume2ProtocolGuid,
+                  &TempDevicePath,
+                  &FoundFvHandle
+                  );
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->HandleProtocol (
+                    FoundFvHandle,
+                    &gEfiFirmwareVolume2ProtocolGuid,
+                    (VOID **) &Fv
+                    );
+    if (!EFI_ERROR (Status)) {
+      //
+      // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
+      //
+      Status = Fv->ReadFile (
+                    Fv,
+                    FileGuid,
+                    NULL,
+                    &Size,
+                    &Type,
+                    &Attributes,
+                    &AuthenticationStatus
+                    );
+      if (!EFI_ERROR (Status)) {
+        return EFI_ALREADY_STARTED;
+      }
+    }
+  }
+
+  //
+  // Look for the input wanted FV file in current FV
+  // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
+  //
+  FindFvFile = FALSE;
+  FoundFvHandle = NULL;
+  Status = gBS->HandleProtocol (
+             mBdsImageHandle,
+             &gEfiLoadedImageProtocolGuid,
+             (VOID **) &LoadedImage
+             );
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->HandleProtocol (
+                    LoadedImage->DeviceHandle,
+                    &gEfiFirmwareVolume2ProtocolGuid,
+                    (VOID **) &Fv
+                    );
+    if (!EFI_ERROR (Status)) {
+      Status = Fv->ReadFile (
+                    Fv,
+                    FileGuid,
+                    NULL,
+                    &Size,
+                    &Type,
+                    &Attributes,
+                    &AuthenticationStatus
+                    );
+      if (!EFI_ERROR (Status)) {
+        FindFvFile = TRUE;
+        FoundFvHandle = LoadedImage->DeviceHandle;
+      }
+    }
+  }
+  //
+  // Second, if fail to find, try to enumerate all FV
+  //
+  if (!FindFvFile) {
+    FvHandleBuffer = NULL;
+    gBS->LocateHandleBuffer (
+          ByProtocol,
+          &gEfiFirmwareVolume2ProtocolGuid,
+          NULL,
+          &FvHandleCount,
+          &FvHandleBuffer
+          );
+    for (Index = 0; Index < FvHandleCount; Index++) {
+      gBS->HandleProtocol (
+            FvHandleBuffer[Index],
+            &gEfiFirmwareVolume2ProtocolGuid,
+            (VOID **) &Fv
+            );
+
+      Status = Fv->ReadFile (
+                    Fv,
+                    FileGuid,
+                    NULL,
+                    &Size,
+                    &Type,
+                    &Attributes,
+                    &AuthenticationStatus
+                    );
+      if (EFI_ERROR (Status)) {
+        //
+        // Skip if input Fv file not in the FV
+        //
+        continue;
+      }
+      FindFvFile = TRUE;
+      FoundFvHandle = FvHandleBuffer[Index];
+      break;
+    }
+
+    if (FvHandleBuffer != NULL) {
+      FreePool (FvHandleBuffer);
+    }
+  }
+
+  if (FindFvFile) {
+    //
+    // Build the shell device path
+    //
+    NewDevicePath = DevicePathFromHandle (FoundFvHandle);
+    EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+    NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+    *DevicePath = NewDevicePath;
+    return EFI_SUCCESS;
+  }
+  return EFI_NOT_FOUND;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsConnect.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsConnect.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsConnect.c	(revision 29125)
@@ -0,0 +1,445 @@
+/* $Id$ */
+/** @file
+ * BdsConnect.c - BDS Lib functions which relate with connect the device
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2004 - 2008, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "InternalBdsLib.h"
+#include <Protocol/DevicePathToText.h>
+
+/**
+  This function will connect all the system driver to controller
+  first, and then special connect the default console, this make
+  sure all the system controller available and the platform default
+  console connected.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAll (
+  VOID
+  )
+{
+  //
+  // Connect the platform console first
+  //
+  BdsLibConnectAllDefaultConsoles ();
+
+  //
+  // Generic way to connect all the drivers
+  //
+  BdsLibConnectAllDriversToAllControllers ();
+
+  //
+  // Here we have the assumption that we have already had
+  // platform default console
+  //
+  BdsLibConnectAllDefaultConsoles ();
+}
+
+
+/**
+  This function will connect all the system drivers to all controllers
+  first, and then connect all the console devices the system current
+  have. After this we should get all the device work and console available
+  if the system have console device.
+
+**/
+VOID
+BdsLibGenericConnectAll (
+  VOID
+  )
+{
+  //
+  // Most generic way to connect all the drivers
+  //
+  BdsLibConnectAllDriversToAllControllers ();
+  BdsLibConnectAllConsoles ();
+}
+
+
+/**
+  This function will create all handles associate with every device
+  path node. If the handle associate with one device path node can not
+  be created success, then still give one chance to do the dispatch,
+  which load the missing drivers if possible.
+
+  @param  DevicePathToConnect   The device path which will be connected, it can be
+                                a multi-instance device path
+
+  @retval EFI_SUCCESS           All handles associate with every device path  node
+                                have been created
+  @retval EFI_OUT_OF_RESOURCES  There is no resource to create new handles
+  @retval EFI_NOT_FOUND         Create the handle associate with one device  path
+                                node failed
+
+**/
+static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToTxt;
+
+EFI_STATUS
+EFIAPI
+BdsLibConnectDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;
+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *Next;
+  EFI_HANDLE                Handle;
+  EFI_HANDLE                PreviousHandle;
+  UINTN                     Size;
+
+  if (DevPathToTxt == NULL)
+  {
+    Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevPathToTxt);
+    ASSERT((!EFI_ERROR(Status)));
+  }
+  if (DevicePathToConnect == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG((DEBUG_INFO, "%a:%d dev path '%s' to connect\n", __FILE__, __LINE__, DevPathToTxt->ConvertDevicePathToText(DevicePathToConnect, TRUE, FALSE)));
+  DevicePath        = DuplicateDevicePath (DevicePathToConnect);
+  if (DevicePath == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyOfDevicePath  = DevicePath;
+
+  do {
+    //
+    // The outer loop handles multi instance device paths.
+    // Only console variables contain multiple instance device paths.
+    //
+    // After this call DevicePath points to the next Instance
+    //
+    Instance  = GetNextDevicePathInstance (&DevicePath, &Size);
+    if (Instance == NULL) {
+      FreePool (CopyOfDevicePath);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    Next      = Instance;
+    while (!IsDevicePathEndType (Next)) {
+      Next = NextDevicePathNode (Next);
+    }
+
+    SetDevicePathEndNode (Next);
+
+    //
+    // Start the real work of connect with RemainingDevicePath
+    //
+    PreviousHandle = NULL;
+    do {
+      //
+      // Find the handle that best matches the Device Path. If it is only a
+      // partial match the remaining part of the device path is returned in
+      // RemainingDevicePath.
+      //
+      RemainingDevicePath = Instance;
+      Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+
+      if (!EFI_ERROR (Status)) {
+        if (Handle == PreviousHandle) {
+          //
+          // If no forward progress is made try invoking the Dispatcher.
+          // A new FV may have been added to the system an new drivers
+          // may now be found.
+          // Status == EFI_SUCCESS means a driver was dispatched
+          // Status == EFI_NOT_FOUND means no new drivers were dispatched
+          //
+          Status = gDS->Dispatch ();
+        }
+
+        if (!EFI_ERROR (Status)) {
+          PreviousHandle = Handle;
+          //
+          // Connect all drivers that apply to Handle and RemainingDevicePath,
+          // the Recursive flag is FALSE so only one level will be expanded.
+          //
+          // Do not check the connect status here, if the connect controller fail,
+          // then still give the chance to do dispatch, because partial
+          // RemainingDevicepath may be in the new FV
+          //
+          // 1. If the connect fail, RemainingDevicepath and handle will not
+          //    change, so next time will do the dispatch, then dispatch's status
+          //    will take effect
+          // 2. If the connect success, the RemainingDevicepath and handle will
+          //    change, then avoid the dispatch, we have chance to continue the
+          //    next connection
+          //
+          gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+        }
+      }
+      //
+      // Loop until RemainingDevicePath is an empty device path
+      //
+    } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+  } while (DevicePath != NULL);
+
+  if (CopyOfDevicePath != NULL) {
+    FreePool (CopyOfDevicePath);
+  }
+  //
+  // All handle with DevicePath exists in the handle database
+  //
+  return Status;
+}
+
+
+/**
+  This function will connect all current system handles recursively.
+
+  gBS->ConnectController() service is invoked for each handle exist in system handler buffer.
+  If the handle is bus type handler, all childrens also will be connected recursively
+  by gBS->ConnectController().
+
+  @retval EFI_SUCCESS           All handles and it's child handle have been connected
+  @retval EFI_STATUS            Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllEfi (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       HandleCount;
+  EFI_HANDLE  *HandleBuffer;
+  UINTN       Index;
+
+  Status = gBS->LocateHandleBuffer (
+                  AllHandles,
+                  NULL,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+  }
+
+  if (HandleBuffer != NULL) {
+    FreePool (HandleBuffer);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function will disconnect all current system handles.
+
+  gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
+  If handle is a bus type handle, all childrens also are disconnected recursively by
+  gBS->DisconnectController().
+
+  @retval EFI_SUCCESS           All handles have been disconnected
+  @retval EFI_STATUS            Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibDisconnectAllEfi (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       HandleCount;
+  EFI_HANDLE  *HandleBuffer;
+  UINTN       Index;
+
+  //
+  // Disconnect all
+  //
+  Status = gBS->LocateHandleBuffer (
+                  AllHandles,
+                  NULL,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+  }
+
+  if (HandleBuffer != NULL) {
+    FreePool (HandleBuffer);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Connects all drivers to all controllers.
+  This function make sure all the current system driver will manage
+  the correspoinding controllers if have. And at the same time, make
+  sure all the system controllers have driver to manage it if have.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllDriversToAllControllers (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  do {
+    //
+    // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+    //
+    BdsLibConnectAllEfi ();
+
+    //
+    // Check to see if it's possible to dispatch an more DXE drivers.
+    // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
+    // If anything is Dispatched Status == EFI_SUCCESS and we will try
+    // the connect again.
+    //
+    Status = gDS->Dispatch ();
+
+  } while (!EFI_ERROR (Status));
+
+}
+
+
+/**
+  Connect the specific Usb device which match the short form device path,
+  and whose bus is determined by Host Controller (Uhci or Ehci).
+
+  @param  HostControllerPI      Uhci (0x00) or Ehci (0x20) or Both uhci and ehci
+                                (0xFF)
+  @param  RemainingDevicePath   a short-form device path that starts with the first
+                                element  being a USB WWID or a USB Class device
+                                path
+
+  @return EFI_INVALID_PARAMETER  RemainingDevicePath is NULL pointer.
+                                 RemainingDevicePath is not a USB device path.
+                                 Invalid HostControllerPI type.
+  @return EFI_SUCCESS            Success to connect USB device
+  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectUsbDevByShortFormDP(
+  IN UINT8                      HostControllerPI,
+  IN EFI_DEVICE_PATH_PROTOCOL   *RemainingDevicePath
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_HANDLE                            *HandleArray;
+  UINTN                                 HandleArrayCount;
+  UINTN                                 Index;
+  EFI_PCI_IO_PROTOCOL                   *PciIo;
+  UINT8                                 Class[3];
+  BOOLEAN                               AtLeastOneConnected;
+
+  //
+  // Check the passed in parameters
+  //
+  if (RemainingDevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((DevicePathType (RemainingDevicePath) != MESSAGING_DEVICE_PATH) ||
+      ((DevicePathSubType (RemainingDevicePath) != MSG_USB_CLASS_DP)
+      && (DevicePathSubType (RemainingDevicePath) != MSG_USB_WWID_DP)
+      )) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (HostControllerPI != 0xFF &&
+      HostControllerPI != 0x00 &&
+      HostControllerPI != 0x20) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Find the usb host controller firstly, then connect with the remaining device path
+  //
+  AtLeastOneConnected = FALSE;
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiPciIoProtocolGuid,
+                  NULL,
+                  &HandleArrayCount,
+                  &HandleArray
+                  );
+  if (!EFI_ERROR (Status)) {
+    for (Index = 0; Index < HandleArrayCount; Index++) {
+      Status = gBS->HandleProtocol (
+                      HandleArray[Index],
+                      &gEfiPciIoProtocolGuid,
+                      (VOID **)&PciIo
+                      );
+      if (!EFI_ERROR (Status)) {
+        //
+        // Check whether the Pci device is the wanted usb host controller
+        //
+        Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
+        if (!EFI_ERROR (Status)) {
+          if ((PCI_CLASS_SERIAL == Class[2]) &&
+              (PCI_CLASS_SERIAL_USB == Class[1])) {
+            if (HostControllerPI == Class[0] || HostControllerPI == 0xFF) {
+              Status = gBS->ConnectController (
+                              HandleArray[Index],
+                              NULL,
+                              RemainingDevicePath,
+                              FALSE
+                              );
+              if (!EFI_ERROR(Status)) {
+                AtLeastOneConnected = TRUE;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (AtLeastOneConnected) {
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsConsole.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsConsole.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsConsole.c	(revision 29125)
@@ -0,0 +1,1030 @@
+/* $Id$ */
+/** @file
+ * BdsConsole.c - BDS Lib functions which contain all the code to connect console device.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2004 - 2009, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "InternalBdsLib.h"
+#include "Bmp.h"
+
+/**
+  Check if we need to save the EFI variable with "ConVarName" as name
+  as NV type
+  If ConVarName is NULL, then ASSERT().
+
+  @param ConVarName The name of the EFI variable.
+
+  @retval TRUE    Set the EFI variable as NV type.
+  @retval FALSE   EFI variable as NV type can be set NonNV.
+**/
+BOOLEAN
+IsNvNeed (
+  IN CHAR16 *ConVarName
+  )
+{
+  CHAR16 *Ptr;
+
+  ASSERT (ConVarName != NULL);
+
+  Ptr = ConVarName;
+
+  //
+  // If the variable includes "Dev" at last, we consider
+  // it does not support NV attribute.
+  //
+  while (*Ptr != L'\0') {
+    Ptr++;
+  }
+
+  if (((INTN)((UINTN)Ptr - (UINTN)ConVarName) / sizeof (CHAR16)) <= 3) {
+    return TRUE;
+  }
+
+  if ((*(Ptr - 3) == 'D') && (*(Ptr - 2) == 'e') && (*(Ptr - 1) == 'v')) {
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+/**
+  Fill console handle in System Table if there are no valid console handle in.
+
+  Firstly, check the validation of console handle in System Table. If it is invalid,
+  update it by the first console device handle from EFI console variable.
+
+  @param  VarName            The name of the EFI console variable.
+  @param  ConsoleGuid        Specified Console protocol GUID.
+  @param  ConsoleHandle      On IN,  console handle in System Table to be checked.
+                             On OUT, new console hanlde in system table.
+  @param  ProtocolInterface  On IN,  console protocol on console handle in System Table to be checked.
+                             On OUT, new console protocol on new console hanlde in system table.
+
+  @retval TRUE               System Table has been updated.
+  @retval FALSE              System Table hasn't been updated.
+
+**/
+BOOLEAN
+UpdateSystemTableConsole (
+  IN     CHAR16                          *VarName,
+  IN     EFI_GUID                        *ConsoleGuid,
+  IN OUT EFI_HANDLE                      *ConsoleHandle,
+  IN OUT VOID                            **ProtocolInterface
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     DevicePathSize;
+  EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *VarConsole;
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;
+  VOID                      *Interface;
+  EFI_HANDLE                NewHandle;
+
+  ASSERT (VarName != NULL);
+  ASSERT (ConsoleHandle != NULL);
+  ASSERT (ConsoleGuid != NULL);
+  ASSERT (ProtocolInterface != NULL);
+
+  if (*ConsoleHandle != NULL) {
+    Status = gBS->HandleProtocol (
+                   *ConsoleHandle,
+                   ConsoleGuid,
+                   &Interface
+                   );
+    if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
+      //
+      // If ConsoleHandle is valid and console protocol on this handle also
+      // also matched, just return.
+      //
+      return FALSE;
+    }
+  }
+
+  //
+  // Get all possible consoles device path from EFI variable
+  //
+  VarConsole = BdsLibGetVariableAndSize (
+                VarName,
+                &gEfiGlobalVariableGuid,
+                &DevicePathSize
+                );
+  if (VarConsole == NULL) {
+    //
+    // If there is no any console device, just return.
+    //
+    return FALSE;
+  }
+
+  FullDevicePath = VarConsole;
+
+  do {
+    //
+    // Check every instance of the console variable
+    //
+    Instance  = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
+    if (Instance == NULL) {
+      FreePool (FullDevicePath);
+      ASSERT (FALSE);
+    }
+
+    //
+    // Find console device handle by device path instance
+    //
+    Status = gBS->LocateDevicePath (
+                   ConsoleGuid,
+                   &Instance,
+                   &NewHandle
+                   );
+    if (!EFI_ERROR (Status)) {
+      //
+      // Get the console protocol on this console device handle
+      //
+      Status = gBS->HandleProtocol (
+                     NewHandle,
+                     ConsoleGuid,
+                     &Interface
+                     );
+      if (!EFI_ERROR (Status)) {
+        //
+        // Update new console handle in System Table.
+        //
+        *ConsoleHandle     = NewHandle;
+        *ProtocolInterface = Interface;
+        return TRUE;
+      }
+    }
+
+  } while (Instance != NULL);
+
+  //
+  // No any available console devcie found.
+  //
+  return FALSE;
+}
+
+/**
+  This function update console variable based on ConVarName, it can
+  add or remove one specific console device path from the variable
+
+  @param  ConVarName               Console related variable name, ConIn, ConOut,
+                                   ErrOut.
+  @param  CustomizedConDevicePath  The console device path which will be added to
+                                   the console variable ConVarName, this parameter
+                                   can not be multi-instance.
+  @param  ExclusiveDevicePath      The console device path which will be removed
+                                   from the console variable ConVarName, this
+                                   parameter can not be multi-instance.
+
+  @retval EFI_UNSUPPORTED          The added device path is same to the removed one.
+  @retval EFI_SUCCESS              Success add or remove the device path from  the
+                                   console variable.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateConsoleVariable (
+  IN  CHAR16                    *ConVarName,
+  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,
+  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *VarConsole;
+  UINTN                     DevicePathSize;
+  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
+  UINT32                    Attributes;
+
+  VarConsole      = NULL;
+  DevicePathSize  = 0;
+
+  //
+  // Notes: check the device path point, here should check
+  // with compare memory
+  //
+  if (CustomizedConDevicePath == ExclusiveDevicePath) {
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Delete the ExclusiveDevicePath from current default console
+  //
+  VarConsole = BdsLibGetVariableAndSize (
+                ConVarName,
+                &gEfiGlobalVariableGuid,
+                &DevicePathSize
+                );
+
+  //
+  // Initialize NewDevicePath
+  //
+  NewDevicePath  = VarConsole;
+
+  //
+  // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
+  // In the end, NewDevicePath is the final device path.
+  //
+  if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
+      NewDevicePath = BdsLibDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
+  }
+  //
+  // Try to append customized device path to NewDevicePath.
+  //
+  if (CustomizedConDevicePath != NULL) {
+    if (!BdsLibMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
+      //
+      // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
+      //
+      NewDevicePath = BdsLibDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
+      //
+      // In the first check, the default console variable will be _ModuleEntryPoint,
+      // just append current customized device path
+      //
+      TempNewDevicePath = NewDevicePath;
+      NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
+      if (TempNewDevicePath != NULL) {
+        FreePool(TempNewDevicePath);
+      }
+    }
+  }
+
+  //
+  // The attribute for ConInDev, ConOutDev and ErrOutDev does not include NV.
+  //
+  if (IsNvNeed(ConVarName)) {
+    //
+    // ConVarName has NV attribute.
+    //
+    Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+  } else {
+    //
+    // ConVarName does not have NV attribute.
+    //
+    Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+  }
+
+  //
+  // Finally, Update the variable of the default console by NewDevicePath
+  //
+  gRT->SetVariable (
+        ConVarName,
+        &gEfiGlobalVariableGuid,
+        Attributes,
+        GetDevicePathSize (NewDevicePath),
+        NewDevicePath
+        );
+
+  if (VarConsole == NewDevicePath) {
+    if (VarConsole != NULL) {
+      FreePool(VarConsole);
+    }
+  } else {
+    if (VarConsole != NULL) {
+      FreePool(VarConsole);
+    }
+    if (NewDevicePath != NULL) {
+      FreePool(NewDevicePath);
+    }
+  }
+
+  return EFI_SUCCESS;
+
+}
+
+
+/**
+  Connect the console device base on the variable ConVarName, if
+  device path of the ConVarName is multi-instance device path, if
+  anyone of the instances is connected success, then this function
+  will return success.
+
+  @param  ConVarName               Console related variable name, ConIn, ConOut,
+                                   ErrOut.
+
+  @retval EFI_NOT_FOUND            There is not any console devices connected
+                                   success
+  @retval EFI_SUCCESS              Success connect any one instance of the console
+                                   device path base on the variable ConVarName.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectConsoleVariable (
+  IN  CHAR16                 *ConVarName
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *StartDevicePath;
+  UINTN                     VariableSize;
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;
+  EFI_DEVICE_PATH_PROTOCOL  *Next;
+  EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
+  UINTN                     Size;
+  BOOLEAN                   DeviceExist;
+
+  Status      = EFI_SUCCESS;
+  DeviceExist = FALSE;
+
+  //
+  // Check if the console variable exist
+  //
+  StartDevicePath = BdsLibGetVariableAndSize (
+                      ConVarName,
+                      &gEfiGlobalVariableGuid,
+                      &VariableSize
+                      );
+  if (StartDevicePath == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  CopyOfDevicePath = StartDevicePath;
+  do {
+    //
+    // Check every instance of the console variable
+    //
+    Instance  = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
+    if (Instance == NULL) {
+      FreePool (StartDevicePath);
+      return EFI_UNSUPPORTED;
+    }
+
+    Next      = Instance;
+    while (!IsDevicePathEndType (Next)) {
+      Next = NextDevicePathNode (Next);
+    }
+
+    SetDevicePathEndNode (Next);
+    //
+    // Check USB1.1 console
+    //
+    if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
+       ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
+       || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
+       )) {
+      //
+      // Check the Usb console in Usb2.0 bus firstly, then Usb1.1 bus
+      //
+      Status = BdsLibConnectUsbDevByShortFormDP (PCI_IF_EHCI, Instance);
+      if (!EFI_ERROR (Status)) {
+        DeviceExist = TRUE;
+      }
+
+      Status = BdsLibConnectUsbDevByShortFormDP (PCI_IF_UHCI, Instance);
+      if (!EFI_ERROR (Status)) {
+        DeviceExist = TRUE;
+      }
+    } else {
+      //
+      // Connect the instance device path
+      //
+      Status = BdsLibConnectDevicePath (Instance);
+      if (EFI_ERROR (Status)) {
+        //
+        // Delete the instance from the console varialbe
+        //
+        BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance);
+      } else {
+        DeviceExist = TRUE;
+      }
+    }
+    FreePool(Instance);
+  } while (CopyOfDevicePath != NULL);
+
+  FreePool (StartDevicePath);
+
+  if (!DeviceExist) {
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This function will search every simpletext device in current system,
+  and make every simpletext device as pertantial console device.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllConsoles (
+  VOID
+  )
+{
+  UINTN                     Index;
+  EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
+  UINTN                     HandleCount;
+  EFI_HANDLE                *HandleBuffer;
+
+  Index         = 0;
+  HandleCount   = 0;
+  HandleBuffer  = NULL;
+  ConDevicePath = NULL;
+
+  //
+  // Update all the console variables
+  //
+  gBS->LocateHandleBuffer (
+          ByProtocol,
+          &gEfiSimpleTextInProtocolGuid,
+          NULL,
+          &HandleCount,
+          &HandleBuffer
+          );
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    gBS->HandleProtocol (
+            HandleBuffer[Index],
+            &gEfiDevicePathProtocolGuid,
+            (VOID **) &ConDevicePath
+            );
+    BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL);
+  }
+
+  if (HandleBuffer != NULL) {
+    FreePool(HandleBuffer);
+    HandleBuffer = NULL;
+  }
+
+  gBS->LocateHandleBuffer (
+          ByProtocol,
+          &gEfiSimpleTextOutProtocolGuid,
+          NULL,
+          &HandleCount,
+          &HandleBuffer
+          );
+  for (Index = 0; Index < HandleCount; Index++) {
+    gBS->HandleProtocol (
+            HandleBuffer[Index],
+            &gEfiDevicePathProtocolGuid,
+            (VOID **) &ConDevicePath
+            );
+    BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL);
+    BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL);
+  }
+
+  if (HandleBuffer != NULL) {
+    FreePool(HandleBuffer);
+  }
+
+  //
+  // Connect all console variables
+  //
+  BdsLibConnectAllDefaultConsoles ();
+
+}
+
+/**
+  This function will connect console device base on the console
+  device variable ConIn, ConOut and ErrOut.
+
+  @retval EFI_SUCCESS              At least one of the ConIn and ConOut device have
+                                   been connected success.
+  @retval EFI_STATUS               Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsoles (
+  VOID
+  )
+{
+  EFI_STATUS                Status;
+  BOOLEAN                   SystemTableUpdated;
+
+  //
+  // Connect all default console variables
+  //
+
+  //
+  // It seems impossible not to have any ConOut device on platform,
+  // so we check the status here.
+  //
+  Status = BdsLibConnectConsoleVariable (L"ConOut");
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Insert the performance probe for Console Out
+  //
+  PERF_START (NULL, "ConOut", "BDS", 1);
+  PERF_END (NULL, "ConOut", "BDS", 0);
+
+  //
+  // Because possibly the platform is legacy free, in such case,
+  // ConIn devices (Serial Port and PS2 Keyboard ) does not exist,
+  // so we need not check the status.
+  //
+  BdsLibConnectConsoleVariable (L"ConIn");
+
+  //
+  // The _ModuleEntryPoint err out var is legal.
+  //
+  BdsLibConnectConsoleVariable (L"ErrOut");
+
+  SystemTableUpdated = FALSE;
+  //
+  // Fill console handles in System Table if no console device assignd.
+  //
+  if (UpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
+    SystemTableUpdated = TRUE;
+  }
+  if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+    SystemTableUpdated = TRUE;
+  }
+  if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
+    SystemTableUpdated = TRUE;
+  }
+
+  if (SystemTableUpdated) {
+    //
+    // Update the CRC32 in the EFI System Table header
+    //
+    gST->Hdr.CRC32 = 0;
+    gBS->CalculateCrc32 (
+          (UINT8 *) &gST->Hdr,
+          gST->Hdr.HeaderSize,
+          &gST->Hdr.CRC32
+          );
+  }
+
+  return EFI_SUCCESS;
+
+}
+
+/**
+  Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
+  is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
+  buffer is passed in it will be used if it is big enough.
+
+  @param  BmpImage      Pointer to BMP file
+  @param  BmpImageSize  Number of bytes in BmpImage
+  @param  GopBlt        Buffer containing GOP version of BmpImage.
+  @param  GopBltSize    Size of GopBlt in bytes.
+  @param  PixelHeight   Height of GopBlt/BmpImage in pixels
+  @param  PixelWidth    Width of GopBlt/BmpImage in pixels
+
+  @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
+  @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
+  @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.
+                                GopBltSize will contain the required size.
+  @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
+
+**/
+EFI_STATUS
+ConvertBmpToGopBlt (
+  IN     VOID      *BmpImage,
+  IN     UINTN     BmpImageSize,
+  IN OUT VOID      **GopBlt,
+  IN OUT UINTN     *GopBltSize,
+     OUT UINTN     *PixelHeight,
+     OUT UINTN     *PixelWidth
+  )
+{
+  UINT8                         *Image;
+  UINT8                         *ImageHeader;
+  BMP_IMAGE_HEADER              *BmpHeader;
+  BMP_COLOR_MAP                 *BmpColorMap;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  UINT64                        BltBufferSize;
+  UINTN                         Index;
+  UINTN                         Height;
+  UINTN                         Width;
+  UINTN                         ImageIndex;
+  BOOLEAN                       IsAllocated;
+
+  BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
+
+  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Doesn't support compress.
+  //
+  if (BmpHeader->CompressionType != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Calculate Color Map offset in the image.
+  //
+  Image       = BmpImage;
+  BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
+
+  //
+  // Calculate graphics image data address in the image
+  //
+  Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
+  ImageHeader   = Image;
+
+  //
+  // Calculate the BltBuffer needed size.
+  //
+  BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
+  //
+  // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+  //
+  if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+      return EFI_UNSUPPORTED;
+   }
+  BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+  IsAllocated   = FALSE;
+  if (*GopBlt == NULL) {
+    //
+    // GopBlt is not allocated by caller.
+    //
+    *GopBltSize = (UINTN) BltBufferSize;
+    *GopBlt     = AllocatePool (*GopBltSize);
+    IsAllocated = TRUE;
+    if (*GopBlt == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // GopBlt has been allocated by caller.
+    //
+    if (*GopBltSize < (UINTN) BltBufferSize) {
+      *GopBltSize = (UINTN) BltBufferSize;
+      return EFI_BUFFER_TOO_SMALL;
+    }
+  }
+
+  *PixelWidth   = BmpHeader->PixelWidth;
+  *PixelHeight  = BmpHeader->PixelHeight;
+
+  //
+  // Convert image from BMP to Blt buffer format
+  //
+  BltBuffer = *GopBlt;
+  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
+    Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
+    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
+      switch (BmpHeader->BitPerPixel) {
+      case 1:
+        //
+        // Convert 1-bit (2 colors) BMP to 24-bit color
+        //
+        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
+          Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
+          Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
+          Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
+          Blt++;
+          Width++;
+        }
+
+        Blt--;
+        Width--;
+        break;
+
+      case 4:
+        //
+        // Convert 4-bit (16 colors) BMP Palette to 24-bit color
+        //
+        Index       = (*Image) >> 4;
+        Blt->Red    = BmpColorMap[Index].Red;
+        Blt->Green  = BmpColorMap[Index].Green;
+        Blt->Blue   = BmpColorMap[Index].Blue;
+        if (Width < (BmpHeader->PixelWidth - 1)) {
+          Blt++;
+          Width++;
+          Index       = (*Image) & 0x0f;
+          Blt->Red    = BmpColorMap[Index].Red;
+          Blt->Green  = BmpColorMap[Index].Green;
+          Blt->Blue   = BmpColorMap[Index].Blue;
+        }
+        break;
+
+      case 8:
+        //
+        // Convert 8-bit (256 colors) BMP Palette to 24-bit color
+        //
+        Blt->Red    = BmpColorMap[*Image].Red;
+        Blt->Green  = BmpColorMap[*Image].Green;
+        Blt->Blue   = BmpColorMap[*Image].Blue;
+        break;
+
+      case 24:
+        //
+        // It is 24-bit BMP.
+        //
+        Blt->Blue   = *Image++;
+        Blt->Green  = *Image++;
+        Blt->Red    = *Image;
+        break;
+
+      default:
+        //
+        // Other bit format BMP is not supported.
+        //
+        if (IsAllocated) {
+          FreePool (*GopBlt);
+          *GopBlt = NULL;
+        }
+        return EFI_UNSUPPORTED;
+        break;
+      };
+
+    }
+
+    ImageIndex = (UINTN) (Image - ImageHeader);
+    if ((ImageIndex % 4) != 0) {
+      //
+      // Bmp Image starts each row on a 32-bit boundary!
+      //
+      Image = Image + (4 - (ImageIndex % 4));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Use SystemTable Conout to stop video based Simple Text Out consoles from going
+  to the video device. Put up LogoFile on every video device that is a console.
+
+  @param[in]  LogoFile   File name of logo to display on the center of the screen.
+
+  @retval EFI_SUCCESS     ConsoleControl has been flipped to graphics and logo displayed.
+  @retval EFI_UNSUPPORTED Logo not found
+
+**/
+EFI_STATUS
+EFIAPI
+EnableQuietBoot (
+  IN  EFI_GUID  *LogoFile
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_OEM_BADGING_PROTOCOL      *Badging;
+  UINT32                        SizeOfX;
+  UINT32                        SizeOfY;
+  INTN                          DestX;
+  INTN                          DestY;
+  UINT8                         *ImageData;
+  UINTN                         ImageSize;
+  UINTN                         BltSize;
+  UINT32                        Instance;
+  EFI_BADGING_FORMAT            Format;
+  EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
+  UINTN                         CoordinateX;
+  UINTN                         CoordinateY;
+  UINTN                         Height;
+  UINTN                         Width;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
+  UINT32                        ColorDepth;
+  UINT32                        RefreshRate;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
+
+  UgaDraw = NULL;
+  //
+  // Try to open GOP first
+  //
+  Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+  if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+    GraphicsOutput = NULL;
+    //
+    // Open GOP failed, try to open UGA
+    //
+    Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
+  }
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Erase Cursor from screen
+  //
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+  Badging = NULL;
+  Status  = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
+
+  if (GraphicsOutput != NULL) {
+    SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+    SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+
+  } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+    Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
+    if (EFI_ERROR (Status)) {
+      return EFI_UNSUPPORTED;
+    }
+  } else {
+    return EFI_UNSUPPORTED;
+  }
+
+  Instance = 0;
+  while (1) {
+    ImageData = NULL;
+    ImageSize = 0;
+
+    if (Badging != NULL) {
+      //
+      // Get image from OEMBadging protocol.
+      //
+      Status = Badging->GetImage (
+                          Badging,
+                          &Instance,
+                          &Format,
+                          &ImageData,
+                          &ImageSize,
+                          &Attribute,
+                          &CoordinateX,
+                          &CoordinateY
+                          );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      //
+      // Currently only support BMP format.
+      //
+      if (Format != EfiBadgingFormatBMP) {
+        if (ImageData != NULL) {
+          FreePool (ImageData);
+        }
+        continue;
+      }
+    } else {
+      //
+      // Get the specified image from FV.
+      //
+      Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
+      if (EFI_ERROR (Status)) {
+        return EFI_UNSUPPORTED;
+      }
+
+      CoordinateX = 0;
+      CoordinateY = 0;
+      Attribute   = EfiBadgingDisplayAttributeCenter;
+    }
+
+    Blt = NULL;
+    Status = ConvertBmpToGopBlt (
+              ImageData,
+              ImageSize,
+              (VOID **) &Blt,
+              &BltSize,
+              &Height,
+              &Width
+              );
+    if (EFI_ERROR (Status)) {
+      FreePool (ImageData);
+
+      if (Badging == NULL) {
+        return Status;
+      } else {
+        continue;
+      }
+    }
+
+    //
+    // Calculate the display position according to Attribute.
+    //
+    switch (Attribute) {
+    case EfiBadgingDisplayAttributeLeftTop:
+      DestX = CoordinateX;
+      DestY = CoordinateY;
+      break;
+
+    case EfiBadgingDisplayAttributeCenterTop:
+      DestX = (SizeOfX - Width) / 2;
+      DestY = CoordinateY;
+      break;
+
+    case EfiBadgingDisplayAttributeRightTop:
+      DestX = (SizeOfX - Width - CoordinateX);
+      DestY = CoordinateY;;
+      break;
+
+    case EfiBadgingDisplayAttributeCenterRight:
+      DestX = (SizeOfX - Width - CoordinateX);
+      DestY = (SizeOfY - Height) / 2;
+      break;
+
+    case EfiBadgingDisplayAttributeRightBottom:
+      DestX = (SizeOfX - Width - CoordinateX);
+      DestY = (SizeOfY - Height - CoordinateY);
+      break;
+
+    case EfiBadgingDisplayAttributeCenterBottom:
+      DestX = (SizeOfX - Width) / 2;
+      DestY = (SizeOfY - Height - CoordinateY);
+      break;
+
+    case EfiBadgingDisplayAttributeLeftBottom:
+      DestX = CoordinateX;
+      DestY = (SizeOfY - Height - CoordinateY);
+      break;
+
+    case EfiBadgingDisplayAttributeCenterLeft:
+      DestX = CoordinateX;
+      DestY = (SizeOfY - Height) / 2;
+      break;
+
+    case EfiBadgingDisplayAttributeCenter:
+      DestX = (SizeOfX - Width) / 2;
+      DestY = (SizeOfY - Height) / 2;
+      break;
+
+    default:
+      DestX = CoordinateX;
+      DestY = CoordinateY;
+      break;
+    }
+
+    if ((DestX >= 0) && (DestY >= 0)) {
+      if (GraphicsOutput != NULL) {
+        Status = GraphicsOutput->Blt (
+                            GraphicsOutput,
+                            Blt,
+                            EfiBltBufferToVideo,
+                            0,
+                            0,
+                            (UINTN) DestX,
+                            (UINTN) DestY,
+                            Width,
+                            Height,
+                            Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                            );
+      } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+        Status = UgaDraw->Blt (
+                            UgaDraw,
+                            (EFI_UGA_PIXEL *) Blt,
+                            EfiUgaBltBufferToVideo,
+                            0,
+                            0,
+                            (UINTN) DestX,
+                            (UINTN) DestY,
+                            Width,
+                            Height,
+                            Width * sizeof (EFI_UGA_PIXEL)
+                            );
+      } else {
+      Status = EFI_UNSUPPORTED;
+      }
+    }
+
+    FreePool (ImageData);
+
+    if (Blt != NULL) {
+      FreePool (Blt);
+    }
+
+    if (Badging == NULL) {
+      break;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Use SystemTable Conout to turn on video based Simple Text Out consoles. The
+  Simple Text Out screens will now be synced up with all non video output devices
+
+  @retval EFI_SUCCESS     UGA devices are back in text mode and synced up.
+
+**/
+EFI_STATUS
+EFIAPI
+DisableQuietBoot (
+  VOID
+  )
+{
+
+  //
+  // Enable Cursor on Screen
+  //
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+  return EFI_SUCCESS;
+}
+
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsMisc.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsMisc.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsMisc.c	(revision 29125)
@@ -0,0 +1,1335 @@
+/* $Id$ */
+/** @file
+ * BdsMisc.c - Misc BDS library function.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2004 - 2008, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "InternalBdsLib.h"
+
+
+#define MAX_STRING_LEN        200
+
+BOOLEAN   mFeaturerSwitch = TRUE;
+BOOLEAN   mResetRequired  = FALSE;
+
+extern UINT16 gPlatformBootTimeOutDefault;
+
+/**
+  The function will go through the driver option link list, load and start
+  every driver the driver option device path point to.
+
+  @param  BdsDriverLists        The header of the current driver option link list
+
+**/
+VOID
+EFIAPI
+BdsLibLoadDrivers (
+  IN LIST_ENTRY                   *BdsDriverLists
+  )
+{
+  EFI_STATUS                Status;
+  LIST_ENTRY                *Link;
+  BDS_COMMON_OPTION         *Option;
+  EFI_HANDLE                ImageHandle;
+  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+  UINTN                     ExitDataSize;
+  CHAR16                    *ExitData;
+  BOOLEAN                   ReconnectAll;
+
+  ReconnectAll = FALSE;
+
+  //
+  // Process the driver option
+  //
+  for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
+    Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+    //
+    // If a load option is not marked as LOAD_OPTION_ACTIVE,
+    // the boot manager will not automatically load the option.
+    //
+    if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
+      continue;
+    }
+
+    //
+    // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
+    // then all of the EFI drivers in the system will be disconnected and
+    // reconnected after the last driver load option is processed.
+    //
+    if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
+      ReconnectAll = TRUE;
+    }
+
+    //
+    // Make sure the driver path is connected.
+    //
+    BdsLibConnectDevicePath (Option->DevicePath);
+
+    //
+    // Load and start the image that Driver#### describes
+    //
+    Status = gBS->LoadImage (
+                    FALSE,
+                    mBdsImageHandle,
+                    Option->DevicePath,
+                    NULL,
+                    0,
+                    &ImageHandle
+                    );
+
+    if (!EFI_ERROR (Status)) {
+      gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+
+      //
+      // Verify whether this image is a driver, if not,
+      // exit it and continue to parse next load option
+      //
+      if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
+        gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
+        continue;
+      }
+
+      if (Option->LoadOptionsSize != 0) {
+        ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;
+        ImageInfo->LoadOptions      = Option->LoadOptions;
+      }
+      //
+      // Before calling the image, enable the Watchdog Timer for
+      // the 5 Minute period
+      //
+#ifndef VBOX
+      gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+#endif
+
+      Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
+      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
+
+      //
+      // Clear the Watchdog Timer after the image returns
+      //
+#ifndef VBOX
+      gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+#endif
+    }
+  }
+
+  //
+  // Process the LOAD_OPTION_FORCE_RECONNECT driver option
+  //
+  if (ReconnectAll) {
+    BdsLibDisconnectAllEfi ();
+    BdsLibConnectAll ();
+  }
+
+}
+
+/**
+  Get the Option Number that does not used.
+  Try to locate the specific option variable one by one utile find a free number.
+
+  @param  VariableName          Indicate if the boot#### or driver#### option
+
+  @return The Minimal Free Option Number
+
+**/
+UINT16
+BdsLibGetFreeOptionNumber (
+  IN  CHAR16    *VariableName
+  )
+{
+  UINTN         Index;
+  CHAR16        StrTemp[10];
+  UINT16        *OptionBuffer;
+  UINTN         OptionSize;
+
+  //
+  // Try to find the minimum free number from 0, 1, 2, 3....
+  //
+  Index = 0;
+  do {
+    if (*VariableName == 'B') {
+      UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
+    } else {
+      UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);
+    }
+    //
+    // try if the option number is used
+    //
+    OptionBuffer = BdsLibGetVariableAndSize (
+                     StrTemp,
+                     &gEfiGlobalVariableGuid,
+                     &OptionSize
+                     );
+    if (OptionBuffer == NULL) {
+      break;
+    }
+    Index++;
+  } while (TRUE);
+
+  return ((UINT16) Index);
+}
+
+
+/**
+  This function will register the new boot#### or driver#### option base on
+  the VariableName. The new registered boot#### or driver#### will be linked
+  to BdsOptionList and also update to the VariableName. After the boot#### or
+  driver#### updated, the BootOrder or DriverOrder will also be updated.
+
+  @param  BdsOptionList         The header of the boot#### or driver#### link list
+  @param  DevicePath            The device path which the boot#### or driver####
+                                option present
+  @param  String                The description of the boot#### or driver####
+  @param  VariableName          Indicate if the boot#### or driver#### option
+
+  @retval EFI_SUCCESS           The boot#### or driver#### have been success
+                                registered
+  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibRegisterNewOption (
+  IN  LIST_ENTRY                     *BdsOptionList,
+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
+  IN  CHAR16                         *String,
+  IN  CHAR16                         *VariableName
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     Index;
+  UINT16                    RegisterOptionNumber;
+  UINT16                    *TempOptionPtr;
+  UINTN                     TempOptionSize;
+  UINT16                    *OptionOrderPtr;
+  VOID                      *OptionPtr;
+  UINTN                     OptionSize;
+  UINT8                     *TempPtr;
+  EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
+  CHAR16                    *Description;
+  CHAR16                    OptionName[10];
+  BOOLEAN                   UpdateDescription;
+  UINT16                    BootOrderEntry;
+  UINTN                     OrderItemNum;
+
+
+  OptionPtr             = NULL;
+  OptionSize            = 0;
+  TempPtr               = NULL;
+  OptionDevicePath      = NULL;
+  Description           = NULL;
+  OptionOrderPtr        = NULL;
+  UpdateDescription     = FALSE;
+  Status                = EFI_SUCCESS;
+  ZeroMem (OptionName, sizeof (OptionName));
+
+  TempOptionSize = 0;
+  TempOptionPtr = BdsLibGetVariableAndSize (
+                    VariableName,
+                    &gEfiGlobalVariableGuid,
+                    &TempOptionSize
+                    );
+  //
+  // Compare with current option variable if the previous option is set in global variable.
+  //
+  for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
+    //
+    // TempOptionPtr must not be NULL if we have non-zero TempOptionSize.
+    //
+    ASSERT (TempOptionPtr != NULL);
+
+    if (*VariableName == 'B') {
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
+    } else {
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
+    }
+
+    OptionPtr = BdsLibGetVariableAndSize (
+                  OptionName,
+                  &gEfiGlobalVariableGuid,
+                  &OptionSize
+                  );
+    if (OptionPtr == NULL) {
+      continue;
+    }
+    TempPtr         =   OptionPtr;
+    TempPtr         +=  sizeof (UINT32) + sizeof (UINT16);
+    Description     =   (CHAR16 *) TempPtr;
+    TempPtr         +=  StrSize ((CHAR16 *) TempPtr);
+    OptionDevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+
+    //
+    // Notes: the description may will change base on the GetStringToken
+    //
+    if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
+      if (CompareMem (Description, String, StrSize (Description)) == 0) {
+        //
+        // Got the option, so just return
+        //
+        FreePool (OptionPtr);
+        FreePool (TempOptionPtr);
+        return EFI_SUCCESS;
+      } else {
+        //
+        // Option description changed, need update.
+        //
+        UpdateDescription = TRUE;
+        FreePool (OptionPtr);
+        break;
+      }
+    }
+
+    FreePool (OptionPtr);
+  }
+
+  OptionSize          = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
+  OptionSize          += GetDevicePathSize (DevicePath);
+  OptionPtr           = AllocateZeroPool (OptionSize);
+  ASSERT (OptionPtr != NULL);
+
+  TempPtr             = OptionPtr;
+  *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
+  TempPtr             += sizeof (UINT32);
+  *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
+  TempPtr             += sizeof (UINT16);
+  CopyMem (TempPtr, String, StrSize (String));
+  TempPtr             += StrSize (String);
+  CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
+
+  if (UpdateDescription) {
+    //
+    // The number in option#### to be updated.
+    // In this case, we must have non-NULL TempOptionPtr.
+    //
+    ASSERT (TempOptionPtr != NULL);
+    RegisterOptionNumber = TempOptionPtr[Index];
+  } else {
+    //
+    // The new option#### number
+    //
+    RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
+  }
+
+  if (*VariableName == 'B') {
+    UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
+  } else {
+    UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
+  }
+
+  Status = gRT->SetVariable (
+                  OptionName,
+                  &gEfiGlobalVariableGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                  OptionSize,
+                  OptionPtr
+                  );
+  //
+  // Return if only need to update a changed description or fail to set option.
+  //
+  if (EFI_ERROR (Status) || UpdateDescription) {
+    FreePool (OptionPtr);
+    if (TempOptionPtr != NULL) {
+      FreePool (TempOptionPtr);
+    }
+    return Status;
+  }
+
+  FreePool (OptionPtr);
+
+  //
+  // Update the option order variable
+  //
+
+  //
+  // If no option order
+  //
+  if (TempOptionSize == 0) {
+    BootOrderEntry = 0;
+    Status = gRT->SetVariable (
+                    VariableName,
+                    &gEfiGlobalVariableGuid,
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                    sizeof (UINT16),
+                    &BootOrderEntry
+                    );
+    if (TempOptionPtr != NULL) {
+      FreePool (TempOptionPtr);
+    }
+    return Status;
+  }
+
+  //
+  // TempOptionPtr must not be NULL if TempOptionSize is not zero.
+  //
+  ASSERT (TempOptionPtr != NULL);
+  //
+  // Append the new option number to the original option order
+  //
+  OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
+  OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
+  ASSERT (OptionOrderPtr!= NULL);
+  CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
+
+  OptionOrderPtr[Index] = RegisterOptionNumber;
+
+  Status = gRT->SetVariable (
+                  VariableName,
+                  &gEfiGlobalVariableGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                  OrderItemNum * sizeof (UINT16),
+                  OptionOrderPtr
+                  );
+  FreePool (TempOptionPtr);
+  FreePool (OptionOrderPtr);
+
+  return Status;
+}
+
+
+/**
+  Build the boot#### or driver#### option from the VariableName, the
+  build boot#### or driver#### will also be linked to BdsCommonOptionList.
+
+  @param  BdsCommonOptionList   The header of the boot#### or driver#### option
+                                link list
+  @param  VariableName          EFI Variable name indicate if it is boot#### or
+                                driver####
+
+  @retval BDS_COMMON_OPTION     Get the option just been created
+  @retval NULL                  Failed to get the new option
+
+**/
+BDS_COMMON_OPTION *
+EFIAPI
+BdsLibVariableToOption (
+  IN OUT LIST_ENTRY                   *BdsCommonOptionList,
+  IN  CHAR16                          *VariableName
+  )
+{
+  UINT32                    Attribute;
+  UINT16                    FilePathSize;
+  UINT8                     *Variable;
+  UINT8                     *TempPtr;
+  UINTN                     VariableSize;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  BDS_COMMON_OPTION         *Option;
+  VOID                      *LoadOptions;
+  UINT32                    LoadOptionsSize;
+  CHAR16                    *Description;
+  UINT8                     NumOff;
+  //
+  // Read the variable. We will never free this data.
+  //
+  Variable = BdsLibGetVariableAndSize (
+              VariableName,
+              &gEfiGlobalVariableGuid,
+              &VariableSize
+              );
+  if (Variable == NULL) {
+    return NULL;
+  }
+  //
+  // Notes: careful defined the variable of Boot#### or
+  // Driver####, consider use some macro to abstract the code
+  //
+  //
+  // Get the option attribute
+  //
+  TempPtr   =  Variable;
+  Attribute =  *(UINT32 *) Variable;
+  TempPtr   += sizeof (UINT32);
+
+  //
+  // Get the option's device path size
+  //
+  FilePathSize =  *(UINT16 *) TempPtr;
+  TempPtr      += sizeof (UINT16);
+
+  //
+  // Get the option's description string
+  //
+  Description = (CHAR16 *) TempPtr;
+
+  //
+  // Get the option's description string size
+  //
+  TempPtr     += StrSize ((CHAR16 *) TempPtr);
+
+  //
+  // Get the option's device path
+  //
+  DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+  TempPtr    += FilePathSize;
+
+  LoadOptions     = TempPtr;
+  LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
+
+  //
+  // The Console variables may have multiple device paths, so make
+  // an Entry for each one.
+  //
+  Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
+  if (Option == NULL) {
+    return NULL;
+  }
+
+  Option->Signature   = BDS_LOAD_OPTION_SIGNATURE;
+  Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));
+  ASSERT(Option->DevicePath != NULL);
+  CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+
+  Option->Attribute   = Attribute;
+  Option->Description = AllocateZeroPool (StrSize (Description));
+  ASSERT(Option->Description != NULL);
+  CopyMem (Option->Description, Description, StrSize (Description));
+
+  Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
+  ASSERT(Option->LoadOptions != NULL);
+  CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
+  Option->LoadOptionsSize = LoadOptionsSize;
+
+  //
+  // Get the value from VariableName Unicode string
+  // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
+  // Unicode stream to ASCII without any loss in meaning.
+  //
+  if (*VariableName == 'B') {
+    NumOff = sizeof (L"Boot")/sizeof(CHAR16) -1 ;
+    Option->BootCurrent = (UINT16) ((VariableName[NumOff]  -'0') * 0x1000);
+    Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100));
+    Option->BootCurrent = (UINT16) (Option->BootCurrent +  ((VariableName[NumOff+2]-'0') * 0x10));
+    Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0')));
+  }
+  //
+  // Insert active entry to BdsDeviceList
+  //
+  if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {
+    InsertTailList (BdsCommonOptionList, &Option->Link);
+    FreePool (Variable);
+    return Option;
+  }
+
+  FreePool (Variable);
+  FreePool (Option);
+  return NULL;
+
+}
+
+/**
+  Process BootOrder, or DriverOrder variables, by calling
+  BdsLibVariableToOption () for each UINT16 in the variables.
+
+  @param  BdsCommonOptionList   The header of the option list base on variable
+                                VariableName
+  @param  VariableName          EFI Variable name indicate the BootOrder or
+                                DriverOrder
+
+  @retval EFI_SUCCESS           Success create the boot option or driver option
+                                list
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the boot option or driver option list
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBuildOptionFromVar (
+  IN  LIST_ENTRY                      *BdsCommonOptionList,
+  IN  CHAR16                          *VariableName
+  )
+{
+  UINT16            *OptionOrder;
+  UINTN             OptionOrderSize;
+  UINTN             Index;
+  BDS_COMMON_OPTION *Option;
+  CHAR16            OptionName[20];
+
+  //
+  // Zero Buffer in order to get all BOOT#### variables
+  //
+  ZeroMem (OptionName, sizeof (OptionName));
+
+  //
+  // Read the BootOrder, or DriverOrder variable.
+  //
+  OptionOrder = BdsLibGetVariableAndSize (
+                  VariableName,
+                  &gEfiGlobalVariableGuid,
+                  &OptionOrderSize
+                  );
+  if (OptionOrder == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+    if (*VariableName == 'B') {
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
+    } else {
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
+    }
+
+    Option              = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
+    ASSERT (Option != NULL);
+    Option->BootCurrent = OptionOrder[Index];
+
+  }
+
+  FreePool (OptionOrder);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get boot mode by looking up configuration table and parsing HOB list
+
+  @param  BootMode              Boot mode from PEI handoff HOB.
+
+  @retval EFI_SUCCESS           Successfully get boot mode
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetBootMode (
+  OUT EFI_BOOT_MODE       *BootMode
+  )
+{
+  *BootMode = GetBootModeHob ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
+  buffer, and the size of the buffer. If failure return NULL.
+
+  @param  Name                  String part of EFI variable name
+  @param  VendorGuid            GUID part of EFI variable name
+  @param  VariableSize          Returns the size of the EFI variable that was read
+
+  @return                       Dynamically allocated memory that contains a copy of the EFI variable
+                                Caller is responsible freeing the buffer.
+  @retval NULL                  Variable was not read
+
+**/
+VOID *
+EFIAPI
+BdsLibGetVariableAndSize (
+  IN  CHAR16              *Name,
+  IN  EFI_GUID            *VendorGuid,
+  OUT UINTN               *VariableSize
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+  VOID        *Buffer;
+
+  Buffer = NULL;
+
+  //
+  // Pass in a zero size buffer to find the required buffer size.
+  //
+  BufferSize  = 0;
+  Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    //
+    // Allocate the buffer to return
+    //
+    Buffer = AllocateZeroPool (BufferSize);
+    if (Buffer == NULL) {
+      return NULL;
+    }
+    //
+    // Read variable into the allocated buffer.
+    //
+    Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+    if (EFI_ERROR (Status)) {
+      BufferSize = 0;
+    }
+  }
+
+  *VariableSize = BufferSize;
+  return Buffer;
+}
+
+/**
+  Delete the instance in Multi which matches partly with Single instance
+
+  @param  Multi                 A pointer to a multi-instance device path data
+                                structure.
+  @param  Single                A pointer to a single-instance device path data
+                                structure.
+
+  @return This function will remove the device path instances in Multi which partly
+          match with the Single, and return the result device path. If there is no
+          remaining device path as a result, this function will return NULL.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsLibDelPartMatchInstance (
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Single
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;
+  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
+  UINTN                     InstanceSize;
+  UINTN                     SingleDpSize;
+  UINTN                     Size;
+
+  NewDevicePath     = NULL;
+  TempNewDevicePath = NULL;
+
+  if (Multi == NULL || Single == NULL) {
+    return Multi;
+  }
+
+  Instance        =  GetNextDevicePathInstance (&Multi, &InstanceSize);
+  SingleDpSize    =  GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
+  InstanceSize    -= END_DEVICE_PATH_LENGTH;
+
+  while (Instance != NULL) {
+
+    Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
+
+    if ((CompareMem (Instance, Single, Size) != 0)) {
+      //
+      // Append the device path instance which does not match with Single
+      //
+      TempNewDevicePath = NewDevicePath;
+      NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
+      if (TempNewDevicePath != NULL) {
+        FreePool(TempNewDevicePath);
+      }
+    }
+    FreePool(Instance);
+    Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+    InstanceSize  -= END_DEVICE_PATH_LENGTH;
+  }
+
+  return NewDevicePath;
+}
+
+/**
+  Function compares a device path data structure to that of all the nodes of a
+  second device path instance.
+
+  @param  Multi                 A pointer to a multi-instance device path data
+                                structure.
+  @param  Single                A pointer to a single-instance device path data
+                                structure.
+
+  @retval TRUE                  If the Single device path is contained within Multi device path.
+  @retval FALSE                 The Single device path is not match within Multi device path.
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibMatchDevicePaths (
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Single
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
+  UINTN                     Size;
+
+  if (Multi == NULL || Single  == NULL) {
+    return FALSE;
+  }
+
+  DevicePath      = Multi;
+  DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);
+
+  //
+  // Search for the match of 'Single' in 'Multi'
+  //
+  while (DevicePathInst != NULL) {
+    //
+    // If the single device path is found in multiple device paths,
+    // return success
+    //
+    if (CompareMem (Single, DevicePathInst, Size) == 0) {
+      FreePool (DevicePathInst);
+      return TRUE;
+    }
+
+    FreePool (DevicePathInst);
+    DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+  }
+
+  return FALSE;
+}
+
+/**
+  This function prints a series of strings.
+
+  @param  ConOut                Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
+  @param  ...                   A variable argument list containing series of
+                                strings, the last string must be NULL.
+
+  @retval EFI_SUCCESS           Success print out the string using ConOut.
+  @retval EFI_STATUS            Return the status of the ConOut->OutputString ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibOutputStrings (
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ConOut,
+  ...
+  )
+{
+  VA_LIST     Args;
+  EFI_STATUS  Status;
+  CHAR16      *String;
+
+  Status = EFI_SUCCESS;
+  VA_START (Args, ConOut);
+
+  while (!EFI_ERROR (Status)) {
+    //
+    // If String is NULL, then it's the end of the list
+    //
+    String = VA_ARG (Args, CHAR16 *);
+    if (String == NULL) {
+      break;
+    }
+
+    Status = ConOut->OutputString (ConOut, String);
+
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  VA_END(Args);
+  return Status;
+}
+
+//
+//  Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
+//  Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser  if
+//  user change any option setting which needs a reset to be effective, and  the reset will be applied according to  the user selection.
+//
+
+
+/**
+  Enable the setup browser reset reminder feature.
+  This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
+
+**/
+VOID
+EFIAPI
+EnableResetReminderFeature (
+  VOID
+  )
+{
+  mFeaturerSwitch = TRUE;
+}
+
+
+/**
+  Disable the setup browser reset reminder feature.
+  This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
+
+**/
+VOID
+EFIAPI
+DisableResetReminderFeature (
+  VOID
+  )
+{
+  mFeaturerSwitch = FALSE;
+}
+
+
+/**
+  Record the info that  a reset is required.
+  A  module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+EnableResetRequired (
+  VOID
+  )
+{
+  mResetRequired = TRUE;
+}
+
+
+/**
+  Record the info that  no reset is required.
+  A  module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+DisableResetRequired (
+  VOID
+  )
+{
+  mResetRequired = FALSE;
+}
+
+
+/**
+  Check whether platform policy enable the reset reminder feature. The default is enabled.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetReminderFeatureEnable (
+  VOID
+  )
+{
+  return mFeaturerSwitch;
+}
+
+
+/**
+  Check if  user changed any option setting which needs a system reset to be effective.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetRequired (
+  VOID
+  )
+{
+  return mResetRequired;
+}
+
+
+/**
+  Check whether a reset is needed, and finish the reset reminder feature.
+  If a reset is needed, Popup a menu to notice user, and finish the feature
+  according to the user selection.
+
+**/
+VOID
+EFIAPI
+SetupResetReminder (
+  VOID
+  )
+{
+  EFI_INPUT_KEY                 Key;
+  CHAR16                        *StringBuffer1;
+  CHAR16                        *StringBuffer2;
+
+
+  //
+  //check any reset required change is applied? if yes, reset system
+  //
+  if (IsResetReminderFeatureEnable ()) {
+    if (IsResetRequired ()) {
+
+      StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
+      ASSERT (StringBuffer1 != NULL);
+      StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
+      ASSERT (StringBuffer2 != NULL);
+      StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? ");
+      StrCpy (StringBuffer2, L"Enter (YES)  /   Esc (NO)");
+      //
+      // Popup a menu to notice user
+      //
+      do {
+        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
+      } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+
+      FreePool (StringBuffer1);
+      FreePool (StringBuffer2);
+      //
+      // If the user hits the YES Response key, reset
+      //
+      if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
+        gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+      }
+      gST->ConOut->ClearScreen (gST->ConOut);
+    }
+  }
+}
+
+/**
+  Get the headers (dos, image, optional header) from an image
+
+  @param  Device                SimpleFileSystem device handle
+  @param  FileName              File name for the image
+  @param  DosHeader             Pointer to dos header
+  @param  Hdr                   The buffer in which to return the PE32, PE32+, or TE header.
+
+  @retval EFI_SUCCESS           Successfully get the machine type.
+  @retval EFI_NOT_FOUND         The file is not found.
+  @retval EFI_LOAD_ERROR        File is not a valid image file.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetImageHeader (
+  IN  EFI_HANDLE                  Device,
+  IN  CHAR16                      *FileName,
+  OUT EFI_IMAGE_DOS_HEADER        *DosHeader,
+  OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr,
+  IN OUT  CHAR16                      **NewFileName
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Volume;
+  EFI_FILE_HANDLE                  Root;
+  EFI_FILE_HANDLE                  ThisFile;
+  UINTN                            BufferSize;
+  UINT64                           FileSize;
+  EFI_FILE_INFO                    *Info;
+  CHAR16                           *FileName0 = NULL; /*application's file*/
+
+  Root     = NULL;
+  ThisFile = NULL;
+  //
+  // Handle the file system interface to the device
+  //
+  Status = gBS->HandleProtocol (
+                  Device,
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  (VOID *) &Volume
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = Volume->OpenVolume (
+                     Volume,
+                     &Root
+                     );
+  if (EFI_ERROR (Status)) {
+    Root = NULL;
+    goto Done;
+  }
+
+  Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
+  DEBUG((DEBUG_INFO, "%a:%d Open FileName:'%s' - %r \n", __FILE__, __LINE__, FileName, Status));
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Get file size
+  //
+  do {
+    BufferSize  = 0;
+    Info   = NULL;
+    /* Get right size we need to allocate */
+    Status = ThisFile->GetInfo (
+                         ThisFile,
+                         &gEfiFileInfoGuid,
+                         &BufferSize,
+                         Info
+                         );
+    if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL)
+    {
+        goto Done;
+    }
+    Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+    Status = ThisFile->GetInfo (
+                         ThisFile,
+                         &gEfiFileInfoGuid,
+                         &BufferSize,
+                         Info
+                         );
+    if (!EFI_ERROR (Status)) {
+      DEBUG((DEBUG_INFO, "%a:%d Open FileName:%s from Info %r \n", __FILE__, __LINE__, Info->FileName, Status));
+      Status = gBS->AllocatePool (EfiBootServicesData, StrLen(Info->FileName), (VOID **) &FileName0);
+      StrCpy(FileName0, Info->FileName);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      break;
+    }
+    if (Status != EFI_BUFFER_TOO_SMALL) {
+      FreePool (Info);
+      goto Done;
+    }
+    FreePool (Info);
+  } while (TRUE);
+
+  FileSize = Info->FileSize;
+  FreePool (Info);
+
+  //
+  // Read dos header
+  //
+#ifndef VBOX
+  BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
+  Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
+  if (EFI_ERROR (Status) ||
+      BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
+      FileSize <= DosHeader->e_lfanew ||
+      DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+    Status = EFI_LOAD_ERROR;
+    goto Done;
+  }
+
+  //
+  // Move to PE signature
+  //
+  Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
+  if (EFI_ERROR (Status)) {
+    Status = EFI_LOAD_ERROR;
+    goto Done;
+  }
+
+  //
+  // Read and check PE signature
+  //
+  BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+  Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
+  if (EFI_ERROR (Status) ||
+      BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
+      Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+    Status = EFI_LOAD_ERROR;
+    goto Done;
+  }
+
+  //
+  // Check PE32 or PE32+ magic
+  //
+  if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
+      Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+    Status = EFI_LOAD_ERROR;
+    goto Done;
+  }
+#endif
+ Done:
+  if (!EFI_ERROR(Status))
+  {
+    EFI_STATUS Status0;
+    /* We need prepare the correct file path for case sensitive loaders ... Sigh.*/
+    CHAR16 *dup;
+    CHAR16 *p, *pp;
+    dup = AllocateZeroPool(StrSize(FileName));
+    StrCpy(dup, FileName);
+    pp = p = dup;
+    while (*p != L'\0')
+    {
+        BufferSize  = 0;
+        Info   = NULL;
+        if (*p == L'\\' && p != dup)
+        {
+            *p = L'\0';
+            Status0 = Root->Open (Root, &ThisFile, dup, EFI_FILE_MODE_READ, 1);
+            DEBUG((DEBUG_INFO, "%a:%d Open FileName:%s - %r \n", __FILE__, __LINE__, dup, Status));
+            if (EFI_ERROR (Status)) {
+              goto Done;
+            }
+            /* Get right size we need to allocate */
+            Status0 = ThisFile->GetInfo (
+                                 ThisFile,
+                                 &gEfiFileInfoGuid,
+                                 &BufferSize,
+                                 Info
+                                 );
+            if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL)
+            {
+                DEBUG((DEBUG_INFO, "%a:%d GetInfo(1) FileName:%s %r \n", __FILE__, __LINE__, FileName, Status));
+                goto Done;
+            }
+            Status0 = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
+            if (EFI_ERROR (Status)) {
+              goto Done;
+            }
+            Status0 = ThisFile->GetInfo (
+                                 ThisFile,
+                                 &gEfiFileInfoGuid,
+                                 &BufferSize,
+                                 Info
+                                 );
+            if (!EFI_ERROR (Status0)) {
+              DEBUG((DEBUG_INFO, "%a:%d Open FileName:%s from Info %r \n", __FILE__, __LINE__, Info->FileName, Status));
+              StrCpy(pp + 1, Info->FileName);
+            }
+            * p = L'\\';
+            pp = p;
+        }
+        p++;
+    }
+    StrCpy(pp + 1, FileName0);
+    DEBUG((DEBUG_INFO, "%a:%d NewFileName:'%s'\n", __FILE__, __LINE__, dup));
+    *NewFileName = dup;
+  }
+  DEBUG((DEBUG_INFO, "%a:%d %s - %r\n", __FILE__, __LINE__, FileName, Status));
+  if (ThisFile != NULL) {
+    ThisFile->Close (ThisFile);
+  }
+  if (Root != NULL) {
+    Root->Close (Root);
+  }
+  return Status;
+}
+
+/**
+
+  This routine is a notification function for legayc boot or exit boot
+  service event. It will adjust the memory information for different
+  memory type and save them into the variables for next boot.
+
+
+  @param Event           The event that triggered this notification function.
+  @param Context         Pointer to the notification functions context.
+
+**/
+VOID
+EFIAPI
+BdsSetMemoryTypeInformationVariable (
+  EFI_EVENT  Event,
+  VOID       *Context
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_MEMORY_TYPE_INFORMATION  *PreviousMemoryTypeInformation;
+  EFI_MEMORY_TYPE_INFORMATION  *CurrentMemoryTypeInformation;
+  UINTN                        VariableSize;
+  BOOLEAN                      UpdateRequired;
+  UINTN                        Index;
+  UINTN                        Index1;
+  UINT32                       Previous;
+  UINT32                       Current;
+  UINT32                       Next;
+  EFI_HOB_GUID_TYPE            *GuidHob;
+
+  UpdateRequired = FALSE;
+
+  //
+  // Retrieve the current memory usage statistics.  If they are not found, then
+  // no adjustments can be made to the Memory Type Information variable.
+  //
+  Status = EfiGetSystemConfigurationTable (
+             &gEfiMemoryTypeInformationGuid,
+             (VOID **) &CurrentMemoryTypeInformation
+             );
+  if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
+    return;
+  }
+
+  //
+  // Get the Memory Type Information settings from Hob if they exist,
+  // PEI is responsible for getting them from variable and build a Hob to save them.
+  // If the previous Memory Type Information is not available, then set defaults
+  //
+  GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+  if (GuidHob == NULL) {
+    //
+    // If Platform has not built Memory Type Info into the Hob, just return.
+    //
+    return;
+  }
+  PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+  VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+
+  //
+  // Use a heuristic to adjust the Memory Type Information for the next boot
+  //
+  for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+
+    Current = 0;
+    for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
+      if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
+        Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
+        break;
+      }
+    }
+
+    if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
+      continue;
+    }
+
+    Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
+
+    //
+    // Write next varible to 125% * current and Inconsistent Memory Reserved across bootings may lead to S4 fail
+    //
+    if (Current > Previous) {
+      Next = Current + (Current >> 2);
+    } else {
+      Next = Previous;
+    }
+    if (Next > 0 && Next < 4) {
+      Next = 4;
+    }
+
+    if (Next != Previous) {
+      PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
+      UpdateRequired = TRUE;
+    }
+
+  }
+
+  //
+  // If any changes were made to the Memory Type Information settings, then set the new variable value
+  //
+  if (UpdateRequired) {
+    Status = gRT->SetVariable (
+          EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+          &gEfiMemoryTypeInformationGuid,
+          EFI_VARIABLE_NON_VOLATILE  | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+          VariableSize,
+          PreviousMemoryTypeInformation
+          );
+  }
+
+  return;
+}
+
+/**
+  This routine register a function to adjust the different type memory page number
+  just before booting and save the updated info into the variable for next boot to use.
+
+**/
+VOID
+EFIAPI
+BdsLibSaveMemoryTypeInformation (
+  VOID
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_EVENT                    ReadyToBootEvent;
+
+  Status = EfiCreateEventReadyToBootEx (
+           TPL_CALLBACK,
+           BdsSetMemoryTypeInformationVariable,
+           NULL,
+           &ReadyToBootEvent
+           );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,"Bds Set Memory Type Informationa Variable Fails\n"));
+  }
+
+}
+
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/Bmp.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/Bmp.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/Bmp.h	(revision 29125)
@@ -0,0 +1,66 @@
+/* $Id$ */
+/** @file
+ * Bmp.h - This file defines BMP file header data structures.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2006 - 2008, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#ifndef _GENERIC_BDS_BMP_H__
+#define _GENERIC_BDS_BMP_H__
+
+#pragma pack(1)
+
+typedef struct {
+  UINT8   Blue;
+  UINT8   Green;
+  UINT8   Red;
+  UINT8   Reserved;
+} BMP_COLOR_MAP;
+
+typedef struct {
+  CHAR8         CharB;
+  CHAR8         CharM;
+  UINT32        Size;
+  UINT16        Reserved[2];
+  UINT32        ImageOffset;
+  UINT32        HeaderSize;
+  UINT32        PixelWidth;
+  UINT32        PixelHeight;
+  UINT16        Planes;          ///< Must be 1
+  UINT16        BitPerPixel;     ///< 1, 4, 8, or 24
+  UINT32        CompressionType;
+  UINT32        ImageSize;       ///< Compressed image size in bytes
+  UINT32        XPixelsPerMeter;
+  UINT32        YPixelsPerMeter;
+  UINT32        NumberOfColors;
+  UINT32        ImportantColors;
+} BMP_IMAGE_HEADER;
+
+#pragma pack()
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/DevicePath.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/DevicePath.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/DevicePath.c	(revision 29125)
@@ -0,0 +1,1562 @@
+/* $Id$ */
+/** @file
+ * DevicePath.c - BDS internal function define the default device path string,
+ * it can be replaced by platform device path.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2004 - 2008, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "InternalBdsLib.h"
+
+/**
+  Concatenates a formatted unicode string to allocated pool.
+  The caller must free the resulting buffer.
+
+  @param  Str      Tracks the allocated pool, size in use, and amount of pool allocated.
+  @param  Fmt      The format string
+  @param  ...      The data will be printed.
+
+  @return Allocated buffer with the formatted string printed in it.
+          The caller must free the allocated buffer.
+          The buffer allocation is not packed.
+
+**/
+CHAR16 *
+EFIAPI
+CatPrint (
+  IN OUT POOL_PRINT   *Str,
+  IN CHAR16           *Fmt,
+  ...
+  )
+{
+  UINT16  *AppendStr;
+  VA_LIST Args;
+  UINTN   StringSize;
+
+  AppendStr = AllocateZeroPool (0x1000);
+  if (AppendStr == NULL) {
+    return Str->Str;
+  }
+
+  VA_START (Args, Fmt);
+  UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args);
+  VA_END (Args);
+  if (NULL == Str->Str) {
+    StringSize   = StrSize (AppendStr);
+    Str->Str  = AllocateZeroPool (StringSize);
+    ASSERT (Str->Str != NULL);
+  } else {
+    StringSize = StrSize (AppendStr);
+    StringSize += (StrSize (Str->Str) - sizeof (UINT16));
+
+    Str->Str = ReallocatePool (
+                StrSize (Str->Str),
+                StringSize,
+                Str->Str
+                );
+    ASSERT (Str->Str != NULL);
+  }
+
+  Str->Maxlen = MAX_CHAR * sizeof (UINT16);
+  if (StringSize < Str->Maxlen) {
+    StrCat (Str->Str, AppendStr);
+    Str->Len = StringSize - sizeof (UINT16);
+  }
+
+  FreePool (AppendStr);
+  return Str->Str;
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathPci (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  PCI_DEVICE_PATH *Pci;
+
+  Pci = DevPath;
+  CatPrint (Str, L"Pci(%x|%x)", (UINTN) Pci->Device, (UINTN) Pci->Function);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathPccard (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  PCCARD_DEVICE_PATH  *Pccard;
+
+  Pccard = DevPath;
+  CatPrint (Str, L"Pcmcia(Function%x)", (UINTN) Pccard->FunctionNumber);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathMemMap (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  MEMMAP_DEVICE_PATH  *MemMap;
+
+  MemMap = DevPath;
+  CatPrint (
+    Str,
+    L"MemMap(%d:%lx-%lx)",
+    (UINTN) MemMap->MemoryType,
+    MemMap->StartingAddress,
+    MemMap->EndingAddress
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathController (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  CONTROLLER_DEVICE_PATH  *Controller;
+
+  Controller = DevPath;
+  CatPrint (Str, L"Ctrl(%d)", (UINTN) Controller->ControllerNumber);
+}
+
+
+/**
+  Convert Vendor device path to device name.
+
+  @param  Str      The buffer store device name
+  @param  DevPath  Pointer to vendor device path
+
+**/
+VOID
+DevPathVendor (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  VENDOR_DEVICE_PATH  *Vendor;
+  CHAR16              *Type;
+  UINTN               DataLength;
+  UINTN               Index;
+  UINT32              FlowControlMap;
+
+  UINT16              Info;
+
+  Vendor  = DevPath;
+
+  switch (DevicePathType (&Vendor->Header)) {
+  case HARDWARE_DEVICE_PATH:
+    Type = L"Hw";
+    break;
+
+  case MESSAGING_DEVICE_PATH:
+    Type = L"Msg";
+    if (CompareGuid (&Vendor->Guid, &gEfiPcAnsiGuid)) {
+      CatPrint (Str, L"VenPcAnsi()");
+      return ;
+    } else if (CompareGuid (&Vendor->Guid, &gEfiVT100Guid)) {
+      CatPrint (Str, L"VenVt100()");
+      return ;
+    } else if (CompareGuid (&Vendor->Guid, &gEfiVT100PlusGuid)) {
+      CatPrint (Str, L"VenVt100Plus()");
+      return ;
+    } else if (CompareGuid (&Vendor->Guid, &gEfiVTUTF8Guid)) {
+      CatPrint (Str, L"VenUft8()");
+      return ;
+    } else if (CompareGuid (&Vendor->Guid, &gEfiUartDevicePathGuid     )) {
+      FlowControlMap = (((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap);
+      switch (FlowControlMap & 0x00000003) {
+      case 0:
+        CatPrint (Str, L"UartFlowCtrl(%s)", L"None");
+        break;
+
+      case 1:
+        CatPrint (Str, L"UartFlowCtrl(%s)", L"Hardware");
+        break;
+
+      case 2:
+        CatPrint (Str, L"UartFlowCtrl(%s)", L"XonXoff");
+        break;
+
+      default:
+        break;
+      }
+
+      return ;
+
+    } else if (CompareGuid (&Vendor->Guid, &gEfiSasDevicePathGuid)) {
+      CatPrint (
+        Str,
+        L"SAS(%lx,%lx,%x,",
+        ((SAS_DEVICE_PATH *) Vendor)->SasAddress,
+        ((SAS_DEVICE_PATH *) Vendor)->Lun,
+        (UINTN) ((SAS_DEVICE_PATH *) Vendor)->RelativeTargetPort
+        );
+      Info = (((SAS_DEVICE_PATH *) Vendor)->DeviceTopology);
+      if ((Info & 0x0f) == 0) {
+        CatPrint (Str, L"NoTopology,0,0,0,");
+      } else if (((Info & 0x0f) == 1) || ((Info & 0x0f) == 2)) {
+        CatPrint (
+          Str,
+          L"%s,%s,%s,",
+          ((Info & (0x1 << 4)) != 0) ? L"SATA" : L"SAS",
+          ((Info & (0x1 << 5)) != 0) ? L"External" : L"Internal",
+          ((Info & (0x1 << 6)) != 0) ? L"Expanded" : L"Direct"
+          );
+        if ((Info & 0x0f) == 1) {
+          CatPrint (Str, L"0,");
+        } else {
+          CatPrint (Str, L"%x,", (UINTN) ((Info >> 8) & 0xff));
+        }
+      } else {
+        CatPrint (Str, L"0,0,0,0,");
+      }
+
+      CatPrint (Str, L"%x)", (UINTN) ((SAS_DEVICE_PATH *) Vendor)->Reserved);
+      return ;
+
+    } else if (CompareGuid (&Vendor->Guid, &gEfiDebugPortProtocolGuid)) {
+      CatPrint (Str, L"DebugPort()");
+      return ;
+    }
+    break;
+
+  case MEDIA_DEVICE_PATH:
+    Type = L"Media";
+    break;
+
+  default:
+    Type = L"?";
+    break;
+  }
+
+  CatPrint (Str, L"Ven%s(%g", Type, &Vendor->Guid);
+  DataLength = DevicePathNodeLength (&Vendor->Header) - sizeof (VENDOR_DEVICE_PATH);
+  if (DataLength > 0) {
+    CatPrint (Str, L",");
+    for (Index = 0; Index < DataLength; Index++) {
+      CatPrint (Str, L"%02x", (UINTN) ((VENDOR_DEVICE_PATH_WITH_DATA *) Vendor)->VendorDefinedData[Index]);
+    }
+  }
+  CatPrint (Str, L")");
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathAcpi (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  ACPI_HID_DEVICE_PATH  *Acpi;
+
+  Acpi = DevPath;
+  if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
+    CatPrint (Str, L"Acpi(PNP%04x,%x)", (UINTN)  EISA_ID_TO_NUM (Acpi->HID), (UINTN) Acpi->UID);
+  } else {
+    CatPrint (Str, L"Acpi(%08x,%x)", (UINTN) Acpi->HID, (UINTN) Acpi->UID);
+  }
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathExtendedAcpi (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  ACPI_EXTENDED_HID_DEVICE_PATH   *ExtendedAcpi;
+
+  //
+  // Index for HID, UID and CID strings, 0 for non-exist
+  //
+  UINT16                          HIDSTRIdx;
+  UINT16                          UIDSTRIdx;
+  UINT16                          CIDSTRIdx;
+  UINT16                          Index;
+  UINT16                          Length;
+  UINT16                          Anchor;
+  CHAR8                           *AsChar8Array;
+
+  HIDSTRIdx    = 0;
+  UIDSTRIdx    = 0;
+  CIDSTRIdx    = 0;
+  ExtendedAcpi = DevPath;
+  Length       = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) ExtendedAcpi);
+
+  AsChar8Array = (CHAR8 *) ExtendedAcpi;
+
+  //
+  // find HIDSTR
+  //
+  Anchor = 16;
+  for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) {
+    ;
+  }
+  if (Index > Anchor) {
+    HIDSTRIdx = Anchor;
+  }
+  //
+  // find UIDSTR
+  //
+  Anchor = (UINT16) (Index + 1);
+  for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) {
+    ;
+  }
+  if (Index > Anchor) {
+    UIDSTRIdx = Anchor;
+  }
+  //
+  // find CIDSTR
+  //
+  Anchor = (UINT16) (Index + 1);
+  for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) {
+    ;
+  }
+  if (Index > Anchor) {
+    CIDSTRIdx = Anchor;
+  }
+
+  if (HIDSTRIdx == 0 && CIDSTRIdx == 0 && ExtendedAcpi->UID == 0) {
+    CatPrint (Str, L"AcpiExp(");
+    if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
+      CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID));
+    } else {
+      CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID);
+    }
+    if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
+      CatPrint (Str, L"PNP%04x,", (UINTN)  EISA_ID_TO_NUM (ExtendedAcpi->CID));
+    } else {
+      CatPrint (Str, L"%08x,", (UINTN)  ExtendedAcpi->CID);
+    }
+    if (UIDSTRIdx != 0) {
+      CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx);
+    } else {
+      CatPrint (Str, L"\"\")");
+    }
+  } else {
+    CatPrint (Str, L"AcpiEx(");
+    if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
+      CatPrint (Str, L"PNP%04x,", (UINTN)  EISA_ID_TO_NUM (ExtendedAcpi->HID));
+    } else {
+      CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID);
+    }
+    if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
+      CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID));
+    } else {
+      CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID);
+    }
+    CatPrint (Str, L"%x,", (UINTN) ExtendedAcpi->UID);
+
+    if (HIDSTRIdx != 0) {
+      CatPrint (Str, L"%a,", AsChar8Array + HIDSTRIdx);
+    } else {
+      CatPrint (Str, L"\"\",");
+    }
+    if (CIDSTRIdx != 0) {
+      CatPrint (Str, L"%a,", AsChar8Array + CIDSTRIdx);
+    } else {
+      CatPrint (Str, L"\"\",");
+    }
+    if (UIDSTRIdx != 0) {
+      CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx);
+    } else {
+      CatPrint (Str, L"\"\")");
+    }
+  }
+
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathAdrAcpi (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  ACPI_ADR_DEVICE_PATH    *AcpiAdr;
+  UINT16                  Index;
+  UINT16                  Length;
+  UINT16                  AdditionalAdrCount;
+
+  AcpiAdr            = DevPath;
+  Length             = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) AcpiAdr);
+  AdditionalAdrCount = (UINT16) ((Length - 8) / 4);
+
+  CatPrint (Str, L"AcpiAdr(%x", (UINTN) AcpiAdr->ADR);
+  for (Index = 0; Index < AdditionalAdrCount; Index++) {
+    CatPrint (Str, L",%x", (UINTN) *(UINT32 *) ((UINT8 *) AcpiAdr + 8 + Index * 4));
+  }
+  CatPrint (Str, L")");
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathAtapi (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  ATAPI_DEVICE_PATH *Atapi;
+
+  Atapi = DevPath;
+  CatPrint (
+    Str,
+    L"Ata(%s,%s)",
+    (Atapi->PrimarySecondary != 0)? L"Secondary" : L"Primary",
+    (Atapi->SlaveMaster != 0)? L"Slave" : L"Master"
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathScsi (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  SCSI_DEVICE_PATH  *Scsi;
+
+  Scsi = DevPath;
+  CatPrint (Str, L"Scsi(Pun%x,Lun%x)", (UINTN) Scsi->Pun, (UINTN) Scsi->Lun);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathFibre (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  FIBRECHANNEL_DEVICE_PATH  *Fibre;
+
+  Fibre = DevPath;
+  CatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPath1394 (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  F1394_DEVICE_PATH *F1394Path;
+
+  F1394Path = DevPath;
+  CatPrint (Str, L"1394(%lx)", &F1394Path->Guid);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathUsb (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  USB_DEVICE_PATH *Usb;
+
+  Usb = DevPath;
+  CatPrint (Str, L"Usb(%x,%x)", (UINTN) Usb->ParentPortNumber, (UINTN) Usb->InterfaceNumber);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathUsbWWID (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  USB_WWID_DEVICE_PATH  *UsbWWId;
+
+  UsbWWId = DevPath;
+  CatPrint (
+    Str,
+    L"UsbWwid(%x,%x,%x,\"WWID\")",
+    (UINTN) UsbWWId->VendorId,
+    (UINTN) UsbWWId->ProductId,
+    (UINTN) UsbWWId->InterfaceNumber
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathLogicalUnit (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  DEVICE_LOGICAL_UNIT_DEVICE_PATH *LogicalUnit;
+
+  LogicalUnit = DevPath;
+  CatPrint (Str, L"Unit(%x)", (UINTN) LogicalUnit->Lun);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathUsbClass (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  USB_CLASS_DEVICE_PATH *UsbClass;
+
+  UsbClass = DevPath;
+  CatPrint (
+    Str,
+    L"Usb Class(%x,%x,%x,%x,%x)",
+    (UINTN) UsbClass->VendorId,
+    (UINTN) UsbClass->ProductId,
+    (UINTN) UsbClass->DeviceClass,
+    (UINTN) UsbClass->DeviceSubClass,
+    (UINTN) UsbClass->DeviceProtocol
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathSata (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  SATA_DEVICE_PATH *Sata;
+
+  Sata = DevPath;
+  if ((Sata->PortMultiplierPortNumber & SATA_HBA_DIRECT_CONNECT_FLAG) != 0) {
+    CatPrint (
+      Str,
+      L"Sata(%x,%x)",
+      (UINTN) Sata->HBAPortNumber,
+      (UINTN) Sata->Lun
+      );
+  } else {
+    CatPrint (
+      Str,
+      L"Sata(%x,%x,%x)",
+      (UINTN) Sata->HBAPortNumber,
+      (UINTN) Sata->PortMultiplierPortNumber,
+      (UINTN) Sata->Lun
+      );
+  }
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathI2O (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  I2O_DEVICE_PATH *I2OPath;
+
+  I2OPath = DevPath;
+  CatPrint (Str, L"I2O(%x)", (UINTN) I2OPath->Tid);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathMacAddr (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  MAC_ADDR_DEVICE_PATH  *MACDevPath;
+  UINTN                 HwAddressSize;
+  UINTN                 Index;
+
+  MACDevPath           = DevPath;
+
+  HwAddressSize = sizeof (EFI_MAC_ADDRESS);
+  if (MACDevPath->IfType == 0x01 || MACDevPath->IfType == 0x00) {
+    HwAddressSize = 6;
+  }
+
+  CatPrint (Str, L"Mac(");
+
+  for (Index = 0; Index < HwAddressSize; Index++) {
+    CatPrint (Str, L"%02x", (UINTN) MACDevPath->MacAddress.Addr[Index]);
+  }
+
+  CatPrint (Str, L")");
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathIPv4 (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  IPv4_DEVICE_PATH  *IPDevPath;
+
+  IPDevPath = DevPath;
+  CatPrint (
+    Str,
+    L"IPv4(%d.%d.%d.%d:%d)",
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[0],
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[1],
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[2],
+    (UINTN) IPDevPath->RemoteIpAddress.Addr[3],
+    (UINTN) IPDevPath->RemotePort
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathIPv6 (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  IPv6_DEVICE_PATH  *IPv6DevPath;
+
+  IPv6DevPath = DevPath;
+  CatPrint (
+    Str,
+    L"IPv6(%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x)",
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[0],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[1],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[2],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[3],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[4],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[5],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[6],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[7],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[8],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[9],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[10],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[11],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[12],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[13],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[14],
+    (UINTN) IPv6DevPath->RemoteIpAddress.Addr[15]
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathInfiniBand (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  INFINIBAND_DEVICE_PATH  *InfiniBand;
+
+  InfiniBand = DevPath;
+  CatPrint (
+    Str,
+    L"Infiniband(%x,%g,%lx,%lx,%lx)",
+    (UINTN) InfiniBand->ResourceFlags,
+    InfiniBand->PortGid,
+    InfiniBand->ServiceId,
+    InfiniBand->TargetPortId,
+    InfiniBand->DeviceId
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathUart (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  UART_DEVICE_PATH  *Uart;
+  CHAR8             Parity;
+
+  Uart = DevPath;
+  switch (Uart->Parity) {
+  case 0:
+    Parity = 'D';
+    break;
+
+  case 1:
+    Parity = 'N';
+    break;
+
+  case 2:
+    Parity = 'E';
+    break;
+
+  case 3:
+    Parity = 'O';
+    break;
+
+  case 4:
+    Parity = 'M';
+    break;
+
+  case 5:
+    Parity = 'S';
+    break;
+
+  default:
+    Parity = 'x';
+    break;
+  }
+
+  if (Uart->BaudRate == 0) {
+    CatPrint (Str, L"Uart(DEFAULT,%c,", Parity);
+  } else {
+    CatPrint (Str, L"Uart(%ld,%c,", Uart->BaudRate, Parity);
+  }
+
+  if (Uart->DataBits == 0) {
+    CatPrint (Str, L"D,");
+  } else {
+    CatPrint (Str, L"%d,", (UINTN) Uart->DataBits);
+  }
+
+  switch (Uart->StopBits) {
+  case 0:
+    CatPrint (Str, L"D)");
+    break;
+
+  case 1:
+    CatPrint (Str, L"1)");
+    break;
+
+  case 2:
+    CatPrint (Str, L"1.5)");
+    break;
+
+  case 3:
+    CatPrint (Str, L"2)");
+    break;
+
+  default:
+    CatPrint (Str, L"x)");
+    break;
+  }
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathiSCSI (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  ISCSI_DEVICE_PATH_WITH_NAME *IScsi;
+  UINT16                      Options;
+
+  IScsi = DevPath;
+  CatPrint (
+    Str,
+    L"iSCSI(%a,%x,%lx,",
+    IScsi->TargetName,
+    (UINTN) IScsi->TargetPortalGroupTag,
+    IScsi->Lun
+    );
+
+  Options = IScsi->LoginOption;
+  CatPrint (Str, L"%s,", (((Options >> 1) & 0x0001) != 0) ? L"CRC32C" : L"None");
+  CatPrint (Str, L"%s,", (((Options >> 3) & 0x0001) != 0) ? L"CRC32C" : L"None");
+  if (((Options >> 11) & 0x0001) != 0) {
+    CatPrint (Str, L"%s,", L"None");
+  } else if (((Options >> 12) & 0x0001) != 0) {
+    CatPrint (Str, L"%s,", L"CHAP_UNI");
+  } else {
+    CatPrint (Str, L"%s,", L"CHAP_BI");
+
+  }
+
+  CatPrint (Str, L"%s)", (IScsi->NetworkProtocol == 0) ? L"TCP" : L"reserved");
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathHardDrive (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  HARDDRIVE_DEVICE_PATH *Hd;
+
+  Hd = DevPath;
+  switch (Hd->SignatureType) {
+  case SIGNATURE_TYPE_MBR:
+    CatPrint (
+      Str,
+      L"HD(Part%d,Sig%08x)",
+      (UINTN) Hd->PartitionNumber,
+      (UINTN) *((UINT32 *) (&(Hd->Signature[0])))
+      );
+    break;
+
+  case SIGNATURE_TYPE_GUID:
+    CatPrint (
+      Str,
+      L"HD(Part%d,Sig%g)",
+      (UINTN) Hd->PartitionNumber,
+      (EFI_GUID *) &(Hd->Signature[0])
+      );
+    break;
+
+  default:
+    CatPrint (
+      Str,
+      L"HD(Part%d,MBRType=%02x,SigType=%02x)",
+      (UINTN) Hd->PartitionNumber,
+      (UINTN) Hd->MBRType,
+      (UINTN) Hd->SignatureType
+      );
+    break;
+  }
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathCDROM (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  CDROM_DEVICE_PATH *Cd;
+
+  Cd = DevPath;
+  CatPrint (Str, L"CDROM(Entry%x)", (UINTN) Cd->BootEntry);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathFilePath (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  FILEPATH_DEVICE_PATH  *Fp;
+
+  Fp = DevPath;
+  CatPrint (Str, L"%s", Fp->PathName);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathMediaProtocol (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  MEDIA_PROTOCOL_DEVICE_PATH  *MediaProt;
+
+  MediaProt = DevPath;
+  CatPrint (Str, L"Media(%g)", &MediaProt->Protocol);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathFvFilePath (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
+
+  FvFilePath = DevPath;
+  CatPrint (Str, L"%g", &FvFilePath->FvFileName);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathRelativeOffsetRange (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset;
+
+  Offset = DevPath;
+  CatPrint (
+    Str,
+    L"Offset(%lx,%lx)",
+    Offset->StartingOffset,
+    Offset->EndingOffset
+    );
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathBssBss (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  BBS_BBS_DEVICE_PATH *Bbs;
+  CHAR16              *Type;
+
+  Bbs = DevPath;
+  switch (Bbs->DeviceType) {
+  case BBS_TYPE_FLOPPY:
+    Type = L"Floppy";
+    break;
+
+  case BBS_TYPE_HARDDRIVE:
+    Type = L"Harddrive";
+    break;
+
+  case BBS_TYPE_CDROM:
+    Type = L"CDROM";
+    break;
+
+  case BBS_TYPE_PCMCIA:
+    Type = L"PCMCIA";
+    break;
+
+  case BBS_TYPE_USB:
+    Type = L"Usb";
+    break;
+
+  case BBS_TYPE_EMBEDDED_NETWORK:
+    Type = L"Net";
+    break;
+
+  case BBS_TYPE_BEV:
+    Type = L"BEV";
+    break;
+
+  default:
+    Type = L"?";
+    break;
+  }
+  CatPrint (Str, L"Legacy-%s", Type);
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathEndInstance (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  CatPrint (Str, L",");
+}
+
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maixmum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathNodeUnknown (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  CatPrint (Str, L"?");
+}
+/**
+  Convert Device Path to a Unicode string for printing.
+
+  @param Str             The buffer holding the output string.
+                         This buffer contains the length of the
+                         string and the maximum length reserved
+                         for the string buffer.
+  @param DevPath         The device path.
+
+**/
+VOID
+DevPathFvPath (
+  IN OUT POOL_PRINT       *Str,
+  IN VOID                 *DevPath
+  )
+{
+  MEDIA_FW_VOL_DEVICE_PATH *FvPath;
+
+  FvPath = DevPath;
+  CatPrint (Str, L"Fv(%g)", &FvPath->FvName);
+}
+
+DEVICE_PATH_STRING_TABLE  DevPathTable[] = {
+  {
+    HARDWARE_DEVICE_PATH,
+    HW_PCI_DP,
+    DevPathPci
+  },
+  {
+    HARDWARE_DEVICE_PATH,
+    HW_PCCARD_DP,
+    DevPathPccard
+  },
+  {
+    HARDWARE_DEVICE_PATH,
+    HW_MEMMAP_DP,
+    DevPathMemMap
+  },
+  {
+    HARDWARE_DEVICE_PATH,
+    HW_VENDOR_DP,
+    DevPathVendor
+  },
+  {
+    HARDWARE_DEVICE_PATH,
+    HW_CONTROLLER_DP,
+    DevPathController
+  },
+  {
+    ACPI_DEVICE_PATH,
+    ACPI_DP,
+    DevPathAcpi
+  },
+  {
+    ACPI_DEVICE_PATH,
+    ACPI_EXTENDED_DP,
+    DevPathExtendedAcpi
+  },
+  {
+    ACPI_DEVICE_PATH,
+    ACPI_ADR_DP,
+    DevPathAdrAcpi
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_ATAPI_DP,
+    DevPathAtapi
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_SCSI_DP,
+    DevPathScsi
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_FIBRECHANNEL_DP,
+    DevPathFibre
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_1394_DP,
+    DevPath1394
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_USB_DP,
+    DevPathUsb
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_USB_WWID_DP,
+    DevPathUsbWWID
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_DEVICE_LOGICAL_UNIT_DP,
+    DevPathLogicalUnit
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_USB_CLASS_DP,
+    DevPathUsbClass
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_SATA_DP,
+    DevPathSata
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_I2O_DP,
+    DevPathI2O
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_MAC_ADDR_DP,
+    DevPathMacAddr
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_IPv4_DP,
+    DevPathIPv4
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_IPv6_DP,
+    DevPathIPv6
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_INFINIBAND_DP,
+    DevPathInfiniBand
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_UART_DP,
+    DevPathUart
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_VENDOR_DP,
+    DevPathVendor
+  },
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_ISCSI_DP,
+    DevPathiSCSI
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_HARDDRIVE_DP,
+    DevPathHardDrive
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_CDROM_DP,
+    DevPathCDROM
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_VENDOR_DP,
+    DevPathVendor
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_FILEPATH_DP,
+    DevPathFilePath
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_PROTOCOL_DP,
+    DevPathMediaProtocol
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_PIWG_FW_VOL_DP,
+    DevPathFvPath,
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_PIWG_FW_FILE_DP,
+    DevPathFvFilePath
+  },
+  {
+    MEDIA_DEVICE_PATH,
+    MEDIA_RELATIVE_OFFSET_RANGE_DP,
+    DevPathRelativeOffsetRange,
+  },
+  {
+    BBS_DEVICE_PATH,
+    BBS_BBS_DP,
+    DevPathBssBss
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_INSTANCE_DEVICE_PATH_SUBTYPE,
+    DevPathEndInstance
+  },
+  {
+    0,
+    0,
+    NULL
+  }
+};
+
+
+/**
+  This function converts an input device structure to a Unicode string.
+
+  @param DevPath                  A pointer to the device path structure.
+
+  @return A new allocated Unicode string that represents the device path.
+
+**/
+CHAR16 *
+EFIAPI
+DevicePathToStr (
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath
+  )
+{
+  POOL_PRINT                Str;
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;
+  VOID (*DumpNode) (POOL_PRINT *, VOID *);
+
+  UINTN Index;
+  UINTN NewSize;
+
+  EFI_STATUS                       Status;
+  CHAR16                           *ToText;
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
+
+  ZeroMem (&Str, sizeof (Str));
+
+  if (DevPath == NULL) {
+    goto Done;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiDevicePathToTextProtocolGuid,
+                  NULL,
+                  (VOID **) &DevPathToText
+                  );
+  if (!EFI_ERROR (Status)) {
+    ToText = DevPathToText->ConvertDevicePathToText (
+                              DevPath,
+                              FALSE,
+                              TRUE
+                              );
+    ASSERT (ToText != NULL);
+    return ToText;
+  }
+
+  //
+  // Process each device path node
+  //
+  DevPathNode = DevPath;
+  while (!IsDevicePathEnd (DevPathNode)) {
+    //
+    // Find the handler to dump this device path node
+    //
+    DumpNode = NULL;
+    for (Index = 0; DevPathTable[Index].Function != NULL; Index += 1) {
+
+      if (DevicePathType (DevPathNode) == DevPathTable[Index].Type &&
+          DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType
+          ) {
+        DumpNode = DevPathTable[Index].Function;
+        break;
+      }
+    }
+    //
+    // If not found, use a generic function
+    //
+    if (!DumpNode) {
+      DumpNode = DevPathNodeUnknown;
+    }
+    //
+    //  Put a path seperator in if needed
+    //
+    if ((Str.Len != 0) && (DumpNode != DevPathEndInstance)) {
+      CatPrint (&Str, L"/");
+    }
+    //
+    // Print this node of the device path
+    //
+    DumpNode (&Str, DevPathNode);
+
+    //
+    // Next device path node
+    //
+    DevPathNode = NextDevicePathNode (DevPathNode);
+  }
+
+Done:
+  NewSize = (Str.Len + 1) * sizeof (CHAR16);
+  Str.Str = ReallocatePool (NewSize, NewSize, Str.Str);
+  ASSERT (Str.Str != NULL);
+  Str.Str[Str.Len] = 0;
+  return Str.Str;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/InternalBdsLib.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/InternalBdsLib.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/InternalBdsLib.h	(revision 29125)
@@ -0,0 +1,133 @@
+/* $Id$ */
+/** @file
+ * InternalBdsLib.h - BDS library definition, include the file and data structure
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2004 - 2009, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#ifndef _INTERNAL_BDS_LIB_H_
+#define _INTERNAL_BDS_LIB_H_
+
+#include <FrameworkDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DebugPort.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/AcpiS3Save.h>
+#include <Protocol/OEMBadging.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/Security.h>
+
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/PcAnsi.h>
+#include <Guid/Performance.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/GenericBdsLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DxeServicesLib.h>
+
+#if !defined (EFI_REMOVABLE_MEDIA_FILE_NAME)
+    #if defined (MDE_CPU_EBC)
+        //
+        // Uefi specification only defines the default boot file name for IA32, X64
+        // and IPF processor, so need define boot file name for EBC architecture here.
+        //
+        #define EFI_REMOVABLE_MEDIA_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI"
+    #else
+        #error "Can not determine the default boot file name for unknown processor type!"
+    #endif
+#endif
+
+/**
+
+  Allocates a block of memory and writes performance data of booting into it.
+  OS can processing these record.
+
+**/
+VOID
+WriteBootToOsPerformanceData (
+  VOID
+  );
+
+/**
+  Get the headers (dos, image, optional header) from an image
+
+  @param  Device                SimpleFileSystem device handle
+  @param  FileName              File name for the image
+  @param  DosHeader             Pointer to dos header
+  @param  Hdr                   The buffer in which to return the PE32, PE32+, or TE header.
+
+  @retval EFI_SUCCESS           Successfully get the machine type.
+  @retval EFI_NOT_FOUND         The file is not found.
+  @retval EFI_LOAD_ERROR        File is not a valid image file.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetImageHeader (
+  IN  EFI_HANDLE                  Device,
+  IN  CHAR16                      *FileName,
+  OUT EFI_IMAGE_DOS_HEADER        *DosHeader,
+  OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr,
+  IN OUT  CHAR16                      **NewFileName
+  );
+
+#endif // _BDS_LIB_H_
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/Performance.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/Performance.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/Performance.c	(revision 29125)
@@ -0,0 +1,338 @@
+/* $Id$ */
+/** @file
+ * Performance.c - This file include the file which can help to get the
+ * system performance, all the function will only include if the performance
+ * switch is set.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+
+This code is based on:
+
+Copyright (c) 2004 - 2009, Intel Corporation. <BR>
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "InternalBdsLib.h"
+
+PERF_HEADER               mPerfHeader;
+PERF_DATA                 mPerfData;
+EFI_PHYSICAL_ADDRESS      mAcpiLowMemoryBase = 0x0FFFFFFFFULL;
+
+/**
+  Get the short verion of PDB file name to be
+  used in performance data logging.
+
+  @param PdbFileName     The long PDB file name.
+  @param GaugeString     The output string to be logged by performance logger.
+
+**/
+VOID
+GetShortPdbFileName (
+  IN  CONST CHAR8  *PdbFileName,
+  OUT       CHAR8  *GaugeString
+  )
+{
+  UINTN Index;
+  UINTN Index1;
+  UINTN StartIndex;
+  UINTN EndIndex;
+
+  if (PdbFileName == NULL) {
+    AsciiStrCpy (GaugeString, " ");
+  } else {
+    StartIndex = 0;
+    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
+      ;
+
+    for (Index = 0; PdbFileName[Index] != 0; Index++) {
+      if (PdbFileName[Index] == '\\') {
+        StartIndex = Index + 1;
+      }
+
+      if (PdbFileName[Index] == '.') {
+        EndIndex = Index;
+      }
+    }
+
+    Index1 = 0;
+    for (Index = StartIndex; Index < EndIndex; Index++) {
+      GaugeString[Index1] = PdbFileName[Index];
+      Index1++;
+      if (Index1 == PERF_TOKEN_LENGTH - 1) {
+        break;
+      }
+    }
+
+    GaugeString[Index1] = 0;
+  }
+
+  return ;
+}
+
+/**
+  Get the name from the Driver handle, which can be a handle with
+  EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
+  This name can be used in performance data logging.
+
+  @param Handle          Driver handle.
+  @param GaugeString     The output string to be logged by performance logger.
+
+**/
+VOID
+GetNameFromHandle (
+  IN  EFI_HANDLE     Handle,
+  OUT CHAR8          *GaugeString
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_LOADED_IMAGE_PROTOCOL   *Image;
+  CHAR8                       *PdbFileName;
+  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+  AsciiStrCpy (GaugeString, " ");
+
+  //
+  // Get handle name from image protocol
+  //
+  Status = gBS->HandleProtocol (
+                  Handle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **) &Image
+                  );
+
+  if (EFI_ERROR (Status)) {
+    Status = gBS->OpenProtocol (
+                    Handle,
+                    &gEfiDriverBindingProtocolGuid,
+                    (VOID **) &DriverBinding,
+                    NULL,
+                    NULL,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      return ;
+    }
+    //
+    // Get handle name from image protocol
+    //
+    Status = gBS->HandleProtocol (
+                    DriverBinding->ImageHandle,
+                    &gEfiLoadedImageProtocolGuid,
+                    (VOID **) &Image
+                    );
+  }
+
+  PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
+
+  if (PdbFileName != NULL) {
+    GetShortPdbFileName (PdbFileName, GaugeString);
+  }
+
+  return ;
+}
+
+/**
+
+  Allocates a block of memory and writes performance data of booting into it.
+  OS can processing these record.
+
+**/
+VOID
+WriteBootToOsPerformanceData (
+  VOID
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    AcpiLowMemoryLength;
+  UINT32                    LimitCount;
+  EFI_HANDLE                *Handles;
+  UINTN                     NoHandles;
+  CHAR8                     GaugeString[PERF_TOKEN_LENGTH];
+  UINT8                     *Ptr;
+  UINT32                    Index;
+  UINT64                    Ticker;
+  UINT64                    Freq;
+  UINT32                    Duration;
+  UINTN                     LogEntryKey;
+  CONST VOID                *Handle;
+  CONST CHAR8               *Token;
+  CONST CHAR8               *Module;
+  UINT64                    StartTicker;
+  UINT64                    EndTicker;
+  UINT64                    StartValue;
+  UINT64                    EndValue;
+  BOOLEAN                   CountUp;
+
+  //
+  // Retrieve time stamp count as early as possible
+  //
+  Ticker  = GetPerformanceCounter ();
+
+  Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);
+
+  Freq    = DivU64x32 (Freq, 1000);
+
+  mPerfHeader.CpuFreq = Freq;
+
+  //
+  // Record BDS raw performance data
+  //
+  if (EndValue >= StartValue) {
+    mPerfHeader.BDSRaw = Ticker - StartValue;
+    CountUp            = TRUE;
+  } else {
+    mPerfHeader.BDSRaw = StartValue - Ticker;
+    CountUp            = FALSE;
+  }
+
+  //
+  // Put Detailed performance data into memory
+  //
+  Handles = NULL;
+  Status = gBS->LocateHandleBuffer (
+                  AllHandles,
+                  NULL,
+                  NULL,
+                  &NoHandles,
+                  &Handles
+                  );
+  if (EFI_ERROR (Status)) {
+    return ;
+  }
+
+
+  AcpiLowMemoryLength = 0x4000;
+  if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {
+    //
+    // Allocate a block of memory that contain performance data to OS
+    //
+    Status = gBS->AllocatePages (
+                    AllocateMaxAddress,
+                    EfiReservedMemoryType,
+                    EFI_SIZE_TO_PAGES (AcpiLowMemoryLength),
+                    &mAcpiLowMemoryBase
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (Handles);
+      return ;
+    }
+  }
+
+
+  Ptr        = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
+  LimitCount = (AcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
+
+
+
+  //
+  // Get DXE drivers performance
+  //
+  for (Index = 0; Index < NoHandles; Index++) {
+    Ticker = 0;
+    LogEntryKey = 0;
+    while ((LogEntryKey = GetPerformanceMeasurement (
+                            LogEntryKey,
+                            &Handle,
+                            &Token,
+                            &Module,
+                            &StartTicker,
+                            &EndTicker)) != 0) {
+      if ((Handle == Handles[Index]) && (EndTicker != 0)) {
+        Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
+      }
+    }
+
+    Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
+
+    if (Duration > 0) {
+
+      GetNameFromHandle (Handles[Index], GaugeString);
+
+      AsciiStrCpy (mPerfData.Token, GaugeString);
+      mPerfData.Duration = Duration;
+
+      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
+      Ptr += sizeof (PERF_DATA);
+
+      mPerfHeader.Count++;
+      if (mPerfHeader.Count == LimitCount) {
+        goto Done;
+      }
+    }
+  }
+
+  FreePool (Handles);
+
+  //
+  // Get inserted performance data
+  //
+  LogEntryKey = 0;
+  while ((LogEntryKey = GetPerformanceMeasurement (
+                          LogEntryKey,
+                          &Handle,
+                          &Token,
+                          &Module,
+                          &StartTicker,
+                          &EndTicker)) != 0) {
+    if (Handle == NULL && EndTicker != 0) {
+
+      ZeroMem (&mPerfData, sizeof (PERF_DATA));
+
+      AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH);
+      Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
+
+      mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
+
+      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
+      Ptr += sizeof (PERF_DATA);
+
+      mPerfHeader.Count++;
+      if (mPerfHeader.Count == LimitCount) {
+        goto Done;
+      }
+    }
+  }
+
+Done:
+
+  mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
+
+  //
+  // Put performance data to Reserved memory
+  //
+  CopyMem (
+    (UINTN *) (UINTN) mAcpiLowMemoryBase,
+    &mPerfHeader,
+    sizeof (PERF_HEADER)
+    );
+
+  gRT->SetVariable (
+        L"PerfDataMemAddr",
+        &gPerformanceProtocolGuid,
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+        sizeof (EFI_PHYSICAL_ADDRESS),
+        &mAcpiLowMemoryBase
+        );
+
+  return ;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/VBoxGenericBdsLib.inf
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/VBoxGenericBdsLib.inf	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/VBoxGenericBdsLib.inf	(revision 29125)
@@ -0,0 +1,131 @@
+# $Id$
+#/** @file
+
+#
+# Copyright (C) 2010 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+#
+# This code is based on:
+#  
+#  General BDS defines and produce general interfaces for platform BDS driver including:
+#  1) BDS boot policy interface;
+#  2) BDS boot device connect interface;
+#  3) BDS Misc interfaces for mainting boot variable, ouput string, etc.
+#  
+#  Copyright (c) 2007 - 2009, Intel Corporation. <BR>
+#  All rights reserved. This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#  
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#  
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VBoxGenericBdsLib
+  FILE_GUID                      = 9d6d3138-d08f-11de-a011-c3f4983a5eb8
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = GenericBdsLib|DXE_DRIVER UEFI_APPLICATION 
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+  DevicePath.c
+  Performance.c
+  BdsConnect.c
+  BdsMisc.c
+  BdsConsole.c
+  BdsBoot.c
+  InternalBdsLib.h
+  Bmp.h
+
+[Packages]
+  VBoxPkg/VBoxPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+  DevicePathLib
+  PeCoffGetEntryPointLib
+  BaseLib
+  HobLib
+  UefiRuntimeServicesTableLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  UefiLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  PrintLib
+  PcdLib
+  PerformanceLib
+  TimerLib
+  PcdLib
+  DxeServicesLib
+
+[Guids]
+  gEfiVT100PlusGuid                             ## CONSUMES ## GUID (The type of terminal)
+  gEfiVT100Guid                                 ## CONSUMES ## GUID (The type of terminal)
+  gEfiMemoryTypeInformationGuid                 ## CONSUMES ## GUID (The identifier of memory type information type in system table)
+                                                ## CONSUMES ## GUID HOB (The hob holding memory type information)
+  gEfiVTUTF8Guid                                ## CONSUMES ## GUID (The type of terminal)
+  gEfiGlobalVariableGuid                        ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot)
+                                                ## SOMETIMES_CONSUMES ## Variable:L"BootXX" (Boot option variable)
+                                                ## CONSUMES           ## Variable:L"Timeout" (The time out value in second of showing progress bar)
+                                                ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array)
+                                                ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" (The driver order list)
+                                                ## SOMETIMES_CONSUMES ## Variable:L"ConIn" (The device path of console in device)
+                                                ## SOMETIMES_CONSUMES ## Variable:L"ConOut" (The device path of console out device)
+                                                ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)
+  gEfiFileInfoGuid                              ## CONSUMES ## GUID
+  gEfiPcAnsiGuid                                ## CONSUMES ## GUID (The type of terminal)
+  gPerformanceProtocolGuid                      ## SOMETIMES_PRODUCES ## Variable:L"PerfDataMemAddr" (The ACPI address of performance data)
+  gEfiUartDevicePathGuid                        ## CONSUMES ## GUID (Identify the device path for UARD device)
+  gEfiSasDevicePathGuid                         ## CONSUMES ## GUID (Identify the device path for SAS device)
+
+[Protocols]
+  gEfiSimpleFileSystemProtocolGuid              # PROTOCOL CONSUMES
+  gEfiSimpleTextOutProtocolGuid                 # PROTOCOL CONSUMES
+  gEfiPciIoProtocolGuid                         # PROTOCOL CONSUMES
+  gEfiLoadedImageProtocolGuid                   # PROTOCOL CONSUMES
+  gEfiDevicePathToTextProtocolGuid              # PROTOCOL SOMETIMES_CONSUMES
+  gEfiSimpleNetworkProtocolGuid                 # PROTOCOL CONSUMES
+  gEfiDebugPortProtocolGuid                     # PROTOCOL CONSUMES
+  gEfiSimpleTextInProtocolGuid                  # PROTOCOL CONSUMES
+  gEfiBlockIoProtocolGuid                       # PROTOCOL CONSUMES
+  gEfiFirmwareVolume2ProtocolGuid               # PROTOCOL CONSUMES
+  gEfiLegacyBiosProtocolGuid                    # PROTOCOL SOMETIMES_CONSUMES
+  gEfiCpuArchProtocolGuid                       # PROTOCOL CONSUMES
+  gEfiDevicePathProtocolGuid                    # PROTOCOL CONSUMES
+  gEfiAcpiS3SaveProtocolGuid                    # PROTOCOL CONSUMES
+  gEfiGraphicsOutputProtocolGuid                # PROTOCOL SOMETIMES_CONSUMES
+  gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES
+  gEfiOEMBadgingProtocolGuid                    # PROTOCOL CONSUMES
+  gEfiHiiFontProtocolGuid                       # PROTOCOL CONSUMES
+  gEfiSecurityArchProtocolGuid                  # PROTOCOL CONSUMES
+  gEfiDevicePathProtocolGuid
+
+[FeaturePcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport
+
+[Pcd]
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFsDxe.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFsDxe.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFsDxe.c	(revision 29125)
@@ -0,0 +1,211 @@
+/* $Id$ */
+/** @file
+ * VBoxFsDxe.c - VirtualBox FS wrapper
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/PciIo.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <IndustryStandard/Pci22.h>
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static EFI_STATUS EFIAPI
+VBoxFsDB_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+                   IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL);
+static EFI_STATUS EFIAPI
+VBoxFsDB_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+               IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL);
+static EFI_STATUS EFIAPI
+VBoxFsDB_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+              IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL);
+
+static EFI_STATUS EFIAPI
+VBoxFsCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+                       IN CHAR8 *Language, OUT CHAR16 **DriverName);
+static EFI_STATUS EFIAPI
+VBoxFsCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+                           IN EFI_HANDLE ControllerHandle,
+                           IN EFI_HANDLE ChildHandle OPTIONAL,
+                           IN CHAR8 *Language,  OUT CHAR16 **ControllerName);
+
+static EFI_STATUS EFIAPI
+VBoxFsCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+                        IN CHAR8 *Language, OUT CHAR16 **DriverName);
+static EFI_STATUS EFIAPI
+VBoxFsCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+                            IN EFI_HANDLE ControllerHandle,
+                            IN EFI_HANDLE ChildHandle OPTIONAL,
+                            IN CHAR8 *Language,  OUT CHAR16 **ControllerName);
+
+
+/** EFI Driver Binding Protocol. */
+static EFI_DRIVER_BINDING_PROTOCOL          g_VBoxFsDB =
+{
+    VBoxFsDB_Supported,
+    VBoxFsDB_Start,
+    VBoxFsDB_Stop,
+    /* .Version             = */    1,
+    /* .ImageHandle         = */ NULL,
+    /* .DriverBindingHandle = */ NULL
+};
+
+/** EFI Component Name Protocol. */
+static const EFI_COMPONENT_NAME_PROTOCOL    g_VBoxFsCN =
+{
+    VBoxFsCN_GetDriverName,
+    VBoxFsCN_GetControllerName,
+    "eng"
+};
+
+/** EFI Component Name 2 Protocol. */
+static const EFI_COMPONENT_NAME2_PROTOCOL   g_VBoxFsCN2 =
+{
+    VBoxFsCN2_GetDriverName,
+    VBoxFsCN2_GetControllerName,
+    "en"
+};
+
+/** Driver name translation table. */
+static CONST EFI_UNICODE_STRING_TABLE       g_aVBoxFsDriverLangAndNames[] =
+{
+    {   "eng;en",   L"VBox Universal FS Wrapper Driver" },
+    {   NULL,       NULL }
+};
+
+
+
+/**
+ * VBoxFsDxe entry point.
+ *
+ * @returns EFI status code.
+ *
+ * @param   ImageHandle     The image handle.
+ * @param   SystemTable     The system table pointer.
+ */
+EFI_STATUS EFIAPI
+DxeInitializeVBoxFs(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+{
+    EFI_STATUS  rc;
+    DEBUG((DEBUG_INFO, "DxeInitializeVBoxFsDxe\n"));
+
+    rc = EfiLibInstallDriverBindingComponentName2(ImageHandle, SystemTable,
+                                                  &g_VBoxFsDB, ImageHandle,
+                                                  &g_VBoxFsCN, &g_VBoxFsCN2);
+    ASSERT_EFI_ERROR(rc);
+    return rc;
+}
+
+EFI_STATUS EFIAPI
+DxeUninitializeVBoxFs(IN EFI_HANDLE         ImageHandle)
+{
+    return EFI_SUCCESS;
+}
+
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_SUPPORTED
+ */
+static EFI_STATUS EFIAPI
+VBoxFsDB_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+                   IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
+{
+    EFI_STATUS              rcRet = EFI_UNSUPPORTED;
+    /* EFI_STATUS              rc; */
+
+    return rcRet;
+}
+
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_START
+ */
+static EFI_STATUS EFIAPI
+VBoxFsDB_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+               IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
+{
+    /* EFI_STATUS              rc; */
+
+    return  EFI_UNSUPPORTED;
+}
+
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_STOP
+ */
+static EFI_STATUS EFIAPI
+VBoxFsDB_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+              IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL)
+{
+    /* EFI_STATUS                  rc; */
+
+    return  EFI_UNSUPPORTED;
+}
+
+
+/** @copydoc EFI_COMPONENT_NAME_GET_DRIVER_NAME */
+static EFI_STATUS EFIAPI
+VBoxFsCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+                       IN CHAR8 *Language, OUT CHAR16 **DriverName)
+{
+    return LookupUnicodeString2(Language,
+                                This->SupportedLanguages,
+                                &g_aVBoxFsDriverLangAndNames[0],
+                                DriverName,
+                                TRUE);
+}
+
+/** @copydoc EFI_COMPONENT_NAME_GET_CONTROLLER_NAME */
+static EFI_STATUS EFIAPI
+VBoxFsCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+                                    IN EFI_HANDLE ControllerHandle,
+                                    IN EFI_HANDLE ChildHandle OPTIONAL,
+                                    IN CHAR8 *Language, OUT CHAR16 **ControllerName)
+{
+    /** @todo try query the protocol from the controller and forward the query. */
+    return EFI_UNSUPPORTED;
+}
+
+/** @copydoc EFI_COMPONENT_NAME2_GET_DRIVER_NAME */
+static EFI_STATUS EFIAPI
+VBoxFsCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+                        IN CHAR8 *Language, OUT CHAR16 **DriverName)
+{
+    return LookupUnicodeString2(Language,
+                                This->SupportedLanguages,
+                                &g_aVBoxFsDriverLangAndNames[0],
+                                DriverName,
+                                FALSE);
+}
+
+/** @copydoc EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME */
+static EFI_STATUS EFIAPI
+VBoxFsCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+                            IN EFI_HANDLE ControllerHandle,
+                            IN EFI_HANDLE ChildHandle OPTIONAL,
+                            IN CHAR8 *Language, OUT CHAR16 **ControllerName)
+{
+    /** @todo try query the protocol from the controller and forward the query. */
+    return EFI_UNSUPPORTED;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFsDxe.inf
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFsDxe.inf	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFsDxe.inf	(revision 29125)
@@ -0,0 +1,69 @@
+# $Id$
+## @file
+# VBoxFsDxe - VBox filesystem wrapper.
+#
+# This layer encorporates generic layer for filesystem implementations.
+# Here we put filesystem implementations needed by VirtualBox,
+# but not (yet) included into EDK2.
+#
+
+#
+# Copyright (C) 2010 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+[Defines]
+        INF_VERSION                = 0x00010005
+        BASE_NAME                  = VBoxFsDxe
+        FILE_GUID                  = 0C842421-5699-4E97-BB6B-17B28696DB6E
+        MODULE_TYPE                = UEFI_DRIVER
+        VERSION_STRING             = 1.0
+#        SUPPORTED_ARCHITECTURES    = IA32|X64|IPF|EBC
+        EDK_RELEASE_VERSION        = 0x00020000
+        EFI_SPECIFICATION_VERSION  = 0x00020000
+        ENTRY_POINT                = DxeInitializeVBoxFs
+        UNLOAD_IMAGE               = DxeUninitializeVBoxFs
+
+[Sources.common]
+        VBoxFsDxe.c
+
+[Packages]
+        MdePkg/MdePkg.dec
+        IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+        VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+   UefiRuntimeServicesTableLib
+   UefiBootServicesTableLib
+   MemoryAllocationLib
+   BaseMemoryLib
+   BaseLib
+   UefiLib
+   UefiDriverEntryPoint
+   DebugLib
+   PcdLib
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
+  gEfiFileSystemVolumeLabelInfoIdGuid
+
+
+[Protocols]
+  gEfiDiskIoProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiUnicodeCollationProtocolGuid
+  gEfiUnicodeCollation2ProtocolGuid
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFswParam.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFswParam.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxFswParam.h	(revision 29125)
@@ -0,0 +1,68 @@
+/* $Id$ */
+/** @file
+ * VBoxFswParam.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VBOXFSPARAM_H
+#define VBOXFSPARAM_H
+/*
+ * Here is common declarations for EDK<->EDK2 compatibility
+ */
+# include <Uefi.h>
+# include <Library/DebugLib.h>
+# include <Library/BaseLib.h>
+# include <Protocol/DriverBinding.h>
+# include <Library/BaseMemoryLib.h>
+# include <Library/UefiRuntimeServicesTableLib.h>
+# include <Library/UefiDriverEntryPoint.h>
+# include <Library/UefiBootServicesTableLib.h>
+# include <Library/MemoryAllocationLib.h>
+# include <Library/DevicePathLib.h>
+# include <Protocol/DevicePathFromText.h>
+# include <Protocol/DevicePathToText.h>
+# include <Protocol/DebugPort.h>
+# include <Protocol/DebugSupport.h>
+# include <Library/PrintLib.h>
+# include <Library/UefiLib.h>
+# include <Protocol/SimpleFileSystem.h>
+# include <Protocol/BlockIo.h>
+# include <Protocol/DiskIo.h>
+# include <Guid/FileSystemInfo.h>
+# include <Guid/FileInfo.h>
+# include <Guid/FileSystemVolumeLabelInfo.h>
+# include <Protocol/ComponentName.h>
+
+# define BS gBS
+# define PROTO_NAME(x) gEfi ## x ## Guid
+# define GUID_NAME(x) gEfi ## x ## Guid
+
+# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
+# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO  SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d)
+# define DivU64x32(x,y,z) DivU64x32((x),(y))
+
+
+INTN CompareGuidEdk1(
+  IN EFI_GUID     *Guid1,
+  IN EFI_GUID     *Guid2
+                     );
+
+//#define CompareGuid(x, y) CompareGuidEdk1((x),(y))
+# define HOST_EFI 1
+//# define FSW_DEBUG_LEVEL 3
+
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len);
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxHfs.inf
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxHfs.inf	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxHfs.inf	(revision 29125)
@@ -0,0 +1,73 @@
+# $Id$
+## @file
+# VBoxHfs - VBox HFS FS driver.
+#
+
+#
+# Copyright (C) 2010 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+[Defines]
+        INF_VERSION                = 0x00010005
+        BASE_NAME                  = VBoxHfs
+        FILE_GUID                  = 6E506CC2-65E0-4814-994A-08ECDA046987
+        MODULE_TYPE                = UEFI_DRIVER
+        VERSION_STRING             = 1.0
+        EDK_RELEASE_VERSION        = 0x00020000
+        EFI_SPECIFICATION_VERSION  = 0x00020000
+
+        ENTRY_POINT                = fsw_efi_main
+
+[Sources.common]
+        fsw_hfs.c
+        fsw_core.c
+        fsw_efi_lib.c
+        fsw_efi.c
+        fsw_lib.c
+
+[Packages]
+        MdePkg/MdePkg.dec
+        IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+        VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+   UefiRuntimeServicesTableLib
+   UefiBootServicesTableLib
+   MemoryAllocationLib
+   BaseMemoryLib
+   BaseLib
+   UefiLib
+   UefiDriverEntryPoint
+   DebugLib
+   PcdLib
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
+  gEfiFileSystemVolumeLabelInfoIdGuid
+
+[Protocols]
+  gEfiDiskIoProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiUnicodeCollationProtocolGuid
+  gEfiUnicodeCollation2ProtocolGuid
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+
+[BuildOptions.common]
+  GCC:*_*_*_CC_FLAGS = -DFSTYPE=hfs
+# -DFSW_DEBUG_LEVEL=3
+  INTEL:*_*_*_CC_FLAGS = -DFSTYPE=hfs
+  MSFT:*_*_*_CC_FLAGS = -DFSTYPE=hfs
+
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf	(revision 29125)
@@ -0,0 +1,74 @@
+# $Id$
+## @file
+# VBox ISO9660 FS driver
+
+#
+# Copyright (C) 2010 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+[Defines]
+        INF_VERSION                = 0x00010005
+        BASE_NAME                  = VBoxIso9600
+        FILE_GUID                  = B34E57EE-2E02-4DAF-867F-7F40BE6FC33D
+        MODULE_TYPE                = UEFI_DRIVER
+        VERSION_STRING             = 1.0
+        EDK_RELEASE_VERSION        = 0x00020000
+        EFI_SPECIFICATION_VERSION  = 0x00020000
+        ENTRY_POINT                = fsw_efi_main
+
+[Sources.common]
+        fsw_iso9660.c
+        fsw_core.c
+        fsw_efi_lib.c
+        fsw_efi.c
+        fsw_lib.c
+
+[Packages]
+        MdePkg/MdePkg.dec
+        IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+        VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+   UefiRuntimeServicesTableLib
+   UefiBootServicesTableLib
+   MemoryAllocationLib
+   BaseMemoryLib
+   BaseLib
+   UefiLib
+   UefiDriverEntryPoint
+   DebugLib
+   PcdLib
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
+  gEfiFileSystemVolumeLabelInfoIdGuid
+
+
+[Protocols]
+  gEfiDiskIoProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiUnicodeCollationProtocolGuid
+  gEfiUnicodeCollation2ProtocolGuid
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+
+[BuildOptions.common]
+  GCC:*_*_*_CC_FLAGS = -DFSTYPE=iso9660
+
+  INTEL:*_*_*_CC_FLAGS = -DFSTYPE=iso9660
+
+  MSFT:*_*_*_CC_FLAGS = -DFSTYPE=iso9660
+
+  
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_base.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_base.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_base.h	(revision 29125)
@@ -0,0 +1,175 @@
+/* $Id$ */
+/** @file
+ * fsw_base.h - Base definitions switch.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_BASE_H_
+#define _FSW_BASE_H_
+
+#ifdef VBOX
+#include "VBoxFswParam.h"
+#endif
+
+#ifndef FSW_DEBUG_LEVEL
+/**
+ * Global debugging level. Can be set locally for the scope of a single
+ * file by defining the macro before fsw_base.h is included.
+ */
+#define FSW_DEBUG_LEVEL 1
+#endif
+
+
+#ifdef HOST_EFI
+#include "fsw_efi_base.h"
+#endif
+
+#ifdef HOST_POSIX
+#include "fsw_posix_base.h"
+#endif
+
+// message printing
+
+#if FSW_DEBUG_LEVEL >= 1
+#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_ASSERT(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 2
+#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUG(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 3
+#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUGV(params)
+#endif
+
+
+// Documentation for system-dependent defines
+
+/**
+ * \typedef fsw_s8
+ * Signed 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_u8
+ * Unsigned 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_s16
+ * Signed 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_u16
+ * Unsigned 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_s32
+ * Signed 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_u32
+ * Unsigned 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_s64
+ * Signed 64-bit integer.
+ */
+
+/**
+ * \typedef fsw_u64
+ * Unsigned 64-bit integer.
+ */
+
+
+/**
+ * \def fsw_alloc(size,ptrptr)
+ * Allocate memory on the heap. This function or macro allocates \a size
+ * bytes of memory using host-specific methods. The address of the
+ * allocated memory block is stored into the pointer variable pointed
+ * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block
+ * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory
+ * to allocated the requested block.
+ */
+
+/**
+ * \def fsw_free(ptr)
+ * Release allocated memory. This function or macro returns an allocated
+ * memory block to the heap for reuse. Does not return a status.
+ */
+
+/**
+ * \def fsw_memcpy(dest,src,size)
+ * Copies a block of memory from \a src to \a dest. The two memory blocks
+ * must not overlap, or the result of the operation will be undefined.
+ * Does not return a status.
+ */
+
+/**
+ * \def fsw_memeq(dest,src,size)
+ * Compares two blocks of memory for equality. Returns boolean true if the
+ * memory blocks are equal, boolean false if they are different.
+ */
+
+/**
+ * \def fsw_memzero(dest,size)
+ * Initializes a block of memory with zeros. Does not return a status.
+ */
+
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_core.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_core.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_core.c	(revision 29125)
@@ -0,0 +1,932 @@
+/* $Id$ */
+/** @file
+ * fsw_core.c - Core file system wrapper abstraction layer code.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+
+// functions
+
+static void fsw_blockcache_free(struct fsw_volume *vol);
+
+#define MAX_CACHE_LEVEL (5)
+
+
+/**
+ * Mount a volume with a given file system driver. This function is called by the
+ * host driver to make a volume accessible. The file system driver to use is specified
+ * by a pointer to its dispatch table. The file system driver will look at the
+ * data on the volume to determine if it can read the format. If the volume is found
+ * unsuitable, FSW_UNSUPPORTED is returned.
+ *
+ * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data
+ * structure. The caller must release it later by calling fsw_unmount.
+ *
+ * If this function returns an error status, the caller only needs to clean up its
+ * own buffers that may have been allocated through the read_block interface.
+ */
+
+fsw_status_t fsw_mount(void *host_data,
+                       struct fsw_host_table *host_table,
+                       struct fsw_fstype_table *fstype_table,
+                       struct fsw_volume **vol_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol;
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol);
+    if (status)
+        return status;
+
+    // initialize fields
+    vol->phys_blocksize = 512;
+    vol->log_blocksize  = 512;
+    vol->label.type     = FSW_STRING_TYPE_EMPTY;
+    vol->host_data      = host_data;
+    vol->host_table     = host_table;
+    vol->fstype_table   = fstype_table;
+    vol->host_string_type = host_table->native_string_type;
+
+    // let the fs driver mount the file system
+    status = vol->fstype_table->volume_mount(vol);
+    if (status)
+        goto errorexit;
+
+    // TODO: anything else?
+
+    *vol_out = vol;
+    return FSW_SUCCESS;
+
+errorexit:
+    fsw_unmount(vol);
+    return status;
+}
+
+/**
+ * Unmount a volume by releasing all memory associated with it. This function is
+ * called by the host driver when a volume is no longer needed. It is also called
+ * by the core after a failed mount to clean up any allocated memory.
+ *
+ * Note that all dnodes must have been released before calling this function.
+ */
+
+void fsw_unmount(struct fsw_volume *vol)
+{
+    if (vol->root)
+        fsw_dnode_release(vol->root);
+    // TODO: check that no other dnodes are still around
+
+    vol->fstype_table->volume_free(vol);
+
+    fsw_blockcache_free(vol);
+    fsw_strfree(&vol->label);
+    fsw_free(vol);
+}
+
+/**
+ * Get in-depth information on the volume. This function can be called by the host
+ * driver to get additional information on the volume.
+ */
+
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb)
+{
+    return vol->fstype_table->volume_stat(vol, sb);
+}
+
+/**
+ * Set the physical and logical block sizes of the volume. This functions is called by
+ * the file system driver to announce the block sizes it wants to use for accessing
+ * the disk (physical) and for addressing file contents (logical).
+ * Usually both sizes will be the same but there may be file systems that need to access
+ * metadata at a smaller block size than the allocation unit for files.
+ *
+ * Calling this function causes the block cache to be dropped. All pointers returned
+ * from fsw_block_get become invalid. This function should only be called while
+ * mounting the file system, not as a part of file access operations.
+ *
+ * Both sizes are measured in bytes, must be powers of 2, and must not be smaller
+ * than 512 bytes. The logical block size cannot be smaller than the physical block size.
+ */
+
+void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
+{
+    // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
+    //  phys_blocksize.
+
+    // drop core block cache if present
+    fsw_blockcache_free(vol);
+
+    // signal host driver to drop caches etc.
+    vol->host_table->change_blocksize(vol,
+                                      vol->phys_blocksize, vol->log_blocksize,
+                                      phys_blocksize, log_blocksize);
+
+    vol->phys_blocksize = phys_blocksize;
+    vol->log_blocksize = log_blocksize;
+}
+
+/**
+ * Get a block of data from the disk. This function is called by the file system driver
+ * or by core functions. It calls through to the host driver's device access routine.
+ * Given a physical block number, it reads the block into memory (or fetches it from the
+ * block cache) and returns the address of the memory buffer. The caller should provide
+ * an indication of how important the block is in the cache_level parameter. Blocks with
+ * a low level are purged first. Some suggestions for cache levels:
+ *
+ *  - 0: File data
+ *  - 1: Directory data, symlink data
+ *  - 2: File system metadata
+ *  - 3..5: File system metadata with a high rate of access
+ *
+ * If this function returns successfully, the returned data pointer is valid until the
+ * caller calls fsw_block_release.
+ */
+
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out)
+{
+    fsw_status_t    status;
+    fsw_u32         i, discard_level, new_bcache_size;
+    struct fsw_blockcache *new_bcache;
+
+    // TODO: allow the host driver to do its own caching; just call through if
+    //  the appropriate function pointers are set
+
+    if (cache_level > MAX_CACHE_LEVEL)
+        cache_level = MAX_CACHE_LEVEL;
+
+    // check block cache
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == phys_bno) {
+            // cache hit!
+            if (vol->bcache[i].cache_level < cache_level)
+                vol->bcache[i].cache_level = cache_level;  // promote the entry
+            vol->bcache[i].refcount++;
+            *buffer_out = vol->bcache[i].data;
+            return FSW_SUCCESS;
+        }
+    }
+
+    // find a free entry in the cache table
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == FSW_INVALID_BNO)
+            break;
+    }
+    if (i >= vol->bcache_size) {
+        for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) {
+            for (i = 0; i < vol->bcache_size; i++) {
+                if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level)
+                    break;
+            }
+            if (i < vol->bcache_size)
+                break;
+        }
+    }
+    if (i >= vol->bcache_size) {
+        // enlarge / create the cache
+        if (vol->bcache_size < 16)
+            new_bcache_size = 16;
+        else
+            new_bcache_size = vol->bcache_size << 1;
+        status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache);
+        if (status)
+            return status;
+        if (vol->bcache_size > 0)
+            fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache));
+        for (i = vol->bcache_size; i < new_bcache_size; i++) {
+            new_bcache[i].refcount = 0;
+            new_bcache[i].cache_level = 0;
+            new_bcache[i].phys_bno = FSW_INVALID_BNO;
+            new_bcache[i].data = NULL;
+        }
+        i = vol->bcache_size;
+
+        // switch caches
+        if (vol->bcache != NULL)
+            fsw_free(vol->bcache);
+        vol->bcache = new_bcache;
+        vol->bcache_size = new_bcache_size;
+    }
+    vol->bcache[i].phys_bno = FSW_INVALID_BNO;
+
+    // read the data
+    if (vol->bcache[i].data == NULL) {
+        status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data);
+        if (status)
+            return status;
+    }
+    status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data);
+    if (status)
+        return status;
+
+    vol->bcache[i].phys_bno = phys_bno;
+    vol->bcache[i].cache_level = cache_level;
+    vol->bcache[i].refcount = 1;
+    *buffer_out = vol->bcache[i].data;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Releases a disk block. This function must be called to release disk blocks returned
+ * from fsw_block_get.
+ */
+
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer)
+{
+    fsw_u32 i;
+
+    // TODO: allow the host driver to do its own caching; just call through if
+    //  the appropriate function pointers are set
+
+    // update block cache
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0)
+            vol->bcache[i].refcount--;
+    }
+}
+
+/**
+ * Release the block cache. Called internally when changing block sizes and when
+ * unmounting the volume. It frees all data occupied by the generic block cache.
+ */
+
+static void fsw_blockcache_free(struct fsw_volume *vol)
+{
+    fsw_u32 i;
+
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].data != NULL)
+            fsw_free(vol->bcache[i].data);
+    }
+    if (vol->bcache != NULL) {
+        fsw_free(vol->bcache);
+        vol->bcache = NULL;
+    }
+    vol->bcache_size = 0;
+}
+
+/**
+ * Add a new dnode to the list of known dnodes. This internal function is used when a
+ * dnode is created to add it to the dnode list that is used to search for existing
+ * dnodes by id.
+ */
+
+static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno)
+{
+    dno->next = vol->dnode_head;
+    if (vol->dnode_head != NULL)
+        vol->dnode_head->prev = dno;
+    dno->prev = NULL;
+    vol->dnode_head = dno;
+}
+
+/**
+ * Create a dnode representing the root directory. This function is called by the file system
+ * driver while mounting the file system. The root directory is special because it has no parent
+ * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions
+ * behaves in the same way as fsw_dnode_create.
+ */
+
+fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u32 dnode_id, struct fsw_dnode **dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno;
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+    if (status)
+        return status;
+
+    // fill the structure
+    dno->vol = vol;
+    dno->parent = NULL;
+    dno->dnode_id = dnode_id;
+    dno->type = FSW_DNODE_TYPE_DIR;
+    dno->refcount = 1;
+    dno->name.type = FSW_STRING_TYPE_EMPTY;
+    // TODO: instead, call a function to create an empty string in the native string type
+
+    fsw_dnode_register(vol, dno);
+
+    *dno_out = dno;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Create a new dnode representing a file system object. This function is called by
+ * the file system driver in response to directory lookup or read requests. Note that
+ * if there already is a dnode with the given dnode_id on record, then no new object
+ * is created. Instead, the existing dnode is returned and its reference count
+ * increased. All other parameters are ignored in this case.
+ *
+ * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient
+ * to fill the type field during the dnode_fill call.
+ *
+ * The name parameter must describe a string with the object's name. A copy will be
+ * stored in the dnode structure for future reference. The name will not be used to
+ * shortcut directory lookups, but may be used to reconstruct paths.
+ *
+ * If the function returns successfully, *dno_out contains a pointer to the dnode
+ * that must be released by the caller with fsw_dnode_release.
+ */
+
+fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u32 dnode_id, int type,
+                              struct fsw_string *name, struct fsw_dnode **dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = parent_dno->vol;
+    struct fsw_dnode *dno;
+
+    // check if we already have a dnode with the same id
+    for (dno = vol->dnode_head; dno; dno = dno->next) {
+        if (dno->dnode_id == dnode_id) {
+            fsw_dnode_retain(dno);
+            *dno_out = dno;
+            return FSW_SUCCESS;
+        }
+    }
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+    if (status)
+        return status;
+
+    // fill the structure
+    dno->vol = vol;
+    dno->parent = parent_dno;
+    fsw_dnode_retain(dno->parent);
+    dno->dnode_id = dnode_id;
+    dno->type = type;
+    dno->refcount = 1;
+    status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
+    if (status) {
+        fsw_free(dno);
+        return status;
+    }
+
+    fsw_dnode_register(vol, dno);
+
+    *dno_out = dno;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Increases the reference count of a dnode. This must be balanced with
+ * fsw_dnode_release calls. Note that some dnode functions return a retained
+ * dnode pointer to their caller.
+ */
+
+void fsw_dnode_retain(struct fsw_dnode *dno)
+{
+    dno->refcount++;
+}
+
+/**
+ * Release a dnode pointer, deallocating it if this was the last reference.
+ * This function decrements the reference counter of the dnode. If the counter
+ * reaches zero, the dnode is freed. Since the parent dnode is released
+ * during that process, this function may cause it to be freed, too.
+ */
+
+void fsw_dnode_release(struct fsw_dnode *dno)
+{
+    struct fsw_volume *vol = dno->vol;
+    struct fsw_dnode *parent_dno;
+
+    dno->refcount--;
+
+    if (dno->refcount == 0) {
+        parent_dno = dno->parent;
+
+        // de-register from volume's list
+        if (dno->next)
+            dno->next->prev = dno->prev;
+        if (dno->prev)
+            dno->prev->next = dno->next;
+        if (vol->dnode_head == dno)
+            vol->dnode_head = dno->next;
+
+        // run fstype-specific cleanup
+        vol->fstype_table->dnode_free(vol, dno);
+
+        fsw_strfree(&dno->name);
+        fsw_free(dno);
+
+        // release our pointer to the parent, possibly deallocating it, too
+        if (parent_dno)
+            fsw_dnode_release(parent_dno);
+    }
+}
+
+/**
+ * Get full information about a dnode from disk. This function is called by the host
+ * driver as well as by the core functions. Some file systems defer reading full
+ * information on a dnode until it is actually needed (i.e. separation between
+ * directory and inode information). This function makes sure that all information
+ * is available in the dnode structure. The following fields may not have a correct
+ * value until fsw_dnode_fill has been called:
+ *
+ * type, size
+ */
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno)
+{
+    // TODO: check a flag right here, call fstype's dnode_fill only once per dnode
+
+    return dno->vol->fstype_table->dnode_fill(dno->vol, dno);
+}
+
+/**
+ * Get extended information about a dnode. This function can be called by the host
+ * driver to get a full compliment of information about a dnode in addition to the
+ * fields of the fsw_dnode structure itself.
+ *
+ * Some data requires host-specific conversion to be useful (i.e. timestamps) and
+ * will be passed to callback functions instead of being written into the structure.
+ * These callbacks must be filled in by the caller.
+ */
+
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+
+    sb->used_bytes = 0;
+    status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
+    if (!status && !sb->used_bytes)
+        sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
+    return status;
+}
+
+/**
+ * Lookup a directory entry by name. This function is called by the host driver.
+ * Given a directory dnode and a file name, it looks up the named entry in the
+ * directory.
+ *
+ * If the dnode is not a directory, the call will fail. The caller is responsible for
+ * resolving symbolic links before calling this function.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+    if (dno->type != FSW_DNODE_TYPE_DIR)
+        return FSW_UNSUPPORTED;
+
+    return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
+}
+
+/**
+ * Find a file system object by path. This function is called by the host driver.
+ * Given a directory dnode and a relative or absolute path, it walks the directory
+ * tree until it finds the target dnode. If an intermediate node turns out to be
+ * a symlink, it is resolved automatically. If the target node is a symlink, it
+ * is not resolved.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+                                   struct fsw_string *lookup_path, char separator,
+                                   struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = dno->vol;
+    struct fsw_dnode *child_dno = NULL;
+    struct fsw_string lookup_name;
+    struct fsw_string remaining_path;
+    int             root_if_empty;
+
+    remaining_path = *lookup_path;
+    fsw_dnode_retain(dno);
+
+    // loop over the path
+    for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
+        // parse next path component
+        fsw_strsplit(&lookup_name, &remaining_path, separator);
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
+                       lookup_name.len, lookup_name.data,
+                       remaining_path.len, remaining_path.data));
+
+        if (fsw_strlen(&lookup_name) == 0) {        // empty path component
+            if (root_if_empty)
+                child_dno = vol->root;
+            else
+                child_dno = dno;
+            fsw_dnode_retain(child_dno);
+
+        } else {
+            // do an actual directory lookup
+
+            // ensure we have full information
+            status = fsw_dnode_fill(dno);
+            if (status)
+                goto errorexit;
+
+            // resolve symlink if necessary
+            if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
+                status = fsw_dnode_resolve(dno, &child_dno);
+                if (status)
+                    goto errorexit;
+
+                // symlink target becomes the new dno
+                fsw_dnode_release(dno);
+                dno = child_dno;   // is already retained
+                child_dno = NULL;
+
+                // ensure we have full information
+                status = fsw_dnode_fill(dno);
+                if (status)
+                    goto errorexit;
+            }
+
+            // make sure we operate on a directory
+            if (dno->type != FSW_DNODE_TYPE_DIR) {
+                return FSW_UNSUPPORTED;
+                goto errorexit;
+            }
+
+            // check special paths
+            if (fsw_streq_cstr(&lookup_name, ".")) {    // self directory
+                child_dno = dno;
+                fsw_dnode_retain(child_dno);
+
+            } else if (fsw_streq_cstr(&lookup_name, "..")) {   // parent directory
+                if (dno->parent == NULL) {
+                    // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
+                    // rely on this behaviour!
+                    status = FSW_NOT_FOUND;
+                    goto errorexit;
+                }
+                child_dno = dno->parent;
+                fsw_dnode_retain(child_dno);
+
+            } else {
+                // do an actual lookup
+                status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
+                if (status)
+                    goto errorexit;
+            }
+        }
+
+        // child_dno becomes the new dno
+        fsw_dnode_release(dno);
+        dno = child_dno;   // is already retained
+        child_dno = NULL;
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
+    }
+
+    *child_dno_out = dno;
+    return FSW_SUCCESS;
+
+errorexit:
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
+    fsw_dnode_release(dno);
+    if (child_dno != NULL)
+        fsw_dnode_release(child_dno);
+    return status;
+}
+
+/**
+ * Get the next directory item in sequential order. This function is called by the
+ * host driver to read the complete contents of a directory in sequential (file system
+ * defined) order. Calling this function returns the next entry. Iteration state is
+ * kept by a shandle on the directory's dnode. The caller must set up the shandle
+ * when starting the iteration.
+ *
+ * When the end of the directory is reached, this function returns FSW_NOT_FOUND.
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno = shand->dnode;
+    fsw_u64         saved_pos;
+
+    if (dno->type != FSW_DNODE_TYPE_DIR)
+        return FSW_UNSUPPORTED;
+
+    saved_pos = shand->pos;
+    status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out);
+    if (status)
+        shand->pos = saved_pos;
+    return status;
+}
+
+/**
+ * Read the target path of a symbolic link. This function is called by the host driver
+ * to read the "content" of a symbolic link, that is the relative or absolute path
+ * it points to.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+    if (dno->type != FSW_DNODE_TYPE_SYMLINK)
+        return FSW_UNSUPPORTED;
+
+    return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
+}
+
+/**
+ * Read the target path of a symbolic link by accessing file data. This function can
+ * be called by the file system driver if the file system stores the target path
+ * as normal file data. This function will open an shandle, read the whole content
+ * of the file into a buffer, and build a string from that. Currently the encoding
+ * for the string is fixed as FSW_STRING_TYPE_ISO88591.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    fsw_u32         buffer_size;
+    char            buffer[FSW_PATH_MAX];
+
+    struct fsw_string s;
+
+    if (dno->size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = (int)dno->size;
+    s.data = buffer;
+
+    // open shandle and read the data
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+    buffer_size = (fsw_u32)s.size;
+    status = fsw_shandle_read(&shand, &buffer_size, buffer);
+    fsw_shandle_close(&shand);
+    if (status)
+        return status;
+    if ((int)buffer_size < s.size)
+        return FSW_VOLUME_CORRUPTED;
+
+    status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
+    return status;
+}
+
+/**
+ * Resolve a symbolic link. This function can be called by the host driver to make
+ * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode
+ * passed in is not a symlink, it is returned unmodified.
+ *
+ * Note that absolute paths will be resolved relative to the root directory of the
+ * volume. If the host is an operating system with its own VFS layer, it should
+ * resolve symlinks on its own.
+ *
+ * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is
+ * not a symlink. The caller is responsible for calling fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_string target_name;
+    struct fsw_dnode *target_dno;
+
+    fsw_dnode_retain(dno);
+
+    while (1) {
+        // get full information
+        status = fsw_dnode_fill(dno);
+        if (status)
+            goto errorexit;
+        if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
+            // found a non-symlink target, return it
+            *target_dno_out = dno;
+            return FSW_SUCCESS;
+        }
+        if (dno->parent == NULL) {    // safety measure, cannot happen in theory
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // read the link's target
+        status = fsw_dnode_readlink(dno, &target_name);
+        if (status)
+            goto errorexit;
+
+        // resolve it
+        status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
+        fsw_strfree(&target_name);
+        if (status)
+            goto errorexit;
+
+        // target_dno becomes the new dno
+        fsw_dnode_release(dno);
+        dno = target_dno;   // is already retained
+    }
+
+errorexit:
+    fsw_dnode_release(dno);
+    return status;
+}
+
+/**
+ * Set up a shandle (storage handle) to access a file's data. This function is called
+ * by the host driver and by the core when they need to access a file's data. It is also
+ * used in accessing the raw data of directories and symlinks if the file system uses
+ * the same mechanisms for storing the data of those items.
+ *
+ * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos
+ * fields may be accessed, pos may also be written to to set the file pointer. The file's
+ * data size is available as shand->dnode->size.
+ *
+ * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
+ * the dnode reference held by the shandle.
+ */
+
+fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = dno->vol;
+
+    // read full dnode information into memory
+    status = vol->fstype_table->dnode_fill(vol, dno);
+    if (status)
+        return status;
+
+    // setup shandle
+    fsw_dnode_retain(dno);
+
+    shand->dnode = dno;
+    shand->pos = 0;
+    shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Close a shandle after accessing the dnode's data. This function is called by the host
+ * driver or core functions when they are finished with accessing a file's data. It
+ * releases the dnode reference and frees any buffers associated with the shandle itself.
+ * The dnode is only released if this was the last reference using it.
+ */
+
+void fsw_shandle_close(struct fsw_shandle *shand)
+{
+    if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+        fsw_free(shand->extent.buffer);
+    fsw_dnode_release(shand->dnode);
+}
+
+/**
+ * Read data from a shandle (storage handle for a dnode). This function is called by the
+ * host driver or internally when data is read from a file. TODO: more
+ */
+
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno = shand->dnode;
+    struct fsw_volume *vol = dno->vol;
+    fsw_u8          *buffer, *block_buffer;
+    fsw_u32         buflen, copylen, pos;
+    fsw_u32         log_bno, pos_in_extent, phys_bno, pos_in_physblock;
+    fsw_u32         cache_level;
+
+    if (shand->pos >= dno->size) {   // already at EOF
+        *buffer_size_inout = 0;
+        return FSW_SUCCESS;
+    }
+
+    // initialize vars
+    buffer = buffer_in;
+    buflen = *buffer_size_inout;
+    pos = (fsw_u32)shand->pos;
+    cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
+    // restrict read to file size
+    if (buflen > dno->size - pos)
+        buflen = (fsw_u32)(dno->size - pos);
+
+    while (buflen > 0) {
+        // get extent for the current logical block
+        log_bno = pos / vol->log_blocksize;
+        if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
+            log_bno < shand->extent.log_start ||
+            log_bno >= shand->extent.log_start + shand->extent.log_count) {
+
+            if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+                fsw_free(shand->extent.buffer);
+
+            // ask the file system for the proper extent
+            shand->extent.log_start = log_bno;
+            status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
+            if (status) {
+                shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+                return status;
+            }
+        }
+
+        pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;
+
+        // dispatch by extent type
+        if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
+            // convert to physical block number and offset
+            phys_bno = shand->extent.phys_start + pos_in_extent / vol->phys_blocksize;
+            pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
+            copylen = vol->phys_blocksize - pos_in_physblock;
+            if (copylen > buflen)
+                copylen = buflen;
+
+            // get one physical block
+            status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
+            if (status)
+                return status;
+
+            // copy data from it
+            fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
+            fsw_block_release(vol, phys_bno, block_buffer);
+
+        } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
+            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+            if (copylen > buflen)
+                copylen = buflen;
+            fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);
+
+        } else {   // _SPARSE or _INVALID
+            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+            if (copylen > buflen)
+                copylen = buflen;
+            fsw_memzero(buffer, copylen);
+
+        }
+
+        buffer += copylen;
+        buflen -= copylen;
+        pos    += copylen;
+    }
+
+    *buffer_size_inout = (fsw_u32)(pos - shand->pos);
+    shand->pos = pos;
+
+    return FSW_SUCCESS;
+}
+
+// EOF
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_core.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_core.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_core.h	(revision 29125)
@@ -0,0 +1,537 @@
+/* $Id$ */
+/** @file
+ * fsw_core.h - Core file system wrapper abstraction layer header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) The Regents of the University of California.
+ * Portions Copyright (c) UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_CORE_H_
+#define _FSW_CORE_H_
+
+#include "fsw_base.h"
+
+
+/** Maximum size for a path, specifically symlink target paths. */
+#ifndef VBOX
+#define FSW_PATH_MAX (4096)
+#else
+/* Too big allocations are handled with alloca() */
+#define FSW_PATH_MAX (2048)
+#endif
+
+/** Helper macro for token concatenation. */
+#define FSW_CONCAT3(a,b,c) a##b##c
+/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */
+#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table)
+
+/** Indicates that the block cache entry is empty. */
+#define FSW_INVALID_BNO (~0UL)
+
+
+//
+// Byte-swapping macros
+//
+
+
+/**
+ * \name Byte Order Macros
+ * Implements big endian vs. little endian awareness and conversion.
+ */
+/*@{*/
+
+typedef fsw_u16             fsw_u16_le;
+typedef fsw_u16             fsw_u16_be;
+typedef fsw_u32             fsw_u32_le;
+typedef fsw_u32             fsw_u32_be;
+typedef fsw_u64             fsw_u64_le;
+typedef fsw_u64             fsw_u64_be;
+
+#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \
+                              (((fsw_u16)(v) & 0x00ff) << 8))
+#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \
+                              (((fsw_u32)(v) & 0x00ff0000UL) >> 8)  | \
+                              (((fsw_u32)(v) & 0x0000ff00UL) << 8)  | \
+                              (((fsw_u32)(v) & 0x000000ffUL) << 24))
+#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \
+                              (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \
+                              (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \
+                              (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8)  | \
+                              (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8)  | \
+                              (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \
+                              (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \
+                              (((fsw_u64)(v) & 0x00000000000000ffULL) << 56))
+
+#ifdef FSW_LITTLE_ENDIAN
+
+#define fsw_u16_le_swap(v) (v)
+#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u32_le_swap(v) (v)
+#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u64_le_swap(v) (v)
+#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v)
+
+#define fsw_u16_le_sip(var)
+#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u32_le_sip(var)
+#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u64_le_sip(var)
+#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var))
+
+#else
+#ifdef FSW_BIG_ENDIAN
+
+#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u16_be_swap(v) (v)
+#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u32_be_swap(v) (v)
+#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v)
+#define fsw_u64_be_swap(v) (v)
+
+#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u16_be_sip(var)
+#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u32_be_sip(var)
+#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var))
+#define fsw_u64_be_sip(var)
+
+#else
+#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined
+#endif
+#endif
+
+/*@}*/
+
+
+//
+// The following evil hack avoids a lot of casts between generic and fstype-specific
+// structures.
+//
+
+#ifndef VOLSTRUCTNAME
+#define VOLSTRUCTNAME fsw_volume
+#else
+struct VOLSTRUCTNAME;
+#endif
+#ifndef DNODESTRUCTNAME
+#define DNODESTRUCTNAME fsw_dnode
+#else
+struct DNODESTRUCTNAME;
+#endif
+
+
+/**
+ * Status code type, returned from all functions that can fail.
+ */
+typedef int fsw_status_t;
+
+/**
+ * Possible status codes.
+ */
+enum {
+    FSW_SUCCESS,
+    FSW_OUT_OF_MEMORY,
+    FSW_IO_ERROR,
+    FSW_UNSUPPORTED,
+    FSW_NOT_FOUND,
+    FSW_VOLUME_CORRUPTED,
+    FSW_UNKNOWN_ERROR
+};
+
+
+/**
+ * Core: A string with explicit length and encoding information.
+ */
+
+struct fsw_string {
+    int         type;               //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16
+    int         len;                //!< Length in characters
+    int         size;               //!< Total data size in bytes
+    void        *data;              //!< Data pointer (may be NULL if type is EMPTY or len is zero)
+};
+
+/**
+ * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY,
+ * all other members of the fsw_string structure may be invalid.
+ */
+enum {
+    FSW_STRING_TYPE_EMPTY,
+    FSW_STRING_TYPE_ISO88591,
+    FSW_STRING_TYPE_UTF8,
+    FSW_STRING_TYPE_UTF16,
+    FSW_STRING_TYPE_UTF16_SWAPPED
+};
+
+#ifdef FSW_LITTLE_ENDIAN
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED
+#else
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16
+#endif
+
+/** Static initializer for an empty string. */
+#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL }
+
+
+/* forward declarations */
+
+struct fsw_dnode;
+struct fsw_host_table;
+struct fsw_fstype_table;
+
+struct fsw_blockcache {
+    fsw_u32     refcount;           //!< Reference count
+    fsw_u32     cache_level;        //!< Level of importance of this block
+    fsw_u32     phys_bno;           //!< Physical block number
+    void        *data;              //!< Block data buffer
+};
+
+/**
+ * Core: Represents a mounted volume.
+ */
+
+struct fsw_volume {
+    fsw_u32     phys_blocksize;     //!< Block size for disk access / file system structures
+    fsw_u32     log_blocksize;      //!< Block size for logical file data
+
+    struct DNODESTRUCTNAME *root;   //!< Root directory dnode
+    struct fsw_string label;        //!< Volume label
+
+    struct fsw_dnode *dnode_head;   //!< List of all dnodes allocated for this volume
+
+    struct fsw_blockcache *bcache;  //!< Array of block cache entries
+    fsw_u32     bcache_size;        //!< Number of entries in the block cache array
+
+    void        *host_data;         //!< Hook for a host-specific data structure
+    struct fsw_host_table *host_table;      //!< Dispatch table for host-specific functions
+    struct fsw_fstype_table *fstype_table;  //!< Dispatch table for file system specific functions
+    int         host_string_type;   //!< String type used by the host environment
+};
+
+/**
+ * Core: Represents a "directory node" - a file, directory, symlink, whatever.
+ */
+
+struct fsw_dnode {
+    fsw_u32     refcount;           //!< Reference count
+
+    struct VOLSTRUCTNAME *vol;      //!< The volume this dnode belongs to
+    struct DNODESTRUCTNAME *parent; //!< Parent directory dnode
+    struct fsw_string name;         //!< Name of this item in the parent directory
+
+    fsw_u32     dnode_id;           //!< Unique id number (usually the inode number)
+    int         type;               //!< Type of the dnode - file, dir, symlink, special
+    fsw_u64     size;               //!< Data size in bytes
+
+    struct fsw_dnode *next;         //!< Doubly-linked list of all dnodes: previous dnode
+    struct fsw_dnode *prev;         //!< Doubly-linked list of all dnodes: next dnode
+};
+
+/**
+ * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before
+ * fsw_dnode_fill has been called on the dnode.
+ */
+enum {
+    FSW_DNODE_TYPE_UNKNOWN,
+    FSW_DNODE_TYPE_FILE,
+    FSW_DNODE_TYPE_DIR,
+    FSW_DNODE_TYPE_SYMLINK,
+    FSW_DNODE_TYPE_SPECIAL
+};
+
+/**
+ * Core: Stores the mapping of a region of a file to the data on disk.
+ */
+
+struct fsw_extent {
+    int         type;               //!< Type of extent specification
+    fsw_u32     log_start;          //!< Starting logical block number
+    fsw_u32     log_count;          //!< Logical block count
+    fsw_u32     phys_start;         //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
+    void        *buffer;            //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only)
+};
+
+/**
+ * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's
+ * internal use only, it must not be returned from a get_extent function.
+ */
+enum {
+    FSW_EXTENT_TYPE_INVALID,
+    FSW_EXTENT_TYPE_SPARSE,
+    FSW_EXTENT_TYPE_PHYSBLOCK,
+    FSW_EXTENT_TYPE_BUFFER
+};
+
+/**
+ * Core: An access structure to a dnode's raw data. There can be multiple
+ * shandles per dnode, each of them has its own position pointer.
+ */
+
+struct fsw_shandle {
+    struct fsw_dnode *dnode;        //!< The dnode this handle reads data from
+
+    fsw_u64     pos;                //!< Current file pointer in bytes
+    struct fsw_extent extent;       //!< Current extent
+};
+
+/**
+ * Core: Used in gathering detailed information on a volume.
+ */
+
+struct fsw_volume_stat {
+    fsw_u64     total_bytes;        //!< Total size of data area size in bytes
+    fsw_u64     free_bytes;         //!< Bytes still available for storing file data
+};
+
+/**
+ * Core: Used in gathering detailed information on a dnode.
+ */
+
+struct fsw_dnode_stat {
+    fsw_u64     used_bytes;         //!< Bytes actually used by the file on disk
+    void        (*store_time_posix)(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time);   //!< Callback for storing a Posix-style timestamp
+    void        (*store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 posix_mode);   //!< Callbock for storing a Posix-style file mode
+    void        *host_data;         //!< Hook for a host-specific data structure
+};
+
+/**
+ * Type of the timestamp passed into store_time_posix.
+ */
+enum {
+    FSW_DNODE_STAT_CTIME,
+    FSW_DNODE_STAT_MTIME,
+    FSW_DNODE_STAT_ATIME
+};
+
+/**
+ * Core: Function table for a host environment.
+ */
+
+struct fsw_host_table
+{
+    int         native_string_type; //!< String type used by the host environment
+
+    void         (*change_blocksize)(struct fsw_volume *vol,
+                                     fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                                     fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+    fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+};
+
+/**
+ * Core: Function table for a file system driver.
+ */
+
+struct fsw_fstype_table
+{
+    struct fsw_string name;         //!< String giving the name of the file system
+    fsw_u32     volume_struct_size; //!< Size for allocating the fsw_volume structure
+    fsw_u32     dnode_struct_size;  //!< Size for allocating the fsw_dnode structure
+
+    fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol);
+    void         (*volume_free)(struct VOLSTRUCTNAME *vol);
+    fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb);
+
+    fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+    void         (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+    fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_dnode_stat *sb);
+    fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_extent *extent);
+
+    fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno);
+    fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                             struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno);
+    fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                             struct fsw_string *link_target);
+};
+
+
+/**
+ * \name Volume Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_mount(void *host_data,
+                       struct fsw_host_table *host_table,
+                       struct fsw_fstype_table *fstype_table,
+                       struct fsw_volume **vol_out);
+void         fsw_unmount(struct fsw_volume *vol);
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb);
+
+void         fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize);
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out);
+void         fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name dnode Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u32 dnode_id, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u32 dnode_id, int type,
+                              struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
+void         fsw_dnode_retain(struct fsw_dnode *dno);
+void         fsw_dnode_release(struct fsw_dnode *dno);
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno);
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb);
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+                                   struct fsw_string *lookup_path, char separator,
+                                   struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out);
+
+/*@}*/
+
+
+/**
+ * \name shandle Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand);
+void         fsw_shandle_close(struct fsw_shandle *shand);
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name Memory Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out);
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len);
+
+/*@}*/
+
+
+/**
+ * \name String Functions
+ */
+/*@{*/
+
+int          fsw_strlen(struct fsw_string *s);
+int          fsw_streq(struct fsw_string *s1, struct fsw_string *s2);
+int          fsw_streq_cstr(struct fsw_string *s1, const char *s2);
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src);
+void         fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator);
+
+void         fsw_strfree(struct fsw_string *s);
+fsw_u16      fsw_to_lower(fsw_u16 ch);
+
+/*@}*/
+
+
+/**
+ * \name Posix Mode Macros
+ * These macros can be used globally to test fields and bits in
+ * Posix-style modes.
+ *
+ * Taken from FreeBSD sys/stat.h.
+ */
+/*@{*/
+#ifndef S_IRWXU
+
+#define	S_ISUID	0004000			/* set user id on execution */
+#define	S_ISGID	0002000			/* set group id on execution */
+#define	S_ISTXT	0001000			/* sticky bit */
+
+#define	S_IRWXU	0000700			/* RWX mask for owner */
+#define	S_IRUSR	0000400			/* R for owner */
+#define	S_IWUSR	0000200			/* W for owner */
+#define	S_IXUSR	0000100			/* X for owner */
+
+#define	S_IRWXG	0000070			/* RWX mask for group */
+#define	S_IRGRP	0000040			/* R for group */
+#define	S_IWGRP	0000020			/* W for group */
+#define	S_IXGRP	0000010			/* X for group */
+
+#define	S_IRWXO	0000007			/* RWX mask for other */
+#define	S_IROTH	0000004			/* R for other */
+#define	S_IWOTH	0000002			/* W for other */
+#define	S_IXOTH	0000001			/* X for other */
+
+#define	S_IFMT	 0170000		/* type of file mask */
+#define	S_IFIFO	 0010000		/* named pipe (fifo) */
+#define	S_IFCHR	 0020000		/* character special */
+#define	S_IFDIR	 0040000		/* directory */
+#define	S_IFBLK	 0060000		/* block special */
+#define	S_IFREG	 0100000		/* regular */
+#define	S_IFLNK	 0120000		/* symbolic link */
+#define	S_IFSOCK 0140000		/* socket */
+#define	S_ISVTX	 0001000		/* save swapped text even after use */
+#define	S_IFWHT  0160000		/* whiteout */
+
+#define	S_ISDIR(m)	(((m) & 0170000) == 0040000)	/* directory */
+#define	S_ISCHR(m)	(((m) & 0170000) == 0020000)	/* char special */
+#define	S_ISBLK(m)	(((m) & 0170000) == 0060000)	/* block special */
+#define	S_ISREG(m)	(((m) & 0170000) == 0100000)	/* regular file */
+#define	S_ISFIFO(m)	(((m) & 0170000) == 0010000)	/* fifo or socket */
+#define	S_ISLNK(m)	(((m) & 0170000) == 0120000)	/* symbolic link */
+#define	S_ISSOCK(m)	(((m) & 0170000) == 0140000)	/* socket */
+#define	S_ISWHT(m)	(((m) & 0170000) == 0160000)	/* whiteout */
+
+#define S_BLKSIZE	512		/* block size used in the stat struct */
+
+#endif
+/*@}*/
+
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.c	(revision 29125)
@@ -0,0 +1,1062 @@
+/* $Id$ */
+/** @file
+ * fsw_efi.c - EFI host environment code.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+#define DEBUG_LEVEL 0
+
+#ifndef FSTYPE
+#ifdef VBOX
+#error FSTYPE must be defined!
+#else
+#define FSTYPE ext2
+#endif
+#endif
+
+/** Helper macro for stringification. */
+#define FSW_EFI_STRINGIFY(x) L#x
+/** Expands to the EFI driver name given the file system type name. */
+#define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System Driver"
+
+// function prototypes
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                                  IN EFI_HANDLE                   ControllerHandle,
+                                                  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                              IN EFI_HANDLE                   ControllerHandle,
+                                              IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                             IN  EFI_HANDLE                   ControllerHandle,
+                                             IN  UINTN                        NumberOfChildren,
+                                             IN  EFI_HANDLE                   *ChildHandleBuffer);
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+                                                      IN  CHAR8                        *Language,
+                                                      OUT CHAR16                       **DriverName);
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN  EFI_COMPONENT_NAME_PROTOCOL    *This,
+                                                          IN  EFI_HANDLE                     ControllerHandle,
+                                                          IN  EFI_HANDLE                     ChildHandle  OPTIONAL,
+                                                          IN  CHAR8                          *Language,
+                                                          OUT CHAR16                         **ControllerName);
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+                                                OUT EFI_FILE **Root);
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+                                       OUT EFI_FILE **NewFileHandle);
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+                             IN OUT UINTN *BufferSize,
+                             OUT VOID *Buffer);
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+                               OUT UINT64 *Position);
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+                               IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+                            OUT EFI_FILE **NewHandle,
+                            IN CHAR16 *FileName,
+                            IN UINT64 OpenMode,
+                            IN UINT64 Attributes);
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+                            IN OUT UINTN *BufferSize,
+                            OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+                              IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+                                 IN EFI_GUID *InformationType,
+                                 IN OUT UINTN *BufferSize,
+                                 OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer);
+
+/**
+ * Interface structure for the EFI Driver Binding protocol.
+ */
+
+EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
+    fsw_efi_DriverBinding_Supported,
+    fsw_efi_DriverBinding_Start,
+    fsw_efi_DriverBinding_Stop,
+    0x10,
+    NULL,
+    NULL
+};
+
+/**
+ * Interface structure for the EFI Component Name protocol.
+ */
+
+EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
+    fsw_efi_ComponentName_GetDriverName,
+    fsw_efi_ComponentName_GetControllerName,
+    "eng"
+};
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table   fsw_efi_host_table = {
+    FSW_STRING_TYPE_UTF16,
+
+    fsw_efi_change_blocksize,
+    fsw_efi_read_block
+};
+
+extern struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+
+/**
+ * Image entry point. Installs the Driver Binding and Component Name protocols
+ * on the image's handle. Actually mounting a file system is initiated through
+ * the Driver Binding protocol at the firmware's request.
+ */
+EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE         ImageHandle,
+                               IN EFI_SYSTEM_TABLE   *SystemTable)
+{
+    EFI_STATUS  Status;
+
+#ifndef VBOX
+    InitializeLib(ImageHandle, SystemTable);
+#endif
+
+    // complete Driver Binding protocol instance
+    fsw_efi_DriverBinding_table.ImageHandle          = ImageHandle;
+    fsw_efi_DriverBinding_table.DriverBindingHandle  = ImageHandle;
+    // install Driver Binding protocol
+    Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+                                          &PROTO_NAME(DriverBindingProtocol),
+                                          EFI_NATIVE_INTERFACE,
+                                          &fsw_efi_DriverBinding_table);
+    if (EFI_ERROR (Status)) {
+        return Status;
+    }
+
+    // install Component Name protocol
+    Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+                                          &PROTO_NAME(ComponentNameProtocol),
+                                          EFI_NATIVE_INTERFACE,
+                                          &fsw_efi_ComponentName_table);
+    if (EFI_ERROR (Status)) {
+        return Status;
+    }
+
+    return EFI_SUCCESS;
+}
+
+/**
+ * Driver Binding EFI protocol, Supported function. This function is called by EFI
+ * to test if this driver can handle a certain device. Our implementation only checks
+ * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
+ * and implicitly checks if the disk is already in use by another driver.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                                  IN EFI_HANDLE                   ControllerHandle,
+                                                  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath)
+{
+    EFI_STATUS          Status;
+    EFI_DISK_IO         *DiskIo;
+
+    // we check for both DiskIO and BlockIO protocols
+
+    // first, open DiskIO
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(DiskIoProtocol),
+                              (VOID **) &DiskIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // we were just checking, close it again
+    BS->CloseProtocol(ControllerHandle,
+                      &PROTO_NAME(DiskIoProtocol),
+                      This->DriverBindingHandle,
+                      ControllerHandle);
+
+    // next, check BlockIO without actually opening it
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(BlockIoProtocol),
+                              NULL,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+    return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Start function. This function is called by EFI
+ * to start driving the given device. It is still possible at this point to
+ * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
+ * cannot find the superblock signature (or equivalent) that it expects.
+ *
+ * This function allocates memory for a per-volume structure, opens the
+ * required protocols (just Disk I/O in our case, Block I/O is only looked
+ * at to get the MediaId field), and lets the FSW core mount the file system.
+ * If successful, an EFI Simple File System protocol is exported on the
+ * device handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                              IN EFI_HANDLE                   ControllerHandle,
+                                              IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath)
+{
+    EFI_STATUS          Status;
+    EFI_BLOCK_IO        *BlockIo;
+    EFI_DISK_IO         *DiskIo;
+    FSW_VOLUME_DATA     *Volume;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Start\n");
+#endif
+
+    // open consumed protocols
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(BlockIoProtocol),
+                              (VOID **) &BlockIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);   // NOTE: we only want to look at the MediaId
+    if (EFI_ERROR(Status)) {
+        Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
+        return Status;
+    }
+
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(DiskIoProtocol),
+                              (VOID **) &DiskIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+    if (EFI_ERROR(Status)) {
+        Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status);
+        return Status;
+    }
+
+    // allocate volume structure
+    Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
+    Volume->Signature       = FSW_VOLUME_DATA_SIGNATURE;
+    Volume->Handle          = ControllerHandle;
+    Volume->DiskIo          = DiskIo;
+    Volume->MediaId         = BlockIo->Media->MediaId;
+    Volume->LastIOStatus    = EFI_SUCCESS;
+
+    // mount the filesystem
+    Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table,
+                                          &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol),
+                                Volume);
+
+    if (!EFI_ERROR(Status)) {
+        // register the SimpleFileSystem protocol
+        Volume->FileSystem.Revision     = EFI_FILE_IO_INTERFACE_REVISION;
+        Volume->FileSystem.OpenVolume   = fsw_efi_FileSystem_OpenVolume;
+        Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+                                                       &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
+                                                       NULL);
+        if (EFI_ERROR(Status))
+            Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
+    }
+
+    // on errors, close the opened protocols
+    if (EFI_ERROR(Status)) {
+        if (Volume->vol != NULL)
+            fsw_unmount(Volume->vol);
+        FreePool(Volume);
+
+        BS->CloseProtocol(ControllerHandle,
+                          &PROTO_NAME(DiskIoProtocol),
+                          This->DriverBindingHandle,
+                          ControllerHandle);
+    }
+
+    return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Stop function. This function is called by EFI
+ * to stop the driver on the given device. This translates to an unmount
+ * call for the FSW core.
+ *
+ * We assume that all file handles on the volume have been closed before
+ * the driver is stopped. At least with the EFI shell, that is actually the
+ * case; it closes all file handles between commands.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                             IN  EFI_HANDLE                   ControllerHandle,
+                                             IN  UINTN                        NumberOfChildren,
+                                             IN  EFI_HANDLE                   *ChildHandleBuffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_IO_INTERFACE *FileSystem;
+    FSW_VOLUME_DATA     *Volume;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Stop\n");
+#endif
+
+    // get the installed SimpleFileSystem interface
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(SimpleFileSystemProtocol),
+                              (VOID **) &FileSystem,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+    if (EFI_ERROR(Status))
+        return EFI_UNSUPPORTED;
+
+    // get private data structure
+    Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
+
+    // uninstall Simple File System protocol
+    Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
+                                                     &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
+                                                     NULL);
+    if (EFI_ERROR(Status)) {
+        Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
+        return Status;
+    }
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
+#endif
+
+    // release private data structure
+    if (Volume->vol != NULL)
+        fsw_unmount(Volume->vol);
+    FreePool(Volume);
+
+    // close the consumed protocols
+    Status = BS->CloseProtocol(ControllerHandle,
+                               &PROTO_NAME(DiskIoProtocol),
+                               This->DriverBindingHandle,
+                               ControllerHandle);
+
+    return Status;
+}
+
+/**
+ * Component Name EFI protocol, GetDriverName function. Used by the EFI
+ * environment to inquire the name of this driver. The name returned is
+ * based on the file system type actually used in compilation.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+                                                      IN  CHAR8                        *Language,
+                                                      OUT CHAR16                       **DriverName)
+{
+    if (Language == NULL || DriverName == NULL)
+        return EFI_INVALID_PARAMETER;
+#if 0
+
+    if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
+        *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
+        return EFI_SUCCESS;
+    }
+#endif
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * Component Name EFI protocol, GetControllerName function. Not implemented
+ * because this is not a "bus" driver in the sense of the EFI Driver Model.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN  EFI_COMPONENT_NAME_PROTOCOL    *This,
+                                                          IN  EFI_HANDLE                     ControllerHandle,
+                                                          IN  EFI_HANDLE                     ChildHandle  OPTIONAL,
+                                                          IN  CHAR8                          *Language,
+                                                          OUT CHAR16                         **ControllerName)
+{
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+    // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)vol->host_data;
+
+    FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d  (%d)\n"), phys_bno, vol->phys_blocksize));
+
+    // read from disk
+    Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
+                                      (UINT64)phys_bno * vol->phys_blocksize,
+                                      vol->phys_blocksize,
+                                      buffer);
+    Volume->LastIOStatus = Status;
+    if (EFI_ERROR(Status))
+        return FSW_IO_ERROR;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
+ * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
+ * the last I/O operation.
+ */
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
+{
+    switch (fsw_status) {
+        case FSW_SUCCESS:
+            return EFI_SUCCESS;
+        case FSW_OUT_OF_MEMORY:
+            return EFI_VOLUME_CORRUPTED;
+        case FSW_IO_ERROR:
+            return Volume->LastIOStatus;
+        case FSW_UNSUPPORTED:
+            return EFI_UNSUPPORTED;
+        case FSW_NOT_FOUND:
+            return EFI_NOT_FOUND;
+        case FSW_VOLUME_CORRUPTED:
+            return EFI_VOLUME_CORRUPTED;
+        default:
+            return EFI_DEVICE_ERROR;
+    }
+}
+
+/**
+ * File System EFI protocol, OpenVolume function. Creates a file handle for
+ * the root directory and returns it. Note that this function may be called
+ * multiple times and returns a new file handle each time. Each returned
+ * handle is closed by the client using it.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+                                                OUT EFI_FILE **Root)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_FileSystem_OpenVolume\n");
+#endif
+
+    Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
+
+    return Status;
+}
+
+/**
+ * File Handle EFI protocol, Open function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
+                                          OUT EFI_FILE **NewHandle,
+                                          IN CHAR16 *FileName,
+                                          IN UINT64 OpenMode,
+                                          IN UINT64 Attributes)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
+    // not supported for regular files
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Close function. Closes the FSW shandle
+ * and frees the memory used for the structure.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_FileHandle_Close\n");
+#endif
+
+    fsw_shandle_close(&File->shand);
+    FreePool(File);
+
+    return EFI_SUCCESS;
+}
+
+/**
+ * File Handle EFI protocol, Delete function. Calls through to Close
+ * and returns a warning because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
+{
+    EFI_STATUS          Status;
+
+    Status = This->Close(This);
+    if (Status == EFI_SUCCESS) {
+        // this driver is read-only
+        Status = EFI_WARN_DELETE_FAILURE;
+    }
+
+    return Status;
+}
+
+/**
+ * File Handle EFI protocol, Read function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
+                                          IN OUT UINTN *BufferSize,
+                                          OUT VOID *Buffer)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_read(File, BufferSize, Buffer);
+    else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_read(File, BufferSize, Buffer);
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Write function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
+                                           IN OUT UINTN *BufferSize,
+                                           IN VOID *Buffer)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, GetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
+                                                 OUT UINT64 *Position)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_getpos(File, Position);
+    // not defined for directories
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, SetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
+                                                 IN UINT64 Position)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_setpos(File, Position);
+    else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_setpos(File, Position);
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, GetInfo function. Dispatches to the common
+ * function implementing this.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
+                                             IN EFI_GUID *InformationType,
+                                             IN OUT UINTN *BufferSize,
+                                             OUT VOID *Buffer)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
+}
+
+/**
+ * File Handle EFI protocol, SetInfo function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
+                                             IN EFI_GUID *InformationType,
+                                             IN UINTN BufferSize,
+                                             IN VOID *Buffer)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, Flush function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Set up a file handle for a dnode. This function allocates a data structure
+ * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
+ * with the interface functions.
+ */
+
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+                                       OUT EFI_FILE **NewFileHandle)
+{
+    EFI_STATUS          Status;
+    FSW_FILE_DATA       *File;
+
+    // make sure the dnode has complete info
+    Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // check type
+    if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
+        return EFI_UNSUPPORTED;
+
+    // allocate file structure
+    File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
+    File->Signature = FSW_FILE_DATA_SIGNATURE;
+    if (dno->type == FSW_DNODE_TYPE_FILE)
+        File->Type = FSW_EFI_FILE_TYPE_FILE;
+    else if (dno->type == FSW_DNODE_TYPE_DIR)
+        File->Type = FSW_EFI_FILE_TYPE_DIR;
+
+    // open shandle
+    Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
+                                (FSW_VOLUME_DATA *)dno->vol->host_data);
+    if (EFI_ERROR(Status)) {
+        FreePool(File);
+        return Status;
+    }
+
+    // populate the file handle
+    File->FileHandle.Revision    = EFI_FILE_HANDLE_REVISION;
+    File->FileHandle.Open        = fsw_efi_FileHandle_Open;
+    File->FileHandle.Close       = fsw_efi_FileHandle_Close;
+    File->FileHandle.Delete      = fsw_efi_FileHandle_Delete;
+    File->FileHandle.Read        = fsw_efi_FileHandle_Read;
+    File->FileHandle.Write       = fsw_efi_FileHandle_Write;
+    File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
+    File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
+    File->FileHandle.GetInfo     = fsw_efi_FileHandle_GetInfo;
+    File->FileHandle.SetInfo     = fsw_efi_FileHandle_SetInfo;
+    File->FileHandle.Flush       = fsw_efi_FileHandle_Flush;
+
+    *NewFileHandle = &File->FileHandle;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Data read function for regular files. Calls through to fsw_shandle_read.
+ */
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+                             IN OUT UINTN *BufferSize,
+                             OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    fsw_u32             buffer_size;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
+#endif
+
+    buffer_size = *BufferSize;
+    Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
+                                (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
+    *BufferSize = buffer_size;
+
+    return Status;
+}
+
+/**
+ * Get file position for regular files.
+ */
+
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+                               OUT UINT64 *Position)
+{
+    *Position = File->shand.pos;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Set file position for regular files. EFI specifies the all-ones value
+ * to be a special value for the end of the file.
+ */
+
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+                               IN UINT64 Position)
+{
+    if (Position == 0xFFFFFFFFFFFFFFFFULL)
+        File->shand.pos = File->shand.dnode->size;
+    else
+        File->shand.pos = Position;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Open function used to open new file handles relative to a directory.
+ * In EFI, the "open file" function is implemented by directory file handles
+ * and is passed a relative or volume-absolute path to the file or directory
+ * to open. We use fsw_dnode_lookup_path to find the node plus an additional
+ * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
+ */
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+                            OUT EFI_FILE **NewHandle,
+                            IN CHAR16 *FileName,
+                            IN UINT64 OpenMode,
+                            IN UINT64 Attributes)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    struct fsw_dnode    *dno;
+    struct fsw_dnode    *target_dno;
+    struct fsw_string   lookup_path;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_dir_open: '%s'\n", FileName);
+#endif
+
+    if (OpenMode != EFI_FILE_MODE_READ)
+        return EFI_WRITE_PROTECTED;
+
+    lookup_path.type = FSW_STRING_TYPE_UTF16;
+    lookup_path.len  = StrLen(FileName);
+    lookup_path.size = lookup_path.len * sizeof(fsw_u16);
+    lookup_path.data = FileName;
+
+    // resolve the path (symlinks along the way are automatically resolved)
+    Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno),
+                                Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // if the final node is a symlink, also resolve it
+    Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
+                                Volume);
+    fsw_dnode_release(dno);
+    if (EFI_ERROR(Status))
+        return Status;
+    dno = target_dno;
+
+    // make a new EFI handle for the target dnode
+    Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
+    fsw_dnode_release(dno);
+    return Status;
+}
+
+/**
+ * Read function for directories. A file handle read on a directory retrieves
+ * the next directory entry.
+ */
+
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+                            IN OUT UINTN *BufferSize,
+                            OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    struct fsw_dnode    *dno;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_dir_read...\n");
+#endif
+
+    // read the next entry
+    Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
+                                Volume);
+    if (Status == EFI_NOT_FOUND) {
+        // end of directory
+        *BufferSize = 0;
+#if DEBUG_LEVEL
+        Print(L"...no more entries\n");
+#endif
+        return EFI_SUCCESS;
+    }
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // get info into buffer
+    Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
+    fsw_dnode_release(dno);
+    return Status;
+}
+
+/**
+ * Set file position for directories. The only allowed set position operation
+ * for directories is to rewind the directory completely by setting the
+ * position to zero.
+ */
+
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+                              IN UINT64 Position)
+{
+    if (Position == 0) {
+        File->shand.pos = 0;
+        return EFI_SUCCESS;
+    } else {
+        // directories can only rewind to the start
+        return EFI_UNSUPPORTED;
+    }
+}
+
+/**
+ * Get file or volume information. This function implements the GetInfo call
+ * for all file handles. Control is dispatched according to the type of information
+ * requested by the caller.
+ */
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+                                 IN EFI_GUID *InformationType,
+                                 IN OUT UINTN *BufferSize,
+                                 OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    EFI_FILE_SYSTEM_INFO *FSInfo;
+    UINTN               RequiredSize;
+    struct fsw_volume_stat vsb;
+
+    if (CompareGuid(InformationType, &GUID_NAME(FileInfo))) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
+#endif
+
+        Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
+
+    } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemInfo)) == 0) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
+#endif
+
+        // check buffer size
+        RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
+        if (*BufferSize < RequiredSize) {
+            *BufferSize = RequiredSize;
+            return EFI_BUFFER_TOO_SMALL;
+        }
+
+        // fill structure
+        FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+        FSInfo->Size        = RequiredSize;
+        FSInfo->ReadOnly    = TRUE;
+        FSInfo->BlockSize   = Volume->vol->log_blocksize;
+        fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
+
+        // get the missing info from the fs driver
+        ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
+        Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
+        if (EFI_ERROR(Status))
+            return Status;
+        FSInfo->VolumeSize  = vsb.total_bytes;
+        FSInfo->FreeSpace   = vsb.free_bytes;
+
+        // prepare for return
+        *BufferSize = RequiredSize;
+        Status = EFI_SUCCESS;
+
+    } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemVolumeLabelInfoId))) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
+#endif
+
+        // check buffer size
+        RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
+        if (*BufferSize < RequiredSize) {
+            *BufferSize = RequiredSize;
+            return EFI_BUFFER_TOO_SMALL;
+        }
+
+        // copy volume label
+        fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
+
+        // prepare for return
+        *BufferSize = RequiredSize;
+        Status = EFI_SUCCESS;
+
+    } else {
+        Status = EFI_UNSUPPORTED;
+    }
+
+    return Status;
+}
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if (which == FSW_DNODE_STAT_CTIME)
+        fsw_efi_decode_time(&FileInfo->CreateTime,       posix_time);
+    else if (which == FSW_DNODE_STAT_MTIME)
+        fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
+    else if (which == FSW_DNODE_STAT_ATIME)
+        fsw_efi_decode_time(&FileInfo->LastAccessTime,   posix_time);
+}
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if ((posix_mode & S_IWUSR) == 0)
+        FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_INFO       *FileInfo;
+    UINTN               RequiredSize;
+    struct fsw_dnode_stat sb;
+
+    // make sure the dnode has complete info
+    Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // TODO: check/assert that the dno's name is in UTF16
+
+    // check buffer size
+    RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
+    if (*BufferSize < RequiredSize) {
+        // TODO: wind back the directory in this case
+
+#if DEBUG_LEVEL
+        Print(L"...BUFFER TOO SMALL\n");
+#endif
+        *BufferSize = RequiredSize;
+        return EFI_BUFFER_TOO_SMALL;
+    }
+
+    // fill structure
+    ZeroMem(Buffer, RequiredSize);
+    FileInfo = (EFI_FILE_INFO *)Buffer;
+    FileInfo->Size = RequiredSize;
+    FileInfo->FileSize          = dno->size;
+    FileInfo->Attribute         = 0;
+    if (dno->type == FSW_DNODE_TYPE_DIR)
+        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
+    fsw_efi_strcpy(FileInfo->FileName, &dno->name);
+
+    // get the missing info from the fs driver
+    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+    sb.store_time_posix = fsw_efi_store_time_posix;
+    sb.store_attr_posix = fsw_efi_store_attr_posix;
+    sb.host_data = FileInfo;
+    Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+    FileInfo->PhysicalSize      = sb.used_bytes;
+
+    // prepare for return
+    *BufferSize = RequiredSize;
+#if DEBUG_LEVEL
+    Print(L"...returning '%s'\n", FileInfo->FileName);
+#endif
+    return EFI_SUCCESS;
+}
+
+// EOF
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.h	(revision 29125)
@@ -0,0 +1,116 @@
+/* $Id$ */
+/** @file
+ * fsw_efi.h - EFI host environment header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_H_
+#define _FSW_EFI_H_
+
+#include "fsw_core.h"
+
+
+/**
+ * EFI Host: Private per-volume structure.
+ */
+
+typedef struct {
+    UINT64                      Signature;      //!< Used to identify this structure
+
+    EFI_FILE_IO_INTERFACE       FileSystem;     //!< Published EFI protocol interface structure
+
+    EFI_HANDLE                  Handle;         //!< The device handle the protocol is attached to
+    EFI_DISK_IO                 *DiskIo;        //!< The Disk I/O protocol we use for disk access
+    UINT32                      MediaId;        //!< The media ID from the Block I/O protocol
+    EFI_STATUS                  LastIOStatus;   //!< Last status from Disk I/O
+
+    struct fsw_volume           *vol;           //!< FSW volume structure
+
+} FSW_VOLUME_DATA;
+
+/** Signature for the volume structure. */
+#define FSW_VOLUME_DATA_SIGNATURE  EFI_SIGNATURE_32 ('f', 's', 'w', 'V')
+/** Access macro for the volume structure. */
+#define FSW_VOLUME_FROM_FILE_SYSTEM(a)  CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE)
+
+/**
+ * EFI Host: Private structure for a EFI_FILE interface.
+ */
+
+typedef struct {
+    UINT64                      Signature;      //!< Used to identify this structure
+
+    EFI_FILE                    FileHandle;     //!< Published EFI protocol interface structure
+
+    UINTN                       Type;           //!< File type used for dispatchinng
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+} FSW_FILE_DATA;
+
+/** File type: regular file. */
+#define FSW_EFI_FILE_TYPE_FILE  (0)
+/** File type: directory. */
+#define FSW_EFI_FILE_TYPE_DIR   (1)
+
+/** Signature for the file handle structure. */
+#define FSW_FILE_DATA_SIGNATURE    EFI_SIGNATURE_32 ('f', 's', 'w', 'F')
+/** Access macro for the file handle structure. */
+#define FSW_FILE_FROM_FILE_HANDLE(a)  CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE)
+
+
+//
+// Library functions
+//
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime);
+
+UINTN fsw_efi_strsize(struct fsw_string *s);
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src);
+
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi_base.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi_base.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi_base.h	(revision 29125)
@@ -0,0 +1,98 @@
+/* $Id$ */
+/** @file
+ * fsw_efi_base.h - Base definitions for the EFI host environment.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_BASE_H_
+#define _FSW_EFI_BASE_H_
+
+#ifndef VBOX
+#include <efi.h>
+#include <efilib.h>
+#define PROTO_NAME(x) x
+#endif
+
+#define FSW_LITTLE_ENDIAN (1)
+
+
+// types, reuse EFI types
+
+typedef INT8    fsw_s8;
+typedef UINT8   fsw_u8;
+typedef INT16   fsw_s16;
+typedef UINT16  fsw_u16;
+typedef INT32   fsw_s32;
+typedef UINT32  fsw_u32;
+typedef INT64   fsw_s64;
+typedef UINT64  fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) FreePool(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) ZeroMem(dest,size)
+#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size)
+#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) L##s
+#define FSW_MSGFUNC Print
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits))
+#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL)
+
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c	(revision 29125)
@@ -0,0 +1,162 @@
+/* $Id$ */
+/** @file
+ * fsw_efi_lib.c - EFI host environment library functions.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+
+//
+// time conversion
+//
+// Adopted from public domain code in FreeBSD libc.
+//
+
+#define SECSPERMIN      60
+#define MINSPERHOUR     60
+#define HOURSPERDAY     24
+#define DAYSPERWEEK     7
+#define DAYSPERNYEAR    365
+#define DAYSPERLYEAR    366
+#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR     12
+
+#define EPOCH_YEAR      1970
+#define EPOCH_WDAY      TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+static const int year_lengths[2] = {
+    DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime)
+{
+    long        days, rem;
+    int         y, newy, yleap;
+    const int   *ip;
+
+    ZeroMem(EfiTime, sizeof(EFI_TIME));
+
+    days = UnixTime / SECSPERDAY;
+    rem = UnixTime % SECSPERDAY;
+
+    EfiTime->Hour = (UINT8) (rem / SECSPERHOUR);
+    rem = rem % SECSPERHOUR;
+    EfiTime->Minute = (UINT8) (rem / SECSPERMIN);
+    EfiTime->Second = (UINT8) (rem % SECSPERMIN);
+
+    y = EPOCH_YEAR;
+    while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+        newy = y + days / DAYSPERNYEAR;
+        if (days < 0)
+            --newy;
+        days -= (newy - y) * DAYSPERNYEAR +
+            LEAPS_THRU_END_OF(newy - 1) -
+            LEAPS_THRU_END_OF(y - 1);
+        y = newy;
+    }
+    EfiTime->Year = (UINT16)y;
+    ip = mon_lengths[yleap];
+    for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month))
+        days = days - (long) ip[EfiTime->Month];
+    EfiTime->Month++;  // adjust range to EFI conventions
+    EfiTime->Day = (UINT8) (days + 1);
+}
+
+//
+// String functions, used for file and volume info
+//
+
+UINTN fsw_efi_strsize(struct fsw_string *s)
+{
+    if (s->type == FSW_STRING_TYPE_EMPTY)
+        return sizeof(CHAR16);
+    return (s->len + 1) * sizeof(CHAR16);
+}
+
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src)
+{
+    if (src->type == FSW_STRING_TYPE_EMPTY) {
+        Dest[0] = 0;
+    } else if (src->type == FSW_STRING_TYPE_UTF16) {
+        CopyMem(Dest, src->data, src->size);
+        Dest[src->len] = 0;
+    } else {
+        // TODO: coerce, recurse
+        Dest[0] = 0;
+    }
+}
+
+#ifdef VBOX
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+
+    for (i = 0; i<len; i++)
+    {
+        if (fsw_to_lower(p1[i]) != fsw_to_lower(p2[i]))
+        {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+// EOF
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.c	(revision 29125)
@@ -0,0 +1,1239 @@
+/* $Id$ */
+/** @file
+ * fsw_hfs.c - HFS file system driver code, see
+ *
+ *   http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ * Current limitations:
+ *  - Doesn't support permissions
+ *  - Complete Unicode case-insenstivness disabled (large tables)
+ *  - No links
+ *  - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "fsw_hfs.h"
+
+#ifdef HOST_POSIX
+#define DPRINT(x) printf(x)
+#define DPRINT2(x,y) printf(x,y)
+#define BP(msg)    do { printf("ERROR: %s", msg); asm("int3"); } while (0)
+#else
+#define CONCAT(x,y) x##y
+#define DPRINT(x) Print(CONCAT(L,x))
+#define DPRINT2(x,y) Print(CONCAT(L,x), y)
+#define BP(msg) DPRINT(msg)
+#endif
+
+// functions
+#if 0
+void dump_str(fsw_u16* p, fsw_u32 len, int swap)
+{
+    int i;
+
+    for (i=0; i<len; i++)
+    {
+        fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
+    }
+    fprintf(stderr, "\n");
+}
+#endif
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
+static void         fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static void         fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_extent *extent);
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
+#if 0
+static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
+#endif
+
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                         struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(hfs) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
+    sizeof(struct fsw_hfs_volume),
+    sizeof(struct fsw_hfs_dnode),
+
+    fsw_hfs_volume_mount,
+    fsw_hfs_volume_free,
+    fsw_hfs_volume_stat,
+    fsw_hfs_dnode_fill,
+    fsw_hfs_dnode_free,
+    fsw_hfs_dnode_stat,
+    fsw_hfs_get_extent,
+    fsw_hfs_dir_lookup,
+    fsw_hfs_dir_read,
+    fsw_hfs_readlink,
+};
+
+static fsw_s32
+fsw_hfs_read_block (struct fsw_hfs_dnode    * dno,
+                    fsw_u32                   log_bno,
+                    fsw_u32                   off,
+                    fsw_s32                   len,
+                    fsw_u8                  * buf)
+{
+    fsw_status_t          status;
+    struct fsw_extent     extent;
+    fsw_u32               phys_bno;
+    fsw_u8*                 buffer;
+
+    extent.log_start = log_bno;
+    status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
+    if (status)
+        return status;
+
+    phys_bno = extent.phys_start;
+    status = fsw_block_get(dno->g.vol, phys_bno, 0, (void **)&buffer);
+    if (status)
+        return status;
+
+    fsw_memcpy(buf, buffer + off, len);
+
+    fsw_block_release(dno->g.vol, phys_bno, buffer);
+
+    return FSW_SUCCESS;
+
+}
+
+/* Read data from HFS file. */
+static fsw_s32
+fsw_hfs_read_file (struct fsw_hfs_dnode    * dno,
+                   fsw_u64                   pos,
+                   fsw_s32                   len,
+                   fsw_u8                  * buf)
+{
+
+    fsw_status_t          status;
+    fsw_u32               log_bno;
+    fsw_u32               block_size_bits = dno->g.vol->block_size_shift;
+    fsw_u32               block_size = (1 << block_size_bits);
+    fsw_u32               block_size_mask = block_size - 1;
+    fsw_s32               read = 0;
+
+    while (len > 0)
+    {
+        fsw_u32 off = (fsw_u32)(pos & block_size_mask);
+        fsw_s32 next_len = len;
+
+        log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
+
+        if (   next_len >= 0
+            && (fsw_u32)next_len >  block_size)
+            next_len = block_size;
+        status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
+        if (status)
+            return -1;
+        buf  += next_len;
+        pos  += next_len;
+        len  -= next_len;
+        read += next_len;
+    }
+
+    return read;
+}
+
+
+static fsw_s32
+fsw_hfs_compute_shift(fsw_u32 size)
+{
+    fsw_s32 i;
+
+    for (i=0; i<32; i++)
+    {
+        if ((size >> i) == 0)
+            return i - 1;
+    }
+
+    BP("BUG\n");
+    return 0;
+}
+
+/**
+ * Mount an HFS+ volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
+{
+    fsw_status_t           status, rv;
+    void                  *buffer = NULL;
+    HFSPlusVolumeHeader   *voldesc;
+    fsw_u32                blockno;
+    struct fsw_string      s;
+
+    rv = FSW_UNSUPPORTED;
+
+    vol->primary_voldesc = NULL;
+    fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
+    blockno = HFS_SUPERBLOCK_BLOCKNO;
+
+#define CHECK(s)         \
+        if (status)  {   \
+            rv = status; \
+            break;       \
+        }
+
+    vol->emb_block_off = 0;
+    vol->hfs_kind = 0;
+    do {
+        fsw_u16       signature;
+        BTHeaderRec   tree_header;
+        fsw_s32       r;
+        fsw_u32       block_size;
+
+        status = fsw_block_get(vol, blockno, 0, &buffer);
+        CHECK(status);
+        voldesc = (HFSPlusVolumeHeader *)buffer;
+        signature = be16_to_cpu(voldesc->signature);
+
+        if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord))
+        {
+            if (vol->hfs_kind == 0)
+            {
+                DPRINT("found HFS+\n");
+                vol->hfs_kind = FSW_HFS_PLUS;
+            }
+        }
+        else if (signature == kHFSSigWord)
+        {
+            HFSMasterDirectoryBlock* mdb = (HFSMasterDirectoryBlock*)buffer;
+
+            if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
+            {
+                DPRINT("found HFS+ inside HFS, untested\n");
+                vol->hfs_kind = FSW_HFS_PLUS_EMB;
+                vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
+                blockno += vol->emb_block_off;
+                /* retry */
+                continue;
+            }
+            else
+            {
+                DPRINT("found plain HFS, unsupported\n");
+                vol->hfs_kind = FSW_HFS_PLAIN;
+            }
+            rv = FSW_UNSUPPORTED;
+            break;
+        }
+        else
+        {
+            rv = FSW_UNSUPPORTED;
+            break;
+        }
+
+        status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
+                            sizeof(*voldesc));
+        CHECK(status);
+
+
+        block_size = be32_to_cpu(voldesc->blockSize);
+        vol->block_size_shift = fsw_hfs_compute_shift(block_size);
+
+        fsw_block_release(vol, blockno, buffer);
+        buffer = NULL;
+        voldesc = NULL;
+        fsw_set_blocksize(vol, block_size, block_size);
+
+        /* get volume name */
+        s.type = FSW_STRING_TYPE_ISO88591;
+        s.size = s.len = kHFSMaxVolumeNameChars;
+        s.data = "HFS+ volume";
+        status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+        CHECK(status);
+
+        /* Setup catalog dnode */
+        status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
+        CHECK(status);
+        fsw_memcpy (vol->catalog_tree.file->extents,
+                    vol->primary_voldesc->catalogFile.extents,
+                    sizeof vol->catalog_tree.file->extents);
+        vol->catalog_tree.file->g.size =
+                be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
+
+        /* Setup extents overflow file */
+        status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
+        fsw_memcpy (vol->extents_tree.file->extents,
+                    vol->primary_voldesc->extentsFile.extents,
+                    sizeof vol->extents_tree.file->extents);
+        vol->extents_tree.file->g.size =
+                be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
+
+        /* Setup the root dnode */
+        status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
+        CHECK(status);
+
+        /*
+         * Read catalog file, we know that first record is in the first node, right after
+         * the node descriptor.
+         */
+        r = fsw_hfs_read_file(vol->catalog_tree.file,
+                              sizeof (BTNodeDescriptor),
+                              sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+        if (r <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+        vol->case_sensitive =
+                (signature == kHFSXSigWord) &&
+                (tree_header.keyCompareType == kHFSBinaryCompare);
+        vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
+        vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+        /* Read extents overflow file */
+        r = fsw_hfs_read_file(vol->extents_tree.file,
+                              sizeof (BTNodeDescriptor),
+                              sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+        if (r <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
+        vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+        rv = FSW_SUCCESS;
+    } while (0);
+
+#undef CHECK
+
+
+    if (buffer != NULL)
+        fsw_block_release(vol, blockno, buffer);
+
+    return rv;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
+{
+    if (vol->primary_voldesc)
+    {
+        fsw_free(vol->primary_voldesc);
+        vol->primary_voldesc = NULL;
+    }
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
+    sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode.
+ */
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+}
+
+static fsw_u32 mac_to_posix(fsw_u32 mac_time)
+{
+  /* Mac time is 1904 year based */
+  return mac_time ?  mac_time - 2082844800 : 0;
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
+                                       struct fsw_hfs_dnode  *dno,
+                                       struct fsw_dnode_stat *sb)
+{
+  sb->used_bytes = dno->used_bytes;
+  sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
+  sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
+  sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
+  sb->store_attr_posix(sb, 0700);
+
+  return FSW_SUCCESS;
+}
+
+static int
+fsw_hfs_find_block(HFSPlusExtentRecord * exts,
+                   fsw_u32             * lbno,
+                   fsw_u32             * pbno)
+{
+    int i;
+    fsw_u32 cur_lbno = *lbno;
+
+    for (i = 0; i < 8; i++)
+    {
+        fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
+        fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
+
+        if (cur_lbno < count)
+        {
+            *pbno = start + cur_lbno;
+            return 1;
+        }
+
+        cur_lbno -= count;
+    }
+
+    *lbno = cur_lbno;
+
+    return 0;
+}
+
+/* Find record offset, numbering starts from the end */
+static fsw_u32
+fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
+                         BTNodeDescriptor     * node,
+                         fsw_u32                index)
+{
+  fsw_u8 *cnode = (fsw_u8 *) node;
+  fsw_u16 *recptr;
+  recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
+  return be16_to_cpu(*recptr);
+}
+
+/* Pointer to the key inside node */
+static BTreeKey *
+fsw_hfs_btree_rec (struct fsw_hfs_btree   * btree,
+                   BTNodeDescriptor       * node,
+                   fsw_u32                  index)
+{
+  fsw_u8 *cnode = (fsw_u8 *) node;
+  fsw_u32 offset;
+  offset = fsw_hfs_btree_recoffset (btree, node, index);
+  return (BTreeKey *) (cnode + offset);
+}
+
+
+static fsw_status_t
+fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
+                      BTreeKey             * key,
+                      int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
+                      BTNodeDescriptor    ** result,
+                      fsw_u32              * key_offset)
+{
+    BTNodeDescriptor* node;
+    fsw_u32 currnode;
+    fsw_u32 rec;
+    fsw_status_t status;
+    fsw_u8* buffer = NULL;
+
+    currnode = btree->root_node;
+    status = fsw_alloc(btree->node_size, &buffer);
+    if (status)
+        return status;
+    node = (BTNodeDescriptor*)buffer;
+
+    while (1)
+    {
+        int cmp = 0;
+        int match;
+        fsw_u32 count;
+
+    readnode:
+        match = 0;
+        /* Read a node.  */
+        if (fsw_hfs_read_file (btree->file,
+                               (fsw_u64)currnode * btree->node_size,
+                               btree->node_size, buffer) <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
+            BP("corrupted node\n");
+
+        count = be16_to_cpu (node->numRecords);
+
+#if 1
+        for (rec = 0; rec < count; rec++)
+        {
+             BTreeKey *currkey;
+
+             currkey = fsw_hfs_btree_rec (btree, node, rec);
+             cmp = compare_keys (currkey, key);
+             //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
+
+             /* Leaf node. */
+             if (node->kind == kBTLeafNode)
+             {
+               if (cmp == 0)
+               {
+                 /* Found!  */
+                 *result = node;
+                 *key_offset = rec;
+
+                 status = FSW_SUCCESS;
+                 goto done;
+               }
+             }
+             else if (node->kind == kBTIndexNode)
+             {
+                 fsw_u32 *pointer;
+
+                 if (cmp > 0)
+                     break;
+
+                 pointer = (fsw_u32 *) ((char *) currkey
+                                        + be16_to_cpu (currkey->length16)
+                                        + 2);
+                 currnode = be32_to_cpu (*pointer);
+                 match = 1;
+             }
+        }
+
+        if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
+        {
+            currnode = be32_to_cpu(node->fLink);
+            goto readnode;
+        }
+        else if (!match)
+        {
+            status = FSW_NOT_FOUND;
+            break;
+        }
+#else
+         /* Perform binary search */
+         fsw_u32 lower = 0;
+         fsw_u32 upper = count - 1;
+         fsw_s32 cmp = -1;
+         BTreeKey *currkey = NULL;
+
+         if (count == 0)
+         {
+             status = FSW_NOT_FOUND;
+             goto done;
+         }
+
+         while (lower <= upper)
+         {
+             fsw_u32 index = (lower + upper) / 2;
+
+             currkey = fsw_hfs_btree_rec (btree, node, index);
+
+             cmp = compare_keys (currkey, key);
+             if (cmp < 0)  upper = index - 1;
+             if (cmp > 0)  lower = index + 1;
+             if (cmp == 0)
+             {
+                 /* Found!  */
+                 *result = node;
+                 *key_offset = rec;
+
+                 status = FSW_SUCCESS;
+                 goto done;
+             }
+         }
+
+         if (cmp < 0)
+             currkey = fsw_hfs_btree_rec (btree, node, upper);
+
+         if (node->kind == kBTIndexNode && currkey)
+         {
+             fsw_u32 *pointer;
+
+             pointer = (fsw_u32 *) ((char *) currkey
+                                    + be16_to_cpu (currkey->length16)
+                                    + 2);
+             currnode = be32_to_cpu (*pointer);
+         }
+         else
+         {
+             status = FSW_NOT_FOUND;
+             break;
+         }
+#endif
+    }
+
+
+  done:
+    if (buffer != NULL && status != FSW_SUCCESS)
+        fsw_free(buffer);
+
+    return status;
+}
+typedef struct
+{
+    fsw_u32                 id;
+    fsw_u32                 type;
+    struct fsw_string     * name;
+    fsw_u64                 size;
+    fsw_u64                 used;
+    fsw_u32                 ctime;
+    fsw_u32                 mtime;
+    HFSPlusExtentRecord     extents;
+} file_info_t;
+
+typedef struct
+{
+    fsw_u32                 cur_pos; /* current position */
+    fsw_u32                 parent;
+    struct fsw_hfs_volume * vol;
+
+    struct fsw_shandle *    shandle; /* this one track iterator's state */
+    file_info_t             file_info;
+} visitor_parameter_t;
+
+static int
+fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
+{
+    visitor_parameter_t* vp = (visitor_parameter_t*)param;
+    fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
+    fsw_u16 rec_type =  be16_to_cpu(*(fsw_u16*)base);
+    struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
+    fsw_u16   name_len;
+    fsw_u16   *name_ptr;
+    fsw_u32   i;
+    struct fsw_string * file_name;
+
+    if (be32_to_cpu(cat_key->parentID) != vp->parent)
+        return -1;
+
+    /* not smth we care about */
+    if (vp->shandle->pos != vp->cur_pos++)
+        return 0;
+
+    switch (rec_type)
+    {
+        case kHFSPlusFolderRecord:
+        {
+            HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base;
+
+            vp->file_info.id = be32_to_cpu(folder_info->folderID);
+            vp->file_info.type = FSW_DNODE_TYPE_DIR;
+            vp->file_info.size = be32_to_cpu(folder_info->valence);
+            vp->file_info.used = be32_to_cpu(folder_info->valence);
+            vp->file_info.ctime = be32_to_cpu(folder_info->createDate);
+            vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate);
+            break;
+        }
+        case kHFSPlusFileRecord:
+        {
+            HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base;
+
+            vp->file_info.id = be32_to_cpu(file_info->fileID);
+            vp->file_info.type = FSW_DNODE_TYPE_FILE;
+            vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize);
+            vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks),
+                                           vp->vol->block_size_shift);
+            vp->file_info.ctime = be32_to_cpu(file_info->createDate);
+            vp->file_info.mtime = be32_to_cpu(file_info->contentModDate);
+            fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents,
+                       sizeof vp->file_info.extents);
+            break;
+        }
+        case kHFSPlusFolderThreadRecord:
+        case kHFSPlusFileThreadRecord:
+        {
+            vp->shandle->pos++;
+            return 0;
+        }
+        default:
+            BP("unknown file type\n");
+            vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+            break;
+    }
+
+    name_len = be16_to_cpu(cat_key->nodeName.length);
+
+    file_name =  vp->file_info.name;
+    file_name->len = name_len;
+    fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
+    file_name->size = 2*name_len;
+    file_name->type = FSW_STRING_TYPE_UTF16;
+    name_ptr = (fsw_u16*)file_name->data;
+    for (i=0; i<name_len; i++)
+    {
+        name_ptr[i] = be16_to_cpu(name_ptr[i]);
+    }
+    vp->shandle->pos++;
+
+    return 1;
+}
+
+static fsw_status_t
+fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
+                            BTNodeDescriptor     * first_node,
+                            fsw_u32                first_rec,
+                            int                    (*callback) (BTreeKey *record, void* param),
+                            void                  * param)
+{
+  fsw_status_t status;
+  /* We modify node, so make a copy */
+  BTNodeDescriptor*     node = first_node;
+  fsw_u8* buffer = NULL;
+
+  status = fsw_alloc(btree->node_size, &buffer);
+  if (status)
+      return status;
+
+  while (1)
+  {
+      fsw_u32 i;
+      fsw_u32 count =  be16_to_cpu(node->numRecords);
+      fsw_u32 next_node;
+
+      /* Iterate over all records in this node.  */
+      for (i = first_rec; i < count; i++)
+      {
+          int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
+
+          switch (rv)
+          {
+              case 1:
+                  status = FSW_SUCCESS;
+                  goto done;
+              case -1:
+                  status = FSW_NOT_FOUND;
+                  goto done;
+          }
+          /* if callback returned 0 - continue */
+      }
+
+      next_node = be32_to_cpu(node->fLink);
+
+      if (!next_node)
+      {
+          status = FSW_NOT_FOUND;
+          break;
+      }
+
+      if (fsw_hfs_read_file (btree->file,
+                             next_node * btree->node_size,
+                             btree->node_size, buffer) <= 0)
+      {
+          status = FSW_VOLUME_CORRUPTED;
+          return 1;
+      }
+
+      node = (BTNodeDescriptor*)buffer;
+      first_rec = 0;
+  }
+ done:
+  if (buffer)
+      fsw_free(buffer);
+
+  return status;
+}
+
+#if 0
+void deb(fsw_u16* p, int len, int swap)
+{
+    int i;
+    for (i=0; i<len; i++)
+    {
+      printf("%c", swap ?  be16_to_cpu(p[i]) : p[i]);
+    }
+    printf("\n");
+}
+#endif
+
+static int
+fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
+{
+    HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
+    HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
+    int result;
+
+    /* First key is read from the FS data, second is in-memory in CPU endianess */
+    result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
+
+    if (result)
+        return result;
+
+    result = ekey1->forkType - ekey2->forkType;
+
+    if (result)
+        return result;
+
+    result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
+    return result;
+}
+
+static int
+fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+  HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+  HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+  int      apos, bpos, lc;
+  fsw_u16  ac, bc;
+  fsw_u32  parentId1;
+  int      key1Len;
+  fsw_u16 *p1;
+  fsw_u16 *p2;
+
+  parentId1 = be32_to_cpu(ckey1->parentID);
+
+  if (parentId1 > ckey2->parentID)
+      return 1;
+  if (parentId1 < ckey2->parentID)
+      return -1;
+
+  p1 = &ckey1->nodeName.unicode[0];
+  p2 = &ckey2->nodeName.unicode[0];
+  key1Len = be16_to_cpu (ckey1->nodeName.length);
+  apos = bpos = 0;
+
+  while(1)
+  {
+    /* get next valid character from ckey1 */
+    for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+      ac = be16_to_cpu(p1[apos]);
+      lc = ac;
+    };
+    ac = (fsw_u16)lc;
+
+    /* get next valid character from ckey2 */
+    for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+      bc = p2[bpos];
+      lc = bc;
+    };
+    bc = (fsw_u16)lc;
+
+    if (ac != bc || (ac == 0  && bc == 0))
+      return ac - bc;
+  }
+}
+
+static int
+fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+  HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+  HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+  int      apos, bpos, lc;
+  fsw_u16  ac, bc;
+  fsw_u32  parentId1;
+  int      key1Len;
+  fsw_u16 *p1;
+  fsw_u16 *p2;
+
+  parentId1 = be32_to_cpu(ckey1->parentID);
+
+  if (parentId1 > ckey2->parentID)
+      return 1;
+  if (parentId1 < ckey2->parentID)
+      return -1;
+
+  key1Len = be16_to_cpu (ckey1->nodeName.length);
+
+  if (key1Len == 0 && ckey2->nodeName.length == 0)
+      return 0;
+
+  p1 = &ckey1->nodeName.unicode[0];
+  p2 = &ckey2->nodeName.unicode[0];
+
+  apos = bpos = 0;
+
+  while(1)
+  {
+    /* get next valid character from ckey1 */
+    for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+      ac = be16_to_cpu(p1[apos]);
+      lc = ac ? fsw_to_lower(ac) : 0;
+    };
+    ac = (fsw_u16)lc;
+
+    /* get next valid character from ckey2 */
+    for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+      bc = p2[bpos];
+      lc = bc ? fsw_to_lower(bc) : 0;
+    };
+    bc = (fsw_u16)lc;
+
+    if (ac != bc || (ac == 0  && bc == 0))
+      return ac - bc;
+  }
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
+                                       struct fsw_hfs_dnode  * dno,
+                                       struct fsw_extent     * extent)
+{
+    fsw_status_t         status;
+    fsw_u32              lbno;
+    HFSPlusExtentRecord  *exts;
+    BTNodeDescriptor     *node = NULL;
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->log_count = 1;
+    lbno = extent->log_start;
+
+    /* we only care about data forks atm, do we? */
+    exts = &dno->extents;
+
+    while (1)
+    {
+        struct HFSPlusExtentKey* key;
+        struct HFSPlusExtentKey  overflowkey;
+        fsw_u32                  ptr;
+        fsw_u32                  phys_bno;
+
+        if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
+        {
+            extent->phys_start = phys_bno + vol->emb_block_off;
+            status = FSW_SUCCESS;
+            break;
+        }
+
+
+        /* Find appropriate overflow record */
+        overflowkey.fileID = dno->g.dnode_id;
+        overflowkey.startBlock = extent->log_start - lbno;
+
+        if (node != NULL)
+        {
+            fsw_free(node);
+            node = NULL;
+        }
+
+        status = fsw_hfs_btree_search (&vol->extents_tree,
+                                       (BTreeKey*)&overflowkey,
+                                       fsw_hfs_cmp_extkey,
+                                       &node, &ptr);
+        if (status)
+            break;
+
+        key = (struct HFSPlusExtentKey *)
+                fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
+        exts = (HFSPlusExtentRecord*) (key + 1);
+    }
+
+    if (node != NULL)
+        fsw_free(node);
+
+    return status;
+}
+
+static const fsw_u16* g_blacklist[] =
+{
+    //L"AppleIntelCPUPowerManagement.kext",
+    NULL
+};
+
+
+//#define HFS_FILE_INJECTION
+
+#ifdef HFS_FILE_INJECTION
+static struct
+{
+  const fsw_u16* path;
+  const fsw_u16* name;
+} g_injectList[] =
+{
+  {
+    L"/System/Library/Extensions",
+    L"ApplePS2Controller.kext"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+#endif
+
+static fsw_status_t
+create_hfs_dnode(struct fsw_hfs_dnode  * dno,
+                 file_info_t           * file_info,
+                 struct fsw_hfs_dnode ** child_dno_out)
+{
+    fsw_status_t           status;
+    struct fsw_hfs_dnode * baby;
+
+    status = fsw_dnode_create(dno, file_info->id, file_info->type,
+                              file_info->name, &baby);
+    if (status)
+        return status;
+
+    baby->g.size = file_info->size;
+    baby->used_bytes = file_info->used;
+    baby->ctime = file_info->ctime;
+    baby->mtime = file_info->mtime;
+
+
+    /* Fill-in extents info */
+    if (file_info->type == FSW_DNODE_TYPE_FILE)
+    {
+        fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
+    }
+
+    *child_dno_out = baby;
+
+    return FSW_SUCCESS;
+}
+
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
+                                       struct fsw_hfs_dnode  * dno,
+                                       struct fsw_string     * lookup_name,
+                                       struct fsw_hfs_dnode ** child_dno_out)
+{
+    fsw_status_t               status;
+    struct HFSPlusCatalogKey   catkey;
+    fsw_u32                    ptr;
+    fsw_u16                    rec_type;
+    BTNodeDescriptor *         node = NULL;
+    struct fsw_string          rec_name;
+    int                        free_data = 0, i;
+    HFSPlusCatalogKey*         file_key;
+    file_info_t                file_info;
+    fsw_u8*                    base;
+
+
+    fsw_memzero(&file_info, sizeof file_info);
+    file_info.name = &rec_name;
+
+    catkey.parentID = dno->g.dnode_id;
+    catkey.nodeName.length = (fsw_u16)lookup_name->len;
+
+    /* no need to allocate anything */
+    if (lookup_name->type == FSW_STRING_TYPE_UTF16)
+    {
+        fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
+        rec_name = *lookup_name;
+    } else
+    {
+        status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
+        /* nothing allocated so far */
+        if (status)
+            goto done;
+        free_data = 1;
+        fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
+    }
+
+    /* Dirty hack: blacklisting of certain files on FS driver level */
+    for (i = 0; g_blacklist[i]; i++)
+    {
+        if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
+        {
+            DPRINT2("Blacklisted %s\n", g_blacklist[i]);
+            status = FSW_NOT_FOUND;
+            goto done;
+        }
+    }
+
+#ifdef HFS_FILE_INJECTION
+    if (fsw_hfs_inject(vol,
+                       dno,
+                       catkey.nodeName.unicode,
+                       catkey.nodeName.length,
+                       &file_info))
+    {
+        status = FSW_SUCCESS;
+        goto create;
+    }
+#endif
+
+    catkey.keyLength = (fsw_u16)(5 + rec_name.size);
+
+    status = fsw_hfs_btree_search (&vol->catalog_tree,
+                                   (BTreeKey*)&catkey,
+                                   vol->case_sensitive ?
+                                       fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+                                   &node, &ptr);
+    if (status)
+        goto done;
+
+    file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
+    /* for plain HFS "-(keySize & 1)" would be needed */
+    base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
+    rec_type =  be16_to_cpu(*(fsw_u16*)base);
+
+    /** @todo: read additional info */
+    switch (rec_type)
+    {
+        case kHFSPlusFolderRecord:
+        {
+            HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
+
+            file_info.id = be32_to_cpu(info->folderID);
+            file_info.type = FSW_DNODE_TYPE_DIR;
+            /* @todo: return number of elements, maybe use smth else */
+            file_info.size = be32_to_cpu(info->valence);
+            file_info.used = be32_to_cpu(info->valence);
+            file_info.ctime = be32_to_cpu(info->createDate);
+            file_info.mtime = be32_to_cpu(info->contentModDate);
+            break;
+        }
+        case kHFSPlusFileRecord:
+        {
+            HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
+
+            file_info.id = be32_to_cpu(info->fileID);
+            file_info.type = FSW_DNODE_TYPE_FILE;
+            file_info.size = be64_to_cpu(info->dataFork.logicalSize);
+            file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
+            file_info.ctime = be32_to_cpu(info->createDate);
+            file_info.mtime = be32_to_cpu(info->contentModDate);
+            fsw_memcpy(&file_info.extents, &info->dataFork.extents,
+                       sizeof file_info.extents);
+            break;
+        }
+        default:
+            BP("unknown file type\n");
+            file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+
+            break;
+    }
+#ifdef HFS_FILE_INJECTION
+create:
+#endif
+    status = create_hfs_dnode(dno, &file_info, child_dno_out);
+    if (status)
+        goto done;
+
+done:
+
+    if (node != NULL)
+        fsw_free(node);
+
+    if (free_data)
+        fsw_strfree(&rec_name);
+
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
+                                     struct fsw_hfs_dnode  *dno,
+                                     struct fsw_shandle    *shand,
+                                     struct fsw_hfs_dnode  **child_dno_out)
+{
+    fsw_status_t               status;
+    struct HFSPlusCatalogKey   catkey;
+    fsw_u32                    ptr;
+    BTNodeDescriptor *         node = NULL;
+
+    visitor_parameter_t        param;
+    struct fsw_string          rec_name;
+
+    catkey.parentID = dno->g.dnode_id;
+    catkey.nodeName.length = 0;
+
+    fsw_memzero(&param, sizeof(param));
+
+    rec_name.type = FSW_STRING_TYPE_EMPTY;
+    param.file_info.name = &rec_name;
+
+    status = fsw_hfs_btree_search (&vol->catalog_tree,
+                                   (BTreeKey*)&catkey,
+                                   vol->case_sensitive ?
+                                       fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+                                   &node, &ptr);
+    if (status)
+        goto done;
+
+    /* Iterator updates shand state */
+    param.vol = vol;
+    param.shandle = shand;
+    param.parent = dno->g.dnode_id;
+    param.cur_pos = 0;
+    status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
+                                         node,
+                                         ptr,
+                                         fsw_hfs_btree_visit_node,
+                                         &param);
+    if (status)
+      goto done;
+
+    status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
+
+    if (status)
+        goto done;
+
+ done:
+    fsw_strfree(&rec_name);
+
+    return status;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ */
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                     struct fsw_string *link_target)
+{
+    return FSW_UNSUPPORTED;
+}
+
+// EOF
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.h	(revision 29125)
@@ -0,0 +1,192 @@
+/* $Id$ */
+/** @file
+ * fsw_hfs.h - HFS file system driver header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef _FSW_HFS_H_
+#define _FSW_HFS_H_
+
+#define VOLSTRUCTNAME fsw_hfs_volume
+#define DNODESTRUCTNAME fsw_hfs_dnode
+
+#include "fsw_core.h"
+
+
+//! Block size for HFS volumes.
+#define HFS_BLOCKSIZE            512
+
+//! Block number where the HFS superblock resides.
+#define HFS_SUPERBLOCK_BLOCKNO   2
+
+/* Make world look Applish enough for the system header describing HFS layout  */
+#define __APPLE_API_PRIVATE
+#define __APPLE_API_UNSTABLE
+
+#define u_int8_t  fsw_u8
+#define u_int16_t fsw_u16
+#define u_int32_t fsw_u32
+#define u_int64_t fsw_u64
+#define int8_t    fsw_s8
+#define int16_t   fsw_s16
+#define int32_t   fsw_s32
+#define int64_t   fsw_s64
+
+#include "hfs_format.h"
+
+#undef u_int8_t
+#undef u_int16_t
+#undef u_int32_t
+#undef u_int64_t
+#undef int8_t
+#undef int16_t
+#undef int32_t
+#undef int64_t
+
+#pragma pack(1)
+#ifdef _MSC_VER
+/* vasily: disable warning for non-standard anonymous struct/union
+ * declarations
+ */
+# pragma warning (disable:4201)
+# define inline __inline
+#endif
+
+struct hfs_dirrec {
+    fsw_u8      _dummy;
+};
+
+struct fsw_hfs_key
+{
+  union
+  {
+    struct HFSPlusExtentKey  ext_key;
+    struct HFSPlusCatalogKey cat_key;
+    fsw_u16                  key_len; /* Length is at the beginning of all keys */
+  };
+};
+
+#pragma pack()
+
+typedef enum {
+    /* Regular HFS */
+    FSW_HFS_PLAIN = 0,
+    /* HFS+ */
+    FSW_HFS_PLUS,
+    /* HFS+ embedded to HFS */
+    FSW_HFS_PLUS_EMB
+} fsw_hfs_kind;
+
+/**
+ * HFS: Dnode structure with HFS-specific data.
+ */
+
+struct fsw_hfs_dnode
+{
+  struct fsw_dnode          g;          //!< Generic dnode structure
+  HFSPlusExtentRecord       extents;
+  fsw_u32                   ctime;
+  fsw_u32                   mtime;
+  fsw_u64                   used_bytes;
+};
+
+/**
+ * HFS: In-memory B-tree structure.
+ */
+struct fsw_hfs_btree
+{
+    fsw_u32                  root_node;
+    fsw_u32                  node_size;
+    struct fsw_hfs_dnode*    file;
+};
+
+
+/**
+ * HFS: In-memory volume structure with HFS-specific data.
+ */
+
+struct fsw_hfs_volume
+{
+    struct fsw_volume            g;            //!< Generic volume structure
+
+    struct HFSPlusVolumeHeader   *primary_voldesc;  //!< Volume Descriptor
+    struct fsw_hfs_btree          catalog_tree;     // Catalog tree
+    struct fsw_hfs_btree          extents_tree;     // Extents overflow tree
+    struct fsw_hfs_dnode          root_file;
+    int                           case_sensitive;
+    fsw_u32                       block_size_shift;
+    fsw_hfs_kind                  hfs_kind;
+    fsw_u32                       emb_block_off;
+};
+
+/* Endianess swappers */
+static inline fsw_u16
+swab16(fsw_u16 x)
+{
+    return x<<8 | x>>8;
+}
+
+static inline fsw_u32
+swab32(fsw_u32 x)
+{
+    return x<<24 | x>>24 |
+            (x & (fsw_u32)0x0000ff00UL)<<8 |
+            (x & (fsw_u32)0x00ff0000UL)>>8;
+}
+
+
+static inline fsw_u64
+swab64(fsw_u64 x)
+{
+    return x<<56 | x>>56 |
+            (x & (fsw_u64)0x000000000000ff00ULL)<<40 |
+            (x & (fsw_u64)0x0000000000ff0000ULL)<<24 |
+            (x & (fsw_u64)0x00000000ff000000ULL)<< 8 |
+            (x & (fsw_u64)0x000000ff00000000ULL)>> 8 |
+            (x & (fsw_u64)0x0000ff0000000000ULL)>>24 |
+            (x & (fsw_u64)0x00ff000000000000ULL)>>40;
+}
+
+static inline fsw_u16
+be16_to_cpu(fsw_u16 x)
+{
+    return swab16(x);
+}
+
+static inline fsw_u16
+cpu_to_be16(fsw_u16 x)
+{
+    return swab16(x);
+}
+
+
+static inline fsw_u32
+cpu_to_be32(fsw_u32 x)
+{
+    return swab32(x);
+}
+
+static inline fsw_u32
+be32_to_cpu(fsw_u32 x)
+{
+    return swab32(x);
+}
+
+static inline fsw_u64
+be64_to_cpu(fsw_u64 x)
+{
+    return swab64(x);
+}
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.c	(revision 29125)
@@ -0,0 +1,682 @@
+/* $Id$ */
+/** @file
+ * fsw_iso9660.c - ISO9660 file system driver code.
+ *
+ * Current limitations:
+ *  - Files must be in one extent (i.e. Level 2)
+ *  - No Joliet or Rock Ridge extensions
+ *  - No interleaving
+ *  - inode number generation strategy fails on volumes > 2 GB
+ *  - No blocksizes != 2048
+ *  - No High Sierra or anything else != 'CD001'
+ *  - No volume sets with directories pointing at other volumes
+ *  - No extended attribute records
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_iso9660.h"
+
+
+// functions
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol);
+static void         fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol);
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static void         fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_extent *extent);
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer);
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_string *link);
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp);
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str);
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin);
+static void dump_dirrec(struct iso9660_dirrec *dirrec);
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(iso9660) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" },
+    sizeof(struct fsw_iso9660_volume),
+    sizeof(struct fsw_iso9660_dnode),
+
+    fsw_iso9660_volume_mount,
+    fsw_iso9660_volume_free,
+    fsw_iso9660_volume_stat,
+    fsw_iso9660_dnode_fill,
+    fsw_iso9660_dnode_free,
+    fsw_iso9660_dnode_stat,
+    fsw_iso9660_get_extent,
+    fsw_iso9660_dir_lookup,
+    fsw_iso9660_dir_read,
+    fsw_iso9660_readlink,
+};
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp)
+{
+    fsw_u8 *r;
+    int off = 0;
+    struct fsw_rock_ridge_susp_sp *sp;
+    r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length);
+    off = (int)(r - (fsw_u8 *)dirrec);
+    while(off < dirrec->dirrec_length)
+    {
+        if (*r == 'S')
+        {
+            sp = (struct fsw_rock_ridge_susp_sp *)r;
+            if(    sp->e.sig[0] == 'S'
+                && sp->e.sig[1] == 'P'
+                && sp->magic[0] == 0xbe
+                && sp->magic[1] == 0xef)
+            {
+                *psp = sp;
+                return FSW_SUCCESS;
+            }
+        }
+        r++;
+        off = (int)(r - (fsw_u8 *)dirrec);
+    }
+    *psp = NULL;
+    return FSW_NOT_FOUND;
+}
+
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str)
+{
+    fsw_u8 *r, *begin;
+    int fCe = 0;
+    struct fsw_rock_ridge_susp_nm *nm;
+    int limit = dirrec->dirrec_length;
+    begin = (fsw_u8 *)dirrec;
+    r = (fsw_u8 *)dirrec + off;
+    str->data = NULL;
+    str->len = 0;
+    str->size = 0;
+    str->type = 0;
+    while(off < limit)
+    {
+        if (r[0] == 'C' && r[1] == 'E' && r[2] == 28)
+        {
+            int rc;
+            int ce_off;
+            union fsw_rock_ridge_susp_ce *ce;
+            if (fCe == 0)
+                fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin);
+            fCe = 1;
+            DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
+            ce = (union fsw_rock_ridge_susp_ce *)r;
+            limit = ISOINT(ce->X.len);
+            ce_off = ISOINT(ce->X.offset);
+            rc = rr_read_ce(vol, ce, begin);
+            if (rc != FSW_SUCCESS)
+            {
+                fsw_free(begin);
+                return rc;
+            }
+            begin += ce_off;
+            r = begin;
+        }
+        if (r[0] == 'N' && r[1] == 'M')
+        {
+            nm = (struct fsw_rock_ridge_susp_nm *)r;
+            if(    nm->e.sig[0] == 'N'
+                && nm->e.sig[1] == 'M')
+            {
+                int len = 0;
+                fsw_u8 *tmp = NULL;
+                if (nm->flags & RR_NM_CURR)
+                {
+                     fsw_memdup(str->data, ".", 1);
+                     str->len = 1;
+                     goto done;
+                }
+                if (nm->flags & RR_NM_PARE)
+                {
+                     fsw_memdup(str->data, "..", 2);
+                     str->len = 2;
+                     goto done;
+                }
+                len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1;
+                fsw_alloc_zero(str->len + len, (void **)&tmp);
+                if (str->data != NULL)
+                {
+                    fsw_memcpy(tmp, str->data, str->len);
+                    fsw_free(str->data);
+                }
+                DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
+                fsw_memcpy(tmp + str->len, &nm->name[0], len);
+                str->data = tmp;
+                str->len += len;
+
+                if ((nm->flags & RR_NM_CONT) == 0);
+                    goto done;
+            }
+        }
+        r++;
+        off = (int)(r - (fsw_u8 *)begin);
+    }
+    if(fCe == 1)
+        fsw_free(begin);
+    return FSW_NOT_FOUND;
+done:
+    str->type = FSW_STRING_TYPE_ISO88591;
+    str->size = str->len;
+    if(fCe == 1)
+        fsw_free(begin);
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin)
+{
+    int rc;
+    int i;
+    fsw_u8 *r = begin + ISOINT(ce->X.offset);
+    int len = ISOINT(ce->X.len);
+    rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin);
+    if (rc != FSW_SUCCESS)
+        return rc;
+    for (i = 0; i < len; ++i)
+    {
+        DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+    }
+    return FSW_SUCCESS;
+}
+static void dump_dirrec(struct iso9660_dirrec *dirrec)
+{
+    int i;
+    fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length;
+    int len = dirrec->dirrec_length;
+    for (i = dirrec->file_identifier_length; i < len; ++i)
+    {
+        DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+    }
+}
+/**
+ * Mount an ISO9660 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blockno;
+    struct iso9660_volume_descriptor *voldesc;
+    struct iso9660_primary_volume_descriptor *pvoldesc;
+    fsw_u32         voldesc_type;
+    int             i;
+    struct fsw_string s;
+    struct iso9660_dirrec rootdir;
+    int sua_pos;
+    char *sig;
+    int skip;
+    struct fsw_rock_ridge_susp_entry *entry;
+
+    // read through the Volume Descriptor Set
+    fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
+    blockno = ISO9660_SUPERBLOCK_BLOCKNO;
+
+    do {
+        status = fsw_block_get(vol, blockno, 0, &buffer);
+        if (status)
+            return status;
+
+        voldesc = (struct iso9660_volume_descriptor *)buffer;
+        voldesc_type = voldesc->volume_descriptor_type;
+        if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
+            // descriptor follows ISO 9660 standard
+            if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
+                // suitable Primary Volume Descriptor found
+                if (vol->primary_voldesc) {
+                    fsw_free(vol->primary_voldesc);
+                    vol->primary_voldesc = NULL;
+                }
+                status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
+            }
+        } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
+            // completely alien standard identifier, stop reading
+            voldesc_type = 255;
+        }
+
+        fsw_block_release(vol, blockno, buffer);
+        blockno++;
+    } while (!status && voldesc_type != 255);
+    if (status)
+        return status;
+
+    // get information from Primary Volume Descriptor
+    if (vol->primary_voldesc == NULL)
+        return FSW_UNSUPPORTED;
+    pvoldesc = vol->primary_voldesc;
+    if (ISOINT(pvoldesc->logical_block_size) != 2048)
+        return FSW_UNSUPPORTED;
+
+    // get volume name
+    for (i = 32; i > 0; i--)
+        if (pvoldesc->volume_identifier[i-1] != ' ')
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = pvoldesc->volume_identifier;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
+    if (status)
+        return status;
+    fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));
+
+    if (   pvoldesc->escape[0] == 0x25
+        && pvoldesc->escape[1] == 0x2f
+        && (   pvoldesc->escape[2] == 0x40
+            || pvoldesc->escape[2] == 0x43
+            || pvoldesc->escape[2] == 0x45))
+    {
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
+        vol->fJoliet = 1;
+    }
+
+
+    rootdir = pvoldesc->root_directory;
+    sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
+    //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
+    //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
+
+#if 1
+    status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
+    sig = (char *)buffer + sua_pos;
+    skip = 0;
+    entry = (struct fsw_rock_ridge_susp_entry *)sig;
+    if (   entry->sig[0] == 'S'
+        && entry->sig[1] == 'P')
+    {
+        struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
+        if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
+        {
+            vol->fRockRidge = 1;
+        } else {
+            FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
+        }
+        skip = sp->skip;
+    }
+#endif
+    // release volume descriptors
+    fsw_free(vol->primary_voldesc);
+    vol->primary_voldesc = NULL;
+
+
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol)
+{
+    if (vol->primary_voldesc)
+        fsw_free(vol->primary_voldesc);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count      * vol->g.log_blocksize;
+    sb->free_bytes  = 0;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of iso9660, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+    // get info from the directory record
+    dno->g.size = ISOINT(dno->dirrec.data_length);
+    if (dno->dirrec.file_flags & 0x02)
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_dnode_stat *sb)
+{
+    sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1);
+    /*
+    sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+    sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+    sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+    sb->store_attr_posix(sb, dno->raw->i_mode);
+    */
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_extent *extent)
+{
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_iso9660_dnode_read_info was called successfully on it.
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->phys_start = ISOINT(dno->dirrec.extent_location);
+    extent->log_start = 0;
+    extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    struct iso9660_dirrec_buffer dirrec_buffer;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+    // Preconditions: The caller has checked that dno is a directory node.
+
+    // setup handle to read the directory
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+
+    // scan the directory for the file
+    while (1) {
+        // read next entry
+        status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer);
+        if (status)
+            goto errorexit;
+        if (dirrec->dirrec_length == 0) {
+            // end of directory reached
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // skip . and ..
+        if (dirrec->file_identifier_length == 1 &&
+            (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+            continue;
+
+        // compare name
+        if (fsw_streq(lookup_name, &dirrec_buffer.name))  // TODO: compare case-insensitively
+            break;
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+    if (status == FSW_SUCCESS)
+        fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+errorexit:
+    fsw_shandle_close(&shand);
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct iso9660_dirrec_buffer dirrec_buffer;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+    /* (vasily) direcory nodes are 4096 bytes that is two logical blocks so read dir operation
+     * should read both blocks.
+     */
+
+    while (1) {
+        // read next entry
+        if (shand->pos >= dno->g.size)
+            return FSW_NOT_FOUND; // end of directory
+        status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer);
+        if (status)
+            return status;
+        if (dirrec->dirrec_length == 0)
+        {
+            // try the next block
+            shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize;
+            continue;
+        }
+
+        // skip . and ..
+        if (dirrec->file_identifier_length == 1 &&
+            (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+            continue;
+        break;
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+    if (status == FSW_SUCCESS)
+        fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+    return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer)
+{
+    fsw_status_t    status;
+    fsw_u32         i, buffer_size, remaining_size, name_len;
+    struct fsw_rock_ridge_susp_sp *sp = NULL;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec;
+    int sp_off;
+    int rc;
+
+    dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location)
+                          << ISO9660_BLOCKSIZE_BITS)
+        + (fsw_u32)shand->pos;
+
+    // read fixed size part of directory record
+    buffer_size = 33;
+    status = fsw_shandle_read(shand, &buffer_size, dirrec);
+    if (status)
+    {
+        DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
+        return status;
+    }
+
+    if (buffer_size < 33 || dirrec->dirrec_length == 0) {
+        // end of directory reached
+        fsw_u8 *r;
+        r = (fsw_u8 *)dirrec;
+        DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
+        for(i = 0; i < buffer_size; ++i)
+        {
+            DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i]));
+        }
+        dirrec->dirrec_length = 0;
+        return FSW_SUCCESS;
+    }
+    if (dirrec->dirrec_length < 33 ||
+        dirrec->dirrec_length < 33 + dirrec->file_identifier_length)
+        return FSW_VOLUME_CORRUPTED;
+
+    DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
+
+    // read variable size part of directory record
+    buffer_size = remaining_size = dirrec->dirrec_length - 33;
+    status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier);
+    if (status)
+        return status;
+    if (buffer_size < remaining_size)
+        return FSW_VOLUME_CORRUPTED;
+
+     dump_dirrec(dirrec);
+     if (vol->fRockRidge)
+     {
+         sp_off = sizeof(*dirrec) + dirrec->file_identifier_length;
+         rc = rr_find_sp(dirrec, &sp);
+         if (   rc == FSW_SUCCESS
+             && sp != NULL)
+         {
+            sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip;
+         }
+         rc = rr_find_nm(vol, dirrec, sp_off,  &dirrec_buffer->name);
+         if (rc == FSW_SUCCESS)
+            return FSW_SUCCESS;
+    }
+
+    // setup name
+    name_len = dirrec->file_identifier_length;
+    for (i = name_len - 1; i > 0; i--) {
+        if (dirrec->file_identifier[i] == ';') {
+            name_len = i;   // cut the ISO9660 version number off
+            break;
+        }
+    }
+    if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.')
+        name_len--;   // also cut the extension separator if the extension is empty
+    dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591;
+    dirrec_buffer->name.len = dirrec_buffer->name.size = name_len;
+    dirrec_buffer->name.data = dirrec->file_identifier;
+    DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For iso9660, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    status = fsw_dnode_readlink_data(dno, link_target);
+
+    return status;
+}
+
+// EOF
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.h	(revision 29125)
@@ -0,0 +1,204 @@
+/* $Id$ */
+/** @file
+ * fsw_iso9660.h - ISO9660 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_ISO9660_H_
+#define _FSW_ISO9660_H_
+
+#define VOLSTRUCTNAME fsw_iso9660_volume
+#define DNODESTRUCTNAME fsw_iso9660_dnode
+#include "fsw_core.h"
+
+
+//! Block size for ISO9660 volumes.
+#define ISO9660_BLOCKSIZE          2048
+#define ISO9660_BLOCKSIZE_BITS       11
+//! Block number where the ISO9660 superblock resides.
+#define ISO9660_SUPERBLOCK_BLOCKNO   16
+
+
+#pragma pack(1)
+
+typedef struct {
+    fsw_u16     lsb;
+    fsw_u16     msb;
+} iso9660_u16;
+
+typedef struct {
+    fsw_u32     lsb;
+    fsw_u32     msb;
+} iso9660_u32;
+
+#define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb)
+
+struct iso9660_dirrec {
+    fsw_u8      dirrec_length;
+    fsw_u8      ear_length;
+    iso9660_u32 extent_location;
+    iso9660_u32 data_length;
+    fsw_u8      recording_datetime[7];
+    fsw_u8      file_flags;
+    fsw_u8      file_unit_size;
+    fsw_u8      interleave_gap_size;
+    iso9660_u16 volume_sequence_number;
+    fsw_u8      file_identifier_length;
+    char        file_identifier[1];
+};
+//#if sizeof(struct fsw_iso9660_dirrec) != 34
+//#fail Structure fsw_iso9660_dirrec has wrong size
+//#endif
+
+struct iso9660_volume_descriptor {
+    fsw_u8      volume_descriptor_type;
+    char        standard_identifier[5];
+    fsw_u8      volume_descriptor_version;
+};
+
+struct iso9660_primary_volume_descriptor {
+    fsw_u8      volume_descriptor_type;
+    char        standard_identifier[5];
+    fsw_u8      volume_descriptor_version;
+    fsw_u8      unused1;
+    char        system_identifier[32];
+    char        volume_identifier[32];
+    fsw_u8      unused2[8];
+    iso9660_u32 volume_space_size;
+    fsw_u8      unused3[4];
+    fsw_u8      escape[3];
+    fsw_u8      unused4[25];
+    iso9660_u16 volume_set_size;
+    iso9660_u16 volume_sequence_number;
+    iso9660_u16 logical_block_size;
+    iso9660_u32 path_table_size;
+    fsw_u32     location_type_l_path_table;
+    fsw_u32     location_optional_type_l_path_table;
+    fsw_u32     location_type_m_path_table;
+    fsw_u32     location_optional_type_m_path_table;
+    struct iso9660_dirrec root_directory;
+    char        volume_set_identifier[128];
+    char        publisher_identifier[128];
+    char        data_preparer_identifier[128];
+    char        application_identifier[128];
+    char        copyright_file_identifier[37];
+    char        abstract_file_identifier[37];
+    char        bibliographic_file_identifier[37];
+    char        volume_creation_datetime[17];
+    char        volume_modification_datetime[17];
+    char        volume_expiration_datetime[17];
+    char        volume_effective_datetime[17];
+    fsw_u8      file_structure_version;
+    fsw_u8      reserved1;
+    fsw_u8      application_use[512];
+    fsw_u8      reserved2[653];
+};
+//#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048
+//#fail Structure fsw_iso9660_volume_descriptor has wrong size
+//#endif
+
+#pragma pack()
+
+struct iso9660_dirrec_buffer {
+    fsw_u32     ino;
+    struct fsw_string name;
+    struct iso9660_dirrec dirrec;
+    char        dirrec_buffer[222];
+};
+
+
+/**
+ * ISO9660: Volume structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    /*Note: don't move g!*/
+    int fJoliet;
+    /*Joliet specific fields*/
+    int fRockRidge;
+    /*Rock Ridge specific fields*/
+    int rr_susp_skip;
+
+    struct iso9660_primary_volume_descriptor *primary_voldesc;  //!< Full Primary Volume Descriptor
+};
+
+/**
+ * ISO9660: Dnode structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+
+    struct iso9660_dirrec dirrec;   //!< Fixed part of the directory record (i.e. w/o name)
+};
+
+
+struct fsw_rock_ridge_susp_entry
+{
+    fsw_u8  sig[2];
+    fsw_u8  len;
+    fsw_u8  ver;
+};
+
+struct fsw_rock_ridge_susp_sp
+{
+    struct fsw_rock_ridge_susp_entry e;
+    fsw_u8  magic[2];
+    fsw_u8  skip;
+};
+
+struct fsw_rock_ridge_susp_nm
+{
+    struct fsw_rock_ridge_susp_entry e;
+    fsw_u8  flags;
+    fsw_u8  name[1];
+};
+
+#define RR_NM_CONT (1<<0)
+#define RR_NM_CURR (1<<1)
+#define RR_NM_PARE (1<<2)
+
+union fsw_rock_ridge_susp_ce
+{
+    struct X{
+        struct fsw_rock_ridge_susp_entry e;
+        iso9660_u32 block_loc;
+        iso9660_u32 offset;
+        iso9660_u32 len;
+    } X;
+    fsw_u8 raw[28];
+};
+
+#endif
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_lib.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_lib.c	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_lib.c	(revision 29125)
@@ -0,0 +1,547 @@
+/* $Id$ */
+/** @file
+ * fsw_lib.c - Core file system wrapper library functions.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+/* Include generated string encoding specific functions */
+#include "fsw_strfunc.h"
+
+
+/**
+ * Allocate memory and clear it.
+ */
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out)
+{
+    fsw_status_t status;
+
+    status = fsw_alloc(len, ptr_out);
+    if (status)
+        return status;
+    fsw_memzero(*ptr_out, len);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Duplicate a piece of data.
+ */
+
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len)
+{
+    fsw_status_t status;
+
+    status = fsw_alloc(len, dest_out);
+    if (status)
+        return status;
+    fsw_memcpy(*dest_out, src, len);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the length of a string. Returns the number of characters in the string.
+ */
+
+int fsw_strlen(struct fsw_string *s)
+{
+    if (s->type == FSW_STRING_TYPE_EMPTY)
+        return 0;
+    return s->len;
+}
+
+#if 0
+static const fsw_u16
+fsw_lower_case_table[] =
+{
+
+    /* High-byte indices ( == 0 iff no case mapping and no ignorables ) */
+
+    /* 0 */	0x0000, 0x0100, 0x0000, 0x0200, 0x0300, 0x0400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 1 */	0x0500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 2 */	0x0600, 0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 3 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 4 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 5 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 6 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 7 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 8 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 9 */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* A */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* B */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* C */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* D */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* E */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* F */	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0900,
+
+    /* Table 1 (for high byte 0x01) */
+
+    /* 0 */	0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+    /* 1 */	0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+    /* 2 */	0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+    /* 3 */	0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+    /* 4 */	0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+    /* 5 */	0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+    /* 6 */	0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+    /* 7 */	0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+    /* 8 */	0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+    /* 9 */	0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+    /* A */	0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+    /* B */	0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+    /* C */	0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+    /* D */	0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+    /* E */	0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+    /* F */	0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+    /* Table 2 (for high byte 0x03) */
+
+    /* 0 */	0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+    /* 1 */	0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+    /* 2 */	0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+    /* 3 */	0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+    /* 4 */	0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+    /* 5 */	0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+    /* 6 */	0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+    /* 7 */	0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+    /* 8 */	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+    /* 9 */	0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    /* A */	0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+    /* B */	0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    /* C */	0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+    /* D */	0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+    /* E */	0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+    /* F */	0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+    /* Table 3 (for high byte 0x04) */
+
+    /* 0 */	0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+    /* 1 */	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    /* 2 */	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    /* 3 */	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    /* 4 */	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    /* 5 */	0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+    /* 6 */	0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+    /* 7 */	0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+    /* 8 */	0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+    /* 9 */	0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+    /* A */	0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+    /* B */	0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+    /* C */	0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+    /* D */	0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+    /* E */	0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+    /* F */	0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+    /* Table 4 (for high byte 0x05) */
+
+    /* 0 */	0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+    /* 1 */	0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+    /* 2 */	0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+    /* 3 */	0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+    /* 4 */	0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+    /* 5 */	0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+    /* 6 */	0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+    /* 7 */	0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+    /* 8 */	0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+    /* 9 */	0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+    /* A */	0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+    /* B */	0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+    /* C */	0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+    /* D */	0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    /* E */	0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+    /* F */	0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+    /* Table 5 (for high byte 0x10) */
+
+    /* 0 */	0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+    /* 1 */	0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+    /* 2 */	0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+    /* 3 */	0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+    /* 4 */	0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+    /* 5 */	0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+    /* 6 */	0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+    /* 7 */	0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+    /* 8 */	0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+    /* 9 */	0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+    /* A */	0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+    /* B */	0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+    /* C */	0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+    /* D */	0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+    /* E */	0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+    /* F */	0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+    /* Table 6 (for high byte 0x20) */
+
+    /* 0 */	0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 1 */	0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+    /* 2 */	0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+    /* 3 */	0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+    /* 4 */	0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+    /* 5 */	0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+    /* 6 */	0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 7 */	0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+    /* 8 */	0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+    /* 9 */	0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+    /* A */	0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+    /* B */	0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+    /* C */	0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+    /* D */	0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+    /* E */	0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+    /* F */	0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+    /* Table 7 (for high byte 0x21) */
+
+    /* 0 */	0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+    /* 1 */	0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+    /* 2 */	0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+    /* 3 */	0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+    /* 4 */	0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+    /* 5 */	0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+    /* 6 */	0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+    /* 7 */	0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+    /* 8 */	0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+    /* 9 */	0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+    /* A */	0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+    /* B */	0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+    /* C */	0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+    /* D */	0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+    /* E */	0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+    /* F */	0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+    /* Table 8 (for high byte 0xFE) */
+
+    /* 0 */	0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+    /* 1 */	0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+    /* 2 */	0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+    /* 3 */	0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+    /* 4 */	0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+    /* 5 */	0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+    /* 6 */	0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+    /* 7 */	0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+    /* 8 */	0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+    /* 9 */	0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+    /* A */	0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+    /* B */	0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+    /* C */	0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+    /* D */	0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+    /* E */	0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+    /* F */	0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+    /* Table 9 (for high byte 0xFF) */
+
+    /* 0 */	0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+    /* 1 */	0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+    /* 2 */	0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+    /* 3 */	0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+    /* 4 */	0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+    /* 5 */	0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+    /* 6 */	0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+    /* 7 */	0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+    /* 8 */	0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+    /* 9 */	0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+    /* A */	0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+    /* B */	0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+    /* C */	0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+    /* D */	0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+    /* E */	0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+    /* F */	0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+#endif
+
+static const fsw_u16 fsw_latin_case_fold[] =
+{
+    /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+    /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+    /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+    /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+    /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+    /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+    /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+    /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+    /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+    /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+    /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+    /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+};
+
+
+fsw_u16 fsw_to_lower(fsw_u16 ch)
+{
+#if 0
+    fsw_u16 temp = temp;
+#endif
+
+    if (ch < 0x0100)
+        return fsw_latin_case_fold[ch];
+#if 0
+    /*
+     * Uncomment this along with above huuuge table (fsw_lower_case_table)
+     * for full UTF-16 case insensitivity
+     */
+    temp = fsw_lower_case_table[ch>>8];
+    if (temp != 0)
+        return fsw_lower_case_table[temp + (ch & 0x00FF)];
+#endif
+
+    return ch;
+}
+
+/**
+ * Compare two strings for equality. The two strings are compared, taking their
+ * encoding into account. If they are considered equal, boolean true is returned.
+ * Otherwise, boolean false is returned.
+ */
+
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2)
+{
+    struct fsw_string temp_s;
+
+    // handle empty strings
+    if (s1->type == FSW_STRING_TYPE_EMPTY) {
+        temp_s.type = FSW_STRING_TYPE_ISO88591;
+        temp_s.size = temp_s.len = 0;
+        temp_s.data = NULL;
+        return fsw_streq(&temp_s, s2);
+    }
+    if (s2->type == FSW_STRING_TYPE_EMPTY) {
+        temp_s.type = FSW_STRING_TYPE_ISO88591;
+        temp_s.size = temp_s.len = 0;
+        temp_s.data = NULL;
+        return fsw_streq(s1, &temp_s);
+    }
+
+    // check length (count of chars)
+    if (s1->len != s2->len)
+        return 0;
+    if (s1->len == 0)   // both strings are empty
+        return 1;
+
+    if (s1->type == s2->type) {
+        // same type, do a dumb memory compare
+        if (s1->size != s2->size)
+            return 0;
+        return fsw_memeq(s1->data, s2->data, s1->size);
+    }
+
+    // dispatch to type-specific functions
+    #define STREQ_DISPATCH(type1, type2) \
+      if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \
+        return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \
+      if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \
+        return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len);
+    STREQ_DISPATCH(ISO88591, UTF8);
+    STREQ_DISPATCH(ISO88591, UTF16);
+    STREQ_DISPATCH(ISO88591, UTF16_SWAPPED);
+    STREQ_DISPATCH(UTF8, UTF16);
+    STREQ_DISPATCH(UTF8, UTF16_SWAPPED);
+    STREQ_DISPATCH(UTF16, UTF16_SWAPPED);
+
+    // final fallback
+    return 0;
+}
+
+/**
+ * Compare a string with a C string constant. This sets up a string descriptor
+ * for the string constant (second argument) and runs fsw_streq on the two
+ * strings. Currently the C string is interpreted as ISO 8859-1.
+ * Returns boolean true if the strings are considered equal, boolean false otherwise.
+ */
+
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2)
+{
+    struct fsw_string temp_s;
+    int i;
+
+    for (i = 0; s2[i]; i++)
+        ;
+
+    temp_s.type = FSW_STRING_TYPE_ISO88591;
+    temp_s.size = temp_s.len = i;
+    temp_s.data = (char *)s2;
+
+    return fsw_streq(s1, &temp_s);
+}
+
+/**
+ * Creates a duplicate of a string, converting it to the given encoding during the copy.
+ * If the function returns FSW_SUCCESS, the caller must free the string later with
+ * fsw_strfree.
+ */
+
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+{
+    fsw_status_t    status;
+
+    if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) {
+        dest->type = type;
+        dest->size = dest->len = 0;
+        dest->data = NULL;
+        return FSW_SUCCESS;
+    }
+
+    if (src->type == type) {
+        dest->type = type;
+        dest->len  = src->len;
+        dest->size = src->size;
+        status = fsw_alloc(dest->size, &dest->data);
+        if (status)
+            return status;
+
+        fsw_memcpy(dest->data, src->data, dest->size);
+        return FSW_SUCCESS;
+    }
+
+    // dispatch to type-specific functions
+    #define STRCOERCE_DISPATCH(type1, type2) \
+      if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \
+        return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest);
+    STRCOERCE_DISPATCH(UTF8, ISO88591);
+    STRCOERCE_DISPATCH(UTF16, ISO88591);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591);
+    STRCOERCE_DISPATCH(ISO88591, UTF8);
+    STRCOERCE_DISPATCH(UTF16, UTF8);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8);
+    STRCOERCE_DISPATCH(ISO88591, UTF16);
+    STRCOERCE_DISPATCH(UTF8, UTF16);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16);
+
+    return FSW_UNSUPPORTED;
+}
+
+/**
+ * Splits a string at the first occurence of the separator character.
+ * The buffer string is searched for the separator character. If it is found, the
+ * element string descriptor is filled to point at the part of the buffer string
+ * before the separator. The buffer string itself is adjusted to point at the
+ * remaining part of the string (without the separator).
+ *
+ * If the separator is not found in the buffer string, then element is changed to
+ * point at the whole buffer string, and the buffer string itself is changed into
+ * an empty string.
+ *
+ * This function only manipulates the pointers and lengths in the two string descriptors,
+ * it does not change the actual string. If the buffer string is dynamically allocated,
+ * you must make a copy of it so that you can release it later.
+ */
+
+void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator)
+{
+    int i, maxlen;
+
+    if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) {
+        element->type = FSW_STRING_TYPE_EMPTY;
+        return;
+    }
+
+    maxlen = buffer->len;
+    *element = *buffer;
+
+    if (buffer->type == FSW_STRING_TYPE_ISO88591) {
+        fsw_u8 *p;
+
+        p = (fsw_u8 *)element->data;
+        for (i = 0; i < maxlen; i++, p++) {
+            if (*p == separator) {
+                buffer->data = p + 1;
+                buffer->len -= i + 1;
+                break;
+            }
+        }
+        element->len = i;
+        if (i == maxlen) {
+            buffer->data = p;
+            buffer->len -= i;
+        }
+
+        element->size = element->len;
+        buffer->size  = buffer->len;
+
+    } else if (buffer->type == FSW_STRING_TYPE_UTF16) {
+        fsw_u16 *p;
+
+        p = (fsw_u16 *)element->data;
+        for (i = 0; i < maxlen; i++, p++) {
+            if (*p == separator) {
+                buffer->data = p + 1;
+                buffer->len -= i + 1;
+                break;
+            }
+        }
+        element->len = i;
+        if (i == maxlen) {
+            buffer->data = p;
+            buffer->len -= i;
+        }
+
+        element->size = element->len * sizeof(fsw_u16);
+        buffer->size  = buffer->len  * sizeof(fsw_u16);
+
+    } else {
+        // fallback
+        buffer->type = FSW_STRING_TYPE_EMPTY;
+    }
+
+    // TODO: support UTF8 and UTF16_SWAPPED
+}
+
+/**
+ * Frees the memory used by a string returned from fsw_strdup_coerce.
+ */
+
+void fsw_strfree(struct fsw_string *s)
+{
+    if (s->type != FSW_STRING_TYPE_EMPTY && s->data)
+        fsw_free(s->data);
+    s->type = FSW_STRING_TYPE_EMPTY;
+}
+
+// EOF
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_strfunc.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_strfunc.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_strfunc.h	(revision 29125)
@@ -0,0 +1,472 @@
+/* $Id$ */
+/** @file
+ * fsw_strfunc.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* fsw_strfunc.h generated by mk_fsw_strfunc.py */
+
+static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u8 *p2 = (fsw_u8 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++;
+        if ((c2 & 0xe0) == 0xc0) {
+            c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f);
+        } else if ((c2 & 0xf0) == 0xe0) {
+            c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6);
+            c2 |= (*p2++ & 0x3f);
+        } else if ((c2 & 0xf8) == 0xf0) {
+            c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12);
+            c2 |= ((*p2++ & 0x3f) << 6);
+            c2 |= (*p2++ & 0x3f);
+        }
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+#ifndef HOST_EFI
+static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++;
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+#endif
+
+static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        if ((c1 & 0xe0) == 0xc0) {
+            c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+        } else if ((c1 & 0xf0) == 0xe0) {
+            c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        } else if ((c1 & 0xf8) == 0xf0) {
+            c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+            c1 |= ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        }
+        c2 = *p2++;
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        if ((c1 & 0xe0) == 0xc0) {
+            c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+        } else if ((c1 & 0xf0) == 0xe0) {
+            c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        } else if ((c1 & 0xf8) == 0xf0) {
+            c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+            c1 |= ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        }
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u16 *p1 = (fsw_u16 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        if ((c & 0xe0) == 0xc0) {
+            c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+        } else if ((c & 0xf0) == 0xe0) {
+            c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        } else if ((c & 0xf8) == 0xf0) {
+            c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+            c |= ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        }
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        if ((c & 0xe0) == 0xc0) {
+            c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+        } else if ((c & 0xf0) == 0xe0) {
+            c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        } else if ((c & 0xf8) == 0xf0) {
+            c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+            c |= ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        }
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u8       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u8 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u16 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u16 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/hfs_format.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/hfs_format.h	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/hfs_format.h	(revision 29125)
@@ -0,0 +1,784 @@
+/* $Id$ */
+/** @file
+ * hfs_format.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#ifndef __HFS_FORMAT__
+#define __HFS_FORMAT__
+
+#if !defined(VBOX) && !defined(HOST_POSIX)
+#include <sys/types.h>
+#include <sys/appleapiopts.h>
+#endif
+
+#ifdef _MSC_VER
+# pragma pack(push,2)
+# define HFS_ALIGNMENT
+#else
+#define HFS_ALIGNMENT __attribute__((aligned(2), packed))
+#endif
+
+/*
+ * hfs_format.c
+ *
+ * This file describes the on-disk format for HFS and HFS Plus volumes.
+ * The HFS Plus volume format is desciibed in detail in Apple Technote 1150.
+ *
+ * http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* some on-disk hfs structures have 68K alignment (misaligned) */
+
+/* Signatures used to differentiate between HFS and HFS Plus volumes */
+enum {
+	kHFSSigWord		= 0x4244,	/* 'BD' in ASCII */
+	kHFSPlusSigWord		= 0x482B,	/* 'H+' in ASCII */
+	kHFSXSigWord		= 0x4858,	/* 'HX' in ASCII */
+
+	kHFSPlusVersion		= 0x0004,	/* 'H+' volumes are version 4 only */
+	kHFSXVersion		= 0x0005,	/* 'HX' volumes start with version 5 */
+
+	kHFSPlusMountVersion	= 0x31302E30,	/* '10.0' for Mac OS X */
+	kHFSJMountVersion	= 0x4846534a,	/* 'HFSJ' for journaled HFS+ on OS X */
+	kFSKMountVersion	= 0x46534b21	/* 'FSK!' for failed journal replay */
+};
+
+
+#ifdef __APPLE_API_PRIVATE
+/*
+ * Mac OS X has two special directories on HFS+ volumes for hardlinked files
+ * and hardlinked directories as well as for open-unlinked files.
+ *
+ * These directories and their contents are not exported from the filesystem
+ * under Mac OS X.
+ */
+#define HFSPLUSMETADATAFOLDER       "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"
+#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd"
+
+/*
+ * Files in the "HFS+ Private Data" folder have one of the following prefixes
+ * followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * Note: Earlier version of Mac OS X used a 32 bit random number for the link
+ * ref number instead of the file id.
+ *
+ * e.g.  iNode7182000 and temp3296
+ */
+#define HFS_INODE_PREFIX	"iNode"
+#define HFS_DELETE_PREFIX	"temp"
+
+/*
+ * Files in the ".HFS+ Private Directory Data" folder have the following
+ * prefix followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * e.g. dir_555
+ */
+#define HFS_DIRINODE_PREFIX	"dir_"
+
+/*
+ * Hardlink inodes save the head of the link chain in
+ * an extended attribute named FIRST_LINK_XATTR_NAME.
+ * The attribute data is the decimal value in ASCII
+ * of the cnid for the first link in the chain.
+ *
+ * This extended attribute is private (i.e. its not
+ * exported in the getxattr/listxattr POSIX APIs).
+ */
+#define FIRST_LINK_XATTR_NAME	"com.apple.system.hfs.firstlink"
+#define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12)
+
+#endif /* __APPLE_API_PRIVATE */
+
+/*
+ * Indirect link files (hard links) have the following type/creator.
+ */
+enum {
+	kHardLinkFileType = 0x686C6E6B,  /* 'hlnk' */
+	kHFSPlusCreator   = 0x6866732B   /* 'hfs+' */
+};
+
+
+/*
+ *	File type and creator for symbolic links
+ */
+enum {
+      kSymLinkFileType  = 0x736C6E6B, /* 'slnk' */
+      kSymLinkCreator   = 0x72686170  /* 'rhap' */
+};
+
+
+#ifndef _HFSUNISTR255_DEFINED_
+#define _HFSUNISTR255_DEFINED_
+/* Unicode strings are used for HFS Plus file and folder names */
+struct HFSUniStr255 {
+	u_int16_t	length;		/* number of unicode characters */
+	u_int16_t	unicode[255];	/* unicode characters */
+} HFS_ALIGNMENT;
+typedef struct HFSUniStr255 HFSUniStr255;
+typedef const HFSUniStr255 *ConstHFSUniStr255Param;
+#endif /* _HFSUNISTR255_DEFINED_ */
+
+enum {
+	kHFSMaxVolumeNameChars		= 27,
+	kHFSMaxFileNameChars		= 31,
+	kHFSPlusMaxFileNameChars	= 255
+};
+
+
+/* Extent overflow file data structures */
+
+/* HFS Extent key */
+struct HFSExtentKey {
+	u_int8_t	keyLength;	/* length of key, excluding this field */
+	u_int8_t	forkType;	/* 0 = data fork, FF = resource fork */
+	u_int32_t	fileID;		/* file ID */
+	u_int16_t	startBlock;	/* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentKey HFSExtentKey;
+
+/* HFS Plus Extent key */
+struct HFSPlusExtentKey {
+	u_int16_t	keyLength;		/* length of key, excluding this field */
+	u_int8_t	forkType;		/* 0 = data fork, FF = resource fork */
+	u_int8_t	pad;			/* make the other fields align on 32-bit boundary */
+	u_int32_t	fileID;			/* file ID */
+	u_int32_t	startBlock;		/* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentKey HFSPlusExtentKey;
+
+/* Number of extent descriptors per extent record */
+enum {
+	kHFSExtentDensity	= 3,
+	kHFSPlusExtentDensity	= 8
+};
+
+/* HFS extent descriptor */
+struct HFSExtentDescriptor {
+	u_int16_t	startBlock;		/* first allocation block */
+	u_int16_t	blockCount;		/* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentDescriptor HFSExtentDescriptor;
+
+/* HFS Plus extent descriptor */
+struct HFSPlusExtentDescriptor {
+	u_int32_t	startBlock;		/* first allocation block */
+	u_int32_t	blockCount;		/* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor;
+
+/* HFS extent record */
+typedef HFSExtentDescriptor HFSExtentRecord[3];
+
+/* HFS Plus extent record */
+typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8];
+
+
+/* Finder information */
+struct FndrFileInfo {
+	u_int32_t	fdType;		/* file type */
+	u_int32_t	fdCreator;	/* file creator */
+	u_int16_t	fdFlags;	/* Finder flags */
+	struct {
+	    int16_t	v;		/* file's location */
+	    int16_t	h;
+	} fdLocation;
+	int16_t	opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrFileInfo FndrFileInfo;
+
+struct FndrDirInfo {
+	struct {			/* folder's window rectangle */
+	    int16_t	top;
+	    int16_t	left;
+	    int16_t	bottom;
+	    int16_t	right;
+	} frRect;
+	unsigned short	frFlags;	/* Finder flags */
+	struct {
+	    u_int16_t	v;		/* folder's location */
+	    u_int16_t	h;
+	} frLocation;
+	int16_t	opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrDirInfo FndrDirInfo;
+
+struct FndrOpaqueInfo {
+	int8_t opaque[16];
+} HFS_ALIGNMENT;
+typedef struct FndrOpaqueInfo FndrOpaqueInfo;
+
+
+/* HFS Plus Fork data info - 80 bytes */
+struct HFSPlusForkData {
+	u_int64_t		logicalSize;	/* fork's logical size in bytes */
+	u_int32_t		clumpSize;	/* fork's clump size in bytes */
+	u_int32_t		totalBlocks;	/* total blocks used by this fork */
+	HFSPlusExtentRecord	extents;	/* initial set of extents */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusForkData HFSPlusForkData;
+
+
+/* Mac OS X has 16 bytes worth of "BSD" info.
+ *
+ * Note:  Mac OS 9 implementations and applications
+ * should preserve, but not change, this information.
+ */
+struct HFSPlusBSDInfo {
+	u_int32_t	ownerID;	/* user-id of owner or hard link chain previous link */
+	u_int32_t	groupID;	/* group-id of owner or hard link chain next link */
+	u_int8_t	adminFlags;	/* super-user changeable flags */
+	u_int8_t	ownerFlags;	/* owner changeable flags */
+	u_int16_t	fileMode;	/* file type and permission bits */
+	union {
+	    u_int32_t	iNodeNum;	/* indirect node number (hard links only) */
+	    u_int32_t	linkCount;	/* links that refer to this indirect node */
+	    u_int32_t	rawDevice;	/* special file device (FBLK and FCHR only) */
+	} special;
+} HFS_ALIGNMENT;
+typedef struct HFSPlusBSDInfo HFSPlusBSDInfo;
+
+/*
+ * Hardlink "links" resolve to an inode
+ * and the actual uid/gid comes from that
+ * inode.
+ *
+ * We repurpose the links's uid/gid fields
+ * for the hardlink link chain. The chain
+ * consists of a doubly linked list of file
+ * ids.
+ */
+
+#define hl_firstLinkID     reserved1         /* Valid only if HasLinkChain flag is set (indirect nodes only) */
+
+#define hl_prevLinkID      bsdInfo.ownerID   /* Valid only if HasLinkChain flag is set */
+#define hl_nextLinkID      bsdInfo.groupID   /* Valid only if HasLinkChain flag is set */
+
+#define hl_linkReference   bsdInfo.special.iNodeNum
+#define hl_linkCount       bsdInfo.special.linkCount
+
+
+/* Catalog file data structures */
+
+enum {
+	kHFSRootParentID		= 1,	/* Parent ID of the root folder */
+	kHFSRootFolderID		= 2,	/* Folder ID of the root folder */
+	kHFSExtentsFileID		= 3,	/* File ID of the extents file */
+	kHFSCatalogFileID		= 4,	/* File ID of the catalog file */
+	kHFSBadBlockFileID		= 5,	/* File ID of the bad allocation block file */
+	kHFSAllocationFileID		= 6,	/* File ID of the allocation file (HFS Plus only) */
+	kHFSStartupFileID		= 7,	/* File ID of the startup file (HFS Plus only) */
+	kHFSAttributesFileID		= 8,	/* File ID of the attribute file (HFS Plus only) */
+	kHFSAttributeDataFileID         = 13,	/* Used in Mac OS X runtime for extent based attributes */
+	                                        /* kHFSAttributeDataFileID is never stored on disk. */
+	kHFSRepairCatalogFileID		= 14,	/* Used when rebuilding Catalog B-tree */
+	kHFSBogusExtentFileID		= 15,	/* Used for exchanging extents in extents file */
+	kHFSFirstUserCatalogNodeID	= 16
+};
+
+/* HFS catalog key */
+struct HFSCatalogKey {
+	u_int8_t	keyLength;		/* key length (in bytes) */
+	u_int8_t	reserved;		/* reserved (set to zero) */
+	u_int32_t	parentID;		/* parent folder ID */
+	u_int8_t	nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogKey HFSCatalogKey;
+
+/* HFS Plus catalog key */
+struct HFSPlusCatalogKey {
+	u_int16_t		keyLength;	/* key length (in bytes) */
+	u_int32_t		parentID;	/* parent folder ID */
+	HFSUniStr255		nodeName;	/* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogKey HFSPlusCatalogKey;
+
+/* Catalog record types */
+enum {
+	/* HFS Catalog Records */
+	kHFSFolderRecord		= 0x0100,	/* Folder record */
+	kHFSFileRecord			= 0x0200,	/* File record */
+	kHFSFolderThreadRecord		= 0x0300,	/* Folder thread record */
+	kHFSFileThreadRecord		= 0x0400,	/* File thread record */
+
+	/* HFS Plus Catalog Records */
+	kHFSPlusFolderRecord		= 1,		/* Folder record */
+	kHFSPlusFileRecord		= 2,		/* File record */
+	kHFSPlusFolderThreadRecord	= 3,		/* Folder thread record */
+	kHFSPlusFileThreadRecord	= 4		/* File thread record */
+};
+
+
+/* Catalog file record flags */
+enum {
+	kHFSFileLockedBit	= 0x0000,	/* file is locked and cannot be written to */
+	kHFSFileLockedMask	= 0x0001,
+
+	kHFSThreadExistsBit	= 0x0001,	/* a file thread record exists for this file */
+	kHFSThreadExistsMask	= 0x0002,
+
+	kHFSHasAttributesBit	= 0x0002,	/* object has extended attributes */
+	kHFSHasAttributesMask	= 0x0004,
+
+	kHFSHasSecurityBit	= 0x0003,	/* object has security data (ACLs) */
+	kHFSHasSecurityMask	= 0x0008,
+
+	kHFSHasFolderCountBit	= 0x0004,	/* only for HFSX, folder maintains a separate sub-folder count */
+	kHFSHasFolderCountMask	= 0x0010,	/* (sum of folder records and directory hard links) */
+
+	kHFSHasLinkChainBit	= 0x0005,	/* has hardlink chain (inode or link) */
+	kHFSHasLinkChainMask	= 0x0020,
+
+	kHFSHasChildLinkBit	= 0x0006,	/* folder has a child that's a dir link */
+	kHFSHasChildLinkMask	= 0x0040
+};
+
+
+/* HFS catalog folder record - 70 bytes */
+struct HFSCatalogFolder {
+	int16_t		recordType;		/* == kHFSFolderRecord */
+	u_int16_t		flags;			/* folder flags */
+	u_int16_t		valence;		/* folder valence */
+	u_int32_t		folderID;		/* folder ID */
+	u_int32_t		createDate;		/* date and time of creation */
+	u_int32_t		modifyDate;		/* date and time of last modification */
+	u_int32_t		backupDate;		/* date and time of last backup */
+	FndrDirInfo		userInfo;		/* Finder information */
+	FndrOpaqueInfo		finderInfo;		/* additional Finder information */
+	u_int32_t		reserved[4];		/* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFolder HFSCatalogFolder;
+
+/* HFS Plus catalog folder record - 88 bytes */
+struct HFSPlusCatalogFolder {
+	int16_t		recordType;		/* == kHFSPlusFolderRecord */
+	u_int16_t		flags;			/* file flags */
+	u_int32_t		valence;		/* folder's item count */
+	u_int32_t		folderID;		/* folder ID */
+	u_int32_t		createDate;		/* date and time of creation */
+	u_int32_t		contentModDate;		/* date and time of last content modification */
+	u_int32_t		attributeModDate;	/* date and time of last attribute modification */
+	u_int32_t		accessDate;		/* date and time of last access (MacOS X only) */
+	u_int32_t		backupDate;		/* date and time of last backup */
+	HFSPlusBSDInfo		bsdInfo;		/* permissions (for MacOS X) */
+	FndrDirInfo		userInfo;		/* Finder information */
+	FndrOpaqueInfo		finderInfo;		/* additional Finder information */
+	u_int32_t		textEncoding;		/* hint for name conversions */
+	u_int32_t		folderCount;		/* number of enclosed folders, active when HasFolderCount is set */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder;
+
+/* HFS catalog file record - 102 bytes */
+struct HFSCatalogFile {
+	int16_t		recordType;		/* == kHFSFileRecord */
+	u_int8_t		flags;			/* file flags */
+	int8_t			fileType;		/* file type (unused ?) */
+	FndrFileInfo		userInfo;		/* Finder information */
+	u_int32_t		fileID;			/* file ID */
+	u_int16_t		dataStartBlock;		/* not used - set to zero */
+	int32_t		dataLogicalSize;	/* logical EOF of data fork */
+	int32_t		dataPhysicalSize;	/* physical EOF of data fork */
+	u_int16_t		rsrcStartBlock;		/* not used - set to zero */
+	int32_t			rsrcLogicalSize;	/* logical EOF of resource fork */
+	int32_t			rsrcPhysicalSize;	/* physical EOF of resource fork */
+	u_int32_t		createDate;		/* date and time of creation */
+	u_int32_t		modifyDate;		/* date and time of last modification */
+	u_int32_t		backupDate;		/* date and time of last backup */
+	FndrOpaqueInfo		finderInfo;		/* additional Finder information */
+	u_int16_t		clumpSize;		/* file clump size (not used) */
+	HFSExtentRecord		dataExtents;		/* first data fork extent record */
+	HFSExtentRecord		rsrcExtents;		/* first resource fork extent record */
+	u_int32_t		reserved;		/* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFile HFSCatalogFile;
+
+/* HFS Plus catalog file record - 248 bytes */
+struct HFSPlusCatalogFile {
+	int16_t		recordType;		/* == kHFSPlusFileRecord */
+	u_int16_t		flags;			/* file flags */
+	u_int32_t		reserved1;		/* reserved - initialized as zero */
+	u_int32_t		fileID;			/* file ID */
+	u_int32_t		createDate;		/* date and time of creation */
+	u_int32_t		contentModDate;		/* date and time of last content modification */
+	u_int32_t		attributeModDate;	/* date and time of last attribute modification */
+	u_int32_t		accessDate;		/* date and time of last access (MacOS X only) */
+	u_int32_t		backupDate;		/* date and time of last backup */
+	HFSPlusBSDInfo		bsdInfo;		/* permissions (for MacOS X) */
+	FndrFileInfo		userInfo;		/* Finder information */
+	FndrOpaqueInfo		finderInfo;		/* additional Finder information */
+	u_int32_t		textEncoding;		/* hint for name conversions */
+	u_int32_t		reserved2;		/* reserved - initialized as zero */
+
+	/* Note: these start on double long (64 bit) boundary */
+	HFSPlusForkData	dataFork;		/* size and block data for data fork */
+	HFSPlusForkData	resourceFork;		/* size and block data for resource fork */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFile HFSPlusCatalogFile;
+
+/* HFS catalog thread record - 46 bytes */
+struct HFSCatalogThread {
+	int16_t	recordType;		/* == kHFSFolderThreadRecord or kHFSFileThreadRecord */
+	int32_t	reserved[2];		/* reserved - initialized as zero */
+	u_int32_t	parentID;		/* parent ID for this catalog node */
+	u_int8_t	nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogThread HFSCatalogThread;
+
+/* HFS Plus catalog thread record -- 264 bytes */
+struct HFSPlusCatalogThread {
+	int16_t	recordType;		/* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */
+	int16_t	reserved;		/* reserved - initialized as zero */
+	u_int32_t	parentID;		/* parent ID for this catalog node */
+	HFSUniStr255	nodeName;		/* name of this catalog node (variable length) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogThread HFSPlusCatalogThread;
+
+#ifdef __APPLE_API_UNSTABLE
+/*
+	These are the types of records in the attribute B-tree.  The values were
+	chosen so that they wouldn't conflict with the catalog record types.
+*/
+enum {
+	kHFSPlusAttrInlineData	= 0x10,   /* attributes whose data fits in a b-tree node */
+	kHFSPlusAttrForkData	= 0x20,   /* extent based attributes (data lives in extents) */
+	kHFSPlusAttrExtents	= 0x30    /* overflow extents for large attributes */
+};
+
+
+/*
+	HFSPlusAttrForkData
+	For larger attributes, whose value is stored in allocation blocks.
+	If the attribute has more than 8 extents, there will be additional
+	records (of type HFSPlusAttrExtents) for this attribute.
+*/
+struct HFSPlusAttrForkData {
+	u_int32_t	recordType;		/* == kHFSPlusAttrForkData*/
+	u_int32_t	reserved;
+	HFSPlusForkData theFork;		/* size and first extents of value*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrForkData HFSPlusAttrForkData;
+
+/*
+	HFSPlusAttrExtents
+	This record contains information about overflow extents for large,
+	fragmented attributes.
+*/
+struct HFSPlusAttrExtents {
+	u_int32_t		recordType;	/* == kHFSPlusAttrExtents*/
+	u_int32_t		reserved;
+	HFSPlusExtentRecord	extents;	/* additional extents*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrExtents HFSPlusAttrExtents;
+
+/*
+ * Atrributes B-tree Data Record
+ *
+ * For small attributes, whose entire value is stored
+ * within a single B-tree record.
+ */
+struct HFSPlusAttrData {
+	u_int32_t    recordType;   /* == kHFSPlusAttrInlineData */
+	u_int32_t    reserved[2];
+	u_int32_t    attrSize;     /* size of attribute data in bytes */
+	u_int8_t     attrData[2];  /* variable length */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrData HFSPlusAttrData;
+
+
+/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */
+struct HFSPlusAttrInlineData {
+	u_int32_t	recordType;
+	u_int32_t	reserved;
+	u_int32_t	logicalSize;
+	u_int8_t	userData[2];
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData;
+
+
+/*	A generic Attribute Record*/
+union HFSPlusAttrRecord {
+	u_int32_t		recordType;
+	HFSPlusAttrInlineData	inlineData;   /* NOT USED */
+	HFSPlusAttrData	attrData;
+	HFSPlusAttrForkData	forkData;
+	HFSPlusAttrExtents	overflowExtents;
+};
+typedef union HFSPlusAttrRecord HFSPlusAttrRecord;
+
+/* Attribute key */
+enum { kHFSMaxAttrNameLen = 127 };
+struct HFSPlusAttrKey {
+	u_int16_t     keyLength;       /* key length (in bytes) */
+	u_int16_t     pad;	       /* set to zero */
+	u_int32_t     fileID;          /* file associated with attribute */
+	u_int32_t     startBlock;      /* first allocation block number for extents */
+	u_int16_t     attrNameLen;     /* number of unicode characters */
+	u_int16_t     attrName[kHFSMaxAttrNameLen];   /* attribute name (Unicode) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrKey HFSPlusAttrKey;
+
+#define kHFSPlusAttrKeyMaximumLength   (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t))
+#define kHFSPlusAttrKeyMinimumLength   (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t))
+
+#endif /* __APPLE_API_UNSTABLE */
+
+
+/* Key and node lengths */
+enum {
+	kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t),
+	kHFSExtentKeyMaximumLength	= sizeof(HFSExtentKey) - sizeof(u_int8_t),
+	kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t),
+	kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t),
+	kHFSCatalogKeyMaximumLength	= sizeof(HFSCatalogKey) - sizeof(u_int8_t),
+	kHFSCatalogKeyMinimumLength	= kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t),
+	kHFSPlusCatalogMinNodeSize	= 4096,
+	kHFSPlusExtentMinNodeSize	= 512,
+	kHFSPlusAttrMinNodeSize		= 4096
+};
+
+/* HFS and HFS Plus volume attribute bits */
+enum {
+							/* Bits 0-6 are reserved (always cleared by MountVol call) */
+	kHFSVolumeHardwareLockBit	= 7,		/* volume is locked by hardware */
+	kHFSVolumeUnmountedBit		= 8,		/* volume was successfully unmounted */
+	kHFSVolumeSparedBlocksBit	= 9,		/* volume has bad blocks spared */
+	kHFSVolumeNoCacheRequiredBit = 10,		/* don't cache volume blocks (i.e. RAM or ROM disk) */
+	kHFSBootVolumeInconsistentBit = 11,		/* boot volume is inconsistent (System 7.6 and later) */
+	kHFSCatalogNodeIDsReusedBit = 12,
+	kHFSVolumeJournaledBit = 13,			/* this volume has a journal on it */
+	kHFSVolumeInconsistentBit = 14,			/* serious inconsistencies detected at runtime */
+	kHFSVolumeSoftwareLockBit	= 15,		/* volume is locked by software */
+
+	kHFSVolumeHardwareLockMask	= 1 << kHFSVolumeHardwareLockBit,
+	kHFSVolumeUnmountedMask		= 1 << kHFSVolumeUnmountedBit,
+	kHFSVolumeSparedBlocksMask	= 1 << kHFSVolumeSparedBlocksBit,
+	kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit,
+	kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit,
+	kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit,
+	kHFSVolumeJournaledMask	= 1 << kHFSVolumeJournaledBit,
+	kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit,
+	kHFSVolumeSoftwareLockMask	= 1 << kHFSVolumeSoftwareLockBit,
+	kHFSMDBAttributesMask		= 0x8380
+};
+
+
+/* HFS Master Directory Block - 162 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSMasterDirectoryBlock {
+	u_int16_t		drSigWord;	/* == kHFSSigWord */
+	u_int32_t		drCrDate;	/* date and time of volume creation */
+	u_int32_t		drLsMod;	/* date and time of last modification */
+	u_int16_t		drAtrb;		/* volume attributes */
+	u_int16_t		drNmFls;	/* number of files in root folder */
+	u_int16_t		drVBMSt;	/* first block of volume bitmap */
+	u_int16_t		drAllocPtr;	/* start of next allocation search */
+	u_int16_t		drNmAlBlks;	/* number of allocation blocks in volume */
+	u_int32_t		drAlBlkSiz;	/* size (in bytes) of allocation blocks */
+	u_int32_t		drClpSiz;	/* default clump size */
+	u_int16_t		drAlBlSt;	/* first allocation block in volume */
+	u_int32_t		drNxtCNID;	/* next unused catalog node ID */
+	u_int16_t		drFreeBks;	/* number of unused allocation blocks */
+	u_int8_t		drVN[kHFSMaxVolumeNameChars + 1];  /* volume name */
+	u_int32_t		drVolBkUp;	/* date and time of last backup */
+	u_int16_t		drVSeqNum;	/* volume backup sequence number */
+	u_int32_t		drWrCnt;	/* volume write count */
+	u_int32_t		drXTClpSiz;	/* clump size for extents overflow file */
+	u_int32_t		drCTClpSiz;	/* clump size for catalog file */
+	u_int16_t		drNmRtDirs;	/* number of directories in root folder */
+	u_int32_t		drFilCnt;	/* number of files in volume */
+	u_int32_t		drDirCnt;	/* number of directories in volume */
+	u_int32_t		drFndrInfo[8];	/* information used by the Finder */
+	u_int16_t		drEmbedSigWord;	/* embedded volume signature (formerly drVCSize) */
+	HFSExtentDescriptor	drEmbedExtent;	/* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */
+	u_int32_t		drXTFlSize;	/* size of extents overflow file */
+	HFSExtentRecord		drXTExtRec;	/* extent record for extents overflow file */
+	u_int32_t		drCTFlSize;	/* size of catalog file */
+	HFSExtentRecord	drCTExtRec;	/* extent record for catalog file */
+} HFS_ALIGNMENT;
+typedef struct HFSMasterDirectoryBlock	HFSMasterDirectoryBlock;
+
+
+#ifdef __APPLE_API_UNSTABLE
+#define SET_HFS_TEXT_ENCODING(hint)  \
+	(0x656e6300 | ((hint) & 0xff))
+#define GET_HFS_TEXT_ENCODING(hint)  \
+	(((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU)
+#endif /* __APPLE_API_UNSTABLE */
+
+
+/* HFS Plus Volume Header - 512 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSPlusVolumeHeader {
+	u_int16_t	signature;		/* == kHFSPlusSigWord */
+	u_int16_t	version;		/* == kHFSPlusVersion */
+	u_int32_t	attributes;		/* volume attributes */
+	u_int32_t	lastMountedVersion;	/* implementation version which last mounted volume */
+	u_int32_t	journalInfoBlock;	/* block addr of journal info (if volume is journaled, zero otherwise) */
+
+	u_int32_t	createDate;		/* date and time of volume creation */
+	u_int32_t	modifyDate;		/* date and time of last modification */
+	u_int32_t	backupDate;		/* date and time of last backup */
+	u_int32_t	checkedDate;		/* date and time of last disk check */
+
+	u_int32_t	fileCount;		/* number of files in volume */
+	u_int32_t	folderCount;		/* number of directories in volume */
+
+	u_int32_t	blockSize;		/* size (in bytes) of allocation blocks */
+	u_int32_t	totalBlocks;		/* number of allocation blocks in volume (includes this header and VBM*/
+	u_int32_t	freeBlocks;		/* number of unused allocation blocks */
+
+	u_int32_t	nextAllocation;		/* start of next allocation search */
+	u_int32_t	rsrcClumpSize;		/* default resource fork clump size */
+	u_int32_t	dataClumpSize;		/* default data fork clump size */
+	u_int32_t	nextCatalogID;		/* next unused catalog node ID */
+
+	u_int32_t	writeCount;		/* volume write count */
+	u_int64_t	encodingsBitmap;	/* which encodings have been use  on this volume */
+
+	u_int8_t	finderInfo[32];		/* information used by the Finder */
+
+	HFSPlusForkData	 allocationFile;	/* allocation bitmap file */
+	HFSPlusForkData  extentsFile;		/* extents B-tree file */
+	HFSPlusForkData  catalogFile;		/* catalog B-tree file */
+	HFSPlusForkData  attributesFile;	/* extended attributes B-tree file */
+	HFSPlusForkData	 startupFile;		/* boot file (secondary loader) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader;
+
+
+/* B-tree structures */
+
+enum BTreeKeyLimits{
+	kMaxKeyLength	= 520
+};
+
+union BTreeKey{
+	u_int8_t	length8;
+	u_int16_t	length16;
+	u_int8_t	rawData [kMaxKeyLength+2];
+};
+typedef union BTreeKey BTreeKey;
+
+/* BTNodeDescriptor -- Every B-tree node starts with these fields. */
+struct BTNodeDescriptor {
+	u_int32_t	fLink;			/* next node at this level*/
+	u_int32_t	bLink;			/* previous node at this level*/
+	int8_t		kind;			/* kind of node (leaf, index, header, map)*/
+	u_int8_t	height;			/* zero for header, map; child is one more than parent*/
+	u_int16_t	numRecords;		/* number of records in this node*/
+	u_int16_t	reserved;		/* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct BTNodeDescriptor BTNodeDescriptor;
+
+/* Constants for BTNodeDescriptor kind */
+enum {
+	kBTLeafNode	= -1,
+	kBTIndexNode	= 0,
+	kBTHeaderNode	= 1,
+	kBTMapNode	= 2
+};
+
+/* BTHeaderRec -- The first record of a B-tree header node */
+struct BTHeaderRec {
+	u_int16_t	treeDepth;		/* maximum height (usually leaf nodes) */
+	u_int32_t	rootNode;		/* node number of root node */
+	u_int32_t	leafRecords;		/* number of leaf records in all leaf nodes */
+	u_int32_t	firstLeafNode;		/* node number of first leaf node */
+	u_int32_t	lastLeafNode;		/* node number of last leaf node */
+	u_int16_t	nodeSize;		/* size of a node, in bytes */
+	u_int16_t	maxKeyLength;		/* reserved */
+	u_int32_t	totalNodes;		/* total number of nodes in tree */
+	u_int32_t	freeNodes;		/* number of unused (free) nodes in tree */
+	u_int16_t	reserved1;		/* unused */
+	u_int32_t	clumpSize;		/* reserved */
+	u_int8_t	btreeType;		/* reserved */
+	u_int8_t	keyCompareType;		/* Key string Comparison Type */
+	u_int32_t	attributes;		/* persistent attributes about the tree */
+	u_int32_t	reserved3[16];		/* reserved */
+} HFS_ALIGNMENT;
+typedef struct BTHeaderRec BTHeaderRec;
+
+/* Constants for BTHeaderRec attributes */
+enum {
+	kBTBadCloseMask		 = 0x00000001,	/* reserved */
+	kBTBigKeysMask		 = 0x00000002,	/* key length field is 16 bits */
+	kBTVariableIndexKeysMask = 0x00000004	/* keys in index nodes are variable length */
+};
+
+
+/* Catalog Key Name Comparison Type */
+enum {
+	kHFSCaseFolding   = 0xCF,  /* case folding (case-insensitive) */
+	kHFSBinaryCompare = 0xBC  /* binary compare (case-sensitive) */
+};
+
+/* JournalInfoBlock - Structure that describes where our journal lives */
+struct JournalInfoBlock {
+	u_int32_t	flags;
+	u_int32_t       device_signature[8];  // signature used to locate our device.
+	u_int64_t       offset;               // byte offset to the journal on the device
+	u_int64_t       size;                 // size in bytes of the journal
+	u_int32_t	reserved[32];
+} HFS_ALIGNMENT;
+typedef struct JournalInfoBlock JournalInfoBlock;
+
+enum {
+    kJIJournalInFSMask          = 0x00000001,
+    kJIJournalOnOtherDeviceMask = 0x00000002,
+    kJIJournalNeedInitMask      = 0x00000004
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+#ifdef _MSC_VER
+# pragma pack(pop)
+#endif
+
+#endif /* __HFS_FORMAT__ */
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/edk2.patch-idtgdt
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/edk2.patch-idtgdt	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/edk2.patch-idtgdt	(revision 29125)
@@ -0,0 +1,283 @@
+Index: UefiCpuPkg/CpuDxe/CpuDxe.inf
+===================================================================
+--- UefiCpuPkg/CpuDxe/CpuDxe.inf	(revision 9332)
++++ UefiCpuPkg/CpuDxe/CpuDxe.inf	(working copy)
+@@ -62,6 +62,9 @@
+ [Protocols]
+   gEfiCpuArchProtocolGuid
+ 
++[Guids]
++  gEfiEventVirtualAddressChangeGuid             # ALWAYS_CONSUMED  Create Event: EVENT_GROUP_GUID
++
+ [Depex]
+   TRUE
+ 
+Index: UefiCpuPkg/CpuDxe/CpuGdt.c
+===================================================================
+--- UefiCpuPkg/CpuDxe/CpuGdt.c	(revision 9332)
++++ UefiCpuPkg/CpuDxe/CpuGdt.c	(working copy)
+@@ -67,6 +67,9 @@
+ #error CPU type not supported for CPU GDT initialization!
+ #endif
+ 
++VOID           * Gdt;
++UINT32           GdtSize;
++
+ //
+ // Global descriptor table (GDT) Template
+ //
+@@ -161,6 +164,20 @@
+   },
+ };
+ 
++VOID EFIAPI
++LoadGdt(VOID* Gdt, UINT32 GdtSize)
++{
++  IA32_DESCRIPTOR gdtPtr;
++
++  //
++  // Write GDT register
++  //
++  gdtPtr.Base = (UINT32)(UINTN)Gdt;
++  gdtPtr.Limit = GdtSize - 1;
++
++  AsmWriteGdtr (&gdtPtr);
++}
++
+ /**
+   Initialize Global Descriptor Table
+ 
+@@ -169,27 +186,27 @@
+ InitGlobalDescriptorTable (
+   )
+ {
+-  GDT_ENTRIES *gdt;
+-  IA32_DESCRIPTOR gdtPtr;
+-
+   //
+   // Allocate Runtime Data for the GDT
+   //
+-  gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8);
+-  ASSERT (gdt != NULL);
+-  gdt = ALIGN_POINTER (gdt, 8);
++  GdtSize = sizeof (GdtTemplate);
++#if 0
++  Gdt = AllocateRuntimePool (GdtSize + 8);
++  ASSERT (Gdt != NULL);
++  Gdt = ALIGN_POINTER (Gdt, 8);
++#else
++  Gdt = (VOID*)(UINTN)HandyCpuPage;
++#endif
+ 
+   //
+   // Initialize all GDT entries
+   //
+-  CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate));
++  CopyMem (Gdt, &GdtTemplate, GdtSize);
+ 
+   //
+   // Write GDT register
+   //
+-  gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt;
+-  gdtPtr.Limit = sizeof (GdtTemplate) - 1;
+-  AsmWriteGdtr (&gdtPtr);
++  LoadGdt(Gdt, GdtSize);
+ 
+   //
+   // Update selector (segment) registers base on new GDT
+@@ -197,4 +214,3 @@
+   SetCodeSelector ((UINT16)CPU_CODE_SEL);
+   SetDataSelectors ((UINT16)CPU_DATA_SEL);
+ }
+-
+Index: UefiCpuPkg/CpuDxe/CpuDxe.c
+===================================================================
+--- UefiCpuPkg/CpuDxe/CpuDxe.c	(revision 9332)
++++ UefiCpuPkg/CpuDxe/CpuDxe.c	(working copy)
+@@ -14,11 +14,14 @@
+ 
+ #include "CpuDxe.h"
+ 
++EFI_EVENT                 mEfiVirtualNotifyEvent;
++EFI_PHYSICAL_ADDRESS      HandyCpuPage;
++IA32_IDT_GATE_DESCRIPTOR* Idt;
++UINT32                    IdtSize;
++
+ //
+ // Global Variables
+ //
+-IA32_IDT_GATE_DESCRIPTOR  gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 };
+-
+ EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100];
+ BOOLEAN                   InterruptState = FALSE;
+ EFI_HANDLE                mCpuHandle = NULL;
+@@ -1004,8 +1007,6 @@
+   )
+ {
+   EFI_STATUS      Status;
+-  VOID            *IdtPtrAlignmentBuffer;
+-  IA32_DESCRIPTOR *IdtPtr;
+   UINTN           Index;
+   UINTN           CurrentHandler;
+ 
+@@ -1015,27 +1016,33 @@
+   // Intialize IDT
+   //
+   CurrentHandler = (UINTN)AsmIdtVector00;
++
++  //
++  // Allocate Runtime Data for the IDT
++  //
++  IdtSize = INTERRUPT_VECTOR_NUMBER*sizeof(IA32_IDT_GATE_DESCRIPTOR);
++#if 0
++  Idt = AllocateRuntimePool (IdtSize + 16);
++  ASSERT (Idt != NULL);
++  Idt = ALIGN_POINTER (Idt, 16);
++#else
++  Idt = (VOID*)(UINTN)HandyCpuPage + 0x500;
++#endif
++
+   for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++, CurrentHandler += 0x08) {
+-    gIdtTable[Index].Bits.OffsetLow   = (UINT16)CurrentHandler;
+-    gIdtTable[Index].Bits.Selector    = AsmReadCs();
+-    gIdtTable[Index].Bits.Reserved_0  = 0;
+-    gIdtTable[Index].Bits.GateType    = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+-    gIdtTable[Index].Bits.OffsetHigh  = (UINT16)(CurrentHandler >> 16);
++    Idt[Index].Bits.OffsetLow   = (UINT16)CurrentHandler;
++    Idt[Index].Bits.Selector    = AsmReadCs();
++    Idt[Index].Bits.Reserved_0  = 0;
++    Idt[Index].Bits.GateType    = IA32_IDT_GATE_TYPE_INTERRUPT_32;
++    Idt[Index].Bits.OffsetHigh  = (UINT16)(CurrentHandler >> 16);
+ #if defined (MDE_CPU_X64)
+-    gIdtTable[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32);
+-    gIdtTable[Index].Bits.Reserved_1  = 0;
++    Idt[Index].Bits.OffsetUpper = (UINT32)(CurrentHandler >> 32);
++    Idt[Index].Bits.Reserved_1  = 0;
+ #endif
+   }
+ 
+-  //
+-  // Load IDT Pointer
+-  //
+-  IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16);
+-  IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16);
+-  IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1));
+-  IdtPtr->Limit = sizeof (gIdtTable) - 1;
+-  AsmWriteIdtr (IdtPtr);
+-  FreePool (IdtPtrAlignmentBuffer);
++  // Load IDT
++  LoadIdt(Idt, IdtSize);
+ 
+   //
+   // Initialize Exception Handlers
+@@ -1052,7 +1059,50 @@
+ 
+ }
+ 
++VOID EFIAPI
++LoadIdt(VOID* Idt, UINT32 IdtSize)
++{
++    IA32_DESCRIPTOR IdtPtr;
+ 
++    IdtPtr.Base = (UINT32)(((UINTN) Idt) & (BASE_4GB-1));
++    IdtPtr.Limit = IdtSize - 1;
++    AsmWriteIdtr (&IdtPtr);
++}
++
++UINT32
++EFIAPI
++IoWrite32 (
++  IN      UINTN                     Port,
++  IN      UINT32                    Value
++  )
++{
++  __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
++  return Value;
++}
++
++VOID
++EFIAPI
++CpuLibVirtualNotifyEvent (
++  IN EFI_EVENT        Event,
++  IN VOID             *Context
++  )
++{
++    EFI_RUNTIME_SERVICES * rs = (EFI_RUNTIME_SERVICES *)Context;
++
++    rs->ConvertPointer (0, (VOID **) &Gdt);
++    rs->ConvertPointer (0, (VOID **) &Idt);
++
++    DisableInterrupts();
++
++    LoadIdt(Idt, IdtSize);
++    LoadGdt(Gdt, GdtSize);
++
++    //IoWrite32(0xef11, 1);
++}
++
++extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
++
++
+ /**
+   Initialize the state information for the CPU Architectural Protocol.
+ 
+@@ -1073,6 +1123,17 @@
+ {
+   EFI_STATUS  Status;
+ 
++
++  // Allocate handy page
++  HandyCpuPage = 0xffffffff;
++  Status = gBS->AllocatePages (
++      AllocateMaxAddress,
++      EfiReservedMemoryType,
++      1,
++      &HandyCpuPage                               );
++  ASSERT_EFI_ERROR (Status);
++  ASSERT (HandyCpuPage != 0xffffffff);
++
+   //
+   // Make sure interrupts are disabled
+   //
+@@ -1103,6 +1164,18 @@
+   //
+   RefreshGcdMemoryAttributes ();
+ 
++
++  // Register virtual address change notifier
++#if 0
++  gBS->CreateEventEx (
++      EVT_NOTIFY_SIGNAL,
++      TPL_NOTIFY,
++      CpuLibVirtualNotifyEvent,
++      SystemTable->RuntimeServices,
++      &gEfiEventVirtualAddressChangeGuid,
++      &mEfiVirtualNotifyEvent
++  );
++#endif
++
+   return Status;
+ }
+-
+Index: UefiCpuPkg/CpuDxe/CpuDxe.h
+===================================================================
+--- UefiCpuPkg/CpuDxe/CpuDxe.h	(revision 9332)
++++ UefiCpuPkg/CpuDxe/CpuDxe.h	(working copy)
+@@ -136,5 +136,17 @@
+   );
+ 
+ 
++VOID EFIAPI
++LoadGdt(VOID* Gdt, UINT32 GdtSize);
++
++VOID EFIAPI
++LoadIdt(VOID* Idt, UINT32 IdtSize);
++
++extern EFI_PHYSICAL_ADDRESS      HandyCpuPage;
++extern VOID*                     Gdt;
++extern UINT32                    GdtSize;
++extern IA32_IDT_GATE_DESCRIPTOR* Idt;
++extern UINT32                    IdtSize;
++
+ #endif
+ 
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/edk2.patch-mem_acpi
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/edk2.patch-mem_acpi	(revision 29125)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/edk2.patch-mem_acpi	(revision 29125)
@@ -0,0 +1,218 @@
+Index: MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c
+===================================================================
+--- MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c	(revision 9332)
++++ MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c	(working copy)
+@@ -10,7 +10,7 @@
+   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ 
+-**/ 
++**/
+ 
+ #include <PiDxe.h>
+ 
+@@ -153,7 +153,134 @@
+   Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
+ }
+ 
++#ifdef VBOX
+ 
++#define ACPI_RSD_PTR      SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ')
++#define EBDA_BASE         (0x9FC0 << 4)
++
++VOID *
++FindAcpiRsdPtr (
++  VOID
++  )
++{
++  UINTN                           Address;
++  UINTN                           Index;
++
++  //
++  // First Search 0x0e0000 - 0x0fffff for RSD Ptr
++  //
++  for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
++    if (*(UINT64 *)(Address) == ACPI_RSD_PTR) {
++      return (VOID *)Address;
++    }
++  }
++
++  //
++  // Search EBDA
++  //
++
++  Address = EBDA_BASE;
++  for (Index = 0; Index < 0x400 ; Index += 16) {
++    if (*(UINT64 *)(Address + Index) == ACPI_RSD_PTR) {
++      return (VOID *)Address;
++    }
++  }
++  return NULL;
++}
++
++VOID* FindSignature(VOID* Start, UINT32 Signature, BOOLEAN NoChecksum)
++{
++    UINT8* Ptr = (UINT8*)Start;
++    UINT32 Count = 0x10000; // 16 pages
++
++    while (Count-- > 0)
++    {
++        if (   *(UINT32*)Ptr == Signature
++            && ((EFI_ACPI_DESCRIPTION_HEADER *)Ptr)->Length <= Count
++            && (NoChecksum ||
++                CalculateCheckSum8(Ptr, ((EFI_ACPI_DESCRIPTION_HEADER *)Ptr)->Length) == 0
++                ))
++        {
++                return Ptr;
++        }
++
++        Ptr++;
++    }
++    return NULL;
++}
++
++VOID
++FillSysTablesInfo(VOID** Tables, UINT32 TablesSize)
++{
++    UINT32 Table = 0;
++    EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*  RsdPtr;
++    VOID* TablesPage;
++#define FLAG_OPTIONAL    1<<0
++#define FLAG_NO_CHECKSUM 1<<1
++    static struct {
++        UINT32 Signature;
++        UINT32 Flags;
++        CHAR8* Name;
++    } TableInfo[] = {
++        // MADT, optional
++        { SIGNATURE_32('A', 'P', 'I', 'C'),  FLAG_OPTIONAL, "MADT"},
++        // FACP (also called FADT)
++        { SIGNATURE_32('F', 'A', 'C', 'P'),  0, "FADT"},
++        // FACS, according 5.2.9 of ACPI v2. spec FACS doesn't have checksum field
++        { SIGNATURE_32('F', 'A', 'C', 'S'),  FLAG_NO_CHECKSUM, "FACS"},
++        // DSDT
++        { SIGNATURE_32('D', 'S', 'D', 'T'), 0, "DSDT"},
++        // SSDT
++        { SIGNATURE_32('S', 'S', 'D', 'T'), 0, "SSDT"},
++        // HPET
++        { SIGNATURE_32('H', 'P', 'E', 'T'), FLAG_OPTIONAL, "HPET"}
++    };
++    UINT32 Index;
++
++    RsdPtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)FindAcpiRsdPtr();
++    ASSERT(RsdPtr != NULL);
++    TablesPage = (VOID*)(UINTN)((RsdPtr->RsdtAddress) & ~0xfff);
++
++    for (Index = 0; Index < sizeof TableInfo / sizeof TableInfo[0]; Index++)
++    {
++        VOID* Ptr = FindSignature(TablesPage, TableInfo[Index].Signature,
++                                  (BOOLEAN)((TableInfo[Index].Flags & FLAG_NO_CHECKSUM) != 0));
++        if (TableInfo[Index].Signature == SIGNATURE_32('F', 'A', 'C', 'P'))
++        {
++             // we actually have 2 FADTs, see https://xtracker.innotek.de/index.php?bug=4082
++            Ptr = FindSignature((UINT8*)Ptr+32, SIGNATURE_32('F', 'A', 'C', 'P'), FALSE);
++        }
++        if (!(TableInfo[Index].Flags & FLAG_OPTIONAL))
++             ASSERT(Ptr != NULL);
++        DEBUG ((EFI_D_ERROR, "%a: %p\n", TableInfo[Index].Name, Ptr));
++        Tables[Table++] = Ptr;
++    }
++
++#if 0
++    // RSDT
++    ASSERT(Table < TablesSize);
++    Tables[Table] = FindSignature(TablesPage, SIGNATURE_32('R', 'S', 'D', 'T'));
++    DEBUG ((EFI_D_ERROR, "RSDT: %p\n", Tables[Table]));
++    ASSERT(Tables[Table] != NULL);
++    Table++;
++
++    // XSDT
++    ASSERT(Table < TablesSize);
++    Tables[Table] = FindSignature(TablesPage, SIGNATURE_32('X', 'S', 'D', 'T'));
++    DEBUG ((EFI_D_ERROR, "XSDT: %p\n", Tables[Table]));
++    ASSERT(Tables[Table] != NULL);
++    Table++;
++#endif
++
++    DEBUG((DEBUG_INFO, "We found %d tables from %d\n", Table, TablesSize));
++    Tables[Table] = NULL;
++}
++#endif
++
++#ifdef VBOX
++#define USE_MEM_TABLES 1
++#endif
++
+ /**
+   Entrypoint of Acpi Platform driver.
+ 
+@@ -174,14 +301,21 @@
+ {
+   EFI_STATUS                     Status;
+   EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
++#if USE_MEM_TABLES
++  VOID                           *VBoxTables[10];
++#else
+   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FwVol;
++#endif
+   INTN                           Instance;
+   EFI_ACPI_COMMON_HEADER         *CurrentTable;
+   UINTN                          TableHandle;
++#if !USE_MEM_TABLES
+   UINT32                         FvStatus;
++#endif
+   UINTN                          TableSize;
+   UINTN                          Size;
+ 
++  Size         = 0;
+   Instance     = 0;
+   CurrentTable = NULL;
+   TableHandle  = 0;
+@@ -194,6 +327,18 @@
+     return EFI_ABORTED;
+   }
+ 
++#if USE_MEM_TABLES
++  /* VBOX already has tables prepared in memory - just reuse it */
++  FillSysTablesInfo(VBoxTables, sizeof(VBoxTables)/sizeof(VBoxTables[0]));
++  while (Status == EFI_SUCCESS) {
++      CurrentTable = (EFI_ACPI_COMMON_HEADER*)VBoxTables[Instance];
++      Status = (CurrentTable == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
++      if (CurrentTable)
++      {
++          Size = CurrentTable->Length;
++          DEBUG ((EFI_D_ERROR, "adding %p %d\n", CurrentTable, Size));
++      }
++#else
+   //
+   // Locate the firmware volume protocol
+   //
+@@ -205,7 +350,6 @@
+   // Read tables from the storage file.
+   //
+   while (Status == EFI_SUCCESS) {
+-
+     Status = FwVol->ReadSection (
+                       FwVol,
+                       (EFI_GUID*)FixedPcdGetPtr (PcdAcpiTableStorageFile),
+@@ -215,6 +359,7 @@
+                       &Size,
+                       &FvStatus
+                       );
++#endif
+     if (!EFI_ERROR(Status)) {
+       //
+       // Add the table
+@@ -222,6 +367,7 @@
+       TableHandle = 0;
+ 
+       TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
++      DEBUG((DEBUG_INFO, "Size:%d, TableSize:%d\n", Size, TableSize));
+       ASSERT (Size >= TableSize);
+ 
+       //
+@@ -252,4 +398,3 @@
+ 
+   return EFI_SUCCESS;
+ }
+-
