HiiUpdatePackageList (
  IN CONST EFI_HII_DATABASE_PROTOCOL    *This,
  IN EFI_HII_HANDLE                     Handle,
  IN CONST EFI_HII_PACKAGE_LIST_HEADER  *PackageList
  )
{
  EFI_STATUS                          Status;
  HII_DATABASE_PRIVATE_DATA           *Private;
  LIST_ENTRY                          *Link;
  HII_DATABASE_RECORD                 *Node;
  EFI_HII_PACKAGE_HEADER              *PackageHdrPtr;
  HII_DATABASE_PACKAGE_LIST_INSTANCE  *OldPackageList;
  EFI_HII_PACKAGE_HEADER              PackageHeader;

  if (This == NULL || PackageList == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (!IsHiiHandleValid (Handle)) {
    return EFI_NOT_FOUND;
  }

  Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);

  PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER));

  Status = EFI_SUCCESS;

  EfiAcquireLock (&mHiiDatabaseLock);
  //
  // Get original packagelist to be updated
  //
  for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
    Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
    if (Node->Handle == Handle) {
      OldPackageList = Node->PackageList;
      //
      // Remove the package if its type matches one of the package types which is
      // contained in the new package list.
      //
      CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
      while (PackageHeader.Type != EFI_HII_PACKAGE_END) {
        switch (PackageHeader.Type) {
        case EFI_HII_PACKAGE_TYPE_GUID:
          Status = RemoveGuidPackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_FORMS:
          Status = RemoveFormPackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
          Status = RemoveKeyboardLayoutPackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_STRINGS:
          Status = RemoveStringPackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_FONTS:
          Status = RemoveFontPackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_IMAGES:
          Status = RemoveImagePackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_SIMPLE_FONTS:
          Status = RemoveSimpleFontPackages (Private, Handle, OldPackageList);
          break;
        case EFI_HII_PACKAGE_DEVICE_PATH:
          Status = RemoveDevicePathPackage (Private, Handle, OldPackageList);
          break;
        }

        if (EFI_ERROR (Status)) {
          EfiReleaseLock (&mHiiDatabaseLock);
          return Status;
        }

        PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length);
        CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
      }

      //
      // Add all of the packages within the new package list
      //
      Status = AddPackages (Private, EFI_HII_DATABASE_NOTIFY_ADD_PACK, PackageList, Node);

      //
      // Check whether need to get the Database info.
      // Only after ReadyToBoot, need to do the export.
      //
      if (gExportAfterReadyToBoot && Status == EFI_SUCCESS) {
        HiiGetDatabaseInfo (This);
      }
      EfiReleaseLock (&mHiiDatabaseLock);

      //
      // Notes:
      // HiiGetDatabaseInfo () will get the contents of HII data base,
      // belong to the atomic behavior of Hii Database update.
      // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers
      // we can not think it belong to the atomic behavior of Hii Database update.
      // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo ().
      //

      //
      // Check whether need to get the configuration setting info from HII drivers.
      // When after ReadyToBoot and need to do the export for form package update.
      //
      if (gExportAfterReadyToBoot && gExportConfigResp && Status == EFI_SUCCESS) {
        HiiGetConfigRespInfo (This);
      }

      return Status;
    }
  }
  EfiReleaseLock (&mHiiDatabaseLock);
  return EFI_NOT_FOUND;
}