summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp321
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch493
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch176
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch56
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0004-Adding-MUX-and-Drives-present-in-HSBP-in-json-config.patch149
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0005-Allow-MUX-idle-state-to-be-configured-as-DISCONNECT.patch131
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0006-Change-HSBP-FRU-address-and-add-MUX-mode-configurati.patch96
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0007-Add-HSBP-FRU-details-in-json-configuration.patch78
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service14
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp431
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch47
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch86
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch55
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch401
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch494
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch149
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch209
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch418
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0034-Add-username-property-to-SessionInfo-interface.patch64
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend22
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/0001-allow-dbus-sensors-without-thresholds.patch39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch41
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch225
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch411
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch415
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch50
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch190
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch116
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch234
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch171
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0019-log-redfish-errors-on-all-pfr-image-auth-failures.patch100
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service9
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh54
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp219
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch832
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch74
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch60
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch158
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch67
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch59
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch75
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch81
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch77
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch120
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-Redfish-Deny-set-AccountLockDuration-to-zero.patch85
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0023-Add-get-IPMI-session-id-s-to-Redfish.patch390
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0024-Add-count-sensor-type.patch29
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0025-Add-Model-CoreCount-to-ProcessorSummary.patch288
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch875
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch148
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch53
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch117
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch46
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch928
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch121
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch453
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch468
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch679
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch296
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch132
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch85
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0009-Restructure-Redifsh-EventLog-Transmit-code-flow.patch225
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch258
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch141
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch202
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch109
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch218
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch140
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch63
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch619
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch295
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch301
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch268
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch313
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch29
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch46
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch61
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch214
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch175
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch43
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend99
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json179
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format99
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch41
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch89
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch356
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch259
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch292
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch140
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp147
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend38
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch535
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0002-Add-log-count-limitation-to-requestAdd.patch94
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0003-Fix-for-clearing-outstanding-requests.patch62
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json22
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch331
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0012-rakp12-Add-username-to-SessionInfo-interface.patch49
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml0
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service11
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml80
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/phosphor-led-manager_%.bbappend13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb27
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service9
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/network/phosphor-snmp_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend5
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init268
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch108
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch159
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch143
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch54
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch29
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0006-CPUSensor-create-RequirediTempSensor-if-defined.patch233
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0007-Add-support-for-the-energy-hwmon-type.patch266
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0008-CPUSensor-additional-debug-message.patch69
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0009-CPUSensor-Create-CPUConfig-for-each-PECI-adapter.patch147
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend49
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch1666
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch348
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/login-company-logo.svg32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/logo-header.svg31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend15
221 files changed, 25713 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb
new file mode 100644
index 000000000..f24f69a5f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb
@@ -0,0 +1,23 @@
+
+SUMMARY = "Beep code manager service"
+DESCRIPTION = "The beep code manager service will provide a method for beep code"
+
+SRC_URI = "\
+ file://CMakeLists.txt;subdir=${BP} \
+ file://beepcode_mgr.cpp;subdir=${BP} \
+ "
+PV = "0.1"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE:${PN} = "beepcode-mgr.service"
+
+inherit cmake
+inherit obmc-phosphor-systemd
+
+DEPENDS += " \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format
@@ -0,0 +1,98 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt
new file mode 100644
index 000000000..472257279
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (beepcode-mgr CXX)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+# boost support
+find_package (Boost REQUIRED)
+# pkg_check_modules(Boost boost REQUIRED)
+include_directories (${Boost_INCLUDE_DIRS})
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+# import sdbusplus
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED)
+include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS})
+link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS})
+
+# import phosphor-logging
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+include_directories (${LOGGING_INCLUDE_DIRS})
+link_directories (${LOGGING_LIBRARY_DIRS})
+
+add_executable (beepcode-mgr beepcode_mgr.cpp)
+
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}
+ phosphor_logging)
+
+install (TARGETS beepcode-mgr DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service
new file mode 100644
index 000000000..8099e2541
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Beep code manager
+
+[Service]
+Restart=always
+RestartSec=2
+ExecStart=/usr/bin/beepcode-mgr
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp
new file mode 100644
index 000000000..5a2deceaf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp
@@ -0,0 +1,321 @@
+/* Copyright 2019 Intel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <linux/input.h>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <chrono>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+static constexpr uint32_t defaultBeepFrequence = 2000;
+static constexpr uint32_t defaultBeepDurationMs = 300;
+// Duration between two beeps
+static constexpr uint32_t defaultInterBeepDurationMs = 300;
+// Duration between two 4-bit digitals
+static constexpr uint32_t defaultInterDigitBeepDurationMs = 800;
+// Duration between two patterns
+static constexpr uint32_t defaultPostBeepDurationMs = 1000;
+
+static constexpr uint8_t offBeepState = 0;
+static constexpr uint8_t onBeepState = 1;
+// finish 1 bit beep
+static constexpr uint8_t interBeepState = 2;
+// finish 4 bits beep
+static constexpr uint8_t interDigitBeepState = 3;
+// finish all bits beep
+static constexpr uint8_t postBeepState = 4;
+
+static const std::vector<uint32_t> beepDelayTable = {
+ 0, defaultBeepDurationMs, defaultInterBeepDurationMs,
+ defaultInterDigitBeepDurationMs, defaultPostBeepDurationMs};
+
+static constexpr uint32_t bpBitCount = 4;
+static constexpr uint32_t bpShiftCount = 32;
+static constexpr uint32_t bpMask = 0xf0000000;
+
+// beep code priority
+static constexpr uint8_t beepOff = 0;
+static constexpr uint8_t beepVRWatchdogTimeout = 1;
+static constexpr uint8_t beepPSUFailure = 2;
+static constexpr uint8_t beepCPUMIssing = 3;
+static constexpr uint8_t beepCPUCatError = 4;
+static constexpr uint8_t beepCPUErr2 = 5;
+static constexpr uint8_t beepVoltageMismatch = 6;
+static constexpr uint8_t beepCPUConfigError = 7;
+static constexpr uint8_t beepPowerFail = 8;
+static constexpr uint8_t beepPowerGoodTimeOut = 9;
+static constexpr uint8_t beepMax = 10;
+
+// priority, abbrev name map
+static const std::map<uint8_t, std::string> beepCodeNameList = {
+ {beepVRWatchdogTimeout, "VRWatchdogTimeout"},
+ {beepPSUFailure, "PSUFailure"},
+ {beepCPUMIssing, "CPUMissing"},
+ {beepCPUCatError, "CPUCatError"},
+ {beepCPUErr2, "CPUErr2"},
+ {beepVoltageMismatch, "VoltageMismatch"},
+ {beepCPUConfigError, "CPUConfigError"},
+ {beepPowerFail, "PowerFail"},
+ {beepPowerGoodTimeOut, "PowerGoodTimeOut"},
+};
+
+// priority, code pattern map
+static const std::map<uint8_t, std::string> beepCodePatternList = {
+ {beepVRWatchdogTimeout, "1-5-1-2"}, {beepPSUFailure, "1-5-1-4"},
+ {beepCPUMIssing, "1-5-2-1"}, {beepCPUCatError, "1-5-2-2"},
+ {beepCPUErr2, "1-5-2-3"}, {beepVoltageMismatch, "1-5-2-4"},
+ {beepCPUConfigError, "1-5-2-5"}, {beepPowerFail, "1-5-4-2"},
+ {beepPowerGoodTimeOut, "1-5-4-4"},
+};
+
+static const std::vector<uint32_t> beepCodeTable = {
+ 0, 0x1512, 0x1514, 0x1521, 0x1522, 0x1523, 0x1524, 0x1525, 0x1542, 0x1544};
+
+static constexpr char bpDevName[] = "/dev/input/event0";
+static constexpr char bpBusName[] = "xyz.openbmc_project.BeepCode";
+static constexpr char bpObjName[] = "/xyz/openbmc_project/BeepCode";
+static constexpr char bpIntfName[] = "xyz.openbmc_project.BeepCode";
+static constexpr char bpMethodName[] = "Beep";
+
+static std::shared_ptr<sdbusplus::asio::dbus_interface> bpIface;
+static boost::asio::io_service io;
+static auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+
+class Beeper
+{
+ public:
+ Beeper(boost::asio::io_service& io)
+ {
+ timer = std::make_unique<boost::asio::steady_timer>(io);
+ fdBeepDev = -1;
+ currentCount = 0;
+ currentBeepCode = 0;
+ currentMask = bpMask;
+ currentShift = bpShiftCount;
+ currentState = offBeepState;
+ timerRunning = false;
+ }
+
+ ~Beeper()
+ {
+ }
+
+ void beep(const uint8_t& beepPriority)
+ {
+ if (timerRunning)
+ {
+ pendingList.push_back(beepPriority);
+ pendingList.sort(std::greater<uint8_t>());
+ return;
+ }
+
+ performBeep(beepPriority);
+ }
+
+ private:
+ void performBeep(const uint8_t& beepPriority)
+ {
+ currentBeepCode = beepCodeTable[beepPriority];
+ currentCount = 0;
+ currentMask = bpMask;
+ currentShift = bpShiftCount;
+ getCurrentCount();
+ startBeep(defaultBeepFrequence);
+ currentState = onBeepState;
+ currentCount--;
+ timerRunning = true;
+ startBeepTimer();
+ }
+
+ void startBeepTimer()
+ {
+ timer->expires_after(
+ std::chrono::milliseconds(beepDelayTable[currentState]));
+ timer->async_wait([this](const boost::system::error_code& ec) {
+ // timer timeout
+ switch (currentState)
+ {
+ case onBeepState:
+ stopBeep();
+ if (currentCount == 0)
+ {
+ // finished the current 4-bit
+ if (currentBeepCode == 0)
+ {
+ // finished all bits
+ currentState = postBeepState;
+ }
+ else
+ {
+ // start next 4-bit
+ currentState = interDigitBeepState;
+ getCurrentCount();
+ currentCount--;
+ }
+ }
+ else
+ {
+ // still in 4-bit processing
+ currentCount--;
+ currentState = interBeepState;
+ }
+ startBeepTimer();
+ break;
+
+ case interBeepState:
+ case interDigitBeepState:
+ startBeep(defaultBeepFrequence);
+ currentState = onBeepState;
+ startBeepTimer();
+ break;
+ case postBeepState:
+ if (pendingList.size() != 0)
+ {
+ // continue the next new beepcode
+ uint8_t beepPriority = pendingList.front();
+ pendingList.pop_front();
+ performBeep(beepPriority);
+ }
+ else
+ {
+ timerRunning = false;
+ }
+ break;
+
+ default:
+ std::cerr << "Incorrect beepState: "
+ << static_cast<unsigned int>(currentState)
+ << std::endl;
+ break;
+ }
+ });
+ }
+
+ void startBeep(uint32_t freq)
+ {
+ if (fdBeepDev != -1)
+ {
+ std::cerr << "beep device is opening already!" << std::endl;
+ ::close(fdBeepDev);
+ fdBeepDev = -1;
+ }
+
+ if ((fdBeepDev = ::open(bpDevName, O_RDWR | O_CLOEXEC)) < 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to open input device");
+ return;
+ }
+
+ struct input_event event;
+ event.type = EV_SND;
+ event.code = SND_TONE;
+ event.value = freq;
+
+ if (::write(fdBeepDev, &event, sizeof(struct input_event)) !=
+ sizeof(struct input_event))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to write a tone sound event");
+ ::close(fdBeepDev);
+ fdBeepDev = -1;
+ return;
+ }
+ return;
+ }
+
+ void stopBeep()
+ {
+ if (fdBeepDev == -1)
+ {
+ std::cerr << "beep device is closed!" << std::endl;
+ return;
+ }
+
+ ::close(fdBeepDev);
+ fdBeepDev = -1;
+ }
+
+ // Split the beep code based on bpBitCount, for example 0x1544,
+ // currentCount=1, 5, 4, 4
+ void getCurrentCount()
+ {
+ while (currentCount == 0)
+ {
+ currentCount = currentMask & currentBeepCode;
+ currentShift -= bpBitCount;
+ currentCount >>= currentShift;
+ currentBeepCode = currentBeepCode & ~currentMask;
+ currentMask >>= bpBitCount;
+ if (currentMask == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ int fdBeepDev;
+ bool timerRunning;
+ uint32_t currentCount;
+ uint32_t currentBeepCode;
+ uint32_t currentMask;
+ uint32_t currentShift;
+ uint8_t currentState;
+ std::unique_ptr<boost::asio::steady_timer> timer;
+ std::list<uint8_t> pendingList;
+};
+
+static Beeper beeper(io);
+
+// dbus method
+static void beep(const uint8_t& beepPriority)
+{
+ if ((beepPriority >= beepMax) || (beepPriority == beepOff))
+ {
+ std::cerr << "Incorrect input: "
+ << static_cast<unsigned int>(beepPriority) << std::endl;
+ return;
+ }
+
+ beeper.beep(beepPriority);
+
+ return;
+}
+
+int main(int argc, char** argv)
+{
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Starting BeepCode service");
+
+ conn->request_name(bpBusName);
+ sdbusplus::asio::object_server server =
+ sdbusplus::asio::object_server(conn);
+ bpIface = server.add_interface(bpObjName, bpIntfName);
+
+ bpIface->register_property("BeepCodeNameList", beepCodeNameList,
+ sdbusplus::asio::PropertyPermission::readOnly);
+ bpIface->register_property("BeepCodePatternList", beepCodePatternList,
+ sdbusplus::asio::PropertyPermission::readOnly);
+ bpIface->register_method(bpMethodName, beep);
+ bpIface->initialize();
+
+ io.run();
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json
@@ -0,0 +1,12 @@
+{
+ "enum_char": ".",
+ "line_ending": "unix",
+ "bullet_char": "*",
+ "max_subargs_per_line": 99,
+ "command_case": "lower",
+ "tab_size": 4,
+ "line_width": 80,
+ "separate_fn_name_with_space": true,
+ "dangle_parens": true,
+ "separate_ctrl_name_with_space": true
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb
new file mode 100644
index 000000000..711e4eced
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb
@@ -0,0 +1,28 @@
+SUMMARY = "BIOS Config Manager daemon for managing the BIOS configuration"
+DESCRIPTION = "To view and modify BIOS setup configuration remotely via BMC"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+inherit meson systemd
+
+SRC_URI = "git://github.com/openbmc/bios-settings-mgr.git"
+SRCREV = "29656f07b7e81c0bb13ca119b4c6ef62f5e79a18"
+
+SYSTEMD_SERVICE:${PN} += " \
+ xyz.openbmc_project.biosconfig_manager.service \
+ xyz.openbmc_project.biosconfig_password.service \
+ "
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ libgpiod \
+ phosphor-logging \
+ boost \
+ nlohmann-json \
+ libtinyxml2 \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch
new file mode 100644
index 000000000..e47111c56
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch
@@ -0,0 +1,493 @@
+From a85d4c9cf702965593ec771e57a975e30d1d5853 Mon Sep 17 00:00:00 2001
+From: Johnathan Mantey <johnathanx.mantey@intel.com>
+Date: Tue, 13 Oct 2020 15:00:51 -0700
+Subject: [PATCH] Improve initialization of I2C sensors
+
+After an AC cycle validation has witnessed some systems sensors are
+missing. As Entity Manager begins the process of scanning for
+sesnsors, and creating the hardware monitoring nodes, there are
+occassionally some failures to correctly create the node. This
+manifests itself by the 'dd' kernel driver emitting an -EBUSY error
+message. Unfortunately the 'dd' driver also eats the error code, and
+continues. This is by design.
+
+This commit modifies how the nodes are initialized. The steps taken:
+1. Determine if the node is already present
+2. Create the node if it is not
+3. Set a timer, to give the kernel time to create the node
+4. For those sensors that create a "hwmon" subdir, search for that
+directory after the timer elapses.
+5. If the subdir is not present, delete the device, and try again by
+initiating another timer.
+6. Continue until the subdir exists, or a retry count expires.
+
+Tested:
+Ran AC cycles via a script.
+After each cycle, wait for the SUT to DC on, and arrive at the EFI
+Shell> propmt.
+Issue "ipmitool sensor list", capturing the results
+Search the list for all of the sensors that have been reported as
+missing after AC cycles.
+
+Change-Id: I118df674162677d66e7d211b089430fce384086b
+Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
+---
+ include/devices.hpp | 167 +++++++++++++++++++++-----------------
+ src/Overlay.cpp | 192 ++++++++++++++++++++++++++++++++++----------
+ 2 files changed, 243 insertions(+), 116 deletions(-)
+
+diff --git a/include/devices.hpp b/include/devices.hpp
+index 50fbe63..2e299a0 100644
+--- a/include/devices.hpp
++++ b/include/devices.hpp
+@@ -31,107 +31,130 @@ struct CmpStr
+
+ struct ExportTemplate
+ {
+- ExportTemplate(const char* params, const char* dev) :
+- parameters(params), device(dev){};
++ ExportTemplate(const char* params, const char* dev, const char* constructor,
++ const char* destructor, bool createsHWMon) :
++ parameters(params),
++ devicePath(dev), add(constructor), remove(destructor),
++ createsHWMon(createsHWMon){};
+ const char* parameters;
+- const char* device;
++ const char* devicePath;
++ const char* add;
++ const char* remove;
++ bool createsHWMon;
+ };
+
+ const boost::container::flat_map<const char*, ExportTemplate, CmpStr>
+ exportTemplates{
+ {{"EEPROM_24C02",
+ ExportTemplate("24c02 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ "/sys/bus/i2c/devices/i2c-$Bus/new_device",
++ "new_device", "delete_device", false)},
+ {"EEPROM_24C64",
+ ExportTemplate("24c64 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"ADM1266",
+- ExportTemplate("adm1266 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ "/sys/bus/i2c/devices/i2c-$Bus/new_device",
++ "new_device", "delete_device", false)},
++ {"24C02",
++ ExportTemplate("24c02 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
++ {"24C64",
++ ExportTemplate("24c64 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
++ {"ADM1266", ExportTemplate("adm1266 $Address",
++ "/sys/bus/i2c/devices/i2c-$Bus/new_device",
++ "new_device", "delete_device", false)},
+ {"ADM1272",
+- ExportTemplate("adm1272 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"EEPROM", ExportTemplate("eeprom $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("adm1272 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
++ {"EEPROM",
++ ExportTemplate("eeprom $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
+ {"EMC1412",
+- ExportTemplate("emc1412 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("emc1412 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"EMC1413",
+- ExportTemplate("emc1413 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("emc1413 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"EMC1414",
+- ExportTemplate("emc1414 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"Gpio", ExportTemplate("$Index", "/sys/class/gpio/export")},
+- {"INA230", ExportTemplate("ina230 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("emc1414 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"Gpio", ExportTemplate("$Index", "/sys/class/gpio", "export",
++ "unexport", false)},
++ {"INA230",
++ ExportTemplate("ina230 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"ISL68137",
+- ExportTemplate("isl68137 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("isl68137 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"ISL68223",
+- ExportTemplate("isl68223 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("isl68223 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"ISL69243",
+- ExportTemplate("isl69243 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("isl69243 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX16601",
+- ExportTemplate("max16601 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max16601 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX20710",
+- ExportTemplate("max20710 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max20710 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX20730",
+- ExportTemplate("max20730 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max20730 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX20734",
+- ExportTemplate("max20734 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max20734 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX20796",
+- ExportTemplate("max20796 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max20796 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX31725",
+- ExportTemplate("max31725 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max31725 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX31730",
+- ExportTemplate("max31730 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"MAX34440",
+- ExportTemplate("max34440 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max31730 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"MAX34440", ExportTemplate("max34440 $Address",
++ "/sys/bus/i2c/devices/i2c-$Bus/new_device",
++ "new_device", "delete_device", true)},
+ {"MAX34451",
+- ExportTemplate("max34451 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max34451 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"MAX6654",
+- ExportTemplate("max6654 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("max6654 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"PCA9543Mux",
+- ExportTemplate("pca9543 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("pca9543 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
+ {"PCA9544Mux",
+- ExportTemplate("pca9544 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("pca9544 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
+ {"PCA9545Mux",
+- ExportTemplate("pca9545 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("pca9545 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
+ {"PCA9546Mux",
+- ExportTemplate("pca9546 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("pca9546 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
+ {"PCA9547Mux",
+- ExportTemplate("pca9547 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"SBTSI", ExportTemplate("sbtsi $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"pmbus", ExportTemplate("pmbus $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"TMP112", ExportTemplate("tmp112 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"TMP175", ExportTemplate("tmp175 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"TMP421", ExportTemplate("tmp421 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
+- {"TMP441", ExportTemplate("tmp441 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")},
++ ExportTemplate("pca9547 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", false)},
++ {"SBTSI",
++ ExportTemplate("sbtsi $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"pmbus",
++ ExportTemplate("pmbus $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"TMP112",
++ ExportTemplate("tmp112 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"TMP175",
++ ExportTemplate("tmp175 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"TMP421",
++ ExportTemplate("tmp421 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
++ {"TMP441",
++ ExportTemplate("tmp441 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)},
+ {"TMP75",
+- ExportTemplate("tmp75 $Address",
+- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}}};
++ ExportTemplate("tmp75 $Address", "/sys/bus/i2c/devices/i2c-$Bus",
++ "new_device", "delete_device", true)}}};
+ } // namespace devices
+diff --git a/src/Overlay.cpp b/src/Overlay.cpp
+index cb6ed10..7a3089e 100644
+--- a/src/Overlay.cpp
++++ b/src/Overlay.cpp
+@@ -21,6 +21,8 @@
+ #include "devices.hpp"
+
+ #include <boost/algorithm/string/predicate.hpp>
++#include <boost/asio/io_context.hpp>
++#include <boost/asio/steady_timer.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <boost/container/flat_set.hpp>
+ #include <boost/process/child.hpp>
+@@ -32,6 +34,8 @@
+ #include <regex>
+ #include <string>
+
++extern boost::asio::io_context io;
++
+ constexpr const char* OUTPUT_DIR = "/tmp/overlays";
+ constexpr const char* TEMPLATE_CHAR = "$";
+ constexpr const char* HEX_FORMAT_STR = "0x";
+@@ -113,16 +117,149 @@ void linkMux(const std::string& muxName, size_t busIndex, size_t address,
+ }
+ }
+
++static int deleteDevice(const std::string& devicePath,
++ std::shared_ptr<uint64_t> address,
++ const std::string& destructor)
++{
++ if (!address)
++ {
++ return -1;
++ }
++ std::filesystem::path deviceDestructor(devicePath);
++ deviceDestructor /= destructor;
++ std::ofstream deviceFile(deviceDestructor);
++ if (!deviceFile.good())
++ {
++ std::cerr << "Error writing " << deviceDestructor << "\n";
++ return -1;
++ }
++ deviceFile << std::to_string(*address);
++ deviceFile.close();
++ return 0;
++}
++
++static int createDevice(const std::string& devicePath,
++ const std::string& parameters,
++ const std::string& constructor)
++{
++ std::filesystem::path deviceConstructor(devicePath);
++ deviceConstructor /= constructor;
++ std::ofstream deviceFile(deviceConstructor);
++ if (!deviceFile.good())
++ {
++ std::cerr << "Error writing " << deviceConstructor << "\n";
++ return -1;
++ }
++ deviceFile << parameters;
++ deviceFile.close();
++
++ return 0;
++}
++
++static bool deviceIsCreated(const std::string& devicePath,
++ std::shared_ptr<uint64_t> bus,
++ std::shared_ptr<uint64_t> address,
++ const bool retrying)
++{
++ // Prevent the device from being created a second time.
++ if (bus && address)
++ {
++ std::ostringstream hex;
++ hex << std::hex << *address;
++ std::string addressHex = hex.str();
++ std::string busStr = std::to_string(*bus);
++
++ if (std::filesystem::is_directory(devicePath))
++ {
++ for (const auto& path :
++ std::filesystem::directory_iterator(devicePath))
++ {
++ if (!std::filesystem::is_directory(path))
++ {
++ continue;
++ }
++
++ const std::string& directoryName = path.path().filename();
++ if (boost::starts_with(directoryName, busStr) &&
++ boost::ends_with(directoryName, addressHex))
++ {
++ if (retrying)
++ {
++ // subsequent attempts should find the hwmon subdir.
++ std::filesystem::path hwmonDir(devicePath);
++ hwmonDir /= directoryName;
++ hwmonDir /= "hwmon";
++ bool dirFound =
++ (std::filesystem::is_directory(hwmonDir));
++ return dirFound;
++ }
++ else
++ {
++ return true;
++ }
++ }
++ }
++ return false;
++ }
++ }
++ return false;
++}
++
++constexpr size_t totalBuildDeviceRetries = 5;
++static int buildDevice(const std::string& devicePath,
++ const std::string& parameters,
++ std::shared_ptr<uint64_t> bus,
++ std::shared_ptr<uint64_t> address,
++ const std::string& constructor,
++ const std::string& destructor, const bool createsHWMon,
++ const size_t retries = totalBuildDeviceRetries)
++{
++ bool tryAgain = false;
++ if (!retries)
++ {
++ return -1;
++ }
++
++ if (!deviceIsCreated(devicePath, bus, address, false))
++ {
++ createDevice(devicePath, parameters, constructor);
++ tryAgain = true;
++ }
++ else if (createsHWMon && !deviceIsCreated(devicePath, bus, address, true))
++ {
++ // device is present, hwmon subdir missing
++ deleteDevice(devicePath, address, destructor);
++ tryAgain = true;
++ }
++
++ if (tryAgain)
++ {
++ std::shared_ptr<boost::asio::steady_timer> createTimer =
++ std::make_shared<boost::asio::steady_timer>(io);
++ createTimer->expires_after(std::chrono::milliseconds(500));
++ createTimer->async_wait([createTimer, devicePath, parameters, bus,
++ address, constructor, destructor, createsHWMon,
++ retries](const boost::system::error_code&) {
++ buildDevice(devicePath, parameters, bus, address, constructor,
++ destructor, createsHWMon, retries - 1);
++ });
++ }
++ return 0;
++}
++
+ void exportDevice(const std::string& type,
+ const devices::ExportTemplate& exportTemplate,
+ const nlohmann::json& configuration)
+ {
+
+ std::string parameters = exportTemplate.parameters;
+- std::string device = exportTemplate.device;
++ std::string devicePath = exportTemplate.devicePath;
++ std::string constructor = exportTemplate.add;
++ std::string destructor = exportTemplate.remove;
++ bool createsHWMon = exportTemplate.createsHWMon;
+ std::string name = "unknown";
+- const uint64_t* bus = nullptr;
+- const uint64_t* address = nullptr;
++ std::shared_ptr<uint64_t> bus = nullptr;
++ std::shared_ptr<uint64_t> address = nullptr;
+ const nlohmann::json::array_t* channels = nullptr;
+
+ for (auto keyPair = configuration.begin(); keyPair != configuration.end();
+@@ -144,11 +281,13 @@ void exportDevice(const std::string& type,
+
+ if (keyPair.key() == "Bus")
+ {
+- bus = keyPair.value().get_ptr<const uint64_t*>();
++ bus = std::make_shared<uint64_t>(
++ *keyPair.value().get_ptr<const uint64_t*>());
+ }
+ else if (keyPair.key() == "Address")
+ {
+- address = keyPair.value().get_ptr<const uint64_t*>();
++ address = std::make_shared<uint64_t>(
++ *keyPair.value().get_ptr<const uint64_t*>());
+ }
+ else if (keyPair.key() == "ChannelNames")
+ {
+@@ -157,49 +296,14 @@ void exportDevice(const std::string& type,
+ }
+ boost::replace_all(parameters, TEMPLATE_CHAR + keyPair.key(),
+ subsituteString);
+- boost::replace_all(device, TEMPLATE_CHAR + keyPair.key(),
++ boost::replace_all(devicePath, TEMPLATE_CHAR + keyPair.key(),
+ subsituteString);
+ }
+
+- // if we found bus and address we can attempt to prevent errors
+- if (bus != nullptr && address != nullptr)
+- {
+- std::ostringstream hex;
+- hex << std::hex << *address;
+- const std::string& addressHex = hex.str();
+- std::string busStr = std::to_string(*bus);
++ int err = buildDevice(devicePath, parameters, bus, address, constructor,
++ destructor, createsHWMon);
+
+- std::filesystem::path devicePath(device);
+- std::filesystem::path parentPath = devicePath.parent_path();
+- if (std::filesystem::is_directory(parentPath))
+- {
+- for (const auto& path :
+- std::filesystem::directory_iterator(parentPath))
+- {
+- if (!std::filesystem::is_directory(path))
+- {
+- continue;
+- }
+-
+- const std::string& directoryName = path.path().filename();
+- if (boost::starts_with(directoryName, busStr) &&
+- boost::ends_with(directoryName, addressHex))
+- {
+- return; // already exported
+- }
+- }
+- }
+- }
+-
+- std::ofstream deviceFile(device);
+- if (!deviceFile.good())
+- {
+- std::cerr << "Error writing " << device << "\n";
+- return;
+- }
+- deviceFile << parameters;
+- deviceFile.close();
+- if (boost::ends_with(type, "Mux") && bus && address && channels)
++ if (!err && boost::ends_with(type, "Mux") && bus && address && channels)
+ {
+ linkMux(name, static_cast<size_t>(*bus), static_cast<size_t>(*address),
+ *channels);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch
new file mode 100644
index 000000000..0fea3e8a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch
@@ -0,0 +1,176 @@
+From 0941036f4206d74bfc3d3e505a5d269fb39c48ff Mon Sep 17 00:00:00 2001
+From: mansijos <mansi.joshi@intel.com>
+Date: Tue, 6 Apr 2021 02:12:56 +0530
+Subject: [PATCH] Entity-manager: Add support to update assetTag
+
+Asset tag is an updateable property from User level interface like
+Redfish. User-level interface will update Asset tag in entity-manager,
+which will further update the needed FRU interface property exposed.
+
+Tested:
+Successfully updated in assetTag interface as well as in fru interface
+while using set-property and using redfish as well.
+The new value is preserved after BMC resets.
+
+Change-Id: If7fbfd8325488280f500ab0e2c8b38475813cc3f
+Signed-off-by: mansijos <mansi.joshi@intel.com>
+---
+ src/EntityManager.cpp | 95 +++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 91 insertions(+), 4 deletions(-)
+
+diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
+index 490c0f5..139ba9a 100644
+--- a/src/EntityManager.cpp
++++ b/src/EntityManager.cpp
+@@ -48,9 +48,19 @@ constexpr const char* lastConfiguration = "/tmp/configuration/last.json";
+ constexpr const char* currentConfiguration = "/var/configuration/system.json";
+ constexpr const char* globalSchema = "global.json";
+ constexpr const int32_t maxMapperDepth = 0;
++constexpr const char* foundObject = "FoundProbe";
+
+ constexpr const bool debug = false;
+
++
++
++using foundProbeData = std::map<std::string, std::string>;
++static foundProbeData foundData;
++static std::map<std::string, foundProbeData> mapFoundData;
++
++constexpr const char* fruConn = "xyz.openbmc_project.FruDevice";
++constexpr const char* fruIntf = "xyz.openbmc_project.FruDevice";
++
+ struct CmpStr
+ {
+ bool operator()(const char* a, const char* b) const
+@@ -577,6 +587,43 @@ void addArrayToDbus(const std::string& name, const nlohmann::json& array,
+ }
+ }
+
++template <typename PropertyType>
++bool persistAssetTag(const PropertyType& newVal,
++ const std::string& jsonPointerString)
++{
++ std::size_t found = jsonPointerString.find_last_of("/\\");
++ std::string jsonPointerPath = jsonPointerString.substr(0, found);
++
++ auto it = mapFoundData.find(jsonPointerPath);
++ if (it == mapFoundData.end())
++ {
++ std::cerr << "Error in finding jsonPointerPath in mapFoundData"
++ << "\n";
++ return false;
++ }
++
++ foundProbeData& tmpMap = it->second;
++ auto foundPath = tmpMap.find("foundPath");
++ if (foundPath == tmpMap.end())
++ {
++ std::cerr << "No prob object data is avaliable in foundProbeData"
++ << "\n";
++ return false;
++ }
++
++ systemBus->async_method_call(
++ [](const boost::system::error_code& ec) {
++ if (ec)
++ {
++ std::cerr << "Error setting AssetTag in FRU interface " << ec
++ << "\n";
++ }
++ },
++ fruConn, foundPath->second, "org.freedesktop.DBus.Properties", "Set",
++ fruIntf, "PRODUCT_ASSET_TAG", std::variant<PropertyType>(newVal));
++ return true;
++}
++
+ template <typename PropertyType>
+ void addProperty(const std::string& propertyName, const PropertyType& value,
+ sdbusplus::asio::dbus_interface* iface,
+@@ -591,9 +638,18 @@ void addProperty(const std::string& propertyName, const PropertyType& value,
+ }
+ iface->register_property(
+ propertyName, value,
+- [&systemConfiguration,
++ [propertyName, &systemConfiguration,
+ jsonPointerString{std::string(jsonPointerString)}](
+ const PropertyType& newVal, PropertyType& val) {
++ if (propertyName == "AssetTag")
++ {
++ if (!persistAssetTag(newVal, jsonPointerString))
++ {
++ std::cerr << "error setting AssetTag in FRU interface\n";
++ return -1;
++ }
++ }
++
+ val = newVal;
+ if (!setJsonFromPointer(jsonPointerString, val,
+ systemConfiguration))
+@@ -993,6 +1049,9 @@ void postToDbus(const nlohmann::json& newConfiguration,
+ populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
+ boardIface, boardValues, objServer);
+ jsonPointerPath += "/";
++
++ std::string foundPath;
++
+ // iterate through board properties
+ for (auto& boardField : boardValues.items())
+ {
+@@ -1002,9 +1061,28 @@ void postToDbus(const nlohmann::json& newConfiguration,
+ createInterface(objServer, boardName, boardField.key(),
+ boardKeyOrig);
+
+- populateInterfaceFromJson(systemConfiguration,
+- jsonPointerPath + boardField.key(),
+- iface, boardField.value(), objServer);
++ if (boardField.key() == "FoundProbe")
++ {
++ foundPath = boardField.value()["Path"];
++ }
++ if (boardField.key() ==
++ "xyz.openbmc_project.Inventory.Decorator.AssetTag")
++ {
++ foundData["foundPath"] = foundPath;
++ mapFoundData[jsonPointerPath + boardField.key()] =
++ foundData;
++
++ populateInterfaceFromJson(
++ systemConfiguration, jsonPointerPath + boardField.key(),
++ iface, boardField.value(), objServer,
++ sdbusplus::asio::PropertyPermission::readWrite);
++ }
++ else
++ {
++ populateInterfaceFromJson(
++ systemConfiguration, jsonPointerPath + boardField.key(),
++ iface, boardField.value(), objServer);
++ }
+ }
+ }
+
+@@ -1362,6 +1440,11 @@ void PerformScan::run()
+ {
+ continue; // non-numeric replacement
+ }
++
++ nlohmann::json recordVal = *recordPtr;
++ // Save the dbus path info of the device
++ recordVal[foundObject]["Path"] = std::get<1>(*itr);
++
+ usedNames.insert(nameIt.value());
+ auto usedIt = std::find(indexes.begin(),
+ indexes.end(), index);
+@@ -1439,6 +1522,10 @@ void PerformScan::run()
+ }
+ }
+
++ // Save the dbus path info of the device
++ record[foundObject]["Path"] =
++ std::get<1>(foundDeviceAndPath);
++
+ if (replaceStr)
+ {
+ std::cerr << "Duplicates found, replacing "
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch
new file mode 100644
index 000000000..94af67967
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch
@@ -0,0 +1,56 @@
+From 28525b56161e1b659e85e85c33fc00dc397758aa Mon Sep 17 00:00:00 2001
+From: Helen Huang <he.huang@intel.com>
+Date: Mon, 19 Apr 2021 16:06:15 +0800
+Subject: [PATCH] Add logs to fwVersionIsSame()
+
+Add logs to fwVersionIsSame() to indicate whether the firmware
+version is changed or not.
+
+Tested:
+Logs are printed as expected when firmware updating and BMC rebooting.
+
+Log of rebooting:
+The firmware version is similiar as the last boot,
+Hash value of versionFile is:3336889560
+
+Log of Firmware update:
+The firmware version is changed since the last boot,
+hash value of current versionFile is:3336889560,
+hash value of versionFile of last boot is:834871226
+
+Change-Id: I5306917329d2e2e015af58cad1e9c59881f0b217
+Signed-off-by: Helen Huang <he.huang@intel.com>
+---
+ include/Utils.hpp | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/include/Utils.hpp b/include/Utils.hpp
+index 657af92..8238807 100644
+--- a/include/Utils.hpp
++++ b/include/Utils.hpp
+@@ -116,13 +116,22 @@ inline bool fwVersionIsSame(void)
+
+ if (expectedHash == hashString)
+ {
++ std::cout << "The firmware version is similiar as the last boot, "
++ "hash value of versionFile is:"
++ << hashString.c_str() << "\n";
+ return true;
+ }
++ std::cout << "The firmware version is changed since the last boot, hash "
++ "value of current versionFile is:"
++ << expectedHash.c_str()
++ << ", hash value of versionFile of last boot is:"
++ << hashString.c_str() << "\n";
+ hashFile.close();
+ }
+
+ std::ofstream output(versionHashFile);
+ output << expectedHash;
++
+ return false;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0004-Adding-MUX-and-Drives-present-in-HSBP-in-json-config.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0004-Adding-MUX-and-Drives-present-in-HSBP-in-json-config.patch
new file mode 100644
index 000000000..4f6679dde
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0004-Adding-MUX-and-Drives-present-in-HSBP-in-json-config.patch
@@ -0,0 +1,149 @@
+From 95a1f9e5f65d35adc3cf8d3b3095d92b63c17f85 Mon Sep 17 00:00:00 2001
+From: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+Date: Sun, 20 Jun 2021 18:22:34 +0000
+Subject: [PATCH] Add MUX and Drives present in HSBP in json configuration
+
+Added Mux addresses for all 3 HSBP configuration and the drive
+names to be exposed via entity manager when the HSBP is connected
+
+Added board instance to separate each HSBP board.
+
+Tested:
+After this addition, detected the MUXes in entity manager
+tree as well as in /dev/i2c-mux location. Also able to detect
+the drive address.
+
+Change-Id: Ic07e3880cf5b6f8a47ee7b8f1f98e12042765da8
+Signed-off-by: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+
+---
+ configurations/F2U8X25 HSBP.json | 78 ++++++++++++++++++++++++++++++--
+ 1 file changed, 75 insertions(+), 3 deletions(-)
+
+diff --git a/configurations/F2U8X25 HSBP.json b/configurations/F2U8X25 HSBP.json
+index c6c7678..e2eedfa 100644
+--- a/configurations/F2U8X25 HSBP.json
++++ b/configurations/F2U8X25 HSBP.json
+@@ -7,6 +7,30 @@
+ "Name": "F2U8X25 HSBP1 FRU",
+ "Type": "EEPROM"
+ },
++ {
++ "Address": "0x70",
++ "Bus": "$bus",
++ "ChannelNames": [
++ "Drive_1",
++ "Drive_2",
++ "Drive_3",
++ "Drive_4"
++ ],
++ "Name": "Drive Mux 1",
++ "Type": "PCA9546Mux"
++ },
++ {
++ "Address": "0x74",
++ "Bus": "$bus",
++ "ChannelNames": [
++ "Drive_5",
++ "Drive_6",
++ "Drive_7",
++ "Drive_8"
++ ],
++ "Name": "Drive Mux 2",
++ "Type": "PCA9546Mux"
++ },
+ {
+ "Address": "0x48",
+ "Bus": "$bus",
+@@ -40,7 +64,7 @@
+ "Type": "TMP75"
+ }
+ ],
+- "Name": "F2U8X25 HSBP",
++ "Name": "F2U8X25 HSBP 1",
+ "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 80})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+@@ -58,6 +82,30 @@
+ "Name": "F2U8X25 HSBP2 FRU",
+ "Type": "EEPROM"
+ },
++ {
++ "Address": "0x73",
++ "Bus": "$bus",
++ "ChannelNames": [
++ "Drive_9",
++ "Drive_10",
++ "Drive_11",
++ "Drive_12"
++ ],
++ "Name": "Drive Mux 3",
++ "Type": "PCA9546Mux"
++ },
++ {
++ "Address": "0x77",
++ "Bus": "$bus",
++ "ChannelNames": [
++ "Drive_13",
++ "Drive_14",
++ "Drive_15",
++ "Drive_16"
++ ],
++ "Name": "Drive Mux 4",
++ "Type": "PCA9546Mux"
++ },
+ {
+ "Address": "0x4B",
+ "Bus": "$bus",
+@@ -91,7 +139,7 @@
+ "Type": "TMP75"
+ }
+ ],
+- "Name": "F2U8X25 HSBP",
++ "Name": "F2U8X25 HSBP 2",
+ "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 83})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+@@ -109,6 +157,30 @@
+ "Name": "F2U8X25 HSBP3 FRU",
+ "Type": "EEPROM"
+ },
++ {
++ "Address": "0x72",
++ "Bus": "$bus",
++ "ChannelNames": [
++ "Drive_17",
++ "Drive_18",
++ "Drive_19",
++ "Drive_20"
++ ],
++ "Name": "Drive Mux 5",
++ "Type": "PCA9546Mux"
++ },
++ {
++ "Address": "0x76",
++ "Bus": "$bus",
++ "ChannelNames": [
++ "Drive_21",
++ "Drive_22",
++ "Drive_23",
++ "Drive_24"
++ ],
++ "Name": "Drive Mux 6",
++ "Type": "PCA9546Mux"
++ },
+ {
+ "Address": "0x4A",
+ "Bus": "$bus",
+@@ -142,7 +214,7 @@
+ "Type": "TMP75"
+ }
+ ],
+- "Name": "F2U8X25 HSBP",
++ "Name": "F2U8X25 HSBP 3",
+ "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 82})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0005-Allow-MUX-idle-state-to-be-configured-as-DISCONNECT.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0005-Allow-MUX-idle-state-to-be-configured-as-DISCONNECT.patch
new file mode 100644
index 000000000..ac0995614
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0005-Allow-MUX-idle-state-to-be-configured-as-DISCONNECT.patch
@@ -0,0 +1,131 @@
+From aada39602a21e83d7e8c39c39fb8c5c32122863c Mon Sep 17 00:00:00 2001
+From: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+Date: Thu, 2 Sep 2021 11:11:40 +0000
+Subject: [PATCH] Allow MUX idle state to be configured as DISCONNECT
+
+The existing Linux behavior is to leave the Mux status as it is after
+an operation. In HSBP and in other places we have more than one MUX
+parallel in same root bus. The existing behavior will result in reading
+multiple buses of different MUXes at the same time and causes bad read.
+In this fix, we can configure "MuxIdleMode" as "Disconnect" in
+configuration file as shown below
+
+{
+ "Address": "0x70",
+ "Bus": "$bus",
+ "ChannelNames": [
+ "Drive_1",
+ "Drive_2",
+ "Drive_3",
+ "Drive_4"
+ ],
+ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 1",
+ "Type": "PCA9546Mux"
+
+Tested:
+Set the MUX idle mode to Disconnect in MUXes present in HSBP board and
+only one channel is read at a time.
+
+Change-Id: I6d29cd3be350682c386bd3072e76b930a7d45587
+Signed-off-by: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+---
+ src/Overlay.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 52 insertions(+), 3 deletions(-)
+
+diff --git a/src/Overlay.cpp b/src/Overlay.cpp
+index 4454423..2843c31 100644
+--- a/src/Overlay.cpp
++++ b/src/Overlay.cpp
+@@ -38,11 +38,46 @@ constexpr const char* outputDir = "/tmp/overlays";
+ constexpr const char* templateChar = "$";
+ constexpr const char* i2CDevsDir = "/sys/bus/i2c/devices";
+ constexpr const char* muxSymlinkDir = "/dev/i2c-mux";
++constexpr const char* idleModeAsIs = "-1";
++constexpr const char* idleModeDisconnect = "-2";
+
+ constexpr const bool debug = false;
+
+ std::regex illegalNameRegex("[^A-Za-z0-9_]");
+
++void setIdleMode(const std::string& muxName, size_t busIndex, size_t address,
++ const std::string& idleMode)
++{
++ std::error_code ec;
++
++ std::ostringstream hexAddress;
++ hexAddress << std::hex << std::setfill('0') << std::setw(4) << address;
++
++ std::filesystem::path idlePath(i2CDevsDir);
++ idlePath /=
++ std::to_string(busIndex) + "-" + hexAddress.str() + "/idle_state";
++
++ std::string modeData =
++ (idleMode == "Disconnect") ? idleModeDisconnect : idleModeAsIs;
++
++ if (debug)
++ {
++ std::cerr << "Setting " << muxName << " idle state to " << modeData
++ << " in " << idlePath << "\n";
++ }
++
++ std::ofstream idleFile(idlePath);
++ if (!idleFile.good())
++ {
++ std::cerr << "Can't set idle mode in " << idlePath << " for " << muxName
++ << "\n";
++ }
++ else
++ {
++ idleFile << modeData;
++ }
++}
++
+ // helper function to make json types into string
+ std::string jsonToString(const nlohmann::json& in)
+ {
+@@ -285,6 +320,7 @@ void exportDevice(const std::string& type,
+ std::shared_ptr<uint64_t> bus = nullptr;
+ std::shared_ptr<uint64_t> address = nullptr;
+ const nlohmann::json::array_t* channels = nullptr;
++ std::string idleMode;
+
+ for (auto keyPair = configuration.begin(); keyPair != configuration.end();
+ keyPair++)
+@@ -318,6 +354,11 @@ void exportDevice(const std::string& type,
+ channels =
+ keyPair.value().get_ptr<const nlohmann::json::array_t*>();
+ }
++ else if (keyPair.key() == "MuxIdleMode")
++ {
++ idleMode = keyPair.value().get<std::string>();
++ }
++
+ boost::replace_all(parameters, templateChar + keyPair.key(),
+ subsituteString);
+ boost::replace_all(devicePath, templateChar + keyPair.key(),
+@@ -327,10 +368,18 @@ void exportDevice(const std::string& type,
+ int err = buildDevice(devicePath, parameters, bus, address, constructor,
+ destructor, createsHWMon);
+
+- if (!err && boost::ends_with(type, "Mux") && bus && address && channels)
++ if (!err && boost::ends_with(type, "Mux") && bus && address)
+ {
+- linkMux(name, static_cast<size_t>(*bus), static_cast<size_t>(*address),
+- *channels);
++ if (channels)
++ {
++ linkMux(name, static_cast<size_t>(*bus),
++ static_cast<size_t>(*address), *channels);
++ }
++ if (!idleMode.empty())
++ {
++ setIdleMode(name, static_cast<size_t>(*bus),
++ static_cast<size_t>(*address), idleMode);
++ }
+ }
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0006-Change-HSBP-FRU-address-and-add-MUX-mode-configurati.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0006-Change-HSBP-FRU-address-and-add-MUX-mode-configurati.patch
new file mode 100644
index 000000000..a3d065fd9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0006-Change-HSBP-FRU-address-and-add-MUX-mode-configurati.patch
@@ -0,0 +1,96 @@
+From 0ece2ae628f6d4ee57319dc7e153680cdddff1d2 Mon Sep 17 00:00:00 2001
+From: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+Date: Sun, 12 Sep 2021 22:21:55 +0000
+Subject: [PATCH] Change HSBP FRU address and add MUX mode configuration
+
+Changed the HSBP EEPROM FRU address according to Hardware
+rework and added the MUX idle mode configuration as
+"Disconnect". The later will keep MUX channel mode in
+disconnected state after the channel is accessed.
+
+Tested:
+1. Detected and read the HSBP EEPROM FRU with new address
+on reworked board.
+2. Confirmed the idle state of MUX channel after it is
+accessed is disconnected, this solved the bad read
+caused by reading multiple buses of different MUXes at
+same time.
+
+Signed-off-by: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+---
+ configurations/F2U8X25 HSBP.json | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/configurations/F2U8X25 HSBP.json b/configurations/F2U8X25 HSBP.json
+index e2eedfa..60e7817 100644
+--- a/configurations/F2U8X25 HSBP.json
++++ b/configurations/F2U8X25 HSBP.json
+@@ -16,6 +16,7 @@
+ "Drive_3",
+ "Drive_4"
+ ],
++ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 1",
+ "Type": "PCA9546Mux"
+ },
+@@ -28,6 +29,7 @@
+ "Drive_7",
+ "Drive_8"
+ ],
++ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 2",
+ "Type": "PCA9546Mux"
+ },
+@@ -65,7 +67,7 @@
+ }
+ ],
+ "Name": "F2U8X25 HSBP 1",
+- "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 80})",
++ "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 84})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "$BOARD_MANUFACTURER",
+@@ -91,6 +93,7 @@
+ "Drive_11",
+ "Drive_12"
+ ],
++ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 3",
+ "Type": "PCA9546Mux"
+ },
+@@ -103,6 +106,7 @@
+ "Drive_15",
+ "Drive_16"
+ ],
++ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 4",
+ "Type": "PCA9546Mux"
+ },
+@@ -140,7 +144,7 @@
+ }
+ ],
+ "Name": "F2U8X25 HSBP 2",
+- "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 83})",
++ "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U8X25PCIHSBP', 'ADDRESS': 87})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "$BOARD_MANUFACTURER",
+@@ -166,6 +170,7 @@
+ "Drive_19",
+ "Drive_20"
+ ],
++ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 5",
+ "Type": "PCA9546Mux"
+ },
+@@ -178,6 +183,7 @@
+ "Drive_23",
+ "Drive_24"
+ ],
++ "MuxIdleMode": "Disconnect",
+ "Name": "Drive Mux 6",
+ "Type": "PCA9546Mux"
+ },
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0007-Add-HSBP-FRU-details-in-json-configuration.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0007-Add-HSBP-FRU-details-in-json-configuration.patch
new file mode 100644
index 000000000..9ad2641bc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0007-Add-HSBP-FRU-details-in-json-configuration.patch
@@ -0,0 +1,78 @@
+From ff4b6cab1dead31bad114321c211797ac28b36b1 Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Wed, 10 Nov 2021 15:17:13 +0000
+Subject: [PATCH] Add HSBP FRU details in json configuration
+
+Added Intel specific HSBP CPLD FRU details in json configuration file.
+
+Tested:
+1. Detected and read the HSBP FRU with new address on reworked board.
+2. busctl tree xyz.openbmc_project.HsbpManager
+└─/xyz
+ └─/xyz/openbmc_project
+ ├─/xyz/openbmc_project/inventory
+ │ └─/xyz/openbmc_project/inventory/item
+ │ ├─/xyz/openbmc_project/inventory/item/drive
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_1
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_10
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_11
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_12
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_13
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_14
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_15
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_16
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_2
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_3
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_4
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_5
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_6
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_7
+ │ │ ├─/xyz/openbmc_project/inventory/item/drive/Drive_8
+ │ │ └─/xyz/openbmc_project/inventory/item/drive/Drive_9
+ │ └─/xyz/openbmc_project/inventory/item/hsbp
+ │ ├─/xyz/openbmc_project/inventory/item/hsbp/HSBP_1
+ │ └─/xyz/openbmc_project/inventory/item/hsbp/HSBP_2
+ └─/xyz/openbmc_project/software
+ ├─/xyz/openbmc_project/software/HSBP_1
+ └─/xyz/openbmc_project/software/HSBP_2
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ configurations/F2U8X25 HSBP.json | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/configurations/F2U8X25 HSBP.json b/configurations/F2U8X25 HSBP.json
+index 60e7817..cdf9076 100644
+--- a/configurations/F2U8X25 HSBP.json
++++ b/configurations/F2U8X25 HSBP.json
+@@ -7,6 +7,13 @@
+ "Name": "F2U8X25 HSBP1 FRU",
+ "Type": "EEPROM"
+ },
++ {
++ "Address": "0x68",
++ "Bus": "$bus",
++ "Index": 1,
++ "Name": "HSBP 1",
++ "Type": "Intel HSBP CPLD"
++ },
+ {
+ "Address": "0x70",
+ "Bus": "$bus",
+@@ -84,6 +91,13 @@
+ "Name": "F2U8X25 HSBP2 FRU",
+ "Type": "EEPROM"
+ },
++ {
++ "Address": "0x69",
++ "Bus": "$bus",
++ "Index": 2,
++ "Name": "HSBP 2",
++ "Type": "Intel HSBP CPLD"
++ },
+ {
+ "Address": "0x73",
+ "Bus": "$bus",
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend
new file mode 100644
index 000000000..ba51f9454
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend
@@ -0,0 +1,14 @@
+# this is here just to bump faster than upstream
+# SRC_URI = "git://github.com/openbmc/entity-manager.git"
+SRCREV = "2c412eef8eb76bf2a998c9d193f2dc92aaec39f8"
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " file://0002-Entity-manager-Add-support-to-update-assetTag.patch \
+ file://0003-Add-logs-to-fwVersionIsSame.patch \
+ file://0004-Adding-MUX-and-Drives-present-in-HSBP-in-json-config.patch \
+ file://0005-Allow-MUX-idle-state-to-be-configured-as-DISCONNECT.patch \
+ file://0006-Change-HSBP-FRU-address-and-add-MUX-mode-configurati.patch \
+ file://0007-Add-HSBP-FRU-details-in-json-configuration.patch \
+ "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf
new file mode 100644
index 000000000..1d332e2a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf
@@ -0,0 +1,3 @@
+baud = 921600
+local-tty = ttyS3
+local-tty-baud = 921600
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service
new file mode 100644
index 000000000..4ec453d9e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Phosphor Console Muxer listening on device /dev/%I
+BindsTo=dev-%i.device
+After=dev-%i.device
+
+[Service]
+ExecStartPre=/usr/bin/sol-option-check.sh
+ExecStart=/usr/bin/env obmc-console-server --config {sysconfdir}/obmc-console.conf %i
+ExecStopPost=/bin/sh -c 'echo -n "0" > /sys/bus/platform/drivers/aspeed-uart-routing/1e789098.uart-routing/hicra'
+SyslogIdentifier=obmc-console-server
+Restart=always
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh
new file mode 100755
index 000000000..19179c497
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Copyright 2017-2020 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+CPUPART="CPU part"
+AST2500_ID="0xb76"
+AST2600_ID="0xc07"
+
+if ([ $(grep "$CPUPART" /proc/cpuinfo | grep "$AST2500_ID" | wc -l) != 0 ] && \
+ [ $(grep 192000000 /sys/class/tty/ttyS0/uartclk | wc -l) != 0 ]) || \
+ ([ $(grep "$CPUPART" /proc/cpuinfo | grep "$AST2600_ID" | wc -l) != 0 ] && \
+ [ $(grep 14769216 /sys/class/tty/ttyS0/uartclk | wc -l) != 0 ]); then
+ echo "hs-uart"
+ sed -i -e 's/115200/921600/g' /etc/obmc-console.conf
+else
+ echo "normal uart"
+ sed -i -e 's/921600/115200/g' /etc/obmc-console.conf
+fi
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend
new file mode 100644
index 000000000..9a0eae176
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend
@@ -0,0 +1,17 @@
+FILESEXTRAPATHS:append := ":${THISDIR}/${PN}"
+OBMC_CONSOLE_HOST_TTY = "ttyS2"
+SRC_URI += "file://sol-option-check.sh \
+ file://obmc-console@.service \
+ "
+inherit obmc-phosphor-systemd
+
+SYSTEMD_SERVICE:${PN} += " \
+ ${PN}@${OBMC_CONSOLE_HOST_TTY}.service \
+ "
+
+do_install:append() {
+ rm -rf ${D}${base_libdir}/udev/rules.d/80-obmc-console-uart.rules
+ install -m 0644 ${WORKDIR}/${PN}@.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/sol-option-check.sh ${D}${bindir}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb
new file mode 100644
index 000000000..83630fc36
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb
@@ -0,0 +1,24 @@
+
+SUMMARY = "PCH BMC time service"
+DESCRIPTION = "This service will read date/time from PCH device periodically, and set the BMC system time accordingly"
+
+SRC_URI = "\
+ file://CMakeLists.txt;subdir=${BP} \
+ file://pch-time-sync.cpp;subdir=${BP} \
+ "
+PV = "0.1"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE:${PN} = "pch-time-sync.service"
+
+inherit cmake
+inherit obmc-phosphor-systemd
+
+DEPENDS += " \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format
@@ -0,0 +1,98 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt
new file mode 100644
index 000000000..a4cf8155f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (pch-time-sync CXX)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+# boost support
+find_package (Boost REQUIRED)
+# pkg_check_modules(Boost boost REQUIRED)
+include_directories (${Boost_INCLUDE_DIRS})
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+# import sdbusplus
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED)
+include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS})
+link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS})
+
+# import phosphor-logging
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+include_directories (${LOGGING_INCLUDE_DIRS})
+link_directories (${LOGGING_LIBRARY_DIRS})
+
+add_executable (pch-time-sync pch-time-sync.cpp)
+
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}
+ phosphor_logging)
+target_link_libraries (${PROJECT_NAME} i2c)
+
+install (TARGETS pch-time-sync DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json
@@ -0,0 +1,12 @@
+{
+ "enum_char": ".",
+ "line_ending": "unix",
+ "bullet_char": "*",
+ "max_subargs_per_line": 99,
+ "command_case": "lower",
+ "tab_size": 4,
+ "line_width": 80,
+ "separate_fn_name_with_space": true,
+ "dangle_parens": true,
+ "separate_ctrl_name_with_space": true
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp
new file mode 100644
index 000000000..454bdc1db
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp
@@ -0,0 +1,431 @@
+/* Copyright 2019 Intel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <systemd/sd-journal.h>
+#include <time.h>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <chrono>
+#include <filesystem>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+extern "C" {
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+}
+
+static constexpr uint32_t syncIntervalNormalMS = 60000;
+static constexpr uint32_t syncIntervalFastMS = (syncIntervalNormalMS / 2);
+static constexpr uint32_t syncIntervalBootMS = 5000;
+
+static uint32_t syncIntervalMS = syncIntervalNormalMS;
+
+// will update bmc time if the time difference beyond this value
+static constexpr uint8_t timeDiffAllowedSecond = 1;
+static uint8_t pchDevI2cBusNo = 0;
+static uint8_t pchDevI2cSlaveAddr = 0;
+static bool getPCHI2cAddrFlag = false;
+static constexpr const char* clockFile = "/var/lib/systemd/timesync/clock";
+static inline uint8_t bcd2Decimal(uint8_t hex)
+{
+ uint8_t dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
+ return dec;
+}
+
+class I2CFile
+{
+ private:
+ int fd = -1;
+
+ public:
+ I2CFile(const int& i2cBus, const int& slaveAddr, const int& flags)
+ {
+ std::string i2cDev = "/dev/i2c-" + std::to_string(i2cBus);
+
+ fd = open(i2cDev.c_str(), flags);
+ if (fd < 0)
+ {
+ throw std::runtime_error("Unable to open i2c device.");
+ }
+
+ if (ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
+ {
+ close(fd);
+ fd = -1;
+ throw std::runtime_error("Unable to set i2c slave address.");
+ }
+ }
+
+ uint8_t i2cReadByteData(const uint8_t& offset)
+ {
+ int ret = i2c_smbus_read_byte_data(fd, offset);
+
+ if (ret < 0)
+ {
+ throw std::runtime_error("i2c read failed");
+ }
+ return static_cast<uint8_t>(ret);
+ }
+
+ ~I2CFile()
+ {
+ if (!(fd < 0))
+ {
+ close(fd);
+ }
+ }
+};
+
+static void getPCHI2cAddr(std::shared_ptr<sdbusplus::asio::connection>& conn,
+ const std::string& service, const std::string& object,
+ const std::string& interface)
+{
+ conn->async_method_call(
+ [](boost::system::error_code ec,
+ const std::vector<
+ std::pair<std::string, std::variant<std::string, uint64_t>>>&
+ propertiesList) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "DBUS response error: cannot get I2c address of PCH timer",
+ phosphor::logging::entry("ECVALUE=%x", ec.value()),
+ phosphor::logging::entry("ECMESSAGE=%s",
+ ec.message().c_str()));
+ return;
+ }
+ const uint64_t* i2cBusNoValue = nullptr;
+ const uint64_t* i2cSlaveAddrValue = nullptr;
+ for (const auto& property : propertiesList)
+ {
+
+ if (property.first == "PchSmbusSlaveI2cBus")
+ {
+ i2cBusNoValue = std::get_if<uint64_t>(&property.second);
+ }
+ if (property.first == "PchSmbusSlaveI2cAddress")
+ {
+ i2cSlaveAddrValue = std::get_if<uint64_t>(&property.second);
+ }
+ }
+ if ((i2cBusNoValue != nullptr) && (i2cSlaveAddrValue != nullptr))
+ {
+ pchDevI2cBusNo = static_cast<uint8_t>(*i2cBusNoValue);
+ pchDevI2cSlaveAddr = static_cast<uint8_t>(*i2cSlaveAddrValue);
+ getPCHI2cAddrFlag = true;
+ }
+ },
+ service, object, "org.freedesktop.DBus.Properties", "GetAll",
+ interface);
+}
+
+static void
+ getPCHTimerConfiguration(std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ conn->async_method_call(
+ [&conn](
+ boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>>&
+ subtree) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "DBUS response error:cannot get PCH configuration",
+ phosphor::logging::entry("ECVALUE=%x", ec.value()),
+ phosphor::logging::entry("ECMESSAGE=%s",
+ ec.message().c_str()));
+ return;
+ }
+ if (subtree.empty())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "subtree empty");
+ return;
+ }
+ getPCHI2cAddr(conn, subtree[0].second[0].first, subtree[0].first,
+ "xyz.openbmc_project.Configuration.PchSmbusSlave");
+ return;
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/", 0,
+ std::array<const char*, 1>{
+ "xyz.openbmc_project.Configuration.PchSmbusSlave"});
+
+ return;
+}
+
+class PCHSync
+{
+ private:
+ bool getPCHDate(uint8_t& year, uint8_t& month, uint8_t& day, uint8_t& hour,
+ uint8_t& minute, uint8_t& second)
+ {
+ try
+ {
+ constexpr uint8_t pchDevRegRTCYear = 0x0f;
+ constexpr uint8_t pchDevRegRTCMonth = 0x0e;
+ constexpr uint8_t pchDevRegRTCDay = 0x0d;
+ constexpr uint8_t pchDevRegRTCHour = 0x0b;
+ constexpr uint8_t pchDevRegRTCMinute = 0x0a;
+ constexpr uint8_t pchDevRegRTCSecond = 0x09;
+ I2CFile pchDev(pchDevI2cBusNo, pchDevI2cSlaveAddr,
+ O_RDWR | O_CLOEXEC);
+ year = pchDev.i2cReadByteData(pchDevRegRTCYear);
+ year = bcd2Decimal(year);
+ if (year > 99)
+ {
+ return false;
+ }
+
+ month = pchDev.i2cReadByteData(pchDevRegRTCMonth);
+ month = bcd2Decimal(month);
+ if ((month < 1) || (month > 12))
+ {
+ return false;
+ }
+
+ day = pchDev.i2cReadByteData(pchDevRegRTCDay);
+ day = bcd2Decimal(day);
+ if ((day < 1) || (day > 31))
+ {
+ return false;
+ }
+
+ hour = pchDev.i2cReadByteData(pchDevRegRTCHour);
+ hour = bcd2Decimal(hour);
+ if (hour >= 24)
+ {
+ return false;
+ }
+
+ minute = pchDev.i2cReadByteData(pchDevRegRTCMinute);
+ minute = bcd2Decimal(minute);
+ if (minute >= 60)
+ {
+ return false;
+ }
+
+ second = pchDev.i2cReadByteData(pchDevRegRTCSecond);
+ second = bcd2Decimal(second);
+ if (second >= 60)
+ {
+ return false;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool getSystemTime(time_t& timeSeconds)
+ {
+ struct timespec sTime = {0};
+ int ret = 0;
+
+ ret = clock_gettime(CLOCK_REALTIME, &sTime);
+
+ if (ret != 0)
+ {
+ return false;
+ }
+ timeSeconds = sTime.tv_sec;
+ return true;
+ }
+
+ bool updateClockFileTimestamp()
+ {
+ if (!std::filesystem::exists(clockFile))
+ {
+ phosphor::logging::log<phosphor::logging::level::WARNING>(
+ "The systemd timestamp synchronization file doesn't exist: ",
+ phosphor::logging::entry("PATHNAME=%s", clockFile));
+ return false;
+ }
+ int rc = utimensat(AT_FDCWD, clockFile, nullptr, 0);
+ if (rc)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "utimensat systemd timestamp synchronization file fail: ",
+ phosphor::logging::entry("PATHNAME=%s", clockFile),
+ phosphor::logging::entry("ERRCODE=%x", errno));
+ return false;
+ }
+ return true;
+ }
+ bool setSystemTime(uint32_t timeSeconds)
+ {
+ struct timespec sTime = {0};
+ int ret = 0;
+
+ sTime.tv_sec = timeSeconds;
+ sTime.tv_nsec = 0;
+
+ ret = clock_settime(CLOCK_REALTIME, &sTime);
+
+ return (ret == 0);
+ }
+
+ bool updateBMCTime()
+ {
+ int ret = 0;
+ time_t BMCTimeSeconds = 0;
+ time_t PCHTimeSeconds = 0;
+ struct tm tm = {0};
+
+ // get PCH and system time
+
+ if (!getPCHDate(year, month, day, hour, minute, second))
+ {
+ return false;
+ };
+ if (!getSystemTime(BMCTimeSeconds))
+ {
+ return false;
+ }
+ // fix error when year is set to 2000-2009.
+ std::string dateString =
+ std::to_string(2000 + year) + "-" + std::to_string(month) + "-" +
+ std::to_string(day) + " " + std::to_string(hour) + ":" +
+ std::to_string(minute) + ":" + std::to_string(second);
+
+ strptime(dateString.c_str(), "%Y-%m-%d %H:%M:%S", &tm);
+
+ PCHTimeSeconds = mktime(&tm);
+ if (PCHTimeSeconds == -1)
+ {
+ return false;
+ }
+
+ if (std::abs(PCHTimeSeconds - BMCTimeSeconds) > timeDiffAllowedSecond)
+ {
+ if (!setSystemTime(PCHTimeSeconds))
+ {
+ return false;
+ }
+ char newDateString[32] = {0};
+ strftime(newDateString, sizeof(newDateString), "%F %T",
+ gmtime(&PCHTimeSeconds));
+
+ struct tm* timeinfo;
+ char oldDateString[32] = {0};
+ timeinfo = gmtime(&BMCTimeSeconds);
+ strftime(oldDateString, sizeof(oldDateString), "%F %T", timeinfo);
+
+ // Log event about BMC time update via PCH
+ sd_journal_send(
+ "MESSAGE=BMC time updated via PCH: New time=%s, Old time=%s",
+ newDateString, oldDateString, "PRIORITY=%i", LOG_INFO,
+ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.BMCTimeUpdatedViaHost",
+ "REDFISH_MESSAGE_ARGS=%s,%s", newDateString, oldDateString,
+ NULL);
+ }
+
+ // During the boot time, systemd-timesyncd.service checks
+ // "/var/lib/systemd/timesync/clock" and updates the system time with
+ // the timestamp of the file
+ if (!updateClockFileTimestamp())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void startSyncTimer(std::shared_ptr<sdbusplus::asio::connection>& conn)
+ {
+ // retry 10 times (10 * 5s = 50s ) to get the pch timer
+ // configuration.
+ static uint8_t retrytimes = 10;
+ if (!getPCHI2cAddrFlag)
+ {
+ if (retrytimes == 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Get pch timer configuration fail");
+ return;
+ }
+ syncIntervalMS = syncIntervalBootMS;
+ getPCHTimerConfiguration(conn);
+ retrytimes--;
+ }
+ else
+ {
+ if (updateBMCTime())
+ {
+ syncIntervalMS = syncIntervalNormalMS;
+ }
+ else
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Update BMC time Fail");
+ syncIntervalMS = syncIntervalFastMS;
+ }
+ }
+
+ syncTimer->expires_after(std::chrono::milliseconds(syncIntervalMS));
+ syncTimer->async_wait(
+ [this, &conn](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Timer cancelled",
+ phosphor::logging::entry("ECVALUE=%x", ec.value()),
+ phosphor::logging::entry("ECMESSAGE=%s",
+ ec.message().c_str()));
+ return;
+ }
+ startSyncTimer(conn);
+ });
+ }
+
+ std::unique_ptr<boost::asio::steady_timer> syncTimer;
+ uint8_t year, month, day, hour, minute, second;
+
+ public:
+ PCHSync(boost::asio::io_service& io,
+ std::shared_ptr<sdbusplus::asio::connection>& conn)
+ {
+ syncTimer = std::make_unique<boost::asio::steady_timer>(io);
+ startSyncTimer(conn);
+ }
+
+ ~PCHSync() = default;
+};
+
+int main(int argc, char** argv)
+{
+ boost::asio::io_service io;
+ std::shared_ptr<sdbusplus::asio::connection> conn =
+ std::make_shared<sdbusplus::asio::connection>(io);
+ sdbusplus::asio::object_server server =
+ sdbusplus::asio::object_server(conn);
+ PCHSync pchSyncer(io, conn);
+
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Starting PCH time sync service");
+
+ io.run();
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service
new file mode 100644
index 000000000..bf4e2a30e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=PCH BMC time sync service
+Conflicts=systemd-timesyncd.service
+Requires=xyz.openbmc_project.EntityManager.service
+After=xyz.openbmc_project.EntityManager.service
+
+[Service]
+Restart=always
+RestartSec=10
+ExecStart=/usr/bin/pch-time-sync
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend
new file mode 100644
index 000000000..4d6031b03
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend
@@ -0,0 +1,2 @@
+RDEPENDS:${PN}:remove = "phosphor-settings-manager"
+RDEPENDS:${PN} += " settings"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch
new file mode 100644
index 000000000..3d2cc43e2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch
@@ -0,0 +1,47 @@
+From 153b125043c28f933579330727d82658979caef3 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Mon, 18 May 2020 20:16:04 +0530
+Subject: [PATCH] Apply Options interface for Software
+
+Apply Options interface is used to pass the settings related to
+firmware image activation such as ClearConfig.
+ClearConfig property is used to denote whether to clear firmware
+configurations along with firmware image activation or not.
+
+Example case:
+BIOS usually requires its NVRAM configuration to be updated or
+erased for certain BIOS firmware updates. Current implementation
+doesn't support to take this option and provide interface to do
+the necessary actions.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ .../Software/ApplyOptions.interface.yaml | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+ create mode 100644 xyz/openbmc_project/Software/ApplyOptions.interface.yaml
+
+diff --git a/xyz/openbmc_project/Software/ApplyOptions.interface.yaml b/xyz/openbmc_project/Software/ApplyOptions.interface.yaml
+new file mode 100644
+index 0000000..45a68ab
+--- /dev/null
++++ b/xyz/openbmc_project/Software/ApplyOptions.interface.yaml
+@@ -0,0 +1,16 @@
++description: >
++ To implement the Activation apply options for a newly uploaded firmware
++ image. The apply options property is global and is specifically used with
++ each firmware update and is used during firmware activation.
++ ApplyOptions usage during firmware activation is implementation specific,
++ not all firmware targets need ApplyOptions.
++ The default value of this property is false.
++properties:
++ - name: ClearConfig
++ type: boolean
++ default: false
++ description: >
++ This property indicates whether to clear the software configurations
++ when the firmware image update is getting applied. A value of true
++ indicates the firmware configurations should be cleared along with
++ firmware image activation.
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch
new file mode 100644
index 000000000..2c443726d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch
@@ -0,0 +1,32 @@
+From bc282f4e9537b115e32733dfc6e16c303f81b3e3 Mon Sep 17 00:00:00 2001
+From: "Jia, Chunhui" <chunhui.jia@intel.com>
+Date: Tue, 24 Jul 2018 11:40:49 +0800
+Subject: [PATCH] set BIOS id
+
+change#2
+add new dbus interface for BIOS attributes
+
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+---
+ .../openbmc_project/Inventory/Item/Bios.interface.yaml | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+ create mode 100644 yaml/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml
+
+diff --git a/yaml/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml b/yaml/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml
+new file mode 100644
+index 000000000000..d7a6b95bfdce
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml
+@@ -0,0 +1,9 @@
++description: >
++ Implement to provide BIOS attributes.
++properties:
++ - name: BiosId
++ type: string
++ description: >
++ BIOS ID (version) string
++
++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch
new file mode 100644
index 000000000..7f315db86
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch
@@ -0,0 +1,34 @@
+From 479b46d2ed42b576cf2aee2ecbd76de7940d0cfe Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Fri, 10 Aug 2018 16:23:13 +0800
+Subject: [PATCH] Increase the default watchdog timeout value
+
+The default timeout for poweron is 30 seconds,
+but currently the host power on needs 120+ seconds
+due to unimplemented ipmi commands for BIOS.
+
+Increase the value as a workaround,
+to avoid the watchdog timeout during power on.
+Will adjust this value in the future
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ yaml/xyz/openbmc_project/State/Watchdog.interface.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml b/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
+index f54ec3b6e4fb..ede961da1942 100644
+--- a/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
++++ b/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
+@@ -37,7 +37,7 @@ properties:
+ type: uint64
+ description: >
+ Time interval to arm the watchdog, in milli-second.
+- default: 30000
++ default: 600000
+ - name: TimeRemaining
+ type: uint64
+ description: >
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch
new file mode 100644
index 000000000..aae1e0248
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch
@@ -0,0 +1,34 @@
+From 6e8b18e2258c7b6327a9b26901846088dd82a663 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 24 Aug 2018 17:55:35 +0800
+Subject: [PATCH] Add RestoreDelay interface for power restore delay
+
+Which provide one property "PowerRestoreDelay"
+
+Change-Id: I4e6d3e45948b1e288301b4aa52cc08cace4f1bc2
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ .../Control/Power/RestoreDelay.interface.yaml | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+ create mode 100644 yaml/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml
+
+diff --git a/yaml/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml b/yaml/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml
+new file mode 100644
+index 000000000000..55ee80a75f7b
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml
+@@ -0,0 +1,11 @@
++description: >
++ Implement to specify power transition behavior on a BMC reset.
++ The implementation based on restore policy and set a delay time
++ for power restore.
++
++properties:
++ - name: PowerRestoreDelay
++ type: uint16
++ description: >
++ The delay time for power restore.
++ Power Restore Delay is NOT applied on power policy is "Always Off"
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch
new file mode 100644
index 000000000..17aef45bf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch
@@ -0,0 +1,86 @@
+From 571ab872be4b486b98bfbed159630b5e21d9a586 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Thu, 30 Aug 2018 16:22:43 +0800
+Subject: [PATCH] Add ErrConfig.yaml interface for processor error
+ configuration.
+
+Which provide 3 properties:
+ ResetCfg
+ type: byte
+ description: >
+ Reset Configuration
+ [0]: CATERR Reset Enabled
+ 0b: Disabled
+ 1b: Enabled
+ [1]: ERR2 Reset Enabled
+ 0b: Disabled
+ 1b: Enabled
+ [7:2]: Reserved
+ ResetErrorOccurrenceCounts
+ type: byte
+ description: >
+ Reset Error Occurrence Counts
+ [0]: Reset CPU Error Counts
+ 0b: Keep CPU Error Counts
+ 1b: Reset all CPU Error Counts to zero
+ [7:1]: Reserved
+ CATERRStatus
+ type: array[byte]
+ description: >
+ For all CPUs including the non-legacy socket CPU
+ CPU CATERR (Core Error) occurrence
+ [5:0]: Error Occurrence Count
+ [7:6]: CPU Status
+ 00b: Disabled
+ 01b: Enabled
+ 11b: Not Present
+
+Change-Id: Ibc5a7a5e15c998e56c04e23b1043d99243a91171
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ .../Processor/ErrConfig.interface.yaml | 33 +++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+ create mode 100644 yaml/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml
+
+diff --git a/yaml/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml b/yaml/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml
+new file mode 100644
+index 000000000000..23042633ca13
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml
+@@ -0,0 +1,33 @@
++description: >
++ This defines processor error configuration.
++properties:
++ - name: ResetCfg
++ type: byte
++ description: >
++ Reset Configuration
++ [0]: CATERR Reset Enabled
++ 0b: Disabled
++ 1b: Enabled
++ [1]: ERR2 Reset Enabled
++ 0b: Disabled
++ 1b: Enabled
++ [7:2]: Reserved
++
++ - name: ResetErrorOccurrenceCounts
++ type: byte
++ description: >
++ Reset Error Occurrence Counts
++ [0]: Reset CPU Error Counts
++ 0b: Keep CPU Error Counts
++ 1b: Reset all CPU Error Counts to zero
++ [7:1]: Reserved
++ - name: CATERRStatus
++ type: array[byte]
++ description: >
++ For all CPUs including the non-legacy socket CPU
++ CPU CATERR (Core Error) occurrence
++ [5:0]: Error Occurrence Count
++ [7:6]: CPU Status
++ 00b: Disabled
++ 01b: Enabled
++ 11b: Not Present
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch
new file mode 100644
index 000000000..06eed126f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch
@@ -0,0 +1,57 @@
+From 45f4457c23a8da9d246bd33c3d426b52186b39f0 Mon Sep 17 00:00:00 2001
+From: Ren Yu <yux.ren@intel.com>
+Date: Fri, 24 May 2019 14:55:10 +0800
+Subject: [PATCH] Add the pre-timeout interrupt defined in IPMI spec
+
+The IPMI watchdog pre-timeout interrupt is used to set the different
+pre-timeout interrupt source. Add them as a dbus property,
+IPMI set/get watchdog commands will use it.
+
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+---
+ .../State/Watchdog.interface.yaml | 22 +++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml b/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
+index ede961da1942..a67a6a30ea2c 100644
+--- a/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
++++ b/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
+@@ -33,6 +33,11 @@ properties:
+ description: >
+ The action the watchdog should perform when it expires.
+ default: 'HardReset'
++ - name: PreTimeoutInterrupt
++ type: enum[self.PreTimeoutInterruptAction]
++ description: >
++ The BMC generates the selected interrupt before the timer expires.
++ default: 'None'
+ - name: Interval
+ type: uint64
+ description: >
+@@ -73,6 +78,23 @@ enumerations:
+ description: >
+ Perform a power cycle of the system.
+
++ - name: PreTimeoutInterruptAction
++ description: >
++ The type of PreTimeout Interrupt.
++ values:
++ - name: 'None'
++ description: >
++ Do nothing.
++ - name: 'SMI'
++ description: >
++ SMI.
++ - name: 'NMI'
++ description: >
++ NMI / Diagnostic Interrupt.
++ - name: 'MI'
++ description: >
++ Messaging Interrupt.
++
+ - name: TimerUse
+ description: >
+ The type of timer use.
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch
new file mode 100644
index 000000000..54920fee3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch
@@ -0,0 +1,39 @@
+From c71c17951e5f00195c9cacd6829a359c3d253714 Mon Sep 17 00:00:00 2001
+From: Ren Yu <yux.ren@intel.com>
+Date: Mon, 29 Jul 2019 10:51:12 +0800
+Subject: [PATCH] Add PreInterruptFlag properity in DBUS.
+
+PreTimeoutInterruptOccurFlag in DBUS would be set 'true'
+when watchdog pre-timeout interrupt occurred.
+
+Tested:
+Enable command(raw 0x06 0x31) that get message flag
+can set right bit about watchdog,
+need record PreTimeoutInterruptOccurFlag
+at xyz.openbmmc_project.State.Watchdog when watchdog
+pre-timeout interrupt occurred.
+
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+---
+ yaml/xyz/openbmc_project/State/Watchdog.interface.yaml | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml b/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
+index a67a6a30ea2c..d1ae8e3411e6 100644
+--- a/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
++++ b/yaml/xyz/openbmc_project/State/Watchdog.interface.yaml
+@@ -59,6 +59,11 @@ properties:
+ description: >
+ The timer user at the time of expiration.
+ default: 'Reserved'
++ - name: PreTimeoutInterruptOccurFlag
++ type: boolean
++ description: >
++ PreTimeoutInterruptOccurFlag that preTimeoutInterrupt action occurred.
++ default: false
+
+ enumerations:
+ - name: Action
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch
new file mode 100644
index 000000000..25ed9a403
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch
@@ -0,0 +1,55 @@
+From 826946ecad67b34818db0634367c4cf7100d0890 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Wed, 15 Jan 2020 10:01:04 +0800
+Subject: [PATCH] Add StandbySpare support for software inventory
+
+Add support to allow update for active / recovery
+regions of specified firmware. This update enables
+the backend modules to advertise whether the
+software object is active or recovery (StandbySpare)
+image.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ .../Software/Activation.interface.yaml | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/yaml/xyz/openbmc_project/Software/Activation.interface.yaml b/yaml/xyz/openbmc_project/Software/Activation.interface.yaml
+index 6af2984b7b2e..26ab87b0262d 100644
+--- a/yaml/xyz/openbmc_project/Software/Activation.interface.yaml
++++ b/yaml/xyz/openbmc_project/Software/Activation.interface.yaml
+@@ -28,12 +28,20 @@ enumerations:
+ - name: Activating
+ description: >
+ The Software.Version is in the process of being Activated.
++ - name: ActivatingAsStandbySpare
++ description: >
++ The Software.Version is in the process of being processed
++ as StandbySpare.
+ - name: Active
+ description: >
+ The Software.Version is currently Active.
+ - name: Failed
+ description: >
+ The Software.Version failed during or after Activation.
++ - name: StandbySpare
++ description: >
++ The Software.Version is part of a redundancy set and awaits
++ a failover or external action to activate.
+ - name: Staged
+ description: >
+ The Software.Version is currently in staged flash area.
+@@ -52,6 +60,10 @@ enumerations:
+ - name: Active
+ description: >
+ The Software.Version has been requested for Activation.
++ - name: StandbySpare
++ description: >
++ The Software.Version has been requested to be enabled as
++ StandbySpare.
+ # TODO: Specify "EAGAIN" type error when requested is unable to be acted on
+ # due to current system state. Currently, sdbusplus does not support
+ # errors on properties.
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch
new file mode 100644
index 000000000..677b699be
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch
@@ -0,0 +1,401 @@
+From 2c270f8fd9f45ff0792d2730c25eb2f673314115 Mon Sep 17 00:00:00 2001
+From: "Kowalski, Mariusz" <mariusz.kowalski@intel.com>
+Date: Thu, 27 Feb 2020 15:48:56 +0100
+Subject: [PATCH] MCTP Daemon D-Bus interface definition.
+
+This interface definition was created on base of the MCTP design
+proposed in this document:
+https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/28424/9/designs/mctp.md
+
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+Signed-off-by: Mariusz Kowalski <mariusz.kowalski@intel.com>
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+Change-Id: Ida66f8ffcf00003655edcb0fb0112202797b8e1a
+---
+ .../openbmc_project/MCTP/Base.interface.yaml | 227 ++++++++++++++++++
+ .../MCTP/Binding/PCIe.interface.yaml | 29 +++
+ .../MCTP/Binding/SMBus.interface.yaml | 17 ++
+ .../MCTP/BusOwner.interface.yaml | 17 ++
+ .../MCTP/Endpoint.interface.yaml | 4 +
+ .../MCTP/SupportedMessageTypes.interface.yaml | 36 +++
+ 6 files changed, 330 insertions(+)
+ create mode 100644 yaml/xyz/openbmc_project/MCTP/Base.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/MCTP/BusOwner.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml
+
+diff --git a/yaml/xyz/openbmc_project/MCTP/Base.interface.yaml b/yaml/xyz/openbmc_project/MCTP/Base.interface.yaml
+new file mode 100644
+index 000000000000..9438551e648e
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/MCTP/Base.interface.yaml
+@@ -0,0 +1,227 @@
++description: >
++ Mandatory interface for each instance of the MCTP Daemon to expose
++ the base MCTP daemon and medium type interfaces.
++
++methods:
++ - name: SendMctpMessagePayload
++ description: >
++ Sends message over MCTP interface
++ parameters:
++ - name: DestinationEID
++ type: byte
++ description: >
++ Destination Endpoint ID. The logical address used to route MCTP
++ messages to a specific MCTP endpoint.
++ - name: MsgTag
++ type: byte
++ description: >
++ Message tag. Field that, along with the Source Endpoint IDs and the
++ Tag Owner (TO) field, identifies a unique message at the MCTP
++ transport level.
++ - name: TagOwner
++ type: boolean
++ description: >
++ Tag Owner bit identifies whether the message tag was originated by
++ the endpoint that is the source of the message or by the endpoint
++ that is the destination of the message.
++ - name: Payload
++ type: array[byte]
++ description: Payload of message.
++ returns:
++ - name: Status
++ type: byte
++ description: 0 - if success
++ errors:
++ - xyz.openbmc_project.Common.Error.Timeout
++ - xyz.openbmc_project.Common.Error.InvalidArgument
++ - xyz.openbmc_project.Common.Error.InternalFailure
++
++ - name: SendMctpMessageFileDescriptor
++ description: >
++ Sends message over MCTP interface
++ parameters:
++ - name: DestinationEID
++ type: byte
++ description: >
++ Destination Endpoint ID. The logical address used to route MCTP
++ messages to a specific MCTP endpoint.
++ - name: MsgTag
++ type: byte
++ description: >
++ Message tag. Field that, along with the Source Endpoint IDs and the
++ Tag Owner (TO) field, identifies a unique message at the MCTP
++ transport level.
++ - name: TagOwner
++ type: boolean
++ description: >
++ Tag Owner bit identifies whether the message tag was originated by
++ the endpoint that is the source of the message or by the endpoint
++ that is the destination of the message.
++ - name: FileDescriptor
++ type: unixfd
++ description: File descriptor of message.
++ returns:
++ - name: Status
++ type: byte
++ description: 0 - if success
++ errors:
++ - xyz.openbmc_project.Common.Error.Timeout
++ - xyz.openbmc_project.Common.Error.InvalidArgument
++ - xyz.openbmc_project.Common.Error.InternalFailure
++
++signals:
++ - name: MessageReceivedSignal
++ description: >
++ Signal indicating upper layers about arrival of a MCTP message.
++ properties:
++ - name: MessageType
++ type: enum[self.MessageTypes]
++ description: >
++ Defines the values for the Message Type field for different message
++ types transported through MCTP.
++ - name: SrcEid
++ type: byte
++ description: >
++ Source Endpoint ID. The logical address used to route MCTP messages
++ to a specific MCTP endpoint.
++ - name: MsgTag
++ type: byte
++ description: >
++ Message tag. Field that, along with the Source Endpoint IDs and the
++ Tag Owner (TO) field, identifies a unique message at the MCTP
++ transport level.
++ - name: TagOwner
++ type: boolean
++ description: >
++ Tag Owner bit identifies whether the message tag was originated by
++ the endpoint that is the source of the message or by the endpoint
++ that is the destination of the message.
++ - name: Payload
++ type: array[byte]
++ description: Payload of message.
++
++properties:
++ - name: Eid
++ type: byte
++ description: >
++ Endpoint ID. The logical address used to route MCTP messages to a
++ specific MCTP endpoint.
++
++ - name: BindingID
++ type: enum[self.BindingTypes]
++
++ - name: BindingMediumID
++ type: enum[self.MctpPhysicalMediumIdentifiers]
++
++ - name: StaticEid
++ type: boolean
++ description: Support for statically/dynamicly allocated IDs
++
++ - name: BindingMode
++ type: enum[self.BindingModeTypes]
++ description: Bus Owner / Endpoint / Bridge
++
++enumerations:
++ - name: BindingTypes
++ description: >
++ All other values than described are reserved.
++ values:
++ - name: MctpOverSmbus
++ - name: MctpOverPcieVdm
++ - name: MctpOverUsb
++ description: Reserved for MCTP over USB
++ - name: MctpOverKcs
++ - name: MctpOverSerial
++ - name: VendorDefined
++
++ - name: MctpPhysicalMediumIdentifiers
++ description: >
++ Identifies MCTP physical medium identifiers. see DSP0239.
++ values:
++ - name: Smbus
++ descritpion: SMBus 2.0 100 kHz compatible
++ - name: SmbusI2c
++ descritpion: SMBus 2.0 + I2C 100 kHz compatible
++ - name: I2cCompatible
++ description: I2C 100 kHz compatible (Standard-mode)
++ - name: Smbus3OrI2c400khzCompatible
++ description: SMBus 3.0 or I2C 400 kHz compatible (Fast-mode)
++ - name: Smbus3OrI2c1MhzCompatible
++ description: SMBus 3.0 or I2C 1 MHz compatible (Fast-mode Plus)
++ - name: I2c3Mhz4Compatible
++ description: I2C 3.4 MHz compatible (High-speed mode)
++ - name: Pcie11
++ description: PCIe revision 1.1 compatible
++ - name: Pcie2
++ description: PCIe revision 2.0 compatible
++ - name: Pcie21
++ description: PCIe revision 2.1 compatible
++ - name: Pcie3
++ description: PCIe revision 3.0 compatible
++ - name: Pcie4
++ description: PCIe revision 4.0 compatible
++ - name: Pcie5
++ description: PCIe revision 4.0 compatible
++ - name: PciCompatible
++ description: >
++ PCI compatible (PCI 1.0,2.0,2.1,2.2,2.3,3.0,PCI-X 1.0, PCI-X 2.0)
++ - name: Usb11Compatible
++ description: USB 1.1 compatible
++ - name: Usb20Compatible
++ description: USB 2.0 compatible
++ - name: Usb30Compatible
++ description: USB 3.0 compatible
++ - name: NcSiOverRbt
++ description: >
++ NC-SI over RBT (A physical interface based on RMII as defined in
++ DSP0222)
++ - name: KcsLegacy
++ description: KCS1 / Legacy (Fixed Address Decoding)
++ - name: KcsPci
++ description: KCS1 / PCI (Base Class 0xC0 Subclass 0x01)
++ - name: SerialHostLegacy
++ description: Serial Host2 / Legacy (Fixed Address Decoding)
++ - name: SerialHostPci
++ description: Serial Host2 / PCI (Base Class 0x07 Subclass 0x00)
++ - name: AsynchronousSerial
++ description: Asynchronous Serial (Between MCs and IMDs)
++ - name: I3cSDR
++ description: I3C 12.5 MHz compatible (SDR)
++ - name: I3cHDRDDR
++ description: I3C 25 MHz compatible (HDR-DDR)
++
++ - name: BindingModeTypes
++ values:
++ - name: Endpoint
++ description: >
++ An MCTP communication terminus. An MCTP endpoint is a terminus or
++ origin of MCTP packets or messages. That is, the combined
++ functionality within a physical device that communicates using the
++ MCTP transport protocol and handles MCTP control commands. This
++ includes MCTP-capable management controllers and managed devices.
++ Also referred to in this document as "endpoint".
++ - name: BusOwner
++ description: >
++ The party responsible for managing address assignments (can be
++ logical or physical addresses) on a bus (for example, in MCTP, the
++ bus owner is the party responsible for managing EID assignments for
++ a given bus). A bus owner may also have additional media-specific
++ responsibilities, such as assignment of physical addresses.
++ - name: Bridge
++ description: >
++ An MCTP endpoint that can route MCTP messages not destined for
++ itself that it receives on one interconnect onto another without
++ interpreting them. The ingress and egress media at the bridge may
++ be either homogeneous or heterogeneous. Also referred to in this
++ document as a "bridge".
++
++ - name: MessageTypes
++ values:
++ - name: MctpControl
++ - name: PLDM
++ - name: NCSI
++ - name: Ethernet
++ - name: NVMeMgmtMsg
++ - name: SPDM
++ - name: VDPCI
++ - name: VDIANA
+diff --git a/yaml/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml b/yaml/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml
+new file mode 100644
+index 000000000000..1bd28818b39a
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml
+@@ -0,0 +1,29 @@
++description: >
++ Interface exposed by MCTP daemon for PCIe binding
++
++properties:
++ - name: DiscoveredFlag
++ type: enum[self.DiscoveryFlags]
++ description: >
++ Each endpoint (except the bus owner) on the PCIe bus maintains an
++ internal flag called the Discovered flag. The flag is set to the
++ discovered state when the Set Endpoint ID command is received.
++
++ - name: BDF
++ type: uint16
++ description: >
++ Byte 1 [7:0] Bus number
++ Byte 2 [7:3] Device number [2:0] Function Number
++
++enumerations:
++ - name: DiscoveryFlags
++ description: >
++ The Prepare for Endpoint Discovery message causes each recipient
++ endpoint on the PCIe bus to set their respective Discovered flag to
++ the undiscovered state. For the Prepare for Endpoint Discovery request
++ message, the routing in the physical transport header should be set to
++ 011b (Broadcast from Root Complex).
++ values:
++ - name: Discovered
++ - name: Undiscovered
++ - name: NotApplicable
+diff --git a/yaml/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml b/yaml/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml
+new file mode 100644
+index 000000000000..9219ad02af06
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml
+@@ -0,0 +1,17 @@
++description: >
++ Interface exposed by MCTP daemon for SMBus binding
++
++properties:
++ - name: ArpMasterSupport
++ type: boolean
++ description: >
++ The SMBus binding can also run ARP Master protocol and
++ assign SMBus addresses to the devices on the bus.
++
++ - name: BusNumber
++ type: byte
++ description: I2C bus number of the medium used
++
++ - name: SlaveAddress
++ type: byte
++ description: Slave address to be used for this medium
+diff --git a/yaml/xyz/openbmc_project/MCTP/BusOwner.interface.yaml b/yaml/xyz/openbmc_project/MCTP/BusOwner.interface.yaml
+new file mode 100644
+index 000000000000..d46298ed35b4
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/MCTP/BusOwner.interface.yaml
+@@ -0,0 +1,17 @@
++description: >
++ Interface exposed by MCTP root object, when executing in Bus Owner mode.
++
++properties:
++ - name: EidPool
++ type: array[struct[byte, byte]]
++ description: >
++ Pool of allowed EIDs to be used.
++ EID pool of 10-100 can be specified as {{10,100}}.
++
++ - name: TopMostBusOwner
++ type: boolean
++ description: To indicate whether BMC is topmost Bus Owner
++
++ - name: OwnEidPool
++ type: boolean
++ description: Indicates Eid pool is managed by self
+diff --git a/yaml/xyz/openbmc_project/MCTP/Endpoint.interface.yaml b/yaml/xyz/openbmc_project/MCTP/Endpoint.interface.yaml
+index 119f1c673c2c..abb3ac930236 100644
+--- a/yaml/xyz/openbmc_project/MCTP/Endpoint.interface.yaml
++++ b/yaml/xyz/openbmc_project/MCTP/Endpoint.interface.yaml
+@@ -6,6 +6,10 @@ description: >
+ MCTP-capable management controllers and managed devices.
+
+ properties:
++ - name: Mode
++ type: enum[xyz.openbmc_project.MCTP.Base.BindingModeTypes]
++ description: >
++ Endpoint / BusOwner / Bridge
+
+ - name: NetworkId
+ type: size
+diff --git a/yaml/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml b/yaml/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml
+new file mode 100644
+index 000000000000..fa447ee6a3bb
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml
+@@ -0,0 +1,36 @@
++description:
++ Interface used to represent the supported MCTP message types.
++ This will be exposed by all MCTP endpoints.
++
++properties:
++ - name: MctpControl
++ type: boolean
++ description: Indicates support availability
++
++ - name: PLDM
++ type: boolean
++ description: Indicates support availability
++
++ - name: NCSI
++ type: boolean
++ description: Indicates support availability
++
++ - name: Ethernet
++ type: boolean
++ description: Indicates support availability
++
++ - name: NVMeMgmtMsg
++ type: boolean
++ description: Indicates support availability
++
++ - name: SPDM
++ type: boolean
++ description: Indicates support availability
++
++ - name: VDPCI
++ type: boolean
++ description: Indicates support availability
++
++ - name: VDIANA
++ type: boolean
++ description: Indicates support availability
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch
new file mode 100644
index 000000000..6da1c2693
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch
@@ -0,0 +1,494 @@
+From 2da0a05ae9b69cd8da67ced1bcac6ae7c6c5f930 Mon Sep 17 00:00:00 2001
+From: "Gade-RajasekharReddy@" <Gade-RajasekharReddy@>
+Date: Wed, 16 Sep 2020 03:19:41 +0530
+Subject: [PATCH] Add D-Bus interfaces for PLDM FW update
+
+Added PLDM FW update base interface, which exposes a method. Using
+this method PLDM FWU can be initiated.
+
+Added interfaces for exposing PLDM FW update inventory info.
+
+Test
+supporting files are created for the yaml files.
+
+Signed-off-by: Gade-RajasekharReddy@ <raja.sekhar.reddy.gade@linux.intel.com>
+---
+ .../PLDM/FWU/ACPIDescriptor.interface.yaml | 14 +++
+ ...ActiveComponentImageSetInfo.interface.yaml | 9 ++
+ .../FWU/ActiveComponentInfo.interface.yaml | 55 ++++++++++
+ .../CapabilitiesDuringUpdate.interface.yaml | 32 ++++++
+ .../ComponentActivationMethods.interface.yaml | 40 +++++++
+ .../PLDM/FWU/FWUBase.interface.yaml | 21 ++++
+ .../PLDM/FWU/IANADescriptor.interface.yaml | 10 ++
+ .../PLDM/FWU/PCIDescriptor.interface.yaml | 30 +++++
+ ...endingComponentImageSetInfo.interface.yaml | 10 ++
+ .../FWU/PendingComponentInfo.interface.yaml | 40 +++++++
+ .../PLDM/FWU/PnPDescriptor.interface.yaml | 14 +++
+ yaml/xyz/openbmc_project/PLDM/FWU/README.md | 103 ++++++++++++++++++
+ 12 files changed, 378 insertions(+)
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml
+ create mode 100644 yaml/xyz/openbmc_project/PLDM/FWU/README.md
+
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml
+new file mode 100644
+index 000000000000..e225bade0df0
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml
+@@ -0,0 +1,14 @@
++description : >
++ This interface has ACPI descriptor properties.
++
++properties :
++
++ - name : ACPIVendorID
++ type : string
++ description: >
++ Property containing ACPI Vendor ID.
++
++ - name : ACPIProductIdentifier
++ type : string
++ description: >
++ Property containing ACPI Product Identifier.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml
+new file mode 100644
+index 000000000000..94115a33e1d9
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml
+@@ -0,0 +1,9 @@
++description : >
++ This interface has the PLDM FWU active component image set properties.
++
++properties :
++
++ - name : ActiveComponentImageSetVersionString
++ type : string
++ description: >
++ String describing the active component image set version.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml
+new file mode 100644
+index 000000000000..77a75669439b
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml
+@@ -0,0 +1,55 @@
++description: >
++ This interface has the component entries for all of the updatable
++ active components that reside on the FD.
++
++properties:
++
++ - name: ComponentClassification
++ type: uint16
++ description: >
++ Vendor specific component classification information.
++ Special values: 0x0000, 0xFFFF are reserved.
++
++ - name: ComponentIdentifier
++ type: uint16
++ description: >
++ FD vendor selected unique value to distinguish between
++ component images.
++
++ - name: ComponentClassificationIndex
++ type: byte
++ description: >
++ Used to distinguish identical components that have the same
++ classification and identifier that can use the same component
++ image but the images are stored in different locations in the FD.
++
++ - name: ActiveComponentComparisonStamp
++ type: uint32
++ description: >
++ Optional Firmware component comparison stamp that is currently
++ active. If the firmware component does not provide a component
++ comparison stamp, this value should be set to 0x00000000.
++
++ - name: ActiveComponentReleaseDate
++ type: string
++ description: >
++ Containing the date corresponding to the component version
++ level being reported – Format YYYYMMDD.
++ If the firmware component does not provide a date, this string
++ shall be empty.
++
++ - name: ComponentAutoApply
++ type: boolean
++ description: >
++ Firmware Device performs an ‘auto-apply’ during transfer
++ phase and apply step will be completed immediately if this
++ property is true.
++ Firmware Device will execute an operation during the APPLY
++ state that will include migrating the new component image to its
++ final non-volatile storage destination if this property is
++ false.
++
++ - name: ActiveComponentVersionString
++ type: string
++ description: >
++ String describing the active component version.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml
+new file mode 100644
+index 000000000000..36560ff0742b
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml
+@@ -0,0 +1,32 @@
++description : >
++ This interface describes the capabilities during update.
++
++properties :
++
++ - name : UpdateModeRestrictions
++ type : boolean
++ description: >
++ This property tells whether update mode restrictions are
++ supported or not.
++
++ - name : PartialUpdates
++ type : boolean
++ description: >
++ This property tells whether partial updates are supported or not.
++
++ - name : HostFunctionalityDuringFirmwareUpdate
++ type : boolean
++ description: >
++ This property tells whether the host device functionality
++ during firmware update is reduced or not.
++
++ - name : ComponentUpdateFailureRetryCapability
++ type : boolean
++ description: >
++ This property shows the component update failure retry capability.
++
++ - name : ComponentUpdateFailureRecoveryCapability
++ type : boolean
++ description: >
++ This property shows the component update failure recovery
++ capability.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml
+new file mode 100644
+index 000000000000..d5ec47cbc77f
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml
+@@ -0,0 +1,40 @@
++description: >
++ This interface has the component activation methods.
++
++properties:
++
++ - name: ACPowerCycle
++ type: boolean
++ description: >
++ Property that tells whether AC power cycle is an activation
++ method or not.
++
++ - name: DCPowerCycle
++ type: boolean
++ description: >
++ Property that tells whether DC power cycle is an activation
++ method or not.
++
++ - name: SystemReboot
++ type: boolean
++ description: >
++ Property that tells whether System reboot is an activation
++ method or not.
++
++ - name: MediumSpecificReset
++ type: boolean
++ description: >
++ Property that tells whether Medium-specific reset is an
++ activation method or not.
++
++ - name: SelfContained
++ type: boolean
++ description: >
++ Property that tells whether Self-Contained option is activation
++ method or not.
++
++ - name: Automatic
++ type: boolean
++ description: >
++ Property that tells whether the component can be activated
++ automatically once apply completes.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml
+new file mode 100644
+index 000000000000..2ba15e26c690
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml
+@@ -0,0 +1,21 @@
++description: >
++ This interface provides a method to initiate the PLDM FW update.
++
++methods:
++ - name: StartFWUpdate
++ description: >
++ This method initiates the PLDM FW update.
++ parameters:
++ - name: filePath
++ type: string
++ description: >
++ PLDM FW update package path.
++ returns:
++ - name: status
++ type: byte
++ description: >
++ PLDM FW update status.
++ errors:
++ - xyz.openbmc_project.Common.Error.NotAllowed
++ - xyz.openbmc_project.Common.Error.InvalidArgument
++ - xyz.openbmc_project.Common.Error.ResourceNotFound
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml
+new file mode 100644
+index 000000000000..c013955af3b6
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml
+@@ -0,0 +1,10 @@
++description : >
++ This interface has device identification info, in which IANA
++ Enterprise ID is used as descriptor.
++
++properties :
++
++ - name : IANAEnterpriseID
++ type : string
++ description: >
++ Property containing the IANA Enterprise ID.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml
+new file mode 100644
+index 000000000000..8d758ed51192
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml
+@@ -0,0 +1,30 @@
++description : >
++ This interface has device identification info,in which PCI Vendor ID
++ is used as descriptor.
++
++properties :
++
++ - name : PCIVendorID
++ type : string
++ description: >
++ Property containing the PCI Vendor ID.
++
++ - name : PCIDeviceID
++ type : string
++ description: >
++ Property containing the PCI Device ID.
++
++ - name : PCISubsystemVendorID
++ type : string
++ description: >
++ Property containing the PCI Subsystem Vendor ID.
++
++ - name : PCISubsystemID
++ type : string
++ description: >
++ Property containing the PCI Subsystem ID.
++
++ - name : PCIRevisionID
++ type : string
++ description: >
++ Property containing the PCI Revision ID.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml
+new file mode 100644
+index 000000000000..3861572d81a4
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml
+@@ -0,0 +1,10 @@
++description : >
++ This interface has the PLDM FWU pending component image set
++ properties.
++
++properties :
++
++ - name : PendingComponentImageSetVersionString
++ type : string
++ description: >
++ String describing the pending component image set version.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml
+new file mode 100644
+index 000000000000..59a2ad8dae8c
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml
+@@ -0,0 +1,40 @@
++description: >
++ This interface has the component entries for all of the pending
++ components that reside on the FD.
++
++properties:
++
++ - name: PendingComponentComparisonStamp
++ type: uint32
++ description: >
++ Optional firmware component comparison stamp that is pending
++ activation. This field, and all other pending component fields,
++ are valid once the firmware device has received the
++ ActivateFirmware command to prepare the firmware component for
++ activation, but the activation method requires further action
++ to enable the pending image to become the actively running code
++ image.
++ If no pending firmware component exists, this value shall be
++ set to 0x00000000
++
++ - name: PendingComponentReleaseDate
++ type: string
++ description: >
++ Eight byte field containing the date corresponding to the
++ component version level being reported – Format YYYYMMDD.
++ If no pending firmware component exists, this string
++ shall be empty.
++
++
++ - name: PendingComponentVersionString
++ type: string
++ description: >
++ Firmware component version, which is pending activation. The
++ version reported here should be the one that will become active
++ on the next initialization or activation of the component. The
++ pending component version value may be same as the active
++ component version. Contains a variable type string describing
++ the pending component version. Refer to
++ PendingComponentComparisonStamp field for additional details.
++ If no pending firmware component exists, this field is zero
++ bytes in length.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml b/yaml/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml
+new file mode 100644
+index 000000000000..801db6d6380c
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml
+@@ -0,0 +1,14 @@
++description : >
++ This interface has PnP descriptor properties.
++
++properties :
++
++ - name : PnPVendorID
++ type : string
++ description: >
++ Property containing the PnP Vendor ID.
++
++ - name : PnPProductIdentifier
++ type : string
++ description: >
++ Property containing the PnP Product Identifier.
+diff --git a/yaml/xyz/openbmc_project/PLDM/FWU/README.md b/yaml/xyz/openbmc_project/PLDM/FWU/README.md
+new file mode 100644
+index 000000000000..293173933baf
+--- /dev/null
++++ b/yaml/xyz/openbmc_project/PLDM/FWU/README.md
+@@ -0,0 +1,103 @@
++#PLDM FW Update
++
++##Overview
++
++The PLDM FW update package contains two major sections: the FW package
++header, and the FW package payload. The FW package header is required to
++describe the target device that the package is intended to update and
++the component images that the FW update package contains. The FW
++package payload is the actual FW image which can be used by FW device
++for FW update.
++
++Update Agent(BMC) will send the inventory commands to the all the
++devices which are capable of PLDM FW update and exposes the inventory
++info to the D-Bus. How PLDM FW update package reaches BMC is out of
++scope of PLDM FWU spec 1.0.1. Once BMC receives the FW package, it
++matches the package header with the inventory info, if matches proceeds
++for FW update.
++
++###PLDM FW update interfaces overview and hierarchy
++
++/xyz/openbmc_project/pldm/fwu
++|--xyz.openbmc_project.PLDM.FWU.FWUBase
++|
++|__/xyz/openbmc_project/pldm/fwu/<tid>
++ |
++ |__/xyz/openbmc_project/pldm/fwu/<tid>/deviceDescriptors
++ | |--xyz.openbmc_project.PLDM.FWU.PCIDescriptor
++ | |--xyz.openbmc_project.PLDM.FWU.IANADescriptor
++ | |--xyz.openbmc_project.PLDM.FWU.PnPDescriptor
++ | |--xyz.openbmc_project.PLDM.FWU.ACPIDescriptor
++ |
++ |__/xyz/openbmc_project/pldm/fwu/<tid>/componentImageSetInfo
++ | |--xyz.openbmc_project.PLDM.FWU.ActiveComponentImageSetInfo
++ | |--xyz.openbmc_project.PLDM.FWU.PendingComponentImageSetInfo
++ |
++ |__/xyz/openbmc_project/pldm/fwu/<tid>/componentImageSetInfo/component_<component_no>
++ |--xyz.openbmc_project.PLDM.FWU.ActiveComponentInfo
++ |--xyz.openbmc_project.PLDM.FWU.PendingComponentInfo
++ |--xyz.openbmc_project.PLDM.FWU.ComponentActivationMethods
++ |--xyz.openbmc_project.PLDM.FWU.CapabilitiesDuringUpdate
++
++Note:
++Descriptor for a device shall be defined by one of the following
++(PCI Vendor ID, IANA Enterprise ID, UUID, PnP Vendor ID, or ACPI Vendor
++ID) and the corresponding descriptor`s interface is exposed by the.
++Device Descriptors object.
++No new UUID descriptor incterface is defined as the existing UUID
++interface will be used.
++
++####FW Update Base
++It is exposed by the object `/xyz/openbmc_project/pldm/fwu` with the
++following interface
++1. `xyz.openbmc_project.pldm.FWUBase` exposes a method by which PLDM
++FWU can be initiated.
++
++Each FW update capable device info is exposed by the object
++`/xyz/openbmc_project/pldm/fwu/<tid>`.
++It will have the following objects.
++1. Device Descriptors
++2. Component Image Set Info
++3. Component Image Info (Each component is exposed as an object)
++
++####Device Descriptors
++Device Descriptors are exposed under the object path
++`/xyz/openbmc_project/pldm/fwu/deviceDescriptors` with one of the
++following interfaces.
++1. `xyz.openbmc_project.PLDM.FWU.PCIDescriptor` which exposes the PCI
++device descriptors. If the FD is a PCI device then this interface will
++be exposed by the device descriptors object.
++2. `xyz.openbmc_project.PLDM.FWU.IANADescriptor` which exposes IANA
++descriptor properties. If FD have IANA Enterprise ID as the descriptor
++type then this interface will be exposed by the device descriptors
++object.
++3. `xyz.openbmc_project.PLDM.FWU.PnPDescriptor` which exposes the Pnp
++descriptor properties. If FD have PnP vendor ID as the descriptor
++type then this interface will be exposed by the device descriptors
++object.
++4. `xyz.openbmc_project.PLDM.FWU.ACPIDescriptor` which exposes the ACPI
++descriptor properties. If FD have ACPI vendor ID as the descriptor
++type then this interface will be exposed by the device descriptors
++object.
++
++####Component Image Set Info
++Component Image Set Info is exposed under the object path
++`/xyz/openbmc_project/pldm/fwu/componentImageSetInfo` with the
++following interface.
++1. `xyz.openbmc_project.PLDM.FWU.ActiveComponentImageSetInfo` which
++exposes the active component image set properties.
++2. `xyz.openbmc_project.PLDM.FWU.PendingComponentImageSetInfo` which
++exposes the pending component image set properties.
++
++####Component Image Info
++Component Image Info is exposed under the object path
++`/xyz/openbmc_project/pldm/fwu/componentImageSetInfo/componentInfo_<component_no>'
++with the following interface
++1. `xyz.openbmc_project.PLDM.FWU.ActiveComponentInfo` which exposes the
++component Image properties.
++2. `xyz.openbmc_project.PLDM.FWU.PendingComponentInfo` which exposes the
++component Image properties.
++3. `xyz.openbmc_project.PLDM.FWU.CapabilitiesDuringUpdate` which exposes
++the capabilities of the component during update.
++4. `xyz.openbmc_project.PLDM.FWU.ComponentActivationMethods` which
++exposes the component activation methods.
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch
new file mode 100644
index 000000000..0a57733aa
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch
@@ -0,0 +1,28 @@
+From 114687e8f5b4728bd5d82b3c2dbc97cb40273cb8 Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Wed, 23 Sep 2020 22:01:25 +0530
+Subject: [PATCH] Add PLDM version purpose enumeration
+
+This change is to add PLDM in enumeration of possible purposes
+of the version to support pldm type version purpose
+
+Change-Id: I7b914d4323bfe44a4e3cd60ed4a627aeceb6b56f
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ yaml/xyz/openbmc_project/Software/Version.interface.yaml | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/yaml/xyz/openbmc_project/Software/Version.interface.yaml b/yaml/xyz/openbmc_project/Software/Version.interface.yaml
+index 345e5b51f653..f2efbecce938 100644
+--- a/yaml/xyz/openbmc_project/Software/Version.interface.yaml
++++ b/yaml/xyz/openbmc_project/Software/Version.interface.yaml
+@@ -38,3 +38,6 @@ enumerations:
+ - name: PSU
+ description: >
+ The version is a version for a PSU.
++ - name: PLDM
++ description: >
++ The version is a version for PLDM.
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch
new file mode 100644
index 000000000..31c5ad95b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch
@@ -0,0 +1,149 @@
+From 20357179065a9157ad89f7c717ba214bf4fe4ded Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Tue, 8 Dec 2020 15:08:21 -0800
+Subject: [PATCH] update meson build files for control and bios
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ .../Control/Power/RestoreDelay/meson.build | 13 +++++++++++++
+ gen/xyz/openbmc_project/Control/Power/meson.build | 14 ++++++++++++++
+ .../Control/Processor/ErrConfig/meson.build | 13 +++++++++++++
+ .../openbmc_project/Control/Processor/meson.build | 13 +++++++++++++
+ .../Inventory/Item/Bios/meson.build | 13 +++++++++++++
+ gen/xyz/openbmc_project/Inventory/Item/meson.build | 14 ++++++++++++++
+ 6 files changed, 80 insertions(+)
+ create mode 100644 gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build
+ create mode 100644 gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build
+ create mode 100644 gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build
+
+diff --git a/gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build b/gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build
+new file mode 100644
+index 000000000000..1afe8d26b87d
+--- /dev/null
++++ b/gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/Control/Power/RestoreDelay__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/Control/Power/RestoreDelay',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/Control/Power/meson.build b/gen/xyz/openbmc_project/Control/Power/meson.build
+index dbd3b409ead0..43ccf1958aa9 100644
+--- a/gen/xyz/openbmc_project/Control/Power/meson.build
++++ b/gen/xyz/openbmc_project/Control/Power/meson.build
+@@ -41,6 +41,20 @@ generated_others += custom_target(
+ ],
+ )
+
++subdir('RestoreDelay')
++generated_others += custom_target(
++ 'xyz/openbmc_project/Control/Power/RestoreDelay__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml', ],
++ output: [ 'RestoreDelay.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/Control/Power/RestoreDelay',
++ ],
++)
++
+ subdir('RestorePolicy')
+ generated_others += custom_target(
+ 'xyz/openbmc_project/Control/Power/RestorePolicy__markdown'.underscorify(),
+diff --git a/gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build b/gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build
+new file mode 100644
+index 000000000000..937004d3d68b
+--- /dev/null
++++ b/gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/Control/Processor/ErrConfig__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/Control/Processor/ErrConfig',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/Control/Processor/meson.build b/gen/xyz/openbmc_project/Control/Processor/meson.build
+index fc32bf2f877f..cc2a1d6507b3 100644
+--- a/gen/xyz/openbmc_project/Control/Processor/meson.build
++++ b/gen/xyz/openbmc_project/Control/Processor/meson.build
+@@ -13,3 +13,16 @@ generated_others += custom_target(
+ ],
+ )
+
++subdir('ErrConfig')
++generated_others += custom_target(
++ 'xyz/openbmc_project/Control/Processor/ErrConfig__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml', ],
++ output: [ 'ErrConfig.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/Control/Processor/ErrConfig',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build b/gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build
+new file mode 100644
+index 000000000000..28fbf85dd97c
+--- /dev/null
++++ b/gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/Inventory/Item/Bios__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/Inventory/Item/Bios',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/Inventory/Item/meson.build b/gen/xyz/openbmc_project/Inventory/Item/meson.build
+index 77d9be8b6c03..7d22037b32b8 100644
+--- a/gen/xyz/openbmc_project/Inventory/Item/meson.build
++++ b/gen/xyz/openbmc_project/Inventory/Item/meson.build
+@@ -40,6 +40,20 @@ generated_others += custom_target(
+ ],
+ )
+
++subdir('Bios')
++generated_others += custom_target(
++ 'xyz/openbmc_project/Inventory/Item/Bios__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml', ],
++ output: [ 'Bios.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/Inventory/Item/Bios',
++ ],
++)
++
+ subdir('Bmc')
+ generated_others += custom_target(
+ 'xyz/openbmc_project/Inventory/Item/Bmc__markdown'.underscorify(),
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch
new file mode 100644
index 000000000..ab13f55fe
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch
@@ -0,0 +1,209 @@
+From f4eddacc871c6bb759e6e355a89ccaaa12c63396 Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Tue, 8 Dec 2020 15:16:25 -0800
+Subject: [PATCH] update meson build for MCTP interfaces
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ gen/xyz/openbmc_project/MCTP/Base/meson.build | 13 ++++++
+ .../MCTP/Binding/PCIe/meson.build | 13 ++++++
+ .../MCTP/Binding/SMBus/meson.build | 13 ++++++
+ .../openbmc_project/MCTP/Binding/meson.build | 30 +++++++++++++
+ .../openbmc_project/MCTP/BusOwner/meson.build | 13 ++++++
+ .../MCTP/SupportedMessageTypes/meson.build | 13 ++++++
+ gen/xyz/openbmc_project/MCTP/meson.build | 42 +++++++++++++++++++
+ 7 files changed, 137 insertions(+)
+ create mode 100644 gen/xyz/openbmc_project/MCTP/Base/meson.build
+ create mode 100644 gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build
+ create mode 100644 gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build
+ create mode 100644 gen/xyz/openbmc_project/MCTP/Binding/meson.build
+ create mode 100644 gen/xyz/openbmc_project/MCTP/BusOwner/meson.build
+ create mode 100644 gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build
+
+diff --git a/gen/xyz/openbmc_project/MCTP/Base/meson.build b/gen/xyz/openbmc_project/MCTP/Base/meson.build
+new file mode 100644
+index 000000000000..c605b2d496ac
+--- /dev/null
++++ b/gen/xyz/openbmc_project/MCTP/Base/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/MCTP/Base__cpp'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/MCTP/Base.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/Base',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build b/gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build
+new file mode 100644
+index 000000000000..4573a64f4099
+--- /dev/null
++++ b/gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/MCTP/Binding/PCIe__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/Binding/PCIe',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build b/gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build
+new file mode 100644
+index 000000000000..bfb4d040a54c
+--- /dev/null
++++ b/gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/MCTP/Binding/SMBus__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/Binding/SMBus',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/MCTP/Binding/meson.build b/gen/xyz/openbmc_project/MCTP/Binding/meson.build
+new file mode 100644
+index 000000000000..36a74ddac294
+--- /dev/null
++++ b/gen/xyz/openbmc_project/MCTP/Binding/meson.build
+@@ -0,0 +1,28 @@
++# Generated file; do not modify.
++subdir('PCIe')
++generated_others += custom_target(
++ 'xyz/openbmc_project/MCTP/Binding/PCIe__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml', ],
++ output: [ 'PCIe.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/Binding/PCIe',
++ ],
++)
++
++subdir('SMBus')
++generated_others += custom_target(
++ 'xyz/openbmc_project/MCTP/Binding/SMBus__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml', ],
++ output: [ 'SMBus.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/Binding/SMBus',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/MCTP/BusOwner/meson.build b/gen/xyz/openbmc_project/MCTP/BusOwner/meson.build
+new file mode 100644
+index 000000000000..4b28bd6b34e7
+--- /dev/null
++++ b/gen/xyz/openbmc_project/MCTP/BusOwner/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/MCTP/BusOwner__cpp'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/MCTP/BusOwner.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/BusOwner',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build b/gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build
+new file mode 100644
+index 000000000000..4fd46823ed17
+--- /dev/null
++++ b/gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes__cpp'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/MCTP/meson.build b/gen/xyz/openbmc_project/MCTP/meson.build
+index b9598adf6fa7..6b6d00b833d2 100644
+--- a/gen/xyz/openbmc_project/MCTP/meson.build
++++ b/gen/xyz/openbmc_project/MCTP/meson.build
+@@ -1,4 +1,33 @@
+ # Generated file; do not modify.
++subdir('Base')
++generated_others += custom_target(
++ 'xyz/openbmc_project/MCTP/Base__markdown'.underscorify(),
++ input: [ '../../../../yaml/xyz/openbmc_project/MCTP/Base.interface.yaml', ],
++ output: [ 'Base.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../yaml',
++ 'xyz/openbmc_project/MCTP/Base',
++ ],
++)
++
++subdir('Binding')
++subdir('BusOwner')
++generated_others += custom_target(
++ 'xyz/openbmc_project/MCTP/BusOwner__markdown'.underscorify(),
++ input: [ '../../../../yaml/xyz/openbmc_project/MCTP/BusOwner.interface.yaml', ],
++ output: [ 'BusOwner.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../yaml',
++ 'xyz/openbmc_project/MCTP/BusOwner',
++ ],
++)
++
+ subdir('Endpoint')
+ generated_others += custom_target(
+ 'xyz/openbmc_project/MCTP/Endpoint__markdown'.underscorify(),
+@@ -13,3 +42,16 @@ generated_others += custom_target(
+ ],
+ )
+
++subdir('SupportedMessageTypes')
++generated_others += custom_target(
++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes__markdown'.underscorify(),
++ input: [ '../../../../yaml/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml', ],
++ output: [ 'SupportedMessageTypes.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../yaml',
++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes',
++ ],
++)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch
new file mode 100644
index 000000000..6497d50d8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch
@@ -0,0 +1,418 @@
+From f73c64bbe2cf9369892269a71893e2911753ba4d Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Tue, 8 Dec 2020 15:28:42 -0800
+Subject: [PATCH] update meson build for PLDM FWU interfaces
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ .../PLDM/FWU/ACPIDescriptor/meson.build | 13 ++
+ .../ActiveComponentImageSetInfo/meson.build | 13 ++
+ .../PLDM/FWU/ActiveComponentInfo/meson.build | 13 ++
+ .../FWU/CapabilitiesDuringUpdate/meson.build | 13 ++
+ .../ComponentActivationMethods/meson.build | 13 ++
+ .../PLDM/FWU/FWUBase/meson.build | 13 ++
+ .../PLDM/FWU/IANADescriptor/meson.build | 13 ++
+ .../PLDM/FWU/PCIDescriptor/meson.build | 13 ++
+ .../PendingComponentImageSetInfo/meson.build | 13 ++
+ .../PLDM/FWU/PendingComponentInfo/meson.build | 13 ++
+ .../PLDM/FWU/PnPDescriptor/meson.build | 13 ++
+ gen/xyz/openbmc_project/PLDM/FWU/meson.build | 154 ++++++++++++++++++
+ gen/xyz/openbmc_project/PLDM/meson.build | 1 +
+ 13 files changed, 298 insertions(+)
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build
+ create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/meson.build
+
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build
+new file mode 100644
+index 000000000000..fbaf6c458645
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build
+new file mode 100644
+index 000000000000..af3df1483126
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build
+new file mode 100644
+index 000000000000..e5ff324231f5
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build
+new file mode 100644
+index 000000000000..03768e24090f
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build
+new file mode 100644
+index 000000000000..31cffd2e311b
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build
+new file mode 100644
+index 000000000000..3b90b51e1b7f
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/FWUBase__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/FWUBase',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build
+new file mode 100644
+index 000000000000..5d28fb5cca5a
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build
+new file mode 100644
+index 000000000000..0c2a5d572dd1
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build
+new file mode 100644
+index 000000000000..3fe7d85bbb29
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build
+new file mode 100644
+index 000000000000..a4d11a3317a4
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build
+new file mode 100644
+index 000000000000..d0508ca366ae
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build
+@@ -0,0 +1,13 @@
++# Generated file; do not modify.
++generated_sources += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor__cpp'.underscorify(),
++ input: [ '../../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml', ],
++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'cpp',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/FWU/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/meson.build
+new file mode 100644
+index 000000000000..2bb71914b606
+--- /dev/null
++++ b/gen/xyz/openbmc_project/PLDM/FWU/meson.build
+@@ -0,0 +1,154 @@
++# Generated file; do not modify.
++subdir('ACPIDescriptor')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml', ],
++ output: [ 'ACPIDescriptor.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor',
++ ],
++)
++
++subdir('ActiveComponentImageSetInfo')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml', ],
++ output: [ 'ActiveComponentImageSetInfo.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo',
++ ],
++)
++
++subdir('ActiveComponentInfo')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml', ],
++ output: [ 'ActiveComponentInfo.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo',
++ ],
++)
++
++subdir('CapabilitiesDuringUpdate')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml', ],
++ output: [ 'CapabilitiesDuringUpdate.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate',
++ ],
++)
++
++subdir('ComponentActivationMethods')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml', ],
++ output: [ 'ComponentActivationMethods.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods',
++ ],
++)
++
++subdir('FWUBase')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/FWUBase__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml', ],
++ output: [ 'FWUBase.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/FWUBase',
++ ],
++)
++
++subdir('IANADescriptor')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml', ],
++ output: [ 'IANADescriptor.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor',
++ ],
++)
++
++subdir('PCIDescriptor')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml', ],
++ output: [ 'PCIDescriptor.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor',
++ ],
++)
++
++subdir('PendingComponentImageSetInfo')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml', ],
++ output: [ 'PendingComponentImageSetInfo.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo',
++ ],
++)
++
++subdir('PendingComponentInfo')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml', ],
++ output: [ 'PendingComponentInfo.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo',
++ ],
++)
++
++subdir('PnPDescriptor')
++generated_others += custom_target(
++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor__markdown'.underscorify(),
++ input: [ '../../../../../yaml/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml', ],
++ output: [ 'PnPDescriptor.md' ],
++ command: [
++ sdbuspp_gen_meson_prog, '--command', 'markdown',
++ '--output', meson.current_build_dir(),
++ '--tool', sdbusplusplus_prog,
++ '--directory', meson.current_source_dir() / '../../../../../yaml',
++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor',
++ ],
++)
+diff --git a/gen/xyz/openbmc_project/PLDM/meson.build b/gen/xyz/openbmc_project/PLDM/meson.build
+index 2be636cbaac0..35ff301901b3 100644
+--- a/gen/xyz/openbmc_project/PLDM/meson.build
++++ b/gen/xyz/openbmc_project/PLDM/meson.build
+@@ -13,6 +13,7 @@ generated_others += custom_target(
+ ],
+ )
+
++subdir('FWU')
+ subdir('PDR')
+ generated_others += custom_target(
+ 'xyz/openbmc_project/PLDM/PDR__markdown'.underscorify(),
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0034-Add-username-property-to-SessionInfo-interface.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0034-Add-username-property-to-SessionInfo-interface.patch
new file mode 100644
index 000000000..f614f88c6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0034-Add-username-property-to-SessionInfo-interface.patch
@@ -0,0 +1,64 @@
+From ee72d92baf3d64d066e0ec64cbd8723177219182 Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Tue, 1 Jun 2021 12:27:50 +0000
+Subject: [PATCH] Add username property to SessionInfo interface
+
+Add username property to SessionInfo interface to get username info on
+individual IPMI session Id's on Redfish
+
+Tested:
+Verified on SessionInfo D-bus interface.
+
+busctl introspect xyz.openbmc_project.Ipmi.Channel.eth0
+ /xyz/openbmc_project/ipmi/session/eth0/0
+NAME TYPE SIGNATURE RESULT/VALUE FLAGS
+......
+xyz.openbmc_project.Ipmi.SessionInfo interface - - -
+.ChannelNum property y 0 emits-change writable
+.CurrentPrivilege property y 0 emits-change writable
+.RemoteIPAddr property u 2225389066 emits-change writable
+.RemoteMACAddress property ay 0 emits-change writable
+.RemotePort property q 35749 emits-change writable
+.SessionHandle property y 0 emits-change writable
+.State property y 0 emits-change writable
+.UserID property y 0 emits-change writable
+.Username property s "" emits-change writable
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ yaml/xyz/openbmc_project/Ipmi/SESSION_README.md | 1 +
+ yaml/xyz/openbmc_project/Ipmi/SessionInfo.interface.yaml | 6 ++++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/yaml/xyz/openbmc_project/Ipmi/SESSION_README.md b/yaml/xyz/openbmc_project/Ipmi/SESSION_README.md
+index c59b251bb88d..ed41c3bf181d 100644
+--- a/yaml/xyz/openbmc_project/Ipmi/SESSION_README.md
++++ b/yaml/xyz/openbmc_project/Ipmi/SESSION_README.md
+@@ -16,6 +16,7 @@ so that both phosphor-ipmi-host & phosphr-ipmi-net will be in sync.
+ * RemotePort - Remote port address.
+ * RemoteMACAddress -Remote MAC Address.
+ * UserID - Session created by given user id.
++* Username - Session created by given username.
+
+
+
+diff --git a/yaml/xyz/openbmc_project/Ipmi/SessionInfo.interface.yaml b/yaml/xyz/openbmc_project/Ipmi/SessionInfo.interface.yaml
+index 0ddc0250db50..50aff5c26072 100644
+--- a/yaml/xyz/openbmc_project/Ipmi/SessionInfo.interface.yaml
++++ b/yaml/xyz/openbmc_project/Ipmi/SessionInfo.interface.yaml
+@@ -46,6 +46,12 @@ properties:
+ Session created by given user ID.
+ errors:
+ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: Username
++ type: string
++ description: >
++ Session created by given username.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
+ - name: State
+ type: byte
+ default: 0
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
new file mode 100644
index 000000000..b8e0e7741
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
@@ -0,0 +1,22 @@
+# Keep this as a comment to enable the auto-bump script without
+# stomping on SRC_URI from previous .bbappend files
+#SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git"
+SRCREV = "e0764cf41d16b823a519e9d4f508b588e3e84aba"
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0007-ipmi-set-BIOS-id.patch \
+ file://0010-Increase-the-default-watchdog-timeout-value.patch \
+ file://0012-Add-RestoreDelay-interface-for-power-restore-delay.patch \
+ file://0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch \
+ file://0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch \
+ file://0025-Add-PreInterruptFlag-properity-in-DBUS.patch \
+ file://0026-Add-StandbySpare-support-for-software-inventory.patch \
+ file://0028-MCTP-Daemon-D-Bus-interface-definition.patch \
+ file://0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch \
+ file://0031-update-meson-build-files-for-control-and-bios.patch \
+ file://0030-Add-PLDM-version-purpose-enumeration.patch \
+ file://0032-update-meson-build-for-MCTP-interfaces.patch \
+ file://0033-update-meson-build-for-PLDM-FWU-interfaces.patch \
+ file://0034-Add-username-property-to-SessionInfo-interface.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service
new file mode 100644
index 000000000..9af9af254
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service
@@ -0,0 +1,20 @@
+[Unit]
+Description=Phosphor DBus Service Discovery Manager
+Before=obmc-mapper.target
+After=dbus.socket
+
+[Service]
+Restart=always
+Type=dbus
+ExecStart=/usr/bin/env mapperx \
+ --service-namespaces="xyz. com. org." \
+ --interface-namespaces="org. com. xyz." \
+ --service-blacklists="org.freedesktop.systemd1"
+SyslogIdentifier=phosphor-mapper
+BusName={BUSNAME}
+TimeoutStartSec=300
+RestartSec=5
+EnvironmentFile={envfiledir}/obmc/mapper
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend
new file mode 100644
index 000000000..4fc41d058
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/0001-allow-dbus-sensors-without-thresholds.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/0001-allow-dbus-sensors-without-thresholds.patch
new file mode 100644
index 000000000..6af0a5702
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/0001-allow-dbus-sensors-without-thresholds.patch
@@ -0,0 +1,39 @@
+From 6b4071c12bdcc3bd20e72a7bd2eed19ff14b97af Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Wed, 12 May 2021 19:11:08 -0700
+Subject: [PATCH] allow dbus sensors without thresholds
+
+catch dbus exceptions when query for thresholds interfaces.
+log messages and continue.
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ dbus/dbusconfiguration.cpp | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dbus/dbusconfiguration.cpp b/dbus/dbusconfiguration.cpp
+index 55151d3..fd7a138 100644
+--- a/dbus/dbusconfiguration.cpp
++++ b/dbus/dbusconfiguration.cpp
+@@ -286,13 +286,15 @@ void populatePidInfo(
+ {
+ interface = thresholds::criticalInterface;
+ }
+- const std::string& path = sensorConfig.at(info.inputs.front()).readPath;
+
+- DbusHelper helper(sdbusplus::bus::new_system());
+- std::string service = helper.getService(interface, path);
+ double reading = 0;
+ try
+ {
++ const std::string& path = sensorConfig.at(info.inputs.front()).readPath;
++
++ DbusHelper helper(sdbusplus::bus::new_system());
++ std::string service = helper.getService(interface, path);
++
+ helper.getProperty(service, path, interface, *thresholdProperty,
+ reading);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service
new file mode 100644
index 000000000..0e80b554a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Phosphor-Pid-Control Margin-based Fan Control Daemon
+After=xyz.openbmc_project.EntityManager.service
+After=xyz.openbmc_project.ObjectMapper.service
+
+[Service]
+Restart=always
+ExecStart={bindir}/swampd
+RestartSec=5
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend
new file mode 100644
index 000000000..328176aca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend
@@ -0,0 +1,14 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+inherit obmc-phosphor-systemd
+SYSTEMD_SERVICE:${PN} = "phosphor-pid-control.service"
+EXTRA_OECONF = "--enable-configure-dbus=yes"
+
+SRC_URI = "git://github.com/openbmc/phosphor-pid-control.git"
+SRCREV = "cca9c659889d149c06e95bab4b8808db4f1e3eab"
+
+SRC_URI += "\
+ file://0001-allow-dbus-sensors-without-thresholds.patch \
+ "
+
+FILES:${PN} = "${bindir}/swampd ${bindir}/setsensor"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch
new file mode 100644
index 000000000..2a4c7e9b6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch
@@ -0,0 +1,44 @@
+From b6b3051c8078267153712ed8cf514373924fd07a Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Mon, 16 Jul 2018 19:15:04 -0700
+Subject: [PATCH 2/6] Redfish firmware activation -- Modified flash.cpp to
+ call to customized flash service
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: I81c3185e9c4c2ee907feeb53620faa22723c04d4
+---
+ ubi/flash.cpp | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/ubi/flash.cpp b/ubi/flash.cpp
+index ffa9348..5af2a17 100644
+--- a/ubi/flash.cpp
++++ b/ubi/flash.cpp
+@@ -15,10 +15,13 @@ void Activation::flashWrite()
+ {
+ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+- method.append("obmc-flash-bmc-ubirw.service", "replace");
++ std::string rwServiceFile =
++ "obmc-flash-bmc-ubirw@" + versionId + ".service";
++ method.append(rwServiceFile, "replace");
+ bus.call_noreply(method);
+
+- auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
++ std::string roServiceFile =
++ "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+ method.append(roServiceFile, "replace");
+@@ -37,7 +40,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg)
+ // Read the msg and populate each variable
+ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+- auto rwServiceFile = "obmc-flash-bmc-ubirw.service";
++ auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service";
+ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ auto ubootVarsServiceFile =
+ "obmc-flash-bmc-updateubootvars@" + versionId + ".service";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch
new file mode 100644
index 000000000..bcf692f5e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch
@@ -0,0 +1,41 @@
+From 1b00440d0c8fabfa2e3eda984a21c0f004ca2150 Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Fri, 26 Oct 2018 11:54:05 -0700
+Subject: [PATCH 4/6] Changed the condition of software version service
+ watching deamon
+
+ Originally it watches only files that are "written" into /tmp/images directory.
+This change modified the condition to also watch files that are "moved" into this directory.
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: I3e9cf1ffc3f5350d4649d32d3d3837991322a65b
+---
+ watch.cpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/watch.cpp b/watch.cpp
+index e46b8aa..eee1bc3 100644
+--- a/watch.cpp
++++ b/watch.cpp
+@@ -46,7 +46,7 @@ Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
+ std::strerror(error));
+ }
+
+- wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
++ wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE | IN_MOVED_TO);
+ if (-1 == wd)
+ {
+ auto error = errno;
+@@ -97,7 +97,8 @@ int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
+ while (offset < bytes)
+ {
+ auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
+- if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
++ if ((event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) &&
++ !(event->mask & IN_ISDIR))
+ {
+ auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
+ auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch
new file mode 100644
index 000000000..fcdc75f8f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch
@@ -0,0 +1,225 @@
+From 6e95f4a761021e3204912e3a7c5b80a18d9f16cf Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Mon, 10 Dec 2018 10:36:44 -0800
+Subject: [PATCH] Modified firmware activation to launch fwupd.sh through
+
+ non-ubi fs code path to match more closely to the upstream design -
+ Added option FWUPD_SCRIPT to saperate intel customized code - Adopted
+ ActivationProgress from ubi fs activation code mainly for progress indicator
+ for ipmi update
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ activation.cpp | 50 +++++++++++++++++++++++++++++++++++++----------
+ meson.build | 2 ++
+ meson_options.txt | 3 +++
+ static/flash.cpp | 42 +++++++++++++++++++++++++++++++++++++--
+ ubi/flash.cpp | 9 +++------
+ 5 files changed, 88 insertions(+), 18 deletions(-)
+
+diff --git a/activation.cpp b/activation.cpp
+index 5490cd9974b3..e43959d78ed2 100644
+--- a/activation.cpp
++++ b/activation.cpp
+@@ -88,20 +88,50 @@ auto Activation::activation(Activations value) -> Activations
+
+ if (value == softwareServer::Activation::Activations::Activating)
+ {
+-#ifdef WANT_SIGNATURE_VERIFY
+- fs::path uploadDir(IMG_UPLOAD_DIR);
+- if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
++#ifdef FWUPD_SCRIPT
++ if (!activationProgress)
+ {
+- onVerifyFailed();
+- // Stop the activation process, if fieldMode is enabled.
+- if (parent.control::FieldMode::fieldModeEnabled())
++ // Enable systemd signals
++ Activation::subscribeToSystemdSignals();
++ parent.freeSpace(*this);
++
++ activationProgress =
++ std::make_unique<ActivationProgress>(bus, path);
++
++#ifdef WANT_SIGNATURE_VERIFY
++ fs::path uploadDir(IMG_UPLOAD_DIR);
++ if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
+ {
+- return softwareServer::Activation::activation(
+- softwareServer::Activation::Activations::Failed);
++ onVerifyFailed();
++ // Stop the activation process, if fieldMode is enabled.
++ if (parent.control::FieldMode::fieldModeEnabled())
++ {
++ return softwareServer::Activation::activation(
++ softwareServer::Activation::Activations::Failed);
++ }
+ }
+- }
+ #endif
++ flashWrite();
++ }
++ else if (activationProgress->progress() == 100)
++ {
++ error("progress == 100...");
++ if (!redundancyPriority)
++ {
++ redundancyPriority =
++ std::make_unique<RedundancyPriority>(bus, path, *this, 0);
++ }
++
++ // Remove version object from image manager
++ Activation::deleteImageManagerObject();
+
++ // Create active association
++ parent.createActiveAssociation(path);
++
++ return softwareServer::Activation::activation(
++ softwareServer::Activation::Activations::Active);
++ }
++#else // !FWUPD_SCRIPT
+ #ifdef HOST_BIOS_UPGRADE
+ auto purpose = parent.versions.find(versionId)->second->purpose();
+ if (purpose == VersionPurpose::Host)
+@@ -124,7 +154,6 @@ auto Activation::activation(Activations value) -> Activations
+ return softwareServer::Activation::activation(value);
+ }
+ #endif
+-
+ auto versionStr = parent.versions.find(versionId)->second->version();
+
+ if (!minimum_ship_level::verify(versionStr))
+@@ -174,6 +203,7 @@ auto Activation::activation(Activations value) -> Activations
+ return softwareServer::Activation::activation(
+ softwareServer::Activation::Activations::Active);
+ #endif
++#endif // FWUPD_SCRIPT
+ }
+ else
+ {
+diff --git a/meson.build b/meson.build
+index a6ebcc43c0ec..5c7900924959 100644
+--- a/meson.build
++++ b/meson.build
+@@ -59,6 +59,8 @@ conf.set('WANT_SIGNATURE_VERIFY', \
+ get_option('verify-full-signature').enabled())
+ conf.set('WANT_SIGNATURE_FULL_VERIFY', get_option('verify-full-signature').enabled())
+
++conf.set('FWUPD_SCRIPT', get_option('fwupd-script').enabled())
++
+ # Configurable variables
+ conf.set('ACTIVE_BMC_MAX_ALLOWED', get_option('active-bmc-max-allowed'))
+ conf.set_quoted('HASH_FILE_NAME', get_option('hash-file-name'))
+diff --git a/meson_options.txt b/meson_options.txt
+index 4def7f982809..74e757b75f01 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -25,6 +25,9 @@ option('verify-signature', type: 'feature',
+ option('verify-full-signature', type: 'feature',
+ description: 'Enable image full signature validation.')
+
++option('fwupd-script', type: 'feature',
++ description: 'Enable fwupd script support.')
++
+ # Variables
+ option(
+ 'active-bmc-max-allowed', type: 'integer',
+diff --git a/static/flash.cpp b/static/flash.cpp
+index 101828b1ade5..5506a59ac499 100644
+--- a/static/flash.cpp
++++ b/static/flash.cpp
+@@ -22,9 +22,11 @@ namespace updater
+
+ namespace fs = std::filesystem;
+ using namespace phosphor::software::image;
++namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
+
+ void Activation::flashWrite()
+ {
++#ifndef FWUPD_SCRIPT
+ // For static layout code update, just put images in /run/initramfs.
+ // It expects user to trigger a reboot and an updater script will program
+ // the image to flash during reboot.
+@@ -36,11 +38,47 @@ void Activation::flashWrite()
+ fs::copy_file(uploadDir / versionId / bmcImage, toPath / bmcImage,
+ fs::copy_options::overwrite_existing);
+ }
++
++#else
++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
++ SYSTEMD_INTERFACE, "StartUnit");
++ method.append("fwupd@" + versionId + ".service", "replace");
++ bus.call_noreply(method);
++#endif
+ }
+
+-void Activation::onStateChanges(sdbusplus::message::message& /*msg*/)
++void Activation::onStateChanges(__attribute__((unused))
++ sdbusplus::message::message& msg)
+ {
+- // Empty
++#ifndef FWUPD_SCRIPT
++ uint32_t newStateID{};
++ sdbusplus::message::object_path newStateObjPath;
++ std::string newStateUnit{};
++ std::string newStateResult{};
++
++ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
++
++ auto rwServiceFile = "fwupdw@" + versionId + ".service";
++
++ if (newStateUnit == rwServiceFile && newStateResult == "done")
++ {
++ activationProgress->progress(100);
++ }
++
++ if (newStateUnit == rwServiceFile)
++ {
++ if (newStateResult == "failed" || newStateResult == "dependency")
++ {
++ Activation::activation(
++ softwareServer::Activation::Activations::Failed);
++ }
++ else
++ {
++ Activation::activation(
++ softwareServer::Activation::Activations::Activating);
++ }
++ }
++#endif
+ }
+
+ } // namespace updater
+diff --git a/ubi/flash.cpp b/ubi/flash.cpp
+index a263bfb81116..c58eefc4ec48 100644
+--- a/ubi/flash.cpp
++++ b/ubi/flash.cpp
+@@ -15,13 +15,10 @@ void Activation::flashWrite()
+ {
+ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+- std::string rwServiceFile =
+- "obmc-flash-bmc-ubirw@" + versionId + ".service";
+- method.append(rwServiceFile, "replace");
++ method.append("obmc-flash-bmc-ubirw.service", "replace");
+ bus.call_noreply(method);
+
+- std::string roServiceFile =
+- "obmc-flash-bmc-ubiro@" + versionId + ".service";
++ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+ method.append(roServiceFile, "replace");
+@@ -40,7 +37,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg)
+ // Read the msg and populate each variable
+ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+- auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service";
++ auto rwServiceFile = "obmc-flash-bmc-ubirw.service";
+ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ auto ubootVarsServiceFile =
+ "obmc-flash-bmc-updateubootvars@" + versionId + ".service";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch
new file mode 100644
index 000000000..1f2a86fb9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch
@@ -0,0 +1,44 @@
+From 9b3c44e9fb3d907c0152f14b967e23ab964c0e0b Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Thu, 14 Feb 2019 14:54:45 -0800
+Subject: [PATCH 6/6] Modify the ID of software image updater object on DBus to
+ allow force update onto same version image
+
+In the original design of image update, it does not allow the same version of image to be flashed onto itself.
+But this blocks validation tests and in most of the cases we don't prevent user from doing such update.
+
+This patch appends a random number after the version ID hash string to unblock such limitation.
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: I16aba4804ae1bc2e8784320f91c0419fb8b23c35
+---
+ image_manager.cpp | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/image_manager.cpp b/image_manager.cpp
+index 5b2ff49..e3d26e3 100644
+--- a/image_manager.cpp
++++ b/image_manager.cpp
+@@ -9,6 +9,7 @@
+ #include <stdlib.h>
+ #include <sys/stat.h>
+ #include <sys/wait.h>
++#include <time.h>
+ #include <unistd.h>
+
+ #include <elog-errors.hpp>
+@@ -174,6 +175,11 @@ int Manager::processImage(const std::string& tarFilePath)
+ // Compute id
+ auto id = Version::getId(version);
+
++ // Append a random number after the original version hash
++ // This will allow forcing image update onto the same version
++ srand(time(NULL));
++ id = id + "_" + std::to_string(rand());
++
+ fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
+ imageDirPath /= id;
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch
new file mode 100644
index 000000000..6039be44b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch
@@ -0,0 +1,76 @@
+From c2ae3ac444f7a5e9674a82f47086874f947bcec6 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+Date: Thu, 5 Dec 2019 12:38:21 +0530
+Subject: [PATCH] Adding StandBySpare for firmware activation
+
+Added new states 'StandBySpare', 'ActivatingAsStandbySpare' for
+firmware activation. If the uploaded firmware image is for
+backup/recovery, then it sets the "StandBySpare" value for
+Activations. When backup/recovery image is in activating state,
+then activations will be set to "ActivatingAsStandbySpare".
+
+Tested:
+Tested using redfish interface.
+Did the GET on "/redfish/v1/UpdateService/FirmwareInventory/<backup image>"
+Response:
+ ....
+ "Status": {
+ "Health": "OK",
+ "HealthRollup": "OK",
+ "State": "StandbySpare"
+ }
+.......
+
+Change-Id: I7f1608fac3196774a6d593b6128d58da3f5c88fc
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+---
+ activation.cpp | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/activation.cpp b/activation.cpp
+index 2966b2f..a098784 100644
+--- a/activation.cpp
++++ b/activation.cpp
+@@ -81,12 +81,16 @@ void Activation::unsubscribeFromSystemdSignals()
+ auto Activation::activation(Activations value) -> Activations
+ {
+ if ((value != softwareServer::Activation::Activations::Active) &&
+- (value != softwareServer::Activation::Activations::Activating))
++ (value != softwareServer::Activation::Activations::Activating) &&
++ (value !=
++ softwareServer::Activation::Activations::ActivatingAsStandbySpare))
+ {
+ redundancyPriority.reset(nullptr);
+ }
+
+- if (value == softwareServer::Activation::Activations::Activating)
++ if (value == softwareServer::Activation::Activations::Activating ||
++ value ==
++ softwareServer::Activation::Activations::ActivatingAsStandbySpare)
+ {
+ #ifdef FWUPD_SCRIPT
+ if (!activationProgress)
+@@ -309,6 +313,20 @@ auto Activation::requestedActivation(RequestedActivations value)
+ softwareServer::Activation::Activations::Activating);
+ }
+ }
++ else if ((value ==
++ softwareServer::Activation::RequestedActivations::StandbySpare) &&
++ (softwareServer::Activation::requestedActivation() !=
++ softwareServer::Activation::RequestedActivations::StandbySpare))
++ {
++ if ((softwareServer::Activation::activation() ==
++ softwareServer::Activation::Activations::Ready) ||
++ (softwareServer::Activation::activation() ==
++ softwareServer::Activation::Activations::Failed))
++ {
++ Activation::activation(softwareServer::Activation::Activations::
++ ActivatingAsStandbySpare);
++ }
++ }
+ return softwareServer::Activation::requestedActivation(value);
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch
new file mode 100644
index 000000000..e1a7f1746
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch
@@ -0,0 +1,411 @@
+From 51fd06346ff492d5d4862886cb34e024d05edb45 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Tue, 13 Aug 2019 22:43:12 +0530
+Subject: [PATCH] PFR images support in phosphor-software-manager
+
+This commit adds support for handling the PFR images
+upload and processing.
+
+Testing:
+tested PFR image uploads and updates
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+
+---
+ item_updater.cpp | 7 +-
+ meson.build | 8 +-
+ meson_options.txt | 3 +
+ pfr_image_manager.cpp | 218 ++++++++++++++++++++++++++++++++++++++++++
+ pfr_image_manager.hpp | 76 +++++++++++++++
+ 5 files changed, 308 insertions(+), 4 deletions(-)
+ create mode 100644 pfr_image_manager.cpp
+ create mode 100644 pfr_image_manager.hpp
+
+diff --git a/item_updater.cpp b/item_updater.cpp
+index 81fc01f..60e7d23 100644
+--- a/item_updater.cpp
++++ b/item_updater.cpp
+@@ -65,10 +65,10 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg)
+ auto value = SVersion::convertVersionPurposeFromString(
+ std::get<std::string>(property.second));
+ if (value == VersionPurpose::BMC ||
+-#ifdef HOST_BIOS_UPGRADE
++#if defined(HOST_BIOS_UPGRADE) || defined(PFR_UPDATE)
+ value == VersionPurpose::Host ||
+ #endif
+- value == VersionPurpose::System)
++ value == VersionPurpose::Other)
+ {
+ purpose = value;
+ }
+@@ -414,6 +414,7 @@ void ItemUpdater::deleteAll()
+ ItemUpdater::ActivationStatus
+ ItemUpdater::validateSquashFSImage(const std::string& filePath)
+ {
++#ifndef PFR_UPDATE
+ bool valid = true;
+
+ // Record the images which are being updated
+@@ -431,7 +432,7 @@ ItemUpdater::ActivationStatus
+ return ItemUpdater::ActivationStatus::invalid;
+ }
+ }
+-
++#endif
+ return ItemUpdater::ActivationStatus::ready;
+ }
+
+diff --git a/meson.build b/meson.build
+index 5c79009..e33998d 100644
+--- a/meson.build
++++ b/meson.build
+@@ -60,6 +60,7 @@ conf.set('WANT_SIGNATURE_VERIFY', \
+ conf.set('WANT_SIGNATURE_FULL_VERIFY', get_option('verify-full-signature').enabled())
+
+ conf.set('FWUPD_SCRIPT', get_option('fwupd-script').enabled())
++conf.set('PFR_UPDATE', get_option('pfr-update').enabled())
+
+ # Configurable variables
+ conf.set('ACTIVE_BMC_MAX_ALLOWED', get_option('active-bmc-max-allowed'))
+@@ -205,12 +206,17 @@ executable(
+ install: true
+ )
+
++image_manager_source = files('image_manager.cpp')
++if get_option('pfr-update').enabled()
++ image_manager_source = files('pfr_image_manager.cpp')
++endif
++
+ executable(
+ 'phosphor-version-software-manager',
+ image_error_cpp,
+ image_error_hpp,
+- 'image_manager.cpp',
+ 'image_manager_main.cpp',
++ image_manager_source,
+ 'version.cpp',
+ 'watch.cpp',
+ dependencies: [deps, ssl],
+diff --git a/meson_options.txt b/meson_options.txt
+index da257b7..2204e04 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -28,6 +28,9 @@ option('verify-full-signature', type: 'feature',
+ option('fwupd-script', type: 'feature',
+ description: 'Enable fwupd script support.')
+
++option('pfr-update', type: 'feature',
++ description: 'Enable PFR image support.')
++
+ # Variables
+ option(
+ 'active-bmc-max-allowed', type: 'integer',
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+new file mode 100644
+index 0000000..fec1e94
+--- /dev/null
++++ b/pfr_image_manager.cpp
+@@ -0,0 +1,218 @@
++#include "config.h"
++
++#include "pfr_image_manager.hpp"
++
++#include "version.hpp"
++#include "watch.hpp"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/stat.h>
++#include <sys/wait.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <elog-errors.hpp>
++#include <xyz/openbmc_project/Software/Image/error.hpp>
++
++#include <algorithm>
++#include <cstring>
++#include <filesystem>
++#include <fstream>
++#include <iomanip>
++#include <sstream>
++#include <string>
++
++namespace phosphor
++{
++namespace software
++{
++namespace manager
++{
++
++using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error;
++namespace Software = phosphor::logging::xyz::openbmc_project::Software;
++
++static constexpr const uint32_t pfmPos = 2054;
++
++static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
++ std::string& version)
++{
++ struct pfrImgBlock0 block0Data;
++ uint8_t verData[2];
++
++ if (std::filesystem::exists(imgPath))
++ {
++ try
++ {
++ std::ifstream imgFile(imgPath, std::ios::binary | std::ios::in);
++
++ if (!imgFile.good())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image file read failed");
++ return -1;
++ }
++
++ imgFile.read(reinterpret_cast<char*>(&block0Data),
++ sizeof(block0Data));
++ imgType = block0Data.pcType[0];
++ imgFile.seekg(pfmPos,
++ std::ios::beg); // Version is at 0x806 in the PFM
++ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData));
++ imgFile.close();
++ version =
++ std::to_string(verData[0]) + "." + std::to_string(verData[1]);
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "PFR image",
++ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]),
++ phosphor::logging::entry("VERSION=%s", version.c_str()));
++ }
++ catch (std::exception& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++int Manager::processImage(const std::string& imgFilePath)
++{
++ std::filesystem::path imgPath(imgFilePath);
++
++ if (!std::filesystem::exists(imgPath))
++ return -1;
++
++ uint8_t imgType;
++ int retry = 3;
++ std::string ver;
++ std::string purposeString;
++
++ if (0 != getPFRImgInfo(imgFilePath, imgType, ver))
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error reading uploaded image type and version");
++ return -1;
++ }
++
++ if (ver.empty())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Empty version from image file");
++ return -1;
++ }
++
++ if (imgType == pfrBMCUpdateCap)
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
++ }
++ else if (imgType == pfrPCHUpdateCap)
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
++ }
++ else if (imgType == pfrCPLDUpdateCap)
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
++ }
++ else
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown";
++
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unknown image type");
++ return -1;
++ }
++
++ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
++ purpose = Version::VersionPurpose::Unknown;
++ try
++ {
++ purpose = Version::convertVersionPurposeFromString(purposeString);
++ }
++ catch (const sdbusplus::exception::InvalidEnumString& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error: Failed to convert purpose to enum."
++ " Setting to Unknown.");
++ }
++
++ // Compute id
++ std::string id = Version::getId(ver);
++
++ // Append a random number after the original version hash
++ // This will allow forcing image update onto the same version
++ // with 3 retries on random number generation.
++ do
++ {
++ srand(time(NULL));
++ id = id + "_" + std::to_string(rand());
++ } while ((versions.find(id) != versions.end()) && retry--);
++
++ if (versions.find(id) != versions.end())
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Software Object with the same version already exists, exiting "
++ "the update",
++ phosphor::logging::entry("VERSION_ID=%s", id.c_str()));
++
++ return -1;
++ }
++
++ std::filesystem::path imageDirPath(IMG_UPLOAD_DIR);
++ imageDirPath /= id;
++
++ std::filesystem::create_directory(imageDirPath);
++
++ std::filesystem::path newFileName = imageDirPath / "image-runtime";
++ std::filesystem::rename(imgFilePath, newFileName);
++
++ // Create Version object
++ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
++
++ auto versionPtr = std::make_unique<Version>(
++ bus, objPath, ver, purpose, imageDirPath.string(),
++ std::bind(&Manager::erase, this, std::placeholders::_1));
++ versionPtr->deleteObject =
++ std::make_unique<phosphor::software::manager::Delete>(bus, objPath,
++ *versionPtr);
++ versions.insert(std::make_pair(id, std::move(versionPtr)));
++
++ return 0;
++}
++
++void Manager::erase(std::string entryId)
++{
++ auto it = versions.find(entryId);
++ if (it == versions.end())
++ {
++ return;
++ }
++
++ if (it->second->isFunctional())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ ("Error: Version " + entryId +
++ " is currently running on the BMC."
++ " Unable to remove.")
++ .c_str());
++ return;
++ }
++
++ // Delete image dir
++ std::filesystem::path imageDirPath = (*(it->second)).path();
++ if (std::filesystem::exists(imageDirPath))
++ {
++ std::filesystem::remove_all(imageDirPath);
++ }
++ this->versions.erase(entryId);
++}
++
++} // namespace manager
++} // namespace software
++} // namespace phosphor
+diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp
+new file mode 100644
+index 0000000..b9a5822
+--- /dev/null
++++ b/pfr_image_manager.hpp
+@@ -0,0 +1,76 @@
++#pragma once
++#include "version.hpp"
++
++#include <sdbusplus/server.hpp>
++
++namespace phosphor
++{
++namespace software
++{
++namespace manager
++{
++
++enum pfrImgPCType
++{
++ pfrCPLDUpdateCap = 0x00,
++ pfrPCHPFM = 0x01,
++ pfrPCHUpdateCap = 0x02,
++ pfrBMCPFM = 0x03,
++ pfrBMCUpdateCap = 0x04
++};
++
++/* PFR image block 0 - As defined in HAS */
++struct pfrImgBlock0
++{
++ uint8_t tag[4];
++ uint8_t pcLength[4];
++ uint8_t pcType[4];
++ uint8_t reserved1[4];
++ uint8_t hash256[32];
++ uint8_t hash384[48];
++ uint8_t reserved2[32];
++} __attribute__((packed));
++
++/** @class Manager
++ * @brief Contains a map of Version dbus objects.
++ * @details The software image manager class that contains the Version dbus
++ * objects and their version ids.
++ */
++class Manager
++{
++ public:
++ /** @brief Constructs Manager Class
++ *
++ * @param[in] bus - The Dbus bus object
++ */
++ Manager(sdbusplus::bus::bus& bus) : bus(bus){};
++
++ /**
++ * @brief Verify the image and provide the image to updater.
++ * Create and populate the version and file path interfaces.
++ *
++ * @param[in] uploaded image.
++ * @param[out] result - 0 if successful.
++ */
++ int processImage(const std::string& imageFilePath);
++
++ /**
++ * @brief Erase specified entry d-bus object
++ * and deletes the image file.
++ *
++ * @param[in] entryId - unique identifier of the entry
++ */
++ void erase(std::string entryId);
++
++ private:
++ /** @brief Persistent map of Version dbus objects and their
++ * version id */
++ std::map<std::string, std::unique_ptr<Version>> versions;
++
++ /** @brief Persistent sdbusplus DBus bus connection. */
++ sdbusplus::bus::bus& bus;
++};
++
++} // namespace manager
++} // namespace software
++} // namespace phosphor
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch
new file mode 100644
index 000000000..72eb0beba
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch
@@ -0,0 +1,415 @@
+From ac6e0c217a1b136d82f93b691aff1acb40009f26 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+Date: Thu, 5 Dec 2019 11:55:36 +0530
+Subject: [PATCH] PFR image HASH verification
+
+This adds HASH verification on PFR images uploaded for
+firmware updates
+
+Tested: tested firmware update with good and bad HASH images.
+
+A)
+1. Upload the corrupted image for fw update.
+2. Image present in /tmp/images/
+-rw-r--r-- 1 root root 22969344 Jun 3 09:27
+5dea710b-8b85-4065-8af7-3149ada81edf
+
+3. Journalctl logs during image verification
+Jun 03 09:27:20 intel-obmc phosphor-version-software-manager[4755]:
+Firmware image HASH verification failed
+Jun 03 09:27:20 intel-obmc phosphor-version-software-manager[4755]:
+Error verifying uploaded image
+Jun 03 09:27:20 intel-obmc phosphor-version-software-manager[4755]:
+Error processing image
+
+4. image deleted from /tmp/images/
+
+B)
+1. Upload the correct image.
+POST: https://<BMC_IP>/redfish/v1/UpdateService/
+ with <BMC_signed_cap> binary file
+2. Image verification is success and proceeds with update.
+{
+ "@odata.id": "/redfish/v1/TaskService/Tasks/0",
+ "@odata.type": "#Task.v1_4_3.Task",
+ "Id": "0",
+ "TaskState": "Running",
+ "TaskStatus": "OK"
+}
+
+Change-Id: I9336980bfb74c8136690024782bfef45f6b08d56
+Signed-off-by: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com>
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+---
+ pfr_image_manager.cpp | 150 +++++++++++++++++++++++++++++++++----------
+ pfr_image_manager.hpp | 112 +++++++++++++++++++++++++++++--
+ 2 files changed, 222 insertions(+), 40 deletions(-)
+
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index 242a6ca..1a41cbe 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -5,6 +5,8 @@
+ #include "version.hpp"
+ #include "watch.hpp"
+
++#include <fcntl.h>
++#include <openssl/err.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/stat.h>
+@@ -20,6 +22,7 @@
+ #include <filesystem>
+ #include <fstream>
+ #include <iomanip>
++#include <set>
+ #include <sstream>
+ #include <string>
+
+@@ -34,12 +37,21 @@ using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error;
+ namespace Software = phosphor::logging::xyz::openbmc_project::Software;
+
+ static constexpr const uint32_t pfmPos = 2054;
++static constexpr const uint32_t block0Magic = 0xB6EAFD19;
++static constexpr const uint32_t lengthBlk0Blk1 = 1024;
+
+-static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
+- std::string& version)
++int Manager::verifyPFRImage(const std::filesystem::path imgPath,
++ std::string& version, std::string& purposeString)
+ {
+- struct pfrImgBlock0 block0Data;
+- uint8_t verData[2];
++ uint8_t imgType = 0;
++ uint32_t imgMagic = 0;
++ uint8_t verData[2] = {0};
++ uint32_t hashLen = 0;
++ struct pfrImgBlock0 block0Data = {};
++
++ std::string imageName;
++
++ EVP_MD_CTX* ctx;
+
+ if (std::filesystem::exists(imgPath))
+ {
+@@ -56,17 +68,101 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
+
+ imgFile.read(reinterpret_cast<char*>(&block0Data),
+ sizeof(block0Data));
++
++ imgMagic = block0Data.tag;
++
++ if (imgMagic != block0Magic)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image magic number match failed",
++ phosphor::logging::entry("IMAGEMAGIC=0x%x", imgMagic));
++ return -1;
++ }
++
+ imgType = block0Data.pcType[0];
++
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Image Type", phosphor::logging::entry(
++ "IMAGETYPE=0x%x", static_cast<int>(imgType)));
++
++ if (imgType == pfrBMCUpdateCap || imgType == pfrBMCPFM)
++ {
++ imageName = "BMC";
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
++ }
++ else if (imgType == pfrPCHUpdateCap || imgType == pfrPCHPFM)
++ {
++ imageName = "BIOS";
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
++ }
++ else if (imgType == pfrCPLDUpdateCap)
++ {
++ imageName = "CPLD";
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
++ }
++ else
++ {
++ purposeString = "xyz.openbmc_project.Software.Version."
++ "VersionPurpose.Unknown";
++
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unknown image type");
++ return -1;
++ }
++
+ imgFile.seekg(pfmPos,
+ std::ios::beg); // Version is at 0x806 in the PFM
+ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData));
+ imgFile.close();
+- version =
+- std::to_string(verData[0]) + "." + std::to_string(verData[1]);
++
++ auto size = std::filesystem::file_size(imgPath);
++
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Image Size", phosphor::logging::entry("IMAGESIZE=0x%x",
++ static_cast<int>(size)));
++
++ // Adds all digest algorithms to the internal table
++ OpenSSL_add_all_digests();
++
++ ctx = EVP_MD_CTX_create();
++ EVP_DigestInit(ctx, EVP_sha256());
++
++ // Hash the image file and update the digest
++ auto dataPtr = mapFile(imgPath, size);
++
++ EVP_DigestUpdate(ctx, ((uint8_t*)dataPtr() + lengthBlk0Blk1),
++ (size - lengthBlk0Blk1));
++
++ std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
++ std::vector<uint8_t> expectedDigest(block0Data.hash256,
++ &block0Data.hash256[0] + 32);
++
++ EVP_DigestFinal(ctx, digest.data(), &hashLen);
++ EVP_MD_CTX_destroy(ctx);
++
++ std::string redfishMsgID = "OpenBMC.0.1";
++
++ if (expectedDigest != digest)
++ {
++ redfishMsgID += ".GeneralFirmwareSecurityViolation";
++ sd_journal_send("MESSAGE=%s",
++ "Firmware image HASH verification failed",
++ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s",
++ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s",
++ "Image HASH check fail", NULL);
++ return -1;
++ }
++
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "PFR image",
+ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]),
+ phosphor::logging::entry("VERSION=%s", version.c_str()));
++
++ version =
++ std::to_string(verData[0]) + "." + std::to_string(verData[1]);
+ }
+ catch (std::exception& e)
+ {
+@@ -80,20 +176,21 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
+
+ int Manager::processImage(const std::string& imgFilePath)
+ {
++
+ std::filesystem::path imgPath(imgFilePath);
+
+ if (!std::filesystem::exists(imgPath))
+ return -1;
+
+- uint8_t imgType;
+ int retry = 3;
+ std::string ver;
+ std::string purposeString;
+
+- if (0 != getPFRImgInfo(imgFilePath, imgType, ver))
++ if (0 != verifyPFRImage(imgFilePath, ver, purposeString))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+- "Error reading uploaded image type and version");
++ "Error verifying uploaded image");
++ std::filesystem::remove_all(imgFilePath);
+ return -1;
+ }
+
+@@ -104,31 +201,6 @@ int Manager::processImage(const std::string& imgFilePath)
+ return -1;
+ }
+
+- if (imgType == pfrBMCUpdateCap)
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
+- }
+- else if (imgType == pfrPCHUpdateCap)
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
+- }
+- else if (imgType == pfrCPLDUpdateCap)
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
+- }
+- else
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown";
+-
+- phosphor::logging::log<phosphor::logging::level::ERR>(
+- "Unknown image type");
+- return -1;
+- }
+-
+ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
+ purpose = Version::VersionPurpose::Unknown;
+ try
+@@ -170,6 +242,7 @@ int Manager::processImage(const std::string& imgFilePath)
+ std::filesystem::create_directory(imageDirPath);
+
+ std::filesystem::path newFileName = imageDirPath / "image-runtime";
++
+ std::filesystem::rename(imgFilePath, newFileName);
+
+ // Create Version object
+@@ -213,6 +286,14 @@ void Manager::erase(std::string entryId)
+ this->versions.erase(entryId);
+ }
+
++CustomMap Manager::mapFile(const std::filesystem::path& path, size_t size)
++{
++
++ CustomFd fd(open(path.c_str(), O_RDONLY));
++
++ return CustomMap(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd(), 0),
++ size);
++}
+ } // namespace manager
+ } // namespace software
+ } // namespace phosphor
+diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp
+index c6ee6a4..5b7b2c3 100644
+--- a/pfr_image_manager.hpp
++++ b/pfr_image_manager.hpp
+@@ -1,8 +1,16 @@
+ #pragma once
+ #include "version.hpp"
+
++#include <openssl/evp.h>
++#include <openssl/pem.h>
++#include <openssl/rsa.h>
++#include <sys/mman.h>
++#include <unistd.h>
++
+ #include <sdbusplus/server.hpp>
+
++#include <filesystem>
++
+ namespace phosphor
+ {
+ namespace software
+@@ -22,7 +30,7 @@ enum pfrImgPCType
+ /* PFR image block 0 - As defined in HAS */
+ struct pfrImgBlock0
+ {
+- uint8_t tag[4];
++ uint32_t tag;
+ uint8_t pcLength[4];
+ uint8_t pcType[4];
+ uint8_t reserved1[4];
+@@ -31,6 +39,82 @@ struct pfrImgBlock0
+ uint8_t reserved2[32];
+ } __attribute__((packed));
+
++/** @struct CustomFd
++ *
++ * RAII wrapper for file descriptor.
++ */
++struct CustomFd
++{
++ public:
++ CustomFd() = delete;
++ CustomFd(const CustomFd&) = delete;
++ CustomFd& operator=(const CustomFd&) = delete;
++ CustomFd(CustomFd&&) = default;
++ CustomFd& operator=(CustomFd&&) = default;
++ /** @brief Saves File descriptor and uses it to do file operation
++ *
++ * @param[in] fd - File descriptor
++ */
++ CustomFd(int fd) : fd(fd)
++ {}
++
++ ~CustomFd()
++ {
++ if (fd >= 0)
++ {
++ close(fd);
++ }
++ }
++
++ int operator()() const
++ {
++ return fd;
++ }
++
++ private:
++ /** @brief File descriptor */
++ int fd = -1;
++};
++
++/** @struct CustomMap
++ *
++ * RAII wrapper for mmap.
++ */
++struct CustomMap
++{
++ private:
++ /** @brief starting address of the map */
++ void* addr;
++
++ /** @brief length of the mapping */
++ size_t length;
++
++ public:
++ CustomMap() = delete;
++ CustomMap(const CustomMap&) = delete;
++ CustomMap& operator=(const CustomMap&) = delete;
++ CustomMap(CustomMap&&) = default;
++ CustomMap& operator=(CustomMap&&) = default;
++
++ /** @brief Saves starting address of the map and
++ * and length of the file.
++ * @param[in] addr - Starting address of the map
++ * @param[in] length - length of the map
++ */
++ CustomMap(void* addr, size_t length) : addr(addr), length(length)
++ {}
++
++ ~CustomMap()
++ {
++ munmap(addr, length);
++ }
++
++ void* operator()() const
++ {
++ return addr;
++ }
++};
++
+ /** @class Manager
+ * @brief Contains a map of Version dbus objects.
+ * @details The software image manager class that contains the Version dbus
+@@ -63,6 +147,22 @@ class Manager
+ void erase(std::string entryId);
+
+ private:
++ /**
++ * @brief Memory map the file
++ * @param[in] - file path
++ * @param[in] - file size
++ * @param[out] - Custom Mmap address
++ */
++ CustomMap mapFile(const std::filesystem::path& path, size_t size);
++
++ /**
++ * @brief Verify the PFR image and return version and purpose
++ * @param[in] - file path
++ * @param[out] - version
++ * @param[out] - purpose
++ */
++ int verifyPFRImage(const std::filesystem::path imgPath,
++ std::string& version, std::string& purposeString);
+ /** @brief Persistent map of Version dbus objects and their
+ * version id */
+ std::map<std::string, std::unique_ptr<Version>> versions;
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch
new file mode 100644
index 000000000..e0ff79795
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch
@@ -0,0 +1,50 @@
+From d9e50ecf8bd8bc764838e7244084184644a3f0fc Mon Sep 17 00:00:00 2001
+From: Chalapathi <chalapathix.venkataramashetty@intel.com>
+Date: Thu, 23 Apr 2020 19:06:19 +0000
+Subject: [PATCH] item_updater: update the bmc_active objectPath
+
+Update the Software object path to bmc_active instead of random Id.
+
+Signed-off-by: Chalapathi <chalapathix.venkataramashetty@intel.com>
+
+---
+ item_updater.cpp | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/item_updater.cpp b/item_updater.cpp
+index e6dd298..c3a846d 100644
+--- a/item_updater.cpp
++++ b/item_updater.cpp
+@@ -175,7 +175,8 @@ void ItemUpdater::processBMCImage()
+ if (0 ==
+ iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX))
+ {
+- // Get the version to calculate the id
++ std::string id = "bmc_active";
++ // upstream changed this to relative_path ... is that right?
+ fs::path releaseFile(OS_RELEASE_FILE);
+ auto osRelease = iter.path() / releaseFile.relative_path();
+ if (!fs::is_regular_file(osRelease))
+@@ -189,7 +190,6 @@ void ItemUpdater::processBMCImage()
+ // volumes created by the UBI layout for example have the id in
+ // the mount directory name. The worst that can happen is that
+ // erase() is called with an non-existent id and returns.
+- auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
+ ItemUpdater::erase(id);
+
+ continue;
+@@ -203,14 +203,11 @@ void ItemUpdater::processBMCImage()
+
+ // Try to delete the version, same as above if the
+ // OS_RELEASE_FILE does not exist.
+- auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
+ ItemUpdater::erase(id);
+
+ continue;
+ }
+
+- auto id = VersionClass::getId(version);
+-
+ // Check if the id has already been added. This can happen if the
+ // BMC partitions / devices were manually flashed with the same
+ // image.
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch
new file mode 100644
index 000000000..f150c1027
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch
@@ -0,0 +1,44 @@
+From 76f169e71be10b50b9617e606c38aff9553e6de8 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Fri, 15 May 2020 21:17:08 +0530
+Subject: [PATCH] Add ApplyOptions D-bus property under Software
+
+This change adds the ApplyOptions D-bus property
+under xyz.openbmc_project.Software.BMC.Updater.
+ApplyOptions is needed for BIOS NVRAM clear during
+BIOS firmware update. ClearConfig attribute is passed
+from RF to fwupd script.
+
+Tested: Set and Get of ClearConfig from fwupd.sh works
+ fine.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ item_updater.hpp | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/item_updater.hpp b/item_updater.hpp
+index 3f0530f..5c1a779 100644
+--- a/item_updater.hpp
++++ b/item_updater.hpp
+@@ -9,6 +9,7 @@
+ #include <xyz/openbmc_project/Association/Definitions/server.hpp>
+ #include <xyz/openbmc_project/Common/FactoryReset/server.hpp>
+ #include <xyz/openbmc_project/Control/FieldMode/server.hpp>
++#include <xyz/openbmc_project/Software/ApplyOptions/server.hpp>
+
+ #include <string>
+ #include <vector>
+@@ -24,7 +25,8 @@ using ItemUpdaterInherit = sdbusplus::server::object::object<
+ sdbusplus::xyz::openbmc_project::Common::server::FactoryReset,
+ sdbusplus::xyz::openbmc_project::Control::server::FieldMode,
+ sdbusplus::xyz::openbmc_project::Association::server::Definitions,
+- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>;
++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll,
++ sdbusplus::xyz::openbmc_project::Software::server::ApplyOptions>;
+
+ namespace MatchRules = sdbusplus::bus::match::rules;
+ using VersionClass = phosphor::software::manager::Version;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch
new file mode 100644
index 000000000..e72398efd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch
@@ -0,0 +1,190 @@
+From ffa3642e436b559d8062f777f00458cc7b5ecb01 Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Thu, 11 Jun 2020 13:30:02 -0700
+Subject: [PATCH 1/1] Add error reporting to pfr_image_manager
+
+This uses report functionality to update error
+return status for redfish updates.
+
+Tested: Got 400 error with different messages based
+on failure type
+
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
+ "Message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid archive.",
+ "MessageArgs": [
+ "/redfish/v1/UpdateService",
+ "invalid archive"
+ ],
+ "MessageId": "OpenBMC.0.1.0.InvalidFile",
+ "Resolution": "None.",
+ "Severity": "Warning"
+ }
+ ],
+ "code": "OpenBMC.0.1.0.InvalidFile",
+ "message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid archive."
+ }
+}
+
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
+ "Message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid image format.",
+ "MessageArgs": [
+ "/redfish/v1/UpdateService",
+ "invalid image format"
+ ],
+ "MessageId": "OpenBMC.0.1.0.InvalidFile",
+ "Resolution": "None.",
+ "Severity": "Warning"
+ }
+ ],
+ "code": "OpenBMC.0.1.0.InvalidFile",
+ "message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid image format."
+ }
+}
+
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "#Message.v1_0_0.Message",
+ "Message": "The resource /redfish/v1/UpdateService was unable to satisfy the request due to unavailability of resources.",
+ "MessageArgs": [
+ "/redfish/v1/UpdateService"
+ ],
+ "MessageId": "Base.1.4.0.ResourceExhaustion",
+ "Resolution": "Ensure that the resources are available and resubmit the request.",
+ "Severity": "Critical"
+ }
+ ],
+ "code": "Base.1.4.0.ResourceExhaustion",
+ "message": "The resource /redfish/v1/UpdateService was unable to satisfy the request due to unavailability of resources."
+ }
+}
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ dbus_helpers.hpp | 30 ++++++++++++++++++++++++++++++
+ pfr_image_manager.cpp | 18 ++++++++++++++++++
+ 2 files changed, 48 insertions(+)
+ create mode 100644 dbus_helpers.hpp
+
+diff --git a/dbus_helpers.hpp b/dbus_helpers.hpp
+new file mode 100644
+index 0000000..b9ffa36
+--- /dev/null
++++ b/dbus_helpers.hpp
+@@ -0,0 +1,30 @@
++#pragma once
++
++#include "config.h"
++
++#include <sdbusplus/bus.hpp>
++inline bool isFwupdScriptRunning(sdbusplus::bus::bus& bus)
++{
++ using ObjectPath = sdbusplus::message::object_path;
++ // type is ssssssouso
++ using ListUnitsType =
++ std::tuple<std::string, std::string, std::string, std::string,
++ std::string, std::string, ObjectPath, uint32_t, std::string,
++ ObjectPath>;
++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
++ SYSTEMD_INTERFACE, "ListUnits");
++
++ auto reply = bus.call(method);
++ std::vector<ListUnitsType> resp;
++ reply.read(resp);
++
++ for (const auto& unit : resp)
++ {
++ if (std::get<0>(unit).find("fwupd@") != std::string::npos &&
++ std::get<3>(unit) != "failed")
++ {
++ return true;
++ }
++ }
++ return false;
++}
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index 1a41cbe..fe1e6f9 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -2,6 +2,7 @@
+
+ #include "pfr_image_manager.hpp"
+
++#include "dbus_helpers.hpp"
+ #include "version.hpp"
+ #include "watch.hpp"
+
+@@ -33,6 +34,9 @@ namespace manager
+
+ using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error;
+ namespace Software = phosphor::logging::xyz::openbmc_project::Software;
++using UnTarFail = Software::Image::UnTarFailure;
++using ImageFail = Software::Image::ImageFailure;
++using BusyFail = Software::Image::BusyFailure;
+
+ static constexpr const uint32_t pfmPos = 2054;
+ static constexpr const uint32_t block0Magic = 0xB6EAFD19;
+@@ -76,6 +80,8 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Image magic number match failed",
+ phosphor::logging::entry("IMAGEMAGIC=0x%x", imgMagic));
++ phosphor::logging::report<UnTarFailure>(
++ UnTarFail::PATH(imgPath.c_str()));
+ return -1;
+ }
+
+@@ -110,6 +116,9 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Unknown image type");
++ phosphor::logging::report<ImageFailure>(
++ ImageFail::FAIL("Unknown image type"),
++ ImageFail::PATH(imgPath.c_str()));
+ return -1;
+ }
+
+@@ -153,6 +162,9 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s",
+ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s",
+ "Image HASH check fail", NULL);
++ phosphor::logging::report<ImageFailure>(
++ ImageFail::FAIL("Security violation: hash mismatch"),
++ ImageFail::PATH(imgPath.c_str()));
+ return -1;
+ }
+
+@@ -167,6 +179,9 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+ catch (std::exception& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ phosphor::logging::report<ImageFailure>(
++ ImageFail::FAIL("Unhandled exception"),
++ ImageFail::PATH(imgPath.c_str()));
+ return -1;
+ }
+ }
+@@ -182,6 +197,12 @@ int Manager::processImage(const std::string& imgFilePath)
+ if (!std::filesystem::exists(imgPath))
+ return -1;
+
++ if (isFwupdScriptRunning(bus))
++ {
++ phosphor::logging::report<BusyFailure>(BusyFail::PATH(imgPath.c_str()));
++ return -1;
++ }
++
+ int retry = 3;
+ std::string ver;
+ std::string purposeString;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch
new file mode 100644
index 000000000..6bbd59918
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch
@@ -0,0 +1,40 @@
+From 0628db177655e6f890c4da8c7de7c3cd7487d528 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Thu, 16 Jul 2020 14:16:28 -0700
+Subject: [PATCH] remove image file on pre-script failures
+
+Multiple back-to-back updates of bad images will cause the software
+manager to leave junk images hanging around. This is part of a fix that
+will remove them if the software manager never gets around to launching
+the fwupd.sh script. The other part is that the fwupd.sh script must
+always delete the image file on exit, success or failure.
+
+Tested: posted a garbage file, saw that it was deleted even though
+ fwupd.sh was never invoked.
+
+Change-Id: I6b049916a3edcb48f9d4ebe0d4715b94214b4feb
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+---
+ watch.cpp | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/watch.cpp b/watch.cpp
+index d6c09a946fd0..5d70edbf52b4 100644
+--- a/watch.cpp
++++ b/watch.cpp
+@@ -106,6 +106,12 @@ int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
+ {
+ error("Error ({RC}) processing image {IMAGE}", "RC", rc,
+ "IMAGE", tarballPath);
++ std::error_code ec{};
++ fs::remove_all(tarballPath, ec);
++ if (!ec)
++ {
++ error("Unable to remove image on processing failure");
++ }
+ }
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch
new file mode 100644
index 000000000..dfc7f2e58
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch
@@ -0,0 +1,116 @@
+From 9d82d53b50769506926dd99273f197a268d68fa3 Mon Sep 17 00:00:00 2001
+From: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com>
+Date: Thu, 30 Jul 2020 09:50:40 +0000
+Subject: [PATCH] PFR-image-verification
+
+Add support verify the complete fw image by using mtd-util repo's
+pfr_authenticate function.
+
+Tested.
+1. Upload the corrupted image.
+POST: https://<BMC_IP>/redfish/v1/UpdateService/
+ with <Corrupted BMC_signed_cap> binary file
+Response:
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
+ "Message": "Invalid file uploaded to /redfish/v1/UpdateService:
+ Invalid image format.",
+ "MessageArgs": [
+ "/redfish/v1/UpdateService",
+ "Invalid image format"
+ ],
+ "MessageId": "OpenBMC.0.1.0.InvalidUpload",
+ "Resolution": "None.",
+ "Severity": "Warning"
+ }
+ ],
+ "code": "OpenBMC.0.1.0.InvalidUpload",
+ "message": "Invalid file uploaded to /redfish/v1/UpdateService:
+ Invalid image format."
+ }
+}
+
+2. Upload the correct image.
+POST: https://<BMC_IP>/redfish/v1/UpdateService/
+ with <BMC_signed_cap> binary file
+
+Image verified and firmware updated.
+{
+ "@odata.id": "/redfish/v1/TaskService/Tasks/0",
+ "@odata.type": "#Task.v1_4_3.Task",
+ "Id": "0",
+ "TaskState": "Running",
+ "TaskStatus": "OK"
+}
+
+Command:
+GET: https://<BMC_IP>/redfish/v1/Systems/system/LogServices/EventLog/
+ Entries
+
+Response:
+{
+ "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/
+ Entries/1596082187",
+ "@odata.type": "#LogEntry.v1_4_0.LogEntry",
+ "Created": "2020-07-30T04:09:47+00:00",
+ "EntryType": "Event",
+ "Id": "1596082187",
+ "Message": "BMC firmware update to version 00.72 completed
+ successfully.",
+ "MessageArgs": [
+ "BMC",
+ "00.72"
+ ],
+ "MessageId": "OpenBMC.0.1.FirmwareUpdateCompleted",
+ "Name": "System Event Log Entry",
+ "Severity": "OK"
+ },
+
+Signed-off-by: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com>
+---
+ pfr_image_manager.cpp | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index eeed4fe..16231fa 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -15,6 +15,7 @@
+ #include <time.h>
+ #include <unistd.h>
+
++#include <boost/process/child.hpp>
+ #include <elog-errors.hpp>
+ #include <xyz/openbmc_project/Software/Image/error.hpp>
+
+@@ -122,6 +123,24 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+ return -1;
+ }
+
++ // Verify the complete image
++ std::string mtdUtilfile = "/usr/bin/mtd-util";
++ std::vector<std::string> mtdUtilCmd = {"p", "a"};
++ mtdUtilCmd.push_back(imgPath);
++
++ boost::process::child execProg(mtdUtilfile, mtdUtilCmd);
++ execProg.wait();
++ if (execProg.exit_code())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image authentication failed");
++ phosphor::logging::report<ImageFailure>(
++ ImageFail::FAIL(
++ "Security violation: image authentication failure"),
++ ImageFail::PATH(imgPath.c_str()));
++ return -1;
++ }
++
+ imgFile.seekg(pfmPos,
+ std::ios::beg); // Version is at 0x806 in the PFM
+ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData));
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch
new file mode 100644
index 000000000..bc94f00af
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch
@@ -0,0 +1,234 @@
+From a78b7a609f58ac82623c357426ef0590d6d76971 Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Mon, 9 Nov 2020 23:04:58 +0530
+Subject: [PATCH] Process PLDM image type
+
+This change is to check whether the image uploaded is of PLDM image
+type based on the PackageHeaderIdentifier check which is a 16 bytes
+uuid field in the pldm package header.
+
+Also, determine image purpose and version.
+Purpose is set to pldm enum type and for version, PackageVersionString
+is concluded based on PackageVersionStringLength value.
+
+Tested:
+- On uploading a pldm image through Redfish. Uuid is identified and
+matched correctly.
+- Purpose and version is given to the image as expected and activation
+intf got added.
+ - verified same with busctl cmd on xyz.openbmc_project.Software.Version
+ and xyz.openbmc_project.Software.BMC.Updater
+- Verified the regular PFR update procedure works
+ - received expected redfish response from postman
+ - verified fwupd.sh script is reached
+
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ item_updater.cpp | 4 +-
+ pfr_image_manager.cpp | 95 +++++++++++++++++++++++++++++++++++++++++--
+ pfr_image_manager.hpp | 6 +--
+ pldm.hpp | 21 ++++++++++
+ 4 files changed, 119 insertions(+), 7 deletions(-)
+ create mode 100644 pldm.hpp
+
+diff --git a/item_updater.cpp b/item_updater.cpp
+index db255d6..7af80e3 100644
+--- a/item_updater.cpp
++++ b/item_updater.cpp
+@@ -67,6 +67,7 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg)
+ #if defined(HOST_BIOS_UPGRADE) || defined(PFR_UPDATE)
+ value == VersionPurpose::Host ||
+ #endif
++ value == VersionPurpose::PLDM ||
+ value == VersionPurpose::Other)
+ {
+ purpose = value;
+@@ -397,7 +398,8 @@ void ItemUpdater::deleteAll()
+ }
+
+ ItemUpdater::ActivationStatus
+- ItemUpdater::validateSquashFSImage(const std::string& filePath)
++ ItemUpdater::validateSquashFSImage(__attribute__((unused))
++ const std::string& filePath)
+ {
+ #ifndef PFR_UPDATE
+ bool valid = true;
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index 178367f..c923494 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -3,6 +3,7 @@
+ #include "pfr_image_manager.hpp"
+
+ #include "dbus_helpers.hpp"
++#include "pldm.hpp"
+ #include "version.hpp"
+ #include "watch.hpp"
+
+@@ -44,9 +45,10 @@ using BusyFail = Software::Image::BusyFailure;
+ static constexpr const uint32_t pfmPos = 2054;
+ static constexpr const uint32_t block0Magic = 0xB6EAFD19;
+ static constexpr const uint32_t lengthBlk0Blk1 = 1024;
++static constexpr const uint32_t pldmMagic = 0xF018878C;
+
+-int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+- std::string& version, std::string& purposeString)
++int Manager::verifyImage(const std::filesystem::path imgPath,
++ std::string& version, std::string& purposeString)
+ {
+ uint8_t imgType = 0;
+ uint32_t imgMagic = 0;
+@@ -76,6 +78,93 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath,
+
+ imgMagic = block0Data.tag;
+
++ if (htobe32(imgMagic) == pldmMagic)
++ {
++ if (!version.empty())
++ {
++ version.clear();
++ }
++
++ imgFile.seekg(0, std::ios_base::end);
++
++ const size_t length = imgFile.tellg();
++ constexpr size_t readBytes = 36;
++
++ if (length < readBytes)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Insufficient file length to read the required "
++ "bytes");
++ return -1;
++ }
++
++ imgFile.seekg(0, std::ios::beg);
++
++ std::array<char, readBytes> buffer = {};
++
++ imgFile.read(
++ buffer.data(),
++ buffer.size()); // read 36 bytes of PLDM Package Header
++
++ if (!imgFile.good())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image file read is not successful");
++ return -1;
++ }
++
++ if (!std::equal(buffer.begin(),
++ buffer.begin() + pldm::headerIdLen,
++ pldm::pldmPkgHeaderId
++ .begin())) // comparing 16 bytes of
++ // PackageHeaderIdentifier field
++ {
++ std::string redfishMsgID =
++ "OpenBMC.0.1.FirmwareUpdateFailed";
++ sd_journal_send(
++ "MESSAGE=%s", "Firmware image verification failed",
++ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s",
++ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s",
++ "PLDM Image package header identifier check fail",
++ NULL);
++
++ return -1;
++ }
++
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Package header identifier matched");
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.PLDM";
++
++ const uint8_t pkgVerStrLen = static_cast<uint8_t>(
++ buffer[35]); // PackageVersionStringLen byte
++
++ imgFile.seekg(readBytes,
++ std::ios::beg); // point to the begin of
++ // PackageVersionString field
++ // i.e. 36th pos
++
++ std::array<char, 255> ver = {};
++ imgFile.read(ver.data(),
++ pkgVerStrLen); // read PackageVersionString bytes
++
++ if (!imgFile.good())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image file read is not successful");
++ return -1;
++ }
++
++ version.assign(ver.data(), pkgVerStrLen);
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Package version string value",
++ phosphor::logging::entry("IMAGE_VERSION=%s",
++ version.c_str()));
++
++ imgFile.close();
++ return 0;
++ }
++
+ if (imgMagic != block0Magic)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+@@ -226,7 +315,7 @@ int Manager::processImage(const std::string& imgFilePath)
+ std::string ver;
+ std::string purposeString;
+
+- if (0 != verifyPFRImage(imgFilePath, ver, purposeString))
++ if (0 != verifyImage(imgFilePath, ver, purposeString))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Error verifying uploaded image");
+diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp
+index 3591f1a..2facfe6 100644
+--- a/pfr_image_manager.hpp
++++ b/pfr_image_manager.hpp
+@@ -156,13 +156,13 @@ class Manager
+ CustomMap mapFile(const std::filesystem::path& path, size_t size);
+
+ /**
+- * @brief Verify the PFR image and return version and purpose
++ * @brief Verify the uploaded image type and return version and purpose
+ * @param[in] - file path
+ * @param[out] - version
+ * @param[out] - purpose
+ */
+- int verifyPFRImage(const std::filesystem::path imgPath,
+- std::string& version, std::string& purposeString);
++ int verifyImage(const std::filesystem::path imgPath, std::string& version,
++ std::string& purposeString);
+ /** @brief Persistent map of Version dbus objects and their
+ * version id */
+ std::map<std::string, std::unique_ptr<Version>> versions;
+diff --git a/pldm.hpp b/pldm.hpp
+new file mode 100644
+index 0000000..edbd6ae
+--- /dev/null
++++ b/pldm.hpp
+@@ -0,0 +1,21 @@
++namespace pldm
++{
++
++struct PldmPkgHeader
++{
++ uint8_t uuid[16]; // PackageHeaderIdentifier
++ uint8_t formatRev; // PackageHeaderFormatRevision
++ uint16_t headerSize; // PackageHeaderSize
++ uint8_t timestamp[13]; // PackageReleaseDateTime
++ uint16_t bitmapLen; // ComponentBitmapBitLength
++ uint8_t verStringType; // PackageVersionStringType
++ uint8_t verStringLen; // PackageVersionStringLength
++} __attribute__((packed));
++
++constexpr size_t headerIdLen = 16;
++
++const std::array<char, headerIdLen> pldmPkgHeaderId = {
++ 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
++ 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02}; // 16 bytes package header
++ // identifier uuid
++} // namespace pldm
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch
new file mode 100644
index 000000000..d21dbd63c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch
@@ -0,0 +1,34 @@
+From 1f3531eff8a05bb5375dea89c1ca9292f69863b0 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 11 Mar 2021 11:42:39 -0800
+Subject: [PATCH] Fix build error
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ pfr_image_manager.cpp | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index f844b8e79565..55ad21f8a3d4 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -333,6 +333,7 @@ int Manager::processImage(const std::string& imgFilePath)
+
+ int retry = 3;
+ std::string ver;
++ std::string extVer;
+ std::string purposeString;
+
+ if (0 != verifyImage(imgFilePath, ver, purposeString))
+@@ -398,7 +399,7 @@ int Manager::processImage(const std::string& imgFilePath)
+ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
+
+ auto versionPtr = std::make_unique<Version>(
+- bus, objPath, ver, purpose, imageDirPath.string(),
++ bus, objPath, ver, purpose, extVer, imageDirPath.string(),
+ std::bind(&Manager::erase, this, std::placeholders::_1));
+ versionPtr->deleteObject =
+ std::make_unique<phosphor::software::manager::Delete>(bus, objPath,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch
new file mode 100644
index 000000000..0b2026c92
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch
@@ -0,0 +1,171 @@
+From 77b861136b6780ce4eabfe9589a0b584e6ed2b43 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 21 Apr 2021 21:16:47 +0000
+Subject: [PATCH] Fix delete image by ID and inhibit removal of bmc_active
+
+Delete image by ID was broken because when hitting the delete dbus
+interface, it recalculated the ID from the parent version, which then
+does not match because of the random number addition that was added
+to the ID when the parent interface was created. This saves away the
+parent interface ID and recalls it rather than recalculating it.
+
+Also, there was a logic error in deleting images that would delete the
+active BMC image. This fixes up that error.
+
+Tested: run multiple back-to back updates and see that when the fwupd
+ script calls delete, the interfaces are deleted and that the
+ bmc_active interface is not deleted.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ image_manager.cpp | 2 +-
+ item_updater.cpp | 16 +++++++++++-----
+ pfr_image_manager.cpp | 2 +-
+ version.cpp | 2 +-
+ version.hpp | 19 +++++++++++++++----
+ 5 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/image_manager.cpp b/image_manager.cpp
+index 6334704cd980..4fefd221e6d2 100644
+--- a/image_manager.cpp
++++ b/image_manager.cpp
+@@ -221,7 +221,7 @@ int Manager::processImage(const std::string& tarFilePath)
+ {
+ // Create Version object
+ auto versionPtr = std::make_unique<Version>(
+- bus, objPath, version, purpose, extendedVersion,
++ bus, objPath, id, version, purpose, extendedVersion,
+ imageDirPath.string(),
+ std::bind(&Manager::erase, this, std::placeholders::_1));
+ versionPtr->deleteObject =
+diff --git a/item_updater.cpp b/item_updater.cpp
+index 26b52b3f7846..3f64feb43c55 100644
+--- a/item_updater.cpp
++++ b/item_updater.cpp
+@@ -145,7 +145,7 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg)
+ activationState, associations)));
+
+ auto versionPtr = std::make_unique<VersionClass>(
+- bus, path, version, purpose, extendedVersion, filePath,
++ bus, path, versionId, version, purpose, extendedVersion, filePath,
+ std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
+ versionPtr->deleteObject =
+ std::make_unique<phosphor::software::manager::Delete>(bus, path,
+@@ -260,7 +260,7 @@ void ItemUpdater::processBMCImage()
+
+ // Create Version instance for this version.
+ auto versionPtr = std::make_unique<VersionClass>(
+- bus, path, version, purpose, extendedVersion, "",
++ bus, path, id, version, purpose, extendedVersion, "",
+ std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
+ auto isVersionFunctional = versionPtr->isFunctional();
+ if (!isVersionFunctional)
+@@ -336,9 +336,9 @@ void ItemUpdater::erase(std::string entryId)
+ auto it = versions.find(entryId);
+ if (it != versions.end())
+ {
+- if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1)
++ if (it->second->isFunctional())
+ {
+- error(
++ info(
+ "Version ({VERSIONID}) is currently running on the BMC; unable to remove.",
+ "VERSIONID", entryId);
+ return;
+@@ -679,6 +679,12 @@ void ItemUpdater::freeSpace(Activation& caller)
+ std::size_t count = 0;
+ for (const auto& iter : activations)
+ {
++ if (versions.find(iter.second->versionId)->second->isFunctional())
++ {
++ // don't bother with function versions
++ continue;
++ }
++
+ if ((iter.second.get()->activation() ==
+ server::Activation::Activations::Active) ||
+ (iter.second.get()->activation() ==
+@@ -772,7 +778,7 @@ void ItemUpdater::createBIOSObject()
+ // Do nothing;
+ };
+ biosVersion = std::make_unique<VersionClass>(
+- bus, path, version, VersionPurpose::Host, "", "",
++ bus, path, versionId, version, VersionPurpose::Host, "", "",
+ std::bind(dummyErase, std::placeholders::_1));
+ biosVersion->deleteObject =
+ std::make_unique<phosphor::software::manager::Delete>(bus, path,
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index 80db63ca4d85..03bc34a3a78b 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -399,7 +399,7 @@ int Manager::processImage(const std::string& imgFilePath)
+ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
+
+ auto versionPtr = std::make_unique<Version>(
+- bus, objPath, ver, purpose, extVer, imageDirPath.string(),
++ bus, objPath, id, ver, purpose, extVer, imageDirPath.string(),
+ std::bind(&Manager::erase, this, std::placeholders::_1));
+ versionPtr->deleteObject =
+ std::make_unique<phosphor::software::manager::Delete>(bus, objPath,
+diff --git a/version.cpp b/version.cpp
+index 97f3be94b4aa..5410c38887f8 100644
+--- a/version.cpp
++++ b/version.cpp
+@@ -208,7 +208,7 @@ void Delete::delete_()
+ {
+ if (parent.eraseCallback)
+ {
+- parent.eraseCallback(parent.getId(parent.version()));
++ parent.eraseCallback(parent.getExtId());
+ }
+ }
+
+diff --git a/version.hpp b/version.hpp
+index 8a68cb5f7b1f..afc589c0226c 100644
+--- a/version.hpp
++++ b/version.hpp
+@@ -77,11 +77,11 @@ class Version : public VersionInherit
+ * @param[in] callback - The eraseFunc callback
+ */
+ Version(sdbusplus::bus::bus& bus, const std::string& objPath,
+- const std::string& versionString, VersionPurpose versionPurpose,
+- const std::string& extVersion, const std::string& filePath,
+- eraseFunc callback) :
++ const std::string& extId, const std::string& versionString,
++ VersionPurpose versionPurpose, const std::string& extVersion,
++ const std::string& filePath, eraseFunc callback) :
+ VersionInherit(bus, (objPath).c_str(), true),
+- eraseCallback(callback), versionStr(versionString)
++ eraseCallback(callback), versionStr(versionString), extId(extId)
+ {
+ // Set properties.
+ extendedVersion(extVersion);
+@@ -150,6 +150,15 @@ class Version : public VersionInherit
+ */
+ bool isFunctional();
+
++ /* @brief Return the extended ID of this version object
++ *
++ * @ return - returns the extended ID string
++ */
++ std::string getExtId()
++ {
++ return extId;
++ }
++
+ /** @brief Persistent Delete D-Bus object */
+ std::unique_ptr<Delete> deleteObject;
+
+@@ -159,6 +168,8 @@ class Version : public VersionInherit
+ private:
+ /** @brief This Version's version string */
+ const std::string versionStr;
++ /** @brief This is extended version string */
++ const std::string extId;
+ };
+
+ } // namespace manager
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0019-log-redfish-errors-on-all-pfr-image-auth-failures.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0019-log-redfish-errors-on-all-pfr-image-auth-failures.patch
new file mode 100644
index 000000000..3a245c944
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0019-log-redfish-errors-on-all-pfr-image-auth-failures.patch
@@ -0,0 +1,100 @@
+From 8d3eb2a57a70715b2cc6088904e8be007ab921b2 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Fri, 27 Aug 2021 11:44:02 -0700
+Subject: [PATCH 1/4] log redfish errors on all pfr image auth failures
+
+Previous code was doing a 'mtd-util pfr authenticate' prior to manually
+calculating and comparing the hashes. This is incorrect behavior. There
+is no need to manually calculate hashes since that is part of the pfr
+authentication process.
+
+An unintended side effect of this is that if pfr authenticate fails for
+some reason other than hash compare, the redfish log does not happen.
+
+Tested: phosphor-version-software-mananger logs a redfish log on rom id
+ mismatch as expected.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+---
+ pfr_image_manager.cpp | 51 +++++--------------------------------------
+ 1 file changed, 5 insertions(+), 46 deletions(-)
+
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index ce850cb..aa96a99 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -53,13 +53,10 @@ int Manager::verifyImage(const std::filesystem::path imgPath,
+ uint8_t imgType = 0;
+ uint32_t imgMagic = 0;
+ uint8_t verData[2] = {0};
+- uint32_t hashLen = 0;
+ struct pfrImgBlock0 block0Data = {};
+
+ std::string imageName;
+
+- EVP_MD_CTX* ctx;
+-
+ if (std::filesystem::exists(imgPath))
+ {
+ try
+@@ -227,52 +224,14 @@ int Manager::verifyImage(const std::filesystem::path imgPath,
+ ImageFail::FAIL(
+ "Security violation: image authentication failure"),
+ ImageFail::PATH(imgPath.c_str()));
+- return -1;
+- }
+-
+- imgFile.seekg(pfmPos,
+- std::ios::beg); // Version is at 0x806 in the PFM
+- imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData));
+- imgFile.close();
+-
+- auto size = std::filesystem::file_size(imgPath);
+-
+- phosphor::logging::log<phosphor::logging::level::INFO>(
+- "Image Size", phosphor::logging::entry("IMAGESIZE=0x%x",
+- static_cast<int>(size)));
+-
+- // Adds all digest algorithms to the internal table
+- OpenSSL_add_all_digests();
+-
+- ctx = EVP_MD_CTX_create();
+- EVP_DigestInit(ctx, EVP_sha256());
+
+- // Hash the image file and update the digest
+- auto dataPtr = mapFile(imgPath, size);
+-
+- EVP_DigestUpdate(ctx, ((uint8_t*)dataPtr() + lengthBlk0Blk1),
+- (size - lengthBlk0Blk1));
+-
+- std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
+- std::vector<uint8_t> expectedDigest(block0Data.hash256,
+- &block0Data.hash256[0] + 32);
+-
+- EVP_DigestFinal(ctx, digest.data(), &hashLen);
+- EVP_MD_CTX_destroy(ctx);
+-
+- std::string redfishMsgID = "OpenBMC.0.1";
+-
+- if (expectedDigest != digest)
+- {
+- redfishMsgID += ".GeneralFirmwareSecurityViolation";
++ constexpr const char* redfishMsgID =
++ "OpenBMC.0.1.GeneralFirmwareSecurityViolation";
+ sd_journal_send("MESSAGE=%s",
+- "Firmware image HASH verification failed",
++ "Firmware image authentication failed",
+ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s",
+- redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s",
+- "Image HASH check fail", NULL);
+- phosphor::logging::report<ImageFailure>(
+- ImageFail::FAIL("Security violation: hash mismatch"),
+- ImageFail::PATH(imgPath.c_str()));
++ redfishMsgID, "REDFISH_MESSAGE_ARGS=%s",
++ "Image authentication check fail", NULL);
+ return -1;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service
new file mode 100644
index 000000000..d21647611
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Flash BMC with fwupd script : %I
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/bin/systemd-inhibit --what=shutdown:sleep --who=fwupd --why "Firmware Update %i" --mode=block /usr/bin/fwupd.sh %i
+SyslogIdentifier=fwupd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
new file mode 100644
index 000000000..53d09387b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
@@ -0,0 +1,30 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+EXTRA_OEMESON += "-Dfwupd-script=enabled"
+
+SYSTEMD_SERVICE:${PN}-updater += "fwupd@.service"
+
+EXTRA_OEMESON += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-Dpfr-update=enabled', '', d)}"
+
+SRC_URI += " \
+ file://0002-Redfish-firmware-activation.patch \
+ file://0004-Changed-the-condition-of-software-version-service-wa.patch \
+ file://0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch \
+ file://0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch \
+ file://0007-Adding-StandBySpare-for-firmware-activation.patch \
+ file://0008-item_updater-update-the-bmc_active-objectPath.patch \
+ file://0009-Add-ApplyOptions-D-bus-property-under-Software.patch \
+ file://0013-remove-image-file-on-pre-script-failures.patch \
+ "
+
+SRC_URI_PFR = " \
+ file://0007-PFR-images-support.patch \
+ file://0008-PFR-image-HASH-verification.patch \
+ file://0010-Add-error-reporting-to-pfr_image_manager.patch \
+ file://0014-PFR-image-verification.patch \
+ file://0016-Process-PLDM-image-type.patch \
+ file://0017-Fix-build-error.patch \
+ file://0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch \
+ file://0019-log-redfish-errors-on-all-pfr-image-auth-failures.patch \
+ "
+
+SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', SRC_URI_PFR, '', d)}"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb
new file mode 100644
index 000000000..a8dd35487
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb
@@ -0,0 +1,26 @@
+SUMMARY = "Default Fru"
+DESCRIPTION = "Builds a default FRU file at runtime based on board ID"
+
+inherit obmc-phosphor-systemd
+inherit cmake
+
+SRC_URI = "file://checkFru.sh;subdir=${BP} \
+ file://decodeBoardID.sh;subdir=${BP} \
+ file://mkfru.cpp;subdir=${BP} \
+ file://CMakeLists.txt;subdir=${BP} \
+ "
+SYSTEMD_SERVICE:${PN} = "SetBaseboardFru.service"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "\
+ file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \
+ file://mkfru.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \
+ "
+
+RDEPENDS:${PN} = "bash"
+
+do_install:append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/checkFru.sh ${D}${bindir}/checkFru.sh
+ install -m 0755 ${S}/decodeBoardID.sh ${D}${bindir}/decodeBoardID.sh
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt
new file mode 100644
index 000000000..a8e633644
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(mkfru CXX)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_executable(mkfru mkfru.cpp)
+install(TARGETS mkfru DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
new file mode 100644
index 000000000..d8c2a75ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Check for FRU presence
+
+[Service]
+ExecStart=/usr/bin/checkFru.sh
+Type=oneshot
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh
new file mode 100755
index 000000000..18a6c7260
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# this script checks the gpio id and loads the correct baseboard fru
+FRUPATH="/etc/fru"
+PRODIDPATH="/var/cache/private"
+fruFile="$FRUPATH/baseboard.fru.bin"
+prodIDFile="$PRODIDPATH/prodID"
+source decodeBoardID.sh
+
+read_id() {
+ local idx=0
+ local result=0
+ local value=0
+ for ((idx=0; idx<6; idx++))
+ do
+ typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N"))
+ value=$((value << idx))
+ result=$((result | value))
+ done
+ echo $result
+}
+
+if [ -f $fruFile -a -f $prodIDFile ] &&
+ grep -q 'CPU part\s*: 0xc07' /proc/cpuinfo; then
+ exit 0
+fi
+
+NAME="Unknown"
+PRODID="0x00"
+EEPROM_FRU=false
+
+BOARD_ID=$(read_id)
+decode_board_id
+
+if [ ! -e $prodIDFile ]
+then
+ echo $PRODID >$prodIDFile
+fi
+
+if $EEPROM_FRU;
+then
+ # Remove baseboard filesystem FRU(if any), as this platform has EEPROM FRU.
+ rm -f $fruFile
+ exit 0
+fi
+
+if [ ! -f $fruFile ]
+then
+ cd /tmp
+ mkdir -p $FRUPATH
+ mkfru $NAME
+ mv $NAME.fru.bin $fruFile
+fi
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh
new file mode 100644
index 000000000..80710ae26
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# this script uses the BOARD_ID set from checkFru.sh and provides the NAME,
+# PRODID, and EEPROM_FRU values for this platform
+decode_board_id() {
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp
new file mode 100644
index 000000000..afadbd324
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp
@@ -0,0 +1,219 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Abstract: default FRU generation
+//
+*/
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <numeric>
+#include <string>
+#include <vector>
+
+constexpr uint8_t fillChar = '.';
+constexpr uint8_t eof = 0xc1;
+const std::string intel = "Intel Corporation";
+
+// round up to nearest block size (power of 2)
+constexpr size_t blockRound(size_t len, size_t blk)
+{
+ return ((len) + (((blk) - ((len) & ((blk)-1))) & ((blk)-1)));
+}
+
+uint8_t mklen(uint8_t len)
+{
+ return static_cast<uint8_t>((0x3 << 6) | len);
+}
+
+struct FruEntry
+{
+ static constexpr size_t fruBlockSize = 8; // type, length, checksum
+ static constexpr size_t fixedBytes = 3; // type, length, checksum
+ FruEntry() = delete;
+ FruEntry(const std::vector<uint8_t>& contents)
+ {
+ constexpr size_t verOffset = 0;
+ constexpr size_t lenOffset = 1;
+ value.resize(blockRound(fixedBytes + contents.size(), fruBlockSize));
+ value[verOffset] = 1;
+ value[lenOffset] = blocks();
+ std::copy(contents.begin(), contents.end(), value.begin() + 2);
+ addChecksum();
+ }
+
+ void addChecksum()
+ {
+ int sum = std::accumulate(value.begin(), value.end(), 0);
+ value.back() = static_cast<uint8_t>(256 - sum & 0xff);
+ }
+
+ uint8_t blocks() const
+ {
+ return static_cast<uint8_t>(value.size() / 8);
+ }
+
+ std::vector<uint8_t> value;
+};
+
+size_t fillDots(std::vector<uint8_t>::iterator start, size_t count)
+{
+ *start++ = mklen(count); // prefix with (0xc0 | count)
+ auto end = start + count++;
+ std::fill(start, end, '.');
+ return count;
+}
+
+size_t fillStr(std::vector<uint8_t>::iterator start, const std::string& str)
+{
+ size_t count = str.size();
+ *start++ = mklen(count++); // prefix with (0xc0 | count)
+ std::copy(str.begin(), str.end(), start);
+ return count;
+}
+
+std::vector<uint8_t> genChassisContents()
+{
+ constexpr size_t pnSize = 18;
+ constexpr size_t snSize = 18;
+ constexpr size_t amSize = 31;
+ constexpr size_t headerSize = 1;
+ constexpr size_t contentSize = headerSize + 1 + pnSize + 1 + snSize + 1 +
+ amSize + 1 + amSize + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0x17;
+ // chassis part number
+ offset += fillDots(data.begin() + offset, pnSize);
+ // chassis serial number
+ offset += fillDots(data.begin() + offset, snSize);
+ // info am1
+ offset += fillDots(data.begin() + offset, amSize);
+ // info am2
+ offset += fillDots(data.begin() + offset, amSize);
+ data[offset] = eof;
+
+ return data;
+}
+
+std::vector<uint8_t> genBoardContents(const std::string& name)
+{
+ constexpr size_t headerSize = 4;
+ constexpr size_t snSize = 12;
+ constexpr size_t pnSize = 10;
+ const std::string version = "FRU Ver 0.01";
+ size_t contentSize = headerSize + 1 + name.size() + 1 + intel.size() + 1 +
+ snSize + 1 + pnSize + 1 + version.size() + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0; // language code
+ data[offset++] = 0; // mfg date/time
+ data[offset++] = 0; // mfg date/time
+ data[offset++] = 0; // mfg date/time
+ // manufacturer name
+ offset += fillStr(data.begin() + offset, intel);
+ // product name
+ offset += fillStr(data.begin() + offset, name);
+ // board sn
+ offset += fillDots(data.begin() + offset, snSize);
+ // board pn
+ offset += fillDots(data.begin() + offset, pnSize);
+ // fru version string
+ offset += fillStr(data.begin() + offset, version);
+ data[offset] = eof;
+
+ return data;
+}
+
+std::vector<uint8_t> genProductContents(const std::string& name)
+{
+ constexpr size_t headerSize = 1;
+ constexpr size_t pnSize = 10;
+ constexpr size_t pvSize = 20;
+ constexpr size_t snSize = 12;
+ constexpr size_t atSize = 20;
+ constexpr size_t idSize = 0;
+ const std::string version = "FRU Ver 0.01";
+ size_t contentSize = headerSize + 1 + intel.size() + 1 + name.size() + 1 +
+ pnSize + 1 + pvSize + 1 + snSize + 1 + atSize + 1 +
+ idSize + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0; // language code
+ // manufacturer name
+ offset += fillStr(data.begin() + offset, intel);
+ // product name
+ offset += fillStr(data.begin() + offset, name);
+ // product part number
+ offset += fillDots(data.begin() + offset, pnSize);
+ // product version
+ offset += fillDots(data.begin() + offset, pvSize);
+ // product serial number
+ offset += fillDots(data.begin() + offset, snSize);
+ // product asset tag
+ offset += fillDots(data.begin() + offset, atSize);
+ // empty fru file id
+ offset += fillDots(data.begin() + offset, idSize);
+ data[offset] = eof;
+
+ return data;
+}
+
+int createFru(const std::string& name)
+{
+ std::vector<uint8_t> internal{1, 0, 0, 0, 0, 0, 0, 1}; // fixed data
+ FruEntry chassis(genChassisContents());
+ FruEntry board(genBoardContents(name));
+ FruEntry product(genProductContents(name));
+ uint8_t offset = 1; // room for header's offset
+ FruEntry header({
+ offset += 1, // internal size
+ offset += chassis.blocks(),
+ offset += board.blocks(),
+ });
+ std::string filename = name + ".fru.bin";
+ std::ofstream output(filename);
+ std::ostream_iterator<uint8_t> outputIter(output);
+ std::copy(header.value.begin(), header.value.end(), outputIter);
+ std::copy(internal.begin(), internal.end(), outputIter);
+ std::copy(chassis.value.begin(), chassis.value.end(), outputIter);
+ std::copy(board.value.begin(), board.value.end(), outputIter);
+ std::copy(product.value.begin(), product.value.end(), outputIter);
+ constexpr size_t minFruSize = 0x1ff;
+ size_t fruSize = header.value.size() + internal.size() +
+ chassis.value.size() + board.value.size() +
+ product.value.size();
+ if (fruSize < minFruSize)
+ {
+ std::vector<uint8_t> padding(minFruSize - fruSize);
+ std::copy(padding.begin(), padding.end(), outputIter);
+ }
+ output.close();
+ return 0;
+}
+
+int main(int argc, const char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage: " << argv[0] << " <'Product Name'>\n";
+ return 1;
+ }
+ return createFru(argv[1]);
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend
new file mode 100644
index 000000000..0c97b0b86
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend
@@ -0,0 +1,4 @@
+DEPENDS += " gtest"
+
+#SRC_URI = "git://github.com/openbmc/phosphor-host-postd.git"
+SRCREV = "996facb65d554f7c0f14c10e3c9252d67a01e21a"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch
new file mode 100644
index 000000000..6621d2512
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch
@@ -0,0 +1,832 @@
+From 7c005c318a12c53ed887b3081bd4b34ea0213053 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Mon, 28 Jun 2021 21:56:18 +0530
+Subject: [PATCH] Firmware update configuration changes
+
+This commit will provide user to PATCH the below firmware update
+attributes before uploding the firmware image.
+
+1. This will have PATCH support for 'HttpPushUriTargets' and
+'HttpPushUriTargetsBusy' attributes. These attributes enables
+'HttpPushUri' to distinguish between the firmware update targets.
+
+2. ApplyOptions are used to specify firmware update specific options
+such as ClearConfig which is used while activating the updated
+firmware. This setting is maintained in a local static variable
+when set using PATCH method. Its used in activate image as input
+parameter. This attribute is added as Oem as the default
+UpdateService interface doesn't specify any relevant or appropriate
+attribute for this.
+
+Tested:
+ - GET on "/redfish/v1/UpdateService", got below response
+.........
+ "HttpPushUriTargets": [],
+ "HttpPushUriTargetsBusy": false
+........
+
+ - PATCH on "/redfish/v1/UpdateService" and works fine.
+{
+ "HttpPushUriTargets": ["bmc_recovery"],
+ "HttpPushUriTargetsBusy": true
+}
+
+ - Did Firmware update and verified end to end functionality
+ for both bmc active and backup images.
+
+ - Tested setting ClearConfig to true or false using PATCH
+ method.
+
+ - Successfully ran redfish validater with no new errors.
+
+Change-Id: I25ef6d64af3f1dcea3acba93d7fd2b505130142e
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ redfish-core/lib/update_service.hpp | 462 ++++++++++++++----
+ static/redfish/v1/$metadata/index.xml | 3 +
+ .../JsonSchemas/OemUpdateService/index.json | 69 +++
+ .../redfish/v1/schema/OemUpdateService_v1.xml | 40 ++
+ 4 files changed, 484 insertions(+), 90 deletions(-)
+ create mode 100644 static/redfish/v1/JsonSchemas/OemUpdateService/index.json
+ create mode 100644 static/redfish/v1/schema/OemUpdateService_v1.xml
+
+diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
+index e420130..b3270f0 100644
+--- a/redfish-core/lib/update_service.hpp
++++ b/redfish-core/lib/update_service.hpp
+@@ -26,7 +26,9 @@
+
+ namespace redfish
+ {
+-
++// params for multiple firmware targets
++std::vector<std::string> httpPushUriTargets;
++bool httpPushUriTargetBusy = false;
+ // Match signals added on software path
+ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
+ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
+@@ -34,6 +36,17 @@ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
+ static bool fwUpdateInProgress = false;
+ // Timer for software available
+ static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
++static constexpr const char* versionIntf =
++ "xyz.openbmc_project.Software.Version";
++static constexpr const char* activationIntf =
++ "xyz.openbmc_project.Software.Activation";
++static constexpr const char* reqActivationPropName = "RequestedActivation";
++static constexpr const char* reqActivationsActive =
++ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active";
++static constexpr const char* reqActivationsStandBySpare =
++ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare";
++static constexpr const char* activationsStandBySpare =
++ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare";
+
+ inline static void cleanUp()
+ {
+@@ -42,28 +55,120 @@ inline static void cleanUp()
+ fwUpdateErrorMatcher = nullptr;
+ }
+ inline static void activateImage(const std::string& objPath,
+- const std::string& service)
++ const std::string& service,
++ const std::vector<std::string>& imgUriTargets)
+ {
+ BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
++ // If targets is empty, it will apply to the active.
++ if (imgUriTargets.size() == 0)
++ {
++ crow::connections::systemBus->async_method_call(
++ [](const boost::system::error_code error_code) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "RequestedActivation failed: error_code = "
++ << error_code;
++ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
++ }
++ },
++ service, objPath, "org.freedesktop.DBus.Properties", "Set",
++ activationIntf, reqActivationPropName,
++ std::variant<std::string>(reqActivationsActive));
++ return;
++ }
++
++ // TODO: Now we support only one target becuase software-manager
++ // code support one activation per object. It will be enhanced
++ // to multiple targets for single image in future. For now,
++ // consider first target alone.
+ crow::connections::systemBus->async_method_call(
+- [](const boost::system::error_code errorCode) {
+- if (errorCode)
++ [objPath, service, imgTarget{imgUriTargets[0]}](
++ const boost::system::error_code ec,
++ const crow::openbmc_mapper::GetSubTreeType& subtree) {
++ if (ec || !subtree.size())
++ {
++ return;
++ }
++
++ for (const auto& [invObjPath, invDict] : subtree)
+ {
+- BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
+- BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
++ std::size_t idPos = invObjPath.rfind("/");
++ if ((idPos == std::string::npos) ||
++ ((idPos + 1) >= invObjPath.size()))
++ {
++ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
++ return;
++ }
++ std::string swId = invObjPath.substr(idPos + 1);
++
++ if (swId != imgTarget)
++ {
++ continue;
++ }
++
++ if (invDict.size() < 1)
++ {
++ continue;
++ }
++ BMCWEB_LOG_DEBUG << "Image target matched with object "
++ << invObjPath;
++ crow::connections::systemBus->async_method_call(
++ [objPath,
++ service](const boost::system::error_code error_code,
++ const std::variant<std::string> value) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying activation value";
++ // not all fwtypes are updateable,
++ // this is ok
++ return;
++ }
++ std::string activationValue =
++ std::get<std::string>(value);
++ BMCWEB_LOG_DEBUG << "Activation Value: "
++ << activationValue;
++ std::string reqActivation = reqActivationsActive;
++ if (activationValue == activationsStandBySpare)
++ {
++ reqActivation = reqActivationsStandBySpare;
++ }
++ BMCWEB_LOG_DEBUG
++ << "Setting RequestedActivation value as "
++ << reqActivation << " for " << service << " "
++ << objPath;
++ crow::connections::systemBus->async_method_call(
++ [](const boost::system::error_code error_code) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "RequestedActivation failed: ec = "
++ << error_code;
++ }
++ return;
++ },
++ service, objPath, "org.freedesktop.DBus.Properties",
++ "Set", activationIntf, reqActivationPropName,
++ std::variant<std::string>(reqActivation));
++ },
++ invDict[0].first,
++ "/xyz/openbmc_project/software/" + imgTarget,
++ "org.freedesktop.DBus.Properties", "Get", activationIntf,
++ "Activation");
+ }
+ },
+- service, objPath, "org.freedesktop.DBus.Properties", "Set",
+- "xyz.openbmc_project.Software.Activation", "RequestedActivation",
+- std::variant<std::string>(
+- "xyz.openbmc_project.Software.Activation.RequestedActivations."
+- "Active"));
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
++ static_cast<int32_t>(0), std::array<const char*, 1>{versionIntf});
+ }
+
+ // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
+ // then no asyncResp updates will occur
+ static void
+ softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::vector<std::string> imgUriTargets,
+ sdbusplus::message::message& m,
+ task::Payload&& payload)
+ {
+@@ -76,23 +181,25 @@ static void
+
+ m.read(objPath, interfacesProperties);
+
+- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
++ BMCWEB_LOG_DEBUG << "Software Interface Added. obj path = " << objPath.str;
+ for (auto& interface : interfacesProperties)
+ {
+ BMCWEB_LOG_DEBUG << "interface = " << interface.first;
+
+- if (interface.first == "xyz.openbmc_project.Software.Activation")
++ if (interface.first == activationIntf)
+ {
+ // Retrieve service and activate
+ crow::connections::systemBus->async_method_call(
+- [objPath, asyncResp, payload(std::move(payload))](
++ [objPath, asyncResp, imgTargets{imgUriTargets},
++ payload(std::move(payload))](
+ const boost::system::error_code errorCode,
+- const std::vector<
+- std::pair<std::string, std::vector<std::string>>>&
+- objInfo) mutable {
++ const std::vector<std::pair<
++ std::string, std::vector<std::string>>>& objInfo) {
+ if (errorCode)
+ {
+- BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
++ BMCWEB_LOG_DEBUG
++ << "GetSoftwareObject path failed: error_code = "
++ << errorCode;
+ BMCWEB_LOG_DEBUG << "error msg = "
+ << errorCode.message();
+ if (asyncResp)
+@@ -119,7 +226,7 @@ static void
+ // is added
+ fwAvailableTimer = nullptr;
+
+- activateImage(objPath.str, objInfo[0].first);
++ activateImage(objPath.str, objInfo[0].first, imgTargets);
+ if (asyncResp)
+ {
+ std::shared_ptr<task::TaskData> task =
+@@ -251,8 +358,7 @@ static void
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
+- std::array<const char*, 1>{
+- "xyz.openbmc_project.Software.Activation"});
++ std::array<const char*, 1>{activationIntf});
+ }
+ }
+ }
+@@ -262,7 +368,7 @@ static void
+ static void monitorForSoftwareAvailable(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const crow::Request& req, const std::string& url,
+- int timeoutTimeSeconds = 10)
++ const std::vector<std::string>& imgUriTargets, int timeoutTimeSeconds = 10)
+ {
+ // Only allow one FW update at a time
+ if (fwUpdateInProgress != false)
+@@ -301,11 +407,12 @@ static void monitorForSoftwareAvailable(
+ redfish::messages::internalError(asyncResp->res);
+ }
+ });
++
+ task::Payload payload(req);
+- auto callback = [asyncResp,
++ auto callback = [asyncResp, imgTargets{imgUriTargets},
+ payload](sdbusplus::message::message& m) mutable {
+ BMCWEB_LOG_DEBUG << "Match fired";
+- softwareInterfaceAdded(asyncResp, m, std::move(payload));
++ softwareInterfaceAdded(asyncResp, imgTargets, m, std::move(payload));
+ };
+
+ fwUpdateInProgress = true;
+@@ -470,12 +577,15 @@ inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
+ std::string fwFile = imageURI.substr(separator + 1);
+ BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
+
++ // We will pass empty targets and its handled in activation.
++ std::vector<std::string> httpUriTargets;
++
+ // Setup callback for when new software detected
+ // Give TFTP 10 minutes to complete
+ monitorForSoftwareAvailable(
+ asyncResp, req,
+ "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
+- 600);
++ httpUriTargets, 600);
+
+ // TFTP can take up to 10 minutes depending on image size and
+ // connection speed. Return to caller as soon as the TFTP operation
+@@ -524,6 +634,9 @@ inline void requestRoutesUpdateService(App& app)
+ asyncResp->res.jsonValue["Name"] = "Update Service";
+ asyncResp->res.jsonValue["HttpPushUri"] =
+ "/redfish/v1/UpdateService";
++ asyncResp->res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets;
++ asyncResp->res.jsonValue["HttpPushUriTargetsBusy"] =
++ httpPushUriTargetBusy;
+ // UpdateService cannot be disabled
+ asyncResp->res.jsonValue["ServiceEnabled"] = true;
+ asyncResp->res.jsonValue["FirmwareInventory"] = {
+@@ -538,7 +651,8 @@ inline void requestRoutesUpdateService(App& app)
+ asyncResp->res
+ .jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
+ updateSvcSimpleUpdate["target"] =
+- "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
++ "/redfish/v1/UpdateService/Actions/"
++ "UpdateService.SimpleUpdate";
+ updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
+ {"TFTP"};
+ #endif
+@@ -580,89 +694,258 @@ inline void requestRoutesUpdateService(App& app)
+ "/xyz/openbmc_project/software/apply_time",
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime");
++
++ // Get the ApplyOptions value
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::variant<bool> applyOption) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const bool* b = std::get_if<bool>(&applyOption);
++
++ if (b)
++ {
++ asyncResp->res
++ .jsonValue["Oem"]["ApplyOptions"]["@odata.type"] =
++ "#OemUpdateService.ApplyOptions";
++ asyncResp->res
++ .jsonValue["Oem"]["ApplyOptions"]["ClearConfig"] =
++ *b;
++ }
++ },
++ "xyz.openbmc_project.Software.BMC.Updater",
++ "/xyz/openbmc_project/software",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.Software.ApplyOptions", "ClearConfig");
+ });
++
+ BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
+ .privileges(redfish::privileges::patchUpdateService)
+- .methods(boost::beast::http::verb::patch)(
+- [](const crow::Request& req,
+- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+- BMCWEB_LOG_DEBUG << "doPatch...";
++ .methods(
++ boost::beast::http::verb::
++ patch)([](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ BMCWEB_LOG_DEBUG << "doPatch...";
++
++ std::optional<nlohmann::json> pushUriOptions;
++ std::optional<std::vector<std::string>> imgTargets;
++ std::optional<bool> imgTargetBusy;
++ std::optional<nlohmann::json> oemProps;
++ if (!json_util::readJson(req, asyncResp->res, "HttpPushUriOptions",
++ pushUriOptions, "HttpPushUriTargets",
++ imgTargets, "HttpPushUriTargetsBusy",
++ imgTargetBusy, "Oem", oemProps))
++ {
++ BMCWEB_LOG_DEBUG
++ << "UpdateService doPatch: Invalid request body";
++ return;
++ }
++
++ if (oemProps)
++ {
++ std::optional<nlohmann::json> applyOptions;
++
++ if (!json_util::readJson(*oemProps, asyncResp->res,
++ "ApplyOptions", applyOptions))
++ {
++ return;
++ }
++
++ if (applyOptions)
++ {
++ std::optional<bool> clearConfig;
++ if (!json_util::readJson(*applyOptions, asyncResp->res,
++ "ClearConfig", clearConfig))
++ {
++ return;
++ }
+
+- std::optional<nlohmann::json> pushUriOptions;
+- if (!json_util::readJson(req, asyncResp->res,
+- "HttpPushUriOptions", pushUriOptions))
++ if (clearConfig)
++ {
++ // Set the requested image apply time value
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "D-Bus responses error: " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ messages::success(asyncResp->res);
++ },
++ "xyz.openbmc_project.Software.BMC.Updater",
++ "/xyz/openbmc_project/software",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.Software.ApplyOptions",
++ "ClearConfig", std::variant<bool>{*clearConfig});
++ }
++ }
++ }
++ if (pushUriOptions)
++ {
++ std::optional<nlohmann::json> pushUriApplyTime;
++ if (!json_util::readJson(*pushUriOptions, asyncResp->res,
++ "HttpPushUriApplyTime",
++ pushUriApplyTime))
+ {
+ return;
+ }
+
+- if (pushUriOptions)
++ if (pushUriApplyTime)
+ {
+- std::optional<nlohmann::json> pushUriApplyTime;
+- if (!json_util::readJson(*pushUriOptions, asyncResp->res,
+- "HttpPushUriApplyTime",
+- pushUriApplyTime))
++ std::optional<std::string> applyTime;
++ if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
++ "ApplyTime", applyTime))
+ {
+ return;
+ }
+
+- if (pushUriApplyTime)
++ if (applyTime)
+ {
+- std::optional<std::string> applyTime;
+- if (!json_util::readJson(*pushUriApplyTime,
+- asyncResp->res, "ApplyTime",
+- applyTime))
++ std::string applyTimeNewVal;
++ if (applyTime == "Immediate")
+ {
++ applyTimeNewVal =
++ "xyz.openbmc_project.Software.ApplyTime."
++ "RequestedApplyTimes.Immediate";
++ }
++ else if (applyTime == "OnReset")
++ {
++ applyTimeNewVal =
++ "xyz.openbmc_project.Software.ApplyTime."
++ "RequestedApplyTimes.OnReset";
++ }
++ else
++ {
++ BMCWEB_LOG_INFO
++ << "ApplyTime value is not in the list of "
++ "acceptable values";
++ messages::propertyValueNotInList(
++ asyncResp->res, *applyTime, "ApplyTime");
+ return;
+ }
+
+- if (applyTime)
++ // Set the requested image apply time value
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "D-Bus responses error: " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ messages::success(asyncResp->res);
++ },
++ "xyz.openbmc_project.Settings",
++ "/xyz/openbmc_project/software/apply_time",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.Software.ApplyTime",
++ "RequestedApplyTime",
++ std::variant<std::string>{applyTimeNewVal});
++ }
++ }
++ }
++ if (imgTargetBusy)
++ {
++ if ((httpPushUriTargetBusy) && (*imgTargetBusy))
++ {
++ BMCWEB_LOG_DEBUG
++ << "Other client has reserved the HttpPushUriTargets "
++ "property for firmware updates.";
++ messages::resourceInUse(asyncResp->res);
++ return;
++ }
++
++ if (imgTargets)
++ {
++ if (!(*imgTargetBusy))
++ {
++ BMCWEB_LOG_DEBUG
++ << "UpdateService doPatch: httpPushUriTargetBusy "
++ "should be "
++ "true before setting httpPushUriTargets";
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargetsBusy");
++ return;
++ }
++ if ((*imgTargets).size() != 0)
++ {
++ // TODO: Now we support max one target becuase
++ // software-manager code support one activation per
++ // object. It will be enhanced to multiple targets for
++ // single image in future. For now, consider first
++ // target alone.
++ if ((*imgTargets).size() != 1)
+ {
+- std::string applyTimeNewVal;
+- if (applyTime == "Immediate")
+- {
+- applyTimeNewVal =
+- "xyz.openbmc_project.Software.ApplyTime."
+- "RequestedApplyTimes.Immediate";
+- }
+- else if (applyTime == "OnReset")
+- {
+- applyTimeNewVal =
+- "xyz.openbmc_project.Software.ApplyTime."
+- "RequestedApplyTimes.OnReset";
+- }
+- else
+- {
+- BMCWEB_LOG_INFO
+- << "ApplyTime value is not in the list of "
+- "acceptable values";
+- messages::propertyValueNotInList(
+- asyncResp->res, *applyTime, "ApplyTime");
+- return;
+- }
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargets");
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, uriTargets{*imgTargets},
++ targetBusy{*imgTargetBusy}](
++ const boost::system::error_code ec,
++ const std::vector<std::string> swInvPaths) {
++ if (ec)
++ {
++ return;
++ }
+
+- // Set the requested image apply time value
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](
+- const boost::system::error_code ec) {
+- if (ec)
++ bool swInvObjFound = false;
++ for (const std::string& path : swInvPaths)
++ {
++ std::size_t idPos = path.rfind("/");
++ if ((idPos == std::string::npos) ||
++ ((idPos + 1) >= path.size()))
+ {
+- BMCWEB_LOG_ERROR
+- << "D-Bus responses error: " << ec;
+ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_DEBUG
++ << "Can't parse firmware ID!!";
+ return;
+ }
+- messages::success(asyncResp->res);
+- },
+- "xyz.openbmc_project.Settings",
+- "/xyz/openbmc_project/software/apply_time",
+- "org.freedesktop.DBus.Properties", "Set",
+- "xyz.openbmc_project.Software.ApplyTime",
+- "RequestedApplyTime",
+- std::variant<std::string>{applyTimeNewVal});
+- }
++ std::string swId = path.substr(idPos + 1);
++
++ if (swId == uriTargets[0])
++ {
++ swInvObjFound = true;
++ break;
++ }
++ }
++ if (!swInvObjFound)
++ {
++ messages::invalidObject(
++ asyncResp->res, "HttpPushUriTargets");
++ return;
++ }
++ httpPushUriTargetBusy = targetBusy;
++ httpPushUriTargets = uriTargets;
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper",
++ "GetSubTreePaths", "/", static_cast<int32_t>(0),
++ std::array<const char*, 1>{versionIntf});
++ }
++ else
++ {
++ httpPushUriTargetBusy = *imgTargetBusy;
++ httpPushUriTargets = *imgTargets;
+ }
+ }
+- });
++ else
++ {
++ httpPushUriTargetBusy = *imgTargetBusy;
++ }
++ }
++ });
++
+ BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
+ .privileges(redfish::privileges::postUpdateService)
+ .methods(boost::beast::http::verb::post)(
+@@ -672,7 +955,8 @@ inline void requestRoutesUpdateService(App& app)
+
+ // Setup callback for when new software detected
+ monitorForSoftwareAvailable(asyncResp, req,
+- "/redfish/v1/UpdateService");
++ "/redfish/v1/UpdateService",
++ httpPushUriTargets);
+
+ std::string filepath("/tmp/images/" +
+ boost::uuids::to_string(
+@@ -685,7 +969,7 @@ inline void requestRoutesUpdateService(App& app)
+ out.close();
+ BMCWEB_LOG_DEBUG << "file upload complete!!";
+ });
+-}
++} // namespace redfish
+
+ inline void requestRoutesSoftwareInventoryCollection(App& app)
+ {
+@@ -748,8 +1032,7 @@ inline void requestRoutesSoftwareInventoryCollection(App& app)
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/software", static_cast<int32_t>(0),
+- std::array<const char*, 1>{
+- "xyz.openbmc_project.Software.Version"});
++ std::array<const char*, 1>{versionIntf});
+ });
+ }
+ /* Fill related item links (i.e. bmc, bios) in for inventory */
+@@ -913,7 +1196,7 @@ inline void requestRoutesSoftwareInventory(App& app)
+ },
+ obj.second[0].first, obj.first,
+ "org.freedesktop.DBus.Properties", "GetAll",
+- "xyz.openbmc_project.Software.Version");
++ versionIntf);
+ }
+ if (!found)
+ {
+@@ -937,8 +1220,7 @@ inline void requestRoutesSoftwareInventory(App& app)
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
+ static_cast<int32_t>(0),
+- std::array<const char*, 1>{
+- "xyz.openbmc_project.Software.Version"});
++ std::array<const char*, 1>{versionIntf});
+ });
+ }
+
+diff --git a/static/redfish/v1/$metadata/index.xml b/static/redfish/v1/$metadata/index.xml
+index 66b6faf..f0919c9 100644
+--- a/static/redfish/v1/$metadata/index.xml
++++ b/static/redfish/v1/$metadata/index.xml
+@@ -2444,6 +2444,9 @@
+ <edmx:Reference Uri="/redfish/v1/schema/OemComputerSystem_v1.xml">
+ <edmx:Include Namespace="OemComputerSystem"/>
+ </edmx:Reference>
++ <edmx:Reference Uri="/redfish/v1/schema/OemUpdateService_v1.xml">
++ <edmx:Include Namespace="OemUpdateService"/>
++ </edmx:Reference>
+ <edmx:Reference Uri="/redfish/v1/schema/OemVirtualMedia_v1.xml">
+ <edmx:Include Namespace="OemVirtualMedia"/>
+ <edmx:Include Namespace="OemVirtualMedia.v1_0_0"/>
+diff --git a/static/redfish/v1/JsonSchemas/OemUpdateService/index.json b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json
+new file mode 100644
+index 0000000..74e39cd
+--- /dev/null
++++ b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json
+@@ -0,0 +1,69 @@
++{
++ "$id": "http://redfish.dmtf.org/schemas/v1/OemUpdateService.json",
++ "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json",
++ "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright",
++ "definitions": {
++ "ApplyOptions": {
++ "additionalProperties": false,
++ "description": "An indication by boolean value whether to update firmware configuration along with firmware image update.",
++ "patternProperties": {
++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": {
++ "description": "This property shall specify a valid odata or Redfish property.",
++ "type": [
++ "array",
++ "boolean",
++ "integer",
++ "number",
++ "null",
++ "object",
++ "string"
++ ]
++ }
++ },
++ "properties": {
++ "ClearConfig": {
++ "description": "This indicates whether to update firmware configuration or not.",
++ "longDescription": "The value of this property is used to indicate the firmware configuration update.",
++ "readonly": false,
++ "type": [
++ "boolean",
++ "null"
++ ]
++ }
++ },
++ "type": "object"
++ },
++ "Oem": {
++ "additionalProperties": true,
++ "description": "OemUpdateService Oem properties.",
++ "patternProperties": {
++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": {
++ "description": "This property shall specify a valid odata or Redfish property.",
++ "type": [
++ "array",
++ "boolean",
++ "integer",
++ "number",
++ "null",
++ "object",
++ "string"
++ ]
++ }
++ },
++ "properties": {
++ "ApplyOptions": {
++ "anyOf": [
++ {
++ "$ref": "#/definitions/ApplyOptions"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ }
++ },
++ "type": "object"
++ }
++ },
++ "title": "#OemUpdateService"
++}
+diff --git a/static/redfish/v1/schema/OemUpdateService_v1.xml b/static/redfish/v1/schema/OemUpdateService_v1.xml
+new file mode 100644
+index 0000000..cbb7aa4
+--- /dev/null
++++ b/static/redfish/v1/schema/OemUpdateService_v1.xml
+@@ -0,0 +1,40 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml">
++ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData" />
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml">
++ <edmx:Include Namespace="Validation.v1_0_0" Alias="Validation"/>
++ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/UpdateService_v1.xml">
++ <edmx:Include Namespace="UpdateService"/>
++ <edmx:Include Namespace="UpdateService.v1_4_0"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml">
++ <edmx:Include Namespace="Resource"/>
++ <edmx:Include Namespace="Resource.v1_0_0"/>
++ </edmx:Reference>
++
++ <edmx:DataServices>
++ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemUpdateService">
++ <ComplexType Name="Oem" BaseType="Resource.OemObject">
++ <Annotation Term="OData.AdditionalProperties" Bool="true" />
++ <Annotation Term="OData.Description" String="OemUpdateService Oem properties." />
++ <Annotation Term="OData.AutoExpand"/>
++ <Property Name="ApplyOptions" Type="OemUpdateService.ApplyOptions"/>
++ </ComplexType>
++
++ <ComplexType Name="ApplyOptions" BaseType="Resource.OemObject">
++ <Annotation Term="OData.AdditionalProperties" Bool="false" />
++ <Annotation Term="OData.Description" String="An indication by boolean value whether to update firmware configuration along with firmware image update." />
++ <Property Name="ClearConfig" Type="Edm.Boolean">
++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/>
++ <Annotation Term="OData.Description" String="This indicates whether to update firmware configuration or not."/>
++ <Annotation Term="OData.LongDescription" String="The value of this property is used to indicate the firmware configuration update."/>
++ </Property>
++ </ComplexType>
++
++ </Schema>
++ </edmx:DataServices>
++</edmx:Edmx>
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch
new file mode 100644
index 000000000..02f843bb8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch
@@ -0,0 +1,74 @@
+From 034920eca21bc25899565484928ee72025e21ff8 Mon Sep 17 00:00:00 2001
+From: Wiktor Golgowski <wiktor.golgowski@linux.intel.com>
+Date: Thu, 30 Apr 2020 11:09:35 +0200
+Subject: [PATCH] Use chip id-based UUID for Service Root.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If the sysfs-provided chip id is available, it will be used as
+payload to generate Service Root UUID from hardcoded namespace.
+
+Tested:
+Generated UUID is consistent between BMC image reflashes.
+If the sysfs node is not available, code falls back to randomly
+generated UUID.
+
+Signed-off-by: Wiktor Gołgowski <wiktor.golgowski@linux.intel.com>
+---
+ include/persistent_data.hpp | 32 +++++++++++++++++++++++++++++---
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/include/persistent_data.hpp b/include/persistent_data.hpp
+index 24f7afd..8826b06 100644
+--- a/include/persistent_data.hpp
++++ b/include/persistent_data.hpp
+@@ -25,6 +25,10 @@ class ConfigFile
+ public:
+ // todo(ed) should read this from a fixed location somewhere, not CWD
+ static constexpr const char* filename = "bmcweb_persistent_data.json";
++ static constexpr const char* chipIdSysfsNode = "/sys/devices/platform"
++ "/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/chip_id";
++ static constexpr const char* UuidNs = "{b7b0553a-54cc-4162-982d-"
++ "944847ed76f5}";
+
+ ConfigFile()
+ {
+@@ -144,9 +148,31 @@ class ConfigFile
+
+ if (systemUuid.empty())
+ {
+- systemUuid =
+- boost::uuids::to_string(boost::uuids::random_generator()());
+- needWrite = true;
++ // Try to retrieve chip id-based uuid.
++ std::ifstream chipIdFile(chipIdSysfsNode);
++ if (chipIdFile.is_open())
++ {
++ std::string chipId;
++ std::getline(chipIdFile, chipId);
++ if (!chipId.empty())
++ {
++ boost::uuids::name_generator_sha1 gen(
++ boost::uuids::string_generator()(UuidNs));
++ systemUuid = boost::uuids::to_string(gen(chipId.c_str()));
++ needWrite = true;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Cannot get chip id-based System UUID.";
++ }
++ }
++ // If the above fails, generate random uuid.
++ if (systemUuid.empty())
++ {
++ systemUuid =
++ boost::uuids::to_string(boost::uuids::random_generator()());
++ needWrite = true;
++ }
+ }
+ if (fileRevision < jsonRevision)
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch
new file mode 100644
index 000000000..e54e495bb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch
@@ -0,0 +1,60 @@
+From 971aa5058ac4bb626eeadf8b00738737748ed549 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 29 Jun 2021 15:25:38 +0000
+Subject: [PATCH] managers: add attributes for Manager.CommandShell
+
+Issue: ConnectTypesSupported, ServiceEnabled and
+ MaxConcurrentSessions Attributes are missing for
+ Manager.CommandShell, though Requirement mandates it.
+
+Fix: Added missing attributes to Manager.CommandShell
+
+Tested:
+1. Verified redfish validator passed
+2. Get bmc details from Redfish
+Redfish URI: https://<BMC IP>/redfish/v1/Managers/bmc
+Response:
+{
+ "@odata.id": "/redfish/v1/Managers/bmc",
+ "@odata.type": "#Manager.v1_9_0.Manager",
+....
+....
+ "CommandShell": {
+ "ConnectTypesSupported": [
+ "SSH",
+ "IPMI"
+ ],
+ "MaxConcurrentSessions": 4,
+ "ServiceEnabled": true
+ },
+....
+....
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Change-Id: I2a56db912fc81064098f7aa9f4d110ac3baf361d
+---
+ redfish-core/lib/managers.hpp | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
+index b286f19..186003b 100644
+--- a/redfish-core/lib/managers.hpp
++++ b/redfish-core/lib/managers.hpp
+@@ -1998,6 +1998,14 @@ inline void requestRoutesManager(App& app)
+ 15;
+ asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] =
+ {"IPMI", "SSH"};
++
++ // Fill in CommandShell info
++ asyncResp->res.jsonValue["CommandShell"]["ServiceEnabled"] = true;
++ asyncResp->res.jsonValue["CommandShell"]["MaxConcurrentSessions"] =
++ 4;
++ asyncResp->res.jsonValue["CommandShell"]["ConnectTypesSupported"] =
++ {"SSH", "IPMI"};
++
+ #ifdef BMCWEB_ENABLE_KVM
+ // Fill in GraphicalConsole info
+ asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch
new file mode 100644
index 000000000..f41e6f994
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch
@@ -0,0 +1,158 @@
+From b9747ecfce682f15dce0bb6e41e0c894f29419f3 Mon Sep 17 00:00:00 2001
+From: Snehalatha Venkatesh <snehalathax.v@intel.com>
+Date: Thu, 8 Apr 2021 14:42:07 +0000
+Subject: [PATCH] bmcweb: Add PhysicalContext to Thermal resources
+
+Adding PhysicalContext to make redfish data compliance with OCP
+Server Mgmt Interface v0.2.1.pdf and specific to Thermal resources.
+https://github.com/opencomputeproject/OCP-Profiles/blob/master/
+OCPServerHardwareManagement.v0_2_4.json
+
+Tested:
+1. Redfish validator - passed for this new change
+2. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Thermal
+Response:
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/0",
+ "@odata.type": "#Thermal.v1_3_0.Temperature",
+ "LowerThresholdCritical": 0.0,
+ "LowerThresholdNonCritical": 5.0,
+ "MaxReadingRangeTemp": 127.0,
+ "MemberId": "BMC_Temp",
+ "MinReadingRangeTemp": -128.0,
+ "Name": "BMC Temp",
+ "PhysicalContext": "SystemBoard",
+ "ReadingCelsius": 25.75,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 115.0,
+ "UpperThresholdNonCritical": 110.0
+},
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/1",
+ "@odata.type": "#Thermal.v1_3_0.Temperature",
+ "LowerThresholdCritical": 0.0,
+ "LowerThresholdNonCritical": 5.0,
+ "MaxReadingRangeTemp": 255.0,
+ "MemberId": "CPU1_P12V_PVCCIN_VR_Temp",
+ "MinReadingRangeTemp": 0.0,
+ "Name": "CPU1 P12V PVCCIN VR Temp",
+ "PhysicalContext": "CPU",
+ "ReadingCelsius": 41.0,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 115.0,
+ "UpperThresholdNonCritical": 110.0
+},
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/28",
+ "@odata.type": "#Thermal.v1_3_0.Temperature",
+ "LowerThresholdCritical": 0.0,
+ "LowerThresholdNonCritical": 5.0,
+ "MaxReadingRangeTemp": 127.0,
+ "MemberId": "Inlet_BRD_Temp",
+ "MinReadingRangeTemp": -128.0,
+ "Name": "Inlet BRD Temp",
+ "PhysicalContext": "Intake",
+ "ReadingCelsius": 23.187,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 115.0,
+ "UpperThresholdNonCritical": 110.0
+},
+{
+ @odata.id": "/redfish/v1/Chassis/F2U8X25_HSBP_2/Thermal#/Temperatures/0",
+ @odata.type": "#Thermal.v1_3_0.Temperature",
+ LowerThresholdCritical": 7.0,
+ LowerThresholdNonCritical": 12.0,
+ MaxReadingRangeTemp": 127.0,
+ MemberId": "HSBP2_Temp",
+ MinReadingRangeTemp": -128.0,
+ Name": "HSBP2 Temp",
+ PhysicalContext": "Backplane",
+ ReadingCelsius": 21.437,
+ Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ UpperThresholdCritical": 57.0,
+ UpperThresholdNonCritical": 52.0
+}
+3. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Power
+Response:
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Power#/Voltages/3",
+ "@odata.type": "#Power.v1_0_0.Voltage",
+ "LowerThresholdCritical": 1.648,
+ "LowerThresholdNonCritical": 1.699,
+ "MaxReadingRange": 2.3984009912875566,
+ "MemberId": "P1V8_PCH",
+ "MinReadingRange": 0.0,
+ "Name": "P1V8 PCH",
+ "ReadingVolts": 1.8055,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 1.961,
+ "UpperThresholdNonCritical": 1.904
+}
+4. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Sensors/PSU1_Input_Current
+Response:
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Sensors/PSU1_Input_Current",
+ "@odata.type": "#Sensor.v1_0_0.Sensor",
+ "Id": "PSU1_Input_Current",
+ "Name": "PSU1 Input Current",
+ "Reading": 0.947,
+ "ReadingRangeMax": 12.0,
+ "ReadingRangeMin": 0.0,
+ "ReadingType": "Current",
+ "ReadingUnits": "A",
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ }
+}
+Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com>
+Signed-off-by: sunitakx <sunitax.kumari@linux.intel.com>
+---
+ redfish-core/lib/sensors.hpp | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index 5d27577..d51d09f 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -973,6 +973,22 @@ inline void objectInterfacesToJson(
+ {
+ unit = "/ReadingCelsius"_json_pointer;
+ sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature";
++ if (sensorName.find("CPU") != std::string::npos)
++ {
++ sensorJson["PhysicalContext"] = "CPU";
++ }
++ else if (sensorName.find("Inlet") != std::string::npos)
++ {
++ sensorJson["PhysicalContext"] = "Intake";
++ }
++ else if (sensorName.find("HSBP") != std::string::npos)
++ {
++ sensorJson["PhysicalContext"] = "Backplane";
++ }
++ else
++ {
++ sensorJson["PhysicalContext"] = "SystemBoard";
++ }
+ // TODO(ed) Documentation says that path should be type fan_tach,
+ // implementation seems to implement fan
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch
new file mode 100644
index 000000000..3ef4ee2de
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch
@@ -0,0 +1,67 @@
+From 1f572a1991fc8d9b08689aa6e3470080467977a7 Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Thu, 15 Apr 2021 10:59:42 +0000
+Subject: [PATCH] Log RedFish event for Invalid login attempt
+
+This commit adds support for logging RedFish event log while user tries
+to attempt login with invalid credentials.
+When user trying to login with invalid credentials on HTTPS interface
+like WebUI and RedFish, event should be logged in RedFish event log.
+This event log is useful for further analysis to debug the root-cause
+for failure.
+
+Tested:
+1. Verified RedFish validator passed
+2. Login with wrong credentials on HTTPS interface.
+3. Verified for RedFish/WebUI events. RedFish event logged successfully.
+GET: https://BMC-IP/redfish/v1/Systems/system/LogServices/
+ EventLog/Entries
+Response:
+"Members": [
+{
+ "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/
+ Entries/1618466128",
+ "@odata.type": "#LogEntry.v1_4_0.LogEntry",
+ "Created": "2021-04-15T05:55:28+00:00",
+ "EntryType": "Event",
+ "Id": "1618466128",
+ "Message": "Invalid username or password attempted on HTTPS.",
+ "MessageArgs": [
+ "HTTPS"
+ ],
+ "MessageId": "OpenBMC.0.1.InvalidLoginAttempted",
+ "Name": "System Event Log Entry",
+ "Severity": "Warning"
+}
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ include/pam_authenticate.hpp | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
+index 12f19c0..01bf301 100644
+--- a/include/pam_authenticate.hpp
++++ b/include/pam_authenticate.hpp
+@@ -1,6 +1,7 @@
+ #pragma once
+
+ #include <security/pam_appl.h>
++#include <systemd/sd-journal.h>
+
+ #include <boost/utility/string_view.hpp>
+
+@@ -75,6 +76,10 @@ inline int pamAuthenticateUser(const std::string_view username,
+ PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
+ if (retval != PAM_SUCCESS)
+ {
++ sd_journal_send("MESSAGE= %s", "Invalid login attempted on HTTPS",
++ "PRIORITY=%i", LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.InvalidLoginAttempted",
++ "REDFISH_MESSAGE_ARGS=%s", "HTTPS", NULL);
+ pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
+ return retval;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch
new file mode 100644
index 000000000..41acb6057
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch
@@ -0,0 +1,59 @@
+From 6c10adb53d3247f65e5d9399290e6b8e7962cdef Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 28 Apr 2021 17:19:50 -0700
+Subject: [PATCH] Add UART routing logic into host console connection flow
+
+Switching UART routing when starting obmc-service introduces garbled
+character printing out on physical host serial output and it's
+inevitable so this commit moves the routing logic into host console
+connection flow in bmcweb to avoid the issue until SOL is actually
+activated.
+
+Tested: The garbled character printing out was not observed during
+BMC booting. SOL worked well.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ include/obmc_console.hpp | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/include/obmc_console.hpp b/include/obmc_console.hpp
+index cdb19901e82d..9c4ae8821074 100644
+--- a/include/obmc_console.hpp
++++ b/include/obmc_console.hpp
+@@ -22,6 +22,9 @@ static boost::container::flat_set<crow::websocket::Connection*> sessions;
+
+ static bool doingWrite = false;
+
++constexpr char const* uartMuxCtrlPath = "/sys/bus/platform/drivers/aspeed-uart-routing/1e789098.uart-routing/hicra";
++constexpr char const* uartMuxCtrlVal = "0x03450003";
++
+ inline void doWrite()
+ {
+ if (doingWrite)
+@@ -110,6 +113,22 @@ inline void connectHandler(const boost::system::error_code& ec)
+ return;
+ }
+
++ FILE* file = fopen(uartMuxCtrlPath, "w");
++ if (file != nullptr)
++ {
++ int rc = fputs(uartMuxCtrlVal, file);
++ fclose(file);
++ if (rc < 0)
++ {
++ BMCWEB_LOG_ERROR << "Couldn't change UART routing: " << rc;
++ for (crow::websocket::Connection* session : sessions)
++ {
++ session->close("Error in connecting to host port");
++ }
++ return;
++ }
++ }
++
+ doWrite();
+ doRead();
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch
new file mode 100644
index 000000000..5ffc259c0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch
@@ -0,0 +1,75 @@
+From aaaa117817687a05284f8bfff07e2404e0d616b7 Mon Sep 17 00:00:00 2001
+From: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Date: Thu, 10 Dec 2020 13:42:20 -0800
+Subject: [PATCH] recommended fixes by crypto review team
+
+some curves/cyphers are forbiden to be used by
+Intel crypto team.
+Only enable approved ones.
+the patch was created by aleksandr.v.tereschenko@intel.com
+
+Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+---
+ include/ssl_key_handler.hpp | 39 ++++++++++++++++++++-----------------
+ 1 file changed, 21 insertions(+), 18 deletions(-)
+
+diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
+index 39e83d7..8de7349 100644
+--- a/include/ssl_key_handler.hpp
++++ b/include/ssl_key_handler.hpp
+@@ -381,31 +381,34 @@ inline std::shared_ptr<boost::asio::ssl::context>
+ mSslContext->use_private_key_file(sslPemFile,
+ boost::asio::ssl::context::pem);
+
+- // Set up EC curves to auto (boost asio doesn't have a method for this)
+- // There is a pull request to add this. Once this is included in an asio
+- // drop, use the right way
+- // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
+- if (SSL_CTX_set_ecdh_auto(mSslContext->native_handle(), 1) != 1)
++ std::string handshakeCurves = "P-384:P-521:X448";
++ if (SSL_CTX_set1_groups_list(mSslContext->native_handle(), handshakeCurves.c_str()) != 1)
+ {
+- BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
++ BMCWEB_LOG_ERROR << "Error setting ECDHE group list\n";
+ }
+
+- std::string mozillaModern = "ECDHE-ECDSA-AES256-GCM-SHA384:"
+- "ECDHE-RSA-AES256-GCM-SHA384:"
+- "ECDHE-ECDSA-CHACHA20-POLY1305:"
+- "ECDHE-RSA-CHACHA20-POLY1305:"
+- "ECDHE-ECDSA-AES128-GCM-SHA256:"
+- "ECDHE-RSA-AES128-GCM-SHA256:"
+- "ECDHE-ECDSA-AES256-SHA384:"
+- "ECDHE-RSA-AES256-SHA384:"
+- "ECDHE-ECDSA-AES128-SHA256:"
+- "ECDHE-RSA-AES128-SHA256";
++ std::string tls12Ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:"
++ "ECDHE-RSA-AES256-GCM-SHA384";
++ std::string tls13Ciphers = "TLS_AES_256_GCM_SHA384";
+
+ if (SSL_CTX_set_cipher_list(mSslContext->native_handle(),
+- mozillaModern.c_str()) != 1)
++ tls12Ciphers.c_str()) != 1)
+ {
+- BMCWEB_LOG_ERROR << "Error setting cipher list\n";
++ BMCWEB_LOG_ERROR << "Error setting TLS 1.2 cipher list\n";
+ }
++
++ if (SSL_CTX_set_ciphersuites(mSslContext->native_handle(),
++ tls13Ciphers.c_str()) != 1)
++ {
++ BMCWEB_LOG_ERROR << "Error setting TLS 1.3 cipher list\n";
++ }
++
++ if ((SSL_CTX_set_options(mSslContext->native_handle(),
++ SSL_OP_CIPHER_SERVER_PREFERENCE) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0)
++ {
++ BMCWEB_LOG_ERROR << "Error setting TLS server preference option\n";
++ }
++
+ return mSslContext;
+ }
+ } // namespace ensuressl
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch
new file mode 100644
index 000000000..1193fe9d1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch
@@ -0,0 +1,98 @@
+From b468b508176dfffe2e8e4adb3052577b9ff70d2f Mon Sep 17 00:00:00 2001
+From: "Arun P. Mohanan" <arun.p.m@linux.intel.com>
+Date: Wed, 27 Jan 2021 18:22:58 +0530
+Subject: [PATCH] Add state sensor messages to the registry
+
+Add messages to registry to indicate state sensor state change.
+
+Tested:
+Build and redfish validator passes.
+Logged these events and confirmed that they appear as expected on
+Redfish.
+GET: https://<BMC IP>/redfish/v1/Systems/system/LogServices/EventLog/Entries/1612528180
+{
+ "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1612528180",
+ "@odata.type": "#LogEntry.v1_4_0.LogEntry",
+ "Created": "2021-02-05T12:29:40+00:00",
+ "EntryType": "Event",
+ "Id": "1612528180",
+ "Message": "Operational Fault Status of Card_health_1 state sensor changed from Error to Normal.",
+ "MessageArgs": [
+ "Operational Fault Status",
+ "Card_health_1",
+ "Error",
+ "Normal"
+ ],
+ "MessageId": "OpenBMC.0.1.StateSensorNormal",
+ "Name": "System Event Log Entry",
+ "Severity": "OK"
+}
+
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+---
+ .../registries/openbmc_message_registry.hpp | 36 +++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
+index 6cf503f..87b2913 100644
+--- a/redfish-core/include/registries/openbmc_message_registry.hpp
++++ b/redfish-core/include/registries/openbmc_message_registry.hpp
+@@ -29,7 +29,7 @@ const Header header = {
+ "0.2.0",
+ "OpenBMC",
+ };
+-constexpr std::array<MessageEntry, 188> registry = {
++constexpr std::array<MessageEntry, 191> registry = {
+ MessageEntry{
+ "ADDDCCorrectable",
+ {
+@@ -2331,6 +2331,39 @@ constexpr std::array<MessageEntry, 188> registry = {
+ {},
+ "None.",
+ }},
++ MessageEntry{
++ "StateSensorNormal",
++ {
++ "Indicates that a state sensor has changed state to normal.",
++ "%1 of %2 state sensor changed from %3 to %4.",
++ "OK",
++ "OK",
++ 4,
++ {"string", "string", "string", "string"},
++ "None.",
++ }},
++ MessageEntry{
++ "StateSensorWarning",
++ {
++ "Indicates that a state sensor has changed state to warning.",
++ "%1 of %2 state sensor changed from %3 to %4.",
++ "Warning",
++ "Warning",
++ 4,
++ {"string", "string", "string", "string"},
++ "Check sensor subsystem for errors.",
++ }},
++ MessageEntry{
++ "StateSensorCritical",
++ {
++ "Indicates that a state sensor has changed state to critical.",
++ "%1 of %2 state sensor changed from %3 to %4.",
++ "Critical",
++ "Critical",
++ 4,
++ {"string", "string", "string", "string"},
++ "Check sensor subsystem for errors.",
++ }},
+ MessageEntry{"SystemInterfaceDisabledProvisioned",
+ {
+ "Indicates that the system interface is in the disabled "
+@@ -2423,6 +2456,5 @@ constexpr std::array<MessageEntry, 188> registry = {
+ {"string"},
+ "None.",
+ }},
+-
+ };
+ } // namespace redfish::message_registries::openbmc
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch
new file mode 100644
index 000000000..bc023839f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch
@@ -0,0 +1,44 @@
+From 48fe2a68d634970795f9ff13903afbedca801088 Mon Sep 17 00:00:00 2001
+From: Nidhin MS <nidhin.ms@intel.com>
+Date: Wed, 14 Apr 2021 11:28:44 +0530
+Subject: [PATCH] Fix: bmcweb crashes if socket directory not present
+
+When trying to mount virtual media image bmcweb tries to create unix
+socket and if the parent directory does not exist
+stream_protocol::acceptor throws error and bmcweb crashes. Fix the same
+
+Tested:
+Removed directory and mounted the vm image. bmcweb crash was not
+observed
+
+Change-Id: I3aea1d8e197c06238f425a97435c01d3c80552a9
+Signed-off-by: Nidhin MS <nidhin.ms@intel.com>
+---
+ include/nbd_proxy.hpp | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp
+index 7b90e90..3b28823 100644
+--- a/include/nbd_proxy.hpp
++++ b/include/nbd_proxy.hpp
+@@ -397,6 +397,17 @@ inline void requestRoutes(App& app)
+ // If the socket file exists (i.e. after bmcweb crash),
+ // we cannot reuse it.
+ std::remove((*socketValue).c_str());
++ std::filesystem::path socketPath(*socketValue);
++ std::error_code fsErr;
++ if (!std::filesystem::exists(socketPath.parent_path(),
++ fsErr))
++ {
++ BMCWEB_LOG_ERROR
++ << "VirtualMedia socket directory not present. "
++ << socketPath.parent_path();
++ conn.close("Unable to create unix socket");
++ return;
++ }
+
+ sessions[&conn] = std::make_shared<NbdProxyServer>(
+ conn, *socketValue, *endpointValue,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch
new file mode 100644
index 000000000..35ac7a114
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch
@@ -0,0 +1,81 @@
+From 40895934bdedb978e8cfd47930ae5a190e19b440 Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Mon, 10 May 2021 12:32:30 +0530
+Subject: [PATCH] Add msg registry for subscription related actions
+
+For subscription event message log purpose, added message registry
+entry for event service subscription related actions- add, update
+and delete.
+
+Tested:
+ - Message registry entry appears in the log for the corresponding
+ subscription action.
+
+Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ .../registries/openbmc_message_registry.hpp | 41 ++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
+index 87b2913..1e493ca 100644
+--- a/redfish-core/include/registries/openbmc_message_registry.hpp
++++ b/redfish-core/include/registries/openbmc_message_registry.hpp
+@@ -29,7 +29,7 @@ const Header header = {
+ "0.2.0",
+ "OpenBMC",
+ };
+-constexpr std::array<MessageEntry, 191> registry = {
++constexpr std::array<MessageEntry, 194> registry = {
+ MessageEntry{
+ "ADDDCCorrectable",
+ {
+@@ -417,6 +417,45 @@ constexpr std::array<MessageEntry, 191> registry = {
+ {},
+ "None.",
+ }},
++ MessageEntry{"EventSubscriptionAdded",
++ {
++ "Indicates that an Event subscription with specific "
++ "id was added.",
++ "Event subscription with id %1 was added.",
++ "OK",
++ "OK",
++ 1,
++ {
++ "string",
++ },
++ "None.",
++ }},
++ MessageEntry{"EventSubscriptionRemoved",
++ {
++ "Indicates that an Event subscription with specific "
++ "id was removed.",
++ "Event subscription with id %1 was removed.",
++ "OK",
++ "OK",
++ 1,
++ {
++ "string",
++ },
++ "None.",
++ }},
++ MessageEntry{"EventSubscriptionUpdated",
++ {
++ "Indicates that an Event subscription with specific "
++ " id was updated.",
++ "Event subscription with id %1 was updated.",
++ "OK",
++ "OK",
++ 1,
++ {
++ "string",
++ },
++ "None.",
++ }},
+ MessageEntry{"FanInserted",
+ {
+ "Indicates that a system fan has been inserted.",
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch
new file mode 100644
index 000000000..54636cb3d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch
@@ -0,0 +1,77 @@
+From eeac51ebaaad82bb4ac65a029c81c221e32b33ea Mon Sep 17 00:00:00 2001
+From: mansijos <mansi.joshi@intel.com>
+Date: Wed, 26 May 2021 17:40:04 +0530
+Subject: [PATCH] Add BMC Time update log to the registry
+
+Add message in registry to log an event that indicates BMC time
+is set via NTP, Host or Manually.
+During early stage of system boot if any critical events occur,
+they are getting logged with 1970 timestamp till the time BMC
+time update happens. This is expected behavior, but to call it out
+explicitly it is good to log when BMC time is updated.
+
+Tested:
+Built and validator passes.
+Confirmed that the event is getting logged correctly in Redfish.
+
+Signed-off-by: mansijos <mansi.joshi@intel.com>
+---
+ .../registries/openbmc_message_registry.hpp | 35 ++++++++++++++++++-
+ 1 file changed, 34 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
+index 1e493ca..967713f 100644
+--- a/redfish-core/include/registries/openbmc_message_registry.hpp
++++ b/redfish-core/include/registries/openbmc_message_registry.hpp
+@@ -29,7 +29,7 @@ const Header header = {
+ "0.2.0",
+ "OpenBMC",
+ };
+-constexpr std::array<MessageEntry, 194> registry = {
++constexpr std::array<MessageEntry, 197> registry = {
+ MessageEntry{
+ "ADDDCCorrectable",
+ {
+@@ -286,6 +286,39 @@ constexpr std::array<MessageEntry, 194> registry = {
+ {},
+ "None.",
+ }},
++ MessageEntry{"BMCTimeUpdatedViaHost",
++ {
++ "Indicates that BMC time has been set via Host.",
++ "BMC time has been set via Host. "
++ "Date Time is set to %1 from %2.",
++ "OK",
++ "OK",
++ 2,
++ {"string", "string"},
++ "None.",
++ }},
++ MessageEntry{"BMCTimeUpdatedManually",
++ {
++ "Indicates that BMC time has been set Manually.",
++ "BMC time has been set Manually. "
++ "Date Time is set to %1 from %2.",
++ "OK",
++ "OK",
++ 2,
++ {"string", "string"},
++ "None.",
++ }},
++ MessageEntry{"BMCTimeUpdatedViaNTP",
++ {
++ "Indicates that BMC time has been set via NTP.",
++ "BMC time has been set via NTP. "
++ "Date Time is set to %1 from %2.",
++ "OK",
++ "OK",
++ 2,
++ {"string", "string"},
++ "None.",
++ }},
+ MessageEntry{"ChassisIntrusionDetected",
+ {
+ "Indicates that a physical security event "
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch
new file mode 100644
index 000000000..522f04886
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch
@@ -0,0 +1,120 @@
+From 6bc3ec77e062e8f2108f755e9f0089a014031f91 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 6 Oct 2021 21:51:16 +0000
+Subject: [PATCH] Add generic message - PropertySizeExceeded
+
+Adding a generic error message "PropertySizeExceeded"
+to address properties which exceed there defined size limit.
+
+Tested:
+No functional change. Build passed.
+Verified by explicitly sending this message as a response.
+
+Change-Id: I0e9f85f82a69c598e169fc8e9a68c3f66c0084d8
+Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ redfish-core/include/error_messages.hpp | 12 +++++++++
+ .../registries/base_message_registry.hpp | 17 +++++++++++-
+ redfish-core/src/error_messages.cpp | 27 +++++++++++++++++++
+ 3 files changed, 55 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
+index 3d11cc4..051cff1 100644
+--- a/redfish-core/include/error_messages.hpp
++++ b/redfish-core/include/error_messages.hpp
+@@ -222,6 +222,18 @@ nlohmann::json propertyValueFormatError(const std::string& arg1,
+ void propertyValueFormatError(crow::Response& res, const std::string& arg1,
+ const std::string& arg2);
+
++/**
++ * @brief Formats PropertySizeExceeded message into JSON
++ * Message body: "The property <arg1> is too long. The value exceeds its size
++ * limit."
++ *
++ * @param[in] arg1 Parameter of message that will replace %1 in its body.
++ *
++ * @returns Message PropertySizeExceeded formatted to JSON */
++nlohmann::json propertySizeExceeded(const std::string& arg1);
++
++void propertySizeExceeded(crow::Response& res, const std::string& arg1);
++
+ /**
+ * @brief Formats PropertyValueNotInList message into JSON
+ * Message body: "The value <arg1> for the property <arg2> is not in the list of
+diff --git a/redfish-core/include/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp
+index 702cd6f..193df16 100644
+--- a/redfish-core/include/registries/base_message_registry.hpp
++++ b/redfish-core/include/registries/base_message_registry.hpp
+@@ -22,7 +22,7 @@ const Header header = {
+ constexpr const char* url =
+ "https://redfish.dmtf.org/registries/Base.1.11.0.json";
+
+-constexpr std::array<MessageEntry, 93> registry = {
++constexpr std::array<MessageEntry, 94> registry = {
+ MessageEntry{
+ "AccessDenied",
+ {
+@@ -692,6 +692,21 @@ constexpr std::array<MessageEntry, 93> registry = {
+ "Remove the property from the request body and resubmit "
+ "the request if the operation failed.",
+ }},
++ MessageEntry{"PropertySizeExceeded",
++ {
++ "Indicates that a given property exceeds the size "
++ "limit imposed.",
++ "The property %1 is too long. The value exceeds "
++ "its size limit.",
++ "Warning",
++ "Warning",
++ 1,
++ {
++ "string",
++ },
++ "Correct the value for the property in the request body "
++ "and resubmit the request if the operation failed.",
++ }},
+ MessageEntry{"PropertyUnknown",
+ {
+ "Indicates that an unknown property was included in the "
+diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
+index 9c28e8f..854a1a5 100644
+--- a/redfish-core/src/error_messages.cpp
++++ b/redfish-core/src/error_messages.cpp
+@@ -514,6 +514,33 @@ void propertyValueFormatError(crow::Response& res, const std::string& arg1,
+ addMessageToJson(res.jsonValue, propertyValueFormatError(arg1, arg2), arg2);
+ }
+
++/**
++ * @internal
++ * @brief Formats PropertySizeExceeded message into JSON for the specified
++ * property
++ *
++ * See header file for more information
++ * @endinternal
++ */
++nlohmann::json propertySizeExceeded(const std::string& arg1)
++{
++ return nlohmann::json{
++ {"@odata.type", "#Message.v1_1_1.Message"},
++ {"MessageId", "Base.1.8.1.PropertySizeExceeded"},
++ {"Message", "The property " + arg1 +
++ " is too long. The value exceeds its size limit."},
++ {"MessageArgs", {arg1}},
++ {"MessageSeverity", "Warning"},
++ {"Resolution", "Correct the value for the property in the request body "
++ "and resubmit the request if the operation failed."}};
++}
++
++void propertySizeExceeded(crow::Response& res, const std::string& arg1)
++{
++ res.result(boost::beast::http::status::bad_request);
++ addMessageToJson(res.jsonValue, propertySizeExceeded(arg1), arg1);
++}
++
+ /**
+ * @internal
+ * @brief Formats PropertyValueNotInList message into JSON for the specified
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-Redfish-Deny-set-AccountLockDuration-to-zero.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-Redfish-Deny-set-AccountLockDuration-to-zero.patch
new file mode 100644
index 000000000..cc9da3b8b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-Redfish-Deny-set-AccountLockDuration-to-zero.patch
@@ -0,0 +1,85 @@
+From f75efac9eebea8bf8f548d10a8cbafa28f556a8f Mon Sep 17 00:00:00 2001
+From: Meera-Katta <meerax.katta@linux.intel.com>
+Date: Wed, 7 Jul 2021 13:19:09 +0000
+Subject: [PATCH] Redfish: Deny set AccountLockDuration to zero
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Issue: Redfish schema says, no lockout shall occur in case of Account
+LockoutDuration value is zero. But Linux PAM module documentation says, if
+account lockout value is zero, account will be locked out indefinitely
+after the number of failed login attempts. As per the current
+implementation user can write any value into the PAM module. If user tried
+to set unlock timeout value to zero, account will be locked out
+indefinitely until administrator explicitly reenables it.
+
+Workaround: Denying user to set AccountLockDuration to zero from Redfish.
+Setting ‘AccountLockDuration’ to 0 will be permitted only after
+‘AccountLockoutCounterResetEnabled’ support is added.
+Otherwise,account will be locked permanently after the AccountLockoutDuration
+if ‘AccountLockDuration’ is set to zero, while
+AccountLockoutThreshold is non zero. If someone wants no account lockout
+irrespective of number of failed login attempts, it can be still achieved by
+setting ‘AccountLockoutThreshold’ to zero
+(instead of trying to set ‘AccountLockDuration’ to zero.)
+
+Tested:
+1) Redfish Service Validator passed for this change.
+2) Verified from Redfish
+PATCH : https://<BMC IP>/redfish/v1/AccountService
+Body:
+{"AccountLockoutDuration":0}
+
+Response:
+{
+ "AccountLockoutDuration@Message.ExtendedInfo": [
+ {
+ "@odata.type": "#Message.v1_1_1.Message",
+ "Message": "The value unlockTimeout for the property
+ AccountLockoutDuration is not in the list of acceptable values.",
+ "MessageArgs": [
+ "unlockTimeout",
+ "AccountLockoutDuration"
+ ],
+ "MessageId": "Base.1.8.1.PropertyValueNotInList",
+ "MessageSeverity": "Warning",
+ "Resolution": "Choose a value from the enumeration list that the
+ implementation can support and resubmit the request if the
+ operation failed."
+ }
+ ]
+}
+
+Signed-off-by: Meera-Katta <meerax.katta@linux.intel.com>
+---
+ redfish-core/lib/account_service.hpp | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
+index e6fe205..42085fa 100644
+--- a/redfish-core/lib/account_service.hpp
++++ b/redfish-core/lib/account_service.hpp
+@@ -1448,6 +1448,19 @@ inline void requestAccountServiceRoutes(App& app)
+
+ if (unlockTimeout)
+ {
++ // Account will be locked permanently after the N number
++ // of failed login attempts if we set unlockTimeout value
++ // to be 0.
++ if (unlockTimeout.value() == 0)
++ {
++ BMCWEB_LOG_INFO
++ << "Unlock timeout value must be greater"
++ "than zero";
++ messages::propertyValueNotInList(asyncResp->res,
++ "unlockTimeout",
++ "AccountLockoutDuration");
++ return;
++ }
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0023-Add-get-IPMI-session-id-s-to-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0023-Add-get-IPMI-session-id-s-to-Redfish.patch
new file mode 100644
index 000000000..b3feee39a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0023-Add-get-IPMI-session-id-s-to-Redfish.patch
@@ -0,0 +1,390 @@
+From 5c79e34be9357c2a2cd9bac61cd0162dbd342a2d Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Fri, 30 Jul 2021 17:33:16 +0000
+Subject: [PATCH] Add/get IPMI session id's to Redfish
+
+As per existing implementation, Redfish supports to get only sessions
+created on Redfish & EWS. But as per Redfish schema Redfish should
+include to get IPMI sessions as well.
+So add support to display IPMI session Id's as well on Redfish.
+This commit will not impact any functionality/behavior of existing code.
+Below functionalities implemented in this commit.
+1. Get IPMI session collection
+2. Get individual IPMI session information
+3. Delete IPMI sessions - Respond with not supported as we can't delete
+ IPMI sessions from Redfish interface
+
+Tested:
+1. Verified redfish validator passed with active IPMI session.
+2. Get session details from Redfish
+GET: https://<BMC-IP>/redfish/v1/SessionService/Sessions
+Response:
+{
+ "@odata.id": "/redfish/v1/SessionService/Sessions/",
+ "@odata.type": "#SessionCollection.SessionCollection",
+ "Description": "Session Collection",
+ "Members": [
+ {
+ "@odata.id": "/redfish/v1/SessionService/Sessions/TlFPbR9ZIn"
+ },
+ {
+ "@odata.id": "/redfish/v1/SessionService/Sessions/184U3014ub"
+ },
+ {
+ "@odata.id": "/redfish/v1/SessionService/Sessions/cV0xi5QoPy"
+ },
+ {
+ "@odata.id": "/redfish/v1/SessionService/Sessions/8f6234d7_81"
+ }
+ ],
+ "Members@odata.count": 4,
+ "Name": "Session Collection"
+}
+
+3. Get session details from RedFish
+Case 1: RedFish session
+GET: https://<BMC-IP>/redfish/v1/SessionService/Sessions/TlFPbR9ZIn
+Response:
+{
+ "@odata.id": "/redfish/v1/SessionService/Sessions/TlFPbR9ZIn",
+ "@odata.type": "#Session.v1_3_0.Session",
+ "ClientOriginIPAddress": "::ffff:10.213.91.40",
+ "Description": "Manager User Session",
+ "Id": "TlFPbR9ZIn",
+ "Name": "User Session",
+ "UserName": "root"
+}
+Case 2: IPMI session
+Verified and displayed IPMI session details on RedFish.
+GET: https://<BMC-IP>/redfish/v1/SessionService/Sessions/8f6234d7_81
+Response:
+{
+ "@odata.id": "/redfish/v1/SessionService/Sessions/8f6234d7_81",
+ "@odata.type": "#Session.v1_3_0.Session",
+ "ClientOriginIPAddress": "xx.xx.xx.xx",
+ "Description": "Manager User Session",
+ "Id": "8f6234d7_81",
+ "Name": "User Session",
+ "UserName": "root"
+}
+4. Delete IPMI session:
+Verified IPMI session is not allowed to delete from Redfish
+DELETE: https://<BMC-IP>/redfish/v1/SessionService/Sessions/8f6234d7_81
+Response:
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "#Message.v1_1_1.Message",
+ "Message": "The action deleting IPMI session from
+ Redfish is not supported by the resource.",
+ "MessageArgs": [
+ "deleting IPMI session from Redfish"
+ ],
+ "MessageId": "Base.1.8.1.ActionNotSupported",
+ "MessageSeverity": "Critical",
+ "Resolution": "The action supplied cannot be resubmitted
+ to the implementation. Perhaps the action was invalid,
+ the wrong resource was the target or the implementation
+ documentation may be of assistance."
+ }
+ ],
+ "code": "Base.1.8.1.ActionNotSupported",
+ "message": "The action deleting IPMI session from Redfish is not
+ supported by the resource."
+ }
+}
+5. Delete RedFish session
+Result: successfully deleted valid RedFish session.
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ redfish-core/lib/redfish_sessions.hpp | 244 +++++++++++++++++++++++---
+ 1 file changed, 222 insertions(+), 22 deletions(-)
+
+diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
+index 929e0c8..3c7a968 100644
+--- a/redfish-core/lib/redfish_sessions.hpp
++++ b/redfish-core/lib/redfish_sessions.hpp
+@@ -56,14 +56,127 @@ inline void requestRoutesSession(App& app)
+ auto session = persistent_data::SessionStore::getInstance()
+ .getSessionByUid(sessionId);
+
+- if (session == nullptr)
++ if (session)
+ {
+- messages::resourceNotFound(asyncResp->res, "Session",
+- sessionId);
++ fillSessionObject(asyncResp->res, *session);
+ return;
+ }
+
+- fillSessionObject(asyncResp->res, *session);
++ std::array<std::string, 1> interfaces = {
++ "xyz.openbmc_project.Ipmi.SessionInfo"};
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, sessionId](const boost::system::error_code ec,
++ const GetSubTreeType& subtree) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying GetSubTree with "
++ "Object Mapper. "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (subtree.size() == 0)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Can't find Session Info Attributes!";
++ messages::resourceNotFound(asyncResp->res,
++ "Session", sessionId);
++ return;
++ }
++ bool ipmiSessionFound = false;
++ std::string ipmiSessionService;
++ std::string ipmiSessionInfPath;
++ for (const auto& [ipmiSessionPath, object] : subtree)
++ {
++ if (ipmiSessionPath.empty() || object.empty())
++ {
++ BMCWEB_LOG_DEBUG
++ << "Session Info Attributes mapper error!";
++ continue;
++ }
++ if (!boost::ends_with(ipmiSessionPath, sessionId))
++ {
++ continue;
++ }
++ ipmiSessionFound = true;
++ ipmiSessionService = object[0].first;
++ ipmiSessionInfPath = ipmiSessionPath;
++ break;
++ }
++ if (!ipmiSessionFound)
++ {
++ messages::resourceNotFound(asyncResp->res,
++ "Session", sessionId);
++ return;
++ }
++ if (ipmiSessionService.empty())
++ {
++ BMCWEB_LOG_DEBUG
++ << "Session Info Attributes mapper "
++ "error!";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, sessionId](
++ const boost::system::error_code ec,
++ const std::vector<std::pair<
++ std::string,
++ std::variant<std::monostate, std::string,
++ uint32_t>>>& properties) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying Session "
++ "Info State property "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ std::string userName = "";
++ uint32_t remoteIpAddr;
++ try
++ {
++ sdbusplus::unpackProperties(
++ properties, "Username", userName,
++ "RemoteIPAddr", remoteIpAddr);
++ asyncResp->res.jsonValue["Id"] = sessionId;
++ asyncResp->res.jsonValue["UserName"] =
++ userName;
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/SessionService/"
++ "Sessions/" +
++ sessionId;
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#Session.v1_3_0.Session";
++ asyncResp->res.jsonValue["Name"] =
++ "User Session";
++ asyncResp->res.jsonValue["Description"] =
++ "Manager User Session";
++ struct in_addr ipAddr;
++ ipAddr.s_addr = remoteIpAddr;
++ asyncResp->res
++ .jsonValue["ClientOriginIPAddress"] =
++ inet_ntoa(ipAddr);
++ }
++ catch (const sdbusplus::exception::
++ UnpackPropertyError& error)
++ {
++ BMCWEB_LOG_ERROR << error.what();
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ return;
++ },
++ ipmiSessionService, ipmiSessionInfPath,
++ "org.freedesktop.DBus.Properties", "GetAll",
++ "xyz.openbmc_project.Ipmi.SessionInfo");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
++ interfaces);
+ });
+
+ BMCWEB_ROUTE(app, "/redfish/v1/SessionService/Sessions/<str>/")
+@@ -75,34 +188,79 @@ inline void requestRoutesSession(App& app)
+ auto session = persistent_data::SessionStore::getInstance()
+ .getSessionByUid(sessionId);
+
+- if (session == nullptr)
+- {
+- messages::resourceNotFound(asyncResp->res, "Session",
+- sessionId);
+- return;
+- }
+-
+ // Perform a proper ConfigureSelf authority check. If a
+ // session is being used to DELETE some other user's session,
+ // then the ConfigureSelf privilege does not apply. In that
+ // case, perform the authority check again without the user's
+ // ConfigureSelf privilege.
+- if (session->username != req.session->username)
++ if (session)
+ {
+- Privileges effectiveUserPrivileges =
+- redfish::getUserPrivileges(req.userRole);
+-
+- if (!effectiveUserPrivileges.isSupersetOf(
+- {"ConfigureUsers"}))
++ if (session->username != req.session->username)
+ {
+- messages::insufficientPrivilege(asyncResp->res);
+- return;
++ Privileges effectiveUserPrivileges =
++ redfish::getUserPrivileges(req.userRole);
++
++ if (!effectiveUserPrivileges.isSupersetOf(
++ {"ConfigureUsers"}))
++ {
++ messages::insufficientPrivilege(asyncResp->res);
++ return;
++ }
+ }
++ persistent_data::SessionStore::getInstance().removeSession(
++ session);
++ messages::success(asyncResp->res);
++ return;
+ }
+
+- persistent_data::SessionStore::getInstance().removeSession(
+- session);
+- messages::success(asyncResp->res);
++ std::array<std::string, 1> interfaces = {
++ "xyz.openbmc_project.Ipmi.SessionInfo"};
++ crow::connections::systemBus->async_method_call(
++ [asyncResp,
++ sessionId](const boost::system::error_code ec,
++ const std::vector<std::string>& ifaceList) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying GetSubTreePaths "
++ "with Object Mapper. "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (ifaceList.size() == 0)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Can't find Session Info Attributes!";
++ return;
++ }
++ bool ipmiSessionFound = false;
++ for (const std::string& ipmiSessionPath : ifaceList)
++ {
++ if (!boost::ends_with(ipmiSessionPath, sessionId))
++ {
++ continue;
++ }
++ ipmiSessionFound = true;
++ break;
++ }
++ if (ipmiSessionFound)
++ {
++ BMCWEB_LOG_DEBUG << "Deleting IPMI session from "
++ "Redfish is not allowed.";
++ messages::actionNotSupported(
++ asyncResp->res,
++ "deleting IPMI session from Redfish");
++ return;
++ }
++ messages::resourceNotFound(asyncResp->res, "Session",
++ sessionId);
++ return;
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
++ 0, interfaces);
+ });
+
+ BMCWEB_ROUTE(app, "/redfish/v1/SessionService/Sessions/")
+@@ -131,6 +289,48 @@ inline void requestRoutesSession(App& app)
+ "/redfish/v1/SessionService/Sessions/";
+ asyncResp->res.jsonValue["Name"] = "Session Collection";
+ asyncResp->res.jsonValue["Description"] = "Session Collection";
++
++ std::array<std::string, 1> interfaces = {
++ "xyz.openbmc_project.Ipmi.SessionInfo"};
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::vector<std::string>& ifaceList) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying GetSubTreePaths "
++ "with Object Mapper. "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (ifaceList.size() == 0)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Can't find Session Info Attributes!";
++ return;
++ }
++ for (const std::string& ipmiSessionPath : ifaceList)
++ {
++ std::filesystem::path filePath(ipmiSessionPath);
++ std::string ipmiSessionID =
++ filePath.has_filename() ? filePath.filename()
++ : "";
++ if (!ipmiSessionID.empty() && ipmiSessionID != "0")
++ {
++ asyncResp->res.jsonValue["Members"].push_back(
++ {{"@odata.id",
++ "/redfish/v1/SessionService/Sessions/" +
++ ipmiSessionID}});
++ }
++ }
++ asyncResp->res.jsonValue["Members@odata.count"] =
++ asyncResp->res.jsonValue["Members"].size();
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
++ 0, interfaces);
+ });
+
+ BMCWEB_ROUTE(app, "/redfish/v1/SessionService/Sessions/")
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0024-Add-count-sensor-type.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0024-Add-count-sensor-type.patch
new file mode 100644
index 000000000..22ae05fa3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0024-Add-count-sensor-type.patch
@@ -0,0 +1,29 @@
+From 94a0ae774933b7801d0c8d843b3ac3a39a5e5646 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Adrian=20Ambro=C5=BCewicz?= <adrian.ambrozewicz@intel.com>
+Date: Fri, 30 Jul 2021 15:25:29 +0200
+Subject: [PATCH] Add 'count' sensor type
+
+PMT exposes data mainly in raw counter formats. This change makes
+bmcweb aware of new sensor type.
+
+Testing:
+- values of type 'count' from PMT exposed successfully on Redfish
+---
+ redfish-core/lib/sensors.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index 45a1eb6..7405e5a 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -63,6 +63,7 @@ static const boost::container::flat_map<std::string_view,
+ {node::sensors,
+ {"/xyz/openbmc_project/sensors/power",
+ "/xyz/openbmc_project/sensors/current",
++ "/xyz/openbmc_project/sensors/count",
+ "/xyz/openbmc_project/sensors/airflow",
+ #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
+ "/xyz/openbmc_project/sensors/voltage",
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0025-Add-Model-CoreCount-to-ProcessorSummary.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0025-Add-Model-CoreCount-to-ProcessorSummary.patch
new file mode 100644
index 000000000..edf4d219e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0025-Add-Model-CoreCount-to-ProcessorSummary.patch
@@ -0,0 +1,288 @@
+From f4f15a52610d1a199ddac948c8f849df05d86151 Mon Sep 17 00:00:00 2001
+From: Ali Ahmed <ama213000@gmail.com>
+Date: Fri, 3 Sep 2021 02:33:43 -0500
+Subject: [PATCH] Add Model & CoreCount to ProcessorSummary
+
+In Redfish ComputerSystem schema, the ProcessorSummary parameter
+lists summary information of the Processors on the system. This commit
+adds the 'Model' and 'CoreCount' properties to ProcessorSummary.
+
+If the CPU Models are different, then the 'Model' field takes the first
+entry in alphabetical order.
+
+Testing:
+1. Redfish Validator Testing successfully passed.
+2. Curl testing:
+
+curl -k -H "X-Auth-Token: $tok" https://$bmc/redfish/v1/Systems/system
+
+...
+ "ProcessorSummary": {
+ "CoreCount": 24,
+ "Count": 2,
+ "Model": "test_name",
+ "Status": {
+ "Health": "OK",
+ "HealthRollup": "OK",
+ "State": "Disabled"
+ }
+ },
+...
+
+Change-Id: I39cbf6ed35c35ce3a3551c9689237d5023775326
+Signed-off-by: Ali Ahmed <ama213000@gmail.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ redfish-core/lib/systems.hpp | 229 ++++++++++++++++++++++-------------
+ 1 file changed, 147 insertions(+), 82 deletions(-)
+
+diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
+index 680a0ee..3b5f9e4 100644
+--- a/redfish-core/lib/systems.hpp
++++ b/redfish-core/lib/systems.hpp
+@@ -139,6 +139,152 @@ inline void
+ }
+ }
+
++inline void getProcessorProperties(
++ const std::shared_ptr<bmcweb::AsyncResp>& aResp, const std::string& service,
++ const std::string& path,
++ const std::vector<std::pair<
++ std::string, std::variant<std::string, uint64_t, uint32_t, uint16_t>>>&
++ properties)
++{
++
++ BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties.";
++
++ auto getCpuPresenceState =
++ [aResp](const boost::system::error_code ec3,
++ const std::variant<bool>& cpuPresenceCheck) {
++ if (ec3)
++ {
++ BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
++ return;
++ }
++ modifyCpuPresenceState(aResp, cpuPresenceCheck);
++ };
++
++ auto getCpuFunctionalState =
++ [aResp](const boost::system::error_code ec3,
++ const std::variant<bool>& cpuFunctionalCheck) {
++ if (ec3)
++ {
++ BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
++ return;
++ }
++ modifyCpuFunctionalState(aResp, cpuFunctionalCheck);
++ };
++
++ // Get the Presence of CPU
++ crow::connections::systemBus->async_method_call(
++ std::move(getCpuPresenceState), service, path,
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.Inventory.Item", "Present");
++
++ // Get the Functional State
++ crow::connections::systemBus->async_method_call(
++ std::move(getCpuFunctionalState), service, path,
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional");
++
++ for (const auto& property : properties)
++ {
++ if (property.first == "Family")
++ {
++ // Get the CPU Model
++ const std::string* modelStr =
++ std::get_if<std::string>(&property.second);
++ if (!modelStr)
++ {
++ BMCWEB_LOG_DEBUG << "Failed to get CPU Family";
++ // Skip it and continue with other properties
++ continue;
++ }
++ if ((*modelStr).size() < 1)
++ {
++ BMCWEB_LOG_DEBUG << "Empty CPU Family info, skipping...";
++ continue;
++ }
++ nlohmann::json& prevModel =
++ aResp->res.jsonValue["ProcessorSummary"]["Model"];
++ std::string* prevModelPtr = prevModel.get_ptr<std::string*>();
++
++ // If CPU Models are different, use the first entry in
++ // alphabetical order
++
++ // If Model has never been set
++ // before, set it to *modelStr
++ if (prevModelPtr == nullptr)
++ {
++ prevModel = *modelStr;
++ }
++ // If Model has been set before, only change if new Model is
++ // higher in alphabetical order
++ else
++ {
++ if (*modelStr < *prevModelPtr)
++ {
++ prevModel = *modelStr;
++ }
++ }
++ }
++ else if (property.first == "CoreCount")
++ {
++ // Get CPU CoreCount and add it to the total
++ const uint16_t* coreCountVal =
++ std::get_if<uint16_t>(&property.second);
++
++ if (!coreCountVal)
++ {
++ BMCWEB_LOG_DEBUG << "Failed to get CPU Core count";
++ // Skip it and continue with other properties
++ continue;
++ }
++
++ nlohmann::json& coreCount =
++ aResp->res.jsonValue["ProcessorSummary"]["CoreCount"];
++ uint64_t* coreCountPtr = coreCount.get_ptr<uint64_t*>();
++
++ if (coreCountPtr == nullptr)
++ {
++ coreCount = *coreCountVal;
++ }
++ else
++ {
++ *coreCountPtr += *coreCountVal;
++ }
++ }
++ }
++}
++
++/*
++ * @brief Get ProcessorSummary fields
++ *
++ * @param[in] aResp Shared pointer for completing asynchronous calls
++ * @param[in] service dbus service for Cpu Information
++ * @param[in] path dbus path for Cpu
++ *
++ * @return None.
++ */
++inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
++ const std::string& service,
++ const std::string& path)
++{
++
++ crow::connections::systemBus->async_method_call(
++ [aResp, service,
++ path](const boost::system::error_code ec2,
++ const std::vector<std::pair<
++ std::string, std::variant<std::string, uint64_t, uint32_t,
++ uint16_t>>>& properties) {
++ if (ec2)
++ {
++ BMCWEB_LOG_ERROR << "DBUS response error " << ec2;
++ messages::internalError(aResp->res);
++ return;
++ }
++ getProcessorProperties(aResp, service, path, properties);
++ },
++ service, path, "org.freedesktop.DBus.Properties", "GetAll",
++ "xyz.openbmc_project.Inventory.Item.Cpu");
++}
++
+ /*
+ * @brief Retrieves computer system properties over dbus
+ *
+@@ -309,88 +455,7 @@ inline void
+ BMCWEB_LOG_DEBUG
+ << "Found Cpu, now get its properties.";
+
+- crow::connections::systemBus->async_method_call(
+- [aResp, service{connection.first},
+- path](const boost::system::error_code ec2,
+- const std::vector<
+- std::pair<std::string, VariantType>>&
+- properties) {
+- if (ec2)
+- {
+- BMCWEB_LOG_ERROR
+- << "DBUS response error " << ec2;
+- messages::internalError(aResp->res);
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "Got "
+- << properties.size()
+- << " Cpu properties.";
+-
+- auto getCpuPresenceState =
+- [aResp](
+- const boost::system::error_code ec3,
+- const std::variant<bool>&
+- cpuPresenceCheck) {
+- if (ec3)
+- {
+- BMCWEB_LOG_ERROR
+- << "DBUS response error "
+- << ec3;
+- return;
+- }
+- modifyCpuPresenceState(
+- aResp, cpuPresenceCheck);
+- };
+-
+- auto getCpuFunctionalState =
+- [aResp](
+- const boost::system::error_code ec3,
+- const std::variant<bool>&
+- cpuFunctionalCheck) {
+- if (ec3)
+- {
+- BMCWEB_LOG_ERROR
+- << "DBUS response error "
+- << ec3;
+- return;
+- }
+- modifyCpuFunctionalState(
+- aResp, cpuFunctionalCheck);
+- };
+-
+- // Get the Presence of CPU
+- crow::connections::systemBus
+- ->async_method_call(
+- std::move(getCpuPresenceState),
+- service, path,
+- "org.freedesktop.DBus."
+- "Properties",
+- "Get",
+- "xyz.openbmc_project.Inventory."
+- "Item",
+- "Present");
+-
+- // Get the Functional State
+- crow::connections::systemBus
+- ->async_method_call(
+- std::move(getCpuFunctionalState),
+- service, path,
+- "org.freedesktop.DBus."
+- "Properties",
+- "Get",
+- "xyz.openbmc_project.State."
+- "Decorator."
+- "OperationalStatus",
+- "Functional");
+-
+- // Get the MODEL from
+- // xyz.openbmc_project.Inventory.Decorator.Asset
+- // support it later as Model is Empty
+- // currently.
+- },
+- connection.first, path,
+- "org.freedesktop.DBus.Properties", "GetAll",
+- "xyz.openbmc_project.Inventory.Item.Cpu");
++ getProcessorSummary(aResp, connection.first, path);
+
+ cpuHealth->inventory.emplace_back(path);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch
new file mode 100644
index 000000000..19a392873
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch
@@ -0,0 +1,875 @@
+From bde7f728d5a87522674bcd5515baaa02bf7b9373 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 4 Sep 2020 19:24:25 +0800
+Subject: [PATCH] Define Redfish interface "/Registries/Bios" and enable
+ Attributes property
+
+1. Define Redfish interface "/Registries/Bios" for BIOS Attribute Registry
+ RBC Daemon provide method to get BIOS attribute registry.
+2. Eanble Attributes property for BIOS resource
+3. Define Redfish interface "/Systems/system/Bios/Settings" for BIOS
+settings
+4. RBC daemon is at
+https://gerrit.openbmc-project.xyz/#/c/openbmc/bios-settings-mgr/+/35563/
+5. IPMI command implementation is at
+https://gerrit.openbmc-project.xyz/#/c/openbmc/intel-ipmi-oem/+/30827/
+6. Property design is at
+https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/xyz/openbmc_project/BIOSConfig
+7. Design doc is at
+https://github.com/openbmc/docs/blob/master/designs/remote-bios-configuration.md
+8. There will be 95 test cases for this feature in the validation team.
+
+Tested:
+
+1. Use postman (Redfish tool) could get all the attributes in bios
+resouce, get bios settings, get bios attribute
+registry.
+https://IP_ADDR/redfish/v1/Systems/system/Bios
+{
+ "@Redfish.Settings": {
+ "@odata.type": "#Settings.v1_3_0.Settings",
+ "SettingsObject": {
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings"
+ }
+ },
+ "@odata.id": "/redfish/v1/Systems/system/Bios",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "Actions": {
+ "#Bios.ChangePassword": {
+ "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"
+ },
+ "#Bios.ResetBios": {
+ "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"
+ }
+ },
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "attr0": "current value"
+ },
+ "Description": "BIOS Configuration Service",
+ "Id": "BIOS",
+ "Links": {
+ "ActiveSoftwareImage": {
+ "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ },
+ "SoftwareImages": [
+ {
+ "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ }
+ ],
+ "SoftwareImages@odata.count": 1
+ },
+ "Name": "BIOS Configuration"
+}
+
+Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry
+{
+ "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry",
+ "@odata.type": "#MessageRegistryFile.v1_1_0.MessageRegistryFile",
+ "Description": "BiosAttributeRegistry Message Registry File Location",
+ "Id": "BiosAttributeRegistry",
+ "Languages": [
+ "en"
+ ],
+ "Languages@odata.count": 1,
+ "Location": [
+ {
+ "Language": "en",
+ "Uri": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry"
+ }
+ ],
+ "Location@odata.count": 1,
+ "Name": "BiosAttributeRegistry Message Registry File",
+ "Registry": "BiosAttributeRegistry.1.0.0"
+}
+
+Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry
+{
+ "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry",
+ "@odata.type": "#AttributeRegistry.v1_3_2.AttributeRegistry",
+ "Id": "BiosAttributeRegistry",
+ "Language": "en",
+ "Name": "Bios Attribute Registry",
+ "OwningEntity": "OpenBMC",
+ "RegistryEntries": {
+ "Attributes": [
+ {
+ "AttributeName": "attr0",
+ "CurrentValue": "current value",
+ "DefaultValue": "default value",
+ "DisplayName": "display name for attr0",
+ "HelpText": "description for attr0",
+ "MenuPath": "./menu/path/for/attr0",
+ "ReadOnly": false,
+ "Type": "String",
+ "Value": []
+ }
+ ]
+ },
+ "RegistryVersion": "1.0.0"
+}
+
+https://BMC_IPADDR/redfish/v1/Systems/system/Bios/Settings
+{
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "QuietBoot": "0x0"
+ },
+ "Id": "BiosSettingsV1",
+ "Name": "Bios Settings Version 1"
+}
+
+2. Passed Validator check for bios resource and bios attribute registry
+*** /redfish/v1/Systems/system/Bios
+INFO - Type (#Bios.v1_1_0.Bios), GET SUCCESS (time: 1.57377)
+INFO - PASS
+*** /redfish/v1/Registries/BiosAttributeRegistry
+INFO - Type (#MessageRegistryFile.v1_1_0.MessageRegistryFile), GET SUCCESS (time: 0.075438)
+INFO - PASS
+INFO -
+*** /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry
+INFO - Type (#AttributeRegistry.v1_3_2.AttributeRegistry), GET SUCCESS (time: 0.075751)
+INFO - PASS
+
+@odata.id /redfish/v1/Systems/system/Bios odata Exists PASS
+@odata.type #Settings.v1_3_0.Settings odata Exists PASS
+Links [JSON Object] Bios.v1_1_0.Links Yes complex
+Links.ActiveSoftwareImage Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active link to: SoftwareInventory Yes PASS
+Links.SoftwareImages Array (size: 1) array of: SoftwareInventory Yes ...
+Links.SoftwareImages[0] Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active SoftwareInventory Yes PASS
+Links.Oem - Resource.Oem No Optional
+SoftwareImages@odata.count 1 odata Exists PASS
+AttributeRegistry BiosAttributeRegistry string Yes PASS
+Actions [JSON Object] Bios.v1_0_0.Actions Yes complex
+Actions.#Bios.ResetBios Action - Yes PASS
+Actions.#Bios.ChangePassword Action - Yes PASS
+Attributes [JSON Object] Bios.v1_0_0.Attributes Yes complex
+Attributes.attr0 current value primitive Yes PASS
+Id BIOS string Yes PASS
+Description BIOS Configuration Service string Yes PASS
+Name BIOS Configuration string Yes PASS
+Oem - Resource.Oem No Optional
+@Redfish.Settings [JSON Object] Settings.Settings Yes complex
+@Redfish.Settings.MaintenanceWindowResource - link to: ItemOrCollection No Optional
+@Redfish.Settings.SupportedApplyTimes - string (enum) No Optional
+@Redfish.Settings.Time - date No Optional
+@Redfish.Settings.ETag - string No Optional
+@Redfish.Settings.SettingsObject Link: /redfish/v1/Systems/system/Bios/Settings link to: Item Yes PASS
+@Redfish.Settings.Messages - Message No Optional
+
+@odata.id /redfish/v1/Registries/BiosAttributeRegistry odata Exists PASS
+@odata.type #MessageRegistryFile.v1_1_0.MessageRegistryFile odata Exists PASS
+Languages@odata.count 1 odata Exists PASS
+Location@odata.count 1 odata Exists PASS
+Actions - MessageRegistryFile.v1_1_0.Actions No Optional
+Languages Array (size: 1) string Yes ...
+Languages[0] en string Yes PASS
+Registry BiosAttributeRegistry.1.0.0 string Yes PASS
+Location Array (size: 1) array of: Location Yes ...
+Location[0] [JSON Object] Location Yes complex
+Location[0].Language en string Yes PASS
+Location[0].Uri /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry string Yes PASS
+Location[0].ArchiveUri - string No Optional
+Location[0].PublicationUri - string No Optional
+Location[0].ArchiveFile - string No Optional
+Id BiosAttributeRegistry string Yes PASS
+Description BiosAttributeRegistry Message Registry File Location string Yes PASS
+Name BiosAttributeRegistry Message Registry File string Yes PASS
+Oem - Resource.Oem No Optional
+
+@odata.id /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry odata Exists PASS
+@odata.type #AttributeRegistry.v1_3_2.AttributeRegistry odata Exists PASS
+Actions - AttributeRegistry.v1_1_0.Actions No Optional
+Language en string Yes PASS
+RegistryVersion 1.0.0 string Yes PASS
+OwningEntity OpenBMC string Yes PASS
+SupportedSystems - SupportedSystems No Optional
+RegistryEntries [JSON Object] AttributeRegistry.v1_0_0.RegistryEntries Yes complex
+RegistryEntries.Attributes Array (size: 1) array of: Attributes Yes ...
+RegistryEntries.Attributes[0] [JSON Object] Attributes Yes complex
+RegistryEntries.Attributes[0].Oem - Resource.Oem No Optional
+RegistryEntries.Attributes[0].ResetRequired - boolean No Optional
+RegistryEntries.Attributes[0].UefiDevicePath - string No Optional
+RegistryEntries.Attributes[0].UefiKeywordName - string No Optional
+RegistryEntries.Attributes[0].UefiNamespaceId - string No Optional
+RegistryEntries.Attributes[0].AttributeName attr0 string Yes PASS
+RegistryEntries.Attributes[0].Type String string (enum) Yes PASS
+RegistryEntries.Attributes[0].Value Array (size: 0) array of: AttributeValue Yes ...
+RegistryEntries.Attributes[0].DisplayName display name for attr0 string Yes PASS
+RegistryEntries.Attributes[0].HelpText description for attr0 string Yes PASS
+RegistryEntries.Attributes[0].WarningText - string No Optional
+RegistryEntries.Attributes[0].CurrentValue current value primitive Yes PASS
+RegistryEntries.Attributes[0].DefaultValue default value primitive Yes PASS
+RegistryEntries.Attributes[0].DisplayOrder - number No Optional
+RegistryEntries.Attributes[0].MenuPath ./menu/path/for/attr0 string Yes PASS
+RegistryEntries.Attributes[0].ReadOnly False boolean Yes PASS
+RegistryEntries.Attributes[0].WriteOnly - boolean No Optional
+RegistryEntries.Attributes[0].GrayOut - boolean No Optional
+RegistryEntries.Attributes[0].Hidden - boolean No Optional
+RegistryEntries.Attributes[0].Immutable - boolean No Optional
+RegistryEntries.Attributes[0].IsSystemUniqueProperty - boolean No Optional
+RegistryEntries.Attributes[0].MaxLength - number No Optional
+RegistryEntries.Attributes[0].MinLength - number No Optional
+RegistryEntries.Attributes[0].ScalarIncrement - number No Optional
+RegistryEntries.Attributes[0].UpperBound - number No Optional
+RegistryEntries.Attributes[0].LowerBound - number No Optional
+RegistryEntries.Attributes[0].ValueExpression - string No Optional
+RegistryEntries.Menus - Menus No Optional
+RegistryEntries.Dependencies - Dependencies No Optional
+Id BiosAttributeRegistry string Yes PASS
+Description - string No Optional
+Name Bios Attribute Registry string Yes PASS
+Oem - Resource.Oem No Optional
+
+Change-Id: Iecc61018c350f0b8c89df59b2864b941508b1916
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com>
+---
+ redfish-core/include/redfish.hpp | 3 +
+ .../include/registries/bios_registry.hpp | 41 ++
+ redfish-core/lib/bios.hpp | 511 ++++++++++++++++++
+ redfish-core/lib/message_registries.hpp | 11 +-
+ 4 files changed, 565 insertions(+), 1 deletion(-)
+ create mode 100644 redfish-core/include/registries/bios_registry.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 0a97150..07a9417 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -148,7 +148,10 @@ class RedfishService
+ requestRoutesSystemActionsReset(app);
+ requestRoutesSystemResetActionInfo(app);
+ requestRoutesBiosService(app);
++ requestRoutesBiosSettings(app);
++ requestRoutesBiosAttributeRegistry(app);
+ requestRoutesBiosReset(app);
++ requestRoutesBiosChangePassword(app);
+
+ #ifdef BMCWEB_ENABLE_VM_NBDPROXY
+ requestNBDVirtualMediaRoutes(app);
+diff --git a/redfish-core/include/registries/bios_registry.hpp b/redfish-core/include/registries/bios_registry.hpp
+new file mode 100644
+index 0000000..c80937a
+--- /dev/null
++++ b/redfish-core/include/registries/bios_registry.hpp
+@@ -0,0 +1,41 @@
++/*
++// Copyright (c) 2020 Intel Corporation
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++*/
++#pragma once
++#include <registries.hpp>
++
++namespace redfish::message_registries::bios
++{
++const Header header = {
++ "Copyright 2020 OpenBMC. All rights reserved.",
++ "#MessageRegistry.v1_4_0.MessageRegistry",
++ "BiosAttributeRegistry.1.0.0",
++ "Bios Attribute Registry",
++ "en",
++ "This registry defines the messages for bios attribute registry.",
++ "BiosAttributeRegistry",
++ "1.0.0",
++ "OpenBMC",
++};
++// BiosAttributeRegistry registry is not defined in DMTF, We should use
++// OEM defined registries for this purpose.
++// Below link is wrong - We need to define OEM registries and use
++// appropriate data here.
++constexpr const char* url =
++ "https://redfish.dmtf.org/registries/BiosAttributeRegistry.1.0.0.json";
++
++constexpr std::array<MessageEntry, 0> registry = {
++};
++} // namespace redfish::message_registries::bios
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index c2fb284..87536d6 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -3,8 +3,140 @@
+ #include <app.hpp>
+ #include <registries/privilege_registry.hpp>
+ #include <utils/fw_utils.hpp>
++
+ namespace redfish
+ {
++
++/*baseBIOSTable
++map{attributeName,struct{attributeType,readonlyStatus,displayname,
++ description,menuPath,current,default,
++ array{struct{optionstring,optionvalue}}}}
++*/
++using BiosBaseTableType = std::vector<std::pair<
++ std::string,
++ std::tuple<
++ std::string, bool, std::string, std::string, std::string,
++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
++ std::vector<
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>>;
++using BiosBaseTableItemType = std::pair<
++ std::string,
++ std::tuple<
++ std::string, bool, std::string, std::string, std::string,
++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
++ std::vector<
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>;
++using OptionsItemType =
++ std::tuple<std::string, std::variant<int64_t, std::string>>;
++
++enum BiosBaseTableIndex
++{
++ biosBaseAttrType = 0,
++ biosBaseReadonlyStatus,
++ biosBaseDisplayName,
++ biosBaseDescription,
++ biosBaseMenuPath,
++ biosBaseCurrValue,
++ biosBaseDefaultValue,
++ biosBaseOptions
++};
++enum OptionsItemIndex
++{
++ optItemType = 0,
++ optItemValue
++};
++/*
++ The Pending attribute name and new value.
++ ex- { {"QuietBoot",Type.Integer, 0x1},
++ { "DdrFreqLimit",Type.String,"2933"}
++ }
++*/
++using PendingAttributesType = std::vector<std::pair<
++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>;
++using PendingAttributesItemType =
++ std::pair<std::string,
++ std::tuple<std::string, std::variant<int64_t, std::string>>>;
++enum PendingAttributesIndex
++{
++ pendingAttrType = 0,
++ pendingAttrValue
++};
++static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
++{
++ std::string ret;
++ if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
++ "AttributeType.Enumeration")
++ {
++ ret = "Enumeration";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.String")
++ {
++ ret = "String";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Password")
++ {
++ ret = "Password";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Integer")
++ {
++ ret = "Integer";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Boolean")
++ {
++ ret = "Boolean";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
++static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
++{
++ std::string ret;
++ if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.ScalarIncrement")
++ {
++ ret = "ScalarIncrement";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.LowerBound")
++ {
++ ret = "LowerBound";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.UpperBound")
++ {
++ ret = "UpperBound";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MinStringLength")
++ {
++ ret = "MinStringLength";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MaxStringLength")
++ {
++ ret = "MaxStringLength";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf")
++ {
++ ret = "OneOf";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
++
+ /**
+ * BiosService class supports handle get method for bios.
+ */
+@@ -23,6 +155,85 @@ inline void
+ // Get the ActiveSoftwareImage and SoftwareImages
+ fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose, "",
+ true);
++
++ asyncResp->res.jsonValue["@Redfish.Settings"] = {
++ {"@odata.type", "#Settings.v1_3_0.Settings"},
++ {"SettingsObject",
++ {{"@odata.id", "/redfish/v1/Systems/system/Bios/Settings"}}}};
++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ const std::string& service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>& retBiosTable) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "getBiosAttributes DBUS error: "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const BiosBaseTableItemType& item : *baseBiosTable)
++ {
++ const std::string& key = item.first;
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(item.second);
++ std::string attrType = mapAttrTypeToRedfish(itemType);
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseCurrValue>(item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr ? *currValue : "");
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<biosBaseCurrValue>(item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr ? *currValue : 0);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
+ }
+ inline void requestRoutesBiosService(App& app)
+ {
+@@ -31,6 +242,306 @@ inline void requestRoutesBiosService(App& app)
+ .methods(boost::beast::http::verb::get)(handleBiosServiceGet);
+ }
+
++/**
++ * BiosSettings class supports handle GET/PATCH method for
++ * BIOS configuration pending settings.
++ */
++inline void requestRoutesBiosSettings(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings")
++ .privileges(redfish::privileges::getBios)
++ .methods(boost::beast::http::verb::get)(
++ [](const crow::Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ asyncResp->res.jsonValue["@odata.id"] =
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Systems/system/Bios/Settings";
++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios";
++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1";
++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1";
++ asyncResp->res.jsonValue["AttributeRegistry"] =
++ "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec,
++ const std::variant<PendingAttributesType>&
++ retPendingAttributes) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "getBiosSettings DBUS error: " << ec;
++ messages::resourceNotFound(
++ asyncResp->res, "Systems/system/Bios",
++ "Settings");
++ return;
++ }
++ const PendingAttributesType* pendingAttributes =
++ std::get_if<PendingAttributesType>(
++ &retPendingAttributes);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (pendingAttributes == nullptr)
++ {
++ BMCWEB_LOG_ERROR
++ << "pendingAttributes == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const PendingAttributesItemType& item :
++ *pendingAttributes)
++ {
++ const std::string& key = item.first;
++ const std::string& itemType =
++ std::get<pendingAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<pendingAttrValue>(
++ item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr
++ ? *currValue
++ : "");
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue =
++ std::get_if<int64_t>(
++ &std::get<pendingAttrValue>(
++ item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr
++ ? *currValue
++ : 0);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "PendingAttributes");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ });
++}
++/**
++ * BiosAttributeRegistry class supports handle get method for BIOS attribute
++ * registry.
++ */
++inline void requestRoutesBiosAttributeRegistry(App& app)
++{
++ BMCWEB_ROUTE(
++ app,
++ "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry/")
++ .privileges(redfish::privileges::getBios)
++ .methods(
++ boost::beast::http::verb::
++ get)([](const crow::Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Registries/BiosAttributeRegistry/"
++ "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#AttributeRegistry.v1_3_2.AttributeRegistry";
++ asyncResp->res.jsonValue["Name"] = "Bios Attribute Registry";
++ asyncResp->res.jsonValue["Id"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["RegistryVersion"] = "1.0.0";
++ asyncResp->res.jsonValue["Language"] = "en";
++ asyncResp->res.jsonValue["OwningEntity"] = "OpenBMC";
++ asyncResp->res.jsonValue["RegistryEntries"]["Attributes"] =
++ nlohmann::json::array();
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "ObjectMapper::GetObject call failed: " << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>&
++ retBiosTable) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "getBiosAttributeRegistry DBUS error: "
++ << ec;
++ messages::resourceNotFound(
++ asyncResp->res, "Registries/Bios", "Bios");
++ return;
++ }
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++ nlohmann::json& attributeArray =
++ asyncResp->res
++ .jsonValue["RegistryEntries"]["Attributes"];
++ nlohmann::json optionsArray =
++ nlohmann::json::array();
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const BiosBaseTableItemType& item :
++ *baseBiosTable)
++ {
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR << "attrType == UNKNOWN";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ nlohmann::json attributeItem;
++ attributeItem["AttributeName"] = item.first;
++ attributeItem["Type"] = attrType;
++ attributeItem["ReadOnly"] =
++ std::get<biosBaseReadonlyStatus>(
++ item.second);
++ attributeItem["DisplayName"] =
++ std::get<biosBaseDisplayName>(item.second);
++ attributeItem["HelpText"] =
++ std::get<biosBaseDescription>(item.second);
++ attributeItem["MenuPath"] =
++ std::get<biosBaseMenuPath>(item.second);
++
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseCurrValue>(
++ item.second));
++ const std::string* defValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseDefaultValue>(
++ item.second));
++ attributeItem["CurrentValue"] =
++ currValue != nullptr ? *currValue : "";
++ attributeItem["DefaultValue"] =
++ defValue != nullptr ? *defValue : "";
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue =
++ std::get_if<int64_t>(
++ &std::get<biosBaseCurrValue>(
++ item.second));
++ const int64_t* defValue =
++ std::get_if<int64_t>(
++ &std::get<biosBaseDefaultValue>(
++ item.second));
++ attributeItem["CurrentValue"] =
++ currValue != nullptr ? *currValue : 0;
++ attributeItem["DefaultValue"] =
++ defValue != nullptr ? *defValue : 0;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::vector<OptionsItemType>&
++ optionsVector =
++ std::get<biosBaseOptions>(item.second);
++ for (const OptionsItemType& optItem :
++ optionsVector)
++ {
++ nlohmann::json optItemJson;
++ const std::string& strOptItemType =
++ std::get<optItemType>(optItem);
++ std::string optItemTypeRedfish =
++ mapBoundTypeToRedfish(strOptItemType);
++ if (optItemTypeRedfish == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR
++ << "optItemTypeRedfish == UNKNOWN";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (optItemTypeRedfish == "OneOf")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<optItemValue>(
++ optItem));
++ optItemJson[optItemTypeRedfish] =
++ currValue != nullptr ? *currValue
++ : "";
++ }
++ else
++ {
++ const int64_t* currValue =
++ std::get_if<int64_t>(
++ &std::get<optItemValue>(
++ optItem));
++ optItemJson[optItemTypeRedfish] =
++ currValue != nullptr ? *currValue
++ : 0;
++ }
++
++ optionsArray.push_back(optItemJson);
++ }
++
++ attributeItem["Value"] = optionsArray;
++ attributeArray.push_back(attributeItem);
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ });
++}
++
+ /**
+ * BiosReset class supports handle POST method for Reset bios.
+ * The class retrieves and sends data directly to D-Bus.
+diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp
+index 43359e3..b2fb43c 100644
+--- a/redfish-core/lib/message_registries.hpp
++++ b/redfish-core/lib/message_registries.hpp
+@@ -17,6 +17,7 @@
+
+ #include "registries.hpp"
+ #include "registries/base_message_registry.hpp"
++#include "registries/bios_registry.hpp"
+ #include "registries/openbmc_message_registry.hpp"
+ #include "registries/resource_event_message_registry.hpp"
+ #include "registries/task_event_message_registry.hpp"
+@@ -125,7 +126,6 @@ inline void requestRoutesMessageRegistryFile(App& app)
+ inline void handleMessageRegistryGet(
+ const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& registry, const std::string& registryMatch)
+-
+ {
+ const message_registries::Header* header;
+ std::vector<const message_registries::MessageEntry*> registryEntries;
+@@ -165,6 +165,15 @@ inline void handleMessageRegistryGet(
+ registryEntries.emplace_back(&entry);
+ }
+ }
++ else if (registry == "BiosAttributeRegistry")
++ {
++ header = &message_registries::bios::header;
++ for (const message_registries::MessageEntry& entry :
++ message_registries::bios::registry)
++ {
++ registryEntries.emplace_back(&entry);
++ }
++ }
+ else
+ {
+ messages::resourceNotFound(
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch
new file mode 100644
index 000000000..099e6ddf5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch
@@ -0,0 +1,148 @@
+From ffa924ef204930a5bb442bf654eac02543acfb8f Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Wed, 30 Jun 2021 15:18:46 +0000
+Subject: [PATCH 2/5] BaseBiosTable: Add support for PATCH operation
+
+This commit brings in support for PATCH operation of the
+bios variables that updates the BaseBiosTable.
+
+Tested-By:
+* Passed Redfish validator
+
+* Single Attribute:
+PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d
+'{"data":[{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>}]}'
+
+* Multiple Attributes:
+PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d
+'{"data":[{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>},
+{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>}]}'
+
+This makes use of the "Set" of "PendingAttributes" in the
+backend and that updates the BaseBiosTable.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Change-Id: I12e78e5ac623c264c7a3e1dd5198aca67172736d
+---
+ redfish-core/lib/bios.hpp | 95 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 95 insertions(+)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index c1a5c56..14d2171 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -96,6 +96,29 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
+
+ return ret;
+ }
++static std::string mapRedfishToAttrType(const std::string_view type)
++{
++ std::string ret;
++ if (type == "string")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
++ }
++ else if (type == "int")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer";
++ }
++ else if (type == "enum")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
++ "Enumeration";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
+ static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
+ {
+ std::string ret;
+@@ -370,6 +393,78 @@ inline void requestRoutesBiosSettings(App& app)
+ "/xyz/openbmc_project/bios_config/manager",
+ std::array<const char*, 0>());
+ });
++
++ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings")
++ .privileges({{"ConfigureComponents"}})
++ .methods(boost::beast::http::verb::patch)(
++ [](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ nlohmann::json inpJson;
++
++ if (!redfish::json_util::readJson(req, asyncResp->res, "data",
++ inpJson))
++ {
++ return;
++ }
++
++ for (auto& attrInfo : inpJson)
++ {
++ std::optional<std::string> attrName;
++ std::optional<std::string> attrType;
++ std::optional<std::string> attrValue;
++ if (!json_util::getValueFromJsonObject(
++ attrInfo, "AttributeName", attrName))
++ {
++ messages::propertyMissing(asyncResp->res,
++ "AttributeName");
++ return;
++ }
++ if (!json_util::getValueFromJsonObject(
++ attrInfo, "AttributeType", attrType))
++ {
++ messages::propertyMissing(asyncResp->res,
++ "AttributeType");
++ return;
++ }
++ if (!json_util::getValueFromJsonObject(
++ attrInfo, "AttributeValue", attrValue))
++ {
++ messages::propertyMissing(asyncResp->res,
++ "AttributeValue");
++ return;
++ }
++ std::string biosAttrType = mapRedfishToAttrType(*attrType);
++
++ if (biosAttrType == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR << "Invalid attribute type";
++ messages::propertyValueNotInList(
++ asyncResp->res, "AttributeType", *attrType);
++ return;
++ }
++
++ PendingAttributesType pendingAttributes;
++ pendingAttributes.emplace_back(std::make_pair(
++ *attrName, std::make_tuple(biosAttrType, *attrValue)));
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "doPatch resp_handler got error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ },
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "PendingAttributes",
++ std::variant<PendingAttributesType>(pendingAttributes));
++ }
++ });
+ }
+ /**
+ * BiosAttributeRegistry class supports handle get method for BIOS attribute
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch
new file mode 100644
index 000000000..5ed92cc3e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch
@@ -0,0 +1,53 @@
+From b7adca60dd69ac9566dc8f417065e244198fc711 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 6 Oct 2021 22:27:20 +0000
+Subject: [PATCH] Add support to ResetBios action
+
+Tested:
+
+Bios reset flag can be modified throw redfish
+POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios
+
+Change-Id: Ic719c55705e5f634539b3dd858b60922e505a8d0
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ redfish-core/lib/bios.hpp | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index f5aa7b7..f613613 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -648,17 +648,23 @@ inline void
+ handleBiosResetPost(const crow::Request&,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+ {
++ std::string resetFlag =
++ "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.FactoryDefaults";
++
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "Failed to reset bios: " << ec;
++ BMCWEB_LOG_ERROR << "doPost bios reset got error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ },
+- "org.open_power.Software.Host.Updater", "/xyz/openbmc_project/software",
+- "xyz.openbmc_project.Common.FactoryReset", "Reset");
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager", "ResetBIOSSettings",
++ std::variant<std::string>(resetFlag));
+ }
+
+ inline void requestRoutesBiosReset(App& app)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch
new file mode 100644
index 000000000..4bfca3006
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch
@@ -0,0 +1,117 @@
+From 22956921a228f6f1cbbbd3045a3cc3969732dca3 Mon Sep 17 00:00:00 2001
+From: Arun Lal K M <arun.lal@intel.com>
+Date: Fri, 8 Oct 2021 20:56:00 +0000
+Subject: [PATCH] Add support to ChangePassword action
+
+Tested:
+
+Passed Redfish validator.
+Bios change password:
+root@intel-obmc:~# cat /var/lib/bios-settings-manager/seedData
+{
+"UserPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
+"AdminPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
+"Seed": "123456",
+"HashAlgo": "SHA384"
+}
+POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword
+{
+ "NewPassword": "12345678",
+ "OldPassword": "1234567890",
+ "PasswordName": "Administrator"
+}
+root@intel-obmc:~# cat /var/lib/bios-settings-manager/passwordData
+{
+ "CurrentPassword": "1234567890",
+ "IsAdminPwdChanged": 1,
+ "IsUserPwdChanged": 0,
+ "NewPassword": "2DD65D57EB60B1D92C5F3D2DC84724FCEE7BC02E57AA75E834712266ED94CAC704047B2FF7CEC1C36BED280B36BB5AC6",
+ "UserName": "Administrator"
+}
+
+Signed-off-by: Arun Lal K M <arun.lal@intel.com>
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/lib/bios.hpp | 59 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index f613613..b06a904 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -175,6 +175,10 @@ inline void
+ asyncResp->res.jsonValue["Actions"]["#Bios.ResetBios"] = {
+ {"target", "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"}};
+
++ asyncResp->res.jsonValue["Actions"]["#Bios.ChangePassword"] = {
++ {"target", "/redfish/v1/Systems/system/Bios/Actions/"
++ "Bios.ChangePassword"}};
++
+ // Get the ActiveSoftwareImage and SoftwareImages
+ fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose, "",
+ true);
+@@ -265,6 +269,61 @@ inline void requestRoutesBiosService(App& app)
+ .methods(boost::beast::http::verb::get)(handleBiosServiceGet);
+ }
+
++/**
++ * BiosChangePassword class supports handle POST method for change bios
++ * password. The class retrieves and sends data directly to D-Bus.
++ */
++inline void requestRoutesBiosChangePassword(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/")
++ .privileges({{"ConfigureComponents"}})
++ .methods(boost::beast::http::verb::post)(
++ [](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ std::string currentPassword, newPassword, userName;
++ if (!json_util::readJson(req, asyncResp->res, "NewPassword",
++ newPassword, "OldPassword",
++ currentPassword, "PasswordName",
++ userName))
++ {
++ return;
++ }
++ if (currentPassword.empty())
++ {
++ messages::actionParameterUnknown(
++ asyncResp->res, "ChangePassword", "OldPassword");
++ return;
++ }
++ if (newPassword.empty())
++ {
++ messages::actionParameterUnknown(
++ asyncResp->res, "ChangePassword", "NewPassword");
++ return;
++ }
++ if (userName.empty())
++ {
++ messages::actionParameterUnknown(
++ asyncResp->res, "ChangePassword", "PasswordName");
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_CRITICAL
++ << "Failed in doPost(BiosChangePassword) "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ },
++ "xyz.openbmc_project.BIOSConfigPassword",
++ "/xyz/openbmc_project/bios_config/password",
++ "xyz.openbmc_project.BIOSConfig.Password", "ChangePassword",
++ userName, currentPassword, newPassword);
++ });
++}
++
+ /**
+ * BiosSettings class supports handle GET/PATCH method for
+ * BIOS configuration pending settings.
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch
new file mode 100644
index 000000000..26393bfee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch
@@ -0,0 +1,46 @@
+From edc6925e8c0d9f60da1f70c524261efaf05b2710 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Wed, 30 Jun 2021 15:42:06 +0000
+Subject: [PATCH 5/5] Fix:remove bios user pwd change option via Redfish
+
+BMC should not provide user bios setup password change option via
+Redfish as per bios security requirements. Only Admin BIOS setup
+password is supported.
+
+Added check for the password name action parameter and
+do not allow if it has User Password value from redfish side.
+
+Tested: sent POST query in redfish on URI:
+https://<ip>/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword
+error occurs for UserPassword parameter and allows for AdminPassword.
+
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+Change-Id: I169cc6a4f786625d9e8b8dfe56816d52b1740f4c
+---
+ redfish-core/lib/bios.hpp | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 0250c59..360a749 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -323,6 +323,16 @@ inline void requestRoutesBiosChangePassword(App& app)
+ asyncResp->res, "ChangePassword", "PasswordName");
+ return;
+ }
++
++ // In Intel BIOS, we are not supporting user password in BIOS
++ // setup
++ if (userName == "UserPassword")
++ {
++ messages::actionParameterUnknown(
++ asyncResp->res, "ChangePassword", "PasswordName");
++ return;
++ }
++
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch
new file mode 100644
index 000000000..2e72a639d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch
@@ -0,0 +1,928 @@
+From f75beb0472a42d5af512661470aadf12ac460470 Mon Sep 17 00:00:00 2001
+From: Arun Lal K M <arun.lal@intel.com>
+Date: Fri, 8 Oct 2021 21:30:33 +0000
+Subject: [PATCH] Add fix for broken feature 'Pending Attributes'.
+
+Fix is added for the following:
+1) GET to 'redfish/v1/Systems/system/Bios'.
+2) PATCH to 'redfish/v1/Systems/system/Bios/Settings'.
+3) GET to 'redfish/v1/Systems/system/Bios/Settings'.
+4) Fix for incremental duplicate values in BiosAttributeRegistry.
+5) POST to '/redfish/v1/Systems/system/Bios/Actions
+ /Bios.ChangePassword/'.
+
+Tested:
+By giving PATCH to 'redfish/v1/Systems/system/Bios/Settings'
+PATCH command raw data:
+{
+ "data":{
+ "AmpPrefetchEnable": "0x1",
+ "Ce2LmLoggingEn": "0x1",
+ "DfxEadrDebugLogs": "0x2",
+ "PsfUrEnable": "0x1",
+ "ATS": "0x0"
+ }
+}
+
+Response:
+{
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "#Message.v1_1_1.Message",
+ "Message": "Successfully Completed Request",
+ "MessageArgs": [],
+ "MessageId": "Base.1.8.1.Success",
+ "MessageSeverity": "OK",
+ "Resolution": "None"
+ }
+ ]
+}
+
+By giving GET to 'redfish/v1/Systems/system/Bios'
+Response:
+{
+ "@Redfish.Settings": {
+ "@odata.type": "#Settings.v1_3_0.Settings",
+ "SettingsObject": {
+ "@odata.id":
+ "/redfish/v1/Systems/system/Bios/Settings"
+ }
+ },
+ "@odata.id": "/redfish/v1/Systems/system/Bios",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "Actions": {
+ "#Bios.ChangePassword": {
+ "target":
+ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"
+ },
+ "#Bios.ResetBios": {
+ "target":
+ "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"
+ }
+ },
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "AEPErrorInjEn": "0x00",
+ "ARIEnable": "0x01",
+ "ARIForward": "0x00",
+ ...
+ ...
+ ...
+ "txEqCalibration": "0x01",
+ "volMemMode": "0x00",
+ "wrVrefCenter": "0x01"
+ },
+ "Description": "BIOS Configuration Service",
+ "Id": "BIOS",
+ "Links": {
+ "ActiveSoftwareImage": {
+ "@odata.id":
+ "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ },
+ "SoftwareImages": [
+ {
+ "@odata.id":
+ "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ }
+ ],
+ "SoftwareImages@odata.count": 1
+ },
+ "Name": "BIOS Configuration"
+}
+
+By giving GET to 'redfish/v1/Systems/system/Bios/Settings'
+Response:
+{
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "ATS": "0x0",
+ "AmpPrefetchEnable": "0x1",
+ "Ce2LmLoggingEn": "0x1",
+ "DfxEadrDebugLogs": "0x2",
+ "PsfUrEnable": "0x1"
+ },
+ "Id": "BiosSettingsV1",
+ "Name": "Bios Settings Version 1"
+}
+
+By giving POST to '/redfish/v1/Systems/system/Bios/Actions
+/Bios.ChangePassword/'
+Response: Success
+
+By running Redfish-Service-Validator
+Result:
+Elapsed time: 0:09:36
+invalidPropertyValue: 108
+metadataNamespaces: 2185
+missingNamespaces: 1
+optionalAction: 9
+pass: 13772
+passAction: 22
+passGet: 541
+reflink: 1
+repeat: 47
+serviceNamespaces: 75
+skipOptional: 9276
+unverifiedComplexAdditional: 1
+warnDeprecated: 230
+warningPresent: 54
+Validation has succeeded.
+
+Signed-off-by: Arun Lal K M <arun.lal@intel.com>
+Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com>
+---
+ redfish-core/lib/bios.hpp | 586 ++++++++++++++++++++++++--------------
+ 1 file changed, 376 insertions(+), 210 deletions(-)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 0bb0b9e..de79be2 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -12,13 +12,15 @@ map{attributeName,struct{attributeType,readonlyStatus,displayname,
+ description,menuPath,current,default,
+ array{struct{optionstring,optionvalue}}}}
+ */
+-using BiosBaseTableType = std::vector<std::pair<
++
++using BiosBaseTableType = boost::container::flat_map<
+ std::string,
+ std::tuple<
+ std::string, bool, std::string, std::string, std::string,
+ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
+ std::vector<
+- std::tuple<std::string, std::variant<int64_t, std::string>>>>>>;
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>;
++
+ using BiosBaseTableItemType = std::pair<
+ std::string,
+ std::tuple<
+@@ -29,6 +31,13 @@ using BiosBaseTableItemType = std::pair<
+ using OptionsItemType =
+ std::tuple<std::string, std::variant<int64_t, std::string>>;
+
++using PendingAttributesType = boost::container::flat_map<
++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>;
++
++using PendingAttributesItemType =
++ std::pair<std::string,
++ std::tuple<std::string, std::variant<int64_t, std::string>>>;
++
+ enum BiosBaseTableIndex
+ {
+ biosBaseAttrType = 0,
+@@ -45,17 +54,7 @@ enum OptionsItemIndex
+ optItemType = 0,
+ optItemValue
+ };
+-/*
+- The Pending attribute name and new value.
+- ex- { {"QuietBoot",Type.Integer, 0x1},
+- { "DdrFreqLimit",Type.String,"2933"}
+- }
+-*/
+-using PendingAttributesType = std::vector<std::pair<
+- std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>;
+-using PendingAttributesItemType =
+- std::pair<std::string,
+- std::tuple<std::string, std::variant<int64_t, std::string>>>;
++
+ enum PendingAttributesIndex
+ {
+ pendingAttrType = 0,
+@@ -64,31 +63,16 @@ enum PendingAttributesIndex
+ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
+ {
+ std::string ret;
+- if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
+- "AttributeType.Enumeration")
+- {
+- ret = "Enumeration";
+- }
+- else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+- "Manager.AttributeType.String")
++ if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.String")
+ {
+ ret = "String";
+ }
+- else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+- "Manager.AttributeType.Password")
+- {
+- ret = "Password";
+- }
+ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+ "Manager.AttributeType.Integer")
+ {
+ ret = "Integer";
+ }
+- else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+- "Manager.AttributeType.Boolean")
+- {
+- ret = "Boolean";
+- }
+ else
+ {
+ ret = "UNKNOWN";
+@@ -96,29 +80,7 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
+
+ return ret;
+ }
+-static std::string mapRedfishToAttrType(const std::string_view type)
+-{
+- std::string ret;
+- if (type == "string")
+- {
+- ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
+- }
+- else if (type == "int")
+- {
+- ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer";
+- }
+- else if (type == "enum")
+- {
+- ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
+- "Enumeration";
+- }
+- else
+- {
+- ret = "UNKNOWN";
+- }
+
+- return ret;
+-}
+ static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
+ {
+ std::string ret;
+@@ -201,6 +163,15 @@ inline void
+
+ return;
+ }
++
++ if (getObjectType.empty())
++ {
++ BMCWEB_LOG_ERROR << "getObjectType is empty.";
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++
+ const std::string& service = getObjectType.begin()->first;
+
+ crow::connections::systemBus->async_method_call(
+@@ -220,7 +191,7 @@ inline void
+ asyncResp->res.jsonValue["Attributes"];
+ if (baseBiosTable == nullptr)
+ {
+- BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ BMCWEB_LOG_ERROR << "baseBiosTable is empty";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+@@ -248,7 +219,6 @@ inline void
+ else
+ {
+ BMCWEB_LOG_ERROR << "Unsupported attribute type.";
+- messages::internalError(asyncResp->res);
+ }
+ }
+ },
+@@ -275,8 +245,9 @@ inline void requestRoutesBiosService(App& app)
+ */
+ inline void requestRoutesBiosChangePassword(App& app)
+ {
+- BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/")
+- .privileges({{"ConfigureComponents"}})
++ BMCWEB_ROUTE(app,
++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword/")
++ .privileges(redfish::privileges::postBios)
+ .methods(boost::beast::http::verb::post)(
+ [](const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+@@ -342,180 +313,298 @@ inline void requestRoutesBiosSettings(App& app)
+ {
+ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings")
+ .privileges(redfish::privileges::getBios)
+- .methods(boost::beast::http::verb::get)(
+- [](const crow::Request&,
+- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+- asyncResp->res.jsonValue["@odata.id"] =
+- asyncResp->res.jsonValue["@odata.id"] =
+- "/redfish/v1/Systems/system/Bios/Settings";
+- asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios";
+- asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1";
+- asyncResp->res.jsonValue["Id"] = "BiosSettingsV1";
+- asyncResp->res.jsonValue["AttributeRegistry"] =
+- "BiosAttributeRegistry";
+- asyncResp->res.jsonValue["Attributes"] = {};
++ .methods(
++ boost::beast::http::verb::
++ get)([](const crow::Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Systems/system/Bios/Settings";
++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios";
++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1";
++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1";
++ asyncResp->res.jsonValue["AttributeRegistry"] =
++ "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
+
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](const boost::system::error_code ec,
+- const GetObjectType& getObjectType) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR
+- << "ObjectMapper::GetObject call failed: "
+- << ec;
+- messages::internalError(asyncResp->res);
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "ObjectMapper::GetObject call failed: " << ec;
++ messages::internalError(asyncResp->res);
+
+- return;
+- }
+- std::string service = getObjectType.begin()->first;
+-
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](
+- const boost::system::error_code ec,
+- const std::variant<PendingAttributesType>&
+- retPendingAttributes) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR
+- << "getBiosSettings DBUS error: " << ec;
+- messages::resourceNotFound(
+- asyncResp->res, "Systems/system/Bios",
+- "Settings");
+- return;
+- }
+- const PendingAttributesType* pendingAttributes =
+- std::get_if<PendingAttributesType>(
+- &retPendingAttributes);
+- nlohmann::json& attributesJson =
+- asyncResp->res.jsonValue["Attributes"];
+- if (pendingAttributes == nullptr)
+- {
+- BMCWEB_LOG_ERROR
+- << "pendingAttributes == nullptr ";
+- messages::internalError(asyncResp->res);
+- return;
+- }
+- for (const PendingAttributesItemType& item :
+- *pendingAttributes)
++ return;
++ }
++
++ if (getObjectType.empty())
++ {
++ BMCWEB_LOG_ERROR << "getObjectType is empty.";
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::variant<PendingAttributesType>&
++ retPendingAttributes) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "getBiosSettings DBUS error: " << ec;
++ messages::resourceNotFound(
++ asyncResp->res, "Systems/system/Bios",
++ "Settings");
++ return;
++ }
++
++ const PendingAttributesType* pendingAttributes =
++ std::get_if<PendingAttributesType>(
++ &retPendingAttributes);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (pendingAttributes == nullptr)
++ {
++ BMCWEB_LOG_ERROR
++ << "pendingAttributes is empty";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ for (const PendingAttributesItemType&
++ pendingAttributesItem : *pendingAttributes)
++ {
++ const std::string& biosAttrType =
++ std::get<pendingAttrType>(
++ pendingAttributesItem.second);
++
++ std::string itemType =
++ mapAttrTypeToRedfish(biosAttrType);
++
++ if (itemType == "String")
+ {
+- const std::string& key = item.first;
+- const std::string& itemType =
+- std::get<pendingAttrType>(item.second);
+- std::string attrType =
+- mapAttrTypeToRedfish(itemType);
+- if (attrType == "String")
+- {
+- const std::string* currValue =
+- std::get_if<std::string>(
+- &std::get<pendingAttrValue>(
+- item.second));
+- attributesJson.emplace(
+- key, currValue != nullptr
+- ? *currValue
+- : "");
+- }
+- else if (attrType == "Integer")
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<pendingAttrValue>(
++ pendingAttributesItem.second));
++
++ if (!currValue)
+ {
+- const int64_t* currValue =
+- std::get_if<int64_t>(
+- &std::get<pendingAttrValue>(
+- item.second));
+- attributesJson.emplace(
+- key, currValue != nullptr
+- ? *currValue
+- : 0);
++ BMCWEB_LOG_ERROR
++ << "No string data in pending "
++ "attributes item data";
++ messages::internalError(asyncResp->res);
++ return;
+ }
+- else
++
++ attributesJson.emplace(
++ pendingAttributesItem.first,
++ *currValue);
++ }
++ else if (itemType == "Integer")
++ {
++ const int64_t* currValue =
++ std::get_if<int64_t>(
++ &std::get<pendingAttrValue>(
++ pendingAttributesItem.second));
++
++ if (!currValue)
+ {
+ BMCWEB_LOG_ERROR
+- << "Unsupported attribute type.";
++ << "No int64_t data in pending "
++ "attributes item data";
+ messages::internalError(asyncResp->res);
++ return;
+ }
++
++ attributesJson.emplace(
++ pendingAttributesItem.first,
++ *currValue);
+ }
+- },
+- service, "/xyz/openbmc_project/bios_config/manager",
+- "org.freedesktop.DBus.Properties", "Get",
+- "xyz.openbmc_project.BIOSConfig.Manager",
+- "PendingAttributes");
+- },
+- "xyz.openbmc_project.ObjectMapper",
+- "/xyz/openbmc_project/object_mapper",
+- "xyz.openbmc_project.ObjectMapper", "GetObject",
+- "/xyz/openbmc_project/bios_config/manager",
+- std::array<const char*, 0>());
+- });
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "PendingAttributes");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ });
+
+ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings")
+- .privileges({{"ConfigureComponents"}})
+- .methods(boost::beast::http::verb::patch)(
+- [](const crow::Request& req,
+- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+- nlohmann::json inpJson;
++ .privileges(redfish::privileges::patchBios)
++ .methods(
++ boost::beast::http::verb::
++ patch)([](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ nlohmann::json inpJson;
+
+- if (!redfish::json_util::readJson(req, asyncResp->res, "data",
+- inpJson))
+- {
+- return;
+- }
++ if (!redfish::json_util::readJson(req, asyncResp->res, "data",
++ inpJson))
++ {
++ BMCWEB_LOG_ERROR << "No 'data' in req!";
++ return;
++ }
+
+- for (auto& attrInfo : inpJson)
+- {
+- std::optional<std::string> attrName;
+- std::optional<std::string> attrType;
+- std::optional<std::string> attrValue;
+- if (!json_util::getValueFromJsonObject(
+- attrInfo, "AttributeName", attrName))
+- {
+- messages::propertyMissing(asyncResp->res,
+- "AttributeName");
+- return;
+- }
+- if (!json_util::getValueFromJsonObject(
+- attrInfo, "AttributeType", attrType))
+- {
+- messages::propertyMissing(asyncResp->res,
+- "AttributeType");
+- return;
+- }
+- if (!json_util::getValueFromJsonObject(
+- attrInfo, "AttributeValue", attrValue))
++ if (inpJson.empty())
++ {
++ messages::invalidObject(asyncResp->res, "data");
++ BMCWEB_LOG_ERROR << "No input in req!";
++ return;
++ }
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, inpJson](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
+ {
+- messages::propertyMissing(asyncResp->res,
+- "AttributeValue");
++ BMCWEB_LOG_ERROR
++ << "ObjectMapper::GetObject call failed: " << ec;
++ messages::internalError(asyncResp->res);
++
+ return;
+ }
+- std::string biosAttrType = mapRedfishToAttrType(*attrType);
+
+- if (biosAttrType == "UNKNOWN")
++ if (getObjectType.empty())
+ {
+- BMCWEB_LOG_ERROR << "Invalid attribute type";
+- messages::propertyValueNotInList(
+- asyncResp->res, "AttributeType", *attrType);
++ BMCWEB_LOG_ERROR << "getObjectType is empty.";
++ messages::internalError(asyncResp->res);
++
+ return;
+ }
+
+- PendingAttributesType pendingAttributes;
+- pendingAttributes.emplace_back(std::make_pair(
+- *attrName, std::make_tuple(biosAttrType, *attrValue)));
++ std::string service = getObjectType.begin()->first;
+
+ crow::connections::systemBus->async_method_call(
+- [asyncResp](const boost::system::error_code ec) {
++ [asyncResp,
++ inpJson](const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>&
++ retBiosTable) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+- << "doPatch resp_handler got error " << ec;
++ << "getBiosAttributes DBUS error: " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable is empty.";
+ messages::internalError(asyncResp->res);
+ return;
+ }
++
++ PendingAttributesType pendingAttributes{};
++
++ for (nlohmann::detail::iteration_proxy_value<
++ nlohmann::detail::iter_impl<
++ const nlohmann::basic_json<>>>&
++ attributes : inpJson.items())
++ {
++ BiosBaseTableType::const_iterator knobIter =
++ baseBiosTable->find(attributes.key());
++ if (knobIter == baseBiosTable->end())
++ {
++ BMCWEB_LOG_ERROR << "Cannot find "
++ << attributes.key()
++ << " in baseBiosTable";
++ messages::propertyValueNotInList(
++ asyncResp->res, attributes.key(),
++ "data");
++ return;
++ }
++
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(
++ knobIter->second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++
++ if (attrType == "String")
++ {
++ std::string val = attributes.value();
++
++ pendingAttributes.emplace(
++ attributes.key(),
++ std::make_tuple(itemType, val));
++ }
++ else if (attrType == "Integer")
++ {
++ pendingAttributes.emplace(
++ attributes.key(),
++ std::make_tuple(
++ itemType, static_cast<int64_t>(
++ attributes.value())));
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "UNKNOWN attrType == "
++ << itemType;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ }
++
++ if (pendingAttributes.empty())
++ {
++ BMCWEB_LOG_ERROR
++ << "pendingAttributes is empty.";
++ messages::invalidObject(asyncResp->res, "data");
++ }
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "doPatch resp_handler got error "
++ << ec << "\n";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ messages::success(asyncResp->res);
++ },
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "PendingAttributes",
++ std::variant<PendingAttributesType>(
++ pendingAttributes));
+ },
+- "xyz.openbmc_project.BIOSConfigManager",
+- "/xyz/openbmc_project/bios_config/manager",
+- "org.freedesktop.DBus.Properties", "Set",
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.BIOSConfig.Manager",
+- "PendingAttributes",
+- std::variant<PendingAttributesType>(pendingAttributes));
+- }
+- });
++ "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ });
+ }
+ /**
+ * BiosAttributeRegistry class supports handle get method for BIOS attribute
+@@ -555,6 +644,15 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+
+ return;
+ }
++
++ if (getObjectType.empty())
++ {
++ BMCWEB_LOG_ERROR << "getObjectType is empty.";
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++
+ std::string service = getObjectType.begin()->first;
+
+ crow::connections::systemBus->async_method_call(
+@@ -575,8 +673,6 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ nlohmann::json& attributeArray =
+ asyncResp->res
+ .jsonValue["RegistryEntries"]["Attributes"];
+- nlohmann::json optionsArray =
+- nlohmann::json::array();
+ if (baseBiosTable == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
+@@ -592,10 +688,11 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ mapAttrTypeToRedfish(itemType);
+ if (attrType == "UNKNOWN")
+ {
+- BMCWEB_LOG_ERROR << "attrType == UNKNOWN";
+- messages::internalError(asyncResp->res);
+- return;
++ BMCWEB_LOG_ERROR << "UNKNOWN attrType == "
++ << itemType;
++ continue;
+ }
++
+ nlohmann::json attributeItem;
+ attributeItem["AttributeName"] = item.first;
+ attributeItem["Type"] = attrType;
+@@ -615,10 +712,30 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ std::get_if<std::string>(
+ &std::get<biosBaseCurrValue>(
+ item.second));
++
++ if (!currValue)
++ {
++ BMCWEB_LOG_ERROR
++ << "Unable to get currValue, no "
++ "std::string data in BIOS "
++ "attributes item data";
++ continue;
++ }
++
+ const std::string* defValue =
+ std::get_if<std::string>(
+ &std::get<biosBaseDefaultValue>(
+ item.second));
++
++ if (!defValue)
++ {
++ BMCWEB_LOG_ERROR
++ << "Unable to get defValue, no "
++ "std::string data in BIOS "
++ "attributes item data";
++ continue;
++ }
++
+ attributeItem["CurrentValue"] =
+ currValue != nullptr ? *currValue : "";
+ attributeItem["DefaultValue"] =
+@@ -630,10 +747,30 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ std::get_if<int64_t>(
+ &std::get<biosBaseCurrValue>(
+ item.second));
++
++ if (!currValue)
++ {
++ BMCWEB_LOG_ERROR
++ << "Unable to get currValue, no "
++ "int64_t data in BIOS "
++ "attributes item data";
++ continue;
++ }
++
+ const int64_t* defValue =
+ std::get_if<int64_t>(
+ &std::get<biosBaseDefaultValue>(
+ item.second));
++
++ if (!defValue)
++ {
++ BMCWEB_LOG_ERROR
++ << "Unable to get defValue, no "
++ "int64_t data in BIOS "
++ "attributes item data";
++ continue;
++ }
++
+ attributeItem["CurrentValue"] =
+ currValue != nullptr ? *currValue : 0;
+ attributeItem["DefaultValue"] =
+@@ -641,12 +778,13 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ }
+ else
+ {
+- BMCWEB_LOG_ERROR
+- << "Unsupported attribute type.";
+- messages::internalError(asyncResp->res);
+- return;
++ BMCWEB_LOG_ERROR << "UNKNOWN attrType == "
++ << itemType;
++ continue;
+ }
+
++ nlohmann::json optionsArray =
++ nlohmann::json::array();
+ const std::vector<OptionsItemType>&
+ optionsVector =
+ std::get<biosBaseOptions>(item.second);
+@@ -661,9 +799,9 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ if (optItemTypeRedfish == "UNKNOWN")
+ {
+ BMCWEB_LOG_ERROR
+- << "optItemTypeRedfish == UNKNOWN";
+- messages::internalError(asyncResp->res);
+- return;
++ << "UNKNOWN optItemTypeRedfish == "
++ << strOptItemType;
++ continue;
+ }
+ if (optItemTypeRedfish == "OneOf")
+ {
+@@ -671,6 +809,17 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ std::get_if<std::string>(
+ &std::get<optItemValue>(
+ optItem));
++
++ if (!currValue)
++ {
++ BMCWEB_LOG_ERROR
++ << "Unable to get currValue, "
++ "no "
++ "std::string data in option "
++ "item value";
++ continue;
++ }
++
+ optItemJson[optItemTypeRedfish] =
+ currValue != nullptr ? *currValue
+ : "";
+@@ -681,6 +830,17 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ std::get_if<int64_t>(
+ &std::get<optItemValue>(
+ optItem));
++
++ if (!currValue)
++ {
++ BMCWEB_LOG_ERROR
++ << "Unable to get currValue, "
++ "no "
++ "int64_t data in option "
++ "item value";
++ continue;
++ }
++
+ optItemJson[optItemTypeRedfish] =
+ currValue != nullptr ? *currValue
+ : 0;
+@@ -689,6 +849,12 @@ inline void requestRoutesBiosAttributeRegistry(App& app)
+ optionsArray.push_back(optItemJson);
+ }
+
++ if (optionsArray.empty())
++ {
++ BMCWEB_LOG_ERROR << "optionsArray is empty";
++ continue;
++ }
++
+ attributeItem["Value"] = optionsArray;
+ attributeArray.push_back(attributeItem);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket
new file mode 100644
index 000000000..8782e4dd3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=BMC Webserver socket
+
+[Socket]
+ListenStream=443
+ReusePort=true
+
+[Install]
+WantedBy=sockets.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch
new file mode 100644
index 000000000..52135e255
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch
@@ -0,0 +1,121 @@
+From 6ff897d2b5513f15445f18aae16d8439ed94f377 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 11 Oct 2021 18:41:27 +0530
+Subject: [PATCH] Add unmerged changes for http retry support
+
+The http retry support added upstream as a single patch was slpit into
+3 patches, but only 2 of them was merged.
+This commit pulls in the differentail changes required to complete the
+entire http retry support. and also allow for other subsequent patches
+to be appplied easily.
+
+Change-Id: Id8ccd991b7ffc505196b1a92b23e1cd51e00bc89
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_client.hpp | 44 +++++++++++--------
+ .../include/event_service_manager.hpp | 2 +-
+ 2 files changed, 27 insertions(+), 19 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index ab20eb0..aad1cce 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -68,7 +68,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ std::optional<
+ boost::beast::http::response_parser<boost::beast::http::string_body>>
+ parser;
+- std::vector<std::pair<std::string, std::string>> headers;
+ boost::circular_buffer_space_optimized<std::string> requestDataQueue{};
+
+ ConnState state;
+@@ -137,18 +136,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port;
+
+- req.version(static_cast<int>(11)); // HTTP 1.1
+- req.target(uri);
+- req.method(boost::beast::http::verb::post);
+-
+- // Set headers
+- for (const auto& [key, value] : headers)
+- {
+- req.set(key, value);
+- }
+- req.set(boost::beast::http::field::host, host);
+- req.keep_alive(true);
+-
+ req.body() = data;
+ req.prepare_payload();
+
+@@ -204,6 +191,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ BMCWEB_LOG_DEBUG << "recvMessage() data: "
+ << self->parser->get();
+
++ // Check if the response and header are received
++ if (!self->parser->is_done())
++ {
++ // The parser failed to receive the response
++ BMCWEB_LOG_ERROR
++ << "recvMessage() parser failed to receive response";
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
++
+ unsigned int respCode = self->parser->get().result_int();
+ BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
+ << respCode;
+@@ -398,11 +396,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ const std::string& destIP, const std::string& destPort,
+ const std::string& destUri) :
+ conn(ioc),
+- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri),
+- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0),
++ timer(ioc), req(boost::beast::http::verb::post, destUri, 11),
++ state(ConnState::initialized), subId(id), host(destIP), port(destPort),
++ uri(destUri), retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0),
+ retryPolicyAction("TerminateAfterRetries"), runningTimer(false)
+ {
+- state = ConnState::initialized;
++ // Set the request header
++ req.set(boost::beast::http::field::host, host);
++ req.set(boost::beast::http::field::content_type, "application/json");
++ req.keep_alive(true);
++
++ requestDataQueue.set_capacity(maxRequestQueueSize);
+ }
+
+ void sendData(const std::string& data)
+@@ -425,10 +429,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ return;
+ }
+
+- void setHeaders(
++ void addHeaders(
+ const std::vector<std::pair<std::string, std::string>>& httpHeaders)
+ {
+- headers = httpHeaders;
++ // Set custom headers
++ for (const auto& [key, value] : httpHeaders)
++ {
++ req.set(key, value);
++ }
+ }
+
+ void setRetryConfig(const uint32_t retryAttempts,
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 8042803..0a63b8c 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -412,7 +412,7 @@ class Subscription : public persistent_data::UserSubscription
+ reqHeaders.emplace_back(std::pair(key, val));
+ }
+ }
+- conn->setHeaders(reqHeaders);
++ conn->addHeaders(reqHeaders);
+ conn->sendData(msg);
+ this->eventSeqNum++;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch
new file mode 100644
index 000000000..aeeafc421
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch
@@ -0,0 +1,453 @@
+From 3f2ad28e6e124249cde3df50c9e18c283fbcbf3e Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Mon, 22 Feb 2021 17:07:47 +0000
+Subject: [PATCH] EventService: https client support
+
+Add https client support for push style eventing. Using this BMC can
+push the event logs/telemetry data to event listener over secure http
+channel.
+
+Tested:
+ - Created subscription with https destination url. Using
+ SubmitTestEvent action set the event and can see event on event
+ listener.
+ - Validator passed.
+
+Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ http/http_client.hpp | 307 ++++++++++++------
+ .../include/event_service_manager.hpp | 2 +-
+ 2 files changed, 202 insertions(+), 107 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index aad1cce..5e7ff47 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -20,6 +20,7 @@
+ #include <boost/beast/core/flat_buffer.hpp>
+ #include <boost/beast/core/tcp_stream.hpp>
+ #include <boost/beast/http/message.hpp>
++#include <boost/beast/ssl/ssl_stream.hpp>
+ #include <boost/beast/version.hpp>
+ #include <include/async_resolve.hpp>
+
+@@ -43,6 +44,8 @@ enum class ConnState
+ resolveFailed,
+ connectInProgress,
+ connectFailed,
++ handshakeInProgress,
++ handshakeFailed,
+ connected,
+ sendInProgress,
+ sendFailed,
+@@ -61,7 +64,9 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ {
+ private:
+ crow::async_resolve::Resolver resolver;
++ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client};
+ boost::beast::tcp_stream conn;
++ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn;
+ boost::asio::steady_timer timer;
+ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer;
+ boost::beast::http::request<boost::beast::http::string_body> req;
+@@ -108,23 +113,52 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ const std::vector<boost::asio::ip::tcp::endpoint>& endpointList)
+ {
+ state = ConnState::connectInProgress;
++ sslConn.emplace(conn, ctx);
+
+ BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port;
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const boost::asio::ip::tcp::endpoint& endpoint) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Connect " << endpoint
++ << " failed: " << ec.message();
++ self->state = ConnState::connectFailed;
++ self->handleConnState();
++ return;
++ }
+
++ BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
++ if (self->sslConn)
++ {
++ self->performHandshake();
++ }
++ else
++ {
++ self->handleConnState();
++ }
++ };
+ conn.expires_after(std::chrono::seconds(30));
+- conn.async_connect(
+- endpointList, [self(shared_from_this())](
+- const boost::beast::error_code ec,
+- const boost::asio::ip::tcp::endpoint& endpoint) {
++ conn.async_connect(endpointList, std::move(respHandler));
++ }
++
++ void performHandshake()
++ {
++ state = ConnState::handshakeInProgress;
++
++ sslConn->async_handshake(
++ boost::asio::ssl::stream_base::client,
++ [self(shared_from_this())](const boost::beast::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "Connect " << endpoint
+- << " failed: " << ec.message();
+- self->state = ConnState::connectFailed;
++ BMCWEB_LOG_ERROR << "SSL handshake failed: "
++ << ec.message();
++ self->state = ConnState::handshakeFailed;
+ self->handleConnState();
+ return;
+ }
+- BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
++
++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull";
+ self->state = ConnState::connected;
+ self->handleConnState();
+ });
+@@ -132,132 +166,187 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void sendMessage(const std::string& data)
+ {
+- state = ConnState::sendInProgress;
+-
+ BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port;
++ state = ConnState::sendInProgress;
+
+ req.body() = data;
+ req.prepare_payload();
+
+- // Set a timeout on the operation
+- conn.expires_after(std::chrono::seconds(30));
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message();
++ self->state = ConnState::sendFailed;
++ self->handleConnState();
++ return;
++ }
+
+- // Send the HTTP request to the remote host
+- boost::beast::http::async_write(
+- conn, req,
+- [self(shared_from_this())](const boost::beast::error_code& ec,
+- const std::size_t& bytesTransferred) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "sendMessage() failed: "
+- << ec.message();
+- self->state = ConnState::sendFailed;
+- self->handleConnState();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
+- << bytesTransferred;
+- boost::ignore_unused(bytesTransferred);
++ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
++ << bytesTransferred;
++ boost::ignore_unused(bytesTransferred);
++ self->recvMessage();
++ };
+
+- self->recvMessage();
+- });
++ // Set a timeout on the operation
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
++ {
++ boost::beast::http::async_write(*sslConn, req,
++ std::move(respHandler));
++ }
++ else
++ {
++ boost::beast::http::async_write(conn, req, std::move(respHandler));
++ }
+ }
+-
+ void recvMessage()
+ {
+ state = ConnState::recvInProgress;
+
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ if (ec && ec != boost::asio::ssl::error::stream_truncated)
++ {
++ BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message();
++
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
++
++ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
++ << bytesTransferred;
++ boost::ignore_unused(bytesTransferred);
++
++ // Check if the response and header are received
++ if (!self->parser->is_done())
++ {
++ // The parser failed to receive the response
++ BMCWEB_LOG_ERROR
++ << "recvMessage() parser failed to receive response";
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
++
++ unsigned int respCode = self->parser->get().result_int();
++ BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
++ << respCode;
++
++ // 2XX response is considered to be successful
++ if ((respCode < 200) || (respCode >= 300))
++ {
++ // The listener failed to receive the Sent-Event
++ BMCWEB_LOG_ERROR << "recvMessage() Listener Failed to "
++ "receive Sent-Event";
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
++
++ // Send is successful, Lets remove data from queue
++ // check for next request data in queue.
++ if (!self->requestDataQueue.empty())
++ {
++ self->requestDataQueue.pop_front();
++ }
++ self->state = ConnState::idle;
++ // Keep the connection alive if server supports it
++ // Else close the connection
++ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
++ << self->parser->keep_alive();
++ if (!self->parser->keep_alive())
++ {
++ // Abort the connection since server is not keep-alive enabled
++ self->state = ConnState::abortConnection;
++ }
++
++ // Returns ownership of the parsed message
++ self->parser->release();
++
++ self->handleConnState();
++ };
+ parser.emplace(std::piecewise_construct, std::make_tuple());
+ parser->body_limit(httpReadBodyLimit);
+
+ // Check only for the response header
+ parser->skip(true);
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
++ {
++ boost::beast::http::async_read(*sslConn, buffer, *parser,
++ std::move(respHandler));
++ }
++ else
++ {
++ boost::beast::http::async_read(conn, buffer, *parser,
++ std::move(respHandler));
++ }
++ }
++ void doClose()
++ {
++ state = ConnState::closeInProgress;
+
+- // Receive the HTTP response
+- boost::beast::http::async_read(
+- conn, buffer, *parser,
+- [self(shared_from_this())](const boost::beast::error_code& ec,
+- const std::size_t& bytesTransferred) {
++ // Set the timeout on the tcp stream socket for the async operation
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
++ {
++ sslConn->async_shutdown([self = shared_from_this()](
++ const boost::system::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "recvMessage() failed: "
+- << ec.message();
+- self->state = ConnState::recvFailed;
+- self->handleConnState();
+- return;
++ // Many https server closes connection abruptly
++ // i.e witnout close_notify. More details are at
++ // https://github.com/boostorg/beast/issues/824
++ if (ec == boost::asio::ssl::error::stream_truncated)
++ {
++ BMCWEB_LOG_INFO << "doClose(): Connection "
++ "closed by server. ";
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "doClose() failed: "
++ << ec.message();
++ }
+ }
+- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
+- << bytesTransferred;
+- BMCWEB_LOG_DEBUG << "recvMessage() data: "
+- << self->parser->get();
+-
+- // Check if the response and header are received
+- if (!self->parser->is_done())
++ else
+ {
+- // The parser failed to receive the response
+- BMCWEB_LOG_ERROR
+- << "recvMessage() parser failed to receive response";
+- self->state = ConnState::recvFailed;
+- self->handleConnState();
+- return;
++ BMCWEB_LOG_DEBUG << "Connection closed gracefully...";
+ }
++ self->conn.close();
+
+- unsigned int respCode = self->parser->get().result_int();
+- BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
+- << respCode;
+-
+- // 2XX response is considered to be successful
+- if ((respCode < 200) || (respCode >= 300))
++ if ((self->state != ConnState::suspended) &&
++ (self->state != ConnState::terminated))
+ {
+- // The listener failed to receive the Sent-Event
+- BMCWEB_LOG_ERROR << "recvMessage() Listener Failed to "
+- "receive Sent-Event";
+- self->state = ConnState::recvFailed;
++ self->state = ConnState::closed;
+ self->handleConnState();
+- return;
+ }
+-
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- if (!self->requestDataQueue.empty())
+- {
+- self->requestDataQueue.pop_front();
+- }
+- self->state = ConnState::idle;
+-
+- // Keep the connection alive if server supports it
+- // Else close the connection
+- BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
+- << self->parser->keep_alive();
+- if (!self->parser->keep_alive())
+- {
+- // Abort the connection since server is not keep-alive
+- // enabled
+- self->state = ConnState::abortConnection;
+- }
+-
+- self->handleConnState();
+ });
+- }
+-
+- void doClose()
+- {
+- state = ConnState::closeInProgress;
+- boost::beast::error_code ec;
+- conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+- conn.close();
+-
+- // not_connected happens sometimes so don't bother reporting it.
+- if (ec && ec != boost::beast::errc::not_connected)
+- {
+- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message();
+- return;
+ }
+- BMCWEB_LOG_DEBUG << "Connection closed gracefully";
+- if ((state != ConnState::suspended) && (state != ConnState::terminated))
++ else
+ {
+- state = ConnState::closed;
+- handleConnState();
++ boost::beast::error_code ec;
++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
++ ec);
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "doClose() failed: " << ec.message();
++ }
++ else
++ {
++ BMCWEB_LOG_DEBUG << "Connection closed gracefully...";
++ }
++ conn.close();
++
++ if ((state != ConnState::suspended) &&
++ (state != ConnState::terminated))
++ {
++ state = ConnState::closed;
++ handleConnState();
++ }
+ }
+ }
+
+@@ -330,6 +419,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ {
+ case ConnState::resolveInProgress:
+ case ConnState::connectInProgress:
++ case ConnState::handshakeInProgress:
+ case ConnState::sendInProgress:
+ case ConnState::recvInProgress:
+ case ConnState::closeInProgress:
+@@ -356,6 +446,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ case ConnState::resolveFailed:
+ case ConnState::connectFailed:
++ case ConnState::handshakeFailed:
+ case ConnState::sendFailed:
+ case ConnState::recvFailed:
+ case ConnState::retry:
+@@ -394,7 +485,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ public:
+ explicit HttpClient(boost::asio::io_context& ioc, const std::string& id,
+ const std::string& destIP, const std::string& destPort,
+- const std::string& destUri) :
++ const std::string& destUri,
++ const std::string& uriProto) :
+ conn(ioc),
+ timer(ioc), req(boost::beast::http::verb::post, destUri, 11),
+ state(ConnState::initialized), subId(id), host(destIP), port(destPort),
+@@ -407,8 +499,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ req.keep_alive(true);
+
+ requestDataQueue.set_capacity(maxRequestQueueSize);
++ if (uriProto == "https")
++ {
++ sslConn.emplace(conn, ctx);
++ }
+ }
+-
+ void sendData(const std::string& data)
+ {
+ if ((state == ConnState::suspended) || (state == ConnState::terminated))
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 08d0b98..f1ce0c0 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -385,7 +385,7 @@ class Subscription : public persistent_data::UserSubscription
+ {
+ conn = std::make_shared<crow::HttpClient>(
+ crow::connections::systemBus->get_io_context(), id, host, port,
+- path);
++ path, uriProto);
+ }
+
+ Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch
new file mode 100644
index 000000000..ea521a7e4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch
@@ -0,0 +1,468 @@
+From d7a2660f200c38e74bfcbfe55b8da1b8bed08833 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Fri, 12 Mar 2021 18:53:25 +0000
+Subject: [PATCH] Add Server-Sent-Events support
+
+Server-Sent Events is a standard describing how servers can
+initiate data transmission towards clients once an initial
+client connection has been established. Unlike websockets
+(which are bidirectional), Server-Sent Events are
+unidirectional and commonly used to send message updates or
+continuous data streams to a browser client.
+
+This is base patch for adding Server-Sent events support to
+bmcweb. Redfish eventservice SSE style subscription uses
+this and will be loaded on top of this commit.
+
+Tested:
+ - Tested using follow-up patch on top which adds
+ support for Redfish EventService SSE style subscription
+ and observed events are getting sent periodically.
+
+Change-Id: I36956565cbba30c2007852c9471f477f6d1736e9
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_connection.hpp | 10 +-
+ http/http_response.hpp | 7 +-
+ http/routing.hpp | 71 ++++++++++
+ http/server_sent_event.hpp | 279 +++++++++++++++++++++++++++++++++++++
+ 4 files changed, 362 insertions(+), 5 deletions(-)
+ create mode 100644 http/server_sent_event.hpp
+
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index 8e53afa..a1bbfce 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -378,11 +378,13 @@ class Connection :
+ [self] { self->completeRequest(); });
+ });
+
+- if (thisReq.isUpgrade() &&
+- boost::iequals(
+- thisReq.getHeaderValue(boost::beast::http::field::upgrade),
+- "websocket"))
++ if ((thisReq.isUpgrade() &&
++ boost::iequals(
++ thisReq.getHeaderValue(boost::beast::http::field::upgrade),
++ "websocket")) ||
++ (req->url == "/sse"))
+ {
++ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded";
+ handler->handleUpgrade(thisReq, res, std::move(adaptor));
+ // delete lambda with self shared_ptr
+ // to enable connection destruction
+diff --git a/http/http_response.hpp b/http/http_response.hpp
+index a983d4a..07b0265 100644
+--- a/http/http_response.hpp
++++ b/http/http_response.hpp
+@@ -15,10 +15,15 @@ namespace crow
+ template <typename Adaptor, typename Handler>
+ class Connection;
+
++template <typename Adaptor>
++class SseConnectionImpl;
++
+ struct Response
+ {
+ template <typename Adaptor, typename Handler>
+ friend class crow::Connection;
++ template <typename Adaptor>
++ friend class crow::SseConnectionImpl;
+ using response_type =
+ boost::beast::http::response<boost::beast::http::string_body>;
+
+@@ -143,8 +148,8 @@ struct Response
+
+ private:
+ bool completed{};
+- std::function<void()> completeRequestHandler;
+ std::function<bool()> isAliveHelper;
++ std::function<void()> completeRequestHandler;
+
+ // In case of a JSON object, set the Content-Type header
+ void jsonMode()
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 5d9c8e3..bfff107 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -6,6 +6,7 @@
+ #include "http_response.hpp"
+ #include "logging.hpp"
+ #include "privileges.hpp"
++#include "server_sent_event.hpp"
+ #include "sessions.hpp"
+ #include "utility.hpp"
+ #include "websocket.hpp"
+@@ -398,6 +399,68 @@ class WebSocketRule : public BaseRule
+ std::function<void(crow::websocket::Connection&)> errorHandler;
+ };
+
++class SseSocketRule : public BaseRule
++{
++ using self_t = SseSocketRule;
++
++ public:
++ SseSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
++ {}
++
++ void validate() override
++ {}
++
++ void handle(const Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const RoutingParams&) override
++ {
++ asyncResp->res.result(boost::beast::http::status::not_found);
++ }
++
++ void handleUpgrade(const Request& req, Response&,
++ boost::asio::ip::tcp::socket&& adaptor) override
++ {
++ std::shared_ptr<crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>
++ myConnection = std::make_shared<
++ crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>(
++ req, std::move(adaptor), openHandler, closeHandler);
++ myConnection->start();
++ }
++#ifdef BMCWEB_ENABLE_SSL
++ void handleUpgrade(const Request& req, Response&,
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
++ adaptor) override
++ {
++ std::shared_ptr<crow::SseConnectionImpl<
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
++ myConnection = std::make_shared<crow::SseConnectionImpl<
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
++ req, std::move(adaptor), openHandler, closeHandler);
++ myConnection->start();
++ }
++#endif
++
++ template <typename Func>
++ self_t& onopen(Func f)
++ {
++ openHandler = f;
++ return *this;
++ }
++
++ template <typename Func>
++ self_t& onclose(Func f)
++ {
++ closeHandler = f;
++ return *this;
++ }
++
++ private:
++ std::function<void(std::shared_ptr<crow::SseConnection>&,
++ const crow::Request&, crow::Response&)>
++ openHandler;
++ std::function<void(std::shared_ptr<crow::SseConnection>&)> closeHandler;
++};
++
+ template <typename T>
+ struct RuleParameterTraits
+ {
+@@ -410,6 +473,14 @@ struct RuleParameterTraits
+ return *p;
+ }
+
++ SseSocketRule& serverSentEvent()
++ {
++ self_t* self = static_cast<self_t*>(this);
++ SseSocketRule* p = new SseSocketRule(self->rule);
++ self->ruleToUpgrade.reset(p);
++ return *p;
++ }
++
+ self_t& name(const std::string_view name) noexcept
+ {
+ self_t* self = static_cast<self_t*>(this);
+diff --git a/http/server_sent_event.hpp b/http/server_sent_event.hpp
+new file mode 100644
+index 0000000..41d18ed
+--- /dev/null
++++ b/http/server_sent_event.hpp
+@@ -0,0 +1,279 @@
++#pragma once
++#include "http_request.hpp"
++
++#include <boost/algorithm/string/predicate.hpp>
++#include <boost/asio/buffer.hpp>
++#include <boost/beast/http/buffer_body.hpp>
++#include <boost/beast/websocket.hpp>
++
++#include <array>
++#include <functional>
++
++#ifdef BMCWEB_ENABLE_SSL
++#include <boost/beast/websocket/ssl.hpp>
++#endif
++
++namespace crow
++{
++
++struct SseConnection : std::enable_shared_from_this<SseConnection>
++{
++ public:
++ SseConnection(const crow::Request& reqIn) : req(reqIn)
++ {}
++ virtual ~SseConnection() = default;
++
++ virtual boost::asio::io_context& getIoContext() = 0;
++ virtual void sendSSEHeader() = 0;
++ virtual void completeRequest() = 0;
++ virtual void close(const std::string_view msg = "quit") = 0;
++ virtual void sendEvent(const std::string_view id,
++ const std::string_view msg) = 0;
++
++ crow::Request req;
++ crow::Response res;
++};
++
++template <typename Adaptor>
++class SseConnectionImpl : public SseConnection
++{
++ public:
++ SseConnectionImpl(
++ const crow::Request& reqIn, Adaptor adaptorIn,
++ std::function<void(std::shared_ptr<SseConnection>&,
++ const crow::Request&, crow::Response&)>
++ openHandler,
++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler) :
++ SseConnection(reqIn),
++ adaptor(std::move(adaptorIn)), openHandler(std::move(openHandler)),
++ closeHandler(std::move(closeHandler))
++ {
++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE constructor " << this;
++ }
++
++ ~SseConnectionImpl() override
++ {
++ res.completeRequestHandler = nullptr;
++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE destructor " << this;
++ }
++
++ boost::asio::io_context& getIoContext() override
++ {
++ return static_cast<boost::asio::io_context&>(
++ adaptor.get_executor().context());
++ }
++
++ void start()
++ {
++ // Register for completion callback.
++ res.completeRequestHandler = [this, self(shared_from_this())] {
++ boost::asio::post(this->adaptor.get_executor(),
++ [self] { self->completeRequest(); });
++ };
++
++ if (openHandler)
++ {
++ std::shared_ptr<SseConnection> self = this->shared_from_this();
++ openHandler(self, req, res);
++ }
++ }
++
++ void close(const std::string_view msg) override
++ {
++ BMCWEB_LOG_DEBUG << "Closing SSE connection " << this << " - " << msg;
++ boost::beast::get_lowest_layer(adaptor).close();
++
++ // send notification to handler for cleanup
++ if (closeHandler)
++ {
++ std::shared_ptr<SseConnection> self = this->shared_from_this();
++ closeHandler(self);
++ }
++ }
++
++ void sendSSEHeader() override
++ {
++ BMCWEB_LOG_DEBUG << "Starting SSE connection";
++ using BodyType = boost::beast::http::buffer_body;
++ auto response =
++ std::make_shared<boost::beast::http::response<BodyType>>(
++ boost::beast::http::status::ok, 11);
++ auto serializer =
++ std::make_shared<boost::beast::http::response_serializer<BodyType>>(
++ *response);
++
++ response->set(boost::beast::http::field::server, "bmcweb");
++ response->set(boost::beast::http::field::content_type,
++ "text/event-stream");
++ response->body().data = nullptr;
++ response->body().size = 0;
++ response->body().more = true;
++
++ boost::beast::http::async_write_header(
++ adaptor, *serializer,
++ [this, self(shared_from_this()), response, serializer](
++ const boost::beast::error_code& ec, const std::size_t&) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Error sending header" << ec;
++ close("async_write_header failed");
++ return;
++ }
++ BMCWEB_LOG_DEBUG << "SSE header sent - Connection established";
++
++ // SSE stream header sent, So lets setup monitor.
++ // Any read data on this stream will be error in case of SSE.
++ setupRead();
++ });
++ }
++
++ void setupRead()
++ {
++ adaptor.async_read_some(
++ outputBuffer.prepare(outputBuffer.capacity() - outputBuffer.size()),
++ [this](const boost::system::error_code& ec, std::size_t bytesRead) {
++ BMCWEB_LOG_DEBUG << "async_read_some: Read " << bytesRead
++ << " bytes";
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Read error: " << ec;
++ }
++ outputBuffer.commit(bytesRead);
++ outputBuffer.consume(bytesRead);
++
++ // After establishing SSE stream, Reading data on this
++ // stream means client is disobeys the SSE protocol.
++ // Read the data to avoid buffer attacks and close connection.
++ close("Close SSE connection");
++ return;
++ });
++ }
++
++ void doWrite()
++ {
++ if (doingWrite)
++ {
++ return;
++ }
++ if (inputBuffer.size() == 0)
++ {
++ BMCWEB_LOG_DEBUG << "inputBuffer is empty... Bailing out";
++ return;
++ }
++ doingWrite = true;
++
++ adaptor.async_write_some(
++ inputBuffer.data(), [this, self(shared_from_this())](
++ boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ doingWrite = false;
++ inputBuffer.consume(bytesTransferred);
++
++ if (ec == boost::asio::error::eof)
++ {
++ BMCWEB_LOG_ERROR << "async_write_some() SSE stream closed";
++ close("SSE stream closed");
++ return;
++ }
++
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "async_write_some() failed: "
++ << ec.message();
++ close("async_write_some failed");
++ return;
++ }
++ BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: "
++ << bytesTransferred;
++
++ doWrite();
++ });
++ }
++
++ void completeRequest() override
++ {
++ BMCWEB_LOG_DEBUG << "SSE completeRequest() handler";
++ if (res.body().empty() && !res.jsonValue.empty())
++ {
++ res.addHeader("Content-Type", "application/json");
++ res.body() = res.jsonValue.dump(
++ 2, ' ', true, nlohmann::json::error_handler_t::replace);
++ }
++
++ res.preparePayload();
++ auto serializer =
++ std::make_shared<boost::beast::http::response_serializer<
++ boost::beast::http::string_body>>(*res.stringResponse);
++
++ boost::beast::http::async_write(
++ adaptor, *serializer,
++ [this, self(shared_from_this()),
++ serializer](const boost::system::error_code& ec,
++ std::size_t bytesTransferred) {
++ BMCWEB_LOG_DEBUG << this << " async_write " << bytesTransferred
++ << " bytes";
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << this << " from async_write failed";
++ return;
++ }
++ res.clear();
++
++ BMCWEB_LOG_DEBUG << this
++ << " Closing SSE connection - Request invalid";
++ close("Request invalid");
++ });
++
++ // delete lambda with self shared_ptr
++ // to enable connection destruction
++ res.completeRequestHandler = nullptr;
++ }
++
++ void sendEvent(const std::string_view id,
++ const std::string_view msg) override
++ {
++ if (msg.empty())
++ {
++ BMCWEB_LOG_DEBUG << "Empty data, bailing out.";
++ return;
++ }
++
++ std::string rawData;
++ if (!id.empty())
++ {
++ rawData += "id: ";
++ rawData.append(id.begin(), id.end());
++ rawData += "\n";
++ }
++
++ rawData += "data: ";
++ for (char character : msg)
++ {
++ rawData += character;
++ if (character == '\n')
++ {
++ rawData += "data: ";
++ }
++ }
++ rawData += "\n\n";
++
++ boost::asio::buffer_copy(inputBuffer.prepare(rawData.size()),
++ boost::asio::buffer(rawData));
++ inputBuffer.commit(rawData.size());
++
++ doWrite();
++ }
++
++ private:
++ Adaptor adaptor;
++
++ boost::beast::flat_static_buffer<1024U * 8U> outputBuffer;
++ boost::beast::flat_static_buffer<1024U * 64U> inputBuffer;
++ bool doingWrite = false;
++
++ std::function<void(std::shared_ptr<SseConnection>&, const crow::Request&,
++ crow::Response&)>
++ openHandler;
++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler;
++};
++} // namespace crow
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch
new file mode 100644
index 000000000..ee69081ef
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch
@@ -0,0 +1,679 @@
+From 799e47842e179f7c752712004f0e96d3219eee11 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Tue, 16 Mar 2021 15:37:24 +0000
+Subject: [PATCH] Add SSE style subscription support to eventservice
+
+This commit adds the SSE style eventservice subscription
+style event. Using this, end user can subscribe for
+Redfish event logs using GET on SSE usri from
+browser.
+URI: /redfish/v1/EventService/Subscriptions/SSE
+
+Tested:
+ - From Browser did GET on above SSE URI and
+ generated some Redfish event logs(power cycle)
+ and saw redfish event logs streaming on browser.
+ - After SSE registration, Check Subscription collections
+ and GET on individual subscription and saw desired
+ response.
+ - Ran RedfishValidation and its passed.
+
+Change-Id: I7f4b7a34974080739c4ba968ed570489af0474de
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_connection.hpp | 2 +-
+ include/eventservice_sse.hpp | 75 +++++
+ .../include/event_service_manager.hpp | 109 +++++--
+ redfish-core/include/server_sent_events.hpp | 290 ------------------
+ redfish-core/lib/event_service.hpp | 8 +-
+ src/webserver_main.cpp | 2 +
+ 6 files changed, 164 insertions(+), 322 deletions(-)
+ create mode 100644 include/eventservice_sse.hpp
+ delete mode 100644 redfish-core/include/server_sent_events.hpp
+
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index a1bbfce..2d08501 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -382,7 +382,7 @@ class Connection :
+ boost::iequals(
+ thisReq.getHeaderValue(boost::beast::http::field::upgrade),
+ "websocket")) ||
+- (req->url == "/sse"))
++ (req->url == "/redfish/v1/EventService/Subscriptions/SSE"))
+ {
+ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded";
+ handler->handleUpgrade(thisReq, res, std::move(adaptor));
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+new file mode 100644
+index 0000000..14daf00
+--- /dev/null
++++ b/include/eventservice_sse.hpp
+@@ -0,0 +1,75 @@
++#pragma once
++
++#include <app.hpp>
++#include <event_service_manager.hpp>
++
++namespace redfish
++{
++namespace eventservice_sse
++{
++
++static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn,
++ const crow::Request& req, crow::Response& res)
++{
++ if ((EventServiceManager::getInstance().getNumberOfSubscriptions() >=
++ maxNoOfSubscriptions) ||
++ EventServiceManager::getInstance().getNumberOfSSESubscriptions() >=
++ maxNoOfSSESubscriptions)
++ {
++ BMCWEB_LOG_ERROR << "Max SSE subscriptions reached";
++ messages::eventSubscriptionLimitExceeded(res);
++ res.end();
++ return false;
++ }
++ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size();
++
++ std::shared_ptr<redfish::Subscription> subValue =
++ std::make_shared<redfish::Subscription>(std::move(conn));
++
++ // GET on this URI means, Its SSE subscriptionType.
++ subValue->subscriptionType = redfish::subscriptionTypeSSE;
++
++ // TODO: parse $filter query params and fill config.
++ subValue->protocol = "Redfish";
++ subValue->retryPolicy = "TerminateAfterRetries";
++ subValue->eventFormatType = "Event";
++
++ std::string id =
++ redfish::EventServiceManager::getInstance().addSubscription(subValue,
++ false);
++ if (id.empty())
++ {
++ messages::internalError(res);
++ res.end();
++ return false;
++ }
++
++ return true;
++}
++
++static void deleteSubscription(std::shared_ptr<crow::SseConnection>& conn)
++{
++ redfish::EventServiceManager::getInstance().deleteSubscription(conn);
++}
++
++inline void requestRoutes(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/SSE")
++ .privileges({{"ConfigureComponents", "ConfigureManager"}})
++ .serverSentEvent()
++ .onopen([](std::shared_ptr<crow::SseConnection>& conn,
++ const crow::Request& req, crow::Response& res) {
++ BMCWEB_LOG_DEBUG << "Connection " << conn << " opened.";
++ if (createSubscription(conn, req, res))
++ {
++ // All success, lets send SSE haader
++ conn->sendSSEHeader();
++ }
++ })
++ .onclose([](std::shared_ptr<crow::SseConnection>& conn) {
++ BMCWEB_LOG_DEBUG << "Connection " << conn << " closed";
++ deleteSubscription(conn);
++ });
++}
++} // namespace eventservice_sse
++} // namespace redfish
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 3f398d7..dd833ce 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -22,15 +22,17 @@
+ #include <sys/inotify.h>
+
+ #include <boost/asio/io_context.hpp>
++#include <boost/beast/core/span.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <error_messages.hpp>
+ #include <event_service_store.hpp>
+ #include <http_client.hpp>
+ #include <persistent_data.hpp>
+ #include <random.hpp>
+-#include <server_sent_events.hpp>
++#include <server_sent_event.hpp>
+ #include <utils/json_utils.hpp>
+
++#include <algorithm>
+ #include <cstdlib>
+ #include <ctime>
+ #include <fstream>
+@@ -46,9 +48,27 @@ using ReadingsObjType =
+ static constexpr const char* eventFormatType = "Event";
+ static constexpr const char* metricReportFormatType = "MetricReport";
+
++static constexpr const char* subscriptionTypeSSE = "SSE";
+ static constexpr const char* eventServiceFile =
+ "/var/lib/bmcweb/eventservice_config.json";
+
++static constexpr const uint8_t maxNoOfSubscriptions = 20;
++static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
++
++#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
++static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
++static constexpr const char* redfishEventLogDir = "/var/log";
++static constexpr const char* redfishEventLogFile = "/var/log/redfish";
++static constexpr const size_t iEventSize = sizeof(inotify_event);
++static int inotifyFd = -1;
++static int dirWatchDesc = -1;
++static int fileWatchDesc = -1;
++
++// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs>
++using EventLogObjectsType =
++ std::tuple<std::string, std::string, std::string, std::string, std::string,
++ std::vector<std::string>>;
++
+ namespace message_registries
+ {
+ inline boost::beast::span<const MessageEntry>
+@@ -68,24 +88,6 @@ inline boost::beast::span<const MessageEntry>
+ }
+ return boost::beast::span<const MessageEntry>(openbmc::registry);
+ }
+-} // namespace message_registries
+-
+-#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+-static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
+-static constexpr const char* redfishEventLogDir = "/var/log";
+-static constexpr const char* redfishEventLogFile = "/var/log/redfish";
+-static constexpr const size_t iEventSize = sizeof(inotify_event);
+-static int inotifyFd = -1;
+-static int dirWatchDesc = -1;
+-static int fileWatchDesc = -1;
+-
+-// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs>
+-using EventLogObjectsType =
+- std::tuple<std::string, std::string, std::string, std::string, std::string,
+- std::vector<std::string>>;
+-
+-namespace message_registries
+-{
+ static const Message*
+ getMsgFromRegistry(const std::string& messageKey,
+ const boost::beast::span<const MessageEntry>& registry)
+@@ -388,11 +390,9 @@ class Subscription : public persistent_data::UserSubscription
+ path, uriProto);
+ }
+
+- Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+- eventSeqNum(1)
+- {
+- sseConn = std::make_shared<crow::ServerSentEvents>(adaptor);
+- }
++ Subscription(const std::shared_ptr<crow::SseConnection>& adaptor) :
++ sseConn(adaptor), eventSeqNum(1)
++ {}
+
+ ~Subscription() = default;
+
+@@ -417,7 +417,7 @@ class Subscription : public persistent_data::UserSubscription
+
+ if (sseConn != nullptr)
+ {
+- sseConn->sendData(eventSeqNum, msg);
++ sseConn->sendEvent(std::to_string(eventSeqNum), msg);
+ }
+ }
+
+@@ -508,6 +508,7 @@ class Subscription : public persistent_data::UserSubscription
+
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
++ this->eventSeqNum++;
+ }
+ #endif
+
+@@ -578,14 +579,39 @@ class Subscription : public persistent_data::UserSubscription
+ return eventSeqNum;
+ }
+
++ void setSubscriptionId(const std::string& id)
++ {
++ BMCWEB_LOG_DEBUG << "Subscription ID: " << id;
++ subId = id;
++ }
++
++ std::string getSubscriptionId()
++ {
++ return subId;
++ }
++
++ std::optional<std::string>
++ getSubscriptionId(const std::shared_ptr<crow::SseConnection>& connPtr)
++ {
++ if (sseConn != nullptr && connPtr == sseConn)
++ {
++ BMCWEB_LOG_DEBUG << __FUNCTION__
++ << " conn matched, subId: " << subId;
++ return subId;
++ }
++
++ return std::nullopt;
++ }
++
+ private:
++ std::shared_ptr<crow::SseConnection> sseConn = nullptr;
+ uint64_t eventSeqNum;
+ std::string host;
+ std::string port;
+ std::string path;
+ std::string uriProto;
+ std::shared_ptr<crow::HttpClient> conn = nullptr;
+- std::shared_ptr<crow::ServerSentEvents> sseConn = nullptr;
++ std::string subId;
+ };
+
+ class EventServiceManager
+@@ -942,6 +968,8 @@ class EventServiceManager
+ subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
+ subValue->updateRetryPolicy();
+
++ // Set Subscription ID for back trace
++ subValue->setSubscriptionId(id);
+ return id;
+ }
+
+@@ -970,11 +998,40 @@ class EventServiceManager
+ }
+ }
+
++ void deleteSubscription(const std::shared_ptr<crow::SseConnection>& connPtr)
++ {
++ for (const auto& it : this->subscriptionsMap)
++ {
++ std::shared_ptr<Subscription> entry = it.second;
++ if (entry->subscriptionType == subscriptionTypeSSE)
++ {
++ std::optional<std::string> id =
++ entry->getSubscriptionId(connPtr);
++ if (id)
++ {
++ deleteSubscription(*id);
++ return;
++ }
++ }
++ }
++ }
++
+ size_t getNumberOfSubscriptions()
+ {
+ return subscriptionsMap.size();
+ }
+
++ size_t getNumberOfSSESubscriptions() const
++ {
++ auto count = std::count_if(
++ subscriptionsMap.begin(), subscriptionsMap.end(),
++ [this](const std::pair<std::string, std::shared_ptr<Subscription>>&
++ entry) {
++ return (entry.second->subscriptionType == subscriptionTypeSSE);
++ });
++ return static_cast<size_t>(count);
++ }
++
+ std::vector<std::string> getAllIDs()
+ {
+ std::vector<std::string> idList;
+diff --git a/redfish-core/include/server_sent_events.hpp b/redfish-core/include/server_sent_events.hpp
+deleted file mode 100644
+index 7613d7b..0000000
+--- a/redfish-core/include/server_sent_events.hpp
++++ /dev/null
+@@ -1,290 +0,0 @@
+-
+-/*
+-// Copyright (c) 2020 Intel Corporation
+-//
+-// Licensed under the Apache License, Version 2.0 (the "License");
+-// you may not use this file except in compliance with the License.
+-// You may obtain a copy of the License at
+-//
+-// http://www.apache.org/licenses/LICENSE-2.0
+-//
+-// Unless required by applicable law or agreed to in writing, software
+-// distributed under the License is distributed on an "AS IS" BASIS,
+-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-// See the License for the specific language governing permissions and
+-// limitations under the License.
+-*/
+-#pragma once
+-
+-#include <boost/asio/strand.hpp>
+-#include <boost/beast/core/span.hpp>
+-#include <boost/beast/http/buffer_body.hpp>
+-#include <boost/beast/http/message.hpp>
+-#include <boost/beast/version.hpp>
+-
+-#include <cstdlib>
+-#include <functional>
+-#include <iostream>
+-#include <memory>
+-#include <queue>
+-#include <string>
+-
+-namespace crow
+-{
+-
+-static constexpr uint8_t maxReqQueueSize = 50;
+-
+-enum class SseConnState
+-{
+- startInit,
+- initInProgress,
+- initialized,
+- initFailed,
+- sendInProgress,
+- sendFailed,
+- idle,
+- suspended,
+- closed
+-};
+-
+-class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents>
+-{
+- private:
+- std::shared_ptr<boost::beast::tcp_stream> sseConn;
+- std::queue<std::pair<uint64_t, std::string>> requestDataQueue;
+- std::string outBuffer;
+- SseConnState state;
+- int retryCount;
+- int maxRetryAttempts;
+-
+- void sendEvent(const std::string& id, const std::string& msg)
+- {
+- if (msg.empty())
+- {
+- BMCWEB_LOG_DEBUG << "Empty data, bailing out.";
+- return;
+- }
+-
+- if (state == SseConnState::sendInProgress)
+- {
+- return;
+- }
+- state = SseConnState::sendInProgress;
+-
+- if (!id.empty())
+- {
+- outBuffer += "id: ";
+- outBuffer.append(id.begin(), id.end());
+- outBuffer += "\n";
+- }
+-
+- outBuffer += "data: ";
+- for (char character : msg)
+- {
+- outBuffer += character;
+- if (character == '\n')
+- {
+- outBuffer += "data: ";
+- }
+- }
+- outBuffer += "\n\n";
+-
+- doWrite();
+- }
+-
+- void doWrite()
+- {
+- if (outBuffer.empty())
+- {
+- BMCWEB_LOG_DEBUG << "All data sent successfully.";
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- requestDataQueue.pop();
+- state = SseConnState::idle;
+- checkQueue();
+- return;
+- }
+-
+- sseConn->async_write_some(
+- boost::asio::buffer(outBuffer.data(), outBuffer.size()),
+- [self(shared_from_this())](
+- boost::beast::error_code ec,
+- [[maybe_unused]] const std::size_t& bytesTransferred) {
+- self->outBuffer.erase(0, bytesTransferred);
+-
+- if (ec == boost::asio::error::eof)
+- {
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- self->requestDataQueue.pop();
+- self->state = SseConnState::idle;
+- self->checkQueue();
+- return;
+- }
+-
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "async_write_some() failed: "
+- << ec.message();
+- self->state = SseConnState::sendFailed;
+- self->checkQueue();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: "
+- << bytesTransferred;
+-
+- self->doWrite();
+- });
+- }
+-
+- void startSSE()
+- {
+- if (state == SseConnState::initInProgress)
+- {
+- return;
+- }
+- state = SseConnState::initInProgress;
+-
+- BMCWEB_LOG_DEBUG << "starting SSE connection ";
+- using BodyType = boost::beast::http::buffer_body;
+- auto response =
+- std::make_shared<boost::beast::http::response<BodyType>>(
+- boost::beast::http::status::ok, 11);
+- auto serializer =
+- std::make_shared<boost::beast::http::response_serializer<BodyType>>(
+- *response);
+-
+- // TODO: Add hostname in http header.
+- response->set(boost::beast::http::field::server, "iBMC");
+- response->set(boost::beast::http::field::content_type,
+- "text/event-stream");
+- response->body().data = nullptr;
+- response->body().size = 0;
+- response->body().more = true;
+-
+- boost::beast::http::async_write_header(
+- *sseConn, *serializer,
+- [this, response,
+- serializer](const boost::beast::error_code& ec,
+- [[maybe_unused]] const std::size_t& bytesTransferred) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Error sending header" << ec;
+- state = SseConnState::initFailed;
+- checkQueue();
+- return;
+- }
+-
+- BMCWEB_LOG_DEBUG << "startSSE Header sent.";
+- state = SseConnState::initialized;
+- checkQueue();
+- });
+- }
+-
+- void checkQueue(const bool newRecord = false)
+- {
+- if (requestDataQueue.empty())
+- {
+- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n";
+- return;
+- }
+-
+- if (retryCount >= maxRetryAttempts)
+- {
+- BMCWEB_LOG_ERROR << "Maximum number of retries is reached.";
+-
+- // Clear queue.
+- while (!requestDataQueue.empty())
+- {
+- requestDataQueue.pop();
+- }
+-
+- // TODO: Take 'DeliveryRetryPolicy' action.
+- // For now, doing 'SuspendRetries' action.
+- state = SseConnState::suspended;
+- return;
+- }
+-
+- if ((state == SseConnState::initFailed) ||
+- (state == SseConnState::sendFailed))
+- {
+- if (newRecord)
+- {
+- // We are already running async wait and retry.
+- // Since record is added to queue, it gets the
+- // turn in FIFO.
+- return;
+- }
+-
+- retryCount++;
+- // TODO: Perform async wait for retryTimeoutInterval before proceed.
+- }
+- else
+- {
+- // reset retry count.
+- retryCount = 0;
+- }
+-
+- switch (state)
+- {
+- case SseConnState::initInProgress:
+- case SseConnState::sendInProgress:
+- case SseConnState::suspended:
+- case SseConnState::startInit:
+- case SseConnState::closed:
+- // do nothing
+- break;
+- case SseConnState::initFailed:
+- {
+- startSSE();
+- break;
+- }
+- case SseConnState::initialized:
+- case SseConnState::idle:
+- case SseConnState::sendFailed:
+- {
+- std::pair<uint64_t, std::string> reqData =
+- requestDataQueue.front();
+- sendEvent(std::to_string(reqData.first), reqData.second);
+- break;
+- }
+- }
+-
+- return;
+- }
+-
+- public:
+- ServerSentEvents(const ServerSentEvents&) = delete;
+- ServerSentEvents& operator=(const ServerSentEvents&) = delete;
+- ServerSentEvents(ServerSentEvents&&) = delete;
+- ServerSentEvents& operator=(ServerSentEvents&&) = delete;
+-
+- ServerSentEvents(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+- sseConn(adaptor), state(SseConnState::startInit), retryCount(0),
+- maxRetryAttempts(5)
+- {
+- startSSE();
+- }
+-
+- ~ServerSentEvents() = default;
+-
+- void sendData(const uint64_t& id, const std::string& data)
+- {
+- if (state == SseConnState::suspended)
+- {
+- return;
+- }
+-
+- if (requestDataQueue.size() <= maxReqQueueSize)
+- {
+- requestDataQueue.push(std::pair(id, data));
+- checkQueue(true);
+- }
+- else
+- {
+- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data.";
+- }
+- }
+-};
+-
+-} // namespace crow
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 8609862..249e594 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -37,8 +37,6 @@ static constexpr const std::array<const char*, 1> supportedResourceTypes = {
+ "Task"};
+ #endif
+
+-static constexpr const uint8_t maxNoOfSubscriptions = 20;
+-
+ inline void requestRoutesEventService(App& app)
+ {
+ BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
+@@ -50,6 +48,8 @@ inline void requestRoutesEventService(App& app)
+ {"@odata.type", "#EventService.v1_5_0.EventService"},
+ {"Id", "EventService"},
+ {"Name", "Event Service"},
++ {"ServerSentEventUri",
++ "/redfish/v1/EventService/Subscriptions/SSE"},
+ {"Subscriptions",
+ {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
+ {"Actions",
+@@ -90,9 +90,7 @@ inline void requestRoutesEventService(App& app)
+ .privileges(redfish::privileges::patchEventService)
+ .methods(boost::beast::http::verb::patch)(
+ [](const crow::Request& req,
+- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+-
+- {
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+ std::optional<bool> serviceEnabled;
+ std::optional<uint32_t> retryAttemps;
+ std::optional<uint32_t> retryInterval;
+diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
+index bf98aae..53745d8 100644
+--- a/src/webserver_main.cpp
++++ b/src/webserver_main.cpp
+@@ -6,6 +6,7 @@
+ #include <cors_preflight.hpp>
+ #include <dbus_monitor.hpp>
+ #include <dbus_singleton.hpp>
++#include <eventservice_sse.hpp>
+ #include <google/google_service_root.hpp>
+ #include <hostname_monitor.hpp>
+ #include <ibm/management_console_rest.hpp>
+@@ -83,6 +84,7 @@ int main(int /*argc*/, char** /*argv*/)
+ #endif
+
+ #ifdef BMCWEB_ENABLE_REDFISH
++ redfish::eventservice_sse::requestRoutes(app);
+ redfish::requestRoutes(app);
+ redfish::RedfishService redfish(app);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch
new file mode 100644
index 000000000..3914cc81a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch
@@ -0,0 +1,296 @@
+From 769f0e20d0a7e786d7091ffb7ee57d35204dfa28 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 17 Mar 2021 01:16:50 +0000
+Subject: [PATCH] Add EventService SSE filter support
+
+This commit implements the Event Service SSE stream
+filters support. As per redfish specification:
+The SSE streams have these formats:
+ - Metric report SSE stream
+ - Event message SSE stream
+
+To reduce the amount of data, service supports $filter
+query parameter in SSE URI.
+Below properties support as filter criteria:
+ - EventFormatType( Event & MetricReport)
+ - MessageId
+ - RegistryPrefix
+ - MetricReportDefinition
+
+For more details, refer Redfish specification section 13.5.2
+
+Tested:
+ Created SSE stream with different filters and observed
+ desired events on SSE stream client(browser), some examples
+ - To get all Redfish events,
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)
+ - To get Redfish events with RegistryPrefix "OpenBMC"
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(RegistryPrefix%20eq%20OpenBMC)
+ - To get only DC power of Events,
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)%20and%20(MessageId%20eq%20DCPowerOff)
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Change-Id: I55c6f53bb5e57aa1f2d1601f1a16525a33b13bd2
+---
+ include/eventservice_sse.hpp | 145 +++++++++++++++++-
+ redfish-core/include/error_messages.hpp | 9 ++
+ .../include/event_service_manager.hpp | 5 +
+ redfish-core/lib/event_service.hpp | 5 -
+ redfish-core/src/error_messages.cpp | 26 ++++
+ 5 files changed, 181 insertions(+), 9 deletions(-)
+
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+index 14daf00..fed7fec 100644
+--- a/include/eventservice_sse.hpp
++++ b/include/eventservice_sse.hpp
+@@ -23,16 +23,153 @@ static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn,
+ }
+ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size();
+
++ // EventService SSE supports only "$filter" query param.
++ if (req.urlParams.size() > 1)
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ std::string eventFormatType;
++ std::string queryFilters;
++ if (req.urlParams.size())
++ {
++ boost::urls::url_view::params_type::iterator it =
++ req.urlParams.find("$filter");
++ if (it == req.urlParams.end())
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ queryFilters = it->value();
++ }
++ else
++ {
++ eventFormatType = "Event";
++ }
++
++ std::vector<std::string> msgIds;
++ std::vector<std::string> regPrefixes;
++ std::vector<std::string> mrdsArray;
++ if (!queryFilters.empty())
++ {
++ // Reading from query params.
++ bool status = readSSEQueryParams(queryFilters, eventFormatType, msgIds,
++ regPrefixes, mrdsArray);
++ if (!status)
++ {
++ messages::invalidObject(res, queryFilters);
++ res.end();
++ return false;
++ }
++
++ // RegsitryPrefix and messageIds are mutuly exclusive as per redfish
++ // specification.
++ if (regPrefixes.size() && msgIds.size())
++ {
++ messages::mutualExclusiveProperties(res, "RegistryPrefix",
++ "MessageId");
++ res.end();
++ return false;
++ }
++
++ if (!eventFormatType.empty())
++ {
++ if (std::find(supportedEvtFormatTypes.begin(),
++ supportedEvtFormatTypes.end(),
++ eventFormatType) == supportedEvtFormatTypes.end())
++ {
++ messages::propertyValueNotInList(res, eventFormatType,
++ "EventFormatType");
++ res.end();
++ return false;
++ }
++ }
++ else
++ {
++ // If nothing specified, using default "Event"
++ eventFormatType = "Event";
++ }
++
++ if (!regPrefixes.empty())
++ {
++ for (const std::string& it : regPrefixes)
++ {
++ if (std::find(supportedRegPrefixes.begin(),
++ supportedRegPrefixes.end(),
++ it) == supportedRegPrefixes.end())
++ {
++ messages::propertyValueNotInList(res, it, "RegistryPrefix");
++ res.end();
++ return false;
++ }
++ }
++ }
++
++ if (!msgIds.empty())
++ {
++ std::vector<std::string> registryPrefix;
++
++ // If no registry prefixes are mentioned, consider all supported
++ // prefixes to validate message ID
++ if (regPrefixes.empty())
++ {
++ registryPrefix.assign(supportedRegPrefixes.begin(),
++ supportedRegPrefixes.end());
++ }
++ else
++ {
++ registryPrefix = regPrefixes;
++ }
++
++ for (const std::string& id : msgIds)
++ {
++ bool validId = false;
++
++ // Check for Message ID in each of the selected Registry
++ for (const std::string& it : registryPrefix)
++ {
++ const boost::beast::span<
++ const redfish::message_registries::MessageEntry>
++ registry =
++ redfish::message_registries::getRegistryFromPrefix(
++ it);
++
++ if (std::any_of(
++ registry.cbegin(), registry.cend(),
++ [&id](
++ const redfish::message_registries::MessageEntry&
++ messageEntry) {
++ return !id.compare(messageEntry.first);
++ }))
++ {
++ validId = true;
++ break;
++ }
++ }
++
++ if (!validId)
++ {
++ messages::propertyValueNotInList(res, id, "MessageIds");
++ res.end();
++ return false;
++ }
++ }
++ }
++ }
++
+ std::shared_ptr<redfish::Subscription> subValue =
+ std::make_shared<redfish::Subscription>(std::move(conn));
+
+ // GET on this URI means, Its SSE subscriptionType.
+- subValue->subscriptionType = redfish::subscriptionTypeSSE;
+-
+- // TODO: parse $filter query params and fill config.
++ subValue->subscriptionType = subscriptionTypeSSE;
+ subValue->protocol = "Redfish";
+ subValue->retryPolicy = "TerminateAfterRetries";
+- subValue->eventFormatType = "Event";
++ subValue->eventFormatType = eventFormatType;
++ subValue->registryMsgIds = msgIds;
++ subValue->registryPrefixes = regPrefixes;
++ subValue->metricReportDefinitions = mrdsArray;
+
+ std::string id =
+ redfish::EventServiceManager::getInstance().addSubscription(subValue,
+diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
+index 3d11cc4..90084e3 100644
+--- a/redfish-core/include/error_messages.hpp
++++ b/redfish-core/include/error_messages.hpp
+@@ -971,6 +971,15 @@ nlohmann::json mutualExclusiveProperties(const std::string& arg1,
+ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1,
+ const std::string& arg2);
+
++/**
++ * @brief Formats InvalidQueryFilter message into JSON
++ * Message body: "The requested URL contains the invalid query filters"
++ *
++ * @returns Message InvalidQueryFilter formatted to JSON */
++nlohmann::json invalidQueryFilter();
++
++void invalidQueryFilter(crow::Response& res);
++
+ } // namespace messages
+
+ } // namespace redfish
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index dd833ce..861f4cb 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -55,6 +55,11 @@ static constexpr const char* eventServiceFile =
+ static constexpr const uint8_t maxNoOfSubscriptions = 20;
+ static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
+
++static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
++ eventFormatType, metricReportFormatType};
++static constexpr const std::array<const char*, 2> supportedRegPrefixes = {
++ "OpenBMC", "TaskEvent"};
++
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+ static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
+ static constexpr const char* redfishEventLogDir = "/var/log";
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 249e594..6f01707 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -21,11 +21,6 @@
+
+ namespace redfish
+ {
+-
+-static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
+- eventFormatType, metricReportFormatType};
+-static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
+- "Base", "OpenBMC", "TaskEvent"};
+ static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
+ "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
+
+diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
+index 9c28e8f..2394398 100644
+--- a/redfish-core/src/error_messages.cpp
++++ b/redfish-core/src/error_messages.cpp
+@@ -2173,6 +2173,32 @@ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1,
+ addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2));
+ }
+
++/**
++ * @internal
++ * @brief Formats InvalidQueryFilter into JSON
++ *
++ * See header file for more information
++ * @endinternal
++ */
++nlohmann::json invalidQueryFilter()
++{
++ return nlohmann::json{
++ {"@odata.type", "#Message.v1_0_0.Message"},
++ {"MessageId", "Base.1.5.0.InvalidQueryFilter"},
++ {"Message", "The requested url contains the invalid query filter."},
++ {"MessageArgs", nlohmann::json::array()},
++ {"Severity", "Warning"},
++ {"Resolution",
++ "Ensure the correct query filter is specified in requested url "
++ "and resubmit the request."}};
++}
++
++void invalidQueryFilter(crow::Response& res)
++{
++ res.result(boost::beast::http::status::bad_request);
++ addMessageToErrorJson(res.jsonValue, invalidQueryFilter());
++}
++
+ } // namespace messages
+
+ } // namespace redfish
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch
new file mode 100644
index 000000000..3be65ee2a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch
@@ -0,0 +1,132 @@
+From b8eb53886106e44e3668857b13f8642d2ad3cfbf Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Fri, 27 Aug 2021 16:02:01 +0000
+Subject: [PATCH] EventService: Log events for subscription actions
+
+Log redfish event for below 3 actions
+ - Add new subscription
+ - Update existing subscription properties
+ - Delete existing subscription
+in order to notify the subscribed clients on the subscription related
+information.
+
+Modified method name accordingly to indicate the clear purpose and
+added updateSubscription method with subscription id param
+to log event for subscription update.
+
+Tested:
+ - Performed all the above actions and verified the redfish event
+ messages are logged.
+
+Change-Id: I3745fa6357bd215379781a9818d9acc02a853d79
+Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ .../include/event_service_manager.hpp | 35 ++++++++++++++++---
+ redfish-core/lib/event_service.hpp | 2 +-
+ 2 files changed, 32 insertions(+), 5 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index c3e7f61..e9bdbfa 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -21,6 +21,7 @@
+ #include "registries/task_event_message_registry.hpp"
+
+ #include <sys/inotify.h>
++#include <systemd/sd-journal.h>
+
+ #include <boost/asio/io_context.hpp>
+ #include <boost/beast/core/span.hpp>
+@@ -788,7 +789,7 @@ class EventServiceManager
+ }
+ }
+
+- void updateSubscriptionData()
++ void persistSubscriptionData()
+ {
+ persistent_data::EventServiceStore::getInstance()
+ .eventServiceConfig.enabled = serviceEnabled;
+@@ -835,7 +836,7 @@ class EventServiceManager
+
+ if (updateConfig)
+ {
+- updateSubscriptionData();
++ persistSubscriptionData();
+ }
+
+ if (updateRetryCfg)
+@@ -947,7 +948,7 @@ class EventServiceManager
+
+ if (updateFile)
+ {
+- updateSubscriptionData();
++ persistSubscriptionData();
+ }
+
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+@@ -962,6 +963,13 @@ class EventServiceManager
+
+ // Set Subscription ID for back trace
+ subValue->setSubscriptionId(id);
++
++ /* Log event for subscription addition */
++ sd_journal_send("MESSAGE=Event subscription added(Id: %s)", id.c_str(),
++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionAdded",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++
+ return id;
+ }
+
+@@ -986,7 +994,14 @@ class EventServiceManager
+ persistent_data::EventServiceStore::getInstance()
+ .subscriptionsConfigMap.erase(obj2);
+ updateNoOfSubscribersCount();
+- updateSubscriptionData();
++
++ persistSubscriptionData();
++ /* Log event for subscription delete. */
++ sd_journal_send("MESSAGE=Event subscription removed.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionRemoved",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
+ }
+ }
+
+@@ -1008,6 +1023,18 @@ class EventServiceManager
+ }
+ }
+
++ void updateSubscription(const std::string& id)
++ {
++ persistSubscriptionData();
++
++ /* Log event for subscription update. */
++ sd_journal_send("MESSAGE=Event subscription updated.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionUpdated",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++ }
++
+ size_t getNumberOfSubscriptions()
+ {
+ return subscriptionsMap.size();
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 9def549..6a8421f 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -617,7 +617,7 @@ inline void requestRoutesEventDestination(App& app)
+ subValue->updateRetryPolicy();
+ }
+
+- EventServiceManager::getInstance().updateSubscriptionData();
++ EventServiceManager::getInstance().updateSubscription(param);
+ });
+ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
+ // The below privilege is wrong, it should be ConfigureManager OR
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
new file mode 100644
index 000000000..84ceb4ba8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
@@ -0,0 +1,85 @@
+From 05fdea2bb8e486b058d137a067ce1f5c885d2a96 Mon Sep 17 00:00:00 2001
+From: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Date: Mon, 28 Jun 2021 19:59:57 +0000
+Subject: [PATCH] Add checks on Event Subscription input parameters
+
+There is no check on the size of input parameters(Context,
+Destination and Header) during Event Subscription.This
+creates out of memory situation.
+This commit checks for the size of input parameters and
+rejects if it is exceeding the input size limits.
+
+Tested
+ - Validated using POST on Event Subscription.
+ - When Context, Destination and Headers were too long,
+ received a error message denoting the same.
+
+Change-Id: Iec2cd766c0e137b72706fc2da468d4fefd8fbaae
+Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+---
+ redfish-core/lib/event_service.hpp | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 52b01e5..f8a1671 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -19,6 +19,10 @@
+ #include <app.hpp>
+ #include <registries/privilege_registry.hpp>
+
++#define MAX_CONTEXT_SIZE 256
++#define MAX_DESTINATION_SIZE 1024
++#define MAX_HEADER_SIZE 8096
++
+ namespace redfish
+ {
+ static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
+@@ -220,6 +224,12 @@ inline void requestRoutesEventDestinationCollection(App& app)
+ return;
+ }
+
++ if (destUrl.size() > MAX_DESTINATION_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res, "Destination");
++ return;
++ }
++
+ if (regPrefixes && msgIds)
+ {
+ if (regPrefixes->size() && msgIds->size())
+@@ -330,11 +340,31 @@ inline void requestRoutesEventDestinationCollection(App& app)
+
+ if (context)
+ {
++ if (context->size() > MAX_CONTEXT_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res, "Context");
++ return;
++ }
+ subValue->customText = *context;
+ }
+
+ if (headers)
+ {
++ size_t cumulativeLen = 0;
++
++ for (nlohmann::json& itr : *headers)
++ {
++ std::string hdr{itr.dump(
++ -1, ' ', true, nlohmann::json::error_handler_t::replace)};
++ cumulativeLen += hdr.length();
++
++ if (cumulativeLen > MAX_HEADER_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res,
++ "HttpHeaders");
++ return;
++ }
++ }
+ subValue->httpHeaders = *headers;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0009-Restructure-Redifsh-EventLog-Transmit-code-flow.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0009-Restructure-Redifsh-EventLog-Transmit-code-flow.patch
new file mode 100644
index 000000000..d1fe475f5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0009-Restructure-Redifsh-EventLog-Transmit-code-flow.patch
@@ -0,0 +1,225 @@
+From 542505dff60e3921b00b51acae882e207d46f1a6 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Wed, 14 Jul 2021 14:13:11 +0000
+Subject: [PATCH] Restructure Redfish EventLog Transmit code flow
+
+In the current implementation:
+ 1. When Event service is disabled and enabled back after a while,
+ all the logs during this time span between disable to enable
+ are dumped to the Event listener.
+ 2. When two events occur very close (in terms of microseconds)
+ and they trigger two different iNotify events, the listener
+ receives both of these events with the same Event ID.
+
+This occurs as the last log time stamp read from redfish file
+and previous time stamp used to generate Event ID's are not
+being updated continuously.
+
+This commit fixes this issue by tweaking the logic to continuously
+update the time stamp values (even during when Event Service is
+disabled), and also replaces multiple string operations with file
+operations. i.e. Instead of looping through the entire Redfish file
+until last time stamp read is reached, this fix makes use of
+fseek to get to the last read position.
+
+Tested:
+ - Subscribed to an event and successfully received Event Logs.
+ - No Event Logs were received when Event Service was disabled.
+ - No Dump of past Events after Event Service was enabled.
+ - Redfish Validator passed
+
+Change-Id: I87136bee78076b1b3219930813702b3b9d20c157
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ .../include/event_service_manager.hpp | 108 ++++++++++++------
+ 1 file changed, 76 insertions(+), 32 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index e9bdbfa..5c4de70 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -134,15 +134,10 @@ static const Message* formatMessage(const std::string_view& messageID)
+
+ namespace event_log
+ {
+-inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
+- const bool firstEntry = true)
++inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID)
+ {
+ static time_t prevTs = 0;
+ static int index = 0;
+- if (firstEntry)
+- {
+- prevTs = 0;
+- }
+
+ // Get the entry timestamp
+ std::time_t curTs = 0;
+@@ -621,6 +616,7 @@ class EventServiceManager
+ }
+
+ std::string lastEventTStr;
++ std::streampos redfishLogFilePosition{0};
+ size_t noOfEventLogSubscribers{0};
+ size_t noOfMetricReportSubscribers{0};
+ std::shared_ptr<sdbusplus::bus::match::match> matchTelemetryMonitor;
+@@ -1163,7 +1159,22 @@ class EventServiceManager
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+ void cacheLastEventTimestamp()
+ {
+- lastEventTStr.clear();
++ // Control comes here when :
++ // 1. Subscription is added and lastEventTStr is empty
++ // 2. lastEventTStr is empty
++ // 3. When a new Redfish file is created
++
++ if (!lastEventTStr.empty())
++ {
++ // Control would be here when Redfish file is created.
++ // Reset File Position as new file is created
++ redfishLogFilePosition = 0;
++ return;
++ }
++
++ // Open the redfish file and read till the last record to get the
++ // last event's time stamp.
++
+ std::ifstream logStream(redfishEventLogFile);
+ if (!logStream.good())
+ {
+@@ -1171,27 +1182,44 @@ class EventServiceManager
+ return;
+ }
+ std::string logEntry;
++ std::string prev_logEntry;
+ while (std::getline(logStream, logEntry))
+ {
+- size_t space = logEntry.find_first_of(' ');
+- if (space == std::string::npos)
+- {
+- // Shouldn't enter here but lets skip it.
+- BMCWEB_LOG_DEBUG << "Invalid log entry found.";
+- continue;
+- }
+- lastEventTStr = logEntry.substr(0, space);
++ prev_logEntry = logEntry;
++ redfishLogFilePosition = logStream.tellg();
++ }
++
++ if (prev_logEntry.empty())
++ {
++ BMCWEB_LOG_ERROR
++ << "Last Event Time Stamp Caching Failed : No Records";
++ redfishLogFilePosition = 0;
++ return;
++ }
++
++ size_t space = prev_logEntry.find_first_of(' ');
++ if (space == std::string::npos)
++ {
++ // Shouldn't enter here but lets skip it.
++ BMCWEB_LOG_DEBUG << "Invalid log entry found.";
++ BMCWEB_LOG_ERROR << "Last Event Time Stamp Caching Failed";
++ return;
+ }
++ lastEventTStr = prev_logEntry.substr(0, space);
+ BMCWEB_LOG_DEBUG << "Last Event time stamp set: " << lastEventTStr;
++ BMCWEB_LOG_DEBUG << "Next Log Position : " << redfishLogFilePosition;
+ }
+
+ void readEventLogsFromFile()
+ {
+- if (!serviceEnabled || !noOfEventLogSubscribers)
++ if (lastEventTStr.empty())
+ {
+- BMCWEB_LOG_DEBUG << "EventService disabled or no Subscriptions.";
+- return;
++ // Shouldn't ideally enter here.
++ // Last event Time stamp would be set by now.
++ // Just incase of any failures before.
++ cacheLastEventTimestamp();
+ }
++
+ std::ifstream logStream(redfishEventLogFile);
+ if (!logStream.good())
+ {
+@@ -1201,27 +1229,21 @@ class EventServiceManager
+
+ std::vector<EventLogObjectsType> eventRecords;
+
+- bool startLogCollection = false;
+- bool firstEntry = true;
+-
+ std::string logEntry;
++
++ // Get the read pointer to the next log to be read.
++ logStream.seekg(redfishLogFilePosition);
++
+ while (std::getline(logStream, logEntry))
+ {
+- if (!startLogCollection && !lastEventTStr.empty())
+- {
+- if (boost::starts_with(logEntry, lastEventTStr))
+- {
+- startLogCollection = true;
+- }
+- continue;
+- }
++ // Update Pointer position
++ redfishLogFilePosition = logStream.tellg();
+
+ std::string idStr;
+- if (!event_log::getUniqueEntryID(logEntry, idStr, firstEntry))
++ if (!event_log::getUniqueEntryID(logEntry, idStr))
+ {
+ continue;
+ }
+- firstEntry = false;
+
+ std::string timestamp;
+ std::string messageID;
+@@ -1233,6 +1255,16 @@ class EventServiceManager
+ continue;
+ }
+
++ lastEventTStr = timestamp;
++
++ if (!serviceEnabled || !noOfEventLogSubscribers)
++ {
++ // If Service is not enabled, no need to compute
++ // the remaining items below.
++ // But, Loop must continue to keep track of Timestamp
++ continue;
++ }
++
+ std::string registryName;
+ std::string messageKey;
+ event_log::getRegistryAndMessageKey(messageID, registryName,
+@@ -1242,11 +1274,23 @@ class EventServiceManager
+ continue;
+ }
+
+- lastEventTStr = timestamp;
+ eventRecords.emplace_back(idStr, timestamp, messageID, registryName,
+ messageKey, messageArgs);
+ }
+
++ if (!serviceEnabled || !noOfEventLogSubscribers)
++ {
++ BMCWEB_LOG_DEBUG << "EventService disabled or no Subscriptions.";
++ return;
++ }
++
++ if (eventRecords.empty())
++ {
++ // No Records to send
++ BMCWEB_LOG_DEBUG << "No log entries available to be transferred.";
++ return;
++ }
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch
new file mode 100644
index 000000000..9af5a066b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch
@@ -0,0 +1,258 @@
+From f665ba085bb2310f008b7534f827fb401ad973c2 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 12 Oct 2021 08:19:51 +0000
+Subject: [PATCH] Delete/Remove Terminated Event Subscription(s)
+
+Added functionality to delete/remove event subscription(s) which are
+configured to Terminate after retries.
+
+Currently, when an Event is subscribed with Retry Policy as
+"TerminateAfterRetries", the state of the connection is set to
+"Terminated" after retrying, but the Subscription is not removed.
+This commit adds the functionality to detect terminated connection and
+remove the respective subscription.
+
+Tested:
+ - Created a Subscription with
+ DeliveryRetryPolicy: "TerminateAfterRetries"
+ - Received Events successfully on Event listener
+ - Once the Event listener was stopped, the Subscription was
+ removed/deleted after retries.
+
+Change-Id: If447acb2db74fb29a5d1cfe6194b77cda82bc8a1
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_client.hpp | 43 +++++++++++++++----
+ .../include/event_service_manager.hpp | 36 ++++++++++++++++
+ 2 files changed, 70 insertions(+), 9 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index 5e7ff47..54ae2c3 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -55,6 +55,8 @@ enum class ConnState
+ closeInProgress,
+ closed,
+ suspended,
++ terminate,
++ terminateInProgress,
+ terminated,
+ abortConnection,
+ retry
+@@ -288,7 +290,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ void doClose()
+ {
+- state = ConnState::closeInProgress;
++ if (state == ConnState::terminate)
++ {
++ state = ConnState::terminateInProgress;
++ }
++ else if (state != ConnState::suspended)
++ {
++ state = ConnState::closeInProgress;
++ }
+
+ // Set the timeout on the tcp stream socket for the async operation
+ conn.expires_after(std::chrono::seconds(30));
+@@ -318,8 +327,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ self->conn.close();
+
+- if ((self->state != ConnState::suspended) &&
+- (self->state != ConnState::terminated))
++ if (self->state == ConnState::terminateInProgress)
++ {
++ self->state = ConnState::terminated;
++ }
++ else if (self->state == ConnState::closeInProgress)
+ {
+ self->state = ConnState::closed;
+ self->handleConnState();
+@@ -341,8 +353,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ conn.close();
+
+- if ((state != ConnState::suspended) &&
+- (state != ConnState::terminated))
++ if (state == ConnState::terminateInProgress)
++ {
++ state = ConnState::terminated;
++ }
++ else if (state == ConnState::closeInProgress)
+ {
+ state = ConnState::closed;
+ handleConnState();
+@@ -365,8 +380,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction;
+ if (retryPolicyAction == "TerminateAfterRetries")
+ {
+- // TODO: delete subscription
+- state = ConnState::terminated;
++ state = ConnState::terminate;
+ }
+ if (retryPolicyAction == "SuspendRetries")
+ {
+@@ -423,6 +437,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ case ConnState::sendInProgress:
+ case ConnState::recvInProgress:
+ case ConnState::closeInProgress:
++ case ConnState::terminateInProgress:
+ {
+ BMCWEB_LOG_DEBUG << "Async operation is already in progress";
+ break;
+@@ -439,7 +454,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ break;
+ }
+ case ConnState::suspended:
+- case ConnState::terminated:
++ case ConnState::terminate:
+ {
+ doClose();
+ break;
+@@ -506,7 +521,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ void sendData(const std::string& data)
+ {
+- if ((state == ConnState::suspended) || (state == ConnState::terminated))
++ if ((state == ConnState::terminate) ||
++ (state == ConnState::terminated) || (state == ConnState::suspended))
+ {
+ return;
+ }
+@@ -524,6 +540,15 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ return;
+ }
+
++ bool isTerminated()
++ {
++ if (state == ConnState::terminated)
++ {
++ return true;
++ }
++ return false;
++ }
++
+ void addHeaders(
+ const std::vector<std::pair<std::string, std::string>>& httpHeaders)
+ {
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 6f60a31..363adb0 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -591,6 +591,14 @@ class Subscription : public persistent_data::UserSubscription
+ return std::nullopt;
+ }
+
++ bool isTerminated()
++ {
++ if (conn != nullptr)
++ return conn->isTerminated();
++
++ return false;
++ }
++
+ private:
+ std::shared_ptr<crow::SseConnection> sseConn = nullptr;
+ uint64_t eventSeqNum;
+@@ -847,6 +855,22 @@ class EventServiceManager
+ }
+ }
+
++ void deleteTerminatedSubcriptions()
++ {
++ boost::container::flat_map<std::string,
++ std::shared_ptr<Subscription>>::iterator it =
++ subscriptionsMap.begin();
++ while (it != subscriptionsMap.end())
++ {
++ std::shared_ptr<Subscription> entry = it->second;
++ if (entry->isTerminated())
++ {
++ subscriptionsMap.erase(it);
++ }
++ it++;
++ }
++ }
++
+ void updateNoOfSubscribersCount()
+ {
+ size_t eventLogSubCount = 0;
+@@ -881,6 +905,7 @@ class EventServiceManager
+
+ std::shared_ptr<Subscription> getSubscription(const std::string& id)
+ {
++ deleteTerminatedSubcriptions();
+ auto obj = subscriptionsMap.find(id);
+ if (obj == subscriptionsMap.end())
+ {
+@@ -971,6 +996,7 @@ class EventServiceManager
+
+ bool isSubscriptionExist(const std::string& id)
+ {
++ deleteTerminatedSubcriptions();
+ auto obj = subscriptionsMap.find(id);
+ if (obj == subscriptionsMap.end())
+ {
+@@ -1033,6 +1059,7 @@ class EventServiceManager
+
+ size_t getNumberOfSubscriptions()
+ {
++ deleteTerminatedSubcriptions();
+ return subscriptionsMap.size();
+ }
+
+@@ -1049,6 +1076,7 @@ class EventServiceManager
+
+ std::vector<std::string> getAllIDs()
+ {
++ deleteTerminatedSubcriptions();
+ std::vector<std::string> idList;
+ for (const auto& it : subscriptionsMap)
+ {
+@@ -1059,6 +1087,7 @@ class EventServiceManager
+
+ bool isDestinationExist(const std::string& destUrl)
+ {
++ deleteTerminatedSubcriptions();
+ for (const auto& it : subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1073,6 +1102,7 @@ class EventServiceManager
+
+ void sendTestEventLog()
+ {
++ deleteTerminatedSubcriptions();
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1100,6 +1130,8 @@ class EventServiceManager
+ }
+ eventRecord.push_back(eventMessage);
+
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1143,6 +1175,8 @@ class EventServiceManager
+ }
+ void sendBroadcastMsg(const std::string& broadcastMsg)
+ {
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1291,6 +1325,8 @@ class EventServiceManager
+ return;
+ }
+
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch
new file mode 100644
index 000000000..585f7bf09
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch
@@ -0,0 +1,141 @@
+From 5b87bb61b58e92a8c5af37a7959347747409a65c Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Thu, 14 Oct 2021 02:56:11 +0530
+Subject: [PATCH] Fix bmcweb crash while deleting terminated subscriptions
+
+This commit fixes bmcweb crash while deleting the terminated
+subscriptions. In the earlier implementation, detection of subscription
+to be deleted and the deletion(erase) was happening in the same loop.
+Due to this, if the Subscription to be deleted is the last one in the
+list, the loop will enter into infinite loop. The fix is to keep the
+detection and deletion loop separate.
+Also, this commit adds code to :
+ - Delete from persistent storage
+ - Add journal entry for deleted entry
+ - update number of subcribers and update persistent storage.
+
+Apart from this, this commit also moves the retry timer check to the top
+to avoid multiple calls to close when the retry count is 3 and timer is
+running.
+
+Tested:
+ - Checked journal logs to confirm each retry is actually spanned to be
+ 30 secs
+ - Verified Journal entry for deleted subscription after retires.
+ - Verified Event service functionality by making three subscriptions:
+ retry for ever, terminate after retires and suspend after retries.
+
+Change-Id: I425a6c749923ce86c457a36394deb0fbbee232db
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_client.hpp | 11 ++--
+ .../include/event_service_manager.hpp | 59 ++++++++++++++++---
+ 2 files changed, 58 insertions(+), 12 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index 54ae2c3..162cb09 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -367,6 +367,12 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void waitAndRetry()
+ {
++ if (runningTimer)
++ {
++ BMCWEB_LOG_DEBUG << "Retry timer is already running.";
++ return;
++ }
++
+ if (retryCount >= maxRetryAttempts)
+ {
+ BMCWEB_LOG_ERROR << "Maximum number of retries reached.";
+@@ -393,11 +399,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ return;
+ }
+
+- if (runningTimer)
+- {
+- BMCWEB_LOG_DEBUG << "Retry timer is already running.";
+- return;
+- }
+ runningTimer = true;
+
+ retryCount++;
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 363adb0..7af7a4d 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -857,18 +857,63 @@ class EventServiceManager
+
+ void deleteTerminatedSubcriptions()
+ {
+- boost::container::flat_map<std::string,
+- std::shared_ptr<Subscription>>::iterator it =
+- subscriptionsMap.begin();
+- while (it != subscriptionsMap.end())
++ BMCWEB_LOG_ERROR << "Map size Before Delete : "
++ << subscriptionsMap.size();
++
++ std::vector<std::string> deleteIds;
++
++ // Determine Subscription ID's to be deleted.
++ for (const auto& it : subscriptionsMap)
+ {
+- std::shared_ptr<Subscription> entry = it->second;
++ std::shared_ptr<Subscription> entry = it.second;
+ if (entry->isTerminated())
+ {
+- subscriptionsMap.erase(it);
++ deleteIds.emplace_back(it.first);
++ }
++ }
++
++ // Delete the Terminated Subcriptions
++ for (std::string& id : deleteIds)
++ {
++ auto map1 = subscriptionsMap.find(id);
++ if (map1 != subscriptionsMap.end())
++ {
++ subscriptionsMap.erase(map1);
++ auto map2 = persistent_data::EventServiceStore::getInstance()
++ .subscriptionsConfigMap.find(id);
++ if (map2 != persistent_data::EventServiceStore::getInstance()
++ .subscriptionsConfigMap.end())
++ {
++ persistent_data::EventServiceStore::getInstance()
++ .subscriptionsConfigMap.erase(map2);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Couldn't find ID: " << id
++ << " in subscriptionsConfigMap";
++ }
++
++ /* Log event for subscription delete. */
++ sd_journal_send("MESSAGE=Event subscription removed.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionRemoved",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Couldn't find ID: " << id
++ << " in subscriptionsMap";
+ }
+- it++;
+ }
++ if (deleteIds.size())
++ {
++ updateNoOfSubscribersCount();
++ persistSubscriptionData();
++ }
++
++ BMCWEB_LOG_ERROR << "Map size After Delete : "
++ << subscriptionsMap.size();
+ }
+
+ void updateNoOfSubscribersCount()
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README
new file mode 100644
index 000000000..c09967456
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README
@@ -0,0 +1,34 @@
+Eventservice specific patches: Temporary pulling down
+the upstream patches. These will be remove as soon as
+thee gets merged upstream.
+
+Upstream revision information:
+ - EventService : Add unmerged changes for http retry support (Downstream patch)
+ file://eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch
+
+ - EventService: https client support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31735/40 (Rebased on latest bmcweb)
+
+ - Add Server-Sent-Events support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41258/9
+
+ - Add SSE style subscription support to eventservice
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41319/10
+
+ - Add EventService SSE filter support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41349/7 (Modified boost::urls::query_params_view to boost::urls::url_view::params_type)
+
+ - EventService Log events for subscription actions (Downstream patch)
+ file://eventservice/0007-EventService-Log-events-for-subscription-actions.patch
+
+ - Add checks on Event-Subscription input parameters (Downstream patch)
+ file://eventservice//0008-Add-checks-on-Event-Subscription-input-parameters.patch
+
+ - Restructure Redifsh EventLog Transmit code flow
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44449/3
+
+ - Remove Terminated Event Subscriptions (Downstream patch)
+ file://eventservice/0010-Remove-Terminated-Event-Subscriptions.patch
+
+ - Fix bmcweb crash while deleting terminated subscriptions (Downstream patch)
+ file://eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch
new file mode 100644
index 000000000..b3aa11774
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch
@@ -0,0 +1,202 @@
+From f2c3271c8eb405a05a3ec383791e1adc3c4a7f86 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:45:37 +0530
+Subject: [PATCH] Add asyncResp support during handleUpgrade
+
+The current implementation uses the earlier method of using the response
+object and calling response.end() to initiate completion handler.
+This commit modifies the implementation to use asyncResp, where the
+completion handler gets called asynchronously as the response object
+goes out of scope.
+
+Tested :
+ - websocket_test.py Passed
+ - KVM was functional in WebUI.
+ - POST to /redfish/v1/EventService/Subscriptions/SSE returned an error
+ message as expected and the connection was kept alive.
+ - GET on /redfish/v1/EventService/Subscriptions/SSE (SSE subscription)
+ was successful. The existing connection was successfully closed and
+ upgraded to SSE connection.
+
+Change-Id: I2d76b34a49a6432c507d939b21b37c1ced761f8e
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/app.hpp | 6 ++++--
+ http/http_connection.hpp | 30 +++++++++++++++++++++++++-----
+ http/routing.hpp | 37 +++++++++++++++++++++----------------
+ 3 files changed, 50 insertions(+), 23 deletions(-)
+
+diff --git a/http/app.hpp b/http/app.hpp
+index 4735197..c46dcf7 100644
+--- a/http/app.hpp
++++ b/http/app.hpp
+@@ -45,9 +45,11 @@ class App
+ }
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
++ void handleUpgrade(const Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ Adaptor&& adaptor)
+ {
+- router.handleUpgrade(req, res, std::move(adaptor));
++ router.handleUpgrade(req, asyncResp, std::move(adaptor));
+ }
+
+ void handle(Request& req,
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index 9d53c17..cdd3707 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -361,6 +361,7 @@ class Connection :
+ boost::asio::post(self->adaptor.get_executor(),
+ [self] { self->completeRequest(); });
+ });
++ auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
+
+ if ((thisReq.isUpgrade() &&
+ boost::iequals(
+@@ -369,13 +370,32 @@ class Connection :
+ (req->url == "/redfish/v1/EventService/Subscriptions/SSE"))
+ {
+ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded";
+- handler->handleUpgrade(thisReq, res, std::move(adaptor));
+- // delete lambda with self shared_ptr
+- // to enable connection destruction
+- res.setCompleteRequestHandler(nullptr);
++ res.setCompleteRequestHandler([self(shared_from_this())] {
++ if (self->res.resultInt() != 200)
++ {
++ // When any error occurs during handle upgradation,
++ // the result in response will be set to respective
++ // error. By default the Result will be OK (200),
++ // which implies successful handle upgrade. Response
++ // needs to be sent over this connection only on
++ // failure.
++ boost::asio::post(self->adaptor.get_executor(),
++ [self] { self->completeRequest(); });
++ }
++ else
++ {
++ // Set Complete request handler to NULL to remove
++ // the shared pointer of connection to enable
++ // connection destruction. As the connection would
++ // get upgraded, we wouldn't need this connection
++ // any longer
++ self->res.setCompleteRequestHandler(nullptr);
++ }
++ });
++ handler->handleUpgrade(thisReq, asyncResp, std::move(adaptor));
+ return;
+ }
+- auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
++
+ handler->handle(thisReq, asyncResp);
+ }
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 25e4ce8..858f146 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -1202,12 +1202,13 @@ class Router
+ }
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
++ void handleUpgrade(const Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ Adaptor&& adaptor)
+ {
+ if (static_cast<size_t>(req.method()) >= perMethods.size())
+ {
+- res.result(boost::beast::http::status::not_found);
+- res.end();
++ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+@@ -1220,8 +1221,7 @@ class Router
+ if (!ruleIndex)
+ {
+ BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
+- res.result(boost::beast::http::status::not_found);
+- res.end();
++ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+@@ -1234,23 +1234,24 @@ class Router
+ {
+ BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
+ << req.url;
+- res.result(boost::beast::http::status::moved_permanently);
++ asyncResp->res.result(
++ boost::beast::http::status::moved_permanently);
+
+ // TODO absolute url building
+ if (req.getHeaderValue("Host").empty())
+ {
+- res.addHeader("Location", std::string(req.url) + "/");
++ asyncResp->res.addHeader("Location",
++ std::string(req.url) + "/");
+ }
+ else
+ {
+- res.addHeader(
++ asyncResp->res.addHeader(
+ "Location",
+ req.isSecure
+ ? "https://"
+ : "http://" + std::string(req.getHeaderValue("Host")) +
+ std::string(req.url) + "/");
+ }
+- res.end();
+ return;
+ }
+
+@@ -1261,8 +1262,7 @@ class Router
+ << " with " << req.methodString() << "("
+ << static_cast<uint32_t>(req.method()) << ") / "
+ << rules[ruleIndex]->getMethods();
+- res.result(boost::beast::http::status::not_found);
+- res.end();
++ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+@@ -1273,13 +1273,18 @@ class Router
+ // any uncaught exceptions become 500s
+ try
+ {
+- rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
++ // Creating temporary response object to call handleUpgrade
++ // We cannot pass the asyncResp as it will be destroyed
++ // The response object is not initialized as handleUpgrade wouldn't
++ // be using this object
++ crow::Response resp;
++ rules[ruleIndex]->handleUpgrade(req, resp, std::move(adaptor));
+ }
+ catch (std::exception& e)
+ {
+ BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+- res.result(boost::beast::http::status::internal_server_error);
+- res.end();
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ catch (...)
+@@ -1287,8 +1292,8 @@ class Router
+ BMCWEB_LOG_ERROR
+ << "An uncaught exception occurred. The type was unknown "
+ "so no information was available.";
+- res.result(boost::beast::http::status::internal_server_error);
+- res.end();
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch
new file mode 100644
index 000000000..1217147b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch
@@ -0,0 +1,109 @@
+From 6483f0af926391e8d1f256ba0f23f3640260cfd1 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:52:17 +0530
+Subject: [PATCH] Move privileges to separate entity
+
+The privilege property of a rule is currently part of RuleParameterTraits
+structure. Moving this property (member function) out into a separate
+entity PrivilegeParameterTraits.
+This move is required to enable inheriting this entity into Weksockets
+and SseSockets.
+
+Tested:
+ - bmcweb is functional and is responding to Redfish URI's
+ - User Privilege check for URI's is functional.
+
+Change-Id: I288ab12258c15ae5a626f4409fc3b4a9cc574ea3
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/routing.hpp | 53 +++++++++++++++++++++++++++---------------------
+ 1 file changed, 30 insertions(+), 23 deletions(-)
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 858f146..acc99dc 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -102,6 +102,8 @@ class BaseRule
+ friend class Router;
+ template <typename T>
+ friend struct RuleParameterTraits;
++ template <typename T>
++ friend struct PrivilegeParameterTraits;
+ };
+
+ namespace detail
+@@ -316,6 +318,33 @@ struct Wrapped
+ } // namespace routing_handler_call_helper
+ } // namespace detail
+
++template <typename T>
++struct PrivilegeParameterTraits
++{
++ using self_t = T;
++ self_t& privileges(
++ const std::initializer_list<std::initializer_list<const char*>>& p)
++ {
++ self_t* self = static_cast<self_t*>(this);
++ for (const std::initializer_list<const char*>& privilege : p)
++ {
++ self->privilegesSet.emplace_back(privilege);
++ }
++ return *self;
++ }
++
++ template <size_t N, typename... MethodArgs>
++ self_t& privileges(const std::array<redfish::Privileges, N>& p)
++ {
++ self_t* self = static_cast<self_t*>(this);
++ for (const redfish::Privileges& privilege : p)
++ {
++ self->privilegesSet.emplace_back(privilege);
++ }
++ return *self;
++ }
++};
++
+ class WebSocketRule : public BaseRule
+ {
+ using self_t = WebSocketRule;
+@@ -462,7 +491,7 @@ class SseSocketRule : public BaseRule
+ };
+
+ template <typename T>
+-struct RuleParameterTraits
++struct RuleParameterTraits : public PrivilegeParameterTraits<T>
+ {
+ using self_t = T;
+ WebSocketRule& websocket()
+@@ -503,28 +532,6 @@ struct RuleParameterTraits
+ self->methodsBitfield |= 1U << static_cast<size_t>(method);
+ return *self;
+ }
+-
+- self_t& privileges(
+- const std::initializer_list<std::initializer_list<const char*>>& p)
+- {
+- self_t* self = static_cast<self_t*>(this);
+- for (const std::initializer_list<const char*>& privilege : p)
+- {
+- self->privilegesSet.emplace_back(privilege);
+- }
+- return *self;
+- }
+-
+- template <size_t N, typename... MethodArgs>
+- self_t& privileges(const std::array<redfish::Privileges, N>& p)
+- {
+- self_t* self = static_cast<self_t*>(this);
+- for (const redfish::Privileges& privilege : p)
+- {
+- self->privilegesSet.emplace_back(privilege);
+- }
+- return *self;
+- }
+ };
+
+ class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch
new file mode 100644
index 000000000..1ba584616
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch
@@ -0,0 +1,218 @@
+From aabe4718b8e6c1f7b91af29cbaf85d5fa1fa0a99 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:55:38 +0530
+Subject: [PATCH] Add Support for privilege check in handleUpgrade
+
+This commit enables privilege check for user(s) in case of upgraded
+connections.
+Currently users with no privileges will also be able to access
+Websockets connections (Ex: KVM).
+
+Tested:
+ - websocket_test.py Passed
+ - Admin and Operator users were able to access KVM on WebUI
+ - Readonly User was unable to access KVM on WebUI
+
+Change-Id: Id9d33aeca24d8fafb2e9dcc28c46a48930740cd6
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/app.hpp | 2 +-
+ http/routing.hpp | 162 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 136 insertions(+), 28 deletions(-)
+
+diff --git a/http/app.hpp b/http/app.hpp
+index c46dcf7..dd51eee 100644
+--- a/http/app.hpp
++++ b/http/app.hpp
+@@ -45,7 +45,7 @@ class App
+ }
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req,
++ void handleUpgrade(Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ Adaptor&& adaptor)
+ {
+diff --git a/http/routing.hpp b/http/routing.hpp
+index acc99dc..e2a8fbb 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -1209,7 +1209,7 @@ class Router
+ }
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req,
++ void handleUpgrade(Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ Adaptor&& adaptor)
+ {
+@@ -1277,32 +1277,140 @@ class Router
+ << "' " << static_cast<uint32_t>(req.method()) << " / "
+ << rules[ruleIndex]->getMethods();
+
+- // any uncaught exceptions become 500s
+- try
+- {
+- // Creating temporary response object to call handleUpgrade
+- // We cannot pass the asyncResp as it will be destroyed
+- // The response object is not initialized as handleUpgrade wouldn't
+- // be using this object
+- crow::Response resp;
+- rules[ruleIndex]->handleUpgrade(req, resp, std::move(adaptor));
+- }
+- catch (std::exception& e)
+- {
+- BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+- asyncResp->res.result(
+- boost::beast::http::status::internal_server_error);
+- return;
+- }
+- catch (...)
+- {
+- BMCWEB_LOG_ERROR
+- << "An uncaught exception occurred. The type was unknown "
+- "so no information was available.";
+- asyncResp->res.result(
+- boost::beast::http::status::internal_server_error);
+- return;
+- }
++ crow::connections::systemBus->async_method_call(
++ [&req, asyncResp, &rules, ruleIndex, &adaptor](
++ const boost::system::error_code ec,
++ std::map<std::string, std::variant<bool, std::string,
++ std::vector<std::string>>>
++ userInfo) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "GetUserInfo failed...";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++
++ const std::string* userRolePtr = nullptr;
++ auto userInfoIter = userInfo.find("UserPrivilege");
++ if (userInfoIter != userInfo.end())
++ {
++ userRolePtr =
++ std::get_if<std::string>(&userInfoIter->second);
++ }
++
++ std::string userRole{};
++ if (userRolePtr != nullptr)
++ {
++ userRole = *userRolePtr;
++ BMCWEB_LOG_DEBUG << "userName = " << req.session->username
++ << " userRole = " << *userRolePtr;
++ }
++
++ bool* remoteUserPtr = nullptr;
++ auto remoteUserIter = userInfo.find("RemoteUser");
++ if (remoteUserIter != userInfo.end())
++ {
++ remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
++ }
++ if (remoteUserPtr == nullptr)
++ {
++ BMCWEB_LOG_ERROR
++ << "RemoteUser property missing or wrong type";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ bool remoteUser = *remoteUserPtr;
++
++ bool passwordExpired = false; // default for remote user
++ if (!remoteUser)
++ {
++ bool* passwordExpiredPtr = nullptr;
++ auto passwordExpiredIter =
++ userInfo.find("UserPasswordExpired");
++ if (passwordExpiredIter != userInfo.end())
++ {
++ passwordExpiredPtr =
++ std::get_if<bool>(&passwordExpiredIter->second);
++ }
++ if (passwordExpiredPtr != nullptr)
++ {
++ passwordExpired = *passwordExpiredPtr;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "UserPasswordExpired property is expected for"
++ " local user but is missing or wrong type";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ }
++
++ // Get the userprivileges from the role
++ redfish::Privileges userPrivileges =
++ redfish::getUserPrivileges(userRole);
++
++ // Set isConfigureSelfOnly based on D-Bus results. This
++ // ignores the results from both pamAuthenticateUser and the
++ // value from any previous use of this session.
++ req.session->isConfigureSelfOnly = passwordExpired;
++
++ // Modifyprivileges if isConfigureSelfOnly.
++ if (req.session->isConfigureSelfOnly)
++ {
++ // Remove allprivileges except ConfigureSelf
++ userPrivileges = userPrivileges.intersection(
++ redfish::Privileges{"ConfigureSelf"});
++ BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
++ }
++
++ if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
++ {
++ asyncResp->res.result(
++ boost::beast::http::status::forbidden);
++ if (req.session->isConfigureSelfOnly)
++ {
++ redfish::messages::passwordChangeRequired(
++ asyncResp->res,
++ "/redfish/v1/AccountService/Accounts/" +
++ req.session->username);
++ }
++ return;
++ }
++
++ req.userRole = userRole;
++
++ // any uncaught exceptions become 500s
++ try
++ {
++ crow::Response resp;
++ rules[ruleIndex]->handleUpgrade(req, resp,
++ std::move(adaptor));
++ }
++ catch (std::exception& e)
++ {
++ BMCWEB_LOG_ERROR << "An uncaught exception occurred: "
++ << e.what();
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ catch (...)
++ {
++ BMCWEB_LOG_ERROR
++ << "An uncaught exception occurred. The type was "
++ "unknown so no information was available.";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ },
++ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
++ "xyz.openbmc_project.User.Manager", "GetUserInfo",
++ req.session->username);
+ }
+
+ void handle(Request& req,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch
new file mode 100644
index 000000000..64e235ce3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch
@@ -0,0 +1,140 @@
+From 9b27d3e7c1670d53cfb1c0a88cc75155ebfba71a Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:58:29 +0530
+Subject: [PATCH] Add Privileges to Websockets
+
+This commit adds Privileges to Websockets.
+In the current implementation, once a rule is upgraded (i.e. from
+BaseRule to WebSocket), there is no provosion to add priviliges.
+In this commit, WebSocket inherits PrivilegeParameterTraits to enable
+privileges.
+
+Also, in the earlier implementation, .privilege() was called after
+BMCWEB_ROUTE(). This results in adding those privileges to the Base rule
+that is created. By moving the privileges() below websocket(), the
+privileges are applied to the websocket.
+
+Tested:
+ - websocket_test.py Passed
+ - Admin and Operator users were able to access KVM on WebUI
+ - Readonly User was unable to access KVM on WebUI
+
+Change-Id: Iff2051dbb7d363c902fd463fa446f280adc6d648
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/routing.hpp | 4 +++-
+ include/dbus_monitor.hpp | 3 ++-
+ include/kvm_websocket.hpp | 4 +++-
+ include/obmc_console.hpp | 4 +++-
+ include/vm_websocket.hpp | 4 +++-
+ 5 files changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index e2a8fbb..6ea3185 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -345,7 +345,9 @@ struct PrivilegeParameterTraits
+ }
+ };
+
+-class WebSocketRule : public BaseRule
++class WebSocketRule :
++ public BaseRule,
++ public PrivilegeParameterTraits<WebSocketRule>
+ {
+ using self_t = WebSocketRule;
+
+diff --git a/include/dbus_monitor.hpp b/include/dbus_monitor.hpp
+index a6c86c6..163f884 100644
+--- a/include/dbus_monitor.hpp
++++ b/include/dbus_monitor.hpp
+@@ -5,6 +5,7 @@
+ #include <boost/container/flat_set.hpp>
+ #include <dbus_singleton.hpp>
+ #include <openbmc_dbus_rest.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <sdbusplus/bus/match.hpp>
+ #include <sdbusplus/message/types.hpp>
+ #include <websocket.hpp>
+@@ -105,8 +106,8 @@ inline int onPropertyUpdate(sd_bus_message* m, void* userdata,
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/subscribe")
+- .privileges({{"Login"}})
+ .websocket()
++ .privileges(redfish::privileges::privilegeSetLogin)
+ .onopen([&](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+diff --git a/include/kvm_websocket.hpp b/include/kvm_websocket.hpp
+index a9dc8ea..3f124a2 100644
+--- a/include/kvm_websocket.hpp
++++ b/include/kvm_websocket.hpp
+@@ -4,6 +4,7 @@
+ #include <app.hpp>
+ #include <async_resp.hpp>
+ #include <boost/container/flat_map.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <websocket.hpp>
+
+ namespace crow
+@@ -159,8 +160,9 @@ inline void requestRoutes(App& app)
+ sessions.reserve(maxSessions);
+
+ BMCWEB_ROUTE(app, "/kvm/0")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .websocket()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+diff --git a/include/obmc_console.hpp b/include/obmc_console.hpp
+index ff0a51f..22a49a8 100644
+--- a/include/obmc_console.hpp
++++ b/include/obmc_console.hpp
+@@ -6,6 +6,7 @@
+ #include <boost/asio/local/stream_protocol.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <boost/container/flat_set.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <websocket.hpp>
+
+ namespace crow
+@@ -136,8 +137,9 @@ inline void connectHandler(const boost::system::error_code& ec)
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/console0")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .websocket()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+diff --git a/include/vm_websocket.hpp b/include/vm_websocket.hpp
+index 02f958a..ebbe68f 100644
+--- a/include/vm_websocket.hpp
++++ b/include/vm_websocket.hpp
+@@ -3,6 +3,7 @@
+ #include <app.hpp>
+ #include <boost/beast/core/flat_static_buffer.hpp>
+ #include <boost/process.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <websocket.hpp>
+
+ #include <csignal>
+@@ -156,8 +157,9 @@ static std::shared_ptr<Handler> handler;
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/vm/0/0")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .websocket()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch
new file mode 100644
index 000000000..06ffb3a46
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch
@@ -0,0 +1,63 @@
+From 0ceb343809ff498cbfa389c54a158d255a2cca88 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 23:02:00 +0530
+Subject: [PATCH] Add Privileges to SseSockets
+
+This commit adds Privileges to Ssesockets.
+In the current implementation, once a rule is upgraded (i.e. from
+BaseRule to SseSocket), there is no provision to add priviliges.
+In this commit, SseSocket inherits PrivilegeParameterTraits to
+enable privileges.
+
+Also, in the earlier implementation, .privilege() was called after
+BMCWEB_ROUTE(). This results in adding those privileges to the Base
+rule that is created. By moving the privileges() below websocket(),
+the privileges are applied to the Ssesocket.
+
+Tested:
+ - SSE Subscription was successful with Admin and Operator Users
+ - SSE Subscription was rejected while using Readonly User
+ - websocket_test.py Passed
+ - Admin and Operator users were able to access KVM on WebUI
+ - Readonly User was unable to access KVM on WebUI
+
+Change-Id: I41739401893b1c2bf718e11ec7676d69f954c98f
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/routing.hpp | 4 +++-
+ include/eventservice_sse.hpp | 3 ++-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 6ea3185..13174b2 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -430,7 +430,9 @@ class WebSocketRule :
+ std::function<void(crow::websocket::Connection&)> errorHandler;
+ };
+
+-class SseSocketRule : public BaseRule
++class SseSocketRule :
++ public BaseRule,
++ public PrivilegeParameterTraits<SseSocketRule>
+ {
+ using self_t = SseSocketRule;
+
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+index 2f22f98..f880344 100644
+--- a/include/eventservice_sse.hpp
++++ b/include/eventservice_sse.hpp
+@@ -192,8 +192,9 @@ static void deleteSubscription(std::shared_ptr<crow::SseConnection>& conn)
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/SSE")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .serverSentEvent()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](std::shared_ptr<crow::SseConnection>& conn,
+ const crow::Request& req, crow::Response& res) {
+ BMCWEB_LOG_DEBUG << "Connection " << conn << " opened.";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch
new file mode 100644
index 000000000..f5226fe6e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch
@@ -0,0 +1,619 @@
+From 32e557279450226ed9c06312649d90b802f3d4c5 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 13 Apr 2021 13:00:18 +0000
+Subject: [PATCH] Add support for MetricDefinition scheme
+
+Added MetricDefinition node to Redfish code. Now user is able to list
+all available metrics in OpenBMC that are supported by Telemetry
+service. Metrics are grouped by reading type.
+
+MetricDefinitions contains all physical sensors supported by redfish,
+algorithm iterates through all chassis and collects results for each
+node available in that chassis (Power, Thermal, Sensors).
+
+When BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM will be enabled by
+default (meson option redfish-new-powersubsystem-thermalsubsystem) it
+will be possible to optimize this algorithm to only get sensors from
+Sensors node. Currently Sensors node doesn't contain all available
+sensors.
+
+Tested:
+ - MetricDefinitions response is filled with existing sensors, it works
+ with and without Telemetry service
+ - Validated a presence of MetricDefinition members and its attributes
+ - Successfully passed RedfishServiceValidator.py using witherspoon
+ image on QEMU
+ - Tested using following GET,POST requests
+
+GET /redfish/v1/TelemetryService/MetricDefinitions
+{
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions",
+ "@odata.type": "#MetricDefinitionCollection.MetricDefinitionCollection",
+ "Members": [
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Fan_Pwm"
+ },
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Fan_Tach"
+ },
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/HostCpuUtilization"
+ },
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/HostMemoryBandwidthUtilization"
+ },
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/HostPciBandwidthUtilization"
+ },
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Inlet_BRD_Temp"
+ },
+ {
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Left_Rear_Board_Temp"
+ }
+ ],
+ "Members@odata.count": 7,
+ "Name": "Metric Definition Collection"
+}
+
+GET /redfish/v1/TelemetryService/MetricDefinitions/Fan_Tach
+{
+ "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Fan_Tach",
+ "@odata.type": "#MetricDefinition.v1_0_3.MetricDefinition",
+ "Id": "Fan_Tach",
+ "IsLinear": true,
+ "MaxReadingRange": 25000.0,
+ "MetricDataType": "Decimal",
+ "MetricProperties": [
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/0/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/1/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/2/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/3/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/4/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/5/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/6/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/7/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/8/Reading",
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/9/Reading"
+ ],
+ "MetricType": "Gauge",
+ "MinReadingRange": 0.0,
+ "Name": "Fan_Tach",
+ "Units": "RPM"
+}
+
+POST redfish/v1/TelemetryService/MetricReportDefinitions, body:
+{
+ "Id": "TestReport",
+ "Metrics": [
+ {
+ "MetricId": "TestMetric",
+ "MetricProperties": [
+ "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/3/Reading",
+ ]
+ }
+ ],
+ "MetricReportDefinitionType": "OnRequest",
+ "ReportActions": [
+ "RedfishEvent",
+ "LogToMetricReportsCollection"
+ ]
+}
+{
+ "@Message.ExtendedInfo": [
+ {
+ "@odata.type": "#Message.v1_1_1.Message",
+ "Message": "The resource has been created successfully",
+ "MessageArgs": [],
+ "MessageId": "Base.1.8.1.Created",
+ "MessageSeverity": "OK",
+ "Resolution": "None"
+ }
+ ]
+}
+
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00
+---
+ redfish-core/include/redfish.hpp | 3 +
+ .../include/utils/get_chassis_names.hpp | 58 +++
+ .../include/utils/telemetry_utils.hpp | 2 +
+ redfish-core/lib/metric_definition.hpp | 368 ++++++++++++++++++
+ redfish-core/lib/telemetry_service.hpp | 3 +-
+ 5 files changed, 433 insertions(+), 1 deletion(-)
+ create mode 100644 redfish-core/include/utils/get_chassis_names.hpp
+ create mode 100644 redfish-core/lib/metric_definition.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 0a97150..67c5af2 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -26,6 +26,7 @@
+ #include "../lib/managers.hpp"
+ #include "../lib/memory.hpp"
+ #include "../lib/message_registries.hpp"
++#include "../lib/metric_definition.hpp"
+ #include "../lib/metric_report.hpp"
+ #include "../lib/metric_report_definition.hpp"
+ #include "../lib/network_protocol.hpp"
+@@ -200,6 +201,8 @@ class RedfishService
+ requestRoutesMetricReportDefinition(app);
+ requestRoutesMetricReportCollection(app);
+ requestRoutesMetricReport(app);
++ requestRoutesMetricDefinitionCollection(app);
++ requestRoutesMetricDefinition(app);
+ }
+ };
+
+diff --git a/redfish-core/include/utils/get_chassis_names.hpp b/redfish-core/include/utils/get_chassis_names.hpp
+new file mode 100644
+index 0000000..0276b6f
+--- /dev/null
++++ b/redfish-core/include/utils/get_chassis_names.hpp
+@@ -0,0 +1,58 @@
++#pragma once
++
++#include <include/dbus_singleton.hpp>
++
++#include <array>
++#include <string>
++#include <vector>
++
++namespace redfish
++{
++
++namespace utils
++{
++
++template <typename F>
++inline void getChassisNames(F&& cb)
++{
++ const std::array<const char*, 2> interfaces = {
++ "xyz.openbmc_project.Inventory.Item.Board",
++ "xyz.openbmc_project.Inventory.Item.Chassis"};
++
++ crow::connections::systemBus->async_method_call(
++ [callback = std::move(cb)](const boost::system::error_code ec,
++ const std::vector<std::string>& chassis) {
++ std::vector<std::string> chassisNames;
++
++ if (ec)
++ {
++ callback(ec, chassisNames);
++ return;
++ }
++
++ chassisNames.reserve(chassis.size());
++ for (const std::string& path : chassis)
++ {
++ sdbusplus::message::object_path dbusPath = path;
++ std::string name = dbusPath.filename();
++ if (name.empty())
++ {
++ callback(boost::system::errc::make_error_code(
++ boost::system::errc::invalid_argument),
++ chassisNames);
++ return;
++ }
++ chassisNames.emplace_back(std::move(name));
++ }
++
++ callback(ec, chassisNames);
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
++ "/xyz/openbmc_project/inventory", 0, interfaces);
++}
++
++} // namespace utils
++
++} // namespace redfish
+diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
+index 5872350..1b4f75d 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -10,6 +10,8 @@ namespace telemetry
+
+ constexpr const char* service = "xyz.openbmc_project.Telemetry";
+ constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report";
++constexpr const char* metricDefinitionUri =
++ "/redfish/v1/TelemetryService/MetricDefinitions/";
+ constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
+ constexpr const char* metricReportUri =
+diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp
+new file mode 100644
+index 0000000..347c297
+--- /dev/null
++++ b/redfish-core/lib/metric_definition.hpp
+@@ -0,0 +1,368 @@
++#pragma once
++
++#include "async_resp.hpp"
++#include "sensors.hpp"
++#include "utils/get_chassis_names.hpp"
++#include "utils/telemetry_utils.hpp"
++
++#include <registries/privilege_registry.hpp>
++
++namespace redfish
++{
++
++namespace telemetry
++{
++
++struct ValueVisitor
++{
++ ValueVisitor(boost::system::error_code& ec) : ec(ec)
++ {}
++
++ template <class T>
++ double operator()(T value) const
++ {
++ return static_cast<double>(value);
++ }
++
++ double operator()(std::monostate) const
++ {
++ ec = boost::system::errc::make_error_code(
++ boost::system::errc::invalid_argument);
++ return double{};
++ }
++
++ boost::system::error_code& ec;
++};
++
++inline void getReadingRange(
++ const std::string& service, const std::string& path,
++ const std::string& property,
++ std::function<void(boost::system::error_code, double)> callback)
++{
++ crow::connections::systemBus->async_method_call(
++ [callback = std::move(callback)](
++ boost::system::error_code ec,
++ const std::variant<std::monostate, double, uint64_t, int64_t,
++ uint32_t, int32_t, uint16_t, int16_t>&
++ valueVariant) {
++ if (ec)
++ {
++ callback(ec, double{});
++ return;
++ }
++
++ const double value = std::visit(ValueVisitor(ec), valueVariant);
++
++ callback(ec, value);
++ },
++ service, path, "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.Sensor.Value", property);
++}
++
++inline void
++ fillMinMaxReadingRange(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::string& serviceName,
++ const std::string& sensorPath)
++{
++ asyncResp->res.jsonValue["MetricType"] = "Numeric";
++
++ telemetry::getReadingRange(
++ serviceName, sensorPath, "MinValue",
++ [asyncResp](boost::system::error_code ec, double readingRange) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ if (std::isfinite(readingRange))
++ {
++ asyncResp->res.jsonValue["MetricType"] = "Gauge";
++
++ asyncResp->res.jsonValue["MinReadingRange"] = readingRange;
++ }
++ });
++
++ telemetry::getReadingRange(
++ serviceName, sensorPath, "MaxValue",
++ [asyncResp](boost::system::error_code ec, double readingRange) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ if (std::isfinite(readingRange))
++ {
++ asyncResp->res.jsonValue["MetricType"] = "Gauge";
++
++ asyncResp->res.jsonValue["MaxReadingRange"] = readingRange;
++ }
++ });
++}
++
++inline void getSensorService(
++ const std::string& sensorPath,
++ std::function<void(boost::system::error_code, const std::string&)> callback)
++{
++ using ResultType = std::pair<
++ std::string,
++ std::vector<std::pair<std::string, std::vector<std::string>>>>;
++
++ crow::connections::systemBus->async_method_call(
++ [sensorPath, callback = std::move(callback)](
++ boost::system::error_code ec,
++ const std::vector<ResultType>& result) {
++ if (ec)
++ {
++ callback(ec, std::string{});
++ return;
++ }
++
++ for (const auto& [path, serviceToInterfaces] : result)
++ {
++ if (path == sensorPath)
++ {
++ for (const auto& [service, interfaces] :
++ serviceToInterfaces)
++ {
++ callback(boost::system::errc::make_error_code(
++ boost::system::errc::success),
++ service);
++ return;
++ }
++ }
++ }
++
++ callback(boost::system::errc::make_error_code(
++ boost::system::errc::no_such_file_or_directory),
++ std::string{});
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
++ "/xyz/openbmc_project/sensors", 2,
++ std::array{"xyz.openbmc_project.Sensor.Value"});
++}
++
++constexpr auto metricDefinitionMapping = std::array{
++ std::pair{"fan_pwm", "Fan_Pwm"}, std::pair{"fan_tach", "Fan_Tach"}};
++
++std::string mapSensorToMetricDefinition(const std::string& sensorPath)
++{
++ sdbusplus::message::object_path sensorObjectPath{sensorPath};
++
++ const auto it = std::find_if(
++ metricDefinitionMapping.begin(), metricDefinitionMapping.end(),
++ [&sensorObjectPath](const auto& item) {
++ return item.first == sensorObjectPath.parent_path().filename();
++ });
++
++ const char* metricDefinitionPath =
++ "/redfish/v1/TelemetryService/MetricDefinitions/";
++
++ if (it != metricDefinitionMapping.end())
++ {
++ return std::string{metricDefinitionPath} + it->second;
++ }
++
++ return metricDefinitionPath + sensorObjectPath.filename();
++}
++
++template <class Callback>
++inline void mapRedfishUriToDbusPath(Callback&& callback)
++{
++ utils::getChassisNames([callback = std::move(callback)](
++ boost::system::error_code ec,
++ const std::vector<std::string>& chassisNames) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value();
++ callback(ec, {});
++ return;
++ }
++
++ auto counter = std::make_shared<std::pair<
++ boost::container::flat_map<std::string, std::string>, size_t>>();
++
++ auto handleRetrieveUriToDbusMap =
++ [counter, callback = std::move(callback)](
++ const boost::beast::http::status status,
++ const boost::container::flat_map<std::string, std::string>&
++ uriToDbus) {
++ if (status != boost::beast::http::status::ok)
++ {
++ BMCWEB_LOG_ERROR << "Failed to retrieve URI to dbus "
++ "sensors map with err "
++ << static_cast<unsigned>(status);
++ counter->second = 0u;
++ callback(boost::system::errc::make_error_code(
++ boost::system::errc::io_error),
++ {});
++ return;
++ }
++
++ for (const auto& [key, value] : uriToDbus)
++ {
++ counter->first[key] = value;
++ }
++
++ if (--counter->second == 0u)
++ {
++ callback(boost::system::errc::make_error_code(
++ boost::system::errc::success),
++ counter->first);
++ }
++ };
++
++ for (const std::string& chassisName : chassisNames)
++ {
++ for (const auto& [sensorNode, dbusPaths] : sensors::dbus::paths)
++ {
++ ++counter->second;
++ retrieveUriToDbusMap(chassisName, sensorNode.data(),
++ handleRetrieveUriToDbusMap);
++ }
++ }
++ });
++}
++
++} // namespace telemetry
++
++inline void requestRoutesMetricDefinitionCollection(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions/")
++ .privileges(privileges::getTelemetryService)
++ .methods(boost::beast::http::verb::get)(
++ [](const crow::Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ telemetry::mapRedfishUriToDbusPath(
++ [asyncResp](boost::system::error_code ec,
++ const boost::container::flat_map<
++ std::string, std::string>& uriToDbus) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_ERROR
++ << "mapRedfishUriToDbusPath error: "
++ << ec.value();
++ return;
++ }
++
++ std::set<std::string> members;
++
++ for (const auto& [uri, dbusPath] : uriToDbus)
++ {
++ members.insert(
++ telemetry::mapSensorToMetricDefinition(
++ dbusPath));
++ }
++
++ for (const std::string& odataId : members)
++ {
++ asyncResp->res.jsonValue["Members"].push_back(
++ {{"@odata.id", odataId}});
++ }
++
++ asyncResp->res.jsonValue["Members@odata.count"] =
++ asyncResp->res.jsonValue["Members"].size();
++ });
++
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#MetricDefinitionCollection."
++ "MetricDefinitionCollection";
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
++ asyncResp->res.jsonValue["Name"] =
++ "Metric Definition Collection";
++ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
++ asyncResp->res.jsonValue["Members@odata.count"] = 0;
++ });
++}
++
++inline void requestRoutesMetricDefinition(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions/<str>/")
++ .privileges(privileges::getTelemetryService)
++ .methods(
++ boost::beast::http::verb::get)([](const crow::Request&,
++ const std::shared_ptr<
++ bmcweb::AsyncResp>& asyncResp,
++ const std::string& name) {
++ telemetry::mapRedfishUriToDbusPath(
++ [asyncResp, name](
++ boost::system::error_code ec,
++ const boost::container::flat_map<std::string, std::string>&
++ uriToDbus) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "mapRedfishUriToDbusPath error: "
++ << ec.value();
++ return;
++ }
++
++ std::string odataId = telemetry::metricDefinitionUri + name;
++ boost::container::flat_map<std::string, std::string>
++ matchingUris;
++
++ for (const auto& [uri, dbusPath] : uriToDbus)
++ {
++ if (telemetry::mapSensorToMetricDefinition(dbusPath) ==
++ odataId)
++ {
++ matchingUris.emplace(uri, dbusPath);
++ }
++ }
++
++ if (matchingUris.empty())
++ {
++ messages::resourceNotFound(asyncResp->res,
++ "MetricDefinition", name);
++ return;
++ }
++
++ std::string sensorPath = matchingUris.begin()->second;
++
++ telemetry::getSensorService(
++ sensorPath,
++ [asyncResp, name, odataId = std::move(odataId),
++ sensorPath, matchingUris = std::move(matchingUris)](
++ boost::system::error_code ec,
++ const std::string& serviceName) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "getServiceSensorFailed: "
++ << ec.value();
++ return;
++ }
++
++ asyncResp->res.jsonValue["Id"] = name;
++ asyncResp->res.jsonValue["Name"] = name;
++ asyncResp->res.jsonValue["@odata.id"] = odataId;
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#MetricDefinition.v1_0_3.MetricDefinition";
++ asyncResp->res.jsonValue["MetricDataType"] =
++ "Decimal";
++ asyncResp->res.jsonValue["IsLinear"] = true;
++ asyncResp->res.jsonValue["Units"] =
++ sensors::toReadingUnits(
++ sdbusplus::message::object_path{sensorPath}
++ .parent_path()
++ .filename());
++
++ for (const auto& [uri, dbusPath] : matchingUris)
++ {
++ asyncResp->res.jsonValue["MetricProperties"]
++ .push_back(uri);
++ }
++
++ telemetry::fillMinMaxReadingRange(
++ asyncResp, serviceName, sensorPath);
++ });
++ });
++ });
++}
++
++} // namespace redfish
+diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
+index 8ecc591..027b51b 100644
+--- a/redfish-core/lib/telemetry_service.hpp
++++ b/redfish-core/lib/telemetry_service.hpp
+@@ -18,11 +18,12 @@ inline void handleTelemetryServiceGet(
+ asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/TelemetryService";
+ asyncResp->res.jsonValue["Id"] = "TelemetryService";
+ asyncResp->res.jsonValue["Name"] = "Telemetry Service";
+-
+ asyncResp->res.jsonValue["MetricReportDefinitions"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions";
+ asyncResp->res.jsonValue["MetricReports"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReports";
++ asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec,
+--
+2.25.1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch
new file mode 100644
index 000000000..3088a7f9d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch
@@ -0,0 +1,295 @@
+From 541353a4e4b06de42b6a9a400629f5a5fba04e86 Mon Sep 17 00:00:00 2001
+From: "Wludzik, Jozef" <jozef.wludzik@intel.com>
+Date: Tue, 15 Dec 2020 12:30:31 +0100
+Subject: [PATCH] Sync Telmetry service with EventService
+
+Synced the latest changes in Telemetry service with Event Service
+code. Now assembling MetricReport is covered in single place in
+code. Updated method of fetching Readings from Telemetry by
+Event Service. Using ReportUpdate signal is no longer
+supported. Now Event Service monitors for PropertiesChanged signal
+from /xyz/openbmc_project/Telemetry/Reports path.
+
+Tested:
+ - Verified that EventListener received MetricReport response from
+ Event Service in insecure http push style eventing mode
+
+Change-Id: I2fc1841a6c9259a8bff30b34bddc0d4aabd41912
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+Signed-off-by: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com>
+---
+ .../include/event_service_manager.hpp | 156 ++++++------------
+ redfish-core/lib/metric_report.hpp | 28 ++--
+ 2 files changed, 69 insertions(+), 115 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 3f398d7..cf9f658 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -14,6 +14,7 @@
+ // limitations under the License.
+ */
+ #pragma once
++#include "metric_report.hpp"
+ #include "registries.hpp"
+ #include "registries/base_message_registry.hpp"
+ #include "registries/openbmc_message_registry.hpp"
+@@ -511,47 +512,32 @@ class Subscription : public persistent_data::UserSubscription
+ }
+ #endif
+
+- void filterAndSendReports(const std::string& id2,
+- const std::string& readingsTs,
+- const ReadingsObjType& readings)
++ void filterAndSendReports(
++ const std::string& id,
++ const std::variant<telemetry::TimestampReadings>& var)
+ {
+- std::string metricReportDef =
+- "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id2;
++ std::string mrdUri = telemetry::metricReportDefinitionUri + id;
+
+ // Empty list means no filter. Send everything.
+ if (metricReportDefinitions.size())
+ {
+ if (std::find(metricReportDefinitions.begin(),
+ metricReportDefinitions.end(),
+- metricReportDef) == metricReportDefinitions.end())
++ mrdUri) == metricReportDefinitions.end())
+ {
+ return;
+ }
+ }
+
+- nlohmann::json metricValuesArray = nlohmann::json::array();
+- for (const auto& it : readings)
++ nlohmann::json msg;
++ if (!telemetry::fillReport(msg, id, var))
+ {
+- metricValuesArray.push_back({});
+- nlohmann::json& entry = metricValuesArray.back();
+-
+- auto& [id, property, value, timestamp] = it;
+-
+- entry = {{"MetricId", id},
+- {"MetricProperty", property},
+- {"MetricValue", std::to_string(value)},
+- {"Timestamp", crow::utility::getDateTime(timestamp)}};
++ BMCWEB_LOG_ERROR << "Failed to fill the MetricReport for DBus "
++ "Report with id "
++ << id;
++ return;
+ }
+
+- nlohmann::json msg = {
+- {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id},
+- {"@odata.type", "#MetricReport.v1_3_0.MetricReport"},
+- {"Id", id2},
+- {"Name", id2},
+- {"Timestamp", readingsTs},
+- {"MetricReportDefinition", {{"@odata.id", metricReportDef}}},
+- {"MetricValues", metricValuesArray}};
+-
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
+ }
+@@ -1317,75 +1303,6 @@ class EventServiceManager
+ }
+
+ #endif
+-
+- void getMetricReading(const std::string& service,
+- const std::string& objPath, const std::string& intf)
+- {
+- std::size_t found = objPath.find_last_of('/');
+- if (found == std::string::npos)
+- {
+- BMCWEB_LOG_DEBUG << "Invalid objPath received";
+- return;
+- }
+-
+- std::string idStr = objPath.substr(found + 1);
+- if (idStr.empty())
+- {
+- BMCWEB_LOG_DEBUG << "Invalid ID in objPath";
+- return;
+- }
+-
+- crow::connections::systemBus->async_method_call(
+- [idStr{std::move(idStr)}](
+- const boost::system::error_code ec,
+- boost::container::flat_map<
+- std::string, std::variant<int32_t, ReadingsObjType>>&
+- resp) {
+- if (ec)
+- {
+- BMCWEB_LOG_DEBUG
+- << "D-Bus call failed to GetAll metric readings.";
+- return;
+- }
+-
+- const int32_t* timestampPtr =
+- std::get_if<int32_t>(&resp["Timestamp"]);
+- if (!timestampPtr)
+- {
+- BMCWEB_LOG_DEBUG << "Failed to Get timestamp.";
+- return;
+- }
+-
+- ReadingsObjType* readingsPtr =
+- std::get_if<ReadingsObjType>(&resp["Readings"]);
+- if (!readingsPtr)
+- {
+- BMCWEB_LOG_DEBUG << "Failed to Get Readings property.";
+- return;
+- }
+-
+- if (!readingsPtr->size())
+- {
+- BMCWEB_LOG_DEBUG << "No metrics report to be transferred";
+- return;
+- }
+-
+- for (const auto& it :
+- EventServiceManager::getInstance().subscriptionsMap)
+- {
+- std::shared_ptr<Subscription> entry = it.second;
+- if (entry->eventFormatType == metricReportFormatType)
+- {
+- entry->filterAndSendReports(
+- idStr, crow::utility::getDateTime(*timestampPtr),
+- *readingsPtr);
+- }
+- }
+- },
+- service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
+- intf);
+- }
+-
+ void unregisterMetricReportSignal()
+ {
+ if (matchTelemetryMonitor)
+@@ -1405,9 +1322,11 @@ class EventServiceManager
+ }
+
+ BMCWEB_LOG_DEBUG << "Metrics report signal - Register";
+- std::string matchStr(
+- "type='signal',member='ReportUpdate', "
+- "interface='xyz.openbmc_project.MonitoringService.Report'");
++ std::string matchStr = "type='signal',member='PropertiesChanged',"
++ "interface='org.freedesktop.DBus.Properties',"
++ "path_namespace=/xyz/openbmc_project/Telemetry/"
++ "Reports/TelemetryService,"
++ "arg0=xyz.openbmc_project.Telemetry.Report";
+
+ matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus, matchStr,
+@@ -1418,10 +1337,43 @@ class EventServiceManager
+ return;
+ }
+
+- std::string service = msg.get_sender();
+- std::string objPath = msg.get_path();
+- std::string intf = msg.get_interface();
+- getMetricReading(service, objPath, intf);
++ sdbusplus::message::object_path path(msg.get_path());
++ std::string id = path.filename();
++ if (id.empty())
++ {
++ BMCWEB_LOG_ERROR << "Failed to get Id from path";
++ return;
++ }
++
++ std::string intf;
++ std::vector<std::pair<
++ std::string, std::variant<telemetry::TimestampReadings>>>
++ props;
++ std::vector<std::string> invalidProps;
++ msg.read(intf, props, invalidProps);
++
++ auto found =
++ std::find_if(props.begin(), props.end(), [](const auto& x) {
++ return x.first == "Readings";
++ });
++ if (found == props.end())
++ {
++ BMCWEB_LOG_INFO
++ << "Failed to get Readings from Report properties";
++ return;
++ }
++
++ const std::variant<telemetry::TimestampReadings>& readings =
++ found->second;
++ for (const auto& it :
++ EventServiceManager::getInstance().subscriptionsMap)
++ {
++ Subscription& entry = *it.second.get();
++ if (entry.eventFormatType == metricReportFormatType)
++ {
++ entry.filterAndSendReports(id, readings);
++ }
++ }
+ });
+ }
+
+diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
+index 63c8c19..7fe281d 100644
+--- a/redfish-core/lib/metric_report.hpp
++++ b/redfish-core/lib/metric_report.hpp
+@@ -33,16 +33,14 @@ inline nlohmann::json toMetricValues(const Readings& readings)
+ return metricValues;
+ }
+
+-inline void fillReport(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+- const std::string& id,
++inline bool fillReport(nlohmann::json& json, const std::string& id,
+ const std::variant<TimestampReadings>& var)
+ {
+- asyncResp->res.jsonValue["@odata.type"] =
+- "#MetricReport.v1_3_0.MetricReport";
+- asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id;
+- asyncResp->res.jsonValue["Id"] = id;
+- asyncResp->res.jsonValue["Name"] = id;
+- asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] =
++ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport";
++ json["@odata.id"] = telemetry::metricReportUri + id;
++ json["Id"] = id;
++ json["Name"] = id;
++ json["MetricReportDefinition"]["@odata.id"] =
+ telemetry::metricReportDefinitionUri + id;
+
+ const TimestampReadings* timestampReadings =
+@@ -50,14 +48,14 @@ inline void fillReport(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ if (!timestampReadings)
+ {
+ BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
+- messages::internalError(asyncResp->res);
+- return;
++ return false;
+ }
+
+ const auto& [timestamp, readings] = *timestampReadings;
+- asyncResp->res.jsonValue["Timestamp"] =
++ json["Timestamp"] =
+ crow::utility::getDateTime(static_cast<time_t>(timestamp));
+- asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings);
++ json["MetricValues"] = toMetricValues(readings);
++ return true;
+ }
+ } // namespace telemetry
+
+@@ -118,7 +116,11 @@ inline void requestRoutesMetricReport(App& app)
+ return;
+ }
+
+- telemetry::fillReport(asyncResp, id, ret);
++ if (!telemetry::fillReport(
++ asyncResp->res.jsonValue, id, ret))
++ {
++ messages::internalError(asyncResp->res);
++ }
+ },
+ telemetry::service, reportPath,
+ "org.freedesktop.DBus.Properties", "Get",
+--
+2.25.1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch
new file mode 100644
index 000000000..5dd2f51bc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch
@@ -0,0 +1,301 @@
+From 8ba1bcc3503cafb33b1a06356d4f8f92ae23e39a Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Thu, 17 Jun 2021 13:37:57 +0000
+Subject: [PATCH] Switched bmcweb to use new telemetry service API
+
+Added support for multiple MetricProperties. Added support for new
+parameters: CollectionTimeScope, CollectionDuration.
+
+Tested:
+ - It is possible to create MetricReportDefinitions with multiple
+ MetricProperties.
+ - Stub values for new parameters are correctly passed to telemetry
+ service.
+ - All existing telemetry service functionalities remain unchanged.
+
+Change-Id: I2cd17069e3ea015c8f5571c29278f1d50536272a
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+---
+ redfish-core/lib/metric_report_definition.hpp | 212 ++++++++++--------
+ 1 file changed, 114 insertions(+), 98 deletions(-)
+
+diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp
+index a0c4f1d..7c26787 100644
+--- a/redfish-core/lib/metric_report_definition.hpp
++++ b/redfish-core/lib/metric_report_definition.hpp
+@@ -7,6 +7,8 @@
+ #include <app.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <registries/privilege_registry.hpp>
++#include <sdbusplus/asio/property.hpp>
++#include <sdbusplus/unpack_properties.hpp>
+
+ #include <tuple>
+ #include <variant>
+@@ -17,87 +19,90 @@ namespace redfish
+ namespace telemetry
+ {
+
+-using ReadingParameters =
+- std::vector<std::tuple<sdbusplus::message::object_path, std::string,
+- std::string, std::string>>;
++using ReadingParameters = std::vector<
++ std::tuple<std::vector<sdbusplus::message::object_path>, std::string,
++ std::string, std::string, std::string, uint64_t>>;
+
+ inline void fillReportDefinition(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
+ const std::vector<
+- std::pair<std::string, std::variant<std::string, bool, uint64_t,
+- ReadingParameters>>>& ret)
++ std::pair<std::string, std::variant<std::monostate, std::string, bool,
++ uint64_t, ReadingParameters>>>&
++ properties)
+ {
+- asyncResp->res.jsonValue["@odata.type"] =
+- "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
+- asyncResp->res.jsonValue["@odata.id"] =
+- telemetry::metricReportDefinitionUri + id;
+- asyncResp->res.jsonValue["Id"] = id;
+- asyncResp->res.jsonValue["Name"] = id;
+- asyncResp->res.jsonValue["MetricReport"]["@odata.id"] =
+- telemetry::metricReportUri + id;
+- asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
+- asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";
+-
+- const bool* emitsReadingsUpdate = nullptr;
+- const bool* logToMetricReportsCollection = nullptr;
+- const ReadingParameters* readingParams = nullptr;
+- const std::string* reportingType = nullptr;
+- const uint64_t* interval = nullptr;
+- for (const auto& [key, var] : ret)
++ try
+ {
+- if (key == "EmitsReadingsUpdate")
++ bool emitsReadingsUpdate = false;
++ bool logToMetricReportsCollection = false;
++ ReadingParameters readingParams;
++ std::string reportingType;
++ uint64_t interval = 0u;
++
++ sdbusplus::unpackProperties(
++ properties, "EmitsReadingsUpdate", emitsReadingsUpdate,
++ "LogToMetricReportsCollection", logToMetricReportsCollection,
++ "ReadingParametersFutureVersion", readingParams, "ReportingType",
++ reportingType, "Interval", interval);
++
++ std::vector<std::string> redfishReportActions;
++ redfishReportActions.reserve(2);
++ if (emitsReadingsUpdate)
+ {
+- emitsReadingsUpdate = std::get_if<bool>(&var);
++ redfishReportActions.emplace_back("RedfishEvent");
+ }
+- else if (key == "LogToMetricReportsCollection")
++ if (logToMetricReportsCollection)
+ {
+- logToMetricReportsCollection = std::get_if<bool>(&var);
++ redfishReportActions.emplace_back("LogToMetricReportsCollection");
+ }
+- else if (key == "ReadingParameters")
+- {
+- readingParams = std::get_if<ReadingParameters>(&var);
+- }
+- else if (key == "ReportingType")
+- {
+- reportingType = std::get_if<std::string>(&var);
+- }
+- else if (key == "Interval")
++
++ nlohmann::json metrics = nlohmann::json::array();
++ for (auto& [sensorPath, operationType, id, metadata,
++ collectionTimeScope, collectionDuration] : readingParams)
+ {
+- interval = std::get_if<uint64_t>(&var);
++ std::vector<std::string> metricProperties;
++
++ nlohmann::json parsedMetadata = nlohmann::json::parse(metadata);
++ if (!json_util::readJson(parsedMetadata, asyncResp->res,
++ "MetricProperties", metricProperties))
++ {
++ BMCWEB_LOG_ERROR << "Failed to read metadata";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ metrics.push_back({
++ {"MetricId", id},
++ {"MetricProperties", std::move(metricProperties)},
++ });
+ }
+- }
+- if (!emitsReadingsUpdate || !logToMetricReportsCollection ||
+- !readingParams || !reportingType || !interval)
+- {
+- BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
+- messages::internalError(asyncResp->res);
+- return;
+- }
+
+- std::vector<std::string> redfishReportActions;
+- redfishReportActions.reserve(2);
+- if (*emitsReadingsUpdate)
+- {
+- redfishReportActions.emplace_back("RedfishEvent");
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
++ asyncResp->res.jsonValue["@odata.id"] =
++ telemetry::metricReportDefinitionUri + id;
++ asyncResp->res.jsonValue["Id"] = id;
++ asyncResp->res.jsonValue["Name"] = id;
++ asyncResp->res.jsonValue["MetricReport"]["@odata.id"] =
++ telemetry::metricReportUri + id;
++ asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
++ asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";
++ asyncResp->res.jsonValue["Metrics"] = metrics;
++ asyncResp->res.jsonValue["MetricReportDefinitionType"] = reportingType;
++ asyncResp->res.jsonValue["ReportActions"] = redfishReportActions;
++ asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
++ time_utils::toDurationString(std::chrono::milliseconds(interval));
+ }
+- if (*logToMetricReportsCollection)
++ catch (const sdbusplus::exception::UnpackPropertyError& error)
+ {
+- redfishReportActions.emplace_back("LogToMetricReportsCollection");
++ BMCWEB_LOG_ERROR << error.what() << ", property: "
++ << error.propertyName + ", reason: " << error.reason;
++ messages::internalError(asyncResp->res);
+ }
+-
+- nlohmann::json metrics = nlohmann::json::array();
+- for (auto& [sensorPath, operationType, id, metadata] : *readingParams)
++ catch (const nlohmann::json::parse_error& e)
+ {
+- metrics.push_back({
+- {"MetricId", id},
+- {"MetricProperties", {metadata}},
+- });
++ BMCWEB_LOG_ERROR << "Failed to parse metadata: " << e.what();
++ messages::internalError(asyncResp->res);
+ }
+- asyncResp->res.jsonValue["Metrics"] = metrics;
+- asyncResp->res.jsonValue["MetricReportDefinitionType"] = *reportingType;
+- asyncResp->res.jsonValue["ReportActions"] = redfishReportActions;
+- asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
+- time_utils::toDurationString(std::chrono::milliseconds(*interval));
+ }
+
+ struct AddReportArgs
+@@ -275,6 +280,11 @@ class AddReport
+
+ for (const auto& [id, uris] : args.metrics)
+ {
++ std::vector<sdbusplus::message::object_path> dbusPaths;
++ dbusPaths.reserve(uris.size());
++ nlohmann::json metadata;
++ metadata["MetricProperties"] = nlohmann::json::array();
++
+ for (size_t i = 0; i < uris.size(); i++)
+ {
+ const std::string& uri = uris[i];
+@@ -291,8 +301,12 @@ class AddReport
+ }
+
+ const std::string& dbusPath = el->second;
+- readingParams.emplace_back(dbusPath, "SINGLE", id, uri);
++ dbusPaths.emplace_back(dbusPath);
++ metadata["MetricProperties"].emplace_back(uri);
+ }
++
++ readingParams.emplace_back(dbusPaths, "SINGLE", id, metadata.dump(),
++ "Point", 0u);
+ }
+ const std::shared_ptr<bmcweb::AsyncResp> aResp = asyncResp;
+ crow::connections::systemBus->async_method_call(
+@@ -330,10 +344,10 @@ class AddReport
+ messages::created(aResp->res);
+ },
+ telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
+- "xyz.openbmc_project.Telemetry.ReportManager", "AddReport",
+- "TelemetryService/" + args.name, args.reportingType,
+- args.emitsReadingsUpdate, args.logToMetricReportsCollection,
+- args.interval, readingParams);
++ "xyz.openbmc_project.Telemetry.ReportManager",
++ "AddReportFutureVersion", "TelemetryService/" + args.name,
++ args.reportingType, args.emitsReadingsUpdate,
++ args.logToMetricReportsCollection, args.interval, readingParams);
+ }
+
+ void insert(const boost::container::flat_map<std::string, std::string>& el)
+@@ -415,37 +429,39 @@ inline void requestRoutesMetricReportDefinition(App& app)
+ BMCWEB_ROUTE(app,
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
+ .privileges(redfish::privileges::getMetricReportDefinition)
+- .methods(boost::beast::http::verb::get)(
+- [](const crow::Request&,
+- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+- const std::string& id) {
+- crow::connections::systemBus->async_method_call(
+- [asyncResp, id](
+- const boost::system::error_code ec,
+- const std::vector<std::pair<
+- std::string,
+- std::variant<std::string, bool, uint64_t,
+- telemetry::ReadingParameters>>>& ret) {
+- if (ec.value() == EBADR ||
+- ec == boost::system::errc::host_unreachable)
+- {
+- messages::resourceNotFound(
+- asyncResp->res, "MetricReportDefinition", id);
+- return;
+- }
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
+- messages::internalError(asyncResp->res);
+- return;
+- }
++ .methods(
++ boost::beast::http::verb::get)([](const crow::Request&,
++ const std::shared_ptr<
++ bmcweb::AsyncResp>& asyncResp,
++ const std::string& id) {
++ sdbusplus::asio::getAllProperties(
++ *crow::connections::systemBus, telemetry::service,
++ telemetry::getDbusReportPath(id), telemetry::reportInterface,
++ [asyncResp,
++ id](boost::system::error_code ec,
++ const std::vector<std::pair<
++ std::string,
++ std::variant<std::monostate, std::string, bool,
++ uint64_t, telemetry::ReadingParameters>>>&
++ properties) {
++ if (ec.value() == EBADR ||
++ ec == boost::system::errc::host_unreachable)
++ {
++ messages::resourceNotFound(
++ asyncResp->res, "MetricReportDefinition", id);
++ return;
++ }
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ telemetry::fillReportDefinition(asyncResp, id, properties);
++ });
++ });
+
+- telemetry::fillReportDefinition(asyncResp, id, ret);
+- },
+- telemetry::service, telemetry::getDbusReportPath(id),
+- "org.freedesktop.DBus.Properties", "GetAll",
+- telemetry::reportInterface);
+- });
+ BMCWEB_ROUTE(app,
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
+ .privileges(redfish::privileges::deleteMetricReportDefinitionCollection)
+--
+2.25.1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch
new file mode 100644
index 000000000..bf5a09d9d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch
@@ -0,0 +1,268 @@
+From dab3c96f9e39a89d7c359e22655650c7c16952ec Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 12 Oct 2021 08:06:13 +0000
+Subject: [PATCH] Add support for MetricDefinition property in MetricReport
+
+Added MetricDefinition as part of MetricValues array returned by
+MetricReport. It contains single @odata.id with URI to proper
+MetricDefinition resource - depending on MetricProperty.
+
+Testing done:
+- GET request on redfish/v1/TelemetryService/MetricReports
+ got response with MetricDefinition and proper id inside
+ MetricValues array.
+
+Testing steps:
+1. POST on redfish/v1/TelemetryService/MetricReportDefinitions
+ with body:
+{
+ "Id": "PeriodicReport_1",
+ "MetricReportDefinitionType": "Periodic",
+ "ReportActions": [
+ "LogToMetricReportsCollection",
+ "RedfishEvent"
+ ],
+ "Metrics": [
+ {
+ "MetricId": "sensor_1",
+ "MetricProperties": [
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/1/Reading"
+ ]
+ }
+ ],
+ "Schedule": {
+ "RecurrenceInterval": "PT10S"
+ }
+}
+
+2. GET on redfish/v1/TelemetryService/MetricReports/PeriodicReport_1
+ should return:
+{
+ "@odata.id":
+ "/redfish/v1/TelemetryService/MetricReports/PeriodicReport_1",
+ "@odata.type": "#MetricReport.v1_3_0.MetricReport",
+ "Id": "PeriodicReport_1",
+ "MetricReportDefinition": {
+ "@odata.id":
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/PeriodicReport_1"
+ },
+ "MetricValues": [
+ {
+ "MetricDefinition": {
+ "@odata.id":
+ "/redfish/v1/TelemetryService/MetricDefinitions/Rotational"
+ },
+ "MetricId": "sensor_1",
+ "MetricProperty":
+ "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/1/Reading",
+ "MetricValue": "nan",
+ "Timestamp": "1970-01-01T00:03:21+00:00"
+ }
+ ],
+ "Name": "PeriodicReport_1",
+ "Timestamp": "1970-01-01T00:03:21+00:00"
+}
+
+Change-Id: I7181c612f9b443015d551259bae25303aa436822
+Signed-off-by: Szymon Dompke <szymon.dompke@intel.com>
+---
+ meson.build | 4 +-
+ .../include/utils/telemetry_utils.hpp | 40 ++++++++++++
+ redfish-core/lib/metric_report.hpp | 64 +++++++++++++++----
+ redfish-core/lib/sensors.hpp | 2 +
+ 4 files changed, 95 insertions(+), 15 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 6b6a8ab..218ea49 100644
+--- a/meson.build
++++ b/meson.build
+@@ -377,6 +377,8 @@ srcfiles_unittest = [
+ 'http/ut/utility_test.cpp'
+ ]
+
++srcfiles_unittest_dependencies = ['redfish-core/src/error_messages.cpp', 'src/boost_url.cpp']
++
+ # Gather the Configuration data
+
+ conf_data = configuration_data()
+@@ -434,7 +436,7 @@ executable('bmcweb',srcfiles_bmcweb,
+ if(get_option('tests').enabled())
+ foreach src_test : srcfiles_unittest
+ testname = src_test.split('/')[-1].split('.')[0]
+- test(testname,executable(testname,src_test,
++ test(testname,executable(testname,[src_test] + srcfiles_unittest_dependencies,
+ include_directories : incdir,
+ install_dir: bindir,
+ dependencies: [
+diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
+index 1b4f75d..c0c5ba3 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -17,6 +17,46 @@ constexpr const char* metricReportDefinitionUri =
+ constexpr const char* metricReportUri =
+ "/redfish/v1/TelemetryService/MetricReports/";
+
++inline std::optional<nlohmann::json>
++ getMetadataJson(const std::string& metadataStr)
++{
++ std::optional<nlohmann::json> res =
++ nlohmann::json::parse(metadataStr, nullptr, false);
++ if (res->is_discarded())
++ {
++ BMCWEB_LOG_ERROR << "Malformed reading metatadata JSON provided by "
++ "telemetry service.";
++ return std::nullopt;
++ }
++ return res;
++}
++
++inline std::optional<std::string>
++ readStringFromMetadata(const nlohmann::json& metadataJson, const char* key)
++{
++ std::optional<std::string> res;
++ if (auto it = metadataJson.find(key); it != metadataJson.end())
++ {
++ if (const std::string* value = it->get_ptr<const std::string*>())
++ {
++ res = *value;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Incorrect reading metatadata JSON provided by "
++ "telemetry service. Missing key '"
++ << key << "'.";
++ }
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Incorrect reading metatadata JSON provided by "
++ "telemetry service. Key '"
++ << key << "' has a wrong type.";
++ }
++ return res;
++}
++
+ inline void
+ getReportCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& uri)
+diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
+index 7fe281d..13bf792 100644
+--- a/redfish-core/lib/metric_report.hpp
++++ b/redfish-core/lib/metric_report.hpp
+@@ -1,5 +1,6 @@
+ #pragma once
+
++#include "sensors.hpp"
+ #include "utils/telemetry_utils.hpp"
+
+ #include <app.hpp>
+@@ -15,34 +16,56 @@ using Readings =
+ std::vector<std::tuple<std::string, std::string, double, uint64_t>>;
+ using TimestampReadings = std::tuple<uint64_t, Readings>;
+
+-inline nlohmann::json toMetricValues(const Readings& readings)
++inline bool fillMetricValues(nlohmann::json& metricValues,
++ const Readings& readings)
+ {
+- nlohmann::json metricValues = nlohmann::json::array_t();
+-
+- for (auto& [id, metadata, sensorValue, timestamp] : readings)
++ for (auto& [id, metadataStr, sensorValue, timestamp] : readings)
+ {
++ std::optional<nlohmann::json> readingMetadataJson =
++ getMetadataJson(metadataStr);
++ if (!readingMetadataJson)
++ {
++ return false;
++ }
++
++ std::optional<std::string> sensorDbusPath =
++ readStringFromMetadata(*readingMetadataJson, "SensorDbusPath");
++ if (!sensorDbusPath)
++ {
++ return false;
++ }
++
++ std::optional<std::string> sensorRedfishUri =
++ readStringFromMetadata(*readingMetadataJson, "SensorRedfishUri");
++ if (!sensorRedfishUri)
++ {
++ return false;
++ }
++
++ std::string metricDefinition =
++ std::string(metricDefinitionUri) +
++ sensors::toReadingType(
++ sdbusplus::message::object_path(*sensorDbusPath)
++ .parent_path()
++ .filename());
++
+ metricValues.push_back({
++ {"MetricDefinition",
++ nlohmann::json{{"@odata.id", metricDefinition}}},
+ {"MetricId", id},
+- {"MetricProperty", metadata},
++ {"MetricProperty", *sensorRedfishUri},
+ {"MetricValue", std::to_string(sensorValue)},
+ {"Timestamp",
+ crow::utility::getDateTime(static_cast<time_t>(timestamp))},
+ });
+ }
+
+- return metricValues;
++ return true;
+ }
+
+ inline bool fillReport(nlohmann::json& json, const std::string& id,
+ const std::variant<TimestampReadings>& var)
+ {
+- json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport";
+- json["@odata.id"] = telemetry::metricReportUri + id;
+- json["Id"] = id;
+- json["Name"] = id;
+- json["MetricReportDefinition"]["@odata.id"] =
+- telemetry::metricReportDefinitionUri + id;
+-
+ const TimestampReadings* timestampReadings =
+ std::get_if<TimestampReadings>(&var);
+ if (!timestampReadings)
+@@ -52,9 +75,22 @@ inline bool fillReport(nlohmann::json& json, const std::string& id,
+ }
+
+ const auto& [timestamp, readings] = *timestampReadings;
++ nlohmann::json metricValues = nlohmann::json::array();
++ if (!fillMetricValues(metricValues, readings))
++ {
++ return false;
++ }
++
++ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport";
++ json["@odata.id"] = telemetry::metricReportUri + id;
++ json["Id"] = id;
++ json["Name"] = id;
++ json["MetricReportDefinition"]["@odata.id"] =
++ telemetry::metricReportDefinitionUri + id;
+ json["Timestamp"] =
+ crow::utility::getDateTime(static_cast<time_t>(timestamp));
+- json["MetricValues"] = toMetricValues(readings);
++ json["MetricValues"] = metricValues;
++
+ return true;
+ }
+ } // namespace telemetry
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index 7405e5a..9850b24 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -21,6 +21,8 @@
+ #include <boost/container/flat_map.hpp>
+ #include <boost/range/algorithm/replace_copy_if.hpp>
+ #include <dbus_singleton.hpp>
++#include <dbus_utility.hpp>
++#include <error_messages.hpp>
+ #include <registries/privilege_registry.hpp>
+ #include <utils/json_utils.hpp>
+
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch
new file mode 100644
index 000000000..0646aba5c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch
@@ -0,0 +1,313 @@
+From a1e89d356ba5ed594a1494efe8257946e1062396 Mon Sep 17 00:00:00 2001
+From: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com>
+Date: Tue, 31 Aug 2021 14:35:31 +0200
+Subject: [PATCH] Add GET method for TriggerCollection
+
+Added GET method for retrieving list of Triggers from Telemetry service
+
+Tested:
+- Added single Trigger and requested result from bmcweb via
+ /redfish/v1/TelemetryService/Triggers
+- Added multiple Triggers numeric and discrete, and requested results
+ from bmcweb via /redfish/v1/TelemetryService/Triggers
+- Verified uri /redfish/v1/TelemetryService/Triggers by using
+ Redfish-Service-Validator (all passed)
+
+Signed-off-by: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com>
+Change-Id: Ide00eb44901ea1b97b80fc5c5ddfd97e393d4a04
+---
+ redfish-core/include/redfish.hpp | 2 +
+ .../include/utils/telemetry_utils.hpp | 40 ++++++++---
+ redfish-core/lib/metric_report.hpp | 6 +-
+ redfish-core/lib/metric_report_definition.hpp | 6 +-
+ redfish-core/lib/trigger.hpp | 31 ++++++++
+ scripts/update_schemas.py | 1 +
+ static/redfish/v1/$metadata/index.xml | 3 +
+ .../v1/schema/TriggersCollection_v1.xml | 70 +++++++++++++++++++
+ 8 files changed, 144 insertions(+), 15 deletions(-)
+ create mode 100644 redfish-core/lib/trigger.hpp
+ create mode 100644 static/redfish/v1/schema/TriggersCollection_v1.xml
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 9fb0ffe..99b3fe6 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -42,6 +42,7 @@
+ #include "../lib/task.hpp"
+ #include "../lib/telemetry_service.hpp"
+ #include "../lib/thermal.hpp"
++#include "../lib/trigger.hpp"
+ #include "../lib/update_service.hpp"
+ #include "../lib/virtual_media.hpp"
+
+@@ -197,6 +198,7 @@ class RedfishService
+
+ hypervisor::requestRoutesHypervisorSystems(app);
+
++ requestRoutesTriggerCollection(app);
+ requestRoutesTelemetryService(app);
+ requestRoutesMetricReportDefinitionCollection(app);
+ requestRoutesMetricReportDefinition(app);
+diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
+index c0c5ba3..df1aa68 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -9,6 +9,8 @@ namespace telemetry
+ {
+
+ constexpr const char* service = "xyz.openbmc_project.Telemetry";
++constexpr const char* reportSubtree =
++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService";
+ constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report";
+ constexpr const char* metricDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricDefinitions/";
+@@ -16,6 +18,11 @@ constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
+ constexpr const char* metricReportUri =
+ "/redfish/v1/TelemetryService/MetricReports/";
++constexpr const char* triggerSubtree =
++ "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService";
++constexpr const char* triggerInterface =
++ "xyz.openbmc_project.Telemetry.Trigger";
++constexpr const char* triggerUri = "/redfish/v1/TelemetryService/Triggers/";
+
+ inline std::optional<nlohmann::json>
+ getMetadataJson(const std::string& metadataStr)
+@@ -57,15 +64,27 @@ inline std::optional<std::string>
+ return res;
+ }
+
+-inline void
+- getReportCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+- const std::string& uri)
++struct CollectionParams
+ {
+- const std::array<const char*, 1> interfaces = {reportInterface};
++ const char* subtree;
++ int depth;
++ std::array<const char*, 1> interfaces;
+
++ CollectionParams() = delete;
++ CollectionParams(const char* st, int dp,
++ const std::array<const char*, 1>& ifaces) :
++ subtree{st},
++ depth{dp}, interfaces{ifaces}
++ {}
++};
++
++inline void getCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::string& uri,
++ const CollectionParams& params)
++{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, uri](const boost::system::error_code ec,
+- const std::vector<std::string>& reports) {
++ const std::vector<std::string>& items) {
+ if (ec == boost::system::errc::io_error)
+ {
+ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
+@@ -82,13 +101,13 @@ inline void
+ nlohmann::json& members = asyncResp->res.jsonValue["Members"];
+ members = nlohmann::json::array();
+
+- for (const std::string& report : reports)
++ for (const std::string& item : items)
+ {
+- sdbusplus::message::object_path path(report);
++ sdbusplus::message::object_path path(item);
+ std::string name = path.filename();
+ if (name.empty())
+ {
+- BMCWEB_LOG_ERROR << "Received invalid path: " << report;
++ BMCWEB_LOG_ERROR << "Received invalid path: " << item;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+@@ -99,9 +118,8 @@ inline void
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+- "/xyz/openbmc_project/Telemetry/Reports/TelemetryService", 1,
+- interfaces);
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", params.subtree,
++ params.depth, params.interfaces);
+ }
+
+ inline std::string getDbusReportPath(const std::string& id)
+diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
+index 13bf792..ea4cd62 100644
+--- a/redfish-core/lib/metric_report.hpp
++++ b/redfish-core/lib/metric_report.hpp
+@@ -108,8 +108,10 @@ inline void requestRoutesMetricReportCollection(App& app)
+ "/redfish/v1/TelemetryService/MetricReports";
+ asyncResp->res.jsonValue["Name"] = "Metric Report Collection";
+
+- telemetry::getReportCollection(asyncResp,
+- telemetry::metricReportUri);
++ telemetry::getCollection(
++ asyncResp, telemetry::metricReportUri,
++ telemetry::CollectionParams(telemetry::reportSubtree, 1,
++ {telemetry::reportInterface}));
+ });
+ }
+
+diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp
+index 7c26787..c97a1df 100644
+--- a/redfish-core/lib/metric_report_definition.hpp
++++ b/redfish-core/lib/metric_report_definition.hpp
+@@ -377,8 +377,10 @@ inline void requestRoutesMetricReportDefinitionCollection(App& app)
+ asyncResp->res.jsonValue["Name"] =
+ "Metric Definition Collection";
+
+- telemetry::getReportCollection(
+- asyncResp, telemetry::metricReportDefinitionUri);
++ telemetry::getCollection(
++ asyncResp, telemetry::metricReportDefinitionUri,
++ telemetry::CollectionParams(telemetry::reportSubtree, 1,
++ {telemetry::reportInterface}));
+ });
+
+ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
+diff --git a/redfish-core/lib/trigger.hpp b/redfish-core/lib/trigger.hpp
+new file mode 100644
+index 0000000..681b3b4
+--- /dev/null
++++ b/redfish-core/lib/trigger.hpp
+@@ -0,0 +1,31 @@
++#pragma once
++
++#include "utils/telemetry_utils.hpp"
++
++#include <app.hpp>
++#include <registries/privilege_registry.hpp>
++
++namespace redfish
++{
++
++inline void requestRoutesTriggerCollection(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/")
++ .privileges(redfish::privileges::getTriggersCollection)
++ .methods(boost::beast::http::verb::get)(
++ [](const crow::Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#TriggersCollection.TriggersCollection";
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/TelemetryService/Triggers";
++ asyncResp->res.jsonValue["Name"] = "Triggers Collection";
++
++ telemetry::getCollection(
++ asyncResp, telemetry::triggerUri,
++ telemetry::CollectionParams(telemetry::triggerSubtree, 1,
++ {telemetry::triggerInterface}));
++ });
++}
++
++} // namespace redfish
+diff --git a/scripts/update_schemas.py b/scripts/update_schemas.py
+index dd39278..d66a59a 100755
+--- a/scripts/update_schemas.py
++++ b/scripts/update_schemas.py
+@@ -93,6 +93,7 @@ include_list = [
+ 'TaskService',
+ 'TelemetryService',
+ 'Thermal',
++ 'TriggersCollection',
+ 'UpdateService',
+ 'VLanNetworkInterfaceCollection',
+ 'VLanNetworkInterface',
+diff --git a/static/redfish/v1/$metadata/index.xml b/static/redfish/v1/$metadata/index.xml
+index 876ebfb..75e3dd4 100644
+--- a/static/redfish/v1/$metadata/index.xml
++++ b/static/redfish/v1/$metadata/index.xml
+@@ -2215,6 +2215,9 @@
+ <edmx:Include Namespace="Thermal.v1_7_0"/>
+ <edmx:Include Namespace="Thermal.v1_7_1"/>
+ </edmx:Reference>
++ <edmx:Reference Uri="/redfish/v1/schema/TriggersCollection_v1.xml">
++ <edmx:Include Namespace="TriggersCollection"/>
++ </edmx:Reference>
+ <edmx:Reference Uri="/redfish/v1/schema/UpdateService_v1.xml">
+ <edmx:Include Namespace="UpdateService"/>
+ <edmx:Include Namespace="UpdateService.v1_0_0"/>
+diff --git a/static/redfish/v1/schema/TriggersCollection_v1.xml b/static/redfish/v1/schema/TriggersCollection_v1.xml
+new file mode 100644
+index 0000000..399bebd
+--- /dev/null
++++ b/static/redfish/v1/schema/TriggersCollection_v1.xml
+@@ -0,0 +1,70 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!---->
++<!--################################################################################ -->
++<!--# Redfish Schema: TriggerSetCollection -->
++<!--# -->
++<!--# For a detailed change log, see the README file contained in the DSP8010 bundle, -->
++<!--# available at http://www.dmtf.org/standards/redfish -->
++<!--# Copyright 2014-2021 DMTF. -->
++<!--# For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright -->
++<!--################################################################################ -->
++<!---->
++<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
++
++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml">
++ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Capabilities.V1.xml">
++ <edmx:Include Namespace="Org.OData.Capabilities.V1" Alias="Capabilities"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml">
++ <edmx:Include Namespace="Resource.v1_0_0"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml">
++ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Triggers_v1.xml">
++ <edmx:Include Namespace="Triggers"/>
++ </edmx:Reference>
++
++ <edmx:DataServices>
++
++ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="TriggersCollection">
++ <Annotation Term="Redfish.OwningEntity" String="DMTF"/>
++
++ <EntityType Name="TriggersCollection" BaseType="Resource.v1_0_0.ResourceCollection">
++ <Annotation Term="OData.Description" String="The collection of Triggers resource instances."/>
++ <Annotation Term="OData.LongDescription" String="This resource shall represent a resource collection of Triggers instances for a Redfish implementation."/>
++ <Annotation Term="Capabilities.InsertRestrictions">
++ <Record>
++ <PropertyValue Property="Insertable" Bool="true"/>
++ <Annotation Term="OData.Description" String="Create triggers through a POST to the trigger collection."/>
++ </Record>
++ </Annotation>
++ <Annotation Term="Capabilities.UpdateRestrictions">
++ <Record>
++ <PropertyValue Property="Updatable" Bool="false"/>
++ </Record>
++ </Annotation>
++ <Annotation Term="Capabilities.DeleteRestrictions">
++ <Record>
++ <PropertyValue Property="Deletable" Bool="false"/>
++ </Record>
++ </Annotation>
++ <Annotation Term="Redfish.Uris">
++ <Collection>
++ <String>/redfish/v1/TelemetryService/Triggers</String>
++ </Collection>
++ </Annotation>
++ <NavigationProperty Name="Members" Type="Collection(Triggers.Triggers)">
++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/>
++ <Annotation Term="OData.Description" String="The members of this collection."/>
++ <Annotation Term="OData.LongDescription" String="This property shall contain an array of links to the members of this collection."/>
++ <Annotation Term="OData.AutoExpandReferences"/>
++ <Annotation Term="Redfish.Required"/>
++ </NavigationProperty>
++ </EntityType>
++
++ </Schema>
++ </edmx:DataServices>
++</edmx:Edmx>
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch
new file mode 100644
index 000000000..a80ac61c7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch
@@ -0,0 +1,26 @@
+From da575aaf0bdcb15be261d58314cf7bbbcd92dd74 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 12 Oct 2021 08:08:06 +0000
+Subject: [PATCH] Revert "Remove LogService from TelemetryService"
+
+This reverts commit 2b3da45876aac57a36d3093379a992d699e7e396.
+---
+ redfish-core/lib/telemetry_service.hpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
+index 027b51b..49471fe 100644
+--- a/redfish-core/lib/telemetry_service.hpp
++++ b/redfish-core/lib/telemetry_service.hpp
+@@ -24,6 +24,8 @@ inline void handleTelemetryServiceGet(
+ "/redfish/v1/TelemetryService/MetricReports";
+ asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricDefinitions";
++ asyncResp->res.jsonValue["LogService"]["@odata.id"] =
++ "/redfish/v1/Managers/bmc/LogServices/Journal";
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec,
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch
new file mode 100644
index 000000000..ffab743f6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch
@@ -0,0 +1,29 @@
+From 0ca8c383db8c9afbce63380955a20ada0acc20b7 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Wed, 2 Jun 2021 12:44:43 +0000
+Subject: [PATCH] event service fix, added Context field to response
+
+Tested:
+ - Context field is present
+ - No regression detected
+
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+---
+ redfish-core/include/event_service_manager.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 2b957ea..289886b 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -556,6 +556,7 @@ class Subscription
+ << id;
+ return;
+ }
++ msg["Context"] = customText;
+
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch
new file mode 100644
index 000000000..548e3d9c6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch
@@ -0,0 +1,46 @@
+From ef83a4fb14648edc6c8370363ff88fb6f060a43b Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 20 Sep 2021 21:55:57 +0530
+Subject: [PATCH] Add support for deleting terminated subscriptions
+
+Added functionality to delete/remove event subscription(s) which are
+configured to Terminate after retries.
+
+Currently, when an Event is subscribed with Retry Policy as
+"TerminateAfterRetries", the state of the connection is set to
+"Terminated" after retrying, but the Subscription is not removed.
+This commit adds the functionality to detect terminated connection and
+remove the respective subscription.
+
+This commit adds this check for metric reports.
+
+Tested:
+ - Created a Subscription with
+ DeliveryRetryPolicy: "TerminateAfterRetries"
+ - Received Events successfully on Event listener
+ - Once the Event listener was stopped, the Subscription was
+ removed/deleted after retries.
+
+Change-Id: I3cb0af5bc24411cddcdb3d1d9de25e8e9144106c
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ redfish-core/include/event_service_manager.hpp | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index c9e2812..c2fefb3 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -1535,6 +1535,9 @@ class EventServiceManager
+
+ std::variant<telemetry::TimestampReadings>& readings =
+ found->second;
++
++ this->deleteTerminatedSubcriptions();
++
+ for (const auto& it :
+ EventServiceManager::getInstance().subscriptionsMap)
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
new file mode 100644
index 000000000..90916ecec
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
@@ -0,0 +1,30 @@
+These patches are mirror of upstream TelemetryService implementation.
+Until change is integrated they will be manually merged here to enable feature in Intel builds.
+
+Current revisions:
+- Add support for MetricDefinition scheme
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/102
+
+- Sync Telmetry service with EventService
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/38798/53
+
+- Switched bmcweb to use new telemetry service API
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44270/19
+
+- Add support for MetricDefinition property in MetricReport
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44512/24
+
+- Add GET method for TriggerCollection
+ file://telemetry/0005-Add-GET-method-for-TriggerCollection.patch
+
+- LogService field, actual implementation will be upstreamed with triggers feature
+ file://telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch
+
+- Event service fix for Context field
+ file://telemetry/0007-event-service-fix-added-Context-field-to-response.patch
+
+- Generalize ReadingType in MetricDefinition
+ file://telemetry/0008-Generalize-ReadingType-in-MetricDefinition.patch
+
+- Add support for deleting terminated subscriptions
+ file://telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch
new file mode 100644
index 000000000..de316c4fa
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch
@@ -0,0 +1,61 @@
+From b6863f9a0c1c36705eba0c3181541f67cd1a202a Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Wed, 14 Jul 2021 09:04:42 +0000
+Subject: [PATCH] Revert "Disable nbd proxy from the build"
+
+NBD Proxy has been disabled upstream. Reenable as we use it for Virtual
+Media
+
+This reverts commit efb8062c306474942bc94f15d748b2eb0b58fbb6.
+
+Change-Id: I19a88b30c1074dd376f2df8f5668245b638b881f
+---
+ meson.build | 3 ++-
+ meson_options.txt | 10 ++--------
+ 2 files changed, 4 insertions(+), 9 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 650a5ec..5738b10 100644
+--- a/meson.build
++++ b/meson.build
+@@ -83,7 +83,8 @@ feature_map = {
+ 'rest' : '-DBMCWEB_ENABLE_DBUS_REST',
+ 'static-hosting' : '-DBMCWEB_ENABLE_STATIC_HOSTING',
+ 'insecure-tftp-update' : '-DBMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE',
+- #'vm-nbdproxy' : '-DBMCWEB_ENABLE_VM_NBDPROXY',
++ 'validate-unsecure-feature' : '-DBMCWEB_ENABLE_VALIDATION_UNSECURE_FEATURE',
++ 'vm-nbdproxy' : '-DBMCWEB_ENABLE_VM_NBDPROXY',
+ 'vm-websocket' : '-DBMCWEB_ENABLE_VM_WEBSOCKET',
+ }
+
+diff --git a/meson_options.txt b/meson_options.txt
+index ff5b887..645f224 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -3,14 +3,7 @@ option('yocto-deps', type: 'feature', value: 'disabled', description : 'Use YOCT
+ option('kvm', type : 'feature',value : 'enabled', description : 'Enable the KVM host video WebSocket. Path is \'/kvm/0\'. Video is from the BMC\'s \'/dev/video\' device.')
+ option ('tests', type : 'feature', value : 'enabled', description : 'Enable Unit tests for bmcweb')
+ option('vm-websocket', type : 'feature', value : 'enabled', description : '''Enable the Virtual Media WebSocket. Path is \'/vm/0/0\'to open the websocket. See https://github.com/openbmc/jsnbd/blob/master/README.''')
+-
+-# if you use this option and are seeing this comment, please comment here:
+-# https://github.com/openbmc/bmcweb/issues/188 and put forward your intentions
+-# for this code. At this point, no daemon has been upstreamed that implements
+-# this interface, so for the moment this appears to be dead code; In leiu of
+-# removing it, it has been disabled to try to give those that use it the
+-# opportunity to upstream their backend implementation
+-#option('vm-nbdproxy', type: 'feature', value : 'disabled', description : 'Enable the Virtual Media WebSocket.')
++option('vm-nbdproxy', type: 'feature', value : 'disabled', description : 'Enable the Virtual Media WebSocket.')
+ option('rest', type : 'feature', value : 'enabled', description : '''Enable Phosphor REST (D-Bus) APIs. Paths directly map Phosphor D-Bus object paths, for example, \'/xyz/openbmc_project/logging/entry/enumerate\'. See https://github.com/openbmc/docs/blob/master/rest-api.md.''')
+ option('redfish', type : 'feature',value : 'enabled', description: 'Enable Redfish APIs. Paths are under \'/redfish/v1/\'. See https://github.com/openbmc/bmcweb/blob/master/DEVELOPING.md#redfish.')
+ option('host-serial-socket', type : 'feature', value : 'enabled', description : 'Enable host serial console WebSocket. Path is \'/console0\'. See https://github.com/openbmc/docs/blob/master/console.md.')
+@@ -39,6 +32,7 @@ option ('https_port', type : 'integer', min : 1, max : 65535, value : 443, descr
+ # the implications of doing so.In general, enabling these options will cause security
+ # problems of varying degrees
+
++option ('validate-unsecure-feature', type : 'feature', value : 'disabled', description : '''Enables unsecure features required by validation. Note: mustbe turned off for production images.''')
+ option ('insecure-disable-csrf', type : 'feature', value : 'disabled', description : 'Disable CSRF prevention checks.Should be set to false for production systems.')
+ option ('insecure-disable-ssl', type : 'feature', value : 'disabled', description : 'Disable SSL ports. Should be set to false for production systems.')
+ option ('insecure-disable-auth', type : 'feature', value : 'disabled', description : 'Disable authentication on all ports. Should be set to false for production systems')
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch
new file mode 100644
index 000000000..e267dc60f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch
@@ -0,0 +1,214 @@
+From bbb69d73ca8b74d34fa250813123de4274d5327b Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Fri, 23 Jul 2021 12:07:02 +0000
+Subject: [PATCH] bmcweb handle device or resource busy exception
+
+Use async_method_call_timed() for mount/unmount dbus oprations.
+Long mount/unmount times are supported by VirtualMedia service,
+this works because of settable timeout property, available for each block
+device.
+Default dbus calls will timeout when mount/unmount timeout is long enough.
+
+Get mount/unmount timeout property and use it for mount/unmount calls.
+Add handling of device or resource busy exception (EBUSY) that
+can be thrown by VirtualMedia service during Mount/Unmount dbus operations.
+
+Tested: Verified that after mounting non-existing HTTPS resource
+ in proxy mode, VirtualMedia recovers restoring ready state
+ and returns EBUSY during that transition.
+ Verfied that resources can be mounted/unmounted in both legacy
+ and proxy mode.
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+Change-Id: Ica62c34db0cce24c4c6169fc661edfde49e948d0
+---
+ redfish-core/lib/virtual_media.hpp | 142 +++++++++++++++++++++--------
+ 1 file changed, 105 insertions(+), 37 deletions(-)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 6e69f20..7fcbf73 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -26,6 +26,8 @@
+ #include <boost/url/url_view.hpp>
+ #include <registries/privilege_registry.hpp>
+
++#include <chrono>
++
+ namespace redfish
+ {
+ /**
+@@ -162,6 +164,26 @@ inline void
+ }
+ }
+
++/**
++ * @brief parses Timeout property and converts to microseconds
++ */
++static std::optional<uint64_t>
++ vmParseTimeoutProperty(const std::variant<int>& timeoutProperty)
++{
++ const int* timeoutValue = std::get_if<int>(&timeoutProperty);
++ if (timeoutValue)
++ {
++ constexpr int timeoutMarginSeconds = 10;
++ return std::chrono::duration_cast<std::chrono::microseconds>(
++ std::chrono::seconds(*timeoutValue + timeoutMarginSeconds))
++ .count();
++ }
++ else
++ {
++ return std::nullopt;
++ }
++}
++
+ /**
+ * @brief Fill template for Virtual Media Item.
+ */
+@@ -712,22 +734,57 @@ inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ }
+
+ crow::connections::systemBus->async_method_call(
+- [asyncResp, secretPipe](const boost::system::error_code ec,
+- bool success) {
++ [asyncResp, service, name, imageUrl, rw, unixFd,
++ secretPipe](const boost::system::error_code ec,
++ const std::variant<int> timeoutProperty) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
+ messages::internalError(asyncResp->res);
++ return;
+ }
+- else if (!success)
++
++ auto timeout = vmParseTimeoutProperty(timeoutProperty);
++ if (timeout == std::nullopt)
+ {
+- BMCWEB_LOG_ERROR << "Service responded with error";
+- messages::generalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "Timeout property is empty.";
++ messages::internalError(asyncResp->res);
++ return;
+ }
++
++ crow::connections::systemBus->async_method_call_timed(
++ [asyncResp, secretPipe](const boost::system::error_code ec,
++ bool success) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
++ if (ec == boost::system::errc::device_or_resource_busy)
++ {
++ messages::resourceInUse(asyncResp->res);
++ }
++ else if (ec == boost::system::errc::permission_denied)
++ {
++ messages::accessDenied(asyncResp->res,
++ "VirtualMedia.Insert");
++ }
++ else
++ {
++ messages::internalError(asyncResp->res);
++ }
++ }
++ else if (!success)
++ {
++ BMCWEB_LOG_ERROR << "Service responded with error ";
++ messages::generalError(asyncResp->res);
++ }
++ },
++ service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
++ "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", *timeout,
++ imageUrl, rw, unixFd);
+ },
+ service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
+- "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
+- unixFd);
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout");
+ }
+
+ /**
+@@ -739,38 +796,49 @@ inline void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& service, const std::string& name,
+ bool legacy)
+ {
++ const std::string vmMode = legacy ? "Legacy" : "Proxy";
++ const std::string objectPath =
++ "/xyz/openbmc_project/VirtualMedia/" + vmMode + "/" + name;
++ const std::string ifaceName = "xyz.openbmc_project.VirtualMedia." + vmMode;
+
+- // Legacy mount requires parameter with image
+- if (legacy)
+- {
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](const boost::system::error_code ec) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
+-
+- messages::internalError(asyncResp->res);
+- return;
+- }
+- },
+- service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
+- "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
+- }
+- else // proxy
+- {
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](const boost::system::error_code ec) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, service, name, objectPath,
++ ifaceName](const boost::system::error_code ec,
++ const std::variant<int> timeoutProperty) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
+
+- messages::internalError(asyncResp->res);
+- return;
+- }
+- },
+- service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
+- "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
+- }
++ auto timeout = vmParseTimeoutProperty(timeoutProperty);
++ if (timeout == std::nullopt)
++ {
++ BMCWEB_LOG_ERROR << "Timeout property is empty.";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ crow::connections::systemBus->async_method_call_timed(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
++ if (ec == boost::system::errc::device_or_resource_busy)
++ {
++ messages::resourceInUse(asyncResp->res);
++ }
++ else
++ {
++ messages::internalError(asyncResp->res);
++ }
++ return;
++ }
++ },
++ service, objectPath, ifaceName, "Unmount", *timeout);
++ },
++ service, objectPath, "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout");
+ }
+
+ inline void requestNBDVirtualMediaRoutes(App& app)
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch
new file mode 100644
index 000000000..c8af3a659
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch
@@ -0,0 +1,28 @@
+From 1abf9a1d336eed835472fe933210d3be7ad5ba7a Mon Sep 17 00:00:00 2001
+From: Karol Wachowski <karol.wachowski@intel.com>
+Date: Thu, 11 Feb 2021 08:35:41 +0000
+Subject: [PATCH] Add ConnectedVia property to virtual media item template
+
+Tested: Verified that ConnectedVia property is returned and set to
+ "NotConnected" for disconnected media.
+
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 57c2bd2..de1cc94 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -200,6 +200,7 @@ inline nlohmann::json vmItemTemplate(const std::string& name,
+ item["@odata.id"] = std::move(id);
+
+ item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
++ item["ConnectedVia"] = "NotConnected";
+ item["Name"] = "Virtual Removable Media";
+ item["Id"] = resName;
+ item["WriteProtected"] = true;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch
new file mode 100644
index 000000000..439b05b3c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch
@@ -0,0 +1,175 @@
+From 437a2a854303ed4e05344684b1990806464268cd Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Thu, 1 Jul 2021 10:08:27 +0000
+Subject: [PATCH] Invalid status code from InsertMedia REST methods GET, PUT,
+ DELETE, PATCH in proxy mode
+
+Add handlers for GET, PUT, DELETE, PATCH method and function that
+checks which mode is used and set suitable status code:
+Not allowed for Legacy and Not found for Proxy.
+
+Change-Id: Ib4c0a3e9a2a8853caa74c59239d9fcfed99c5e8b
+Signed-off-by: Alicja Rybak <alicja.rybak@intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 137 +++++++++++++++++++++++++++++
+ 1 file changed, 137 insertions(+)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 3b9f7ef..7d77b9f 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -30,6 +30,117 @@
+
+ namespace redfish
+ {
++
++/**
++ * @brief Function checks if insert media request is Legacy or Proxy type
++ * and sets suitable response code for unsupported REST method.
++ *
++ */
++void CheckProxyMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
++ const crow::Request& req, const std::string& name,
++ const std::string& resName)
++{
++ if (name != "bmc")
++ {
++ messages::resourceNotFound(aResp->res, "VirtualMedia.Insert", resName);
++
++ return;
++ }
++
++ crow::connections::systemBus->async_method_call(
++ [aResp, req, resName](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ aResp->res.result(boost::beast::http::status::not_found);
++
++ return;
++ }
++
++ if (getObjectType.size() == 0)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper : No Service found";
++ aResp->res.result(boost::beast::http::status::not_found);
++ return;
++ }
++
++ std::string service = getObjectType.begin()->first;
++ BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
++
++ crow::connections::systemBus->async_method_call(
++ [service, resName, req,
++ aResp](const boost::system::error_code ec,
++ ManagedObjectType& subtree) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << "DBUS response error";
++
++ return;
++ }
++
++ for (auto& item : subtree)
++ {
++ std::string thispath = item.first.filename();
++ if (thispath.empty())
++ {
++ continue;
++ }
++
++ if (thispath != resName)
++ {
++ continue;
++ }
++
++ auto mode = item.first.parent_path();
++ auto type = mode.parent_path();
++ if (mode.filename().empty() || type.filename().empty())
++ {
++ continue;
++ }
++
++ if (type.filename() != "VirtualMedia")
++ {
++ continue;
++ }
++
++ // Check if dbus path is Legacy type
++ if (mode.filename() == "Legacy")
++ {
++ BMCWEB_LOG_DEBUG << "InsertMedia only allowed "
++ "with POST method "
++ "in legacy mode";
++ aResp->res.result(
++ boost::beast::http::status::method_not_allowed);
++
++ return;
++ }
++ // Check if dbus path is Proxy type
++ if (mode.filename() == "Proxy")
++ {
++ // Not possible in proxy mode
++ BMCWEB_LOG_DEBUG << "InsertMedia not "
++ "allowed in proxy mode";
++ aResp->res.result(
++ boost::beast::http::status::not_found);
++
++ return;
++ }
++ }
++
++ BMCWEB_LOG_DEBUG << "Parent item not found";
++ aResp->res.result(boost::beast::http::status::not_found);
++ },
++ service, "/xyz/openbmc_project/VirtualMedia",
++ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
++}
++
+ /**
+ * @brief Function extracts transfer protocol name from URI.
+ */
+@@ -844,6 +955,32 @@ inline void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+
+ inline void requestNBDVirtualMediaRoutes(App& app)
+ {
++ BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
++ "VirtualMedia.InsertMedia")
++ .privileges({{"Login"}})
++ .methods(boost::beast::http::verb::get)(
++ [](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::string& name, const std::string& resName) {
++ CheckProxyMode(asyncResp, req, name, resName);
++ });
++
++ for (auto method :
++ {boost::beast::http::verb::patch, boost::beast::http::verb::put,
++ boost::beast::http::verb::delete_})
++ {
++ BMCWEB_ROUTE(app,
++ "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
++ "VirtualMedia.InsertMedia")
++ .privileges({{"ConfigureManager"}})
++ .methods(method)(
++ [](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::string& name, const std::string& resName) {
++ CheckProxyMode(asyncResp, req, name, resName);
++ });
++ }
++
+ BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
+ "VirtualMedia.InsertMedia")
+ .privileges(redfish::privileges::postVirtualMedia)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch
new file mode 100644
index 000000000..3d80aeb20
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch
@@ -0,0 +1,43 @@
+From 89ca38dbc3433b3b734a20068e599809f3bd7b90 Mon Sep 17 00:00:00 2001
+From: Karol Wachowski <karol.wachowski@intel.com>
+Date: Tue, 23 Feb 2021 15:53:16 +0000
+Subject: [PATCH] Set Inserted redfish property for not inserted resources
+
+Tested: Verified that Inserted property is returned and set to
+ "false" for not inserted media.
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 3e28164..4c475b7 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -96,6 +96,7 @@ static void
+ BMCWEB_LOG_DEBUG << "Value Active not found";
+ return;
+ }
++ aResp->res.jsonValue["Inserted"] = *activeValue;
+
+ const std::string* endpointIdValue =
+ std::get_if<std::string>(&endpointIdProperty->second);
+@@ -107,7 +108,6 @@ static void
+ aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
+ *endpointIdValue;
+ aResp->res.jsonValue["TransferProtocolType"] = "OEM";
+- aResp->res.jsonValue["Inserted"] = *activeValue;
+ if (*activeValue == true)
+ {
+ aResp->res.jsonValue["ConnectedVia"] = "Applet";
+@@ -138,7 +138,6 @@ static void
+ }
+
+ aResp->res.jsonValue["Image"] = *imageUrlValue;
+- aResp->res.jsonValue["Inserted"] = *activeValue;
+ aResp->res.jsonValue["TransferProtocolType"] =
+ getTransferProtocolTypeFromUri(*imageUrlValue);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch
new file mode 100644
index 000000000..6ad7cf174
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch
@@ -0,0 +1,37 @@
+From 1d69a22d0ec1eddbe6d703d6824f413f6b68399e Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Thu, 1 Jul 2021 10:41:47 +0000
+Subject: [PATCH] Bmcweb handle permission denied exception
+
+Add handling of permission denied exception (EPERM) that
+can be thrown by VirtualMedia service during Mount/Unmount dbus operations.
+
+Tested:
+Verified that after mounting/unmounting HTTPS resource twice in a row in legacy mode,
+VirtualMedia returns EPERM, which bmcweb handles as 403 status code.
+
+Change-Id: Ibc18d5ec822c5072605b1fc4651389982002798b
+Signed-off-by: Alicja Rybak <alicja.rybak@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 186c04b..8e7c2e4 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -917,6 +917,11 @@ inline void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ {
+ messages::resourceInUse(asyncResp->res);
+ }
++ else if (ec == boost::system::errc::permission_denied)
++ {
++ messages::accessDenied(asyncResp->res,
++ "VirtualMedia.Insert");
++ }
+ else
+ {
+ messages::internalError(asyncResp->res);
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch
new file mode 100644
index 000000000..88fa89465
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch
@@ -0,0 +1,35 @@
+From 6f4b5fc1879f39b0f5fee0838f0ecbc481275d5e Mon Sep 17 00:00:00 2001
+From: Alicja Rybak <alicja.rybak@intel.com>
+Date: Fri, 23 Apr 2021 17:35:52 +0200
+Subject: [PATCH] Fix unmounting image in proxy mode.
+
+Sometimes Slot0 got higher key than Slot1 and erase function for Slot1
+invalidates elements with keys not less than the erased element.
+In that case invalid slot0 will be unmounted.
+Change order of calling close() and erase() functions to
+unmount correct device.
+
+Change-Id: I7a40a4518982f697d3eed635cde6d06978149cf0
+Signed-off-by: Alicja Rybak <alicja.rybak@intel.com>
+---
+ include/nbd_proxy.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp
+index 3b28823..897bcf2 100644
+--- a/include/nbd_proxy.hpp
++++ b/include/nbd_proxy.hpp
+@@ -439,9 +439,9 @@ inline void requestRoutes(App& app)
+ BMCWEB_LOG_DEBUG << "No session to close";
+ return;
+ }
++ session->second->close();
+ // Remove reference to session in global map
+ sessions.erase(session);
+- session->second->close();
+ })
+ .onmessage([](crow::websocket::Connection& conn,
+ const std::string& data, bool) {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
new file mode 100644
index 000000000..a716e612d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
@@ -0,0 +1,99 @@
+SRC_URI = "git://github.com/openbmc/bmcweb.git"
+SRCREV = "b7ff344535c42af074c60bfb272ef66a2ba157b4"
+
+DEPENDS += "boost-url"
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+# add a user called bmcweb for the server to assume
+# bmcweb is part of group shadow for non-root pam authentication
+USERADD_PARAM:${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb"
+
+GROUPADD_PARAM:${PN} = "web; redfish "
+
+SRC_URI += "file://0001-Firmware-update-configuration-changes.patch \
+ file://0002-Use-chip-id-based-UUID-for-Service-Root.patch \
+ file://0010-managers-add-attributes-for-Manager.CommandShell.patch \
+ file://0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch \
+ file://0012-Log-RedFish-event-for-Invalid-login-attempt.patch \
+ file://0013-Add-UART-routing-logic-into-host-console-connection-.patch \
+ file://0014-recommended-fixes-by-crypto-review-team.patch \
+ file://0015-Add-state-sensor-messages-to-the-registry.patch \
+ file://0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch \
+ file://0017-Add-msg-registry-for-subscription-related-actions.patch \
+ file://0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch \
+ file://0019-Add-generic-message-PropertySizeExceeded.patch \
+ file://0020-Redfish-Deny-set-AccountLockDuration-to-zero.patch \
+ file://0023-Add-get-IPMI-session-id-s-to-Redfish.patch \
+ file://0024-Add-count-sensor-type.patch \
+ file://0025-Add-Model-CoreCount-to-ProcessorSummary.patch \
+"
+
+# OOB Bios Config:
+SRC_URI += "file://biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch \
+ file://biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch \
+ file://biosconfig/0003-Add-support-to-ResetBios-action.patch \
+ file://biosconfig/0004-Add-support-to-ChangePassword-action.patch \
+ file://biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch \
+ file://biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch \
+"
+
+# Virtual Media: Backend code is not upstreamed so downstream only patches.
+SRC_URI += "file://vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch \
+ file://vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch \
+ file://vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch \
+ file://vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch \
+ file://vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch \
+ file://vm/0006-Bmcweb-handle-permission-denied-exception.patch \
+ file://vm/0007-Fix-unmounting-image-in-proxy-mode.patch \
+"
+
+# EventService: Temporary pulled to downstream. See eventservice\README for details
+SRC_URI += "file://eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch \
+ file://eventservice/0002-EventService-https-client-support.patch \
+ file://eventservice/0004-Add-Server-Sent-Events-support.patch \
+ file://eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch \
+ file://eventservice/0006-Add-EventService-SSE-filter-support.patch \
+ file://eventservice/0007-EventService-Log-events-for-subscription-actions.patch \
+ file://eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch \
+ file://eventservice/0009-Restructure-Redifsh-EventLog-Transmit-code-flow.patch \
+ file://eventservice/0010-Remove-Terminated-Event-Subscriptions.patch \
+ file://eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch \
+"
+
+# Temporary downstream mirror of upstream patches, see telemetry\README for details
+SRC_URI += " file://telemetry/0001-Add-support-for-MetricDefinition-scheme.patch \
+ file://telemetry/0002-Sync-Telmetry-service-with-EventService.patch \
+ file://telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch \
+ file://telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch \
+ file://telemetry/0005-Add-GET-method-for-TriggerCollection.patch \
+ file://telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch \
+ file://telemetry/0007-event-service-fix-added-Context-field-to-response.patch \
+ file://telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch \
+"
+
+# Temporary downstream patch for routing and privilege changes
+SRC_URI += " file://http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch \
+ file://http_routing/0002-Move-privileges-to-separate-entity.patch \
+ file://http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch \
+ file://http_routing/0004-Add-Privileges-to-Websockets.patch \
+ file://http_routing/0005-Add-Privileges-to-SseSockets.patch \
+"
+
+# Temporary fix: Move it to service file
+do_install:append() {
+ install -d ${D}/var/lib/bmcweb
+ install -d ${D}/etc/ssl/certs/authority
+}
+
+# Enable PFR support
+EXTRA_OEMESON += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-Dredfish-provisioning-feature=enabled', '', d)}"
+
+# Enable NBD proxy embedded in bmcweb
+EXTRA_OEMESON += " -Dvm-nbdproxy=enabled"
+
+# Disable dependency on external nbd-proxy application
+EXTRA_OEMESON += " -Dvm-websocket=disabled"
+RDEPENDS:${PN}:remove += "jsnbd"
+
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend
new file mode 100644
index 000000000..73c3f2190
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend
@@ -0,0 +1,21 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+SRC_URI += " file://dev_id.json \
+ file://channel_access.json \
+ file://channel_config.json \
+ file://master_write_read_white_list.json \
+ "
+
+FILES:${PN} += " \
+ ${datadir}/ipmi-providers/channel_access.json \
+ ${datadir}/ipmi-providers/channel_config.json \
+ ${datadir}/ipmi-providers/master_write_read_white_list.json \
+ "
+
+do_install:append() {
+ install -m 0644 -D ${WORKDIR}/channel_access.json \
+ ${D}${datadir}/ipmi-providers/channel_access.json
+ install -m 0644 -D ${WORKDIR}/channel_config.json \
+ ${D}${datadir}/ipmi-providers/channel_config.json
+ install -m 0644 -D ${WORKDIR}/master_write_read_white_list.json \
+ ${D}${datadir}/ipmi-providers/master_write_read_white_list.json
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json
new file mode 100644
index 000000000..299483121
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json
@@ -0,0 +1,23 @@
+{
+ "1" : {
+ "access_mode" : "always_available",
+ "user_auth_disabled" : false,
+ "per_msg_auth_disabled" : false,
+ "alerting_disabled" : false,
+ "priv_limit" : "priv-admin"
+ },
+ "2" : {
+ "access_mode" : "always_available",
+ "user_auth_disabled" : false,
+ "per_msg_auth_disabled" : false,
+ "alerting_disabled" : false,
+ "priv_limit" : "priv-admin"
+ },
+ "3" : {
+ "access_mode" : "always_available",
+ "user_auth_disabled" : false,
+ "per_msg_auth_disabled" : false,
+ "alerting_disabled" : false,
+ "priv_limit" : "priv-admin"
+ }
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json
new file mode 100644
index 000000000..73fb214a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json
@@ -0,0 +1,179 @@
+{
+ "0" : {
+ "name" : "Ipmb",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "1" : {
+ "name" : "eth1",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "lan-802.3",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "multi-session",
+ "is_ipmi" : true
+ }
+ },
+ "2" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "3" : {
+ "name" : "eth0",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "is_management_nic" : true,
+ "channel_info" : {
+ "medium_type" : "lan-802.3",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "multi-session",
+ "is_ipmi" : true
+ }
+ },
+ "4" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "5" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "6" : {
+ "name" : "SMLINK",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "7" : {
+ "name" : "ipmi_kcs4",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "system-interface",
+ "protocol_type" : "kcs",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "8" : {
+ "name" : "INTRABMC",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "oem",
+ "protocol_type" : "oem",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "9" : {
+ "name" : "SIPMB",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "10" : {
+ "name" : "PCIE",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "11" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "12" : {
+ "name" : "INTERNAL",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "13" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "14" : {
+ "name" : "SELF",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "unknown",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "15" : {
+ "name" : "ipmi_kcs3",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "system-interface",
+ "protocol_type" : "kcs",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ }
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json
new file mode 100644
index 000000000..e561569d9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json
@@ -0,0 +1,2 @@
+{"id": 35, "revision": 0, "addn_dev_support": 191,
+ "manuf_id": 343, "prod_id": 123, "aux": 0}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json
new file mode 100644
index 000000000..6fc46f452
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json
@@ -0,0 +1,76 @@
+{
+ "filters": [
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x01",
+ "slaveAddr": "0x4d",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x01",
+ "slaveAddr": "0x57",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x02",
+ "slaveAddr": "0x40",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x02",
+ "slaveAddr": "0x49",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x02",
+ "slaveAddr": "0x51",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x03",
+ "slaveAddr": "0x44",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x03",
+ "slaveAddr": "0x68",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x06",
+ "slaveAddr": "0x40",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x07",
+ "slaveAddr": "0x51",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ }
+ ]
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend
new file mode 100644
index 000000000..3a2cf0e01
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+SRC_URI += " file://config.yaml"
+
+#override source file before it is used for final FRU file (merged from multiple sources)
+do_install() {
+ cp ${WORKDIR}/config.yaml ${config_datadir}/
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml
new file mode 100644
index 000000000..e9b7a621e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml
@@ -0,0 +1,31 @@
+# A YAML similar to this example would have to be generated, for eg with MRW
+# inputs and system configuration, to depict IPMI Fru information.
+#
+# This file maps IPMI properties to phosphor dbus inventory properties
+#
+# This YAML could help generate C++ code.
+# Format of the YAML:
+# Fruid:
+# Associated Fru paths
+# d-bus Interfaces
+# d-bus Properties
+# IPMI Fru mapping
+0:
+ /system/board/WFP_Baseboard:
+ entityID: 23
+ entityInstance: 1
+ interfaces:
+ xyz.openbmc_project.Inventory.Item:
+ name:
+ IPMIFruProperty: Product Name
+ IPMIFruSection: Product
+ xyz.openbmc_project.Inventory.Decorator.Asset:
+ Manufacturer:
+ IPMIFruProperty: Manufacturer
+ IPMIFruSection: Product
+ PartNumber:
+ IPMIFruProperty: Part Number
+ IPMIFruSection: Product
+ SerialNumber:
+ IPMIFruProperty: Serial Number
+ IPMIFruSection: Product
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format
new file mode 100644
index 000000000..ea71ad6e1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format
@@ -0,0 +1,99 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+ReflowComments: true
+SortIncludes: true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch
new file mode 100644
index 000000000..a7d09f61e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch
@@ -0,0 +1,41 @@
+From f18efe239cb4bbfd6996f753ae694f81041d8d43 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Fri, 14 Feb 2020 13:13:06 -0800
+Subject: [PATCH] Fix 'Get System GUID' to use settings UUID
+
+The upstream Get System GUID command looks first for a BMC interface
+and then assumes that the UUID interface is next to that. But that is
+not the case on Intel systems where the system GUID is found in the
+settings daemon.
+
+Change-Id: I924bd05e0a546f2b30288c1faf72157296ab6579
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ apphandler.cpp | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index 90818a9..dcf2c86 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -788,8 +788,6 @@ auto ipmiAppGetBtCapabilities()
+
+ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
+ {
+- static constexpr auto bmcInterface =
+- "xyz.openbmc_project.Inventory.Item.Bmc";
+ static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID";
+ static constexpr auto uuidProperty = "UUID";
+
+@@ -798,7 +796,7 @@ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
+ {
+ // Get the Inventory object implementing BMC interface
+ auto busPtr = getSdBus();
+- auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface);
++ auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface);
+
+ // Read UUID property value from bmcObject
+ // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch
new file mode 100644
index 000000000..0d86a4223
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch
@@ -0,0 +1,89 @@
+From 58771a22dfcaa1e67bcf4fc0bd2ce0aa28c67e3f Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@linux.intel.com>
+Date: Wed, 23 Jan 2019 17:02:40 +0800
+Subject: [PATCH] Fix keep looping issue when entering OS
+
+Sometimes when entering OS, OS will keep continuously sending ipmi command
+"READ EVENT MESSAGE BUFFER" to BMC. This issue is caused by incorrect KCS
+status. If restart the host immediately while OS is still running, SMS_ATN
+will be set, after that KCS come into an incorrect status, and then KCS
+communction between BMC and OS crash. To make KCS go back to correct status
+and fix the issue, clear SMS_ATN after every time power cycle happen.
+
+Unit Test:
+ After entered OS, force reset system, after enter OS again, OS can start
+normally without keep sending READ EVENT MESSAGE BUFFER command.
+ After power on system, enter EFI SHELL, check IPMI can work
+correctly through KCS channel.
+---
+ host-cmd-manager.cpp | 33 ++++++++++++++++++++++++---------
+ 1 file changed, 24 insertions(+), 9 deletions(-)
+
+diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp
+index e52c9bb..b3a5d71 100644
+--- a/host-cmd-manager.cpp
++++ b/host-cmd-manager.cpp
+@@ -23,6 +23,8 @@ namespace command
+ constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
+ constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
+ constexpr auto HOST_TRANS_PROP = "RequestedHostTransition";
++constexpr const char* IPMI_PATH = "/xyz/openbmc_project/Ipmi/Channel/ipmi_kcs3";
++constexpr const char* IPMI_INTERFACE = "xyz.openbmc_project.Ipmi.Channel.SMS";
+
+ // For throwing exceptions
+ using namespace phosphor::logging;
+@@ -103,6 +105,20 @@ void Manager::clearQueue()
+ // `false` indicating Failure
+ std::get<CallBack>(command)(ipmiCmdData, false);
+ }
++
++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH);
++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH,
++ IPMI_INTERFACE, "clearAttention");
++
++ try
++ {
++ auto reply = this->bus.call(method);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ log<level::ERR>("Error in clearing SMS attention");
++ elog<InternalFailure>();
++ }
+ }
+
+ // Called for alerting the host
+@@ -112,9 +128,7 @@ void Manager::checkQueueAndAlertHost()
+ {
+ log<level::DEBUG>("Asserting SMS Attention");
+
+- std::string HOST_IPMI_SVC("org.openbmc.HostIpmi");
+- std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
+- std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH);
+
+ // Start the timer for this transaction
+ auto time = std::chrono::duration_cast<std::chrono::microseconds>(
+@@ -127,12 +141,13 @@ void Manager::checkQueueAndAlertHost()
+ return;
+ }
+
+- auto method =
+- this->bus.new_method_call(HOST_IPMI_SVC.c_str(), IPMI_PATH.c_str(),
+- IPMI_INTERFACE.c_str(), "setAttention");
+- auto reply = this->bus.call(method);
+-
+- if (reply.is_method_error())
++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH,
++ IPMI_INTERFACE, "setAttention");
++ try
++ {
++ auto reply = this->bus.call(method);
++ }
++ catch (const std::exception&)
+ {
+ log<level::ERR>("Error in setting SMS attention");
+ elog<InternalFailure>();
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch
new file mode 100644
index 000000000..ba8896195
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch
@@ -0,0 +1,356 @@
+From 9f4fb8a6aa076261b19c187aeef840d818158ec7 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Wed, 16 Oct 2019 14:24:20 +0800
+Subject: [PATCH] Move Set SOL config parameter to host-ipmid
+
+Move Set SOL config parameter command from net-ipmid to host-ipmid,
+so that BIOS in Intel platform can enable or disable SOL through KCS.
+Get SOL config parameter command will be moved later.
+
+Tested by:
+With the related change in phospher-ipmi-net and phospher-dbus-interface,
+Run commands:
+ipmitool raw 0x0c 0x21 0x0e 0x00 0x01
+ipmitool raw 0x0c 0x21 0x0e 0x01 0x00
+ipmitool raw 0x0c 0x21 0x0e 0x02 0x03
+ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03
+ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03
+All these commands have correct response and all dbus interface for
+sol command change to same value in above commands.
+After reboot BMC, "Progress" property in dbus interface change back
+to 0 and other properties will not reset to default value.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ host-ipmid-whitelist.conf | 1 +
+ transporthandler.cpp | 294 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 295 insertions(+)
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index 5397115..c93f3b1 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -41,6 +41,7 @@
+ 0x0A:0x48 //<Storage>:<Get SEL Time>
+ 0x0A:0x49 //<Storage>:<Set SEL Time>
+ 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters>
++0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters>
+ 0x2C:0x00 //<Group Extension>:<Group Extension Command>
+ 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities>
+ 0x2C:0x02 //<Group Extension>:<Get Power Reading>
+diff --git a/transporthandler.cpp b/transporthandler.cpp
+index 0012746..0de76c4 100644
+--- a/transporthandler.cpp
++++ b/transporthandler.cpp
+@@ -2030,8 +2030,298 @@ RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
+ } // namespace transport
+ } // namespace ipmi
+
++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
++
+ void register_netfn_transport_functions() __attribute__((constructor));
+
++static std::string
++ getSOLService(std::shared_ptr<sdbusplus::asio::connection> dbus,
++ const std::string& solPathWitheEthName)
++{
++ static std::string solService{};
++ if (solService.empty())
++ {
++ try
++ {
++ solService =
++ ipmi::getService(*dbus, solInterface, solPathWitheEthName);
++ }
++ catch (const sdbusplus::exception::SdBusError& e)
++ {
++ solService.clear();
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error: get SOL service failed");
++ return solService;
++ }
++ }
++ return solService;
++}
++
++static int setSOLParameter(const std::string& property,
++ const ipmi::Value& value, const uint8_t& channelNum)
++{
++ auto dbus = getSdBus();
++
++ std::string ethdevice = ipmi::getChannelName(channelNum);
++
++ std::string solPathWitheEthName = std::string(solPath) + ethdevice;
++
++ std::string service = getSOLService(dbus, solPathWitheEthName);
++ if (service.empty())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get SOL service failed");
++ return -1;
++ }
++ try
++ {
++ ipmi::setDbusProperty(*dbus, service, solPathWitheEthName, solInterface,
++ property, value);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error setting sol parameter");
++ return -1;
++ }
++
++ return 0;
++}
++
++static int getSOLParameter(const std::string& property, ipmi::Value& value,
++ const uint8_t& channelNum)
++{
++ auto dbus = getSdBus();
++
++ std::string ethdevice = ipmi::getChannelName(channelNum);
++
++ std::string solPathWitheEthName = std::string(solPath) + ethdevice;
++
++ std::string service = getSOLService(dbus, solPathWitheEthName);
++ if (service.empty())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get SOL service failed");
++ return -1;
++ }
++ try
++ {
++ value = ipmi::getDbusProperty(*dbus, service, solPathWitheEthName,
++ solInterface, property);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error getting sol parameter");
++ return -1;
++ }
++
++ return 0;
++}
++
++static const constexpr uint8_t encryptMask = 0x80;
++static const constexpr uint8_t encryptShift = 7;
++static const constexpr uint8_t authMask = 0x40;
++static const constexpr uint8_t authShift = 6;
++static const constexpr uint8_t privilegeMask = 0xf;
++
++namespace ipmi
++{
++constexpr Cc ccParmNotSupported = 0x80;
++constexpr Cc ccSetInProgressActive = 0x81;
++constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82;
++
++static inline auto responseParmNotSupported()
++{
++ return response(ccParmNotSupported);
++}
++static inline auto responseSetInProgressActive()
++{
++ return response(ccSetInProgressActive);
++}
++static inline auto responseSystemInfoParameterSetReadOnly()
++{
++ return response(ccSystemInfoParameterSetReadOnly);
++}
++
++} // namespace ipmi
++
++namespace sol
++{
++enum class Parameter
++{
++ progress, //!< Set In Progress.
++ enable, //!< SOL Enable.
++ authentication, //!< SOL Authentication.
++ accumulate, //!< Character Accumulate Interval & Send Threshold.
++ retry, //!< SOL Retry.
++ nvbitrate, //!< SOL non-volatile bit rate.
++ vbitrate, //!< SOL volatile bit rate.
++ channel, //!< SOL payload channel.
++ port, //!< SOL payload port.
++};
++
++enum class Privilege : uint8_t
++{
++ highestPriv,
++ callbackPriv,
++ userPriv,
++ operatorPriv,
++ adminPriv,
++ oemPriv,
++};
++
++} // namespace sol
++
++constexpr uint8_t progressMask = 0x03;
++constexpr uint8_t enableMask = 0x01;
++constexpr uint8_t retryMask = 0x07;
++
++ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum,
++ uint4_t reserved, uint8_t paramSelector,
++ uint8_t configParamData1,
++ std::optional<uint8_t> configParamData2)
++{
++ ipmi::ChannelInfo chInfo;
++ uint8_t channelNum = ipmi::convertCurrentChannelNum(
++ static_cast<uint8_t>(chNum), ctx->channel);
++ if (reserved != 0 ||
++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ ipmi_ret_t compCode =
++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo);
++ if (compCode != IPMI_CC_OK ||
++ chInfo.mediumType !=
++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ switch (static_cast<sol::Parameter>(paramSelector))
++ {
++ case sol::Parameter::progress:
++ {
++ if (configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ uint8_t progress = configParamData1 & progressMask;
++ ipmi::Value currentProgress = 0;
++ if (getSOLParameter("Progress", currentProgress, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ if ((std::get<uint8_t>(currentProgress) == 1) && (progress == 1))
++ {
++ return ipmi::responseSetInProgressActive();
++ }
++
++ if (setSOLParameter("Progress", progress, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ break;
++ }
++ case sol::Parameter::enable:
++ {
++ if (configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ bool enable = configParamData1 & enableMask;
++ if (setSOLParameter("Enable", enable, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ break;
++ }
++ case sol::Parameter::authentication:
++ {
++ if (configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ uint8_t encrypt = (configParamData1 & encryptMask) >> encryptShift;
++ uint8_t auth = (configParamData1 & authMask) >> authShift;
++ uint8_t privilege = configParamData1 & privilegeMask;
++ // For security considering encryption and authentication must be
++ // true.
++ if (!encrypt || !auth)
++ {
++ return ipmi::responseSystemInfoParameterSetReadOnly();
++ }
++ else if (privilege <
++ static_cast<uint8_t>(sol::Privilege::userPriv) ||
++ privilege > static_cast<uint8_t>(sol::Privilege::oemPriv))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ if (setSOLParameter("Privilege", privilege, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ break;
++ }
++ case sol::Parameter::accumulate:
++ {
++ if (!configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ if (*configParamData2 == 0)
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++ if (setSOLParameter("AccumulateIntervalMS", configParamData1,
++ channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ if (setSOLParameter("Threshold", *configParamData2, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ break;
++ }
++ case sol::Parameter::retry:
++ {
++ if (!configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ if ((setSOLParameter(
++ "RetryCount",
++ static_cast<uint8_t>(configParamData1 & retryMask),
++ channelNum) < 0) ||
++ (setSOLParameter("RetryIntervalMS", *configParamData2,
++ channelNum) < 0))
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ break;
++ }
++ case sol::Parameter::port:
++ {
++ return ipmi::responseSystemInfoParameterSetReadOnly();
++ }
++ case sol::Parameter::nvbitrate:
++ case sol::Parameter::vbitrate:
++ case sol::Parameter::channel:
++ default:
++ return ipmi::responseParmNotSupported();
++ }
++
++ return ipmi::responseSuccess();
++}
++
+ void register_netfn_transport_functions()
+ {
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+@@ -2040,4 +2330,8 @@ void register_netfn_transport_functions()
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+ ipmi::transport::cmdGetLanConfigParameters,
+ ipmi::Privilege::Operator, ipmi::transport::getLan);
++
++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
++ ipmi::transport::cmdSetSolConfigParameters,
++ ipmi::Privilege::Admin, setSOLConfParams);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch
new file mode 100644
index 000000000..d6ba70562
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch
@@ -0,0 +1,259 @@
+From ff1d4198e8ad8f824f34fb9d261ea0e25179f070 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Thu, 11 Jul 2019 00:32:58 +0800
+Subject: [PATCH] Move Get SOL config parameter to host-ipmid
+
+Move Get SOL config parameter command from net-ipmid to host-ipmid.
+
+Tested:
+Run command ipmitool sol info 1
+Set in progress : set-complete
+Enabled : true
+Force Encryption : false
+Force Authentication : false
+Privilege Level : ADMINISTRATOR
+Character Accumulate Level (ms) : 60
+Character Send Threshold : 96
+Retry Count : 6
+Retry Interval (ms) : 200
+Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting
+Non-Volatile Bit Rate (kbps) : 115.2
+Payload Channel : 1 (0x01)
+Payload Port : 623
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ host-ipmid-whitelist.conf | 1 +
+ transporthandler.cpp | 191 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 192 insertions(+)
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index c93f3b1..730437d 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -42,6 +42,7 @@
+ 0x0A:0x49 //<Storage>:<Set SEL Time>
+ 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters>
+ 0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters>
++0x0C:0x22 //<Transport>:<Get SOL Configuration Parameters>
+ 0x2C:0x00 //<Group Extension>:<Group Extension Command>
+ 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities>
+ 0x2C:0x02 //<Group Extension>:<Get Power Reading>
+diff --git a/transporthandler.cpp b/transporthandler.cpp
+index 0de76c4..b81e0d5 100644
+--- a/transporthandler.cpp
++++ b/transporthandler.cpp
+@@ -2120,6 +2120,28 @@ static int getSOLParameter(const std::string& property, ipmi::Value& value,
+ return 0;
+ }
+
++constexpr const char* consoleInterface = "xyz.openbmc_project.console";
++constexpr const char* consolePath = "/xyz/openbmc_project/console";
++static int getSOLBaudRate(ipmi::Value& value)
++{
++ auto dbus = getSdBus();
++
++ try
++ {
++ value =
++ ipmi::getDbusProperty(*dbus, "xyz.openbmc_project.console",
++ consolePath, consoleInterface, "baudrate");
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error getting sol baud rate");
++ return -1;
++ }
++
++ return 0;
++}
++
+ static const constexpr uint8_t encryptMask = 0x80;
+ static const constexpr uint8_t encryptShift = 7;
+ static const constexpr uint8_t authMask = 0x40;
+@@ -2322,6 +2344,171 @@ ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum,
+ return ipmi::responseSuccess();
+ }
+
++static const constexpr uint8_t retryCountMask = 0x07;
++static constexpr uint16_t ipmiStdPort = 623;
++static constexpr uint8_t solParameterRevision = 0x11;
++ipmi::RspType<uint8_t, std::optional<uint8_t>, std::optional<uint8_t>>
++ getSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, uint3_t reserved,
++ bool getParamRev, uint8_t paramSelector,
++ uint8_t setSelector, uint8_t blockSelector)
++{
++ ipmi::ChannelInfo chInfo;
++ uint8_t channelNum = ipmi::convertCurrentChannelNum(
++ static_cast<uint8_t>(chNum), ctx->channel);
++ if (reserved != 0 ||
++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))) ||
++ (ipmi::EChannelSessSupported::none ==
++ ipmi::getChannelSessionSupport(static_cast<uint8_t>(channelNum))))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++ ipmi_ret_t compCode =
++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo);
++ if (compCode != IPMI_CC_OK ||
++ chInfo.mediumType !=
++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ if (getParamRev)
++ {
++ return ipmi::responseSuccess(solParameterRevision, std::nullopt,
++ std::nullopt);
++ }
++
++ ipmi::Value value;
++ switch (static_cast<sol::Parameter>(paramSelector))
++ {
++ case sol::Parameter::progress:
++ {
++ if (getSOLParameter("Progress", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(
++ solParameterRevision, std::get<uint8_t>(value), std::nullopt);
++ }
++ case sol::Parameter::enable:
++ {
++ if (getSOLParameter("Enable", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(
++ solParameterRevision,
++ static_cast<uint8_t>(std::get<bool>(value)), std::nullopt);
++ }
++ case sol::Parameter::authentication:
++ {
++ uint8_t authentication = 0;
++ if (getSOLParameter("Privilege", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ authentication = (std::get<uint8_t>(value) & 0x0f);
++
++ if (getSOLParameter("ForceAuthentication", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ authentication |=
++ (static_cast<uint8_t>(std::get<bool>(value)) << 6);
++
++ if (getSOLParameter("ForceEncryption", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ authentication |=
++ (static_cast<uint8_t>(std::get<bool>(value)) << 7);
++ return ipmi::responseSuccess(solParameterRevision, authentication,
++ std::nullopt);
++ }
++ case sol::Parameter::accumulate:
++ {
++ if (getSOLParameter("AccumulateIntervalMS", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ ipmi::Value value1;
++ if (getSOLParameter("Threshold", value1, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(solParameterRevision,
++ std::get<uint8_t>(value),
++ std::get<uint8_t>(value1));
++ }
++ case sol::Parameter::retry:
++ {
++ if (getSOLParameter("RetryCount", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ ipmi::Value value1;
++ if (getSOLParameter("RetryIntervalMS", value1, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(
++ solParameterRevision, std::get<uint8_t>(value) & retryCountMask,
++ std::get<uint8_t>(value1));
++ }
++ case sol::Parameter::channel:
++ {
++ return ipmi::responseSuccess(solParameterRevision, channelNum,
++ std::nullopt);
++ }
++ case sol::Parameter::port:
++ {
++ uint16_t port = htole16(ipmiStdPort);
++ auto buffer = reinterpret_cast<const uint8_t*>(&port);
++ return ipmi::responseSuccess(solParameterRevision, buffer[0],
++ buffer[1]);
++ }
++ case sol::Parameter::nvbitrate:
++ {
++ if (getSOLBaudRate(value) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ uint8_t bitRate = 0;
++ uint32_t* pBaudRate = std::get_if<uint32_t>(&value);
++ if (!pBaudRate)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Failed to get valid baud rate from D-Bus interface");
++ }
++ switch (*pBaudRate)
++ {
++ case 9600:
++ bitRate = 0x06;
++ break;
++ case 19200:
++ bitRate = 0x07;
++ break;
++ case 38400:
++ bitRate = 0x08;
++ break;
++ case 57600:
++ bitRate = 0x09;
++ break;
++ case 115200:
++ bitRate = 0x0a;
++ break;
++ default:
++ break;
++ }
++ return ipmi::responseSuccess(solParameterRevision, bitRate,
++ std::nullopt);
++ }
++ default:
++ return ipmi::responseParmNotSupported();
++ }
++}
++
+ void register_netfn_transport_functions()
+ {
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+@@ -2334,4 +2521,8 @@ void register_netfn_transport_functions()
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+ ipmi::transport::cmdSetSolConfigParameters,
+ ipmi::Privilege::Admin, setSOLConfParams);
++
++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
++ ipmi::transport::cmdGetSolConfigParameters,
++ ipmi::Privilege::User, getSOLConfParams);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch
new file mode 100644
index 000000000..112c1ffab
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch
@@ -0,0 +1,292 @@
+From 99f63d2af9f45badaa8aff4ef958443bea62ede8 Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Mon, 3 Jun 2019 17:01:47 -0700
+Subject: [PATCH] Update IPMI Chassis Control command
+
+This change updates the IPMI Chassis Control command to use the new
+host state transitions. This allows each chassis control action
+to more closely follow the behavior defined in the IPMI spec.
+
+ref: https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/22358
+
+Tested:
+Ran each IPMI chassis control command to confirm the expected
+behavior:
+ipmitool power on: system is powered-on
+ipmitool power off: system is forced off
+ipmitool power cycle: system is forced off then powered-on
+ipmitool power reset: system is hard reset
+ipmitool power soft: soft power-off requested from system software
+
+Change-Id: Ic9fba3ca4abd9a758eb88f1e6ee09f7ca64ff80a
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ chassishandler.cpp | 204 +++++++++++----------------------------------
+ 1 file changed, 48 insertions(+), 156 deletions(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index dfbe004be490..cd0ba3402f84 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -32,6 +32,7 @@
+ #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
+ #include <xyz/openbmc_project/Control/Boot/Type/server.hpp>
+ #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
++#include <xyz/openbmc_project/State/Chassis/server.hpp>
+ #include <xyz/openbmc_project/State/Host/server.hpp>
+ #include <xyz/openbmc_project/State/PowerOnHours/server.hpp>
+
+@@ -815,59 +816,63 @@ ipmi::RspType<> ipmiSetChassisCap(bool intrusion, bool fpLockout,
+ //------------------------------------------
+ // Calls into Host State Manager Dbus object
+ //------------------------------------------
+-int initiate_state_transition(State::Host::Transition transition)
++int initiateHostStateTransition(State::Host::Transition transition)
+ {
+ // OpenBMC Host State Manager dbus framework
+- constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0";
+- constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host";
+- constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
+- constexpr auto PROPERTY = "RequestedHostTransition";
++ constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
++ constexpr auto hostStateIntf = "xyz.openbmc_project.State.Host";
+
+- // sd_bus error
+- int rc = 0;
+- char* busname = NULL;
++ auto service = ipmi::getService(*getSdBus(), hostStateIntf, hostStatePath);
+
+- // SD Bus error report mechanism.
+- sd_bus_error bus_error = SD_BUS_ERROR_NULL;
++ // Convert to string equivalent of the passed in transition enum.
++ auto request = State::convertForMessage(transition);
+
+- // Gets a hook onto either a SYSTEM or SESSION bus
+- sd_bus* bus_type = ipmid_get_sd_bus_connection();
+- rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname);
+- if (rc < 0)
++ try
++ {
++ ipmi::setDbusProperty(*getSdBus(), service, hostStatePath,
++ hostStateIntf, "RequestedHostTransition",
++ request);
++ }
++ catch (std::exception& e)
+ {
+ log<level::ERR>(
+- "Failed to get bus name",
+- entry("ERRNO=0x%X, OBJPATH=%s", -rc, HOST_STATE_MANAGER_ROOT));
+- return rc;
++ "Failed to initiate transition",
++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str()));
++ return -1;
+ }
++ return 0;
++}
++
++//------------------------------------------
++// Calls into Chassis State Manager Dbus object
++//------------------------------------------
++int initiateChassisStateTransition(State::Chassis::Transition transition)
++{
++ // OpenBMC Chassis State Manager dbus framework
++ constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0";
++ constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis";
++
++ auto service =
++ ipmi::getService(*getSdBus(), chassisStateIntf, chassisStatePath);
+
+ // Convert to string equivalent of the passed in transition enum.
+ auto request = State::convertForMessage(transition);
+
+- rc = sd_bus_call_method(bus_type, // On the system bus
+- busname, // Service to contact
+- HOST_STATE_MANAGER_ROOT, // Object path
+- DBUS_PROPERTY_IFACE, // Interface name
+- "Set", // Method to be called
+- &bus_error, // object to return error
+- nullptr, // Response buffer if any
+- "ssv", // Takes 3 arguments
+- HOST_STATE_MANAGER_IFACE, PROPERTY, "s",
+- request.c_str());
+- if (rc < 0)
+- {
+- log<level::ERR>("Failed to initiate transition",
+- entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str()));
++ try
++ {
++ ipmi::setDbusProperty(*getSdBus(), service, chassisStatePath,
++ chassisStateIntf, "RequestedPowerTransition",
++ request);
+ }
+- else
++ catch (std::exception& e)
+ {
+- log<level::INFO>("Transition request initiated successfully");
++ log<level::ERR>(
++ "Failed to initiate transition",
++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str()));
++ return -1;
+ }
+
+- sd_bus_error_free(&bus_error);
+- free(busname);
+-
+- return rc;
++ return 0;
+ }
+
+ //------------------------------------------
+@@ -1302,76 +1307,6 @@ ipmi::RspType<uint4_t, // Restart Cause
+ return ipmi::responseSuccess(cause.value(), reserved, channel);
+ }
+
+-//-------------------------------------------------------------
+-// Send a command to SoftPowerOff application to stop any timer
+-//-------------------------------------------------------------
+-int stop_soft_off_timer()
+-{
+- constexpr auto iface = "org.freedesktop.DBus.Properties";
+- constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal."
+- "SoftPowerOff";
+-
+- constexpr auto property = "ResponseReceived";
+- constexpr auto value = "xyz.openbmc_project.Ipmi.Internal."
+- "SoftPowerOff.HostResponse.HostShutdown";
+-
+- // Get the system bus where most system services are provided.
+- auto bus = ipmid_get_sd_bus_connection();
+-
+- // Get the service name
+- // TODO openbmc/openbmc#1661 - Mapper refactor
+- //
+- // See openbmc/openbmc#1743 for some details but high level summary is that
+- // for now the code will directly call the soft off interface due to a
+- // race condition with mapper usage
+- //
+- // char *busname = nullptr;
+- // auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname);
+- // if (r < 0)
+- //{
+- // fprintf(stderr, "Failed to get %s bus name: %s\n",
+- // SOFTOFF_OBJPATH, -r);
+- // return r;
+- //}
+-
+- // No error object or reply expected.
+- int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface,
+- "Set", nullptr, nullptr, "ssv", soft_off_iface,
+- property, "s", value);
+- if (rc < 0)
+- {
+- log<level::ERR>("Failed to set property in SoftPowerOff object",
+- entry("ERRNO=0x%X", -rc));
+- }
+-
+- // TODO openbmc/openbmc#1661 - Mapper refactor
+- // free(busname);
+- return rc;
+-}
+-
+-//----------------------------------------------------------------------
+-// Create file to indicate there is no need for softoff notification to host
+-//----------------------------------------------------------------------
+-void indicate_no_softoff_needed()
+-{
+- fs::path path{HOST_INBAND_REQUEST_DIR};
+- if (!fs::is_directory(path))
+- {
+- fs::create_directory(path);
+- }
+-
+- // Add the host instance (default 0 for now) to the file name
+- std::string file{HOST_INBAND_REQUEST_FILE};
+- auto size = std::snprintf(nullptr, 0, file.c_str(), 0);
+- size++; // null
+- std::unique_ptr<char[]> buf(new char[size]);
+- std::snprintf(buf.get(), size, file.c_str(), 0);
+-
+- // Append file name to directory and create it
+- path /= buf.get();
+- std::ofstream(path.c_str());
+-}
+-
+ /** @brief Implementation of chassis control command
+ *
+ * @param - chassisControl command byte
+@@ -1384,66 +1319,22 @@ ipmi::RspType<> ipmiChassisControl(uint8_t chassisControl)
+ switch (chassisControl)
+ {
+ case CMD_POWER_ON:
+- rc = initiate_state_transition(State::Host::Transition::On);
++ rc = initiateHostStateTransition(State::Host::Transition::On);
+ break;
+ case CMD_POWER_OFF:
+- // This path would be hit in 2 conditions.
+- // 1: When user asks for power off using ipmi chassis command 0x04
+- // 2: Host asking for power off post shutting down.
+-
+- // If it's a host requested power off, then need to nudge Softoff
+- // application that it needs to stop the watchdog timer if running.
+- // If it is a user requested power off, then this is not really
+- // needed. But then we need to differentiate between user and host
+- // calling this same command
+-
+- // For now, we are going ahead with trying to nudge the soft off and
+- // interpret the failure to do so as a non softoff case
+- rc = stop_soft_off_timer();
+-
+- // Only request the Off transition if the soft power off
+- // application is not running
+- if (rc < 0)
+- {
+- // First create a file to indicate to the soft off application
+- // that it should not run. Not doing this will result in State
+- // manager doing a default soft power off when asked for power
+- // off.
+- indicate_no_softoff_needed();
+-
+- // Now request the shutdown
+- rc = initiate_state_transition(State::Host::Transition::Off);
+- }
+- else
+- {
+- log<level::INFO>("Soft off is running, so let shutdown target "
+- "stop the host");
+- }
++ rc =
++ initiateChassisStateTransition(State::Chassis::Transition::Off);
+ break;
+-
+ case CMD_HARD_RESET:
+- rc = initiate_state_transition(
++ rc = initiateHostStateTransition(
+ State::Host::Transition::ForceWarmReboot);
+ break;
+ case CMD_POWER_CYCLE:
+- // SPEC has a section that says certain implementations can trigger
+- // PowerOn if power is Off when a command to power cycle is
+- // requested
+-
+- // First create a file to indicate to the soft off application
+- // that it should not run since this is a direct user initiated
+- // power reboot request (i.e. a reboot request that is not
+- // originating via a soft power off SMS request)
+- indicate_no_softoff_needed();
+-
+- rc = initiate_state_transition(State::Host::Transition::Reboot);
++ rc = initiateHostStateTransition(State::Host::Transition::Reboot);
+ break;
+-
+ case CMD_SOFT_OFF_VIA_OVER_TEMP:
+- // Request Host State Manager to do a soft power off
+- rc = initiate_state_transition(State::Host::Transition::Off);
++ rc = initiateHostStateTransition(State::Host::Transition::Off);
+ break;
+-
+ case CMD_PULSE_DIAGNOSTIC_INTR:
+ rc = setNmiProperty(true);
+ break;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch
new file mode 100644
index 000000000..d0f9331d2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch
@@ -0,0 +1,140 @@
+From cfb5e13388531e1317eeb3ccf0f8eef0c6eeca60 Mon Sep 17 00:00:00 2001
+From: Ren Yu <yux.ren@intel.com>
+Date: Tue, 28 May 2019 17:11:17 +0800
+Subject: [PATCH] Save the pre-timeout interrupt in dbus property
+
+Get the watchdog pre-timeout interrupt value from ipmi watchdog set command,
+and store it into dbus property.
+
+Tested:
+Config IPMI watchdog: BIOS FRB2 Power Cycle after 1 seconds:
+ipmitool raw 0x06 0x24 0x01 0x13 0x0 0x2 0xa 0x00
+Start watchdog:
+Ipmitool mc watchdog reset
+Check the watchdog pre-timeout interrupt in below:
+https://BMCIP/redfish/v1/Systems/system/LogServices/EventLog/Entries
+
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+---
+ app/watchdog.cpp | 47 ++++++++++++++++++++++++++++++++++++++++
+ app/watchdog_service.cpp | 6 +++++
+ app/watchdog_service.hpp | 9 ++++++++
+ 3 files changed, 62 insertions(+)
+
+diff --git a/app/watchdog.cpp b/app/watchdog.cpp
+index 03c373e..cb0b1fd 100644
+--- a/app/watchdog.cpp
++++ b/app/watchdog.cpp
+@@ -80,6 +80,7 @@ ipmi::RspType<> ipmiAppResetWatchdogTimer()
+
+ static constexpr uint8_t wd_dont_stop = 0x1 << 6;
+ static constexpr uint8_t wd_timeout_action_mask = 0x3;
++static constexpr uint8_t wdPreTimeoutInterruptMask = 0x3;
+
+ static constexpr uint8_t wdTimerUseResTimer1 = 0x0;
+ static constexpr uint8_t wdTimerUseResTimer2 = 0x6;
+@@ -127,6 +128,45 @@ WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action)
+ }
+ }
+
++enum class IpmiPreTimeoutInterrupt : uint8_t
++{
++ None = 0x0,
++ SMI = 0x1,
++ NMI = 0x2,
++ MI = 0x3,
++};
++/** @brief Converts an IPMI Watchdog PreTimeoutInterrupt to DBUS defined action
++ * @param[in] ipmi_action The IPMI Watchdog PreTimeoutInterrupt
++ * @return The Watchdog PreTimeoutInterrupt that the ipmi_action maps to
++ */
++WatchdogService::PreTimeoutInterruptAction ipmiPreTimeoutInterruptToWdAction(
++ IpmiPreTimeoutInterrupt ipmiPreTimeOutInterrupt)
++{
++ switch (ipmiPreTimeOutInterrupt)
++ {
++ case IpmiPreTimeoutInterrupt::None:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::None;
++ }
++ case IpmiPreTimeoutInterrupt::SMI:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::SMI;
++ }
++ case IpmiPreTimeoutInterrupt::NMI:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::NMI;
++ }
++ case IpmiPreTimeoutInterrupt::MI:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::MI;
++ }
++ default:
++ {
++ throw std::domain_error("IPMI PreTimeoutInterrupt is invalid");
++ }
++ }
++}
++
+ enum class IpmiTimerUse : uint8_t
+ {
+ Reserved = 0x0,
+@@ -250,6 +290,13 @@ ipmi::RspType<>
+ // Mark as initialized so that future resets behave correctly
+ wd_service.setInitialized(true);
+
++ // pretimeOutAction
++ const auto ipmiPreTimeoutInterrupt =
++ static_cast<IpmiPreTimeoutInterrupt>(wdPreTimeoutInterruptMask &
++ (static_cast<uint8_t>(preTimeoutInterrupt)));
++ wd_service.setPreTimeoutInterrupt(
++ ipmiPreTimeoutInterruptToWdAction(ipmiPreTimeoutInterrupt));
++
+ lastCallSuccessful = true;
+ return ipmi::responseSuccess();
+ }
+diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp
+index 3534e89..4df1ab6 100644
+--- a/app/watchdog_service.cpp
++++ b/app/watchdog_service.cpp
+@@ -198,3 +198,9 @@ void WatchdogService::setInterval(uint64_t interval)
+ {
+ setProperty("Interval", interval);
+ }
++
++void WatchdogService::setPreTimeoutInterrupt(
++ PreTimeoutInterruptAction preTimeoutInterrupt)
++{
++ setProperty("PreTimeoutInterrupt", convertForMessage(preTimeoutInterrupt));
++}
+\ No newline at end of file
+diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp
+index 141bdb7..32b7461 100644
+--- a/app/watchdog_service.hpp
++++ b/app/watchdog_service.hpp
+@@ -15,6 +15,8 @@ class WatchdogService
+
+ using Action =
+ sdbusplus::xyz::openbmc_project::State::server::Watchdog::Action;
++ using PreTimeoutInterruptAction = sdbusplus::xyz::openbmc_project::State::
++ server::Watchdog::PreTimeoutInterruptAction;
+ using TimerUse =
+ sdbusplus::xyz::openbmc_project::State::server::Watchdog::TimerUse;
+
+@@ -92,6 +94,13 @@ class WatchdogService
+ */
+ void setInterval(uint64_t interval);
+
++ /** @brief Sets the value of the PreTimeoutInterrupt property on the host
++ * watchdog
++ *
++ * @param[in] PreTimeoutInterrupt - The new PreTimeoutInterrupt value
++ */
++ void setPreTimeoutInterrupt(PreTimeoutInterruptAction preTimeoutInterrupt);
++
+ private:
+ /** @brief sdbusplus handle */
+ sdbusplus::bus::bus bus;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service
new file mode 100644
index 000000000..1e45ee6c9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Phosphor Inband IPMI
+
+[Service]
+Restart=always
+RestartSec=5
+StartLimitBurst=10
+ExecStart=/usr/bin/env ipmid
+SyslogIdentifier=ipmid
+RuntimeDirectory = ipmi
+RuntimeDirectoryPreserve = yes
+StateDirectory = ipmi
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp
new file mode 100644
index 000000000..856a80fbc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp
@@ -0,0 +1,147 @@
+/* Copyright 2019 Intel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dcmihandler.hpp"
+
+#include <cstdint>
+#include <ipmid/api-types.hpp>
+#include <ipmid/api.hpp>
+#include <ipmid/message.hpp>
+#include <ipmid/message/types.hpp>
+#include <ipmid/utils.hpp>
+#include <vector>
+
+enum class oemLanParam : uint8_t
+{
+ intelHostnameConfig = 0xc7,
+};
+
+constexpr size_t IpmiHostnameLen = 16;
+constexpr uint8_t CurrentRevision = 0x11; // Current rev per IPMI Spec 2.0
+
+constexpr ipmi::Cc ccParamNotSupported = 0x80;
+constexpr ipmi::Cc ccUnprintable = 0x90;
+
+namespace ipmi::transport
+{
+
+constexpr auto validHostnameChars =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX"
+ "YZ0123456789-";
+constexpr int lanOemHostnameLength = 64;
+
+RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
+{
+ std::vector<uint8_t> dataBytes;
+ switch (static_cast<oemLanParam>(parameter))
+ {
+ case oemLanParam::intelHostnameConfig:
+ {
+ static std::array<uint8_t, lanOemHostnameLength> blockData;
+ uint8_t block = 0;
+ uint8_t complete = 0;
+ if ((req.unpack(block, complete, dataBytes) != 0) ||
+ (!req.fullyUnpacked()))
+ {
+ return responseReqDataLenInvalid();
+ }
+
+ size_t numDataBytes = req.size() - 4;
+ if ((numDataBytes > IpmiHostnameLen) ||
+ (!complete && (numDataBytes < IpmiHostnameLen)))
+ {
+ return responseReqDataLenInvalid();
+ }
+
+ if (!((block > 0) && (block < 5)) ||
+ ((complete != 0) && (complete != 1)))
+ {
+ return responseInvalidFieldRequest();
+ }
+
+ if (block == 1)
+ {
+ blockData.fill(0);
+ }
+
+ std::copy(dataBytes.begin(), dataBytes.end(),
+ blockData.data() + ((block - 1) * IpmiHostnameLen));
+ if (complete)
+ {
+ blockData[lanOemHostnameLength - 1] = 0;
+ // check hostname, and write it
+ std::string newHostname(
+ reinterpret_cast<char*>(blockData.data()),
+ lanOemHostnameLength);
+ size_t firstNull = newHostname.find_first_of('\0');
+ if (newHostname.find_first_not_of(validHostnameChars) !=
+ firstNull)
+ {
+ return response(ccUnprintable);
+ }
+ std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
+ ipmi::setDbusProperty(*busp, ::dcmi::networkServiceName,
+ ::dcmi::networkConfigObj,
+ ::dcmi::networkConfigIntf,
+ ::dcmi::hostNameProp, newHostname);
+ }
+ return responseSuccess();
+ }
+ default:
+ return response(ccParamNotSupported);
+ }
+ return response(ccParamNotSupported);
+}
+
+RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
+ uint8_t set, uint8_t block)
+{
+ message::Payload message;
+ message.pack(CurrentRevision);
+ oemLanParam param = static_cast<oemLanParam>(parameter);
+ switch (param)
+ {
+ case oemLanParam::intelHostnameConfig:
+ {
+ if (set != 0)
+ {
+ return responseInvalidFieldRequest();
+ }
+ if ((block < 1) || (block > 4))
+ {
+ return responseInvalidFieldRequest();
+ }
+ std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
+ auto service = ipmi::getService(*busp, ::dcmi::networkConfigIntf,
+ ::dcmi::networkConfigObj);
+ auto value = ipmi::getDbusProperty(
+ *busp, service, ::dcmi::networkConfigObj,
+ ::dcmi::networkConfigIntf, ::dcmi::hostNameProp);
+ std::string hostname = std::get<std::string>(value);
+ std::array<char, IpmiHostnameLen> buf = {0};
+ size_t head = (block - 1) * IpmiHostnameLen;
+ if (head < hostname.size())
+ {
+ size_t numToCopy = hostname.size() - head;
+ numToCopy = std::min(IpmiHostnameLen, numToCopy);
+ hostname.copy(buf.data(), numToCopy, head);
+ }
+ message.pack(buf);
+ return responseSuccess(std::move(message));
+ }
+ }
+ return response(ccParamNotSupported);
+}
+} // namespace ipmi::transport
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
new file mode 100644
index 000000000..87aab6f79
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
@@ -0,0 +1,38 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+PROJECT_SRC_DIR := "${THISDIR}/${PN}"
+
+#SRC_URI += "git://github.com/openbmc/phosphor-host-ipmid"
+SRCREV = "78fe1b14f60d55ae335369fb2c6e81ed9ac6d865"
+
+SRC_URI += "file://phosphor-ipmi-host.service \
+ file://0010-fix-get-system-GUID-ipmi-command.patch \
+ file://0053-Fix-keep-looping-issue-when-entering-OS.patch \
+ file://0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch \
+ file://0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch \
+ file://0062-Update-IPMI-Chassis-Control-command.patch \
+ file://0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch \
+ "
+
+EXTRA_OECONF:append = " --disable-i2c-whitelist-check"
+EXTRA_OECONF:append = " --enable-transport-oem=yes"
+EXTRA_OECONF:append = " --disable-boot-flag-safe-mode-support"
+EXTRA_OECONF:append = " --disable-ipmi-whitelist"
+
+RDEPENDS:${PN}:remove = "clear-once"
+
+# remove the softpoweroff service since we do not need it
+SYSTEMD_SERVICE:${PN}:remove = " \
+ xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service"
+
+SYSTEMD_LINK:${PN}:remove = " \
+ ../xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service:obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \
+ "
+
+do_compile:prepend(){
+ cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
+}
+
+do_install:append(){
+ rm -f ${D}/${bindir}/phosphor-softpoweroff
+ rm -f ${S}/transporthandler_oem.cpp
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch
new file mode 100644
index 000000000..d071ebd67
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch
@@ -0,0 +1,535 @@
+From 42231615d6a1effbfaa581ca41c0d406174feee8 Mon Sep 17 00:00:00 2001
+From: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@linux.intel.com>
+Date: Mon, 23 Mar 2020 22:19:07 +0530
+Subject: [PATCH] Add dbus method SlotIpmbRequest
+
+Added dbus method SlotIpmbRequest which enables the applications to
+communicate with add-in cards.
+
+This is submitted in down stream because SlotIpmbRequest uses hold and
+unhold mux kernel patches which are downstream only patches.
+
+Tested:
+
+busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb
+/xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb SlotIpmbRequest
+"yyyyyay" <valid_addressType> <valid_slot> <valid_slaveAddr> <valid_netFun> <valid_cmd> <data> // method call
+(iyyyyay) 0 7 0 1 0 15 0 0 0 0 2 12 87 1 0 0 0 0 0 0 0 // success
+
+busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb
+/xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb SlotIpmbRequest
+"yyyyyay" <valid_addressType> <invalid_slot> <valid_slaveAddr> <valid_netFun> <valid_cmd> <data> // method call
+(iyyyyay) 4 0 0 0 0 0 // failure
+
+busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb
+/xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb SlotIpmbRequest
+"yyyyyay" <valid_addressType> <valid_slot> <invalid_slaveAddr> <valid_netFun> <valid_cmd> <data> // method call
+(iyyyyay) 4 0 0 0 0 0 // failure
+
+//This ipmi command internally calls the dbus method SlotIpmbRequest.
+ipmitool raw 0x3e 0x51 0 0x01 0xb0 0x6 1
+00 00 00 00 00 02 0c 57 01 00 00 00 00 00 00 00 //success
+
+Note: Tested for all possible negative test cases and it works fine.
+
+Signed-off-by: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@intel.com>
+---
+ CMakeLists.txt | 2 +-
+ include/linux/i2c.h | 159 +++++++++++++++++++++++++++++++
+ ipmb-channels.json | 6 ++
+ ipmbbridged.cpp | 221 +++++++++++++++++++++++++++++++++++++++++++-
+ ipmbbridged.hpp | 8 +-
+ 5 files changed, 392 insertions(+), 4 deletions(-)
+ create mode 100644 include/linux/i2c.h
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 4acdccf..3484a58 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -8,7 +8,7 @@ set (CMAKE_CXX_STANDARD_REQUIRED ON)
+ #set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+ #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+-include_directories (${CMAKE_CURRENT_SOURCE_DIR})
++include_directories (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include)
+ find_package (Boost REQUIRED)
+ include_directories (${Boost_INCLUDE_DIRS})
+ add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+new file mode 100644
+index 0000000..a1db9b1
+--- /dev/null
++++ b/include/linux/i2c.h
+@@ -0,0 +1,159 @@
++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
++/* ------------------------------------------------------------------------- */
++/* */
++/* i2c.h - definitions for the i2c-bus interface */
++/* */
++/* ------------------------------------------------------------------------- */
++/* Copyright (C) 1995-2000 Simon G. Vogl
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ MA 02110-1301 USA. */
++/* ------------------------------------------------------------------------- */
++
++/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
++ Frodo Looijaard <frodol@dds.nl> */
++
++#ifndef _UAPI_LINUX_I2C_H
++#define _UAPI_LINUX_I2C_H
++
++#include <linux/types.h>
++
++/**
++ * struct i2c_msg - an I2C transaction segment beginning with START
++ * @addr: Slave address, either seven or ten bits. When this is a ten
++ * bit address, I2C_M_TEN must be set in @flags and the adapter
++ * must support I2C_FUNC_10BIT_ADDR.
++ * @flags: I2C_M_RD is handled by all adapters. No other flags may be
++ * provided unless the adapter exported the relevant I2C_FUNC_*
++ * flags through i2c_check_functionality().
++ * @len: Number of data bytes in @buf being read from or written to the
++ * I2C slave address. For read transactions where I2C_M_RECV_LEN
++ * is set, the caller guarantees that this buffer can hold up to
++ * 32 bytes in addition to the initial length byte sent by the
++ * slave (plus, if used, the SMBus PEC); and this value will be
++ * incremented by the number of block data bytes received.
++ * @buf: The buffer into which data is read, or from which it's written.
++ *
++ * An i2c_msg is the low level representation of one segment of an I2C
++ * transaction. It is visible to drivers in the @i2c_transfer() procedure,
++ * to userspace from i2c-dev, and to I2C adapter drivers through the
++ * @i2c_adapter.@master_xfer() method.
++ *
++ * Except when I2C "protocol mangling" is used, all I2C adapters implement
++ * the standard rules for I2C transactions. Each transaction begins with a
++ * START. That is followed by the slave address, and a bit encoding read
++ * versus write. Then follow all the data bytes, possibly including a byte
++ * with SMBus PEC. The transfer terminates with a NAK, or when all those
++ * bytes have been transferred and ACKed. If this is the last message in a
++ * group, it is followed by a STOP. Otherwise it is followed by the next
++ * @i2c_msg transaction segment, beginning with a (repeated) START.
++ *
++ * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
++ * passing certain @flags may have changed those standard protocol behaviors.
++ * Those flags are only for use with broken/nonconforming slaves, and with
++ * adapters which are known to support the specific mangling options they
++ * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
++ */
++struct i2c_msg {
++ __u16 addr; /* slave address */
++ __u16 flags;
++#define I2C_M_RD 0x0001 /* read data, from slave to master */
++ /* I2C_M_RD is guaranteed to be 0x0001! */
++#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
++#define I2C_M_HOLD 0x0100 /* for holding a mux path */
++#define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */
++ /* makes only sense in kernelspace */
++ /* userspace buffers are copied anyway */
++#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
++#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
++#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
++#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
++#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
++#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
++ __u16 len; /* msg length */
++ __u8 *buf; /* pointer to msg data */
++};
++
++/* To determine what functionality is present */
++
++#define I2C_FUNC_I2C 0x00000001
++#define I2C_FUNC_10BIT_ADDR 0x00000002
++#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */
++#define I2C_FUNC_SMBUS_PEC 0x00000008
++#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */
++#define I2C_FUNC_SLAVE 0x00000020
++#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
++#define I2C_FUNC_SMBUS_QUICK 0x00010000
++#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
++#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
++#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
++#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
++#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
++#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
++#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
++#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
++#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
++#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
++#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
++#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000
++
++#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
++ I2C_FUNC_SMBUS_WRITE_BYTE)
++#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
++ I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
++#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
++ I2C_FUNC_SMBUS_WRITE_WORD_DATA)
++#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
++#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
++
++#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \
++ I2C_FUNC_SMBUS_BYTE | \
++ I2C_FUNC_SMBUS_BYTE_DATA | \
++ I2C_FUNC_SMBUS_WORD_DATA | \
++ I2C_FUNC_SMBUS_PROC_CALL | \
++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
++ I2C_FUNC_SMBUS_I2C_BLOCK | \
++ I2C_FUNC_SMBUS_PEC)
++
++/*
++ * Data for SMBus Messages
++ */
++#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
++union i2c_smbus_data {
++ __u8 byte;
++ __u16 word;
++ __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
++ /* and one more for user-space compatibility */
++};
++
++/* i2c_smbus_xfer read or write markers */
++#define I2C_SMBUS_READ 1
++#define I2C_SMBUS_WRITE 0
++
++/* SMBus transaction types (size parameter in the above functions)
++ Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
++#define I2C_SMBUS_QUICK 0
++#define I2C_SMBUS_BYTE 1
++#define I2C_SMBUS_BYTE_DATA 2
++#define I2C_SMBUS_WORD_DATA 3
++#define I2C_SMBUS_PROC_CALL 4
++#define I2C_SMBUS_BLOCK_DATA 5
++#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
++#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
++#define I2C_SMBUS_I2C_BLOCK_DATA 8
++
++#endif /* _UAPI_LINUX_I2C_H */
+diff --git a/ipmb-channels.json b/ipmb-channels.json
+index 0876db7..ff570c6 100644
+--- a/ipmb-channels.json
++++ b/ipmb-channels.json
+@@ -11,6 +11,12 @@
+ "slave-path": "/dev/ipmb-0",
+ "bmc-addr": 32,
+ "remote-addr": 88
++ },
++ {
++ "type": "slot-ipmb",
++ "slave-path": "/dev/ipmb-6",
++ "bmc-addr": 18,
++ "remote-addr": 176
+ }
+ ]
+ }
+diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
+index 3bf8469..6d1be04 100644
+--- a/ipmbbridged.cpp
++++ b/ipmbbridged.cpp
+@@ -18,6 +18,11 @@
+ #include "ipmbdefines.hpp"
+ #include "ipmbutils.hpp"
+
++#include <i2c/smbus.h>
++#include <linux/i2c-dev.h>
++#include <linux/i2c.h>
++#include <sys/ioctl.h>
++
+ #include <boost/algorithm/string/replace.hpp>
+ #include <boost/asio/write.hpp>
+ #include <filesystem>
+@@ -40,7 +45,8 @@ auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+ static std::list<IpmbChannel> ipmbChannels;
+ static const std::unordered_map<std::string, ipmbChannelType>
+ ipmbChannelTypeMap = {{"me", ipmbChannelType::me},
+- {"ipmb", ipmbChannelType::ipmb}};
++ {"ipmb", ipmbChannelType::ipmb},
++ {"slot-ipmb", ipmbChannelType::slot_ipmb}};
+
+ /**
+ * @brief Ipmb request class methods
+@@ -555,7 +561,10 @@ int IpmbChannel::ipmbChannelInit(const char *ipmbI2cSlave)
+ {
+ std::string deviceFileName =
+ "/sys/bus/i2c/devices/i2c-" + busStr + "/new_device";
+- std::string para = "ipmb-dev 0x1010"; // init with BMC addr 0x20
++ std::ostringstream param;
++ param << "ipmb-dev 0x" << std::hex
++ << static_cast<uint16_t>(0x1000 | (ipmbBmcSlaveAddress >> 1));
++ std::string para(param.str());
+ std::fstream deviceFile;
+ deviceFile.open(deviceFileName, std::ios::out);
+ if (!deviceFile.good())
+@@ -711,6 +720,171 @@ void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
+ }
+ }
+
++class Mux
++{
++ public:
++ Mux(const std::string &path) : heldMux(false)
++ {
++ fd = open(path.c_str(), O_RDWR | O_NONBLOCK);
++ }
++ ~Mux()
++ {
++ if (heldMux)
++ {
++ if (unholdMux() < 0)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error while unholding the bus");
++ }
++ }
++ if (!(fd < 0))
++ {
++ close(fd);
++ }
++ }
++
++ int transferAndHoldMux(const uint8_t slaveAddr, uint8_t *buffer,
++ const uint8_t len, uint16_t timeout)
++ {
++ if (!isMuxFdOpen())
++ {
++ return -1;
++ }
++ struct i2c_msg holdmsg[2] = {
++ {slaveAddr, 0, len, buffer},
++ {0, I2C_M_HOLD, sizeof(timeout), (uint8_t *)&timeout}};
++
++ struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg[0], 2};
++
++ int retVal = ioctl(fd, I2C_RDWR, &msgrdwr);
++ if (retVal >= 0)
++ {
++ heldMux = true;
++ }
++ return retVal;
++ }
++
++ bool isMuxFdOpen()
++ {
++ if (fd < 0)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error while opening the mux device file");
++ return false;
++ }
++ return true;
++ }
++
++ private:
++ int unholdMux()
++ {
++ if (!isMuxFdOpen())
++ {
++ return -1;
++ }
++ uint16_t holdtimeout = 0; // unhold the bus
++
++ struct i2c_msg holdmsg = {0, I2C_M_HOLD, sizeof(holdtimeout),
++ (uint8_t *)&holdtimeout};
++
++ struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg, 1};
++
++ return ioctl(fd, I2C_RDWR, &msgrdwr);
++ }
++
++ int fd;
++ bool heldMux;
++};
++
++std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
++ IpmbChannel::slotRequestAdd(boost::asio::yield_context &yield,
++ std::shared_ptr<IpmbRequest> request,
++ const uint8_t pcieSlot)
++{
++ makeRequestValid(request);
++ std::filesystem::path p =
++ "/dev/i2c-mux/PCIE_Mux/Pcie_Slot_" + std::to_string(pcieSlot);
++
++ if (!std::filesystem::exists(p) || !std::filesystem::is_symlink(p))
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "does not exist or not a symlink ",
++ phosphor::logging::entry("File:%s", p.c_str()));
++ return returnStatus(ipmbResponseStatus::error);
++ }
++
++ Mux mux(p);
++ if (!mux.isMuxFdOpen())
++ {
++ return returnStatus(ipmbResponseStatus::error);
++ }
++
++ std::vector<uint8_t> buffer(0);
++ if (request->ipmbToi2cConstruct(buffer) != 0)
++ {
++ return returnStatus(ipmbResponseStatus::error);
++ }
++
++ uint8_t size = buffer.size();
++
++ const uint8_t slaveAddrIndex = 1;
++ const uint8_t slotIpmbHeader = 2;
++
++ for (int i = 0; i < ipmbNumberOfTries; i++)
++ {
++ boost::system::error_code ec;
++ int i2cRetryCnt = 0;
++ do
++ {
++ if (mux.transferAndHoldMux(
++ buffer[slaveAddrIndex] >> 1, buffer.data() + slotIpmbHeader,
++ size - slotIpmbHeader, ipmbRequestRetryTimeout) >= 0)
++ {
++ break;
++ }
++
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error sending slot IPMB command");
++ i2cRetryCnt++;
++ } while (i2cRetryCnt < ipmbI2cNumberOfRetries);
++
++ if (i2cRetryCnt == ipmbI2cNumberOfRetries)
++ {
++ std::string msgToLog =
++ "slotRequestAdd: Sent to I2C failed after retries."
++ " busId=" +
++ std::to_string(ipmbBusId) + ", error=" + ec.message();
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ msgToLog.c_str());
++ makeRequestInvalid(*request);
++ return returnStatus(ipmbResponseStatus::error);
++ }
++
++ request->timer->expires_after(
++ std::chrono::milliseconds(ipmbRequestRetryTimeout));
++ request->timer->async_wait(yield[ec]);
++
++ if (ec && ec != boost::asio::error::operation_aborted)
++ {
++ // unexpected error - invalidate request and return generic error
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "requestAdd: async_wait error");
++ makeRequestInvalid(*request);
++ return returnStatus(ipmbResponseStatus::error);
++ }
++
++ if (request->state == ipmbRequestState::matched)
++ {
++ // matched response, send it to client application
++ makeRequestInvalid(*request);
++ return request->returnMatchedResponse();
++ }
++ }
++
++ makeRequestInvalid(*request);
++ return returnStatus(ipmbResponseStatus::timeout);
++}
++
+ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+ IpmbChannel::requestAdd(boost::asio::yield_context &yield,
+ std::shared_ptr<IpmbRequest> request)
+@@ -848,6 +1022,47 @@ static int initializeChannels()
+ return 0;
+ }
+
++auto slotIpmbHandleRequest =
++ [](boost::asio::yield_context yield, uint8_t addressType,
++ uint8_t slotNumber, uint8_t targetSlaveAddr, uint8_t netfn, uint8_t cmd,
++ std::vector<uint8_t> dataReceived) {
++ uint8_t lun = 0; // No support for lun in slot IPMB
++ IpmbChannel *channel =
++ getChannel(static_cast<uint8_t>(ipmbChannelType::slot_ipmb));
++ if (channel == nullptr)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "slotIpmbHandleRequest: Slot IPMB channel does not exist");
++ return returnStatus(ipmbResponseStatus::error);
++ }
++
++ // check outstanding request list for valid sequence number
++ uint8_t seqNum = 0;
++ bool seqValid = channel->seqNumGet(seqNum);
++ if (!seqValid)
++ {
++ phosphor::logging::log<phosphor::logging::level::WARNING>(
++ "slotIpmbHandleRequest: cannot add more requests to the list");
++ return returnStatus(ipmbResponseStatus::busy);
++ }
++
++ uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
++ uint8_t rqSlaveAddress = targetSlaveAddr;
++
++ // construct the request to add it to outstanding request list
++ std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
++ rqSlaveAddress, netfn, ipmbRsLun, bmcSlaveAddress, seqNum, lun, cmd,
++ dataReceived);
++
++ if (!request->timer)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "slotIpmbHandleRequest: timer object does not exist");
++ return returnStatus(ipmbResponseStatus::error);
++ }
++ return channel->slotRequestAdd(yield, request, slotNumber);
++ };
++
+ auto ipmbHandleRequest = [](boost::asio::yield_context yield,
+ uint8_t reqChannel, uint8_t netfn, uint8_t lun,
+ uint8_t cmd, std::vector<uint8_t> dataReceived) {
+@@ -994,6 +1209,8 @@ int main(int argc, char *argv[])
+ server.add_interface(ipmbObj, ipmbDbusIntf);
+
+ ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
++ ipmbIface->register_method("SlotIpmbRequest",
++ std::move(slotIpmbHandleRequest));
+ ipmbIface->initialize();
+
+ if (initializeChannels() < 0)
+diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp
+index 052c193..c79ac63 100644
+--- a/ipmbbridged.hpp
++++ b/ipmbbridged.hpp
+@@ -155,7 +155,8 @@ enum class ipmbRequestState
+ enum class ipmbChannelType
+ {
+ ipmb = 0,
+- me = 1
++ me = 1,
++ slot_ipmb = 2
+ };
+
+ /**
+@@ -293,6 +294,11 @@ class IpmbChannel
+ void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
+ size_t retriesAttempted);
+
++ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
++ slotRequestAdd(boost::asio::yield_context &yield,
++ std::shared_ptr<IpmbRequest> requestToSend,
++ const uint8_t pcieSlot);
++
+ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+ requestAdd(boost::asio::yield_context &yield,
+ std::shared_ptr<IpmbRequest> requestToSend);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0002-Add-log-count-limitation-to-requestAdd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0002-Add-log-count-limitation-to-requestAdd.patch
new file mode 100644
index 000000000..f24d585a9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0002-Add-log-count-limitation-to-requestAdd.patch
@@ -0,0 +1,94 @@
+From 1b01638d44ebb5d6163899775dea2fcc7e0715d6 Mon Sep 17 00:00:00 2001
+From: Helen Huang <he.huang@intel.com>
+Date: Mon, 31 May 2021 09:19:55 +0800
+Subject: [PATCH] Add log count limitation to requestAdd()
+
+To avoid log storm, add the log count limitation to
+requestAdd().
+
+Change-Id: I91894ff07fa252ed7746816535611a33b6f640ea
+Signed-off-by: Helen Huang <he.huang@intel.com>
+---
+ ipmbbridged.cpp | 44 ++++++++++++++++++++++++++++++++++++++------
+ ipmbbridged.hpp | 3 +++
+ 2 files changed, 41 insertions(+), 6 deletions(-)
+
+diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
+index 6d1be04..93f5b2f 100644
+--- a/ipmbbridged.cpp
++++ b/ipmbbridged.cpp
+@@ -916,12 +916,44 @@ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+
+ if (i2cRetryCnt == ipmbI2cNumberOfRetries)
+ {
+- std::string msgToLog =
+- "requestAdd: Sent to I2C failed after retries."
+- " busId=" +
+- std::to_string(ipmbBusId) + ", error=" + ec.message();
+- phosphor::logging::log<phosphor::logging::level::INFO>(
+- msgToLog.c_str());
++ if ((requestAddLogCount <= ipmbRequestAddLogLimit) ||
++ (!(requestAddLogCount % ipmbRequestAddLogInterval)) ||
++ (UINT_MAX == requestAddLogCount))
++ {
++ std::string msgToLog;
++ if (requestAddLogCount == ipmbRequestAddLogLimit)
++ {
++ msgToLog = "requestAdd: There are " +
++ std::to_string(ipmbRequestAddLogLimit - 1) +
++ " similiar logs."
++ " To avoid log storm, not all the logs for the "
++ "issue will be shown: ";
++ }
++ if (!(requestAddLogCount % ipmbRequestAddLogInterval) && (requestAddLogCount != 0))
++ {
++ msgToLog = "requestAdd: There are " +
++ std::to_string(requestAddLogCount) +
++ " similiar logs so far: ";
++ }
++ if (UINT_MAX == requestAddLogCount)
++ {
++ msgToLog = "requestAdd: There are " +
++ std::to_string(requestAddLogCount) +
++ " similiar logs,"
++ " The log count will be rolled back to zero: ";
++ }
++ msgToLog += "requestAdd: Sent to I2C failed after retries."
++ " busId=" +
++ std::to_string(ipmbBusId) +
++ ", error=" + ec.message();
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ msgToLog.c_str());
++ }
++ requestAddLogCount++;
++ }
++ else
++ {
++ requestAddLogCount = 0;
+ }
+
+ request->timer->expires_after(
+diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp
+index c79ac63..eaba7ae 100644
+--- a/ipmbbridged.hpp
++++ b/ipmbbridged.hpp
+@@ -50,6 +50,8 @@ constexpr int ipmbMaxOutstandingRequestsCount = 64;
+ constexpr int ipmbNumberOfTries = 6;
+ constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
+
++constexpr int ipmbRequestAddLogLimit = 10;
++constexpr int ipmbRequestAddLogInterval = 100;
+ /**
+ * @brief Ipmb I2C communication
+ */
+@@ -313,6 +315,7 @@ class IpmbChannel
+ uint8_t ipmbBusId;
+ uint8_t channelIdx;
+
++ unsigned int requestAddLogCount = 0;
+ std::shared_ptr<IpmbCommandFilter> commandFilter;
+
+ // array storing outstanding requests
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0003-Fix-for-clearing-outstanding-requests.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0003-Fix-for-clearing-outstanding-requests.patch
new file mode 100644
index 000000000..ffa3ab1b0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0003-Fix-for-clearing-outstanding-requests.patch
@@ -0,0 +1,62 @@
+From e107bdc375aa23a4c0a3d23978cfe8b378bce09a Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Mon, 20 Sep 2021 14:06:05 +0000
+Subject: [PATCH] Fix for clearing outstanding requests
+
+IPMB requests were made valid even if there was an error in opening the
+mux bus. This fix makes the IPMB requests valid only we were able to
+successfully open the Mux fd.
+
+Tested:
+Verified using busctl command.
+Command: busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb
+ /xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb
+ sendRequest yyyyay 0 0x30 0 0x70 2 0 32
+Response: (iyyyyay) 0 49 0 112 193 0
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ ipmbbridged.cpp | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
+index 3ffc1f7..0508fcc 100644
+--- a/ipmbbridged.cpp
++++ b/ipmbbridged.cpp
+@@ -801,7 +801,6 @@ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+ std::shared_ptr<IpmbRequest> request,
+ const uint8_t pcieSlot)
+ {
+- makeRequestValid(request);
+ std::filesystem::path p =
+ "/dev/i2c-mux/PCIE_Mux/Pcie_Slot_" + std::to_string(pcieSlot);
+
+@@ -825,6 +824,7 @@ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+ return returnStatus(ipmbResponseStatus::error);
+ }
+
++ makeRequestValid(request);
+ uint8_t size = buffer.size();
+
+ const uint8_t slaveAddrIndex = 1;
+@@ -894,6 +894,7 @@ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+ std::vector<uint8_t> buffer(0);
+ if (request->ipmbToi2cConstruct(buffer) != 0)
+ {
++ makeRequestInvalid(*request);
+ return returnStatus(ipmbResponseStatus::error);
+ }
+
+@@ -929,7 +930,8 @@ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
+ " To avoid log storm, not all the logs for the "
+ "issue will be shown: ";
+ }
+- if (!(requestAddLogCount % ipmbRequestAddLogInterval) && (requestAddLogCount != 0))
++ if (!(requestAddLogCount % ipmbRequestAddLogInterval) &&
++ (requestAddLogCount != 0))
+ {
+ msgToLog = "requestAdd: There are " +
+ std::to_string(requestAddLogCount) +
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json
new file mode 100644
index 000000000..2d77aa6e7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json
@@ -0,0 +1,22 @@
+{
+ "channels": [
+ {
+ "type": "me",
+ "slave-path": "/dev/ipmb-5",
+ "bmc-addr": 32,
+ "remote-addr": 44
+ },
+ {
+ "type": "ipmb",
+ "slave-path": "/dev/ipmb-13",
+ "bmc-addr": 32,
+ "remote-addr": 32
+ },
+ {
+ "type": "slot-ipmb",
+ "slave-path": "/dev/ipmb-6",
+ "bmc-addr": 18,
+ "remote-addr": 176
+ }
+ ]
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend
new file mode 100644
index 000000000..caf25fdd6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend
@@ -0,0 +1,13 @@
+SRC_URI = "git://github.com/openbmc/ipmbbridge.git"
+SRCREV = "8227626764edf13350c5f5a5857298a905fb43f7"
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+SRC_URI += "file://0001-Add-dbus-method-SlotIpmbRequest.patch \
+ file://0002-Add-log-count-limitation-to-requestAdd.patch \
+ file://0003-Fix-for-clearing-outstanding-requests.patch \
+ file://ipmb-channels.json \
+ "
+
+do_install:append() {
+ install -D ${WORKDIR}/ipmb-channels.json \
+ ${D}/usr/share/ipmbbridge
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules
new file mode 100644
index 000000000..0a64b58db
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules
@@ -0,0 +1,2 @@
+KERNEL=="ipmi-kcs3", SYMLINK+="ipmi_kcs3"
+KERNEL=="ipmi-kcs4", SYMLINK+="ipmi_kcs4"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend
new file mode 100644
index 000000000..fd1677543
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend
@@ -0,0 +1,21 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+#SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}"
+
+# Default kcs device is ipmi-kcs3; this is SMS.
+# Add SMM kcs device instance
+
+# Replace the '-' to '_', since Dbus object/interface names do not allow '-'.
+KCS_DEVICE = "ipmi_kcs3"
+SMM_DEVICE = "ipmi_kcs4"
+SYSTEMD_SERVICE:${PN}:append = " ${PN}@${SMM_DEVICE}.service "
+
+SRC_URI = "git://github.com/openbmc/kcsbridge.git"
+SRCREV = "7580a8e60d868b5bcb1a8f8d276374afe7c0983a"
+
+SRC_URI += "file://99-ipmi-kcs.rules"
+
+do_install:append() {
+ install -d ${D}${base_libdir}/udev/rules.d
+ install -m 0644 ${WORKDIR}/99-ipmi-kcs.rules ${D}${base_libdir}/udev/rules.d/
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch
new file mode 100644
index 000000000..867b3aba6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch
@@ -0,0 +1,40 @@
+From 0fd38eb0a155cb11ff5a5452087f68c46d12111b Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Thu, 28 Mar 2019 18:10:40 +0800
+Subject: [PATCH] Change Authentication Parameter
+
+Seprate D-bus interface Authentication to forceAuthentication,
+forceEncryption, Privilege according to the related change in
+sol-dbus-interface.
+
+Tested By:
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x03
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0xc2
+The parameters has been changed to the request data in above command.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ sol/sol_manager.cpp | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
+index de36723..0bd837e 100644
+--- a/sol/sol_manager.cpp
++++ b/sol/sol_manager.cpp
+@@ -195,8 +195,12 @@ void Manager::updateSOLParameter()
+
+ enable = std::get<bool>(properties["Enable"]);
+
++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
++
++ forceAuth = std::get<bool>(properties["ForceAuthentication"]);
++
+ solMinPrivilege = static_cast<session::Privilege>(
+- std::get<uint8_t>(properties["Authentication"]));
++ std::get<uint8_t>(properties["Privilege"]));
+
+ accumulateInterval =
+ std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch
new file mode 100644
index 000000000..0ad625a1f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch
@@ -0,0 +1,39 @@
+From 6fc55bb689272d34ff6616cdd4b24367ea39c749 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Mon, 2 Jul 2018 15:51:52 +0800
+Subject: [PATCH] Modify dbus namespace of chassis control for guid.cpp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Switch chassis control service namespace for guid.cpp from “org” to “xyz”,
+to compatible with new intel-chassis services
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ command/guid.cpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+Index: phosphor-net-ipmid.clean/command/guid.cpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/command/guid.cpp
++++ phosphor-net-ipmid.clean/command/guid.cpp
+@@ -21,7 +21,8 @@ namespace command
+
+ std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr);
+
+-static constexpr auto guidObjPath = "/org/openbmc/control/chassis0";
++static constexpr auto guidObjPath =
++ "/xyz/openbmc_project/Chassis/Control/Chassis0";
+ static constexpr auto propInterface = "org.freedesktop.DBus.Properties";
+
+ Guid getSystemGUID()
+@@ -31,7 +32,7 @@ Guid getSystemGUID()
+ Guid guid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
+
+- constexpr auto chassisIntf = "org.openbmc.control.Chassis";
++ constexpr auto chassisIntf = "xyz.openbmc_project.Chassis.Control.Chassis";
+
+ sd_bus_message* reply = nullptr;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch
new file mode 100644
index 000000000..7b690998f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch
@@ -0,0 +1,331 @@
+From adabdfa46aa0db56f40030c7077f991ba1987b04 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Tue, 30 Apr 2019 05:35:31 +0800
+Subject: [PATCH] Remove Get SOL Config Command from Netipmid
+
+Since Get SOL Config Parameter command already exists in host-ipmid, and
+can be shared to net channel, remove this command from net-ipmid.
+
+Tested:
+Run ipmitool -I lanplus -H xxx -U root -P 0penBmc sol info, the command
+returns the same result as ipmitool sol info as below.
+Info: SOL parameter 'Nonvolatile Bitrate (5)' not supported
+Info: SOL parameter 'Volatile Bitrate (6)' not supported
+Info: SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e
+Set in progress : set-complete
+Enabled : true
+Force Encryption : true
+Force Authentication : true
+Privilege Level : USER
+Character Accumulate Level (ms) : 100
+Character Send Threshold : 1
+Retry Count : 3
+Retry Interval (ms) : 100
+Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting
+Non-Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting
+Payload Channel : 14 (0x0e)
+Payload Port : 623
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ command/sol_cmds.cpp | 86 ----------------------
+ command/sol_cmds.hpp | 168 -------------------------------------------
+ sol_module.cpp | 6 --
+ 3 files changed, 260 deletions(-)
+
+diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp
+index 81dfc993236c..be2cc81fc9cc 100644
+--- a/command/sol_cmds.cpp
++++ b/command/sol_cmds.cpp
+@@ -69,92 +69,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID)
+ outPayload);
+ }
+
+-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload,
+- std::shared_ptr<message::Handler>& handler)
+-{
+- std::vector<uint8_t> outPayload(sizeof(GetConfParamsResponse));
+- auto request =
+- reinterpret_cast<const GetConfParamsRequest*>(inPayload.data());
+- auto response = reinterpret_cast<GetConfParamsResponse*>(outPayload.data());
+- response->completionCode = IPMI_CC_OK;
+- response->paramRev = parameterRevision;
+-
+- if (request->getParamRev)
+- {
+- return outPayload;
+- }
+-
+- switch (static_cast<Parameter>(request->paramSelector))
+- {
+- case Parameter::PROGRESS:
+- {
+- outPayload.push_back(sol::Manager::get().progress);
+- break;
+- }
+- case Parameter::ENABLE:
+- {
+- outPayload.push_back(sol::Manager::get().enable);
+- break;
+- }
+- case Parameter::AUTHENTICATION:
+- {
+- Auth value{0};
+-
+- value.encrypt = sol::Manager::get().forceEncrypt;
+- value.auth = sol::Manager::get().forceAuth;
+- value.privilege =
+- static_cast<uint8_t>(sol::Manager::get().solMinPrivilege);
+- auto buffer = reinterpret_cast<const uint8_t*>(&value);
+-
+- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::ACCUMULATE:
+- {
+- Accumulate value{0};
+-
+- value.interval = sol::Manager::get().accumulateInterval.count() /
+- sol::accIntervalFactor;
+- value.threshold = sol::Manager::get().sendThreshold;
+- auto buffer = reinterpret_cast<const uint8_t*>(&value);
+-
+- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::RETRY:
+- {
+- Retry value{0};
+-
+- value.count = sol::Manager::get().retryCount;
+- value.interval = sol::Manager::get().retryInterval.count() /
+- sol::retryIntervalFactor;
+- auto buffer = reinterpret_cast<const uint8_t*>(&value);
+-
+- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::PORT:
+- {
+- auto port = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
+- auto buffer = reinterpret_cast<const uint8_t*>(&port);
+-
+- std::copy_n(buffer, sizeof(port), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::CHANNEL:
+- {
+- outPayload.push_back(sol::Manager::get().channel);
+- break;
+- }
+- case Parameter::NVBITRATE:
+- case Parameter::VBITRATE:
+- default:
+- response->completionCode = ipmiCCParamNotSupported;
+- }
+-
+- return outPayload;
+-}
+-
+ } // namespace command
+
+ } // namespace sol
+diff --git a/command/sol_cmds.hpp b/command/sol_cmds.hpp
+index 3e05e0fc035f..9aedfddf0d39 100644
+--- a/command/sol_cmds.hpp
++++ b/command/sol_cmds.hpp
+@@ -62,174 +62,6 @@ struct ActivatingRequest
+ */
+ void activating(uint8_t payloadInstance, uint32_t sessionID);
+
+-/** @enum Parameter
+- *
+- * SOL parameters are volatile, they are initialized by the SOL manager.
+- * They can be read using Get SOL configuration parameters command and updated
+- * using Set SOL configuration parameters command.
+- */
+-enum class Parameter
+-{
+- PROGRESS, //!< Set In Progress.
+- ENABLE, //!< SOL Enable.
+- AUTHENTICATION, //!< SOL Authentication.
+- ACCUMULATE, //!< Character Accumulate Interval & Send Threshold.
+- RETRY, //!< SOL Retry.
+- NVBITRATE, //!< SOL non-volatile bit rate.
+- VBITRATE, //!< SOL volatile bit rate.
+- CHANNEL, //!< SOL payload channel.
+- PORT, //!< SOL payload port.
+-};
+-
+-constexpr uint8_t progressMask = 0x03;
+-constexpr uint8_t enableMask = 0x01;
+-
+-/** @struct Auth
+- *
+- * SOL authentication parameter.
+- */
+-struct Auth
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t privilege : 4; //!< SOL privilege level.
+- uint8_t reserved : 2; //!< Reserved.
+- uint8_t auth : 1; //!< Force SOL payload Authentication.
+- uint8_t encrypt : 1; //!< Force SOL payload encryption.
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t encrypt : 1; //!< Force SOL payload encryption.
+- uint8_t auth : 1; //!< Force SOL payload Authentication.
+- uint8_t reserved : 2; //!< Reserved.
+- uint8_t privilege : 4; //!< SOL privilege level.
+-#endif
+-} __attribute__((packed));
+-
+-/** @struct Accumulate
+- *
+- * Character accumulate interval & Character send threshold.
+- */
+-struct Accumulate
+-{
+- uint8_t interval; //!< Character accumulate interval.
+- uint8_t threshold; //!< Character send threshold.
+-} __attribute__((packed));
+-
+-constexpr uint8_t retryCountMask = 0x07;
+-
+-/** @struct Retry
+- *
+- * SOL retry count and interval.
+- */
+-struct Retry
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t count : 3; //!< SOL retry count.
+- uint8_t reserved : 5; //!< Reserved.
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t reserved : 5; //!< Reserved.
+- uint8_t count : 3; //!< SOL retry count.
+-#endif
+-
+- uint8_t interval; //!< SOL retry interval.
+-} __attribute__((packed));
+-
+-constexpr uint8_t ipmiCCParamNotSupported = 0x80;
+-constexpr uint8_t ipmiCCInvalidSetInProgress = 0x81;
+-constexpr uint8_t ipmiCCWriteReadParameter = 0x82;
+-constexpr uint8_t ipmiCCReadWriteParameter = 0x83;
+-constexpr uint8_t parameterRevision = 0x11;
+-
+-/** @struct SetConfParamsRequest
+- *
+- * IPMI payload for Set SOL configuration parameters command request.
+- */
+-struct SetConfParamsRequest
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t channelNumber : 4; //!< Channel number.
+- uint8_t reserved : 4; //!< Reserved.
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t reserved : 4; //!< Reserved.
+- uint8_t channelNumber : 4; //!< Channel number.
+-#endif
+-
+- uint8_t paramSelector; //!< Parameter selector.
+- union
+- {
+- uint8_t value; //!< Represents one byte SOL parameters.
+- struct Accumulate acc; //!< Character accumulate values.
+- struct Retry retry; //!< Retry values.
+- struct Auth auth; //!< Authentication parameters.
+- };
+-} __attribute__((packed));
+-
+-/** @struct SetConfParamsResponse
+- *
+- * IPMI payload for Set SOL configuration parameters command response.
+- */
+-struct SetConfParamsResponse
+-{
+- uint8_t completionCode; //!< Completion code.
+-} __attribute__((packed));
+-
+-/** @brief Set SOL configuration parameters command.
+- *
+- * @param[in] inPayload - Request data for the command.
+- * @param[in] handler - Reference to the message handler.
+- *
+- * @return Response data for the command.
+- */
+-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload,
+- std::shared_ptr<message::Handler>& handler);
+-
+-/** @struct GetConfParamsRequest
+- *
+- * IPMI payload for Get SOL configuration parameters command request.
+- */
+-struct GetConfParamsRequest
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t channelNum : 4; //!< Channel number.
+- uint8_t reserved : 3; //!< Reserved.
+- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision
+- uint8_t reserved : 3; //!< Reserved.
+- uint8_t channelNum : 4; //!< Channel number.
+-#endif
+-
+- uint8_t paramSelector; //!< Parameter selector.
+- uint8_t setSelector; //!< Set selector.
+- uint8_t blockSelector; //!< Block selector.
+-} __attribute__((packed));
+-
+-/** @struct GetConfParamsResponse
+- *
+- * IPMI payload for Get SOL configuration parameters command response.
+- */
+-struct GetConfParamsResponse
+-{
+- uint8_t completionCode; //!< Completion code.
+- uint8_t paramRev; //!< Parameter revision.
+-} __attribute__((packed));
+-
+-/** @brief Get SOL configuration parameters command.
+- *
+- * @param[in] inPayload - Request data for the command.
+- * @param[in] handler - Reference to the message handler.
+- *
+- * @return Response data for the command.
+- */
+-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload,
+- std::shared_ptr<message::Handler>& handler);
+-
+ } // namespace command
+
+ } // namespace sol
+diff --git a/sol_module.cpp b/sol_module.cpp
+index d9a9a7c9551f..21196d8a2cbf 100644
+--- a/sol_module.cpp
++++ b/sol_module.cpp
+@@ -41,12 +41,6 @@ void registerCommands()
+ &getPayloadInfo,
+ session::Privilege::USER,
+ false},
+- // Get SOL Configuration Parameters
+- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22},
+- &getConfParams,
+- session::Privilege::USER,
+- false},
+ };
+
+ for (const auto& iter : commands)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0012-rakp12-Add-username-to-SessionInfo-interface.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0012-rakp12-Add-username-to-SessionInfo-interface.patch
new file mode 100644
index 000000000..89a111d06
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0012-rakp12-Add-username-to-SessionInfo-interface.patch
@@ -0,0 +1,49 @@
+From 20bf13de482b02a4a467f44070f7ff184c340dd2 Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Tue, 1 Jun 2021 12:22:19 +0000
+Subject: [PATCH] rakp12: Add username to SessionInfo interface
+
+Add username to SessionInfo interface to get username info on individual
+IPMI session Id's on Redfish
+
+Tested:
+1. Activate SOL session
+Command: ipmitool -I lanplus -U root -P 0penBmc -H <BMC_IP> -C 17
+ sol activate
+Response: // Success
+2. Verified on SessionInfo D-bus interface.
+busctl introspect xyz.openbmc_project.Ipmi.Channel.eth0
+ /xyz/openbmc_project/ipmi/session/eth0/<session_id>
+NAME TYPE SIGNATURE RESULT/VALUE FLAGS
+......
+xyz.openbmc_project.Ipmi.SessionInfo interface - - -
+.ChannelNum property y 3 emits-change writable
+.CurrentPrivilege property y 4 emits-change writable
+.RemoteIPAddr property u 22253066 emits-change writable
+.RemoteMACAddress property ay 0 emits-change writable
+.RemotePort property q 41096 emits-change writable
+.SessionHandle property y 129 emits-change writable
+.State property y 2 emits-change writable
+.UserID property y 1 emits-change writable
+.Username property s "root" emits-change writable
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ command/rakp12.cpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/command/rakp12.cpp b/command/rakp12.cpp
+index 099c5dc..98b6891 100644
+--- a/command/rakp12.cpp
++++ b/command/rakp12.cpp
+@@ -227,6 +227,7 @@ std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload,
+ }
+ session->channelNum(chNum);
+ session->userID(userId);
++ session->username(userName);
+ // minimum privilege of Channel / User / session::privilege::USER
+ // has to be used as session current privilege level
+ uint8_t minPriv = 0;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf
new file mode 100644
index 000000000..d2fb5ba04
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf
@@ -0,0 +1,2 @@
+[Service]
+Nice=-18
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
new file mode 100644
index 000000000..a0b507cb8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
@@ -0,0 +1,31 @@
+inherit useradd
+
+# TODO: This should be removed, once up-stream bump up
+# issue is resolved
+SRC_URI += "git://github.com/openbmc/phosphor-net-ipmid"
+SRCREV = "5819666c23ee1d01a54fc5fb2c068bb1da1f29c7"
+
+USERADD_PACKAGES = "${PN}"
+# add a group called ipmi
+GROUPADD_PARAM:${PN} = "ipmi "
+
+# Default rmcpp iface is eth0; channel 1
+# Add channel 2 instance (eth1)
+RMCPP_EXTRA = "eth1"
+SYSTEMD_SERVICE:${PN} += " \
+ ${PN}@${RMCPP_EXTRA}.service \
+ ${PN}@${RMCPP_EXTRA}.socket \
+ "
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " file://10-nice-rules.conf \
+ file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \
+ file://0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch \
+ file://0012-rakp12-Add-username-to-SessionInfo-interface.patch \
+ "
+
+do_install:append() {
+ mkdir -p ${D}${sysconfdir}/systemd/system/phosphor-ipmi-net@.service.d/
+ install -m 0644 ${WORKDIR}/10-nice-rules.conf ${D}${sysconfdir}/systemd/system/phosphor-ipmi-net@.service.d/
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend
new file mode 100644
index 000000000..4fc41d058
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb
new file mode 100644
index 000000000..14093cf3e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb
@@ -0,0 +1,19 @@
+SUMMARY = "Node Manager Proxy"
+DESCRIPTION = "The Node Manager Proxy provides a simple interface for communicating \
+with Management Engine via IPMB"
+
+SRC_URI = "git://github.com/Intel-BMC/node-manager;protocol=ssh"
+SRCREV = "9aca80fa2a405938de99aae777e6cfcf08525563"
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SYSTEMD_SERVICE:${PN} = "node-manager-proxy.service"
+
+DEPENDS = "sdbusplus \
+ phosphor-logging \
+ boost"
+
+S = "${WORKDIR}/git"
+inherit cmake systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service
new file mode 100644
index 000000000..51e59c614
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=turn off the ID LED when BMC is ready
+Wants=multi-user.target
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/id-led-off.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh
new file mode 100755
index 000000000..b609fc0ea
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+busctl set-property "xyz.openbmc_project.LED.GroupManager" \
+"/xyz/openbmc_project/led/groups/enclosure_identify" \
+"xyz.openbmc_project.Led.Group" "Asserted" b false
+
+busctl set-property "xyz.openbmc_project.LED.GroupManager" \
+"/xyz/openbmc_project/led/groups/enclosure_identify_blink" \
+"xyz.openbmc_project.Led.Group" "Asserted" b false
+
+busctl set-property "xyz.openbmc_project.LED.Controller.identify" \
+"/xyz/openbmc_project/led/physical/identify" \
+"xyz.openbmc_project.Led.Physical" "State" s "xyz.openbmc_project.Led.Physical.Action.Off"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb
new file mode 100644
index 000000000..21557d96b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Turn off the ID LED"
+DESCRIPTION = "Script to turn off the ID LED after BMC is ready"
+
+S = "${WORKDIR}"
+SRC_URI = "file://id-led-off.sh \
+ file://id-led-off.service \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+RDEPENDS:${PN} += "bash"
+
+inherit systemd
+
+FILES:${PN} += "${systemd_system_unitdir}/id-led-off.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/id-led-off.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/id-led-off.sh ${D}/${bindir}/id-led-off.sh
+}
+
+SYSTEMD_SERVICE:${PN} += " id-led-off.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb
new file mode 100644
index 000000000..47c66ccb8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb
@@ -0,0 +1,21 @@
+SUMMARY = "Phosphor LED Group Management for Intel"
+PR = "r1"
+
+inherit obmc-phosphor-utils
+inherit native
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+PROVIDES += "virtual/phosphor-led-manager-config-native"
+
+SRC_URI += "file://led.yaml"
+S = "${WORKDIR}"
+
+# Overwrite the example led layout yaml file prior
+# to building the phosphor-led-manager package
+do_install() {
+ SRC=${S}
+ DEST=${D}${datadir}/phosphor-led-manager
+ install -D ${SRC}/led.yaml ${DEST}/led.yaml
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml
new file mode 100644
index 000000000..1605b8e6b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml
@@ -0,0 +1,80 @@
+bmc_booted:
+
+power_on:
+
+status_ok:
+ status_green:
+ Action: 'On'
+ status_amber:
+ Action: 'Off'
+
+status_degraded:
+ status_green:
+ Action: 'Blink'
+ DutyOn: 50
+ Period: 1000
+ status_amber:
+ Action: 'Off'
+
+status_non_critical:
+ status_green:
+ Action: 'Off'
+ status_amber:
+ Action: 'Blink'
+ DutyOn: 50
+ Period: 1000
+
+status_critical:
+ status_green:
+ Action: 'Off'
+ status_amber:
+ Action: 'On'
+
+enclosure_identify:
+ identify:
+ Action: 'On'
+
+enclosure_identify_blink:
+ identify:
+ Action: 'Blink'
+
+cpu0_fault:
+ cpu0fault:
+ Action: 'On'
+
+cpu1_fault:
+ cpu1fault:
+ Action: 'On'
+
+fan1_fault:
+ fan1_fault:
+ Action: 'On'
+
+fan2_fault:
+ fan2_fault:
+ Action: 'On'
+
+fan3_fault:
+ fan3_fault:
+ Action: 'On'
+
+fan4_fault:
+ fan4_fault:
+ Action: 'On'
+
+fan5_fault:
+ fan5_fault:
+ Action: 'On'
+
+fan6_fault:
+ fan6_fault:
+ Action: 'On'
+
+fan7_fault:
+ fan7_fault:
+ Action: 'On'
+
+fan8_fault:
+ fan8_fault:
+ Action: 'On'
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/phosphor-led-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/phosphor-led-manager_%.bbappend
new file mode 100644
index 000000000..132fe2337
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/phosphor-led-manager_%.bbappend
@@ -0,0 +1,13 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+RDEPENDS:${PN}:remove = "clear-once"
+
+do_compile:prepend(){
+ install -m 0644 ${STAGING_DATADIR_NATIVE}/${PN}/led.yaml ${S}
+}
+
+do_install:append(){
+ rm -f ${S}/led.yaml
+}
+
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb
new file mode 100644
index 000000000..2468a487d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb
@@ -0,0 +1,27 @@
+SUMMARY = "Multi-node Non-legacy"
+DESCRIPTION = "New systemd target for non-legacy nodes on multi-node platform"
+
+inherit systemd
+
+SYSTEMD_SERVICE:${PN} = "multi-node-nl.target"
+SYSTEMD_SERVICE:${PN} += "nonLegacyNode.service"
+
+S = "${WORKDIR}"
+SRC_URI = "file://multi-node-nl.target \
+ file://nonLegacyNode.service \
+ file://nonLegacyNode.sh \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+RDEPENDS:${PN} = "bash"
+
+do_install:append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/nonLegacyNode.sh ${D}/${bindir}/nonLegacyNode.sh
+
+ install -d ${D}${base_libdir}/systemd/system
+ install -m 0644 ${S}/multi-node-nl.target ${D}${base_libdir}/systemd/system
+ install -m 0644 ${S}/nonLegacyNode.service ${D}${base_libdir}/systemd/system
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target
new file mode 100644
index 000000000..32b50532f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target
@@ -0,0 +1,4 @@
+[Unit]
+Description=Target for non-legacy node in multi-node system
+Documentation=man:systemd.special(7)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service
new file mode 100644
index 000000000..8e3d07ba4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Non Legacy node
+
+[Service]
+ExecStart=/usr/bin/nonLegacyNode.sh
+Type=exec
+
+[Install]
+WantedBy=multi-node-nl.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh
new file mode 100755
index 000000000..28a6bbe2a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+PWM_FILE="/sys/class/hwmon/hwmon0/pwm"
+FAN_SPEED=$((255 * 80 / 100))
+
+set_fan_speed() {
+ local idx=0
+ for ((idx=1; idx<=8; idx++))
+ do
+ if [ -f $PWM_FILE$idx ]; then
+ echo $FAN_SPEED > $PWM_FILE$idx
+ fi
+ done
+}
+
+$(set_fan_speed)
+
+#Stop power control service in NL mode
+systemctl stop xyz.openbmc_project.Chassis.Control.Power.service
+
+export TERM=xterm
+# Autologin root user to serial console (ttyS4) on boot
+exec /sbin/agetty -a root -J -8 -L ttyS4 115200 $TERM
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/network/phosphor-snmp_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/network/phosphor-snmp_%.bbappend
new file mode 100644
index 000000000..6d9294635
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/network/phosphor-snmp_%.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS:append := ":${THISDIR}/${PN}"
+
+# SRC_URI = "git://github.com/openbmc/phosphor-snmp"
+SRCREV = "d560529eb7e22c0b78fb0def20f57c6f35be9dfe"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend
new file mode 100644
index 000000000..e7c5d1af3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend
@@ -0,0 +1,5 @@
+SRC_URI = "git://github.com/openbmc/peci-pcie"
+
+SRCREV = "de624395a587be555463a14a3db90500b4e0521c"
+
+EXTRA_OECMAKE += "-DWAIT_FOR_OS_STANDBY=1 -DUSE_RDENDPOINTCFG=1"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb
new file mode 100644
index 000000000..5a6191fcd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb
@@ -0,0 +1,18 @@
+SUMMARY = "Phosphor U-Boot environment manager"
+DESCRIPTION = "Daemon to read or write U-Boot environment variables"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+SRC_URI = "git://github.com/openbmc/phosphor-u-boot-env-mgr.git;protocol=ssh"
+
+SRCREV = "1979d3b31a96e9359402ac4d7867ec5dddbece7e"
+
+inherit cmake systemd
+SYSTEMD_SERVICE:${PN} = "xyz.openbmc_project.U_Boot.Environment.Manager.service"
+
+DEPENDS = "boost sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb
new file mode 100644
index 000000000..592d6ae0c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb
@@ -0,0 +1,16 @@
+SUMMARY = "libmctp:intel"
+DESCRIPTION = "Implementation of MCTP(DMTF DSP0236)"
+
+SRC_URI = "git://github.com/Intel-BMC/libmctp.git;protocol=ssh"
+SRCREV = "d530c2271e1f9ff5d76a170c0abd64bd03ef40fd"
+
+S = "${WORKDIR}/git"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0 | GPLv2"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=0d30807bb7a4f16d36e96b78f9ed8fae"
+
+inherit cmake
+
+DEPENDS += "i2c-tools"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb
new file mode 100644
index 000000000..162b4ed74
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb
@@ -0,0 +1,18 @@
+SUMMARY = "libpldm_intel"
+DESCRIPTION = "Provides encode/decode APIs for PLDM specifications"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git/libpldm_intel"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+inherit cmake
+
+DEPENDS += " \
+ gtest \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb
new file mode 100644
index 000000000..fda4d6b79
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb
@@ -0,0 +1,30 @@
+SUMMARY = "MCTP Daemon"
+DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=bcd9ada3a943f58551867d72893cc9ab"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git/mctp_emulator"
+
+PV = "1.0+git${SRCPV}"
+
+inherit cmake systemd
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " \
+ libmctp-intel \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ cli11 \
+ nlohmann-json \
+ gtest \
+ "
+
+SYSTEMD_SERVICE:${PN} = "xyz.openbmc_project.mctp-emulator.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb
new file mode 100644
index 000000000..05e64ed46
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb
@@ -0,0 +1,28 @@
+SUMMARY = "MCTP Wrapper Library"
+DESCRIPTION = "Implementation of MCTP Wrapper Library"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=bcd9ada3a943f58551867d72893cc9ab"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git/mctp_wrapper"
+
+PV = "1.0+git${SRCPV}"
+
+inherit cmake systemd
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " \
+ libmctp-intel \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ gtest \
+ boost \
+ phosphor-dbus-interfaces \
+ "
+
+EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb
new file mode 100644
index 000000000..8b088be23
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb
@@ -0,0 +1,34 @@
+SUMMARY = "MCTP Daemon"
+DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${PN}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git"
+
+PV = "1.0+git${SRCPV}"
+
+OECMAKE_SOURCEPATH = "${S}/${PN}"
+
+inherit cmake systemd
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " \
+ libmctp-intel \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ cli11 \
+ nlohmann-json \
+ gtest \
+ phosphor-dbus-interfaces \
+ udev \
+ "
+FILES:${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.mctpd@.service"
+FILES:${PN} += "/usr/share/mctp/mctp_config.json"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb
new file mode 100644
index 000000000..b1c40ab61
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb
@@ -0,0 +1,24 @@
+SUMMARY = "MCTP Wrapper Library Plus"
+DESCRIPTION = "Implementation of MCTP Wrapper Library Plus"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=615045c30a05cde5c0e924854d43c327"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git/mctpwplus"
+
+PV = "1.0+git${SRCPV}"
+
+inherit cmake
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ cli11 \
+ "
+EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb
new file mode 100644
index 000000000..84c2c8066
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb
@@ -0,0 +1,17 @@
+SUMMARY = "NVMe MI Daemon"
+DESCRIPTION = "Implementation of NVMe MI daemon"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+SRC_URI = "git://github.com/Intel-BMC/nvme-mi.git;protocol=ssh"
+SRCREV = "c3d5021fb60cd46d5c948c69f3d57ac9648b5be5"
+S = "${WORKDIR}/git"
+PV = "1.0+git${SRCPV}"
+
+inherit meson systemd
+
+SYSTEMD_SERVICE:${PN} += "xyz.openbmc_project.nvme-mi.service"
+DEPENDS = "boost sdbusplus systemd phosphor-logging mctpwplus googletest nlohmann-json"
+
+EXTRA_OEMESON = "-Dyocto_dep='enabled'"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb
new file mode 100644
index 000000000..16253b5d0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb
@@ -0,0 +1,31 @@
+SUMMARY = "PLDM Requester Stack"
+DESCRIPTION = "Implementation of PLDM specifications"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+SRC_URI += "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git/pldmd"
+
+PV = "1.0+git${SRCPV}"
+
+inherit cmake systemd
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " \
+ libpldm-intel \
+ mctp-wrapper \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ gtest \
+ boost \
+ phosphor-dbus-interfaces \
+ mctpwplus \
+ "
+
+FILES:${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.pldmd.service"
+SYSTEMD_SERVICE:${PN} += "xyz.openbmc_project.pldmd.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb
new file mode 100644
index 000000000..c640c5664
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb
@@ -0,0 +1,23 @@
+SUMMARY = "PMCI Launcher"
+DESCRIPTION = "Support to launch pmci services on-demand"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "94437a678a1d23b22dc179b5cb7b165e52a429c0"
+
+S = "${WORKDIR}/git/pmci_launcher"
+
+PV = "1.0+git${SRCPV}"
+
+inherit cmake systemd
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ "
+FILES:${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.pmci-launcher.service"
+SYSTEMD_SERVICE:${PN} += "xyz.openbmc_project.pmci-launcher.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend
new file mode 100644
index 000000000..76b60aa8e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI = "file://init"
+
+RDEPENDS:${PN} += "bash"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
new file mode 100755
index 000000000..2065f94ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
@@ -0,0 +1,268 @@
+#!/bin/bash
+
+# Copyright 2017-2019 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# provide a couple of places in the RO root filesystem
+# that can be made RW with an overlayfs
+
+log() {
+ [ -c /dev/kmsg ] && echo "init: $*" > /dev/kmsg
+ echo "init: $*"
+}
+
+# start with /proc and /tmp mounted
+[ -e /proc/mounts ] || mount -t proc proc /proc
+# FIXME: add size limits to /tmp
+grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp
+grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys
+
+# fix up /srv to be RW
+mkdir -p /tmp/srv
+mount --bind /tmp/srv /srv
+
+if grep -q debug-init /proc/cmdline; then
+ exec > /tmp/init.log 2>&1
+ set -x
+ env
+else
+ # Suppress any stray output but we want to see any errors
+ exec >/dev/null 2>/dev/kmsg
+fi
+
+# list of things that need to be rw at boot
+NV_OVERLAYS="/etc /var /home"
+
+# place to mount the overlay backing store
+OVERLAY_MNT=/tmp/.overlay
+# OVERLAY_SIZE=16384
+# place to mount NV
+RWFS_MNT=/tmp/.rwfs
+# NV overlay storage
+OVERLAY_SYNC=${RWFS_MNT}/.overlay
+
+if grep -q "$RWFS_MNT" /proc/mounts; then
+ # quit - we have already run
+ exit 0
+fi
+mkdir -p "$OVERLAY_MNT"
+# TODO: remount the overlay with a size limit?
+# mount -t tmpfs -o rw,size=${OVERLAY_SIZE} oltmp ${OVERLAY_MNT}
+
+mtd_by_name() {
+ local name="$1"
+ echo "/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)"
+}
+
+mtdnum_by_name() {
+ local name="$1"
+ grep "$name" /proc/mtd | cut -c 4
+}
+
+NV_MTD=rwfs
+
+nvrw() {
+ local p="$1"
+ # Clear the work dir doing overlay mount
+ rm -rf "${OVERLAY_MNT}${p}.work"
+ mkdir -p "${OVERLAY_MNT}${p}" "${OVERLAY_MNT}${p}.work"
+ local mname
+ mname=$(echo "ol${p}" | sed 's,/,,g')
+ local opts="lowerdir=${p},upperdir=${OVERLAY_MNT}${p},workdir=${OVERLAY_MNT}${p}.work,sync"
+ mount -t overlay -o "$opts" "$mname" "$p"
+}
+
+targeted_clean() {
+ log "restore-defaults: targeted_clean"
+ # Do not delete FRU info, ssh/ssl certs, or machine-id
+ (
+ cd "${OVERLAY_SYNC}/etc" || exit
+ find . ! -regex '.*/\(ssl\|dropbear\|machine-id\|fru\).*' -a ! -path '.' \
+ -exec rm -rf {} +
+ )
+ # nothing should be in the workdir, but clear it just in case
+ rm -rf "${OVERLAY_SYNC}/etc.work"
+
+ # clean everything out of /home
+ rm -rf "${OVERLAY_SYNC}/home" "${OVERLAY_SYNC}/home.work"
+
+ # clean everything out of /var
+ rm -rf "${OVERLAY_SYNC}/var" "${OVERLAY_SYNC}/var.work"
+
+ echo "Files remaining: $(find $OVERLAY_SYNC/)"
+ sync
+}
+
+full_clean() {
+ log "restore-defaults: full_clean"
+ local OVL=''
+ for OVL in $NV_OVERLAYS; do
+ rm -rf "${OVERLAY_SYNC}${OVL}" "${OVERLAY_SYNC}${OVL}.work"
+ done
+ sync
+}
+
+jffs2_mount() {
+ mtd_name=$1
+ mnt=$2
+ mount -t jffs2 -o sync,ro mtd:"$mtd_name" "$mnt"
+}
+
+reformat_jffs2_partition() {
+ local mtd_name="$1"
+ local mnt="$2"
+ # unmount the partition to reformat it
+ umount -f "$mnt"
+ flash_erase "$(mtd_by_name "$mtd_name")" 0 0
+ # remount the JFFS2
+ if ! jffs2_mount "$mtd_name" "$mnt"; then
+ log "Failed to mount reformatted NV volume; system unstable"
+ fi
+}
+
+clear_ubenv() {
+ log "Clearing U-Boot environment"
+ flash_erase "$(mtd_by_name u-boot-env)" 0 0
+}
+
+# mount NV filesystem
+mkdir -p "$RWFS_MNT"
+if ! jffs2_mount "$NV_MTD" "$RWFS_MNT"; then
+ log "Failed to mount NV volume; attempting recovery"
+ reformat_jffs2_partition $NV_MTD $RWFS_MNT
+fi
+
+# check for full factory reset: if so, format $NV_MTD_DEV
+RESTORE_FLAG=$RWFS_MNT/.restore_op
+if [ -f "$RESTORE_FLAG" ]; then
+ mount -o remount,rw "$RWFS_MNT"
+ restore_op=$(cat $RESTORE_FLAG) # read from NV
+ modified_on=$(stat -c %y $RESTORE_FLAG) # get last modified time
+ log "restore_op: $restore_op modified on: $modified_on"
+ # To rule out stale file mounted, Write unique, unused value 0x10
+ # (last 2-bits are b00) before removing the file.
+ echo 16 > $RESTORE_FLAG
+ # set default value 0 if RESTORE_FLAG file was empty
+ restore_op=${restore_op:-0}
+ restore_op=$((restore_op & 3)) # mask off 2 bits
+ if [ $restore_op -eq 1 ]; then
+ targeted_clean
+ elif [ $restore_op -eq 2 ]; then
+ full_clean
+ clear_ubenv
+ elif [ $restore_op -eq 3 ]; then
+ log "restore-defaults: reformat"
+ reformat_jffs2_partition $NV_MTD $RWFS_MNT
+ clear_ubenv
+ fi
+ rm -f $RESTORE_FLAG
+ mount -o remount,ro "$RWFS_MNT"
+fi
+
+# Restore the overlay saved in the sync
+rsync -a --delete "${OVERLAY_SYNC}/" "${OVERLAY_MNT}"
+log "Restored overlay from sync location"
+
+for FS in $NV_OVERLAYS; do
+ nvrw "$FS"
+done
+
+# work around bug where /etc/machine-id will be mounted with a temporary file
+# if rootfs is read-only and the file is empty
+MACHINE_ID=/etc/machine-id
+generate_machine_id() {
+ systemd-machine-id-setup
+ cp -pf "$MACHINE_ID" "${MACHINE_ID}_bkup"
+}
+
+if [ ! -s "$MACHINE_ID" ]; then
+ # work around - Bug: Overlay fs fails for machine-id due to
+ # origin mismatch. Clean it up, from overlay fs before re-creating
+ # the same.
+ if [ -e "$OVERLAY_MNT$MACHINE_ID" ]; then
+ umount "/etc"
+ rm -f "$OVERLAY_MNT$MACHINE_ID"
+ nvrw "/etc"
+ # Restore the machine-id from backup, else generate it.
+ if [ -s "${MACHINE_ID}_bkup" ]; then
+ cp -pf "${MACHINE_ID}_bkup" "${MACHINE_ID}"
+ else
+ generate_machine_id
+ fi
+ log "Remounted /etc for machine-id origin mismatch"
+ else
+ generate_machine_id
+ fi
+fi
+
+# mount persistent NV filesystem, where immortal settings live
+SOFS_MNT=/var/sofs
+if ! grep -q sofs /proc/mounts; then
+ mkdir -p $SOFS_MNT
+ SOFS_MTD=sofs
+
+ # mount a JFFS2 on the partition
+ if ! jffs2_mount "$SOFS_MTD" "$SOFS_MNT"; then
+ log "Failed to mount SOFS volume; attempting recovery"
+ reformat_jffs2_partition $SOFS_MTD $SOFS_MNT
+ fi
+fi
+
+log "Finished mounting nv and overlays"
+
+
+# Detect the non-legacy node in cooper city and boot in to special mode.
+
+readonly COOPER_CITY=40 # Board id of cooper city
+
+is_nl_node() {
+ typeset -i nid1=$(gpioget $(gpiofind "FM_NODE_ID_1"))
+ typeset -i nid2=$(gpioget $(gpiofind "FM_NODE_ID_2"))
+ echo $((nid1|nid2))
+}
+
+read_board_id() {
+ local idx=0
+ local result=0
+ local value=0
+ for ((idx=0; idx<6; idx++))
+ do
+ typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N"))
+ value=$((value << idx))
+ result=$((result | value))
+ done
+ echo $result
+}
+
+pfr_write() {
+ [ $# -ne 2 ] && return 1
+ local PFR_BUS=4
+ local PFR_ADDR=0x38
+ local reg=$1
+ local val=$2
+ i2cset -y $PFR_BUS $PFR_ADDR "$reg" "$val" >&/dev/null
+}
+
+board_id=$(read_board_id)
+if [ "$board_id" -eq $COOPER_CITY ]; then
+ if [ "$(is_nl_node)" -ne 0 ]; then
+ systemctl set-default multi-node-nl.target
+ PFR_BMC_CHECKPOINT_REG=0xf
+ PFR_BMC_CHECKPOINT_COMPLETE=0x9
+ pfr_write $PFR_BMC_CHECKPOINT_REG $PFR_BMC_CHECKPOINT_COMPLETE
+ fi
+fi
+
+exec /lib/systemd/systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb
new file mode 100644
index 000000000..79971942a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb
@@ -0,0 +1,18 @@
+SUMMARY = "Provision mode daemon - RestrictionMode"
+DESCRIPTION = "Daemon allows to configure RestrictionMode property"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/provisioning-mode-manager.git;protocol=ssh"
+
+SRCREV = "0aca01b4ce9b303e12ba0f757f56390da139c8bb"
+
+inherit cmake systemd
+SYSTEMD_SERVICE:${PN} = "xyz.openbmc_project.RestrictionMode.Manager.service"
+
+DEPENDS = "boost sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb
new file mode 100644
index 000000000..783dea029
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb
@@ -0,0 +1,23 @@
+SUMMARY = "Security Manager daemon to detect the security violation- ASD/ user management"
+DESCRIPTION = "Daemon check for Remote debug enable and user account violation"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git/security-manager"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+inherit cmake systemd
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+SYSTEMD_SERVICE:${PN} += "xyz.openbmc_project.SecurityManager.service"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ libgpiod \
+ phosphor-logging \
+ boost \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend
new file mode 100644
index 000000000..8c2eeb83f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend
@@ -0,0 +1,4 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git"
+SRCREV = "87e3fcf439f2b943272365e1d294984f39bb52b8"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service
new file mode 100644
index 000000000..b8c3554ae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service
@@ -0,0 +1,10 @@
+[Unit]
+Description= BMC Self-Test
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/env selftest
+SyslogIdentifier=selftest
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch
new file mode 100644
index 000000000..33d35ec5e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch
@@ -0,0 +1,108 @@
+From 2516d67f8bb5ecd241b8dcdec3f8c58d0e3c4744 Mon Sep 17 00:00:00 2001
+From: Wojciech Dembinski <wojciech.dembinski@intel.com>
+Date: Mon, 7 Dec 2020 19:23:10 +0100
+Subject: [PATCH] Add check for min/max received from hwmon files
+
+When hwmon reports incorrect min/max values or CPU Sensor cannot access
+readings, it shall keep the last known good readings and not update
+DBus with incorrect values.
+This patch adds min < max verification check for the values received
+from hwmon and removes check for power on/off in the case of a read
+failure.
+
+Tested manually on a physical platform, test cases cover incorrect
+max/min values and failing access to hwmon files.
+SDR over IPMI can be fully received in the case of error.
+
+Signed-off-by: Wojciech Dembinski <wojciech.dembinski@intel.com>
+Change-Id: Ia061f849b0f434812f822ed1902c8964d4c64b45
+---
+ src/CPUSensor.cpp | 50 ++++++++++++++++++++++++-----------------------
+ 1 file changed, 26 insertions(+), 24 deletions(-)
+
+diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
+index 2356821..01f5eb6 100644
+--- a/src/CPUSensor.cpp
++++ b/src/CPUSensor.cpp
+@@ -1,5 +1,5 @@
+ /*
+-// Copyright (c) 2018 Intel Corporation
++// Copyright (c) 2018-2021 Intel Corporation
+ //
+ // Licensed under the Apache License, Version 2.0 (the "License");
+ // you may not use this file except in compliance with the License.
+@@ -146,19 +146,22 @@ void CPUSensor::setupRead(void)
+
+ void CPUSensor::updateMinMaxValues(void)
+ {
++ double newMin = std::numeric_limits<double>::quiet_NaN();
++ double newMax = std::numeric_limits<double>::quiet_NaN();
++
+ const boost::container::flat_map<
+ std::string,
+ std::vector<std::tuple<const char*, std::reference_wrapper<double>,
+- const char*>>>
+- map = {
++ const char*, std::reference_wrapper<double>>>>
++ map = {
++ {
++ "cap",
+ {
+- "cap",
+- {
+- std::make_tuple("cap_max", std::ref(maxValue), "MaxValue"),
+- std::make_tuple("cap_min", std::ref(minValue), "MinValue"),
+- },
++ std::make_tuple("cap_max", std::ref(maxValue), "MaxValue", std::ref(newMax)),
++ std::make_tuple("cap_min", std::ref(minValue), "MinValue", std::ref(newMin)),
+ },
+- };
++ },
++ };
+
+ if (auto fileParts = splitFileName(path))
+ {
+@@ -168,26 +171,25 @@ void CPUSensor::updateMinMaxValues(void)
+ {
+ for (const auto& vectorItem : mapIt->second)
+ {
+- auto& [suffix, oldValue, dbusName] = vectorItem;
++ auto& [suffix, oldValue, dbusName, newValue] = vectorItem;
+ auto attrPath = boost::replace_all_copy(path, fileItem, suffix);
+- if (auto newVal =
+- readFile(attrPath, CPUSensor::sensorScaleFactor))
++
++ if(auto tmp = readFile(attrPath, CPUSensor::sensorScaleFactor))
+ {
+- updateProperty(sensorInterface, oldValue, *newVal,
+- dbusName);
++ newValue.get() = *tmp;
+ }
+ else
+ {
+- if (isPowerOn())
+- {
+- updateProperty(sensorInterface, oldValue, 0, dbusName);
+- }
+- else
+- {
+- updateProperty(sensorInterface, oldValue,
+- std::numeric_limits<double>::quiet_NaN(),
+- dbusName);
+- }
++ newValue.get() = std::numeric_limits<double>::quiet_NaN();
++ }
++ }
++
++ if(std::isfinite(newMin) && std::isfinite(newMax) && (newMin < newMax))
++ {
++ for (const auto& vectorItem : mapIt->second)
++ {
++ auto& [suffix, oldValue, dbusName, newValue] = vectorItem;
++ updateProperty(sensorInterface, oldValue, newValue, dbusName);
+ }
+ }
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch
new file mode 100644
index 000000000..cfdc99d66
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch
@@ -0,0 +1,159 @@
+From 0a1b2a13f6dbc64b5851ac2b1ca99d57afa78d60 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 27 Jan 2021 15:52:16 -0800
+Subject: [PATCH] Fix PECI client creation flow
+
+This commit fixes the PECI client creation flow to make it retry
+the creation when the client is not exposed correctly.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ src/CPUSensorMain.cpp | 66 +++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 54 insertions(+), 12 deletions(-)
+
+diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp
+index f304e3f..92c1716 100644
+--- a/src/CPUSensorMain.cpp
++++ b/src/CPUSensorMain.cpp
+@@ -82,6 +82,7 @@ struct CPUConfig
+ };
+
+ static constexpr const char* peciDev = "/dev/peci-";
++static constexpr const char* peciDevPath = "/sys/bus/peci/devices/";
+ static constexpr const unsigned int rankNumMax = 8;
+
+ namespace fs = std::filesystem;
+@@ -167,7 +168,7 @@ bool createSensors(boost::asio::io_service& io,
+ }
+
+ std::vector<fs::path> hwmonNamePaths;
+- if (!findFiles(fs::path(R"(/sys/bus/peci/devices)"),
++ if (!findFiles(fs::path(peciDevPath),
+ R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/name$)",
+ hwmonNamePaths, 6))
+ {
+@@ -403,7 +404,7 @@ bool createSensors(boost::asio::io_service& io,
+ return true;
+ }
+
+-void exportDevice(const CPUConfig& config)
++int exportDevice(const CPUConfig& config)
+ {
+ std::ostringstream hex;
+ hex << std::hex << config.addr;
+@@ -411,9 +412,12 @@ void exportDevice(const CPUConfig& config)
+ std::string busStr = std::to_string(config.bus);
+
+ std::string parameters = "peci-client 0x" + addrHexStr;
+- std::string device = "/sys/bus/peci/devices/peci-" + busStr + "/new_device";
++ std::string devPath = peciDevPath;
++ std::string delDevice = devPath + "peci-" + busStr + "/delete_device";
++ std::string newDevice = devPath + "peci-" + busStr + "/new_device";
++ std::string newClient = devPath + busStr + "-" + addrHexStr + "/driver";
+
+- std::filesystem::path devicePath(device);
++ std::filesystem::path devicePath(newDevice);
+ const std::string& dir = devicePath.parent_path().string();
+ for (const auto& path : std::filesystem::directory_iterator(dir))
+ {
+@@ -431,20 +435,38 @@ void exportDevice(const CPUConfig& config)
+ std::cout << parameters << " on bus " << busStr
+ << " is already exported\n";
+ }
+- return;
++
++ std::ofstream delDeviceFile(delDevice);
++ if (!delDeviceFile.good())
++ {
++ std::cerr << "Error opening " << delDevice << "\n";
++ return -1;
++ }
++ delDeviceFile << parameters;
++ delDeviceFile.close();
++
++ break;
+ }
+ }
+
+- std::ofstream deviceFile(device);
++ std::ofstream deviceFile(newDevice);
+ if (!deviceFile.good())
+ {
+- std::cerr << "Error writing " << device << "\n";
+- return;
++ std::cerr << "Error opening " << newDevice << "\n";
++ return -1;
+ }
+ deviceFile << parameters;
+ deviceFile.close();
+
++ if (!std::filesystem::exists(newClient))
++ {
++ std::cerr << "Error creating " << newClient << "\n";
++ return -1;
++ }
++
+ std::cout << parameters << " on bus " << busStr << " is exported\n";
++
++ return 0;
+ }
+
+ void detectCpu(boost::asio::deadline_timer& pingTimer,
+@@ -460,6 +482,11 @@ void detectCpu(boost::asio::deadline_timer& pingTimer,
+
+ for (CPUConfig& config : cpuConfigs)
+ {
++ if (config.state == State::READY)
++ {
++ continue;
++ }
++
+ std::string peciDevPath = peciDev + std::to_string(config.bus);
+ auto file = open(peciDevPath.c_str(), O_RDWR | O_CLOEXEC);
+ if (file < 0)
+@@ -510,16 +537,29 @@ void detectCpu(boost::asio::deadline_timer& pingTimer,
+ newState = State::OFF;
+ }
+
+- close(file);
+-
+ if (config.state != newState)
+ {
+ if (newState != State::OFF)
+ {
+ if (config.state == State::OFF)
+ {
+- std::cout << config.name << " is detected\n";
+- exportDevice(config);
++ struct peci_rd_pkg_cfg_msg msg;
++ msg.addr = config.addr;
++ msg.index = PECI_MBX_INDEX_CPU_ID;
++ msg.param = 0;
++ msg.rx_len = 4;
++ if (!ioctl(file, PECI_IOC_RD_PKG_CFG, &msg))
++ {
++ std::cout << config.name << " is detected\n";
++ if (exportDevice(config))
++ {
++ newState = State::OFF;
++ }
++ }
++ else
++ {
++ newState = State::OFF;
++ }
+ }
+
+ if (newState == State::ON)
+@@ -542,6 +582,8 @@ void detectCpu(boost::asio::deadline_timer& pingTimer,
+ keepPinging = true;
+ }
+
++ close(file);
++
+ if (debug)
+ {
+ std::cout << config.name << ", state: " << config.state << "\n";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch
new file mode 100644
index 000000000..1cba1095d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch
@@ -0,0 +1,143 @@
+From db4353de222b51726c8e3c765cc8f1df4ad67687 Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Tue, 22 Jun 2021 11:35:12 -0700
+Subject: [PATCH] Fix missing de-assert event when threshold changes
+
+Issue:
+Sensor can be re-constructed when sensor configuration changes
+like a new threshold value. Threshold deassert can be missed
+if the new threshold value fixes the alarm because the
+default state for new threshold interface is de-asserted.
+
+Resolution:
+Add a member variable hadValidSensor that is initialized to false
+for new sensor. When hadValidSensor is false, threshold property changed
+message will be emitted even if threshold property did not change,
+If the previous sensor instance had the threshold raised,
+Phosphor-sel-logger would notice the change and log a de-assert event.
+If the previous sensor instance did not have the threshold raised,
+Phosphor-sel-logger would notice this is not a change and not create
+new SEL log.
+Set hadValidSensor to true when sensor value is updated with a value
+that is not NaN. This is done after threshold property changed message
+is emitted.
+
+Tested:
+1. Change threshold value for a voltage sensor to force a SEL.
+ ipmitool raw 0x04 0x26 0x60 0x1b 0x95 0x6b 0x00 0x99 0xa6 0x00
+
+2. Verify SEL logged threshold assert event as expected
+ ipmitool sel list
+ 1 | Pre-Init |0000007277| Voltage #0x60 | Upper Non-critical going high | Asserted
+
+3. Use ipmitool to change threshold value back to normal
+ ipmitool raw 0x04 0x26 0x60 0x1b 0x95 0x6b 0x00 0xa4 0xa6 0x00
+
+4. Verify SEL logged threshold de-assert event as expected
+ ipmitool sel list
+ 1 | Pre-Init |0000007277| Voltage #0x60 | Upper Non-critical going high | Asserted
+ 2 | Pre-Init |0000007304| Voltage #0x60 | Upper Non-critical going high | Deasserted
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ include/Thresholds.hpp | 2 +-
+ include/sensor.hpp | 2 ++
+ src/Thresholds.cpp | 20 ++++++++++++++++----
+ 3 files changed, 19 insertions(+), 5 deletions(-)
+
+diff --git a/include/Thresholds.hpp b/include/Thresholds.hpp
+index af63f72..fd507d0 100644
+--- a/include/Thresholds.hpp
++++ b/include/Thresholds.hpp
+@@ -44,7 +44,7 @@ struct Threshold
+
+ void assertThresholds(Sensor* sensor, double assertValue,
+ thresholds::Level level, thresholds::Direction direction,
+- bool assert);
++ bool assert, bool force = false);
+
+ struct TimerUsed
+ {
+diff --git a/include/sensor.hpp b/include/sensor.hpp
+index b98241b..6235674 100644
+--- a/include/sensor.hpp
++++ b/include/sensor.hpp
+@@ -71,6 +71,7 @@ struct Sensor
+ std::shared_ptr<sdbusplus::asio::dbus_interface> operationalInterface;
+ double value = std::numeric_limits<double>::quiet_NaN();
+ double rawValue = std::numeric_limits<double>::quiet_NaN();
++ bool hadValidValue = false;
+ bool overriddenState = false;
+ bool internalSet = false;
+ double hysteresisTrigger;
+@@ -432,6 +433,7 @@ struct Sensor
+ {
+ markFunctional(true);
+ markAvailable(true);
++ hadValidValue = true;
+ }
+ }
+
+diff --git a/src/Thresholds.cpp b/src/Thresholds.cpp
+index 821083a..da0d650 100644
+--- a/src/Thresholds.cpp
++++ b/src/Thresholds.cpp
+@@ -418,10 +418,19 @@ bool checkThresholds(Sensor* sensor)
+ {
+ bool status = true;
+ std::vector<ChangeParam> changes = checkThresholds(sensor, sensor->value);
++
++ // Sensor can be reconstructed when sensor configuration changes
++ // like a new threshold value. Threshold deassert can be missed
++ // if the new threshold value fixes the alarm because
++ // default state for new threshold interface is de-asserted.
++ // force sending assert/de-assert message when a not NaN value is updated
++ // for the first time even when threshold property did not change.
++ bool forceAssert = !sensor->hadValidValue;
+ for (const auto& change : changes)
+ {
+ assertThresholds(sensor, change.assertValue, change.threshold.level,
+- change.threshold.direction, change.asserted);
++ change.threshold.direction, change.asserted,
++ forceAssert);
+ if (change.threshold.level == thresholds::Level::CRITICAL &&
+ change.asserted)
+ {
+@@ -443,6 +452,7 @@ void checkThresholdsPowerDelay(const std::weak_ptr<Sensor>& weakSensor,
+
+ Sensor* sensor = sensorPtr.get();
+ std::vector<ChangeParam> changes = checkThresholds(sensor, sensor->value);
++ bool forceAssert = !sensor->hadValidValue;
+ for (const auto& change : changes)
+ {
+ // When CPU is powered off, some volatges are expected to
+@@ -467,13 +477,13 @@ void checkThresholdsPowerDelay(const std::weak_ptr<Sensor>& weakSensor,
+ }
+ }
+ assertThresholds(sensor, change.assertValue, change.threshold.level,
+- change.threshold.direction, change.asserted);
++ change.threshold.direction, change.asserted, forceAssert);
+ }
+ }
+
+ void assertThresholds(Sensor* sensor, double assertValue,
+ thresholds::Level level, thresholds::Direction direction,
+- bool assert)
++ bool assert, bool force)
+ {
+ std::string property;
+ std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
+@@ -513,7 +523,9 @@ void assertThresholds(Sensor* sensor, double assertValue,
+ return;
+ }
+
+- if (interface->set_property<bool, true>(property, assert))
++ bool propertyChanged =
++ interface->set_property<bool, true>(property, assert);
++ if (force || propertyChanged)
+ {
+ try
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch
new file mode 100644
index 000000000..214fbe888
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch
@@ -0,0 +1,54 @@
+From 221aaf1431a01fefb5e7df2461a1c691738a50a7 Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Fri, 19 Feb 2021 12:14:05 -0800
+Subject: [PATCH] Fan Tach Sensor Threshold Ignore Zero
+
+Currently there are systems that have system fans plugged
+into different fan connectors. Fan present detection is
+not supported in most of these systems. Critical low
+threshold is asserted for the non-utilized fans
+resulting in FSC boost all fans.
+
+Skip threshold checking for fan tach reading less or equal
+to zero. This is a temporary WA until a more robust solution
+is available.
+
+Note: with this workaround a completely non-working fan
+will not be detected. FSC will still boost fans due to other
+constraints if the system can't be cooled with the working fans.
+
+Tested:
+No cr event for the missing fans.
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ src/TachSensor.cpp | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/src/TachSensor.cpp b/src/TachSensor.cpp
+index c375dbf..e85a2a2 100644
+--- a/src/TachSensor.cpp
++++ b/src/TachSensor.cpp
+@@ -186,10 +186,16 @@ void TachSensor::checkThresholds(void)
+ // WA - treat value <= 0 as not present
+ bool status = false;
+
+- if (redundancy && *redundancy)
++ if (value > 0)
+ {
+- (*redundancy)
+- ->update("/xyz/openbmc_project/sensors/fan_tach/" + name, !status);
++ status = thresholds::checkThresholds(this);
++
++ if (redundancy && *redundancy)
++ {
++ (*redundancy)
++ ->update("/xyz/openbmc_project/sensors/fan_tach/" + name,
++ !status);
++ }
+ }
+
+ bool curLed = !status;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch
new file mode 100644
index 000000000..8119f7542
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch
@@ -0,0 +1,29 @@
+From f85dd776301371892ff5197c1995bf2224dd87ab Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 22 Feb 2021 15:57:20 -0800
+Subject: [PATCH] Fix PECI ioctl number
+
+This commit fixes PECI ioctl number to 0xb8 to avoid conflicts in
+kernel v5.10.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ include/linux/peci-ioctl.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/peci-ioctl.h b/include/linux/peci-ioctl.h
+index e5b4b8bd3275..1f44edf4fc04 100644
+--- a/include/linux/peci-ioctl.h
++++ b/include/linux/peci-ioctl.h
+@@ -601,7 +601,7 @@ struct peci_crashdump_get_frame_msg {
+ __u8 data[16];
+ } __attribute__((__packed__));
+
+-#define PECI_IOC_BASE 0xb7
++#define PECI_IOC_BASE 0xb8
+
+ #define PECI_IOC_XFER \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_XFER, struct peci_xfer_msg)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0006-CPUSensor-create-RequirediTempSensor-if-defined.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0006-CPUSensor-create-RequirediTempSensor-if-defined.patch
new file mode 100644
index 000000000..2083adfef
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0006-CPUSensor-create-RequirediTempSensor-if-defined.patch
@@ -0,0 +1,233 @@
+From 6ace96be5a7b6763545c1dfc572f8e2790d99d4b Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Tue, 11 May 2021 11:14:55 -0700
+Subject: [PATCH] CPUSensor: create RequiredTempSensor if defined
+
+When BMC fails to talk to CPU through PECI, no
+CPU sensors are created. Fan speed control only boost
+fan when input sensor is not available. It does not
+have the knowledge of which sensors are expected to
+be present and can't treat "missing" sensor as failed one.
+The failure on PECI goes unnoticed and we can have a thermal
+run away.
+
+Query sensor config for RequiredTempSensor for any present
+CPUs. Create a CPU sensor that is not available.
+This sensor will be replaced by a normal CPU sensor when
+peci detect the CPU and associated hwmon file is discovered.
+
+This is an initial patch that target to address the particular
+failure case. More work will follow to support a more generic
+"Required" sensor config.
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ include/CPUSensor.hpp | 9 ++++++
+ src/CPUSensor.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++
+ src/CPUSensorMain.cpp | 54 +++++++++++++++++++++++++++++-----
+ 3 files changed, 123 insertions(+), 8 deletions(-)
+
+diff --git a/include/CPUSensor.hpp b/include/CPUSensor.hpp
+index 8b51b76..93b7fcc 100644
+--- a/include/CPUSensor.hpp
++++ b/include/CPUSensor.hpp
+@@ -26,6 +26,15 @@ class CPUSensor : public Sensor
+ std::vector<thresholds::Threshold>&& thresholds,
+ const std::string& configuration, int cpuId, bool show,
+ double dtsOffset);
++
++ // Create a CPUSensor without a path to sensor value
++ CPUSensor(const std::string& objectType,
++ sdbusplus::asio::object_server& objectServer,
++ std::shared_ptr<sdbusplus::asio::connection>& conn,
++ boost::asio::io_service& io, const std::string& sensorName,
++ std::vector<thresholds::Threshold>&& thresholdsIn,
++ const std::string& sensorConfiguration);
++
+ ~CPUSensor() override;
+ static constexpr unsigned int sensorScaleFactor = 1000;
+ static constexpr unsigned int sensorPollMs = 1000;
+diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
+index c330088..3861ade 100644
+--- a/src/CPUSensor.cpp
++++ b/src/CPUSensor.cpp
+@@ -98,6 +98,74 @@ CPUSensor::CPUSensor(const std::string& path, const std::string& objectType,
+ setupRead();
+ }
+
++// Create a dummy "not available" CPUSensor
++// This is used to indicate a missing required sensor for
++// other services like fan control
++CPUSensor::CPUSensor(const std::string& objectType,
++ sdbusplus::asio::object_server& objectServer,
++ std::shared_ptr<sdbusplus::asio::connection>& conn,
++ boost::asio::io_service& io, const std::string& sensorName,
++ std::vector<thresholds::Threshold>&& thresholdsIn,
++ const std::string& sensorConfiguration) :
++ Sensor(escapeName(sensorName), std::move(thresholdsIn), sensorConfiguration,
++ objectType, false, false, 0, 0, conn, PowerState::on),
++ objServer(objectServer), inputDev(io), waitTimer(io),
++ privTcontrol(std::numeric_limits<double>::quiet_NaN()), dtsOffset(0),
++ show(true), pollTime(CPUSensor::sensorPollMs), minMaxReadCounter(0)
++{
++ // assume it is a temperature sensor for now
++ // support for other type can be added later
++ std::string interfacePath =
++ "/xyz/openbmc_project/sensors/temperature/" + name;
++ const char* units = sensor_paths::unitDegreesC;
++ minValue = -128;
++ maxValue = 127;
++
++ sensorInterface = objectServer.add_interface(
++ interfacePath, "xyz.openbmc_project.Sensor.Value");
++
++ sensorInterface->register_property("Unit", units);
++ sensorInterface->register_property("MaxValue", maxValue);
++ sensorInterface->register_property("MinValue", minValue);
++ sensorInterface->register_property(
++ "Value", value, [&](const double& newValue, double& oldValue) {
++ return setSensorValue(newValue, oldValue);
++ });
++ if (!sensorInterface->initialize())
++ {
++ std::cerr << "error initializing value interface\n";
++ }
++
++ if (!availableInterface)
++ {
++ availableInterface = std::make_shared<sdbusplus::asio::dbus_interface>(
++ conn, sensorInterface->get_object_path(), availableInterfaceName);
++ availableInterface->register_property(
++ "Available", false, [this](const bool propIn, bool& old) {
++ if (propIn == old)
++ {
++ return 1;
++ }
++ old = propIn;
++ if (!propIn)
++ {
++ updateValue(std::numeric_limits<double>::quiet_NaN());
++ }
++ return 1;
++ });
++ availableInterface->initialize();
++ }
++ if (!operationalInterface)
++ {
++ operationalInterface =
++ std::make_shared<sdbusplus::asio::dbus_interface>(
++ conn, sensorInterface->get_object_path(),
++ operationalInterfaceName);
++ operationalInterface->register_property("Functional", true);
++ operationalInterface->initialize();
++ }
++}
++
+ CPUSensor::~CPUSensor()
+ {
+ // close the input dev to cancel async operations
+diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp
+index 0d94e4b..1d12fa6 100644
+--- a/src/CPUSensorMain.cpp
++++ b/src/CPUSensorMain.cpp
+@@ -332,10 +332,9 @@ bool createSensors(boost::asio::io_service& io,
+ {
+ if (debug)
+ {
+- std::cout << "Skipped: " << inputPath << ": " << sensorName
+- << " is already created\n";
++ std::cout << "Will be replaced: " << inputPath << ": "
++ << sensorName << " is already created\n";
+ }
+- continue;
+ }
+
+ // check hidden properties
+@@ -636,9 +635,9 @@ void detectCpuAsync(
+ });
+ }
+
+-bool getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
++bool getCpuConfig(std::shared_ptr<sdbusplus::asio::connection>& systemBus,
+ boost::container::flat_set<CPUConfig>& cpuConfigs,
+- ManagedObjectType& sensorConfigs,
++ ManagedObjectType& sensorConfigs, boost::asio::io_service& io,
+ sdbusplus::asio::object_server& objectServer)
+ {
+ bool useCache = false;
+@@ -700,6 +699,45 @@ bool getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
+ iface->register_property("Present", *present);
+ iface->initialize();
+ inventoryIfaces[name] = std::move(iface);
++ if (*present)
++ {
++ // create required CPU sensors here in unavailable state
++ auto findRequiredTempSensor =
++ config.second.find("RequiredTempSensor");
++ auto findCpuId = config.second.find("CpuID");
++ if (findRequiredTempSensor != config.second.end() &&
++ findCpuId != config.second.end())
++ {
++ std::string label =
++ std::visit(VariantToStringVisitor(),
++ findRequiredTempSensor->second);
++ // for temp sensor hwmon sysfs use input
++ std::string item{"input"};
++ int cpuId =
++ std::visit(VariantToUnsignedIntVisitor(),
++ findCpuId->second);
++ std::string requiredSensorName =
++ createSensorName(label, item, cpuId);
++
++ auto& sensorPtr = gCpuSensors[requiredSensorName];
++ if (sensorPtr == nullptr)
++ {
++ // created a dummy sensor for required sensor,
++ // will be replaced with a real one if it is
++ // detected
++ std::string objectType{};
++ std::vector<thresholds::Threshold>
++ emptyThreshold{};
++ std::string emptyConfig{};
++ sensorPtr = std::make_unique<CPUSensor>(
++ objectType, objectServer, systemBus, io,
++ requiredSensorName,
++ std::move(emptyThreshold), emptyConfig);
++ std::cout << "created required CPU sensor "
++ << requiredSensorName << "\n";
++ }
++ }
++ }
+ }
+
+ auto findBus = config.second.find("Bus");
+@@ -728,7 +766,6 @@ bool getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
+ std::cout << "name: " << name << "\n";
+ std::cout << "type: " << type << "\n";
+ }
+-
+ cpuConfigs.emplace(bus, addr, name, State::OFF);
+ }
+ }
+@@ -764,7 +801,8 @@ int main()
+ return; // we're being canceled
+ }
+
+- if (getCpuConfig(systemBus, cpuConfigs, sensorConfigs, objectServer))
++ if (getCpuConfig(systemBus, cpuConfigs, sensorConfigs, io,
++ objectServer))
+ {
+ detectCpuAsync(pingTimer, creationTimer, io, objectServer,
+ systemBus, cpuConfigs, sensorConfigs);
+@@ -792,7 +830,7 @@ int main()
+ return; // we're being canceled
+ }
+
+- if (getCpuConfig(systemBus, cpuConfigs, sensorConfigs,
++ if (getCpuConfig(systemBus, cpuConfigs, sensorConfigs, io,
+ objectServer))
+ {
+ detectCpuAsync(pingTimer, creationTimer, io, objectServer,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0007-Add-support-for-the-energy-hwmon-type.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0007-Add-support-for-the-energy-hwmon-type.patch
new file mode 100644
index 000000000..daaca7fae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0007-Add-support-for-the-energy-hwmon-type.patch
@@ -0,0 +1,266 @@
+From 9f5ef2e8d9c34d9d9ddce34d450aaedd5c122b22 Mon Sep 17 00:00:00 2001
+From: Szymon Dompke <szymon.dompke@intel.com>
+Date: Tue, 18 May 2021 05:22:33 +0200
+Subject: [PATCH] Add support for the energy hwmon type
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+With this commit CPUSensors should be able detect hwmon files of type
+‘energy’ described here:
+
+ https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
+
+These files hold a cumulative energy [micro Joule].
+Values read from these type of files will be exposed on dbus as a new
+sensor. An example:
+
+└─/xyz
+ └─/xyz/openbmc_project
+ └─/xyz/openbmc_project/sensors
+ ├─/xyz/openbmc_project/sensors/energy
+ │ └─/xyz/openbmc_project/sensors/energy/Cumulative_Energy_CPU1
+
+The energy counter will have different scale factor and different
+default min/max values than other types of CPU sensors (power/temp).
+
+Tested:
+ Tested on physical machine where the `energy_input` files were present,
+ works as desired no regression detected.
+
+Authored-by: Zbigniew Kurzynski <zbigniew.kurzynski@intel.com>
+Signed-off-by: Szymon Dompke <szymon.dompke@intel.com>
+---
+ include/CPUSensor.hpp | 13 +++++++--
+ src/CPUSensor.cpp | 68 +++++++++++++++----------------------------
+ src/CPUSensorMain.cpp | 30 ++++++++++++++++---
+ 3 files changed, 60 insertions(+), 51 deletions(-)
+
+diff --git a/include/CPUSensor.hpp b/include/CPUSensor.hpp
+index 93b7fcc..76e43dc 100644
+--- a/include/CPUSensor.hpp
++++ b/include/CPUSensor.hpp
+@@ -16,6 +16,15 @@
+ #include <variant>
+ #include <vector>
+
++struct SensorProperties
++{
++ std::string path;
++ std::string units;
++ double max;
++ double min;
++ unsigned int scaleFactor;
++};
++
+ class CPUSensor : public Sensor
+ {
+ public:
+@@ -25,7 +34,7 @@ class CPUSensor : public Sensor
+ boost::asio::io_service& io, const std::string& sensorName,
+ std::vector<thresholds::Threshold>&& thresholds,
+ const std::string& configuration, int cpuId, bool show,
+- double dtsOffset);
++ double dtsOffset, const SensorProperties& sensorProperties);
+
+ // Create a CPUSensor without a path to sensor value
+ CPUSensor(const std::string& objectType,
+@@ -36,7 +45,6 @@ class CPUSensor : public Sensor
+ const std::string& sensorConfiguration);
+
+ ~CPUSensor() override;
+- static constexpr unsigned int sensorScaleFactor = 1000;
+ static constexpr unsigned int sensorPollMs = 1000;
+ static constexpr size_t warnAfterErrorCount = 10;
+ static constexpr const char* labelTcontrol = "Tcontrol";
+@@ -54,6 +62,7 @@ class CPUSensor : public Sensor
+ size_t pollTime;
+ bool loggedInterfaceDown = false;
+ uint8_t minMaxReadCounter;
++ unsigned int scaleFactor;
+ void setupRead(void);
+ void handleResponse(const boost::system::error_code& err);
+ void checkThresholds(void) override;
+diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
+index 3861ade..6737151 100644
+--- a/src/CPUSensor.cpp
++++ b/src/CPUSensor.cpp
+@@ -39,58 +39,37 @@ CPUSensor::CPUSensor(const std::string& path, const std::string& objectType,
+ boost::asio::io_service& io, const std::string& sensorName,
+ std::vector<thresholds::Threshold>&& thresholdsIn,
+ const std::string& sensorConfiguration, int cpuId,
+- bool show, double dtsOffset) :
++ bool show, double dtsOffset,
++ const SensorProperties& sensorProperties) :
+ Sensor(escapeName(sensorName), std::move(thresholdsIn), sensorConfiguration,
+- objectType, false, false, 0, 0, conn, PowerState::on),
++ objectType, false, false, sensorProperties.max, sensorProperties.min,
++ conn, PowerState::on),
+ objServer(objectServer), inputDev(io), waitTimer(io), path(path),
+ privTcontrol(std::numeric_limits<double>::quiet_NaN()),
+ dtsOffset(dtsOffset), show(show), pollTime(CPUSensor::sensorPollMs),
+- minMaxReadCounter(0)
++ minMaxReadCounter(0), scaleFactor(sensorProperties.scaleFactor)
+ {
+ nameTcontrol = labelTcontrol;
+ nameTcontrol += " CPU" + std::to_string(cpuId);
+ if (show)
+ {
+- if (auto fileParts = splitFileName(path))
++ std::string interfacePath = sensorProperties.path + name;
++ sensorInterface = objectServer.add_interface(
++ interfacePath, "xyz.openbmc_project.Sensor.Value");
++ if (thresholds::hasWarningInterface(thresholds))
+ {
+- auto& [type, nr, item] = *fileParts;
+- std::string interfacePath;
+- const char* units;
+- if (type.compare("power") == 0)
+- {
+- interfacePath = "/xyz/openbmc_project/sensors/power/" + name;
+- units = sensor_paths::unitWatts;
+- minValue = 0;
+- maxValue = 511;
+- }
+- else
+- {
+- interfacePath =
+- "/xyz/openbmc_project/sensors/temperature/" + name;
+- units = sensor_paths::unitDegreesC;
+- minValue = -128;
+- maxValue = 127;
+- }
+-
+- sensorInterface = objectServer.add_interface(
+- interfacePath, "xyz.openbmc_project.Sensor.Value");
+- if (thresholds::hasWarningInterface(thresholds))
+- {
+- thresholdInterfaceWarning = objectServer.add_interface(
+- interfacePath,
+- "xyz.openbmc_project.Sensor.Threshold.Warning");
+- }
+- if (thresholds::hasCriticalInterface(thresholds))
+- {
+- thresholdInterfaceCritical = objectServer.add_interface(
+- interfacePath,
+- "xyz.openbmc_project.Sensor.Threshold.Critical");
+- }
+- association = objectServer.add_interface(interfacePath,
+- association::interface);
+-
+- setInitialProperties(conn, units);
++ thresholdInterfaceWarning = objectServer.add_interface(
++ interfacePath, "xyz.openbmc_project.Sensor.Threshold.Warning");
+ }
++ if (thresholds::hasCriticalInterface(thresholds))
++ {
++ thresholdInterfaceCritical = objectServer.add_interface(
++ interfacePath, "xyz.openbmc_project.Sensor.Threshold.Critical");
++ }
++ association =
++ objectServer.add_interface(interfacePath, association::interface);
++
++ setInitialProperties(conn, sensorProperties.units);
+ }
+
+ // call setup always as not all sensors call setInitialProperties
+@@ -248,7 +227,7 @@ void CPUSensor::updateMinMaxValues(void)
+ auto& [suffix, oldValue, dbusName, newValue] = vectorItem;
+ auto attrPath = boost::replace_all_copy(path, fileItem, suffix);
+
+- if(auto tmp = readFile(attrPath, CPUSensor::sensorScaleFactor))
++ if (auto tmp = readFile(attrPath, scaleFactor))
+ {
+ newValue.get() = *tmp;
+ }
+@@ -302,7 +281,7 @@ void CPUSensor::handleResponse(const boost::system::error_code& err)
+ std::getline(responseStream, response);
+ rawValue = std::stod(response);
+ responseStream.clear();
+- double nvalue = rawValue / CPUSensor::sensorScaleFactor;
++ double nvalue = rawValue / scaleFactor;
+
+ if (show)
+ {
+@@ -328,8 +307,7 @@ void CPUSensor::handleResponse(const boost::system::error_code& err)
+ {
+ std::vector<thresholds::Threshold> newThresholds;
+ if (parseThresholdsFromAttr(newThresholds, path,
+- CPUSensor::sensorScaleFactor,
+- dtsOffset))
++ scaleFactor, dtsOffset))
+ {
+ if (!std::equal(thresholds.begin(), thresholds.end(),
+ newThresholds.begin(),
+diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp
+index 1d12fa6..e348aa7 100644
+--- a/src/CPUSensorMain.cpp
++++ b/src/CPUSensorMain.cpp
+@@ -94,6 +94,18 @@ static constexpr auto sensorTypes{std::to_array<const char*>({"XeonCPU"})};
+ static constexpr auto hiddenProps{std::to_array<const char*>(
+ {CPUSensor::labelTcontrol, "Tthrottle", "Tjmax"})};
+
++static const boost::container::flat_map<std::string, SensorProperties>
++ sensorPropertiesMap = {
++ {"power",
++ {"/xyz/openbmc_project/sensors/power/", sensor_paths::unitWatts, 511,
++ 0, 1000}},
++ {"energy",
++ {"/xyz/openbmc_project/sensors/energy/", sensor_paths::unitJoules,
++ std::numeric_limits<uint32_t>::max() / 1000000, 0.0, 1000000}},
++ {"temp",
++ {"/xyz/openbmc_project/sensors/temperature/",
++ sensor_paths::unitDegreesC, 127.0, -128.0, 1000}}};
++
+ void detectCpuAsync(
+ boost::asio::deadline_timer& pingTimer,
+ boost::asio::deadline_timer& creationTimer, boost::asio::io_service& io,
+@@ -296,7 +308,8 @@ bool createSensors(boost::asio::io_service& io,
+
+ auto directory = hwmonNamePath.parent_path();
+ std::vector<fs::path> inputPaths;
+- if (!findFiles(directory, R"((temp|power)\d+_(input|average|cap)$)",
++ if (!findFiles(directory,
++ R"((temp|power|energy)\d+_(input|average|cap)$)",
+ inputPaths, 0))
+ {
+ std::cerr << "No temperature sensors in system\n";
+@@ -364,6 +377,16 @@ bool createSensors(boost::asio::io_service& io,
+ }
+ }
+
++ const auto& it = sensorPropertiesMap.find(type);
++ if (it == sensorPropertiesMap.end())
++ {
++ std::cerr
++ << "Failure getting sensor properties for sensor type: "
++ << type << "\n";
++ continue;
++ }
++ const SensorProperties& prop = it->second;
++
+ std::vector<thresholds::Threshold> sensorThresholds;
+ std::string labelHead = label.substr(0, label.find(' '));
+ parseThresholdsFromConfig(*sensorData, sensorThresholds,
+@@ -371,8 +394,7 @@ bool createSensors(boost::asio::io_service& io,
+ if (sensorThresholds.empty())
+ {
+ if (!parseThresholdsFromAttr(sensorThresholds, inputPathStr,
+- CPUSensor::sensorScaleFactor,
+- dtsOffset))
++ prop.scaleFactor, dtsOffset))
+ {
+ std::cerr << "error populating thresholds for "
+ << sensorName << "\n";
+@@ -384,7 +406,7 @@ bool createSensors(boost::asio::io_service& io,
+ sensorPtr = std::make_unique<CPUSensor>(
+ inputPathStr, sensorType, objectServer, dbusConnection, io,
+ sensorName, std::move(sensorThresholds), *interfacePath, cpuId,
+- show, dtsOffset);
++ show, dtsOffset, prop);
+ createdSensors.insert(sensorName);
+ if (debug)
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0008-CPUSensor-additional-debug-message.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0008-CPUSensor-additional-debug-message.patch
new file mode 100644
index 000000000..40c8d46bd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0008-CPUSensor-additional-debug-message.patch
@@ -0,0 +1,69 @@
+From c045d0ace218a8f0c9e9af0b04aed24ec733fc79 Mon Sep 17 00:00:00 2001
+From: Zhikui Ren <zhikui.ren@intel.com>
+Date: Tue, 22 Jun 2021 14:49:44 -0700
+Subject: [PATCH] CPUSensor: additional debug message
+
+Add debug message to capture more information on threshold changes.
+
+Example output - DTS threshold changes when Tcontrol was first read
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: Core_16_CPU1: Tcontrol changed from nan to 92
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: Core_22_CPU1: Tcontrol changed from nan to 92
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: Core_24_CPU1: Tcontrol changed from nan to 92
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: DTS_CPU1: Tcontrol changed from nan to 92
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: Threshold: /sys/bus/peci/devices/peci-0/0-30/peci-cputemp.0/hwmon/hwmon12/temp2_max: 92
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: Threshold: /sys/bus/peci/devices/peci-0/0-30/peci-cputemp.0/hwmon/hwmon12/temp2_crit: 100
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: DTS_CPU1: new threshold value 92
+ Jan 01 00:06:06 intel-obmc cpusensor[461]: DTS_CPU1: new threshold value 100
+
+The above message will be logged when BMC reset or host resets.
+
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+---
+ src/CPUSensor.cpp | 5 +++++
+ src/Thresholds.cpp | 7 ++-----
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
+index 0621e04..65acdac 100644
+--- a/src/CPUSensor.cpp
++++ b/src/CPUSensor.cpp
+@@ -300,6 +300,7 @@ void CPUSensor::handleResponse(const boost::system::error_code& err)
+ : std::numeric_limits<double>::quiet_NaN();
+ if (gTcontrol != privTcontrol)
+ {
++ std::cout << name << ": Tcontrol changed from " << privTcontrol << " to " << gTcontrol << "\n";
+ privTcontrol = gTcontrol;
+
+ if (!thresholds.empty())
+@@ -318,6 +319,10 @@ void CPUSensor::handleResponse(const boost::system::error_code& err)
+ thresholds::updateThresholds(this);
+ }
+ }
++ for (auto& threshold : thresholds)
++ {
++ std::cout << name << ": new threshold value " << threshold.value << "\n";
++ }
+ }
+ else
+ {
+diff --git a/src/Thresholds.cpp b/src/Thresholds.cpp
+index 78ded55..283dacf 100644
+--- a/src/Thresholds.cpp
++++ b/src/Thresholds.cpp
+@@ -583,11 +583,8 @@ bool parseThresholdsFromAttr(
+ if (auto val = readFile(attrPath, scaleFactor))
+ {
+ *val += offset;
+- if (debug)
+- {
+- std::cout << "Threshold: " << attrPath << ": " << *val
+- << "\n";
+- }
++ std::cout << "Threshold: " << attrPath << ": " << *val
++ << "\n";
+ thresholdVector.emplace_back(level, direction, *val);
+ }
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0009-CPUSensor-Create-CPUConfig-for-each-PECI-adapter.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0009-CPUSensor-Create-CPUConfig-for-each-PECI-adapter.patch
new file mode 100644
index 000000000..737ba9128
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0009-CPUSensor-Create-CPUConfig-for-each-PECI-adapter.patch
@@ -0,0 +1,147 @@
+From 262682632ee493d0b6593540cfc902d11286b7c3 Mon Sep 17 00:00:00 2001
+From: Iwona Winiarska <iwona.winiarska@intel.com>
+Date: Tue, 13 Jul 2021 15:16:16 +0200
+Subject: [PATCH] CPUSensor: Create CPUConfig for each PECI adapter
+
+Currently CPUSensor is based on configuration that defines CPUs for the
+specific PECI adapter (usually peci-wire). As a consequence, MFD devices
+are created only for the defined adapter.
+
+Since duplicating static CPU records in configuration file for other
+PECI adapters may be confusing to users, let's add CPUConfig for other
+PECI adapters dynamically by detecting if there is more than one PECI
+adapter driver bound in the system.
+
+Please note, that this change is limited to enabling HWMON driver,
+sensors for all adapters will not be exposed on D-Bus.
+
+Tested:
+No changes if only one PECI interface is available, HWMON drivers
+creation will be based on provided configuration.
+When both peci-aspeed (peci-wire) and peci-mctp are bound in the system,
+HWMON drivers are created for each PECI interface.
+
+Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
+---
+ src/CPUSensorMain.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 90 insertions(+)
+
+diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp
+index 744ca50..6850df7 100644
+--- a/src/CPUSensorMain.cpp
++++ b/src/CPUSensorMain.cpp
+@@ -33,6 +33,7 @@
+ #include <fstream>
+ #include <functional>
+ #include <memory>
++#include <optional>
+ #include <regex>
+ #include <sstream>
+ #include <stdexcept>
+@@ -658,6 +659,91 @@ void detectCpuAsync(
+ });
+ }
+
++std::optional<uint64_t> getPeciDeviceNum(const fs::path& peciAdapterNamePath)
++{
++ fs::path::iterator it = peciAdapterNamePath.begin();
++ std::advance(it, 5); // /sys/bus/peci/devices/peci-xxxx
++ std::string peciDeviceName = *it;
++ auto pos = peciDeviceName.find('-');
++ if (pos == std::string::npos)
++ {
++ std::cerr << "Incorrect PECI device name: " << peciDeviceName << "\n";
++ return std::nullopt;
++ }
++
++ try
++ {
++ return std::stoull(peciDeviceName.substr(pos + 1, 1));
++ }
++ catch (std::logic_error&)
++ {
++ return std::nullopt;
++ }
++}
++
++std::optional<std::string>
++ readPeciAdapterNameFromFile(const fs::path& peciAdapterNamePath)
++{
++ std::ifstream nameFile(peciAdapterNamePath);
++ if (!nameFile.good())
++ {
++ std::cerr << "Cannot read: " << peciAdapterNamePath << "\n";
++ return std::nullopt;
++ }
++
++ std::string peciAdapterName;
++ std::getline(nameFile, peciAdapterName);
++ nameFile.close();
++ if (peciAdapterName.empty())
++ {
++ return std::nullopt;
++ }
++
++ auto pos = peciAdapterName.find('-');
++ peciAdapterName = peciAdapterName.substr(pos + 1);
++
++ return peciAdapterName;
++}
++
++void addConfigsForOtherPeciAdapters(
++ boost::container::flat_set<CPUConfig>& cpuConfigs, uint64_t& bus,
++ uint64_t& addr, std::string& name, const State& state)
++{
++ std::vector<fs::path> peciAdapterNamePaths;
++ if (!findFiles(fs::path(peciDevPath), R"(peci-\d+/name$)",
++ peciAdapterNamePaths, 1))
++ {
++ std::cerr << "No PECI adapters in system\n";
++ return;
++ }
++
++ for (const fs::path& peciAdapterNamePath : peciAdapterNamePaths)
++ {
++ std::optional<uint64_t> peciDeviceNum =
++ getPeciDeviceNum(peciAdapterNamePath);
++ if (!peciDeviceNum || peciDeviceNum == bus)
++ {
++ continue;
++ }
++
++ std::optional<std::string> peciAdapterName =
++ readPeciAdapterNameFromFile(peciAdapterNamePath);
++ if (!peciAdapterName)
++ {
++ continue;
++ }
++
++ // Change result for peci-aspeed
++ if (peciAdapterName->compare("bus") == 0)
++ {
++ peciAdapterName = "wire";
++ }
++
++ cpuConfigs.emplace(*peciDeviceNum, addr, name + "_" + *peciAdapterName,
++ state);
++ }
++}
++
+ bool getCpuConfig(std::shared_ptr<sdbusplus::asio::connection>& systemBus,
+ boost::container::flat_set<CPUConfig>& cpuConfigs,
+ ManagedObjectType& sensorConfigs, boost::asio::io_service& io,
+@@ -789,7 +875,11 @@ bool getCpuConfig(std::shared_ptr<sdbusplus::asio::connection>& systemBus,
+ std::cout << "name: " << name << "\n";
+ std::cout << "type: " << type << "\n";
+ }
++
+ cpuConfigs.emplace(bus, addr, name, State::OFF);
++
++ addConfigsForOtherPeciAdapters(cpuConfigs, bus, addr, name,
++ State::OFF);
+ }
+ }
+ }
+--
+2.31.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf
new file mode 100644
index 000000000..6f0fd3ffc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf
@@ -0,0 +1,3 @@
+[Unit]
+After=systemd-networkd.service
+Requires=systemd-networkd.service
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend
new file mode 100644
index 000000000..765ad3739
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -0,0 +1,49 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+PROJECT_SRC_DIR := "${THISDIR}/${PN}"
+
+SRCREV = "77518b28db824e01af18351094680a99b1ba3cae"
+#SRC_URI = "git://github.com/openbmc/dbus-sensors.git"
+
+SRC_URI += "\
+ file://intrusionsensor-depend-on-networkd.conf \
+ file://0001-Add-check-for-min-max-received-from-hwmon-files.patch \
+ file://0002-Fix-PECI-client-creation-flow.patch \
+ file://0003-Fix-missing-threshold-de-assert-event-when-threshold.patch \
+ file://0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch \
+ file://0005-Fix-PECI-ioctl-number.patch \
+ file://0006-CPUSensor-create-RequirediTempSensor-if-defined.patch \
+ file://0007-Add-support-for-the-energy-hwmon-type.patch \
+ file://0008-CPUSensor-additional-debug-message.patch \
+ file://0009-CPUSensor-Create-CPUConfig-for-each-PECI-adapter.patch \
+ "
+
+DEPENDS:append = " libgpiod libmctp"
+
+PACKAGECONFIG += " \
+ adcsensor \
+ cpusensor \
+ exitairtempsensor \
+ fansensor \
+ hwmontempsensor \
+ intrusionsensor \
+ ipmbsensor \
+ mcutempsensor \
+ psusensor \
+"
+
+PACKAGECONFIG[nvmesensor] = "-Dnvme=enabled, -Dnvme=disabled"
+
+# Enable Validation unsecure based on IMAGE_FEATURES
+EXTRA_OEMESON += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-Dvalidate-unsecure-feature=enabled', '', d)}"
+
+SYSTEMD_SERVICE:${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'nvmesensor', \
+ 'xyz.openbmc_project.nvmesensor.service', \
+ '', d)}"
+
+do_install:append() {
+ svc="xyz.openbmc_project.intrusionsensor.service"
+ srcf="${WORKDIR}/intrusionsensor-depend-on-networkd.conf"
+ dstf="${D}/etc/systemd/system/${svc}.d/10-depend-on-networkd.conf"
+ mkdir -p "${D}/etc/systemd/system/${svc}.d"
+ install "${srcf}" "${dstf}"
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb
new file mode 100644
index 000000000..703cbb803
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb
@@ -0,0 +1,20 @@
+SUMMARY = "Settings"
+
+SRC_URI = "git://github.com/Intel-BMC/settings.git;protocol=ssh"
+SRCREV = "85a8be9a3fb8ef4726899b28f10fb9afa6fa9e89"
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE:${PN} = "xyz.openbmc_project.Settings.service"
+
+DEPENDS = "boost \
+ nlohmann-json \
+ sdbusplus"
+
+S = "${WORKDIR}/git"
+inherit cmake systemd
+
+EXTRA_OECMAKE = "-DYOCTO=1"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb
new file mode 100644
index 000000000..d17aebf00
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb
@@ -0,0 +1,31 @@
+SUMMARY = "Special mode manager daemon to handle manufacturing modes"
+DESCRIPTION = "Daemon exposes the manufacturing mode property"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/special-mode-manager.git;protocol=ssh"
+SRCREV = "42a0ba3c61ae38cc84b06705159065860492fc2e"
+
+EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}"
+
+inherit cmake systemd
+SYSTEMD_SERVICE:${PN} = "specialmodemgr.service"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ libpam \
+ libgpiod \
+ "
+RDEPENDS:${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-logging \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend
new file mode 100644
index 000000000..a4e894cbc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend
@@ -0,0 +1,2 @@
+#SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git"
+SRCREV = "9ce5a645f50c0ab94e582abbf95474f636aba678"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
new file mode 100644
index 000000000..b7e8c0b22
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
@@ -0,0 +1,3 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += "gtest"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb
new file mode 100644
index 000000000..b123ddb35
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb
@@ -0,0 +1,19 @@
+SUMMARY = "Callback Manager"
+DESCRIPTION = "D-Bus daemon that registers matches that trigger method calls"
+
+SRC_URI = "git://github.com/openbmc/s2600wf-misc.git;protocol=ssh"
+
+inherit cmake systemd
+DEPENDS = "boost sdbusplus"
+
+PV = "0.1+git${SRCPV}"
+SRCREV = "0c5059f685f6df0704a4b773f2e617cf10d03210"
+
+S = "${WORKDIR}/git/callback-manager"
+
+SYSTEMD_SERVICE:${PN} += "callback-manager.service"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENCE;md5=7becf906c8f8d03c237bad13bc3dac53"
+
+EXTRA_OECMAKE = "-DYOCTO=1"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend
new file mode 100644
index 000000000..ebd808168
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend
@@ -0,0 +1,6 @@
+SRC_URI = "git://github.com/openbmc/telemetry.git"
+SRCREV = "e28aa53dc1492f09a64dc9f1dbfd5b6dba06e31f"
+
+EXTRA_OEMESON += " -Dmax-reports=10"
+EXTRA_OEMESON += " -Dmax-reading-parameters=200"
+EXTRA_OEMESON += " -Dmin-interval=1000"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch
new file mode 100644
index 000000000..a7f431049
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch
@@ -0,0 +1,1666 @@
+From 75971b8faf7ef7af7285ba7d5207be71c66e5d11 Mon Sep 17 00:00:00 2001
+From: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Date: Mon, 2 Jul 2018 19:23:25 -0700
+Subject: [PATCH] Added suport for multiple user manager services
+
+Support added for SSSD service implementation
+
+Signed-off-by: Alberto Salazar Perez <alberto.salazar.perez@intel.com>
+Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+---
+ Makefile.am | 5 +-
+ mainapp.cpp | 90 +++++-
+ user_mgr.cpp | 297 ++----------------
+ user_mgr.hpp | 9 +-
+ user_service.cpp | 789 +++++++++++++++++++++++++++++++++++++++++++++++
+ user_service.hpp | 233 ++++++++++++++
+ 6 files changed, 1149 insertions(+), 274 deletions(-)
+ create mode 100644 user_service.cpp
+ create mode 100644 user_service.hpp
+
+diff --git a/Makefile.am b/Makefile.am
+index 1dbd594..fe47aaf 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,11 +1,12 @@
+ bin_PROGRAMS = phosphor-user-manager
+
+-noinst_HEADERS = user_mgr.hpp users.hpp
++noinst_HEADERS = user_mgr.hpp users.hpp user_service.hpp
+
+ phosphor_user_manager_SOURCES = \
+ mainapp.cpp \
+ user_mgr.cpp \
+- users.cpp
++ users.cpp \
++ user_service.cpp
+
+ phosphor_user_manager_LDFLAGS = $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+diff --git a/mainapp.cpp b/mainapp.cpp
+index e08da61..f4b7f8c 100644
+--- a/mainapp.cpp
++++ b/mainapp.cpp
+@@ -16,18 +16,106 @@
+ #include "config.h"
+
+ #include "user_mgr.hpp"
++#include "user_service.hpp"
+
++#include <getopt.h>
++
++#include <iostream>
+ #include <string>
+
+ // D-Bus root for user manager
+ constexpr auto USER_MANAGER_ROOT = "/xyz/openbmc_project/user";
+
++void printUsage()
++{
++ std::string usage =
++ R"(Usage:
++ phosphor-user-manager [OPTIONS]
++
++Backend DBUS service for OpenBMC User Management.
++If no OPTIONS are specified, shadow file will be used.
++
++Options:
++ -s, --service={shadow|sssd}
++ Specify the authentication service to use:
++ 'shadow' will use the /etc/shadow file.
++ 'sssd' will use the sssd service domains.
++ -h, --help Displays this help message.
++)";
++ std::cerr << usage;
++}
++
++void parseArgs(int argc, char** argv,
++ phosphor::user::UserService::ServiceType& srvc)
++{
++ const std::string shortOpts{"s:h"};
++ const struct option longOpts[] = {{"service", 1, nullptr, 's'},
++ {"help", 0, nullptr, 'h'},
++ {nullptr, 0, nullptr, 0}};
++
++ while (true)
++ {
++ const auto opt =
++ getopt_long(argc, argv, shortOpts.c_str(), longOpts, nullptr);
++
++ if (opt == -1)
++ {
++ if (srvc == phosphor::user::UserService::ServiceType::none)
++ {
++ srvc = phosphor::user::UserService::ServiceType::shadow;
++ }
++ break;
++ }
++
++ switch (opt)
++ {
++ case 's':
++ {
++ std::string srvcStr{optarg};
++ if (!srvcStr.compare("shadow"))
++ {
++ srvc = phosphor::user::UserService::ServiceType::shadow;
++ }
++ else if (!srvcStr.compare("sssd"))
++ {
++ srvc = phosphor::user::UserService::ServiceType::sssd;
++ }
++ else
++ {
++ std::cerr << "Error. '" << srvcStr << "' is not a valid"
++ << " authentication service." << std::endl;
++ printUsage();
++ exit(1);
++ }
++ }
++ break;
++
++ case 'h':
++ {
++ printUsage();
++ exit(0);
++ }
++
++ default:
++ {
++ printUsage();
++ exit(1);
++ }
++ }
++ }
++}
++
+ int main(int argc, char** argv)
+ {
++ // Check command line options. Exit if error.
++ phosphor::user::UserService::ServiceType srvc =
++ phosphor::user::UserService::ServiceType::none;
++ parseArgs(argc, argv, srvc);
++
+ auto bus = sdbusplus::bus::new_default();
+ sdbusplus::server::manager::manager objManager(bus, USER_MANAGER_ROOT);
+
+- phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT);
++ phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT, srvc);
+
+ // Claim the bus now
+ bus.request_name(USER_MANAGER_BUSNAME);
+diff --git a/user_mgr.cpp b/user_mgr.cpp
+index 1b14e8e..f6f2fdb 100644
+--- a/user_mgr.cpp
++++ b/user_mgr.cpp
+@@ -18,43 +18,34 @@
+
+ #include "user_mgr.hpp"
+
+-#include "file.hpp"
+ #include "shadowlock.hpp"
+ #include "users.hpp"
+
+ #include <grp.h>
+ #include <pwd.h>
+-#include <shadow.h>
+-#include <sys/types.h>
+-#include <sys/wait.h>
+ #include <time.h>
+-#include <unistd.h>
+
+ #include <boost/algorithm/string/split.hpp>
+-#include <boost/process/child.hpp>
+-#include <boost/process/io.hpp>
+ #include <phosphor-logging/elog-errors.hpp>
+ #include <phosphor-logging/elog.hpp>
+ #include <phosphor-logging/log.hpp>
+ #include <xyz/openbmc_project/Common/error.hpp>
+ #include <xyz/openbmc_project/User/Common/error.hpp>
+
+-#include <algorithm>
++#include <cstdio>
+ #include <fstream>
+-#include <numeric>
+ #include <regex>
++#include <stdexcept>
+
+ namespace phosphor
+ {
+ namespace user
+ {
+
+-static constexpr const char* passwdFileName = "/etc/passwd";
+ static constexpr size_t ipmiMaxUsers = 15;
+ static constexpr size_t ipmiMaxUserNameLen = 16;
+ static constexpr size_t systemMaxUserNameLen = 30;
+ static constexpr size_t maxSystemUsers = 30;
+-static constexpr const char* grpSsh = "ssh";
+ static constexpr uint8_t minPasswdLength = 8;
+ static constexpr int success = 0;
+ static constexpr int failure = -1;
+@@ -100,79 +91,6 @@ using NoResource =
+
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+
+-template <typename... ArgTypes>
+-static std::vector<std::string> executeCmd(const char* path,
+- ArgTypes&&... tArgs)
+-{
+- std::vector<std::string> stdOutput;
+- boost::process::ipstream stdOutStream;
+- boost::process::child execProg(path, const_cast<char*>(tArgs)...,
+- boost::process::std_out > stdOutStream);
+- std::string stdOutLine;
+-
+- while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
+- !stdOutLine.empty())
+- {
+- stdOutput.emplace_back(stdOutLine);
+- }
+-
+- execProg.wait();
+-
+- int retCode = execProg.exit_code();
+- if (retCode)
+- {
+- log<level::ERR>("Command execution failed", entry("PATH=%d", path),
+- entry("RETURN_CODE:%d", retCode));
+- elog<InternalFailure>();
+- }
+-
+- return stdOutput;
+-}
+-
+-static std::string getCSVFromVector(std::vector<std::string> vec)
+-{
+- switch (vec.size())
+- {
+- case 0:
+- {
+- return "";
+- }
+- break;
+-
+- case 1:
+- {
+- return std::string{vec[0]};
+- }
+- break;
+-
+- default:
+- {
+- return std::accumulate(
+- std::next(vec.begin()), vec.end(), vec[0],
+- [](std::string a, std::string b) { return a + ',' + b; });
+- }
+- }
+-}
+-
+-static bool removeStringFromCSV(std::string& csvStr, const std::string& delStr)
+-{
+- std::string::size_type delStrPos = csvStr.find(delStr);
+- if (delStrPos != std::string::npos)
+- {
+- // need to also delete the comma char
+- if (delStrPos == 0)
+- {
+- csvStr.erase(delStrPos, delStr.size() + 1);
+- }
+- else
+- {
+- csvStr.erase(delStrPos - 1, delStr.size() + 1);
+- }
+- return true;
+- }
+- return false;
+-}
+-
+ bool UserMgr::isUserExist(const std::string& userName)
+ {
+ if (userName.empty())
+@@ -299,39 +217,14 @@ void UserMgr::createUser(std::string userName,
+ {
+ throwForInvalidPrivilege(priv);
+ throwForInvalidGroups(groupNames);
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+ throwForUserExists(userName);
+ throwForUserNameConstraints(userName, groupNames);
+ throwForMaxGrpUserCount(groupNames);
+
+- std::string groups = getCSVFromVector(groupNames);
+- bool sshRequested = removeStringFromCSV(groups, grpSsh);
+-
+- // treat privilege as a group - This is to avoid using different file to
+- // store the same.
+- if (!priv.empty())
+- {
+- if (groups.size() != 0)
+- {
+- groups += ",";
+- }
+- groups += priv;
+- }
+- try
+- {
+- executeCmd("/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(),
+- "-m", "-N", "-s",
+- (sshRequested ? "/bin/sh" : "/bin/nologin"), "-e",
+- (enabled ? "" : "1970-01-02"));
+- }
+- catch (const InternalFailure& e)
+- {
+- log<level::ERR>("Unable to create new user");
+- elog<InternalFailure>();
+- }
++ // Tell the User Service to create a new user with the info provided.
++ userSrvc->createUser(userName, groupNames, priv, enabled);
+
+- // Add the users object before sending out the signal
++ // Add the users to the local list before sending out the signal
+ std::string userObj = std::string(usersObjPath) + "/" + userName;
+ std::sort(groupNames.begin(), groupNames.end());
+ usersList.emplace(
+@@ -345,19 +238,11 @@ void UserMgr::createUser(std::string userName,
+
+ void UserMgr::deleteUser(std::string userName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+ throwForUserDoesNotExist(userName);
+- try
+- {
+- executeCmd("/usr/sbin/userdel", userName.c_str(), "-r");
+- }
+- catch (const InternalFailure& e)
+- {
+- log<level::ERR>("User delete failed",
+- entry("USER_NAME=%s", userName.c_str()));
+- elog<InternalFailure>();
+- }
++
++ // Tell the User Service to delete user
++ userSrvc->deleteUser(userName);
++ // Then delete user from local list
+
+ usersList.erase(userName);
+
+@@ -368,24 +253,13 @@ void UserMgr::deleteUser(std::string userName)
+
+ void UserMgr::renameUser(std::string userName, std::string newUserName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+ throwForUserDoesNotExist(userName);
+ throwForUserExists(newUserName);
+ throwForUserNameConstraints(newUserName,
+ usersList[userName].get()->userGroups());
+- try
+- {
+- std::string newHomeDir = "/home/" + newUserName;
+- executeCmd("/usr/sbin/usermod", "-l", newUserName.c_str(),
+- userName.c_str(), "-d", newHomeDir.c_str(), "-m");
+- }
+- catch (const InternalFailure& e)
+- {
+- log<level::ERR>("User rename failed",
+- entry("USER_NAME=%s", userName.c_str()));
+- elog<InternalFailure>();
+- }
++ // Call The User Service to rename user on the system
++ userSrvc->renameUser(userName, newUserName);
++ // Update local list to reflect the name change
+ const auto& user = usersList[userName];
+ std::string priv = user.get()->userPrivilege();
+ std::vector<std::string> groupNames = user.get()->userGroups();
+@@ -409,8 +283,6 @@ void UserMgr::updateGroupsAndPriv(const std::string& userName,
+ {
+ throwForInvalidPrivilege(priv);
+ throwForInvalidGroups(groupNames);
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+ throwForUserDoesNotExist(userName);
+ const std::vector<std::string>& oldGroupNames =
+ usersList[userName].get()->userGroups();
+@@ -426,29 +298,8 @@ void UserMgr::updateGroupsAndPriv(const std::string& userName,
+ throwForMaxGrpUserCount(groupNames);
+ }
+
+- std::string groups = getCSVFromVector(groupNames);
+- bool sshRequested = removeStringFromCSV(groups, grpSsh);
+-
+- // treat privilege as a group - This is to avoid using different file to
+- // store the same.
+- if (!priv.empty())
+- {
+- if (groups.size() != 0)
+- {
+- groups += ",";
+- }
+- groups += priv;
+- }
+- try
+- {
+- executeCmd("/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(),
+- "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"));
+- }
+- catch (const InternalFailure& e)
+- {
+- log<level::ERR>("Unable to modify user privilege / groups");
+- elog<InternalFailure>();
+- }
++ // Call The User Service to update user groups and priv on the system
++ userSrvc->updateGroupsAndPriv(userName, groupNames, priv);
+
+ log<level::INFO>("User groups / privilege updated successfully",
+ entry("USER_NAME=%s", userName.c_str()));
+@@ -644,19 +495,9 @@ int UserMgr::setPamModuleArgValue(const std::string& moduleName,
+
+ void UserMgr::userEnable(const std::string& userName, bool enabled)
+ {
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+ throwForUserDoesNotExist(userName);
+- try
+- {
+- executeCmd("/usr/sbin/usermod", userName.c_str(), "-e",
+- (enabled ? "" : "1970-01-02"));
+- }
+- catch (const InternalFailure& e)
+- {
+- log<level::ERR>("Unable to modify user enabled state");
+- elog<InternalFailure>();
+- }
++ // Call The User Service to update user groups and priv on the system
++ userSrvc->updateUserStatus(userName, enabled);
+
+ log<level::INFO>("User enabled/disabled state updated successfully",
+ entry("USER_NAME=%s", userName.c_str()),
+@@ -779,54 +620,8 @@ bool UserMgr::userPasswordExpired(const std::string& userName)
+
+ UserSSHLists UserMgr::getUserAndSshGrpList()
+ {
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+-
+- std::vector<std::string> userList;
+- std::vector<std::string> sshUsersList;
+- struct passwd pw, *pwp = nullptr;
+- std::array<char, 1024> buffer{};
+-
+- phosphor::user::File passwd(passwdFileName, "r");
+- if ((passwd)() == NULL)
+- {
+- log<level::ERR>("Error opening the passwd file");
+- elog<InternalFailure>();
+- }
+-
+- while (true)
+- {
+- auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(),
+- &pwp);
+- if ((r != 0) || (pwp == NULL))
+- {
+- // Any error, break the loop.
+- break;
+- }
+-#ifdef ENABLE_ROOT_USER_MGMT
+- // Add all users whose UID >= 1000 and < 65534
+- // and special UID 0.
+- if ((pwp->pw_uid == 0) ||
+- ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)))
+-#else
+- // Add all users whose UID >=1000 and < 65534
+- if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))
+-#endif
+- {
+- std::string userName(pwp->pw_name);
+- userList.emplace_back(userName);
+-
+- // ssh doesn't have separate group. Check login shell entry to
+- // get all users list which are member of ssh group.
+- std::string loginShell(pwp->pw_shell);
+- if (loginShell == "/bin/sh")
+- {
+- sshUsersList.emplace_back(userName);
+- }
+- }
+- }
+- endpwent();
+- return std::make_pair(std::move(userList), std::move(sshUsersList));
++ // Call The User Service to get the User and SSUsers lists
++ return std::move(userSrvc->getUserAndSshGrpList());
+ }
+
+ size_t UserMgr::getIpmiUsersCount()
+@@ -837,49 +632,14 @@ size_t UserMgr::getIpmiUsersCount()
+
+ bool UserMgr::isUserEnabled(const std::string& userName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+- std::array<char, 4096> buffer{};
+- struct spwd spwd;
+- struct spwd* resultPtr = nullptr;
+- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(),
+- buffer.max_size(), &resultPtr);
+- if (!status && (&spwd == resultPtr))
+- {
+- if (resultPtr->sp_expire >= 0)
+- {
+- return false; // user locked out
+- }
+- return true;
+- }
+- return false; // assume user is disabled for any error.
++ // Call The User Service to verify if user is enabled
++ return userSrvc->isUserEnabled(userName);
+ }
+
+ std::vector<std::string> UserMgr::getUsersInGroup(const std::string& groupName)
+ {
+- std::vector<std::string> usersInGroup;
+- // Should be more than enough to get the pwd structure.
+- std::array<char, 4096> buffer{};
+- struct group grp;
+- struct group* resultPtr = nullptr;
+-
+- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(),
+- buffer.max_size(), &resultPtr);
+-
+- if (!status && (&grp == resultPtr))
+- {
+- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
+- {
+- usersInGroup.emplace_back(*(grp.gr_mem));
+- }
+- }
+- else
+- {
+- log<level::ERR>("Group not found",
+- entry("GROUP=%s", groupName.c_str()));
+- // Don't throw error, just return empty userList - fallback
+- }
+- return usersInGroup;
++ // Call The User Service to get the users that belong to a group
++ return std::move(userSrvc->getUsersInGroup(groupName));
+ }
+
+ DbusUserObj UserMgr::getPrivilegeMapperObject(void)
+@@ -1106,11 +866,9 @@ void UserMgr::initUserObjects(void)
+ {
+ // All user management lock has to be based on /etc/shadow
+ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
+- std::vector<std::string> userNameList;
+- std::vector<std::string> sshGrpUsersList;
+ UserSSHLists userSSHLists = getUserAndSshGrpList();
+- userNameList = std::move(userSSHLists.first);
+- sshGrpUsersList = std::move(userSSHLists.second);
++ std::vector<std::string> userNameList = std::move(userSSHLists.first);
++ std::vector<std::string> sshGrpUsersList = std::move(userSSHLists.second);
+
+ if (!userNameList.empty())
+ {
+@@ -1165,8 +923,10 @@ void UserMgr::initUserObjects(void)
+ }
+ }
+
+-UserMgr::UserMgr(sdbusplus::bus::bus& bus, const char* path) :
+- Ifaces(bus, path, true), bus(bus), path(path)
++UserMgr::UserMgr(sdbusplus::bus::bus& bus, const char* path,
++ UserService::ServiceType srvc) :
++ Ifaces(bus, path, true),
++ bus(bus), path(path)
+ {
+ UserMgrIface::allPrivileges(privMgr);
+ std::sort(groupsMgr.begin(), groupsMgr.end());
+@@ -1274,6 +1034,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus& bus, const char* path) :
+ }
+ AccountPolicyIface::accountUnlockTimeout(value32);
+ }
++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr);
+ initUserObjects();
+
+ // emit the signal
+diff --git a/user_mgr.hpp b/user_mgr.hpp
+index f5aac22..5d5ca99 100644
+--- a/user_mgr.hpp
++++ b/user_mgr.hpp
+@@ -14,6 +14,7 @@
+ // limitations under the License.
+ */
+ #pragma once
++#include "user_service.hpp"
+ #include "users.hpp"
+
+ #include <sdbusplus/bus.hpp>
+@@ -30,8 +31,6 @@ namespace user
+ {
+
+ using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager;
+-using UserSSHLists =
+- std::pair<std::vector<std::string>, std::vector<std::string>>;
+ using AccountPolicyIface =
+ sdbusplus::xyz::openbmc_project::User::server::AccountPolicy;
+
+@@ -77,8 +76,10 @@ class UserMgr : public Ifaces
+ *
+ * @param[in] bus - sdbusplus handler
+ * @param[in] path - D-Bus path
++ * @param[in] srvc - User service to be used
+ */
+- UserMgr(sdbusplus::bus::bus& bus, const char* path);
++ UserMgr(sdbusplus::bus::bus& bus, const char* path,
++ UserService::ServiceType srvc);
+
+ /** @brief create user method.
+ * This method creates a new user as requested
+@@ -194,6 +195,8 @@ class UserMgr : public Ifaces
+ /** @brief object path */
+ const std::string path;
+
++ /** @brief user service to be used */
++ std::unique_ptr<UserService> userSrvc;
+ /** @brief privilege manager container */
+ std::vector<std::string> privMgr = {"priv-admin", "priv-operator",
+ "priv-user", "priv-noaccess"};
+diff --git a/user_service.cpp b/user_service.cpp
+new file mode 100644
+index 0000000..6e11755
+--- /dev/null
++++ b/user_service.cpp
+@@ -0,0 +1,789 @@
++/*
++// Copyright (c) 2018 Intel Corporation
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++*/
++
++#include "user_service.hpp"
++
++#include "file.hpp"
++#include "shadowlock.hpp"
++
++#include <grp.h>
++#include <pwd.h>
++
++#include <boost/algorithm/string/split.hpp>
++#include <boost/process/child.hpp>
++#include <boost/process/io.hpp>
++
++#include <numeric>
++
++/* anonymous namespace for User Service interface implementations.
++// Each class inside this namespace implements a special service
++// to be used for the User Manager class. This can be extended to use
++// other user management services and it should be as simple as
++// adding a new class which inherits from phosphor::user::UserServiceInterface
++*/
++
++namespace
++{
++
++std::string getCSVFromVector(std::vector<std::string> vec)
++{
++ switch (vec.size())
++ {
++ case 0:
++ {
++ return "";
++ }
++ break;
++
++ case 1:
++ {
++ return std::string{vec[0]};
++ }
++ break;
++
++ default:
++ {
++ return std::accumulate(
++ std::next(vec.begin()), vec.end(), vec[0],
++ [](std::string a, std::string b) { return a + ',' + b; });
++ }
++ }
++}
++
++bool removeStringFromCSV(std::string& csvStr, const std::string& delStr)
++{
++ std::string::size_type delStrPos = csvStr.find(delStr);
++ if (delStrPos != std::string::npos)
++ {
++ // need to also delete the comma char
++ if (delStrPos == 0)
++ {
++ csvStr.erase(delStrPos, delStr.size() + 1);
++ }
++ else
++ {
++ csvStr.erase(delStrPos - 1, delStr.size() + 1);
++ }
++ return true;
++ }
++ return false;
++}
++
++class ShadowService : public phosphor::user::UserServiceInterface
++{
++ public:
++ ShadowService() = default;
++
++ ~ShadowService() = default;
++
++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++
++ std::vector<std::string> userList;
++ std::vector<std::string> sshUsersList;
++
++ struct passwd pw, *pwp = nullptr;
++ std::array<char, 1024> buffer{};
++
++ phosphor::user::File passwd(passwdFileName, "r");
++ if ((passwd)() == NULL)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error opening the passwd file");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ while (true)
++ {
++ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(),
++ buffer.max_size(), &pwp);
++ if ((r != 0) || (pwp == NULL))
++ {
++ // Any error, break the loop.
++ break;
++ }
++#ifdef ENABLE_ROOT_USER_MGMT
++ // Add all users whose UID >= 1000 and < 65534
++ // and special UID 0.
++ if ((pwp->pw_uid == 0) ||
++ ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)))
++#else
++ // Add all users whose UID >=1000 and < 65534
++ if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))
++#endif
++ {
++ std::string userName(pwp->pw_name);
++ userList.emplace_back(userName);
++
++ // ssh doesn't have separate group. Check login shell entry to
++ // get all users list which are member of ssh group.
++ std::string loginShell(pwp->pw_shell);
++ if (loginShell == "/bin/sh")
++ {
++ sshUsersList.emplace_back(userName);
++ }
++ }
++ }
++ endpwent();
++ return std::make_pair(std::move(userList), std::move(sshUsersList));
++ }
++
++ std::vector<std::string>
++ getUsersInGroup(const std::string& groupName) const override
++ {
++ std::vector<std::string> usersInGroup;
++ // Should be more than enough to get the pwd structure.
++ std::array<char, 4096> buffer{};
++ struct group grp;
++ struct group* grpPtr = &grp;
++ struct group* resultPtr;
++
++ int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(),
++ buffer.max_size(), &resultPtr);
++
++ if (!status && (grpPtr == resultPtr))
++ {
++ for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
++ {
++ usersInGroup.emplace_back(*(grp.gr_mem));
++ }
++ }
++ else
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Group not found",
++ phosphor::logging::entry("GROUP=%s", groupName.c_str()));
++ // Don't throw error, just return empty usersInGroup - fallback
++ }
++ return usersInGroup;
++ }
++
++ void createUser(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv, const bool& enabled) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups.append(",");
++ }
++ groups.append(priv);
++ }
++
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(),
++ "-m", "-N", "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"),
++ "-e", (enabled ? "" : "1970-01-02"));
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to create new user");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void renameUser(const std::string& userName,
++ const std::string& newUserName) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++ try
++ {
++ std::string newHomeDir = "/home/" + newUserName;
++ phosphor::user::executeCmd("/usr/sbin/usermod", "-l",
++ newUserName.c_str(), userName.c_str(),
++ "-d", newHomeDir.c_str(), "-m");
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "User rename failed",
++ phosphor::logging::entry("USER_NAME=%s", userName.c_str()));
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void deleteUser(const std::string& userName) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/userdel", userName.c_str(),
++ "-r");
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "User delete failed",
++ phosphor::logging::entry("USER_NAME=%s", userName.c_str()));
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateGroupsAndPriv(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same.
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups += ",";
++ }
++ groups += priv;
++ }
++
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(),
++ "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"));
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to modify user privilege / groups");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateUserStatus(const std::string& userName,
++ const bool& enabled) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/usermod", userName.c_str(),
++ "-e", (enabled ? "" : "1970-01-02"));
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to modify user enabled state");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ bool isUserEnabled(const std::string& userName) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ // TODO phosphor-user-manager#10 phosphor::user::shadow::Lock lock{};
++ std::array<char, 4096> buffer{};
++ struct spwd spwd;
++ struct spwd* resultPtr = nullptr;
++ int status = getspnam_r(userName.c_str(), &spwd, buffer.data(),
++ buffer.max_size(), &resultPtr);
++ if (!status && (&spwd == resultPtr))
++ {
++ if (resultPtr->sp_expire >= 0)
++ {
++ return false; // user locked out
++ }
++ return true;
++ }
++ return false; // assume user is disabled for any error.
++ }
++
++ std::vector<std::string>
++ getUserGroups(const std::string& userName) const override
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "ShadowService::getUserGroups not implemented!");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ return std::vector<std::string>();
++ }
++
++ void createGroup(const std::string& groupName) const override
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "ShadowService::createGroup not implemented!");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ private:
++ static constexpr const char* passwdFileName = "/etc/passwd";
++};
++
++class SSSDService : public phosphor::user::UserServiceInterface
++{
++ public:
++ SSSDService(const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs)
++ {
++
++ createGroup(lockedGrp);
++ for (const auto& g : groups)
++ {
++ createGroup(g);
++ }
++ for (const auto& p : privs)
++ {
++ createGroup(p);
++ }
++ }
++
++ ~SSSDService() = default;
++
++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override
++ {
++ std::vector<std::string> users;
++ std::vector<std::string> sshGroup;
++ std::vector<std::string> exeOutput;
++
++ try
++ {
++ exeOutput = phosphor::user::executeCmd("/usr/bin/getent", "-s",
++ "sss", "passwd");
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get users information "
++ "from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ for (const auto& userLine : exeOutput)
++ {
++ std::vector<std::string> userInfo;
++ boost::algorithm::split(userInfo, userLine,
++ boost::algorithm::is_any_of(":"));
++ // At this point userInfo is a vector containing the passwd
++ // info for the user, so we know the correct positions:
++ // 0: User name.
++ // 1: Encrypted password.
++ // 2: User ID number (UID)
++ // 3: User's group ID number (GID)
++ // 4: Full name of the user (GECOS)
++ // 5: User home directory.
++ // 6: Login shell.
++ users.emplace_back(userInfo[0]);
++
++ // ssh doesn't have separate group. Check login shell entry to
++ // get all users list which are member of ssh group.
++ if (userInfo[6] == "/bin/sh")
++ {
++ sshGroup.emplace_back(userInfo[0]);
++ }
++ }
++
++ return std::make_pair(std::move(users), std::move(sshGroup));
++ }
++
++ std::vector<std::string>
++ getUsersInGroup(const std::string& groupName) const override
++ {
++ std::vector<std::string> userList;
++ std::vector<std::string> exeOutput;
++
++ try
++ {
++ exeOutput = phosphor::user::executeCmd("/usr/sbin/sss_groupshow",
++ groupName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get group users from sssd service");
++ // Don't throw error, just return empty usersInGroup - return
++ return userList;
++ }
++ // exeOutput should have 5 entries
++ // 0: Group
++ // 1: GID number
++ // 2: Member users
++ // 3: Is a member of
++ // 4: Member groups
++ exeOutput[2].erase(
++ exeOutput[2].begin(),
++ std::find(exeOutput[2].begin(), exeOutput[2].end(), ':'));
++ boost::algorithm::trim_left(exeOutput[2]);
++ boost::algorithm::split(userList, exeOutput[2],
++ boost::algorithm::is_any_of(","));
++ return userList;
++ }
++
++ void createUser(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv, const bool& enabled) const override
++ {
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups += ",";
++ }
++ groups += priv;
++ }
++
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/sss_useradd", "-m", "-G", groups.c_str(), "-s",
++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to create new user in sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ // Sometimes the SSSD service needs some time to actually
++ // reflect the changes to the local DB to the NSS service,
++ // that is why we have this sleep here ...
++ std::this_thread::sleep_for(std::chrono::seconds(1));
++ // update user status (locked/unlocked)
++ updateUserStatus(userName, enabled);
++ }
++
++ void renameUser(const std::string& userName,
++ const std::string& newUserName) const override
++ {
++ std::vector<std::string> exeOutput;
++ // Local Domain for sssd doesn't have a rename feature
++ // so we need to first create a new user and then delete
++ // the old one.
++ // The only issue with this is that the password for the
++ // user will have to be reseted since it is a new user being created.
++
++ // Get original user groups
++ std::vector<std::string> groups = getUserGroups(userName);
++ // Check if it has a "ssh" group by looking for the shell login
++ try
++ {
++ exeOutput = phosphor::user::executeCmd(
++ "/usr/bin/getent", "-s", "sss", "passwd", userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get information for user");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ if (exeOutput[0].find("/bin/sh"))
++ {
++ groups.emplace_back(phosphor::user::grpSsh);
++ }
++ // Call create user with the new user names and previous groups
++ // Priv is already part of the groups so that can be empty.
++ createUser(newUserName, groups, "", isUserEnabled(userName));
++
++ // Now delete original user
++ deleteUser(userName);
++ }
++
++ void deleteUser(const std::string& userName) const override
++ {
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/sss_userdel", "-r",
++ userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to delete user from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateGroupsAndPriv(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv) const override
++ {
++ // local domain sssd do not allow to update all list of groups,
++ // so we will remove all groups first (except for the user one)
++ // and then all all the ones that were passed
++ std::string oldGroups = getCSVFromVector(getUserGroups(userName));
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups += ",";
++ }
++ groups += priv;
++ }
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/sss_usermod", "-r", oldGroups.c_str(), "-a",
++ groups.c_str(), "-s",
++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to update user groups and "
++ "priv from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateUserStatus(const std::string& userName,
++ const bool& enabled) const override
++ {
++ std::string enabledStr;
++ std::string lockedStr;
++ if (isUserEnabled(userName) == enabled)
++ {
++ return;
++ }
++ if (enabled)
++ {
++ enabledStr = "-r";
++ lockedStr = "-U";
++ }
++ else
++ {
++ enabledStr = "-a";
++ lockedStr = "-L";
++ }
++ try
++ {
++ // We will add a special locked group to identify the users
++ // that have been locked out of the system.
++ // TODO: sss_usermod is not locking user accounts for the
++ // LOCAL domain, need to find the correct PAM configuration
++ // to actually lockout users for SSSD.
++ // As a workaround we are using the pam module pam_listfile.so
++ // to lockout all users that belong to the locked group.
++ phosphor::user::executeCmd("/usr/sbin/sss_usermod",
++ enabledStr.c_str(), lockedGrp.c_str(),
++ lockedStr.c_str(), userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to update user status from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ bool isUserEnabled(const std::string& userName) const override
++ {
++ std::vector<std::string> userGrps = getUserGroups(userName);
++ return std::find(userGrps.begin(), userGrps.end(), lockedGrp) ==
++ userGrps.end();
++ }
++
++ std::vector<std::string>
++ getUserGroups(const std::string& userName) const override
++ {
++ std::vector<std::string> exeOutput;
++ try
++ {
++ exeOutput =
++ phosphor::user::executeCmd("/usr/bin/groups", userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get groups for user");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ std::vector<std::string> groups;
++ boost::algorithm::split(groups, exeOutput[0],
++ boost::algorithm::is_any_of(" "));
++ // Delete group that equals user name if it exists
++ auto userNameGroup = std::find(groups.begin(), groups.end(), userName);
++ if (userNameGroup != groups.end())
++ {
++ groups.erase(userNameGroup);
++ }
++ return groups;
++ }
++
++ void createGroup(const std::string& groupName) const override
++ {
++ try
++ {
++ if (!groupExists(groupName))
++ {
++ phosphor::user::executeCmd("/usr/sbin/sss_groupadd",
++ groupName.c_str());
++ }
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to create group");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ private:
++ static const std::string lockedGrp;
++
++ bool groupExists(const std::string& groupName) const
++ {
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/sss_groupshow",
++ groupName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure& e)
++ {
++ return false;
++ }
++ return true;
++ }
++};
++
++const std::string SSSDService::lockedGrp = "sssd_locked";
++} // anonymous namespace
++
++namespace phosphor
++{
++namespace user
++{
++
++UserService::UserService(const ServiceType& srvcType,
++ const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs)
++{
++ setServiceImpl(srvcType, groups, privs);
++}
++
++void UserService::updateServiceType(const ServiceType& srvcType,
++ const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs)
++{
++ usrSrvcImpl.reset();
++ setServiceImpl(srvcType, groups, privs);
++}
++
++void UserService::setServiceImpl(const ServiceType& srvcType,
++ const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs)
++{
++ switch (srvcType)
++ {
++ case ServiceType::shadow:
++ {
++ usrSrvcImpl = std::make_unique<ShadowService>();
++ }
++ break;
++
++ case ServiceType::sssd:
++ {
++ usrSrvcImpl = std::make_unique<SSSDService>(groups, privs);
++ }
++ break;
++
++ case ServiceType::none:
++ default:
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Invalid service type initialization!");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ break;
++ }
++}
++
++UserService::~UserService()
++{}
++
++phosphor::user::UserSSHLists UserService::getUserAndSshGrpList() const
++{
++ return usrSrvcImpl->getUserAndSshGrpList();
++}
++
++std::vector<std::string>
++ UserService::getUsersInGroup(const std::string& groupName) const
++{
++ return usrSrvcImpl->getUsersInGroup(groupName);
++}
++
++void UserService::createUser(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv, const bool& enabled) const
++{
++ usrSrvcImpl->createUser(userName, groupNames, priv, enabled);
++}
++
++void UserService::renameUser(const std::string& userName,
++ const std::string& newUserName) const
++{
++ usrSrvcImpl->renameUser(userName, newUserName);
++}
++
++void UserService::deleteUser(const std::string& userName) const
++{
++ usrSrvcImpl->deleteUser(userName);
++}
++
++void UserService::updateGroupsAndPriv(
++ const std::string& userName, const std::vector<std::string>& groupNames,
++ const std::string& priv) const
++{
++ usrSrvcImpl->updateGroupsAndPriv(userName, groupNames, priv);
++}
++
++void UserService::updateUserStatus(const std::string& userName,
++ const bool& enabled) const
++{
++ usrSrvcImpl->updateUserStatus(userName, enabled);
++}
++
++bool UserService::isUserEnabled(const std::string& userName) const
++{
++ return usrSrvcImpl->isUserEnabled(userName);
++}
++
++std::vector<std::string>
++ UserService::getUserGroups(const std::string& userName) const
++{
++ return usrSrvcImpl->getUserGroups(userName);
++}
++
++} // namespace user
++} // namespace phosphor
+diff --git a/user_service.hpp b/user_service.hpp
+new file mode 100644
+index 0000000..50ee4db
+--- /dev/null
++++ b/user_service.hpp
+@@ -0,0 +1,233 @@
++/*
++// Copyright (c) 2018 Intel Corporation
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++*/
++
++#pragma once
++#include <boost/process/child.hpp>
++#include <boost/process/io.hpp>
++#include <phosphor-logging/elog.hpp>
++#include <phosphor-logging/log.hpp>
++#include <xyz/openbmc_project/Common/error.hpp>
++#include <xyz/openbmc_project/User/Common/error.hpp>
++
++namespace phosphor
++{
++namespace user
++{
++
++using UserSSHLists =
++ std::pair<std::vector<std::string>, std::vector<std::string>>;
++using InternalFailure =
++ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
++using InsufficientPermission =
++ sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission;
++
++const std::string grpSsh = "ssh";
++
++template <typename... ArgTypes>
++std::vector<std::string> executeCmd(const char* path, ArgTypes&&... tArgs)
++{
++ std::vector<std::string> stdOutput;
++ boost::process::ipstream stdOutStream;
++ boost::process::child execProg(path, const_cast<char*>(tArgs)...,
++ boost::process::std_out > stdOutStream);
++ std::string stdOutLine;
++
++ while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
++ !stdOutLine.empty())
++ {
++ stdOutput.emplace_back(stdOutLine);
++ }
++
++ execProg.wait();
++
++ int retCode = execProg.exit_code();
++ if (retCode)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Command execution failed",
++ phosphor::logging::entry("PATH=%d", path),
++ phosphor::logging::entry("RETURN_CODE:%d", retCode));
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ return stdOutput;
++}
++
++/** @class UserServiceInterface
++ * @brief Interface class for methods provided by the implemmentations
++ * of the user service. Provides the same methods as the UserService
++ * class.
++ */
++class UserServiceInterface
++{
++ public:
++ UserServiceInterface() = default;
++ virtual ~UserServiceInterface() = default;
++ virtual UserSSHLists getUserAndSshGrpList() const = 0;
++ virtual std::vector<std::string>
++ getUsersInGroup(const std::string& groupName) const = 0;
++ virtual void createUser(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv,
++ const bool& enabled) const = 0;
++ virtual void renameUser(const std::string& userName,
++ const std::string& newUserName) const = 0;
++ virtual void deleteUser(const std::string& userName) const = 0;
++ virtual void updateGroupsAndPriv(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv) const = 0;
++ virtual void updateUserStatus(const std::string& userName,
++ const bool& enabled) const = 0;
++ virtual bool isUserEnabled(const std::string& userName) const = 0;
++ virtual std::vector<std::string>
++ getUserGroups(const std::string& userName) const = 0;
++ virtual void createGroup(const std::string& groupName) const = 0;
++};
++
++/** @class UserService
++ * @brief Responsible for managing the user service for the user manager.
++ * This service is the one responsible to actually change the user information
++ * of the application. It can support sevaral services, currently the ones
++ * supported are:
++ *
++ * 1) Shadow: Which uses the /etc/shadow file for updating the users
++ * 2) SSSD: Which uses the sssd service for a LOCAL domain only right now.
++ */
++class UserService
++{
++ public:
++ UserService() = delete;
++ UserService(const UserService&) = delete;
++ UserService& operator=(const UserService&) = delete;
++ UserService(UserService&&) = delete;
++ UserService& operator=(UserService&&) = delete;
++
++ // Service Types implemented. None is used to validate.
++ enum class ServiceType
++ {
++ none,
++ shadow,
++ sssd
++ };
++
++ UserService(const ServiceType& srvcType,
++ const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs);
++ ~UserService();
++
++ /** @brief update the current Service type of the instance.
++ * This function is used to update in real time the service
++ * being used for the user management without restarting the
++ * whole service.
++ *
++ * @param[in] srvcType
++ * @param[in] groups
++ * @param[in] privs
++ */
++ void updateServiceType(const ServiceType& srvcType,
++ const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs);
++
++ /** @brief get user list and SSH group members list
++ * This method gets the list of users from the service.
++ * If the userlist reference is empty, all the users will be added
++ * and DBus notified about them. If the list is not empty, the function
++ * will only update list adding the missing ones to it. It will not remove
++ * any extra users on the list that are not part of the service!
++ *
++ */
++ UserSSHLists getUserAndSshGrpList() const;
++
++ /** @brief Get users in group.
++ * This method creates a new user as requested
++ *
++ * @param[in] groupName - Name of the group which has to be queried
++ */
++ std::vector<std::string>
++ getUsersInGroup(const std::string& groupName) const;
++
++ /** @brief create user method.
++ * This method creates a new user as requested
++ *
++ * @param[in] userName - Name of the user which has to be created
++ * @param[in] groupNames - Group names list, to which user has to be added.
++ * @param[in] priv - Privilege of the user.
++ * @param[in] enabled - State of the user enabled / disabled.
++ */
++ void createUser(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv, const bool& enabled) const;
++
++ /** @brief rename user method.
++ * This method renames the user as requested
++ *
++ * @param[in] userName - current name of the user
++ * @param[in] userName - user name to which it has to be renamed.
++ */
++ void renameUser(const std::string& userName,
++ const std::string& newUserName) const;
++
++ /** @brief delete user method.
++ * This method deletes the user as requested
++ *
++ * @param[in] userName - Name of the user which has to be deleted
++ */
++ void deleteUser(const std::string& userName) const;
++
++ /** @brief Updates user Groups and Privilege.
++ *
++ * @param[in] userName - Name of the user which has to be modified
++ * @param[in] groupNames - Group names list for user.
++ * @param[in] priv - Privilege of the user.
++ */
++ void updateGroupsAndPriv(const std::string& userName,
++ const std::vector<std::string>& groupNames,
++ const std::string& priv) const;
++
++ /** @brief Updates user status
++ * If enabled = false: User will be disabled
++ * If enabled = true : User will be enabled
++ *
++ * @param[in] userName - Name of the user
++ * @param[in] enabled - Status of the user: enabled / disabled?
++ */
++ void updateUserStatus(const std::string& userName,
++ const bool& enabled) const;
++
++ /** @brief Verify if user is enabled or not
++ * If enabled returns true
++ * If not enabled returns false
++ *
++ * @param[in] userName - Name of the user
++ */
++ bool isUserEnabled(const std::string& userName) const;
++
++ /** @brief Get the list of groups a user belongs to
++ *
++ * @param[in] userName - Name of the user
++ */
++ std::vector<std::string> getUserGroups(const std::string& userName) const;
++
++ private:
++ // User service implementation.
++ void setServiceImpl(const ServiceType& srvcType,
++ const std::vector<std::string>& groups,
++ const std::vector<std::string>& privs);
++ std::unique_ptr<UserServiceInterface> usrSrvcImpl;
++};
++
++} // namespace user
++} // namespace phosphor
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch
new file mode 100644
index 000000000..7a0eff80e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch
@@ -0,0 +1,76 @@
+From 06064b3d6e56f4e13e6b85552f8525b74d9f1931 Mon Sep 17 00:00:00 2001
+From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Date: Mon, 24 Feb 2020 13:37:12 +0530
+Subject: [PATCH 2/2] Use groupmems instead of getgrnam_r due to overlay
+
+With JFFS2 overlay, getgrnam_r during initial time returns the
+old group details as per the lower dir, instead of the overlay one
+but at the same time groupmems where returning proper values, which
+reads the file everytime. Hence replacing getgrnam_r with groupmems
+
+Tested:
+1. Verified that when added multiple user and then doing
+BMC reset using ipmitool raw 6 2 doesn't reproduce the issue of
+user with only ssh group. (on 38 version source + this fix)
+2. Updated using redfish to version 39 + this fix, and made sure
+issue doesn't happen.
+
+Note: For testing purpose added debug statements to dump ouput of
+both getgrnam_r & groupmems and able to see proper list only
+in groupmems when the issue is reproduced
+
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ user_service.cpp | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/user_service.cpp b/user_service.cpp
+index ad4e510..89b27ed 100644
+--- a/user_service.cpp
++++ b/user_service.cpp
+@@ -147,28 +147,26 @@ class ShadowService : public phosphor::user::UserServiceInterface
+ getUsersInGroup(const std::string& groupName) const override
+ {
+ std::vector<std::string> usersInGroup;
+- // Should be more than enough to get the pwd structure.
+- std::array<char, 4096> buffer{};
+- struct group grp;
+- struct group* grpPtr = &grp;
+- struct group* resultPtr;
+-
+- int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(),
+- buffer.max_size(), &resultPtr);
+-
+- if (!status && (grpPtr == resultPtr))
++ std::vector<std::string> output;
++ try
+ {
+- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
+- {
+- usersInGroup.emplace_back(*(grp.gr_mem));
+- }
++ output = phosphor::user::executeCmd("/usr/sbin/groupmems", "-l",
++ "-g", groupName.c_str());
+ }
+- else
++ catch (const phosphor::user::InternalFailure& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Group not found",
+ phosphor::logging::entry("GROUP=%s", groupName.c_str()));
+ // Don't throw error, just return empty usersInGroup - fallback
++ return usersInGroup;
++ }
++ if (!output.empty())
++ {
++ boost::algorithm::trim_right(output[0]);
++ boost::algorithm::split(usersInGroup, output[0],
++ boost::algorithm::is_any_of("\t "),
++ boost::token_compress_on);
+ }
+ return usersInGroup;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend
new file mode 100644
index 000000000..21c7991bd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend
@@ -0,0 +1,16 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI = "git://github.com/openbmc/phosphor-user-manager"
+SRCREV = "c0760c9109a0d847fd77d54c6b7948322a375d1d"
+
+EXTRA_OECONF += "${@bb.utils.contains_any("IMAGE_FEATURES", [ 'debug-tweaks', 'allow-root-login' ], '', '--disable-root_user_mgmt', d)}"
+
+SRC_URI += " \
+ file://0005-Added-suport-for-multiple-user-manager-services.patch \
+ file://0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch \
+ "
+
+FILES:${PN} += "${datadir}/dbus-1/system.d/phosphor-nslcd-cert-config.conf"
+FILES:${PN} += "/usr/share/phosphor-certificate-manager/nslcd"
+FILES:${PN} += "\
+ /lib/systemd/system/multi-user.target.wants/phosphor-certificate-manager@nslcd.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb
new file mode 100644
index 000000000..b8aedc6ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Virtual Media Service"
+DESCRIPTION = "Virtual Media Service"
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+S = "${WORKDIR}/git/virtual-media"
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SYSTEMD_SERVICE:${PN} += "xyz.openbmc_project.VirtualMedia.service"
+
+DEPENDS = "udev boost nlohmann-json systemd sdbusplus"
+
+RDEPENDS:${PN} = "nbd-client nbdkit"
+
+inherit cmake systemd
+
+EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON"
+EXTRA_OECMAKE += "-DLEGACY_MODE_ENABLED=ON"
+
+FULL_OPTIMIZATION = "-Os -pipe -flto -fno-rtti"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch
new file mode 100644
index 000000000..48bc4a086
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch
@@ -0,0 +1,348 @@
+From a7d1d3770a650df8fe61d594885fcb388ac2ca42 Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Mon, 17 Jun 2019 12:00:58 -0700
+Subject: [PATCH] Customize phosphor-watchdog for Intel platforms
+
+This patch adds various changes to phosphor-watchdog that are
+required for compatibility with Intel platforms.
+
+ 1. Add Redfish messages for watchdog timeout and pre-interrupt
+ 2. Use dbus properties for power control insted of service files
+ 3. Use host status to enable/disable watchdog
+ 4. Set preTimeoutInterruptOccurFlag
+ 5. Assign watchdog cause for correct reset cause reporting
+ 6. Add NMI Pre-Interrupt support for IPMI watchdog timer.
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
+Signed-off-by: Sunita Kumari <sunitax.kumari@intel.com>
+
+%% original patch: 0001-Customize-phosphor-watchdog-for-Intel-platforms.patch
+---
+ src/watchdog.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++++---
+ src/watchdog.hpp | 22 ++++-
+ 2 files changed, 240 insertions(+), 11 deletions(-)
+
+diff --git a/src/watchdog.cpp b/src/watchdog.cpp
+index 7de98ae3e70f..f96faebc7368 100644
+--- a/src/watchdog.cpp
++++ b/src/watchdog.cpp
+@@ -5,8 +5,10 @@
+ #include <phosphor-logging/elog.hpp>
+ #include <phosphor-logging/log.hpp>
+ #include <sdbusplus/exception.hpp>
++#include <systemd/sd-journal.h>
+ #include <string_view>
+ #include <xyz/openbmc_project/Common/error.hpp>
++#include <xyz/openbmc_project/State/Host/server.hpp>
+
+ namespace phosphor
+ {
+@@ -19,10 +21,86 @@ using namespace phosphor::logging;
+ using sdbusplus::exception::SdBusError;
+ using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+-// systemd service to kick start a target.
+-constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
+-constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
+-constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
++const static constexpr char* currentHostState = "CurrentHostState";
++const static constexpr char* hostStatusOff =
++ "xyz.openbmc_project.State.Host.HostState.Off";
++
++const static constexpr char* actionDescription = " due to Watchdog timeout";
++const static constexpr char* hardResetDescription = "Hard Reset - System reset";
++const static constexpr char* powerOffDescription =
++ "Power Down - System power down";
++const static constexpr char* powerCycleDescription =
++ "Power Cycle - System power cycle";
++const static constexpr char* timerExpiredDescription = "Timer expired";
++
++const static constexpr char* preInterruptActionNone =
++ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None";
++
++const static constexpr char* preInterruptDescriptionSMI = "SMI";
++const static constexpr char* preInterruptDescriptionNMI = "NMI";
++const static constexpr char* preInterruptDescriptionMI = "Messaging Interrupt";
++
++const static constexpr char* reservedDescription = "Reserved";
++
++const static constexpr char* timerUseDescriptionBIOSFRB2 = "BIOS FRB2";
++const static constexpr char* timerUseDescriptionBIOSPOST = "BIOS/POST";
++const static constexpr char* timerUseDescriptionOSLoad = "OSLoad";
++const static constexpr char* timerUseDescriptionSMSOS = "SMS/OS";
++const static constexpr char* timerUseDescriptionOEM = "OEM";
++
++namespace restart
++{
++static constexpr const char* busName =
++ "xyz.openbmc_project.Control.Host.RestartCause";
++static constexpr const char* path =
++ "/xyz/openbmc_project/control/host0/restart_cause";
++static constexpr const char* interface =
++ "xyz.openbmc_project.Control.Host.RestartCause";
++static constexpr const char* property = "RequestedRestartCause";
++} // namespace restart
++
++// chassis state manager service
++namespace chassis
++{
++static constexpr const char* busName = "xyz.openbmc_project.State.Chassis";
++static constexpr const char* path = "/xyz/openbmc_project/state/chassis0";
++static constexpr const char* interface = "xyz.openbmc_project.State.Chassis";
++static constexpr const char* request = "RequestedPowerTransition";
++} // namespace chassis
++
++namespace host
++{
++static constexpr const char* busName = "xyz.openbmc_project.State.Host";
++static constexpr const char* path = "/xyz/openbmc_project/state/host0";
++static constexpr const char* interface = "xyz.openbmc_project.State.Host";
++static constexpr const char* request = "RequestedHostTransition";
++} // namespace host
++
++namespace nmi
++{
++static constexpr const char* busName = "xyz.openbmc_project.Control.Host.NMI";
++static constexpr const char* path = "/xyz/openbmc_project/control/host0/nmi";
++static constexpr const char* interface = "xyz.openbmc_project.Control.Host.NMI";
++static constexpr const char* request = "NMI";
++
++} // namespace nmi
++
++void Watchdog::powerStateChangedHandler(
++ const std::map<std::string, std::variant<std::string>>& props)
++{
++ const auto iter = props.find(currentHostState);
++ if (iter != props.end())
++ {
++ const std::string* powerState = std::get_if<std::string>(&iter->second);
++ if (powerState && (*powerState == hostStatusOff))
++ {
++ if (timerEnabled())
++ {
++ enabled(false);
++ }
++ }
++ }
++}
+
+ void Watchdog::resetTimeRemaining(bool enableWatchdog)
+ {
+@@ -108,13 +186,111 @@ uint64_t Watchdog::interval(uint64_t value)
+ // Optional callback function on timer expiration
+ void Watchdog::timeOutHandler()
+ {
++ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt();
++ std::string preInterruptActionMessageArgs{};
++
+ Action action = expireAction();
++ std::string actionMessageArgs{};
++
++ expiredTimerUse(currentTimerUse());
++
++ TimerUse timeUser = expiredTimerUse();
++ std::string timeUserMessage{};
++
+ if (!this->enabled())
+ {
+ action = fallback->action;
+ }
+
+- expiredTimerUse(currentTimerUse());
++ switch (timeUser)
++ {
++ case Watchdog::TimerUse::BIOSFRB2:
++ timeUserMessage = timerUseDescriptionBIOSFRB2;
++ break;
++ case Watchdog::TimerUse::BIOSPOST:
++ timeUserMessage = timerUseDescriptionBIOSPOST;
++ break;
++ case Watchdog::TimerUse::OSLoad:
++ timeUserMessage = timerUseDescriptionOSLoad;
++ break;
++ case Watchdog::TimerUse::SMSOS:
++ timeUserMessage = timerUseDescriptionSMSOS;
++ break;
++ case Watchdog::TimerUse::OEM:
++ timeUserMessage = timerUseDescriptionOEM;
++ break;
++ default:
++ timeUserMessage = reservedDescription;
++ break;
++ }
++
++ switch (action)
++ {
++ case Watchdog::Action::HardReset:
++ actionMessageArgs = std::string(hardResetDescription) +
++ std::string(actionDescription);
++ break;
++ case Watchdog::Action::PowerOff:
++ actionMessageArgs = std::string(powerOffDescription) +
++ std::string(actionDescription);
++ break;
++ case Watchdog::Action::PowerCycle:
++ actionMessageArgs = std::string(powerCycleDescription) +
++ std::string(actionDescription);
++ break;
++ case Watchdog::Action::None:
++ actionMessageArgs = timerExpiredDescription;
++ break;
++ default:
++ actionMessageArgs = reservedDescription;
++ break;
++ }
++
++ // Log into redfish event log
++ sd_journal_send("MESSAGE=IPMIWatchdog: Timed out ACTION=%s",
++ convertForMessage(action).c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.IPMIWatchdog",
++ "REDFISH_MESSAGE_ARGS=%s. timer use: %s",
++ actionMessageArgs.c_str(), timeUserMessage.c_str(), NULL);
++
++ switch (preTimeoutInterruptAction)
++ {
++ case Watchdog::PreTimeoutInterruptAction::SMI:
++ preInterruptActionMessageArgs = preInterruptDescriptionSMI;
++ break;
++ case Watchdog::PreTimeoutInterruptAction::NMI:
++ preInterruptActionMessageArgs = preInterruptDescriptionNMI;
++ break;
++ case Watchdog::PreTimeoutInterruptAction::MI:
++ preInterruptActionMessageArgs = preInterruptDescriptionMI;
++ break;
++ default:
++ preInterruptActionMessageArgs = reservedDescription;
++ break;
++ }
++
++ if (preInterruptActionNone != convertForMessage(preTimeoutInterruptAction))
++ {
++ preTimeoutInterruptOccurFlag(true);
++
++ sd_journal_send("MESSAGE=IPMIWatchdog: Pre Timed out Interrupt=%s",
++ convertForMessage(preTimeoutInterruptAction).c_str(),
++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.IPMIWatchdog",
++ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to "
++ "Watchdog timeout. timer use: %s",
++ preInterruptActionMessageArgs.c_str(),
++ timeUserMessage.c_str(), NULL);
++
++ if (preTimeoutInterruptAction ==
++ Watchdog::PreTimeoutInterruptAction::NMI)
++ {
++ sdbusplus::message::message preTimeoutInterruptHandler;
++ preTimeoutInterruptHandler = bus.new_method_call(
++ nmi::busName, nmi::path, nmi::interface, nmi::request);
++ bus.call_noreply(preTimeoutInterruptHandler);
++ }
++ }
+
+ auto target = actionTargetMap.find(action);
+ if (target == actionTargetMap.end())
+@@ -147,12 +323,45 @@ void Watchdog::timeOutHandler()
+
+ try
+ {
+- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
+- SYSTEMD_INTERFACE, "StartUnit");
+- method.append(target->second);
+- method.append("replace");
++ sdbusplus::message::message method;
++ if (action == Watchdog::Action::HardReset)
++ {
++ auto method = bus.new_method_call(
++ restart::busName, restart::path,
++ "org.freedesktop.DBus.Properties", "Set");
++ method.append(
++ restart::interface, restart::property,
++ std::variant<std::string>("xyz.openbmc_project.State.Host."
++ "RestartCause.WatchdogTimer"));
++ bus.call_noreply(method);
+
+- bus.call_noreply(method);
++ method = bus.new_method_call(host::busName, host::path,
++ "org.freedesktop.DBus.Properties",
++ "Set");
++ method.append(host::interface, host::request,
++ std::variant<std::string>(target->second));
++ bus.call_noreply(method);
++ }
++ else
++ {
++ if (action == Watchdog::Action::PowerCycle)
++ {
++ auto method = bus.new_method_call(
++ restart::busName, restart::path,
++ "org.freedesktop.DBus.Properties", "Set");
++ method.append(restart::interface, restart::property,
++ std::variant<std::string>(
++ "xyz.openbmc_project.State.Host."
++ "RestartCause.WatchdogTimer"));
++ bus.call_noreply(method);
++ }
++ method = bus.new_method_call(chassis::busName, chassis::path,
++ "org.freedesktop.DBus.Properties",
++ "Set");
++ method.append(chassis::interface, chassis::request,
++ std::variant<std::string>(target->second));
++ bus.call_noreply(method);
++ }
+ }
+ catch (const SdBusError& e)
+ {
+diff --git a/src/watchdog.hpp b/src/watchdog.hpp
+index 736e71f68fcc..79158f192f40 100644
+--- a/src/watchdog.hpp
++++ b/src/watchdog.hpp
+@@ -73,7 +73,17 @@ class Watchdog : public WatchdogInherits
+ bus(bus), actionTargetMap(std::move(actionTargetMap)),
+ fallback(std::move(fallback)), minInterval(minInterval),
+ timer(event, std::bind(&Watchdog::timeOutHandler, this)),
+- objPath(objPath)
++ objPath(objPath), powerStateChangedSignal(
++ bus,
++ sdbusplus::bus::match::rules::propertiesChanged(
++ "/xyz/openbmc_project/state/host0",
++ "xyz.openbmc_project.State.Host"),
++ [this](sdbusplus::message::message& msg) {
++ std::string objectName;
++ std::map<std::string, std::variant<std::string>> props;
++ msg.read(objectName, props);
++ powerStateChangedHandler(props);
++ })
+ {
+ // Use default if passed in otherwise just use default that comes
+ // with object
+@@ -90,6 +100,12 @@ class Watchdog : public WatchdogInherits
+ tryFallbackOrDisable();
+ }
+
++ /** @brief Disable watchdog when power status change meet
++ * the specific requirement
++ */
++ void powerStateChangedHandler(
++ const std::map<std::string, std::variant<std::string>>& props);
++
+ /** @brief Resets the TimeRemaining to the configured Interval
+ * Optionally enables the watchdog.
+ *
+@@ -178,6 +194,10 @@ class Watchdog : public WatchdogInherits
+ /** @brief Contained timer object */
+ sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
+
++ /** @brief Optional Callback handler when power status change meet
++ * the specific requirement */
++ sdbusplus::bus::match_t powerStateChangedSignal;
++
+ /** @brief Optional Callback handler on timer expirartion */
+ void timeOutHandler();
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service
new file mode 100644
index 000000000..35d3e8e0f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Phosphor Watchdog
+
+[Service]
+ExecStart=/usr/bin/phosphor-watchdog --continue --service=xyz.openbmc_project.Watchdog \
+ --path=/xyz/openbmc_project/watchdog/host0 \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=xyz.openbmc_project.State.Host.Transition.ForceWarmReboot \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=xyz.openbmc_project.State.Chassis.Transition.Off \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=xyz.openbmc_project.State.Chassis.Transition.PowerCycle
+
+BusName=xyz.openbmc_project.Watchdog
+Type=dbus
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
new file mode 100644
index 000000000..cc439b2c5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS:append := ":${THISDIR}/${PN}"
+
+SRC_URI += "file://0001-Customize-phosphor-watchdog-for-Intel-platforms.patch \
+ "
+
+# Remove the override to keep service running after DC cycle
+SYSTEMD_OVERRIDE:${PN}:remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf"
+SYSTEMD_SERVICE:${PN} = "phosphor-watchdog.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb
new file mode 100644
index 000000000..ac1302d9c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb
@@ -0,0 +1,12 @@
+SUMMARY = "System watchdog"
+DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \
+ when unrecoverable events occurs"
+
+inherit allarch
+inherit obmc-phosphor-systemd
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE:${PN} += "system-watchdog.service"
+SYSTEMD_ENVIRONMENT_FILE:${PN} += "obmc/system-watchdog/system-watchdog.conf"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf
new file mode 100644
index 000000000..defe830a1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf
@@ -0,0 +1,3 @@
+TIMEOUT=60
+INTERVAL=10
+DEVICE=/dev/watchdog1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service
new file mode 100644
index 000000000..1564fda20
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=BMC Hardware Watchdog Daemon
+
+[Service]
+EnvironmentFile=/etc/default/obmc/system-watchdog/system-watchdog.conf
+ExecStart=/sbin/watchdog -T ${{TIMEOUT}} -t ${{INTERVAL}} -F ${{DEVICE}}
+KillSignal=SIGKILL
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json
new file mode 100644
index 000000000..348a7792d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json
@@ -0,0 +1,9 @@
+{
+ "customKeyEnable": true,
+ "keyType" : "VT100+",
+ "customConsoleDisplaySize": {
+ "width": 100,
+ "height": 32
+ },
+ "VirtualMediaEnabled" : true
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
new file mode 100644
index 000000000..19db93805
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
@@ -0,0 +1,4 @@
+SRC_URI = "git://github.com/Intel-BMC/phosphor-webui;protocol=ssh;branch=intel2"
+FILESEXTRAPATHS:prepend:intel := "${THISDIR}/${PN}:"
+
+SRCREV = "b5707d7648de19350b3f308b9602c888c6418d6f"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/login-company-logo.svg b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/login-company-logo.svg
new file mode 100644
index 000000000..0976f72e8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/login-company-logo.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 395.4 155.9" style="enable-background:new 0 0 395.4 155.9;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#0068B5;}
+</style>
+<rect x="4.7" y="5.2" class="st0" width="28.1" height="28.1"/>
+<g>
+ <path d="M32.1,151.6V50.4H5.5v101.2H32.1z M208.9,152.6v-24.8c-3.9,0-7.2-0.2-9.6-0.6c-2.8-0.4-4.9-1.4-6.3-2.8
+ c-1.4-1.4-2.3-3.4-2.8-6c-0.4-2.5-0.6-5.8-0.6-9.8V73.2h19.3V50.4h-19.3V10.9h-26.7v97.9c0,8.3,0.7,15.3,2.1,20.9
+ c1.4,5.5,3.8,10,7.1,13.4s7.7,5.8,13,7.3c5.4,1.5,12.2,2.2,20.3,2.2L208.9,152.6L208.9,152.6z M361.7,151.6V3.1H335v148.5H361.7z
+ M137.2,60.3c-7.4-8-17.8-12-31-12c-6.4,0-12.2,1.3-17.5,3.9C83.5,54.8,79,58.4,75.5,63L74,64.9v-1.7V50.4H47.7v101.2h26.5V97.7
+ v3.7c0-0.6,0-1.2,0-1.8c0.3-9.5,2.6-16.5,7-21c4.7-4.8,10.4-7.2,16.9-7.2c7.7,0,13.6,2.4,17.5,7c3.8,4.6,5.8,11.1,5.8,19.4l0,0V98
+ l0,0l0,0v53.5h26.9V94.1C148.4,79.7,144.6,68.3,137.2,60.3z M321.2,100.8c0-7.3-1.3-14.1-3.8-20.5c-2.6-6.3-6.2-11.9-10.7-16.7
+ c-4.6-4.8-10.1-8.5-16.5-11.2s-13.5-4-21.2-4c-7.3,0-14.2,1.4-20.6,4.1c-6.4,2.8-12,6.5-16.7,11.2s-8.5,10.3-11.2,16.7
+ c-2.8,6.4-4.1,13.3-4.1,20.6c0,7.3,1.3,14.2,3.9,20.6c2.6,6.4,6.3,12,10.9,16.7c4.6,4.7,10.3,8.5,16.9,11.2
+ c6.6,2.8,13.9,4.2,21.7,4.2c22.6,0,36.6-10.3,45-19.9l-19.2-14.6c-4,4.8-13.6,11.3-25.6,11.3c-7.5,0-13.7-1.7-18.4-5.2
+ c-4.7-3.4-7.9-8.2-9.6-14.1l-0.3-0.9h79.5L321.2,100.8L321.2,100.8z M241.9,91.5c0-7.4,8.5-20.3,26.8-20.4
+ c18.3,0,26.9,12.9,26.9,20.3L241.9,91.5z"/>
+ <path d="M392.1,138.4c-0.5-1.2-1.2-2.2-2.1-3.1c-0.9-0.9-1.9-1.6-3.1-2.1s-2.5-0.8-3.8-0.8c-1.4,0-2.6,0.3-3.8,0.8
+ c-1.2,0.5-2.2,1.2-3.1,2.1c-0.9,0.9-1.6,1.9-2.1,3.1c-0.5,1.2-0.8,2.5-0.8,3.8c0,1.4,0.3,2.6,0.8,3.8s1.2,2.2,2.1,3.1
+ c0.9,0.9,1.9,1.6,3.1,2.1s2.5,0.8,3.8,0.8c1.4,0,2.6-0.3,3.8-0.8c1.2-0.5,2.2-1.2,3.1-2.1c0.9-0.9,1.6-1.9,2.1-3.1
+ c0.5-1.2,0.8-2.5,0.8-3.8S392.6,139.6,392.1,138.4z M390.5,145.4c-0.4,1-1,1.9-1.7,2.6c-0.7,0.7-1.6,1.3-2.6,1.7s-2,0.6-3.2,0.6
+ c-1.1,0-2.2-0.2-3.2-0.6c-1-0.4-1.9-1-2.6-1.7s-1.3-1.6-1.7-2.6c-0.4-1-0.6-2-0.6-3.2c0-1.1,0.2-2.2,0.6-3.2s1-1.9,1.7-2.6
+ c0.7-0.7,1.6-1.3,2.6-1.7s2-0.6,3.2-0.6c1.1,0,2.2,0.2,3.2,0.6c1,0.4,1.9,1,2.6,1.7s1.3,1.6,1.7,2.6c0.4,1,0.6,2,0.6,3.2
+ C391.2,143.4,390.9,144.4,390.5,145.4z M384.9,143c0.8-0.1,1.4-0.4,1.9-0.9s0.8-1.2,0.8-2.2c0-1.1-0.3-1.9-1-2.5
+ c-0.6-0.6-1.7-0.9-3-0.9h-4.4v11.3h2.1v-4.6h1.5l2.8,4.6h2.2L384.9,143z M383.8,141.4c-0.3,0-0.6,0-1,0h-1.5v-3.2h1.5
+ c0.3,0,0.6,0,1,0c0.3,0,0.6,0.1,0.9,0.2c0.3,0.1,0.5,0.3,0.6,0.5s0.2,0.5,0.2,0.9s-0.1,0.7-0.2,0.9c-0.2,0.2-0.4,0.4-0.6,0.5
+ C384.4,141.3,384.1,141.4,383.8,141.4z"/>
+</g>
+</svg>
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/logo-header.svg b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/logo-header.svg
new file mode 100644
index 000000000..dc449a1b6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue/logo-header.svg
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="81px" height="32px"
+ viewBox="0 0 395.4 155.9" style="enable-background:new 0 0 395.4 155.9;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#00C7FD;}
+ .st1{fill:#FFFFFF;}
+</style>
+<rect x="4.7" y="5.2" class="st0" width="28.1" height="28.1"/>
+<path class="st1" d="M32.1,151.6V50.3H5.4v101.2H32.1z M208.9,152.6v-24.8c-3.9,0-7.2-0.2-9.6-0.6c-2.8-0.4-4.9-1.4-6.3-2.8
+ c-1.4-1.4-2.3-3.4-2.8-6.1c-0.4-2.5-0.6-5.8-0.6-9.8V73.2h19.3V50.3h-19.3V10.9h-26.7v97.9c0,8.3,0.7,15.3,2.1,20.9
+ c1.4,5.5,3.8,10,7.1,13.4c3.3,3.4,7.7,5.8,13,7.3c5.4,1.5,12.2,2.2,20.3,2.2H208.9z M361.7,151.6V3.1h-26.7v148.5H361.7z
+ M137.2,60.3c-7.4-8-17.8-12-31-12c-6.4,0-12.3,1.3-17.5,3.9C83.4,54.8,79,58.4,75.4,63L74,64.9l0-1.7V50.3H47.7v101.2h26.5V97.6
+ l0,3.7c0-0.6,0-1.2,0-1.8c0.3-9.5,2.6-16.5,7-21c4.7-4.8,10.4-7.2,16.9-7.2c7.7,0,13.6,2.4,17.5,7c3.8,4.6,5.8,11.1,5.8,19.4l0,0V98
+ c0,0,0,0,0,0l0,0l0,53.5h26.9V94.1C148.4,79.7,144.6,68.3,137.2,60.3z M321.2,100.8c0-7.3-1.3-14.1-3.8-20.5
+ c-2.6-6.3-6.2-11.9-10.7-16.7c-4.6-4.8-10.1-8.5-16.5-11.2c-6.4-2.7-13.5-4-21.2-4c-7.3,0-14.2,1.4-20.6,4.1
+ c-6.4,2.8-12,6.5-16.7,11.2c-4.7,4.7-8.5,10.3-11.2,16.7c-2.8,6.4-4.1,13.3-4.1,20.6c0,7.3,1.3,14.2,3.9,20.6
+ c2.6,6.4,6.3,12,10.9,16.7c4.6,4.7,10.3,8.5,16.9,11.2c6.6,2.8,13.9,4.2,21.7,4.2c22.6,0,36.6-10.3,45-19.9l-19.2-14.6
+ c-4,4.8-13.6,11.3-25.6,11.3c-7.5,0-13.7-1.7-18.4-5.2c-4.7-3.4-7.9-8.2-9.6-14.1l-0.3-0.9h79.5V100.8z M241.9,91.5
+ c0-7.4,8.5-20.3,26.8-20.4c18.3,0,26.9,12.9,26.9,20.3L241.9,91.5z M392.1,138.8c-0.5-1.2-1.2-2.2-2.1-3.1c-0.9-0.9-1.9-1.6-3.1-2.1
+ c-1.2-0.5-2.5-0.8-3.8-0.8c-1.4,0-2.6,0.3-3.8,0.8c-1.2,0.5-2.2,1.2-3.1,2.1c-0.9,0.9-1.6,1.9-2.1,3.1c-0.5,1.2-0.8,2.5-0.8,3.8
+ c0,1.4,0.3,2.6,0.8,3.8s1.2,2.2,2.1,3.1c0.9,0.9,1.9,1.6,3.1,2.1c1.2,0.5,2.5,0.8,3.8,0.8c1.4,0,2.6-0.3,3.8-0.8
+ c1.2-0.5,2.2-1.2,3.1-2.1c0.9-0.9,1.6-1.9,2.1-3.1c0.5-1.2,0.8-2.5,0.8-3.8C392.9,141.3,392.6,140,392.1,138.8z M390.5,145.8
+ c-0.4,1-1,1.9-1.7,2.6c-0.7,0.7-1.6,1.3-2.6,1.7c-1,0.4-2,0.6-3.2,0.6c-1.1,0-2.2-0.2-3.2-0.6c-1-0.4-1.9-1-2.6-1.7
+ c-0.7-0.7-1.3-1.6-1.7-2.6c-0.4-1-0.6-2-0.6-3.2c0-1.1,0.2-2.2,0.6-3.2c0.4-1,1-1.9,1.7-2.6c0.7-0.7,1.6-1.3,2.6-1.7
+ c1-0.4,2-0.6,3.2-0.6c1.1,0,2.2,0.2,3.2,0.6c1,0.4,1.9,1,2.6,1.7c0.7,0.7,1.3,1.6,1.7,2.6c0.4,1,0.6,2,0.6,3.2
+ C391.1,143.8,390.9,144.8,390.5,145.8z M384.9,143.5c0.8-0.1,1.4-0.4,1.9-0.9c0.5-0.5,0.8-1.2,0.8-2.2c0-1.1-0.3-1.9-1-2.5
+ c-0.6-0.6-1.7-0.9-3-0.9h-4.4v11.3h2.1v-4.6h1.5l2.8,4.6h2.2L384.9,143.5z M383.8,141.8c-0.3,0-0.6,0-1,0h-1.5v-3.2h1.5
+ c0.3,0,0.6,0,1,0c0.3,0,0.6,0.1,0.9,0.2c0.3,0.1,0.5,0.3,0.6,0.5c0.2,0.2,0.2,0.5,0.2,0.9c0,0.4-0.1,0.7-0.2,0.9
+ c-0.2,0.2-0.4,0.4-0.6,0.5C384.4,141.7,384.1,141.8,383.8,141.8z"/>
+</svg>
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend
new file mode 100644
index 000000000..1273ebb29
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend
@@ -0,0 +1,15 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/webui-vue.git"
+SRCREV = "2a2e1021f48e2a939859ba7f4ae86c5de6df5655"
+
+FILESEXTRAPATHS:append := "${THISDIR}/${PN}:"
+SRC_URI += " \
+ file://login-company-logo.svg \
+ file://logo-header.svg \
+ "
+
+do_compile:prepend() {
+ cp -vf ${S}/.env.intel ${S}/.env
+ cp -vf ${WORKDIR}/login-company-logo.svg ${S}/src/assets/images
+ cp -vf ${WORKDIR}/logo-header.svg ${S}/src/assets/images
+}