phosphor-software-manager: multihost support

-Background: redfish uri FirmwreInventory/bios_active depends on
phosphor-software-manager, and currently it will only show one bios
version in multi-host system due to lack of multihost support.

- Solution: Add compile flag -DMULTIHOST. When specified, it will create
  bios_active_1 and bios_active_2 dbus object.

Tested:
```
root ~#: busctl tree xyz.openbmc_project.Software.BMC.Updater
└─ /xyz
  └─ /xyz/openbmc_project
    └─ /xyz/openbmc_project/software
      ├─ /xyz/openbmc_project/software/bios_active_1
      ├─ /xyz/openbmc_project/software/bios_active_2
      └─ /xyz/openbmc_project/software/fd5a0214
```

Fusion-Link:
platform5:  https://fusion2.corp.google.com/0008dabc-2835-3ea8-8fb3-2f481746726d
platform11: https://fusion2.corp.google.com/fe5f5cc0-fe73-3b32-972c-849bd4b302fa
platform17: https://fusion2.corp.google.com/e6a9339d-d2a4-3372-bc3e-82f5cd249fe8
Google-Bug-Id: 405060721
Change-Id: I1ca41064644b967a8e64d10c4d5d138c5868136d
Signed-off-by: Jimmy Chang <cmchang@google.com>
diff --git a/recipes-phosphor/flash/phosphor-software-manager/0001-Show-two-bios_active-object-in-multihost-system.patch b/recipes-phosphor/flash/phosphor-software-manager/0001-Show-two-bios_active-object-in-multihost-system.patch
new file mode 100644
index 0000000..cc7f8de
--- /dev/null
+++ b/recipes-phosphor/flash/phosphor-software-manager/0001-Show-two-bios_active-object-in-multihost-system.patch
@@ -0,0 +1,159 @@
+From 31eb98d569c6cc21b66922d94e7af66a46bb8753 Mon Sep 17 00:00:00 2001
+From: Jimmy Chang <cmchang@google.com>
+Date: Fri, 7 Nov 2025 08:27:15 +0000
+Subject: [PATCH] Show two bios_active object in multihost system
+
+Add compile flag -DMULTIHOST. When enabled, the phosphor-image-updater
+will generate bios_active_1 and bios_active_2 dbus object. This will
+allow bmcweb to show bios version for multihost system.
+
+Signed-off-by: Jimmy Chang <cmchang@google.com>
+---
+ activation.cpp   |  2 +-
+ item_updater.cpp | 63 ++++++++++++++++++++++++++++--------------------
+ item_updater.hpp |  8 +++---
+ meson.build      |  1 +
+ meson.options    |  5 ++++
+ 5 files changed, 48 insertions(+), 31 deletions(-)
+
+diff --git a/activation.cpp b/activation.cpp
+index 8f4c4c0..04011fd 100644
+--- a/activation.cpp
++++ b/activation.cpp
+@@ -434,7 +434,7 @@ void Activation::onStateChangesBios(sdbusplus::message_t& msg)
+             activation(softwareServer::Activation::Activations::Active);
+ 
+             info("Bios upgrade completed successfully.");
+-            parent.biosVersion->version(
++            parent.biosVersions.at(versionId)->version(
+                 parent.versions.find(versionId)->second->version());
+ 
+             // Delete the uploaded activation
+diff --git a/item_updater.cpp b/item_updater.cpp
+index 9cb9467..ad975d3 100644
+--- a/item_updater.cpp
++++ b/item_updater.cpp
+@@ -848,34 +848,45 @@ bool ItemUpdater::checkImage(const std::string& filePath,
+ #ifdef HOST_BIOS_UPGRADE
+ void ItemUpdater::createBIOSObject()
+ {
+-    std::string path = BIOS_OBJPATH;
+-    // Get version id from last item in the path
+-    auto pos = path.rfind("/");
+-    if (pos == std::string::npos)
++#ifdef MULTIHOST
++    const std::vector<std::string> bios_object_paths = {
++        std::string(BIOS_OBJPATH) + "_1", std::string(BIOS_OBJPATH) + "_2"};
++#else
++    const std::vector<std::string> bios_object_paths = {
++        std::string(BIOS_OBJPATH)};
++#endif
++    for (const auto& path : bios_object_paths)
+     {
+-        error("No version id found in object path {PATH}", "PATH", path);
+-        return;
+-    }
+-
+-    createActiveAssociation(path);
+-    createFunctionalAssociation(path);
++        // Get version id from last item in the path
++        auto pos = path.rfind("/");
++        if (pos == std::string::npos)
++        {
++            error("No version id found in object path {PATH}", "PATH", path);
++            return;
++        }
+ 
+-    auto versionId = path.substr(pos + 1);
+-    auto version = "null";
+-    AssociationList assocs = {};
+-    biosActivation = std::make_unique<Activation>(
+-        bus, path, *this, versionId, server::Activation::Activations::Active,
+-        assocs);
+-    auto dummyErase = [](std::string /*entryId*/) {
+-        // Do nothing;
+-    };
+-    biosVersion = std::make_unique<VersionClass>(
+-        bus, path, version, VersionPurpose::Host, "", "",
+-        std::vector<std::string>(),
+-        std::bind(dummyErase, std::placeholders::_1), "");
+-    biosVersion->deleteObject =
+-        std::make_unique<phosphor::software::manager::Delete>(bus, path,
+-                                                              *biosVersion);
++        createActiveAssociation(path);
++        createFunctionalAssociation(path);
++
++        auto versionId = path.substr(pos + 1);
++        auto version = "null";
++        AssociationList assocs = {};
++        biosActivations.emplace(
++            versionId, std::make_unique<Activation>(
++                           bus, path, *this, versionId,
++                           server::Activation::Activations::Active, assocs));
++        auto dummyErase = [](std::string /*entryId*/) {
++            // Do nothing;
++        };
++        auto biosVersionPtr = std::make_unique<VersionClass>(
++            bus, path, version, VersionPurpose::Host, "", "",
++            std::vector<std::string>(),
++            std::bind(dummyErase, std::placeholders::_1), "");
++        biosVersionPtr->deleteObject =
++            std::make_unique<phosphor::software::manager::Delete>(
++                bus, path, *biosVersionPtr);
++        biosVersions.emplace(versionId, std::move(biosVersionPtr));
++    }
+ }
+ #endif
+ 
+diff --git a/item_updater.hpp b/item_updater.hpp
+index 316113a..aea157f 100644
+--- a/item_updater.hpp
++++ b/item_updater.hpp
+@@ -272,12 +272,12 @@ class ItemUpdater : public ItemUpdaterInherit
+      */
+     void createBIOSObject();
+ 
+-    /** @brief Persistent Activation D-Bus object for BIOS */
+-    std::unique_ptr<Activation> biosActivation;
++    /** @brief Manages the Activation D-Bus objects for the BIOS */
++    std::map<std::string, std::unique_ptr<Activation>> biosActivations;
+ 
+   public:
+-    /** @brief Persistent Version D-Bus object for BIOS */
+-    std::unique_ptr<VersionClass> biosVersion;
++    /** @brief Manages the Version D-Bus objects for the BIOS */
++    std::map<std::string, std::unique_ptr<VersionClass>> biosVersions;
+ #endif
+ 
+     /** @brief Get the slot number of running image */
+diff --git a/meson.build b/meson.build
+index 4cf01fe..f94962f 100644
+--- a/meson.build
++++ b/meson.build
+@@ -68,6 +68,7 @@ conf.set('MMC_LAYOUT', get_option('bmc-layout').contains('mmc'))
+ # Configurable features
+ conf.set('HOST_BIOS_UPGRADE', get_option('host-bios-upgrade').allowed())
+ conf.set('WANT_SIGNATURE_VERIFY', get_option('verify-signature').allowed())
++conf.set('MULTIHOST', get_option('multihost').allowed())
+ 
+ # Configurable variables
+ conf.set('ACTIVE_BMC_MAX_ALLOWED', get_option('active-bmc-max-allowed'))
+diff --git a/meson.options b/meson.options
+index b088a8d..cdf1f0c 100644
+--- a/meson.options
++++ b/meson.options
+@@ -30,6 +30,11 @@ option(
+     description: 'Automatic flash side switch on boot',
+ )
+ 
++option(
++    'multihost', type: 'feature', value: 'disabled',
++    description: 'Enable multihost system support.',
++)
++
+ # Variables
+ option(
+     'active-bmc-max-allowed', type: 'integer',
+-- 
+2.51.2.1041.gc1ab5b90ca-goog
+
diff --git a/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
index d6a370d..4bd3070 100644
--- a/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
+++ b/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
@@ -1,2 +1,9 @@
+FILESEXTRAPATHS:prepend:gbmc := "${THISDIR}/${PN}:"
+
 FILES:${PN}-updater += "${systemd_system_unitdir}/obmc-flash-host-bios@.service"
+
+SRC_URI:append:gbmc = " \
+        file://0001-Show-two-bios_active-object-in-multihost-system.patch \
+"
+
 EXTRA_OEMESON:append:gbmc = " -Dhost-bios-upgrade=enabled"