hypervisor: state management support

Some systems have a hypervisor firmware stack which they wish to track
and change the state of. This new state management object will provide
this function if a user selects to bring it into their system.

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I6082c6e06c6731d71f2e580e1ab87af38917bb3a
diff --git a/hypervisor_state_manager.cpp b/hypervisor_state_manager.cpp
new file mode 100644
index 0000000..acfbb83
--- /dev/null
+++ b/hypervisor_state_manager.cpp
@@ -0,0 +1,62 @@
+#include "config.h"
+
+#include "hypervisor_state_manager.hpp"
+
+#include <fmt/format.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/exception.hpp>
+#include <sdbusplus/server.hpp>
+
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <string>
+
+namespace phosphor
+{
+namespace state
+{
+namespace manager
+{
+
+// When you see server:: you know we're referencing our base class
+namespace server = sdbusplus::xyz::openbmc_project::State::server;
+using namespace phosphor::logging;
+using sdbusplus::exception::SdBusError;
+
+server::Host::Transition Hypervisor::requestedHostTransition(Transition value)
+{
+    log<level::INFO>(fmt::format("Hypervisor state transition request of {}",
+                                 convertForMessage(value))
+                         .c_str());
+
+    // Only support the transition to On
+    if (value != server::Host::Transition::On)
+    {
+        log<level::ERR>("Hypervisor state only supports a transition to On");
+        // TODO raise appropriate error exception
+        return server::Host::Transition::Off;
+    }
+
+    // This property is monitored by a separate application (for example PLDM)
+    // which is responsible for propagating the On request to the hypervisor
+
+    return server::Host::requestedHostTransition(value);
+}
+
+// TODO - Monitor BootProgress and update hypervisor state to Running if
+//        OS is started
+
+server::Host::HostState Hypervisor::currentHostState(HostState value)
+{
+    log<level::INFO>(
+        fmt::format("Change to Hypervisor State: {}", convertForMessage(value))
+            .c_str());
+    return server::Host::currentHostState(value);
+}
+
+} // namespace manager
+} // namespace state
+} // namespace phosphor
diff --git a/hypervisor_state_manager.hpp b/hypervisor_state_manager.hpp
new file mode 100644
index 0000000..b0ce297
--- /dev/null
+++ b/hypervisor_state_manager.hpp
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "config.h"
+
+#include "settings.hpp"
+#include "xyz/openbmc_project/State/Host/server.hpp"
+
+#include <sdbusplus/bus.hpp>
+
+namespace phosphor
+{
+namespace state
+{
+namespace manager
+{
+
+using HypervisorInherit = sdbusplus::server::object::object<
+    sdbusplus::xyz::openbmc_project::State::server::Host>;
+
+namespace server = sdbusplus::xyz::openbmc_project::State::server;
+
+/** @class Host
+ *  @brief OpenBMC host state management implementation.
+ *  @details A concrete implementation for xyz.openbmc_project.State.Host
+ *  DBus API.
+ */
+class Hypervisor : public HypervisorInherit
+{
+  public:
+    Hypervisor() = delete;
+    Hypervisor(const Hypervisor&) = delete;
+    Hypervisor& operator=(const Hypervisor&) = delete;
+    Hypervisor(Hypervisor&&) = delete;
+    Hypervisor& operator=(Hypervisor&&) = delete;
+    virtual ~Hypervisor() = default;
+
+    /** @brief Constructs Hypervisor State Manager
+     *
+     * @param[in] bus       - The Dbus bus object
+     * @param[in] objPath   - The Dbus object path
+     */
+    Hypervisor(sdbusplus::bus::bus& bus, const char* objPath) :
+        HypervisorInherit(bus, objPath, false), bus(bus)
+    {}
+
+    /** @brief Set value of HostTransition */
+    server::Host::Transition
+        requestedHostTransition(server::Host::Transition value) override;
+
+    /** @brief Set value of CurrentHostState */
+    server::Host::HostState
+        currentHostState(server::Host::HostState value) override;
+
+  private:
+    /** @brief Persistent sdbusplus DBus bus connection. */
+    sdbusplus::bus::bus& bus;
+};
+
+} // namespace manager
+} // namespace state
+} // namespace phosphor
diff --git a/hypervisor_state_manager_main.cpp b/hypervisor_state_manager_main.cpp
new file mode 100644
index 0000000..61154d6
--- /dev/null
+++ b/hypervisor_state_manager_main.cpp
@@ -0,0 +1,29 @@
+#include "config.h"
+
+#include "hypervisor_state_manager.hpp"
+
+#include <sdbusplus/bus.hpp>
+
+#include <cstdlib>
+
+int main()
+{
+    auto bus = sdbusplus::bus::new_default();
+
+    // For now, we only have one instance of the hypervisor
+    auto objPathInst = std::string{HYPERVISOR_OBJPATH} + '0';
+
+    // Add sdbusplus ObjectManager.
+    sdbusplus::server::manager::manager objManager(bus, objPathInst.c_str());
+
+    phosphor::state::manager::Hypervisor manager(bus, objPathInst.c_str());
+
+    bus.request_name(HYPERVISOR_BUSNAME);
+
+    while (true)
+    {
+        bus.process_discard();
+        bus.wait();
+    }
+    return 0;
+}
diff --git a/meson.build b/meson.build
index 610b4ba..170971a 100644
--- a/meson.build
+++ b/meson.build
@@ -16,6 +16,10 @@
 conf.set_quoted(
     'HOST_OBJPATH', get_option('host-objpath'))
 conf.set_quoted(
+    'HYPERVISOR_BUSNAME', get_option('hypervisor-busname'))
+conf.set_quoted(
+    'HYPERVISOR_OBJPATH', get_option('hypervisor-objpath'))
+conf.set_quoted(
     'CHASSIS_BUSNAME', get_option('chassis-busname'))
 conf.set_quoted(
     'CHASSIS_OBJPATH', get_option('chassis-objpath'))
@@ -65,6 +69,18 @@
     install: true
 )
 
+executable('phosphor-hypervisor-state-manager',
+            'hypervisor_state_manager.cpp',
+            'hypervisor_state_manager_main.cpp',
+            'settings.cpp',
+            dependencies: [
+            sdbusplus, sdeventplus, phosphorlogging,
+            phosphordbusinterfaces, cppfs
+            ],
+    implicit_include_directories: true,
+    install: true
+)
+
 executable('phosphor-chassis-state-manager',
             'chassis_state_manager.cpp',
             'chassis_state_manager_main.cpp',
diff --git a/meson_options.txt b/meson_options.txt
index 9412421..d340668 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -13,6 +13,18 @@
 )
 
 option(
+    'hypervisor-busname', type: 'string',
+    value: 'xyz.openbmc_project.State.Hypervisor',
+    description: 'The Hypervisor DBus busname to own.',
+)
+
+option(
+    'hypervisor-objpath', type: 'string',
+    value: '/xyz/openbmc_project/state/hypervisor',
+    description: 'The hypervisor state manager Dbus root.',
+)
+
+option(
     'chassis-busname', type: 'string',
     value: 'xyz.openbmc_project.State.Chassis',
     description: 'The Chassis DBus busname to own.',
diff --git a/service_files/meson.build b/service_files/meson.build
index a1f38f9..31b1974 100644
--- a/service_files/meson.build
+++ b/service_files/meson.build
@@ -9,6 +9,7 @@
     'xyz.openbmc_project.State.BMC.service',
     'xyz.openbmc_project.State.Chassis.service',
     'xyz.openbmc_project.State.Host.service',
+    'xyz.openbmc_project.State.Hypervisor.service',
     'xyz.openbmc_project.State.ScheduledHostTransition.service',
     'phosphor-clear-one-time@.service',
     'phosphor-set-host-transition-to-off@.service',
diff --git a/service_files/xyz.openbmc_project.State.Hypervisor.service b/service_files/xyz.openbmc_project.State.Hypervisor.service
new file mode 100644
index 0000000..e0879bf
--- /dev/null
+++ b/service_files/xyz.openbmc_project.State.Hypervisor.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Phosphor Hypervisor State Manager
+Before=mapper-wait@-xyz-openbmc_project-state-hypervisor.service
+Wants=obmc-mapper.target
+After=obmc-mapper.target
+
+[Service]
+ExecStart=/usr/bin/phosphor-hypervisor-state-manager
+Restart=always
+Type=dbus
+BusName=xyz.openbmc_project.State.Hypervisor
+
+[Install]
+WantedBy=multi-user.target