From 5d3fc64c142786581d792d145231c835afbcdded Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Mon, 21 Sep 2020 12:59:23 -0700 Subject: Update to internal 0.74-57 Signed-off-by: Jason M. Bills --- .../configuration/entity-manager/WC-Baseboard.json | 31 +- .../configuration/entity-manager/WC-Chassis.json | 6 + .../classes/obmc-phosphor-full-fitimage.bbclass | 43 +- .../classes/obmc-phosphor-image-common.bbclass | 4 +- .../meta-common/classes/systemd-watchdog.bbclass | 8 + .../recipes-core/crashdump/crashdump_git.bb | 2 +- .../host-error-monitor_%.bbappend | 2 +- ...dundancy-is-not-runing-as-user-configurat.patch | 121 +++ ...wVersionInfo-Fix-for-Firmware-aux-version.patch | 120 +++ ...gecommands-Fix-for-GetFruAreaInfo-command.patch | 48 ++ ...e-update-Add-Support-to-get-fwSecurityVer.patch | 111 +++ .../recipes-core/ipmi/intel-ipmi-oem_%.bbappend | 9 + .../recipes-core/nv-sync/nv-sync/nv-sync.service | 6 +- .../recipes-core/nv-sync/nv-sync/nv-syncd | 32 + .../recipes-core/nv-sync/nv-sync_git.bb | 5 + .../0005-Refine-HID-report-writing-logic.patch | 295 ++++++++ .../obmc-ikvm/obmc-ikvm_%.bbappend | 1 + .../recipes-intel/intel-pfr/pfr-manager_%.bbappend | 2 +- .../nic/enable-nics/enable-nics.service | 1 - .../linux-aspeed/0113-hwmon-peci-PCS-utils.patch | 706 ++++++++++++++++++ .../0114-hwmon-peci-cpupower-extension.patch | 708 ++++++++++++++++++ .../0115-hwmon-peci-dimmpower-implementation.patch | 677 +++++++++++++++++ .../0001-blktrace-fix-debugfs-use-after-free.patch | 214 ++++++ ...oup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch | 178 +++++ ...cgroup-Fix-sock_cgroup_data-on-big-endian.patch | 39 + ...date-the-net-random-state-on-interrupt-an.patch | 116 +++ .../recipes-kernel/linux/linux-aspeed_%.bbappend | 22 + .../recipes-network/network/ncsi-monitor.bb | 25 + .../network/ncsi-monitor/check-for-host-in-reset | 65 ++ .../network/ncsi-monitor/ncsi-monitor.service | 11 + .../beepcode-mgr/files/beepcode_mgr.cpp | 6 - .../0005-EventService-https-client-support.patch | 390 ++++++---- ...0007-cpudimm-get-cpu-details-from-Redfish.patch | 231 ++++++ ...8-systems-Fix-for-Processor-Summary-Model.patch | 138 ++++ ...etricReportDefinitions-filter-not-working.patch | 112 +++ .../bmcweb/0009-Workaround-Fix-memory-leak.patch | 33 + ...010-Fix-EventService-stops-sending-events.patch | 67 ++ ...0011-Deallocate-memory-during-failed-case.patch | 32 + ...12-System-Replace-chassis-name-in-Redfish.patch | 64 ++ ...url_view-throws-if-a-parse-error-is-found.patch | 54 ++ ...fficient-delay-to-create-fw-update-object.patch | 44 ++ ...mware-activation-messages-to-the-registry.patch | 72 ++ ...Service-Fix-type-mismatch-in-MetricReport.patch | 83 +++ ...17-Add-MutualExclusiveProperties-registry.patch | 151 ++++ .../0018-Add-sse-event-sequence-number.patch | 74 ++ ...rvice-Limit-SSE-connections-as-per-design.patch | 108 +++ ...0-EventService-Validate-SSE-query-filters.patch | 262 +++++++ ...x-MetricReport-timestamp-for-EventService.patch | 78 -- .../recipes-phosphor/interfaces/bmcweb_%.bbappend | 16 +- ...-transporthandler-Fix-for-invalid-VLAN-id.patch | 94 +++ ...ler-Fix-for-set-system-Info-parameter-cmd.patch | 98 +++ ...handler-Fix-for-total-session-slots-count.patch | 64 ++ ...et-Channel-Info-cmd-for-reserved-channels.patch | 61 ++ ...Removal-of-OEM-privilege-setting-for-User.patch | 43 ++ ...pphandler-Fix-for-get-system-info-command.patch | 89 +++ ...r-fix-corrected-cc-for-get-channel-access.patch | 39 + ...ishandler-SetSystemBootOptions-to-new-API.patch | 821 +++++++++++++++++++++ ...ishandler-GetSystemBootOptions-to-new-API.patch | 429 +++++++++++ .../ipmi/phosphor-ipmi-host_%.bbappend | 9 + .../0009-Add-dbus-interface-for-sol-commands.patch | 36 +- .../ipmi/phosphor-ipmi-net_%.bbappend | 2 +- .../sensors/dbus-sensors_%.bbappend | 2 +- ...-Add-a-workaround-for-spurious-CPU-errors.patch | 133 ++++ ...-Override-crashdump-timeout-to-30-minutes.patch | 41 + .../host-error-monitor_%.bbappend | 2 + 65 files changed, 7313 insertions(+), 273 deletions(-) create mode 100644 meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0001-Fix-cold-redundancy-is-not-runing-as-user-configurat.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0002-GetFwVersionInfo-Fix-for-Firmware-aux-version.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0003-storagecommands-Fix-for-GetFruAreaInfo-command.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0004-firmware-update-Add-Support-to-get-fwSecurityVer.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-syncd create mode 100644 meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0113-hwmon-peci-PCS-utils.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0114-hwmon-peci-cpupower-extension.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0115-hwmon-peci-dimmpower-implementation.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2019-19770/0001-blktrace-fix-debugfs-use-after-free.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0001-cgroup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0002-cgroup-Fix-sock_cgroup_data-on-big-endian.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-16166/0001-random32-update-the-net-random-state-on-interrupt-an.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor.bb create mode 100755 meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/check-for-host-in-reset create mode 100644 meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/ncsi-monitor.service create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-EventService-Fix-type-mismatch-in-MetricReport.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-transporthandler-Fix-for-invalid-VLAN-id.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0065-apphandler-Fix-for-set-system-Info-parameter-cmd.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-apphandler-Fix-for-total-session-slots-count.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0067-Fix-for-get-Channel-Info-cmd-for-reserved-channels.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0068-Removal-of-OEM-privilege-setting-for-User.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0069-apphandler-Fix-for-get-system-info-command.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0070-minor-fix-corrected-cc-for-get-channel-access.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0071-chassishandler-SetSystemBootOptions-to-new-API.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0072-chassishandler-GetSystemBootOptions-to-new-API.patch create mode 100644 meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0002-Add-a-workaround-for-spurious-CPU-errors.patch create mode 100644 meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0003-Override-crashdump-timeout-to-30-minutes.patch diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json index 83e6deabe..34a38489e 100644 --- a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json @@ -499,96 +499,112 @@ { "BindConnector": "System Fan connector 1", "Index": 0, + "MaxReading": 8000, "Name": "Fan 1a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 1", "Index": 1, + "MaxReading": 8000, "Name": "Fan 1b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 2", "Index": 2, + "MaxReading": 8000, "Name": "Fan 2a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 2", "Index": 3, + "MaxReading": 8000, "Name": "Fan 2b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 3", "Index": 4, + "MaxReading": 8000, "Name": "Fan 3a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 3", "Index": 5, + "MaxReading": 8000, "Name": "Fan 3b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 4", "Index": 6, + "MaxReading": 8000, "Name": "Fan 4a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 4", "Index": 7, + "MaxReading": 8000, "Name": "Fan 4b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 5", "Index": 8, + "MaxReading": 8000, "Name": "Fan 5a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 5", "Index": 9, + "MaxReading": 8000, "Name": "Fan 5b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 6", "Index": 10, + "MaxReading": 8000, "Name": "Fan 6a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 6", "Index": 11, + "MaxReading": 8000, "Name": "Fan 6b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 7", "Index": 12, + "MaxReading": 8000, "Name": "Fan 7a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 7", "Index": 13, + "MaxReading": 8000, "Name": "Fan 7b", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 8", "Index": 14, + "MaxReading": 8000, "Name": "Fan 8a", "Type": "AspeedFan" }, { "BindConnector": "System Fan connector 8", "Index": 15, + "MaxReading": 8000, "Name": "Fan 8b", "Type": "AspeedFan" }, @@ -1667,6 +1683,11 @@ "Name": "PSU address", "Type": "PSUPresence" }, + { + "RedundantCount": 1, + "Name": "Power Unit Redundancy", + "Type": "PURedundancy" + }, { "Class": "temp", "FFGainCoefficient": 0.0, @@ -1951,7 +1972,7 @@ "Outputs": [], "PCoefficient": -0.15, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 60.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -1977,7 +1998,7 @@ "Outputs": [], "PCoefficient": -0.15, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 60.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -2002,7 +2023,7 @@ "Outputs": [], "PCoefficient": -0.15, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 60.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -2028,7 +2049,7 @@ "Outputs": [], "PCoefficient": -0.15, "PositiveHysteresis": 0.0, - "SetPoint": 80.0, + "SetPoint": 60.0, "SlewNeg": -1, "SlewPos": 0.0, "Type": "Pid", @@ -2451,4 +2472,4 @@ "ProductId": 145 }, "xyz.openbmc_project.Inventory.Item.System": {} -} \ No newline at end of file +} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Chassis.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Chassis.json index 12c2e6084..ad10d87a4 100644 --- a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Chassis.json +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Chassis.json @@ -3,6 +3,7 @@ { "BindConnector": "System Fan connector 1", "Index": 0, + "MaxReading": 21000, "Name": "Fan 1", "Thresholds": [ { @@ -23,6 +24,7 @@ { "BindConnector": "System Fan connector 2", "Index": 2, + "MaxReading": 21000, "Name": "Fan 2", "Thresholds": [ { @@ -43,6 +45,7 @@ { "BindConnector": "System Fan connector 3", "Index": 4, + "MaxReading": 21000, "Name": "Fan 3", "Thresholds": [ { @@ -63,6 +66,7 @@ { "BindConnector": "System Fan connector 6", "Index": 10, + "MaxReading": 21000, "Name": "Fan 4", "Thresholds": [ { @@ -83,6 +87,7 @@ { "BindConnector": "System Fan connector 7", "Index": 12, + "MaxReading": 21000, "Name": "Fan 5", "Thresholds": [ { @@ -103,6 +108,7 @@ { "BindConnector": "System Fan connector 8", "Index": 14, + "MaxReading": 21000, "Name": "Fan 6", "Thresholds": [ { diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass index 26c895951..0fdad5b5c 100644 --- a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass @@ -242,6 +242,7 @@ EOF # $5 ... config ID # $6 ... default flag # $7 ... Hash type +# $8 ... DTB index fitimage_emit_section_config() { conf_csum="${7}" @@ -430,7 +431,7 @@ fitimage_assemble() { if [ -n "${DTBS}" ]; then i=1 for DTB in ${DTBS}; do - fitimage_emit_section_config ${1} "${kernelcount}" "${DTB}" "${ramdiskcount}" "${setupcount}" "`expr ${i} = ${dtbcount}`" "${hash_type}" + fitimage_emit_section_config ${1} "${kernelcount}" "${DTB}" "${ramdiskcount}" "${setupcount}" "`expr ${i} = ${dtbcount}`" "${hash_type}" "${i}" i=`expr ${i} + 1` done fi @@ -470,6 +471,43 @@ python do_generate_phosphor_manifest() { fd.write('HashType=RSA-SHA256\n') } +# Get HEAD git hash +def get_head_hash(codebase): + err = None + try: + cmd = 'git --work-tree {} --git-dir {}/.git {}'.format(codebase, codebase, "rev-parse HEAD") + ret, err = bb.process.run(cmd) + if err is not None: + ret += err + except bb.process.ExecutionError as e: + ret = '' + if e.stdout is not None: + ret += e.stdout + if e.stderr is not None: + ret += e.stderr + except Exception as e: + ret = str(e) + return ret.split("\n")[0] + +# Generate file 'RELEASE' +# It contains git hash info which is required by rest of release process (release note, for example) +python do_generate_release_metainfo() { + b = d.getVar('DEPLOY_DIR_IMAGE', True) + corebase = d.getVar('COREBASE', True) + intelbase = os.path.join(corebase, 'meta-openbmc-mods') + filename = os.path.join(b, "RELEASE") + version = do_get_version(d) + + with open(filename, 'w') as fd: + fd.write('VERSION_ID={}\n'.format(version.strip('"'))) + if os.path.exists(corebase): + obmc_hash = get_head_hash(corebase) + fd.write('COMMUNITY_HASH={}\n'.format(obmc_hash)) + if os.path.exists(intelbase): + intel_hash = get_head_hash(intelbase) + fd.write('INTEL_HASH={}\n'.format(intel_hash)) +} + def get_pubkey_type(d): return os.listdir(get_pubkey_basedir(d))[0] @@ -521,7 +559,9 @@ do_image_fitimage_rootfs() { tar -h -cvf "${DEPLOY_DIR_IMAGE}/${PN}-image-update-${MACHINE}-${DATETIME}.tar" MANIFEST image-u-boot image-runtime image-kernel image-rofs image-rwfs # make a symlink ln -sf "${PN}-image-update-${MACHINE}-${DATETIME}.tar" "${DEPLOY_DIR_IMAGE}/image-update-${MACHINE}" + ln -sf "${PN}-image-update-${MACHINE}-${DATETIME}.tar" "${DEPLOY_DIR_IMAGE}/OBMC-${@ do_get_version(d)}-oob.bin" ln -sf "image-update-${MACHINE}" "${DEPLOY_DIR_IMAGE}/image-update" + ln -sf "image-update-${MACHINE}" "${DEPLOY_DIR_IMAGE}/OBMC-${@ do_get_version(d)}-inband.bin" } do_image_fitimage_rootfs[vardepsexclude] = "DATETIME" @@ -530,3 +570,4 @@ do_image_fitimage_rootfs[depends] += " ${DEPS}" addtask do_image_fitimage_rootfs before do_generate_auto after do_image_complete addtask do_generate_phosphor_manifest before do_image_fitimage_rootfs after do_image_complete +addtask do_generate_release_metainfo before do_generate_phosphor_manifest after do_image_complete diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass index 3bbed738a..034f7ac70 100644 --- a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass @@ -47,7 +47,9 @@ IMAGE_INSTALL_append = " \ host-misc-comm-manager \ " -IMAGE_INSTALL_append = "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'pfr-manager', '', d)}" +IMAGE_INSTALL_append = " ${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'pfr-manager', '', d)}" + +IMAGE_INSTALL_append = " ${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'ncsi-monitor', '', d)}" # this package was flagged as a security risk IMAGE_INSTALL_remove += " lrzsz" diff --git a/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass index ad49eed82..ec5209029 100644 --- a/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass +++ b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass @@ -16,6 +16,14 @@ add_watchdog_confs() { continue fi + if [ "$service" = "systemd-timesyncd.service" ]; then + continue + fi + + if [ "$service" = "nv-sync.service" ]; then + continue + fi + if cat $D/lib/systemd/system/${service} | grep oneshot > /dev/null; then continue fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb index 1a1a83dce..ae6303668 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb @@ -13,7 +13,7 @@ LICENSE = "Proprietary" LIC_FILES_CHKSUM = "file://LICENSE;md5=43c09494f6b77f344027eea0a1c22830" SRC_URI = "git://github.com/Intel-BMC/crashdump;protocol=git" -SRCREV = "wht-0.9" +SRCREV = "wht-1.0" S = "${WORKDIR}/git" diff --git a/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend index 869cf5f2f..c95b2c92e 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend @@ -1,5 +1,5 @@ # Enable downstream autobump #SRC_URI = "git://github.com/openbmc/host-error-monitor" -SRCREV = "2fbb9eadeda2ae8a77ac53346b53f2d0a72f3e74" +SRCREV = "9a9bf9846cabf0ef4c7076776f70230e1a7b8b13" EXTRA_OECMAKE = "-DYOCTO=1" diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0001-Fix-cold-redundancy-is-not-runing-as-user-configurat.patch b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0001-Fix-cold-redundancy-is-not-runing-as-user-configurat.patch new file mode 100644 index 000000000..ae5f7b7bf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0001-Fix-cold-redundancy-is-not-runing-as-user-configurat.patch @@ -0,0 +1,121 @@ +From e45333a83822e8ccb8e3dbc1e547fbe45b8cf959 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang +Date: Wed, 22 Jul 2020 22:06:37 +0800 +Subject: [PATCH] Fix cold redundancy is not runing as user configuration. + +Cold redundancy service is not runing as user configuration. +1. Properties are not sync between settings server and daemon. +2. Wrong property is used to config cold redundancy enabling. + +Tested: +Cold redundancy is working as user config. + +Change-Id: Ia0b7aa6aff65be4d86daa82616eefaea575baf5e +Signed-off-by: Kuiying Wang +--- + src/oemcommands.cpp | 44 +++++++++----------------------------------- + 1 file changed, 9 insertions(+), 35 deletions(-) + +diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp +index 78f4f82..d2a1811 100644 +--- a/src/oemcommands.cpp ++++ b/src/oemcommands.cpp +@@ -2060,7 +2060,7 @@ int setCRConfig(ipmi::Context::ptr ctx, const std::string& property, + { + boost::system::error_code ec; + ctx->bus->yield_method_call( +- ctx->yield, ec, "xyz.openbmc_project.Settings", ++ ctx->yield, ec, "xyz.openbmc_project.PSURedundancy", + "/xyz/openbmc_project/control/power_supply_redundancy", + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value); +@@ -2074,10 +2074,10 @@ int setCRConfig(ipmi::Context::ptr ctx, const std::string& property, + return 0; + } + +-int getCRConfig(ipmi::Context::ptr ctx, const std::string& property, +- crConfigVariant& value, +- const std::string& service = "xyz.openbmc_project.Settings", +- std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) ++int getCRConfig( ++ ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value, ++ const std::string& service = "xyz.openbmc_project.PSURedundancy", ++ std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) + { + boost::system::error_code ec; + value = ctx->bus->yield_method_call( +@@ -2172,25 +2172,6 @@ ipmi::RspType ipmiOEMSetCRConfig(ipmi::Context::ptr ctx, + { + switch (static_cast(parameter)) + { +- case crParameter::crFeature: +- { +- uint8_t param1; +- if (payload.unpack(param1) || !payload.fullyUnpacked()) +- { +- return ipmi::responseReqDataLenInvalid(); +- } +- // ColdRedundancy Enable can only be true or flase +- if (param1 > 1) +- { +- return ipmi::responseInvalidFieldRequest(); +- } +- if (setCRConfig(ctx, "ColdRedundancyEnabled", +- static_cast(param1))) +- { +- return ipmi::responseResponseError(); +- } +- break; +- } + case crParameter::rotationFeature: + { + uint8_t param1; +@@ -2301,13 +2282,6 @@ ipmi::RspType ipmiOEMSetCRConfig(ipmi::Context::ptr ctx, + } + } + +- // TODO Halfwidth needs to set SetInProgress +- if (setCRConfig(ctx, "ColdRedundancyStatus", +- std::string("xyz.openbmc_project.Control." +- "PowerSupplyRedundancy.Status.completed"))) +- { +- return ipmi::responseResponseError(); +- } + return ipmi::responseSuccess(crSetCompleted); + } + +@@ -2338,11 +2312,11 @@ ipmi::RspType>> + { + case server::PowerSupplyRedundancy::Status::inProgress: + return ipmi::responseSuccess(parameter, +- static_cast(0)); ++ static_cast(1)); + + case server::PowerSupplyRedundancy::Status::completed: + return ipmi::responseSuccess(parameter, +- static_cast(1)); ++ static_cast(0)); + default: + phosphor::logging::log( + "Error to get valid status"); +@@ -2351,7 +2325,7 @@ ipmi::RspType>> + } + case crParameter::crFeature: + { +- if (getCRConfig(ctx, "ColdRedundancyEnabled", value)) ++ if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value)) + { + return ipmi::responseResponseError(); + } +@@ -2359,7 +2333,7 @@ ipmi::RspType>> + if (!pResponse) + { + phosphor::logging::log( +- "Error to get ColdRedundancyEnable property"); ++ "Error to get PowerSupplyRedundancyEnabled property"); + return ipmi::responseResponseError(); + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0002-GetFwVersionInfo-Fix-for-Firmware-aux-version.patch b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0002-GetFwVersionInfo-Fix-for-Firmware-aux-version.patch new file mode 100644 index 000000000..514f2dde7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0002-GetFwVersionInfo-Fix-for-Firmware-aux-version.patch @@ -0,0 +1,120 @@ +From 52a292b8dd1b5705a6e0ce8e260d3b960b2b6edb Mon Sep 17 00:00:00 2001 +From: srikanta mondal +Date: Mon, 27 Jul 2020 23:49:14 +0000 +Subject: [PATCH] GetFwVersionInfo: Fix for Firmware aux version + +Issue: Get Version Information return incorrect Firmware AUX version + +FIX: Firmware aux version was parsing incorrectly. Do the parsing by + correct regex pattern of BMC version. + +Tested: +Verified using ipmitool raw commands +Before fix: +Command: ipmitool raw 0x08 0x20 // Get version Information +Response: 01 02 00 70 01 00 00 00 00 00 00 00 00 00 00 00 + +After fix: +Command: ipmitool raw 0x08 0x20 // Get version Information +Response: 02 01 00 74 0a 8a 37 78 00 00 00 00 00 00 00 00 + 02 00 70 01 00 00 00 00 00 00 00 00 00 00 00 + +Signed-off-by: srikanta mondal +Change-Id: I7c2baf8a0da15e3ca4db5d6f9d6de7bf739aa755 +--- + src/firmware-update.cpp | 56 +++++++++++++++++++++++++---------------- + 1 file changed, 35 insertions(+), 21 deletions(-) + +diff --git a/src/firmware-update.cpp b/src/firmware-update.cpp +index 8c3cc94..ec1d14a 100644 +--- a/src/firmware-update.cpp ++++ b/src/firmware-update.cpp +@@ -1,3 +1,4 @@ ++#include + #include + #include + #include +@@ -6,6 +7,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -836,26 +838,44 @@ ipmi::RspType> ipmiGetFwVersionInfo() + continue; + } + +- // BMC Version format: .-- +- std::vector splitVer; +- boost::split(splitVer, verStr, boost::is_any_of(".-")); +- if (splitVer.size() < 3) +- { +- phosphor::logging::log( +- "Invalid Version format.", +- phosphor::logging::entry("Version=%s", verStr.c_str()), +- phosphor::logging::entry("PATH=%s", fwDev.second)); +- continue; +- } +- + uint8_t majorNum = 0; + uint8_t minorNum = 0; + uint32_t buildNum = 0; + try + { +- majorNum = std::stoul(splitVer[0], nullptr, 16); +- minorNum = std::stoul(splitVer[1], nullptr, 16); +- buildNum = std::stoul(splitVer[2], nullptr, 16); ++ std::optional rev = ++ ipmi::convertIntelVersion(verStr); ++ if (rev.has_value()) ++ { ++ ipmi::MetaRevision revision = rev.value(); ++ majorNum = revision.major % 10 + (revision.major / 10) * 16; ++ minorNum = (revision.minor > 99 ? 99 : revision.minor); ++ minorNum = minorNum % 10 + (minorNum / 10) * 16; ++ uint32_t hash = std::stoul(revision.metaHash, 0, 16); ++ hash = bswap_32(hash); ++ buildNum = (revision.buildNo & 0xFF) + (hash & 0xFFFFFF00); ++ } ++ else ++ { ++ std::vector splitVer; ++ boost::split(splitVer, verStr, boost::is_any_of(".-")); ++ if (splitVer.size() < 3) ++ { ++ phosphor::logging::log( ++ "Invalid Version format.", ++ phosphor::logging::entry("Version=%s", verStr.c_str()), ++ phosphor::logging::entry("PATH=%s", fwDev.second)); ++ continue; ++ } ++ majorNum = std::stoul(splitVer[0], nullptr, 16); ++ minorNum = std::stoul(splitVer[1], nullptr, 16); ++ buildNum = std::stoul(splitVer[2], nullptr, 16); ++ } ++ // Build Timestamp - Not supported. ++ // Update Timestamp - TODO: Need to check with CPLD team. ++ fwVerInfoList.emplace_back( ++ fwVersionInfoType(static_cast(fwDev.first), majorNum, ++ minorNum, buildNum, 0, 0)); + } + catch (const std::exception& e) + { +@@ -864,12 +884,6 @@ ipmi::RspType> ipmiGetFwVersionInfo() + phosphor::logging::entry("ERROR=%s", e.what())); + continue; + } +- +- // Build Timestamp - Not supported. +- // Update Timestamp - TODO: Need to check with CPLD team. +- fwVerInfoList.emplace_back( +- fwVersionInfoType(static_cast(fwDev.first), majorNum, +- minorNum, buildNum, 0, 0)); + } + + return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0003-storagecommands-Fix-for-GetFruAreaInfo-command.patch b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0003-storagecommands-Fix-for-GetFruAreaInfo-command.patch new file mode 100644 index 000000000..32a170d90 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0003-storagecommands-Fix-for-GetFruAreaInfo-command.patch @@ -0,0 +1,48 @@ +From 1e2ab0613dde7d8051052eecf6f5f2381e91ce87 Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala +Date: Mon, 3 Aug 2020 16:57:00 +0000 +Subject: [PATCH] storagecommands: Fix for GetFruAreaInfo command + +Issue: GetFruAreaInfo command is giving incorrect response for Invalid +FRU Device ID's. + +Fix: Add check for invalid FRU Device ID's to return completion code as +0xCB. + +Tested: +Verified using ipmitool raw commands. +Case 1: Valid FRU Device ID: +Command: ipmitool raw 0x0a 0x10 0xce //Get fru Area info +Response: a9 00 00 +Case 2: Invalid FRU Device ID: +Command: ipmitool raw 0x0a 0x10 0x01 //Get fru Area info +Response: Unable to send RAW command (channel=0x0 netfn=0xa lun=0x0 + cmd=0x10 rsp=0xcb): Requested sensor, data, or record not + found + +Signed-off-by: Jayaprakash Mutyala +Change-Id: I8e3416beff40c133804af9e913d83c2372784439 +--- + src/storagecommands.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp +index f1b98e0..bd43a34 100644 +--- a/src/storagecommands.cpp ++++ b/src/storagecommands.cpp +@@ -538,7 +538,11 @@ ipmi::RspType(GetFRUAreaAccessType::byte); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0004-firmware-update-Add-Support-to-get-fwSecurityVer.patch b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0004-firmware-update-Add-Support-to-get-fwSecurityVer.patch new file mode 100644 index 000000000..20e94b79d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem/0004-firmware-update-Add-Support-to-get-fwSecurityVer.patch @@ -0,0 +1,111 @@ +From a8dd197a4b729c10d09c55ebf26ed7d0796fd261 Mon Sep 17 00:00:00 2001 +From: Punith Nadur Basavarajaiah +Date: Wed, 19 Aug 2020 18:05:44 +0000 +Subject: [PATCH] firmware-update:Add Support to get fwSecurityVer + +Add support to read BKC and SVN version for BMC Active and Recovery +image. + +Tested: +Command : ipmitool raw 0x08 0x21 //get firmware security version +Response: 02 01 01 01 02 01 01 + +Signed-off-by: Punith Nadur Basavarajaiah +Change-Id: I25a801fe00fef3c4c65b57aacb59089be1705d58 +--- + src/firmware-update.cpp | 70 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 64 insertions(+), 6 deletions(-) + +diff --git a/src/firmware-update.cpp b/src/firmware-update.cpp +index ec1d14a..d27b8c6 100644 +--- a/src/firmware-update.cpp ++++ b/src/firmware-update.cpp +@@ -72,6 +72,13 @@ static inline auto responseNotSupportedInPresentState() + } + } // namespace ipmi + ++static constexpr size_t imageCount = 2; ++std::array, imageCount> imgFwSecurityVersion = { ++ (0, 0), (0, 0)}; ++static constexpr size_t svnActiveVerOffsetInPfm = 0x404; ++static constexpr size_t bkcActiveVerOffsetInPfm = 0x405; ++static constexpr size_t svnRecoveryVerOffsetInPfm = 0x804; ++static constexpr size_t bkcRecoveryVerOffsetInPfm = 0x805; + static constexpr const char* bmcStateIntf = "xyz.openbmc_project.State.BMC"; + static constexpr const char* bmcStatePath = "/xyz/openbmc_project/state/bmc0"; + static constexpr const char* bmcStateReady = +@@ -888,14 +895,65 @@ ipmi::RspType> ipmiGetFwVersionInfo() + + return ipmi::responseSuccess(fwVerInfoList.size(), fwVerInfoList); + } +-using fwSecurityVersionInfoType = std::tuple; // SVN Version +-ipmi::RspType> ++ ++std::array getSecurityVersionInfo(const char* mtdDevBuf, ++ size_t svnVerOffsetInPfm, ++ size_t bkcVerOffsetInPfm) ++{ ++ constexpr size_t bufLength = 1; ++ std::array fwSecurityVersionBuf = {0}, temp; ++ constexpr uint8_t svnIndexValue = 0x00; ++ constexpr uint8_t bkcIndexValue = 0x01; ++ constexpr uint8_t tempIndexValue = 0x00; ++ try ++ { ++ SPIDev spiDev(mtdDevBuf); ++ spiDev.spiReadData(svnVerOffsetInPfm, bufLength, temp.data()); ++ fwSecurityVersionBuf.at(svnIndexValue) = temp.at(tempIndexValue); ++ spiDev.spiReadData(bkcVerOffsetInPfm, bufLength, temp.data()); ++ fwSecurityVersionBuf.at(bkcIndexValue) = temp.at(tempIndexValue); ++ } ++ catch (const std::exception& e) ++ { ++ phosphor::logging::log( ++ "Exception caught in getSecurityVersionInfo", ++ phosphor::logging::entry("MSG=%s", e.what())); ++ fwSecurityVersionBuf = {0, 0}; ++ } ++ ++ return fwSecurityVersionBuf; ++} ++ ++ipmi::RspType< ++ uint8_t, // device ID ++ uint8_t, // Active Image Value ++ std::array, // Security version for Active Image ++ uint8_t, // recovery Image Value ++ std::array> // Security version for Recovery Image + ipmiGetFwSecurityVersionInfo() + { +- // TODO: Need to add support. +- return ipmi::responseInvalidCommand(); ++ static bool cacheFlag = false; ++ constexpr std::array mtdDevBuf = { ++ bmcActivePfmMTDDev, bmcRecoveryImgMTDDev}; ++ ++ // To avoid multiple reading from SPI device ++ if (!cacheFlag) ++ { ++ imgFwSecurityVersion[0] = getSecurityVersionInfo( ++ mtdDevBuf[0], svnActiveVerOffsetInPfm, bkcActiveVerOffsetInPfm); ++ imgFwSecurityVersion[1] = getSecurityVersionInfo( ++ mtdDevBuf[1], svnRecoveryVerOffsetInPfm, bkcRecoveryVerOffsetInPfm); ++ cacheFlag = true; ++ } ++ ++ constexpr uint8_t ActivePfmMTDDev = 0x00; ++ constexpr uint8_t RecoveryImgMTDDev = 0x01; ++ ++ return ipmi::responseSuccess( ++ imageCount, static_cast(FWDeviceIDTag::bmcActiveImage), ++ imgFwSecurityVersion[ActivePfmMTDDev], ++ static_cast(FWDeviceIDTag::bmcRecoveryImage), ++ imgFwSecurityVersion[RecoveryImgMTDDev]); + } + + ipmi::RspType, +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend index cd2011b4a..a7486376f 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend @@ -3,3 +3,12 @@ EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsec EXTRA_OECMAKE += "-DUSING_ENTITY_MANAGER_DECORATORS=OFF" SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git" SRCREV = "04a38ed10db3a0203aa7804bfea6fbd69dafdde8" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +PROJECT_SRC_DIR := "${THISDIR}/${PN}" + +SRC_URI += "file://0001-Fix-cold-redundancy-is-not-runing-as-user-configurat.patch \ + file://0002-GetFwVersionInfo-Fix-for-Firmware-aux-version.patch \ + file://0003-storagecommands-Fix-for-GetFruAreaInfo-command.patch \ + file://0004-firmware-update-Add-Support-to-get-fwSecurityVer.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service index bad3329d3..4595541c6 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service @@ -2,10 +2,8 @@ Description=Overlay sync to NV storage [Service] -# Run rsync periodically to sync the overlay to NV storage -ExecStart=bash -c 'while true; do rsync -a --delete /tmp/.overlay/ /tmp/.rwfs/.overlay; sync /tmp/.rwfs/.overlay; sleep 10; done' -# On shutdown, archive the bash history so we don't lose it and run one last sync -ExecStop=bash -c 'history -a; rsync -a --delete /tmp/.overlay/ /tmp/.rwfs/.overlay; sync /tmp/.rwfs/.overlay; sleep 5' +# Run a job to periodically sync the overlay to NV storage +ExecStart=/usr/bin/nv-syncd # Due to sync delay stopping this service will take more than default 10 seconds TimeoutStopSec=20 diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-syncd b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-syncd new file mode 100644 index 000000000..e2bb4bb0c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-syncd @@ -0,0 +1,32 @@ +#!/bin/bash + +NVMP=/tmp/.rwfs +SOMP=/var/sofs + +do_sync() { + rsync -a --delete /tmp/.overlay/ $NVMP/.overlay + sync $NVMP/.overlay +} + +stop_nv() { + history -a + do_sync + mount -o remount,ro $NVMP + mount -o remount,ro $SOMP + exit 0 +} + +# register cleanup function +trap stop_nv SIGINT +trap stop_nv SIGTERM +trap stop_nv EXIT + +# make sure the mount points are RW +mount -o remount,rw $NVMP +mount -o remount,rw $SOMP + +# Run rsync periodically to sync the overlay to NV storage +while true; do + do_sync + sleep 10 +done diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb index 0ee70e880..420fc258b 100644 --- a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb @@ -3,6 +3,7 @@ DESCRIPTION = "Script to periodically sync the overlay to NV storage" S = "${WORKDIR}" SRC_URI = "file://nv-sync.service \ + file://nv-syncd \ " LICENSE = "Apache-2.0" @@ -10,11 +11,15 @@ LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fe inherit systemd +RDEPENDS_${PN} += "bash" + FILES_${PN} += "${systemd_system_unitdir}/nv-sync.service" do_install() { install -d ${D}${systemd_system_unitdir} install -m 0644 ${WORKDIR}/nv-sync.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/nv-syncd ${D}${bindir}/nv-syncd } SYSTEMD_SERVICE_${PN} += " nv-sync.service" diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch new file mode 100644 index 000000000..5293f3f27 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch @@ -0,0 +1,295 @@ +From 68885eb4d056b8343c567c48ece7e875feb28fc0 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Thu, 30 Jul 2020 00:29:19 -0700 +Subject: [PATCH] Refine HID report writing logic + +Blocking write on the keyboard HID device causes screen freezing +during turning off the host power. To fix this issue, this commit +refines the logic using non-blocking write. As a side effect, +non-blocking write introduces event dropping when kernel HID driver +returns -EAGAIN when the driver is in busy state so this commit also +adds retry logic to cover the case. + +Tested: Didn't see the screen freezing issue. + +Change-Id: Ibd95f567c49f448cd053948c14c006de17c52420 +Signed-off-by: Jae Hyun Yoo +--- + ikvm_input.cpp | 106 ++++++++++++++++++++++++++++++++---------------- + ikvm_input.hpp | 13 +++--- + ikvm_server.cpp | 2 - + 3 files changed, 79 insertions(+), 42 deletions(-) + +diff --git a/ikvm_input.cpp b/ikvm_input.cpp +index c4cce5088461..480db3c094bc 100644 +--- a/ikvm_input.cpp ++++ b/ikvm_input.cpp +@@ -25,9 +25,8 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::File::Error; + + Input::Input(const std::string& kbdPath, const std::string& ptrPath) : +- sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1), +- keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath), +- pointerPath(ptrPath) ++ keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0}, ++ keyboardPath(kbdPath), pointerPath(ptrPath) + { + hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit); + hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app); +@@ -79,7 +78,8 @@ void Input::connect() + + if (!keyboardPath.empty()) + { +- keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC); ++ keyboardFd = open(keyboardPath.c_str(), ++ O_RDWR | O_CLOEXEC | O_NONBLOCK); + if (keyboardFd < 0) + { + log("Failed to open input device", +@@ -135,6 +135,12 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl) + { + Server::ClientData* cd = (Server::ClientData*)cl->clientData; + Input* input = cd->input; ++ bool sendKeyboard = false; ++ ++ if (input->keyboardFd < 0) ++ { ++ return; ++ } + + if (down) + { +@@ -150,7 +156,7 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl) + { + input->keyboardReport[i] = sc; + input->keysDown.insert(std::make_pair(key, i)); +- input->sendKeyboard = true; ++ sendKeyboard = true; + break; + } + } +@@ -163,7 +169,7 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl) + if (mod) + { + input->keyboardReport[0] |= mod; +- input->sendKeyboard = true; ++ sendKeyboard = true; + } + } + } +@@ -175,7 +181,7 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl) + { + input->keyboardReport[it->second] = 0; + input->keysDown.erase(it); +- input->sendKeyboard = true; ++ sendKeyboard = true; + } + else + { +@@ -184,10 +190,15 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl) + if (mod) + { + input->keyboardReport[0] &= ~mod; +- input->sendKeyboard = true; ++ sendKeyboard = true; + } + } + } ++ ++ if (sendKeyboard) ++ { ++ input->writeKeyboard(input->keyboardReport); ++ } + } + + void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl) +@@ -197,6 +208,11 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl) + Server* server = (Server*)cl->screen->screenData; + const Video& video = server->getVideo(); + ++ if (input->pointerFd < 0) ++ { ++ return; ++ } ++ + input->pointerReport[0] = ((buttonMask & 0x4) >> 1) | + ((buttonMask & 0x2) << 1) | (buttonMask & 0x1); + +@@ -214,8 +230,8 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl) + memcpy(&input->pointerReport[3], &yy, 2); + } + +- input->sendPointer = true; + rfbDefaultPtrAddEvent(buttonMask, x, y, cl); ++ input->writePointer(input->pointerReport); + } + + void Input::sendWakeupPacket() +@@ -249,23 +265,6 @@ void Input::sendWakeupPacket() + } + } + +-void Input::sendReport() +-{ +- if (sendKeyboard && keyboardFd >= 0) +- { +- writeKeyboard(keyboardReport); +- +- sendKeyboard = false; +- } +- +- if (sendPointer && pointerFd >= 0) +- { +- writePointer(pointerReport); +- +- sendPointer = false; +- } +-} +- + uint8_t Input::keyToMod(rfbKeySym key) + { + uint8_t mod = 0; +@@ -489,14 +488,35 @@ uint8_t Input::keyToScancode(rfbKeySym key) + + bool Input::writeKeyboard(const uint8_t *report) + { +- if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH) ++ std::unique_lock lk(keyMutex); ++ uint retryCount = HID_REPORT_RETRY_MAX; ++ ++ while (retryCount > 0) + { +- if (errno != ESHUTDOWN && errno != EAGAIN) ++ if (write(keyboardFd, report, KEY_REPORT_LENGTH) == KEY_REPORT_LENGTH) + { +- log("Failed to write keyboard report", +- entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ ++ if (errno != EAGAIN) ++ { ++ if (errno != ESHUTDOWN) ++ { ++ log("Failed to write keyboard report", ++ entry("ERROR=%s", strerror(errno))); ++ } ++ ++ break; + } + ++ lk.unlock(); ++ std::this_thread::sleep_for(std::chrono::milliseconds(10)); ++ lk.lock(); ++ retryCount--; ++ } ++ ++ if (!retryCount || errno) ++ { + return false; + } + +@@ -505,13 +525,31 @@ bool Input::writeKeyboard(const uint8_t *report) + + void Input::writePointer(const uint8_t *report) + { +- if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH) ++ std::unique_lock lk(ptrMutex); ++ uint retryCount = HID_REPORT_RETRY_MAX; ++ ++ while (retryCount > 0) + { +- if (errno != ESHUTDOWN && errno != EAGAIN) ++ if (write(pointerFd, report, PTR_REPORT_LENGTH) == PTR_REPORT_LENGTH) + { +- log("Failed to write pointer report", +- entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ ++ if (errno != EAGAIN) ++ { ++ if (errno != ESHUTDOWN) ++ { ++ log("Failed to write pointer report", ++ entry("ERROR=%s", strerror(errno))); ++ } ++ ++ break; + } ++ ++ lk.unlock(); ++ std::this_thread::sleep_for(std::chrono::milliseconds(10)); ++ lk.lock(); ++ retryCount--; + } + } + +diff --git a/ikvm_input.hpp b/ikvm_input.hpp +index aae7cefbef6e..558251d673cc 100644 +--- a/ikvm_input.hpp ++++ b/ikvm_input.hpp +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + + namespace ikvm +@@ -56,8 +57,6 @@ class Input + + /* @brief Sends a wakeup data packet to the USB input device */ + void sendWakeupPacket(); +- /* @brief Sends an HID report to the USB input device */ +- void sendReport(); + + private: + static constexpr int NUM_MODIFIER_BITS = 4; +@@ -84,6 +83,8 @@ class Input + /* @brief Path to the USB virtual hub */ + static constexpr const char* usbVirtualHubPath = + "/sys/bus/platform/devices/1e6a0000.usb-vhub"; ++ /* @brief Retry limit for writing an HID report */ ++ static constexpr int HID_REPORT_RETRY_MAX = 5; + /* + * @brief Translates a RFB-specific key code to HID modifier bit + * +@@ -100,10 +101,6 @@ class Input + bool writeKeyboard(const uint8_t *report); + void writePointer(const uint8_t *report); + +- /* @brief Indicates whether or not to send a keyboard report */ +- bool sendKeyboard; +- /* @brief Indicates whether or not to send a pointer report */ +- bool sendPointer; + /* @brief File descriptor for the USB keyboard device */ + int keyboardFd; + /* @brief File descriptor for the USB mouse device */ +@@ -123,6 +120,10 @@ class Input + std::map keysDown; + /* @brief Handle of the HID gadget UDC */ + std::ofstream hidUdcStream; ++ /* @brief Mutex for sending keyboard reports */ ++ std::mutex keyMutex; ++ /* @brief Mutex for sending pointer reports */ ++ std::mutex ptrMutex; + }; + + } // namespace ikvm +diff --git a/ikvm_server.cpp b/ikvm_server.cpp +index 0736d1f55f73..7be99e4379d1 100644 +--- a/ikvm_server.cpp ++++ b/ikvm_server.cpp +@@ -79,8 +79,6 @@ void Server::run() + + if (server->clientHead) + { +- input.sendReport(); +- + frameCounter++; + if (pendingResize && frameCounter > video.getFrameRate()) + { +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend index baa93bc04..9ea9e1a4e 100644 --- a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend @@ -6,4 +6,5 @@ SRCREV = "861337e8ec92767c4c88237ec5db494a2a67fa8d" SRC_URI += " \ file://0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch \ file://0004-Connect-HID-gadget-device-dynamically.patch \ + file://0005-Refine-HID-report-writing-logic.patch \ " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend index c6dd34bb1..fa5bc79af 100644 --- a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend @@ -1,5 +1,5 @@ # Enable downstream autobump SRC_URI = "git://github.com/openbmc/pfr-manager" -SRCREV = "53b8700fd18873cffe7ee70b2306e7c66b2f7037" +SRCREV = "068c66db7d099b179e5588b156ba7444a5b68819" DEPENDS += " libgpiod \ " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service index 531b5d86e..c1d0f602f 100644 --- a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service +++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service @@ -1,7 +1,6 @@ [Unit] Description=Re-enable NICs mistakenly disabled by earlier BMC firmware Wants=multi-user.target -After=multi-user.target [Service] Type=oneshot diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0113-hwmon-peci-PCS-utils.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0113-hwmon-peci-PCS-utils.patch new file mode 100644 index 000000000..6f6aab922 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0113-hwmon-peci-PCS-utils.patch @@ -0,0 +1,706 @@ +From 44842b3fc1ceb7da68171b6b6c2f24a3b70405ed Mon Sep 17 00:00:00 2001 +From: Zbigniew Lukwinski +Date: Tue, 16 Jun 2020 11:34:28 +0200 +Subject: [PATCH] hwmon: peci: PCS utils + +1. Helpers for reading/writing PCS registers added. +2. PECI sensor configuration structure definition and helpers added. +3. New PECI PCS index and parameters definitions added. + +Tested: + * on WilsonCity platform + * hwmon/peci modules work as before the change + +Signed-off-by: Zbigniew Lukwinski +--- + drivers/hwmon/peci-cpupower.c | 4 +- + drivers/hwmon/peci-hwmon.h | 557 +++++++++++++++++++++++++++++++++- + include/linux/mfd/intel-peci-client.h | 34 ++- + include/uapi/linux/peci-ioctl.h | 5 +- + 4 files changed, 592 insertions(+), 8 deletions(-) + +diff --git a/drivers/hwmon/peci-cpupower.c b/drivers/hwmon/peci-cpupower.c +index 6907696..a3a8fc1 100644 +--- a/drivers/hwmon/peci-cpupower.c ++++ b/drivers/hwmon/peci-cpupower.c +@@ -49,7 +49,7 @@ static int get_average_power(struct peci_cpupower *priv) + + ret = peci_client_read_package_config(priv->mgr, + PECI_MBX_INDEX_TDP_UNITS, +- PECI_PKG_ID_PKG_ENERGY_STATUS, ++ PECI_PKG_ID_CPU_PACKAGE, + pkg_cfg); + + u32 power_unit = ((le32_to_cpup((__le32 *)pkg_cfg)) & 0x1f00) >> 8; +@@ -59,7 +59,7 @@ static int get_average_power(struct peci_cpupower *priv) + + ret = peci_client_read_package_config(priv->mgr, + PECI_MBX_INDEX_ENERGY_COUNTER, +- PECI_PKG_ID_PKG_ENERGY_STATUS, ++ PECI_PKG_ID_CPU_PACKAGE, + pkg_cfg); + if (!ret) { + u32 energy_cnt = le32_to_cpup((__le32 *)pkg_cfg); +diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h +index 4d78c52..b8949ae 100644 +--- a/drivers/hwmon/peci-hwmon.h ++++ b/drivers/hwmon/peci-hwmon.h +@@ -1,20 +1,23 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018-2019 Intel Corporation */ ++/* Copyright (c) 2018-2020 Intel Corporation */ + + #ifndef __PECI_HWMON_H + #define __PECI_HWMON_H + + #include ++#include + + #define TEMP_TYPE_PECI 6 /* Sensor type 6: Intel PECI */ +-#define UPDATE_INTERVAL HZ ++#define UPDATE_INTERVAL_DEFAULT HZ ++#define UPDATE_INTERVAL_100MS (HZ / 10) ++#define UPDATE_INTERVAL_10S (HZ * 10) + + #define PECI_HWMON_LABEL_STR_LEN 10 + + /** + * struct peci_sensor_data - PECI sensor information + * @valid: flag to indicate the sensor value is valid +- * @value: sensor value in millidegree Celsius ++ * @value: sensor value in milli units + * @last_updated: time of the last update in jiffies + */ + struct peci_sensor_data { +@@ -32,7 +35,24 @@ struct peci_sensor_data { + static inline bool peci_sensor_need_update(struct peci_sensor_data *sensor) + { + return !sensor->valid || +- time_after(jiffies, sensor->last_updated + UPDATE_INTERVAL); ++ time_after(jiffies, sensor->last_updated + ++ UPDATE_INTERVAL_DEFAULT); ++} ++ ++/** ++ * peci_sensor_need_update_with_time - check whether sensor update is needed ++ * or not ++ * @sensor: pointer to sensor data struct ++ * @update_interval: update interval to check ++ * ++ * Return: true if update is needed, false if not. ++ */ ++static inline bool ++peci_sensor_need_update_with_time(struct peci_sensor_data *sensor, ++ ulong update_interval) ++{ ++ return !sensor->valid || ++ time_after(jiffies, sensor->last_updated + update_interval); + } + + /** +@@ -45,4 +65,533 @@ static inline void peci_sensor_mark_updated(struct peci_sensor_data *sensor) + sensor->last_updated = jiffies; + } + ++/** ++ * peci_sensor_mark_updated_with_time - mark the sensor is updated ++ * @sensor: pointer to sensor data struct ++ * @jif: jiffies value to update with ++ */ ++static inline void ++peci_sensor_mark_updated_with_time(struct peci_sensor_data *sensor, ++ ulong jif) ++{ ++ sensor->valid = 1; ++ sensor->last_updated = jif; ++} ++ ++/** ++ * struct peci_sensor_conf - PECI sensor information ++ * @attribute: Sensor attribute ++ * @config: Part of channel parameters brought by single sensor ++ * @update_interval: time in jiffies needs to elapse to read sensor again ++ * @read: Read callback for data attributes. Mandatory if readable ++ * data attributes are present. ++ * Parameters are: ++ * @module_ctx: Pointer peci module context ++ * @sensor_conf: Pointer to sensor configuration object ++ * @sensor_data: Pointer to sensor data object ++ * @val: Pointer to returned value ++ * The function returns 0 on success or a negative error number. ++ * @write: Write callback for data attributes. Mandatory if writeable ++ * data attributes are present. ++ * Parameters are: ++ * @module_ctx: Pointer peci module context ++ * @sensor_conf: Pointer to sensor configuration object ++ * @sensor_data: Pointer to sensor data object ++ * @val: Value to write ++ * The function returns 0 on success or a negative error number. ++ */ ++struct peci_sensor_conf { ++ const s32 attribute; ++ const u32 config; ++ const ulong update_interval; ++ ++ int (*const read)(void *priv, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val); ++ int (*const write)(void *priv, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 val); ++}; ++ ++/** ++ * peci_sensor_get_config - get peci sensor configuration for provided channel ++ * @sensors: Sensors list ++ * @sensor_count: Sensors count ++ * ++ * Return: sensor configuration ++ */ ++static inline u32 peci_sensor_get_config(struct peci_sensor_conf sensors[], ++ u8 sensor_count) ++{ ++ u32 config = 0u; ++ int iter; ++ ++ for (iter = 0; iter < sensor_count; ++iter) ++ config |= sensors[iter].config; ++ ++ return config; ++} ++ ++/** ++ * peci_sensor_get_ctx - get peci sensor context - both configuration and data ++ * @attribute: Sensor attribute ++ * @sensor_conf_list: Sensors configuration object list ++ * @sensor_conf: Sensor configuration object found ++ * @sensor_data_list: Sensors data object list, maybe NULL in case there is no ++ * need to find sensor data object ++ * @sensor_data: Sensor data object found, maybe NULL in case there is no need ++ * to find sensor data object ++ * @sensor_count: Sensor count ++ * ++ * Return: 0 on success or -EOPNOTSUPP in case sensor attribute not found ++ */ ++static inline int peci_sensor_get_ctx(s32 attribute, ++ struct peci_sensor_conf ++ sensor_conf_list[], ++ struct peci_sensor_conf **sensor_conf, ++ struct peci_sensor_data ++ sensor_data_list[], ++ struct peci_sensor_data **sensor_data, ++ const u8 sensor_count) ++{ ++ int iter; ++ ++ for (iter = 0; iter < sensor_count; ++iter) { ++ if (attribute == sensor_conf_list[iter].attribute) { ++ *sensor_conf = &sensor_conf_list[iter]; ++ if (sensor_data_list && sensor_data) ++ *sensor_data = &sensor_data_list[iter]; ++ return 0; ++ } ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++/* Value for the most common parameter used for PCS accessing */ ++#define PECI_PCS_PARAM_ZERO 0x0000u ++ ++#define PECI_PCS_REGISTER_SIZE 4u /* PCS register size in bytes */ ++ ++/* PPL1 value to PPL2 value conversation macro */ ++#define PECI_PCS_PPL1_TO_PPL2(ppl1_value) ((((u32)(ppl1_value)) * 12uL) / 10uL) ++ ++#define PECI_PCS_PPL1_TIME_WINDOW 250 /* PPL1 Time Window value in ms */ ++ ++#define PECI_PCS_PPL2_TIME_WINDOW 10 /* PPL2 Time Window value in ms */ ++ ++/** ++ * union peci_pkg_power_sku_unit - PECI Package Power Unit PCS ++ * This register coresponds to the MSR@606h - MSR_RAPL_POWER_UNIT ++ * Accessing over PECI: PCS=0x1E, Parameter=0x0000 ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @pwr_unit: Bits [3:0] - Power Unit ++ * @rsvd0: Bits [7:4] ++ * @eng_unit: Bits [12:8] - Energy Unit ++ * @rsvd1: Bits [15:13] ++ * @tim_unit: Bits [19:16] - Time Unit ++ * @rsvd2: Bits [31:20] ++ */ ++union peci_pkg_power_sku_unit { ++ u32 value; ++ struct { ++ u32 pwr_unit : 4; ++ u32 rsvd0 : 4; ++ u32 eng_unit : 5; ++ u32 rsvd1 : 3; ++ u32 tim_unit : 4; ++ u32 rsvd2 : 12; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_pkg_power_sku_unit) == PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * union peci_package_power_info_low - Platform and Package Power SKU (Low) PCS ++ * This PCS coresponds to the MSR@614h - PACKAGE_POWER_SKU, bits [31:0] ++ * Accessing over PECI: PCS=0x1C, parameter=0x00FF ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @pkg_tdp: Bits [14:0] - TDP Package Power ++ * @rsvd0: Bits [15:15] ++ * @pkg_min_pwr: Bits [30:16] - Minimal Package Power ++ * @rsvd1: Bits [31:31] ++ */ ++union peci_package_power_info_low { ++ u32 value; ++ struct { ++ u32 pkg_tdp : 15; ++ u32 rsvd0 : 1; ++ u32 pkg_min_pwr : 15; ++ u32 rsvd1 : 1; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_package_power_info_low) == ++ PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * union peci_package_power_limit_high - Package Power Limit 2 PCS ++ * This PCS coresponds to the MSR@610h - PACKAGE_RAPL_LIMIT, bits [63:32] ++ * Accessing over PECI: PCS=0x1B, Parameter=0x0000 ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @pwr_lim_2: Bits [14:0] - Power Limit 2 ++ * @pwr_lim_2_en: Bits [15:15] - Power Limit 2 Enable ++ * @pwr_clmp_lim_2:Bits [16:16] - Package Clamping Limitation 2 ++ * @pwr_lim_2_time:Bits [23:17] - Power Limit 2 Time Window ++ * @rsvd0: Bits [31:24] ++ */ ++union peci_package_power_limit_high { ++ u32 value; ++ struct { ++ u32 pwr_lim_2 : 15; ++ u32 pwr_lim_2_en : 1; ++ u32 pwr_clmp_lim_2 : 1; ++ u32 pwr_lim_2_time : 7; ++ u32 rsvd0 : 8; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_package_power_limit_high) == ++ PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * union peci_package_power_limit_low - Package Power Limit 1 PCS ++ * This PCS coresponds to the MSR@610h - PACKAGE_RAPL_LIMIT, bits [31:0] ++ * Accessing over PECI: PCS=0x1A, Parameter=0x0000 ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @pwr_lim_1: Bits [14:0] - Power Limit 1 ++ * @pwr_lim_1_en: Bits [15:15] - Power Limit 1 Enable ++ * @pwr_clmp_lim_1:Bits [16:16] - Package Clamping Limitation 1 ++ * @pwr_lim_1_time:Bits [23:17] - Power Limit 1 Time Window ++ * @rsvd0: Bits [31:24] ++ */ ++union peci_package_power_limit_low { ++ u32 value; ++ struct { ++ u32 pwr_lim_1 : 15; ++ u32 pwr_lim_1_en : 1; ++ u32 pwr_clmp_lim_1 : 1; ++ u32 pwr_lim_1_time : 7; ++ u32 rsvd0 : 8; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_package_power_limit_low) == ++ PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * union peci_dram_power_info_high - DRAM Power Info high PCS ++ * This PCS coresponds to the MSR@61Ch - MSR_DRAM_POWER_INFO, bits [63:32] ++ * Accessing over PECI: PCS=0x23, Parameter=0x0000 ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @max_pwr: Bits [14:0] - Maximal DRAM Power ++ * @rsvd0: Bits [15:15] ++ * @max_win: Bits [22:16] - Maximal Time Window ++ * @rsvd1: Bits [30:23] ++ * @lock: Bits [31:31] - Locking bit ++ */ ++union peci_dram_power_info_high { ++ u32 value; ++ struct { ++ u32 max_pwr : 15; ++ u32 rsvd0 : 1; ++ u32 max_win : 7; ++ u32 rsvd1 : 8; ++ u32 lock : 1; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_dram_power_info_high) == ++ PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * union peci_dram_power_info_low - DRAM Power Info low PCS ++ * This PCS coresponds to the MSR@61Ch - MSR_DRAM_POWER_INFO, bits [31:0] ++ * Accessing over PECI: PCS=0x24, Parameter=0x0000 ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @tdp: Bits [14:0] - Spec DRAM Power ++ * @rsvd0: Bits [15:15] ++ * @min_pwr: Bits [30:16] - Minimal DRAM Power ++ * @rsvd1: Bits [31:31] ++ */ ++union peci_dram_power_info_low { ++ u32 value; ++ struct { ++ u32 tdp : 15; ++ u32 rsvd0 : 1; ++ u32 min_pwr : 15; ++ u32 rsvd1 : 1; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_dram_power_info_low) == PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * union peci_dram_power_limit - DRAM Power Limit PCS ++ * This PCS coresponds to the MSR@618h - DRAM_PLANE_POWER_LIMIT, bits [31:0] ++ * Accessing over PECI: PCS=0x22, Parameter=0x0000 ++ * @value: PCS register value ++ * @bits: PCS register bits ++ * @pp_pwr_lim: Bits [14:0] - Power Limit[0] for DDR domain, ++ * format: U11.3 ++ * @pwr_lim_ctrl_en:Bits [15:15] - Power Limit[0] enable bit for ++ * DDR domain ++ * @rsvd0: Bits [16:16] ++ * @ctrl_time_win: Bits [23:17] - Power Limit[0] time window for ++ * DDR domain ++ * @rsvd1: Bits [31:24] ++ */ ++union peci_dram_power_limit { ++ u32 value; ++ struct { ++ u32 pp_pwr_lim : 15; ++ u32 pwr_lim_ctrl_en : 1; ++ u32 rsvd0 : 1; ++ u32 ctrl_time_win : 7; ++ u32 rsvd1 : 8; ++ } __attribute__((__packed__)) bits; ++} __attribute__((__packed__)); ++ ++static_assert(sizeof(union peci_dram_power_limit) == PECI_PCS_REGISTER_SIZE); ++ ++/** ++ * peci_pcs_xn_to_munits - function converting value in units in x.N format to ++ * milli units (millijoules, milliseconds, millidegrees) in regular format ++ * @x_n_value: Value in units in x.n format ++ * @n: n factor for x.n format ++ ++ * ++ * Return: value in milli units (millijoules, milliseconds, millidegrees) ++ * in regular format ++ */ ++static inline u64 peci_pcs_xn_to_munits(u32 x_n_value, u8 n) ++{ ++ /* Convert value in units in x.n format to milli units in x.n format */ ++ u64 mx_n_value = (u64)x_n_value * 1000uLL; ++ /* Convert x.n format to regular format */ ++ return mx_n_value >> n; ++} ++ ++/** ++ * peci_pcs_munits_to_xn - function converting value in milli units ++ * (millijoules,milliseconds, millidegrees) in regular format to value in units ++ * in x.n format ++ * @mu_value: Value in milli units (millijoules, milliseconds, millidegrees) ++ * @n: n factor for x.n format, assumed here maximal value for n is 32 ++ * ++ * Return: value in units in x.n format ++ */ ++static inline u32 peci_pcs_munits_to_xn(u32 mu_value, u8 n) ++{ ++ /* Convert value in milli units (regular format) to the x.n format */ ++ u64 mx_n_value = (u64)mu_value << n; ++ /* Convert milli units (x.n format) to units (x.n format) */ ++ if (mx_n_value > (u64)U32_MAX) { ++ do_div(mx_n_value, 1000uL); ++ return (u32)mx_n_value; ++ } else { ++ return (u32)mx_n_value / 1000uL; ++ } ++} ++ ++/** ++ * peci_pcs_read - read PCS register ++ * @peci_mgr: PECI client manager handle ++ * @index: PCS index ++ * @parameter: PCS parameter ++ * @reg: Pointer to the variable read value is going to be put ++ * ++ * Return: 0 if succeeded, ++ * -EINVAL if there are null pointers among arguments, ++ * other values in case other errors. ++ */ ++static inline int peci_pcs_read(struct peci_client_manager *peci_mgr, u8 index, ++ u16 parameter, u32 *reg) ++{ ++ u32 pcs_reg; ++ int ret; ++ ++ if (!reg) ++ return -EINVAL; ++ ++ ret = peci_client_read_package_config(peci_mgr, index, parameter, ++ (u8 *)&pcs_reg); ++ if (!ret) ++ *reg = le32_to_cpup((__le32 *)&pcs_reg); ++ ++ return ret; ++} ++ ++/** ++ * peci_pcs_write - write PCS register ++ * @peci_mgr: PECI client manager handle ++ * @index: PCS index ++ * @parameter: PCS parameter ++ * @reg: Variable which value is going to be written to the PCS ++ * ++ * Return: 0 if succeeded, other values in case an error. ++ */ ++static inline int peci_pcs_write(struct peci_client_manager *peci_mgr, u8 index, ++ u16 parameter, u32 reg) ++{ ++ u32 pcs_reg; ++ int ret; ++ ++ pcs_reg = cpu_to_le32p(®); ++ ++ ret = peci_client_write_package_config(peci_mgr, index, parameter, ++ (u8 *)&pcs_reg); ++ ++ return ret; ++} ++ ++/** ++ * peci_pcs_calc_pwr_from_eng - calculate power (in milliwatts) based on ++ * energy reading ++ * @dev: Device handle ++ * @energy: Energy reading context ++ * @energy_cnt: Raw energy reading ++ * @unit: Calculation factor ++ * @power_val_in_mW: Pointer to the variable calculation result is going to ++ * be put ++ * ++ * Return: 0 if succeeded, ++ * -EINVAL if there are null pointers among arguments, ++ * -EAGAIN if calculation is skipped. ++ */ ++static inline int peci_pcs_calc_pwr_from_eng(struct device *dev, ++ struct peci_sensor_data *sensor, ++ u32 energy_cnt, u32 unit, ++ s32 *power_in_mW) ++{ ++ ulong jif = jiffies; ++ ulong elapsed; ++ int ret; ++ ++ if (!dev || !sensor || !power_in_mW) ++ return -EINVAL; ++ ++ elapsed = jif - sensor->last_updated; ++ ++ dev_dbg(dev, "raw energy before %u, raw energy now %u, unit %u, jiffies elapsed %lu\n", ++ sensor->value, energy_cnt, unit, elapsed); ++ ++ /* ++ * Don't calculate average power for first counter read last counter ++ * read was more than 60 minutes ago (jiffies did not wrap and power ++ * calculation does not overflow or underflow). ++ */ ++ if (sensor->last_updated > 0 && elapsed < (HZ * 3600)) { ++ u32 energy_consumed; ++ u64 energy_consumed_in_mJ; ++ u64 energy_by_jiffies; ++ ++ /* Take care here about energy counter rollover */ ++ if (energy_cnt >= (u32)(sensor->value)) ++ energy_consumed = energy_cnt - (u32)(sensor->value); ++ else ++ energy_consumed = (U32_MAX - (u32)(sensor->value)) + ++ energy_cnt + 1u; ++ ++ /* Calculate the energy here */ ++ energy_consumed_in_mJ = ++ peci_pcs_xn_to_munits(energy_consumed, unit); ++ energy_by_jiffies = energy_consumed_in_mJ * HZ; ++ ++ /* Calculate the power */ ++ if (energy_by_jiffies > (u64)U32_MAX) { ++ do_div(energy_by_jiffies, elapsed); ++ *power_in_mW = (long)energy_by_jiffies; ++ } else { ++ *power_in_mW = (u32)energy_by_jiffies / elapsed; ++ } ++ ++ dev_dbg(dev, "raw energy consumed %u, scaled energy consumed %llumJ, scaled power %dmW\n", ++ energy_consumed, energy_consumed_in_mJ, *power_in_mW); ++ ++ ret = 0; ++ } else { ++ dev_dbg(dev, "skipping calculate power, try again\n"); ++ *power_in_mW = 0; ++ ret = -EAGAIN; ++ } ++ ++ /* Update sensor context */ ++ sensor->value = energy_cnt; ++ ++ return ret; ++} ++ ++/** ++ * peci_pcs_get_units - read units (power, energy, time) from HW or cache ++ * @peci_mgr: PECI client manager handle ++ * @units: Pointer to the variable read value is going to be put in case reading ++ * from HW ++ * @valid: Flag telling cache is valid ++ * ++ * Return: 0 if succeeded ++ * -EINVAL if there are null pointers among arguments, ++ * other values in case other errors. ++ */ ++static inline int peci_pcs_get_units(struct peci_client_manager *peci_mgr, ++ union peci_pkg_power_sku_unit *units, ++ bool *valid) ++{ ++ int ret = 0; ++ ++ if (!valid) ++ return -EINVAL; ++ ++ if (!(*valid)) { ++ ret = peci_pcs_read(peci_mgr, PECI_MBX_INDEX_TDP_UNITS, ++ PECI_PCS_PARAM_ZERO, &units->value); ++ if (!ret) ++ *valid = true; ++ } ++ return ret; ++} ++ ++/** ++ * peci_pcs_calc_plxy_time_window - calculate power limit time window in ++ * PCS format. To figure that value out needs to solve the following equation: ++ * time_window = (1+(x/4)) * (2 ^ y), where time_window is known value and ++ * x and y values are variables to find. ++ * Return value is about X & Y compostion according to the following: ++ * x = ret[6:5], y = ret[4:0]. ++ * @pl_tim_wnd_in_xn: PPL time window in X-n format ++ * ++ * Return: Power limit time window value ++ */ ++static inline u32 peci_pcs_calc_plxy_time_window(u32 pl_tim_wnd_in_xn) ++{ ++ u32 x = 0u; ++ u32 y = 0u; ++ ++ /* Calculate y first */ ++ while (pl_tim_wnd_in_xn > 7u) { ++ pl_tim_wnd_in_xn >>= 1; ++ y++; ++ } ++ ++ /* Correct y value */ ++ if (pl_tim_wnd_in_xn >= 4u) ++ y += 2u; ++ else if (pl_tim_wnd_in_xn >= 2u) ++ y += 1u; ++ ++ /* Calculate x then */ ++ if (pl_tim_wnd_in_xn >= 4u) ++ x = pl_tim_wnd_in_xn % 4; ++ else ++ x = 0u; ++ ++ return ((x & 0x3) << 5) | (y & 0x1F); ++} ++ + #endif /* __PECI_HWMON_H */ +diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h +index dbf0670..ba9c03d 100644 +--- a/include/linux/mfd/intel-peci-client.h ++++ b/include/linux/mfd/intel-peci-client.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018-2019 Intel Corporation */ ++/* Copyright (c) 2018-2020 Intel Corporation */ + + #ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H + #define __LINUX_MFD_INTEL_PECI_CLIENT_H +@@ -131,4 +131,36 @@ peci_client_read_package_config(struct peci_client_manager *priv, + return 0; + } + ++/** ++ * peci_client_write_package_config - write to the Package Configuration Space ++ * @priv: driver private data structure ++ * @index: encoding index for the requested service ++ * @param: parameter to specify the exact data being requested ++ * @data: data buffer with values to write ++ * Context: can sleep ++ * ++ * Return: zero on success, else a negative error code. ++ */ ++static inline int ++peci_client_write_package_config(struct peci_client_manager *priv, ++ u8 index, u16 param, u8 *data) ++{ ++ struct peci_rd_pkg_cfg_msg msg; ++ int ret; ++ ++ msg.addr = priv->client->addr; ++ msg.index = index; ++ msg.param = param; ++ msg.rx_len = 4u; ++ memcpy(msg.pkg_config, data, msg.rx_len); ++ ++ ret = peci_command(priv->client->adapter, PECI_CMD_WR_PKG_CFG, &msg); ++ if (!ret) { ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ } ++ ++ return ret; ++} ++ + #endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */ +diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h +index c0f0bb3..1c76c7f 100644 +--- a/include/uapi/linux/peci-ioctl.h ++++ b/include/uapi/linux/peci-ioctl.h +@@ -226,12 +226,15 @@ struct peci_rd_pkg_cfg_msg { + __u16 param; + /* When index is PECI_MBX_INDEX_CPU_ID */ + #define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */ ++#define PECI_PKG_POWER_SKU_UNIT 0x0000 /* Time, Energy, Power units */ + #define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ + #define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ + #define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ + #define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ + #define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ +-#define PECI_PKG_ID_PKG_ENERGY_STATUS 0x00ff /* Average Energy */ ++#define PECI_PKG_ID_CPU_PACKAGE 0x00ff /* CPU package ID*/ ++#define PECI_PKG_ID_DIMM 0x00ff /* DIMM ID*/ ++#define PECI_PKG_ID_PLATFORM 0x00fe /* Entire platform ID */ + + __u8 rx_len; + __u8 cc; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0114-hwmon-peci-cpupower-extension.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0114-hwmon-peci-cpupower-extension.patch new file mode 100644 index 000000000..72457917c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0114-hwmon-peci-cpupower-extension.patch @@ -0,0 +1,708 @@ +From ca6f311baec11435dbd27b45c83eba0bfcb2ebdc Mon Sep 17 00:00:00 2001 +From: Zbigniew Lukwinski +Date: Wed, 17 Jun 2020 07:11:07 +0200 +Subject: [PATCH] hwmon: peci: cpupower extension + +1. Use hwmon peci pcs utils to refactor peci cpupower module. +2. Enable CPU power limit, power limit max (TDP) setting, + power limit min setting reading and expose them under + power1_cap, power1_cap_max, power1_cap_min. +3. Enable CPU power limit writing through power1_cap. + +Tested: + * on WilsonCity platform, + * power1_avarage works as before the change, + * power1_cap, power1_cap_max, power1_cap_min work as expected. + +Signed-off-by: Zbigniew Lukwinski +--- + Documentation/hwmon/peci-cpupower.rst | 13 +- + drivers/hwmon/Kconfig | 4 +- + drivers/hwmon/peci-cpupower.c | 550 +++++++++++++++++++++++++++------- + 3 files changed, 446 insertions(+), 121 deletions(-) + +diff --git a/Documentation/hwmon/peci-cpupower.rst b/Documentation/hwmon/peci-cpupower.rst +index 4d7bd61..1e1f4e0 100644 +--- a/Documentation/hwmon/peci-cpupower.rst ++++ b/Documentation/hwmon/peci-cpupower.rst +@@ -38,15 +38,22 @@ Description + ----------- + + This driver implements a generic PECI hwmon feature which provides +-average power consumption readings of the CPU package based on energy counter +-accessible using the PECI Client Command Suite via the processor PECI client. ++average power consumption readings of the CPU package based on energy counter. + + Power values are average power since last measure given in milli Watt and + will be measurable only when the target CPU is powered on. + ++Driver provides current package power limit, maximal (TDP) and minimal power ++setting as well. ++All needed processor registers are accessible using the PECI Client Command ++Suite via the processor PECI client. ++ + ``sysfs`` interface + ------------------- + ======================= ======================================================= ++power1_label Provides string "cpu power". + power1_average Provides average power since last read in milli Watt. +-power1_label Provides string "Average Power". ++power1_cap Provides current package power limit 1 (PPL1). ++power1_cap_max Provides maximal (TDP) package power setting. ++power1_cap_min Provides minimal package power setting. + ======================= ======================================================= +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 07d8826..807b489 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1367,8 +1367,8 @@ config SENSORS_PECI_CPUPOWER + select MFD_INTEL_PECI_CLIENT + help + If you say yes here you get support for the generic Intel PECI +- cputemp driver which provides average engergy +- readings of the CPU package using ++ cpupower driver which provides average engergy readings of the CPU package, ++ current package power limit, maximal (TDP) and minimal power setting using + the PECI Client Command Suite via the processor PECI client. + Check Documentation/hwmon/peci-cpupower for details. + +diff --git a/drivers/hwmon/peci-cpupower.c b/drivers/hwmon/peci-cpupower.c +index a3a8fc1..d0a3af7 100644 +--- a/drivers/hwmon/peci-cpupower.c ++++ b/drivers/hwmon/peci-cpupower.c +@@ -9,159 +9,478 @@ + #include + #include "peci-hwmon.h" + +-#define POWER_DEFAULT_CHANNEL_NUMS 1 ++#define PECI_CPUPOWER_CHANNEL_COUNT 1 /* Supported channels number */ ++ ++#define PECI_CPUPOWER_SENSOR_COUNT 4 /* Supported sensors/readings number */ + + struct peci_cpupower { +- struct peci_client_manager *mgr; + struct device *dev; ++ struct peci_client_manager *mgr; + char name[PECI_NAME_SIZE]; +- const struct cpu_gen_info *gen_info; +- struct peci_sensor_data energy; +- long avg_power_val; +- u64 core_mask; +- u32 power_config[POWER_DEFAULT_CHANNEL_NUMS + 1]; +- uint config_idx; ++ u32 power_config[PECI_CPUPOWER_CHANNEL_COUNT + 1]; ++ u32 config_idx; + struct hwmon_channel_info power_info; + const struct hwmon_channel_info *info[2]; + struct hwmon_chip_info chip; +-}; + +-enum cpupower_channels { +- average_power, +-}; ++ struct peci_sensor_data ++ sensor_data_list[PECI_CPUPOWER_CHANNEL_COUNT] ++ [PECI_CPUPOWER_SENSOR_COUNT]; ++ ++ s32 avg_power_val; ++ union peci_pkg_power_sku_unit units; ++ bool units_valid; + +-static const u32 config_table[POWER_DEFAULT_CHANNEL_NUMS] = { +- /* average power */ +- HWMON_P_LABEL | HWMON_P_AVERAGE, ++ u32 ppl1_time_window; ++ u32 ppl2_time_window; ++ bool ppl_time_windows_valid; + }; + +-static const char *cpupower_label[POWER_DEFAULT_CHANNEL_NUMS] = { +- "Average Power", ++static const char *peci_cpupower_labels[PECI_CPUPOWER_CHANNEL_COUNT] = { ++ "cpu power", + }; + +-static int get_average_power(struct peci_cpupower *priv) ++/** ++ * peci_cpupower_read_cpu_pkg_pwr_info_low - read PCS Platform Power SKU low. ++ * @peci_mgr: PECI client manager handle ++ * @reg: Pointer to the variable read value is going to be put ++ * ++ * Return: 0 if succeeded, other values in case an error. ++ */ ++static inline int ++peci_cpupower_read_cpu_pkg_pwr_info_low(struct peci_client_manager *peci_mgr, ++ union peci_package_power_info_low *reg) + { +- u8 pkg_cfg[4]; ++ return peci_pcs_read(peci_mgr, PECI_MBX_INDEX_TDP, ++ PECI_PKG_ID_CPU_PACKAGE, ®->value); ++} ++ ++/** ++ * peci_cpupower_read_cpu_pkg_pwr_lim_low - read PCS Package Power Limit Low ++ * @peci_mgr: PECI client manager handle ++ * @reg: Pointer to the variable read value is going to be put ++ * ++ * Return: 0 if succeeded, other values in case an error. ++ */ ++static inline int ++peci_cpupower_read_cpu_pkg_pwr_lim_low(struct peci_client_manager *peci_mgr, ++ union peci_package_power_limit_low *reg) ++{ ++ return peci_pcs_read(peci_mgr, PECI_MBX_INDEX_PKG_POWER_LIMIT1, ++ PECI_PCS_PARAM_ZERO, ®->value); ++} ++ ++static int ++peci_cpupower_get_average_power(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_cpupower *priv = (struct peci_cpupower *)ctx; ++ u32 energy_cnt; ++ ulong jif; + int ret; + +- if (!peci_sensor_need_update(&priv->energy)) ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = priv->avg_power_val; ++ dev_dbg(priv->dev, ++ "skip reading peci, average power %dmW\n", *val); + return 0; ++ } + +- ret = peci_client_read_package_config(priv->mgr, +- PECI_MBX_INDEX_TDP_UNITS, +- PECI_PKG_ID_CPU_PACKAGE, +- pkg_cfg); ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } + +- u32 power_unit = ((le32_to_cpup((__le32 *)pkg_cfg)) & 0x1f00) >> 8; ++ jif = jiffies; ++ ret = peci_pcs_read(priv->mgr, PECI_MBX_INDEX_ENERGY_COUNTER, ++ PECI_PKG_ID_CPU_PACKAGE, &energy_cnt); + +- dev_dbg(priv->dev, "cpupower units %d (1J/pow(2, unit))\n", +- power_unit); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read package energy\n"); ++ return ret; ++ } + +- ret = peci_client_read_package_config(priv->mgr, +- PECI_MBX_INDEX_ENERGY_COUNTER, +- PECI_PKG_ID_CPU_PACKAGE, +- pkg_cfg); +- if (!ret) { +- u32 energy_cnt = le32_to_cpup((__le32 *)pkg_cfg); +- ulong jif = jiffies; +- ulong elapsed = (jif - priv->energy.last_updated); +- long power_val = 0; +- /* +- * Don't calculate average power for first counter read or +- * counter wrapped around or last counter read was more than +- * 60 minutes ago (jiffies did not wrap and power calculation +- * does not overflow or underflow +- */ +- if (priv->energy.last_updated > 0 && +- energy_cnt > priv->energy.value && +- (elapsed < (HZ * 3600))) { +- power_val = (long)(energy_cnt - priv->energy.value) +- / elapsed * HZ; +- dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, raw powerValue %d scale to %d mW\n", +- (long)(energy_cnt - priv->energy.value), +- elapsed, power_val, +- power_val >> (power_unit - 10)); +- } else { +- dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, skipping calculate power, try agin\n", +- (long)(energy_cnt - priv->energy.value), +- elapsed); +- ret = -EAGAIN; +- } +- +- priv->energy.value = energy_cnt; +- priv->avg_power_val = power_val >> ((power_unit - 10)); +- peci_sensor_mark_updated(&priv->energy); +- +- dev_dbg(priv->dev, "energy counter 0x%8x, average power %dmW, jif %u, HZ is %d jiffies\n", +- priv->energy.value, priv->avg_power_val, +- jif, HZ); ++ ret = peci_pcs_calc_pwr_from_eng(priv->dev, sensor_data, energy_cnt, ++ priv->units.bits.eng_unit, val); ++ ++ priv->avg_power_val = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "average power %dmW, jif %lu, HZ is %d jiffies\n", ++ *val, jif, HZ); ++ ++ return ret; ++} ++ ++static int ++peci_cpupower_get_power_limit(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_cpupower *priv = (struct peci_cpupower *)ctx; ++ union peci_package_power_limit_low power_limit; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = sensor_data->value; ++ dev_dbg(priv->dev, "skip reading peci, power limit %dmW\n", ++ *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_cpupower_read_cpu_pkg_pwr_lim_low(priv->mgr, &power_limit); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read power limit\n"); ++ return ret; + } ++ ++ *val = peci_pcs_xn_to_munits(power_limit.bits.pwr_lim_1, ++ priv->units.bits.pwr_unit); ++ ++ sensor_data->value = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "raw power limit %u, unit %u, power limit %d\n", ++ power_limit.bits.pwr_lim_1, priv->units.bits.pwr_unit, *val); ++ + return ret; + } + +-static int cpupower_read_string(struct device *dev, +- enum hwmon_sensor_types type, +- u32 attr, int channel, const char **str) ++static int ++peci_cpupower_set_power_limit(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 val) + { +- if (attr != hwmon_power_label) +- return -EOPNOTSUPP; +- if (channel >= POWER_DEFAULT_CHANNEL_NUMS) ++ struct peci_cpupower *priv = (struct peci_cpupower *)ctx; ++ union peci_package_power_limit_high power_limit_high; ++ union peci_package_power_limit_low power_limit_low; ++ int ret; ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ ret = peci_cpupower_read_cpu_pkg_pwr_lim_low(priv->mgr, ++ &power_limit_low); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read package power limit 1\n"); ++ return ret; ++ } ++ ++ ret = peci_pcs_read(priv->mgr, PECI_MBX_INDEX_PKG_POWER_LIMIT2, ++ PECI_PCS_PARAM_ZERO, &power_limit_high.value); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read package power limit 2\n"); ++ return ret; ++ } ++ ++ /* Calculate PPL time windows if needed */ ++ if (!priv->ppl_time_windows_valid) { ++ priv->ppl1_time_window = ++ peci_pcs_calc_plxy_time_window(peci_pcs_munits_to_xn( ++ PECI_PCS_PPL1_TIME_WINDOW, ++ priv->units.bits.tim_unit)); ++ priv->ppl2_time_window = ++ peci_pcs_calc_plxy_time_window(peci_pcs_munits_to_xn( ++ PECI_PCS_PPL2_TIME_WINDOW, ++ priv->units.bits.tim_unit)); ++ priv->ppl_time_windows_valid = true; ++ } ++ ++ /* Enable or disable power limitation */ ++ if (val > 0) { ++ /* Set PPL1 */ ++ power_limit_low.bits.pwr_lim_1 = ++ peci_pcs_munits_to_xn(val, priv->units.bits.pwr_unit); ++ power_limit_low.bits.pwr_lim_1_en = 1u; ++ power_limit_low.bits.pwr_clmp_lim_1 = 1u; ++ power_limit_low.bits.pwr_lim_1_time = priv->ppl1_time_window; ++ ++ /* Set PPL2 */ ++ power_limit_high.bits.pwr_lim_2 = ++ peci_pcs_munits_to_xn(PECI_PCS_PPL1_TO_PPL2(val), ++ priv->units.bits.pwr_unit); ++ power_limit_high.bits.pwr_lim_2_en = 1u; ++ power_limit_high.bits.pwr_clmp_lim_2 = 1u; ++ power_limit_high.bits.pwr_lim_2_time = priv->ppl2_time_window; ++ } else { ++ power_limit_low.bits.pwr_lim_1 = 0u; ++ power_limit_low.bits.pwr_lim_1_en = 0u; ++ power_limit_low.bits.pwr_clmp_lim_1 = 0u; ++ power_limit_high.bits.pwr_lim_2 = 0u; ++ power_limit_high.bits.pwr_lim_2_en = 0u; ++ power_limit_high.bits.pwr_clmp_lim_2 = 0u; ++ } ++ ++ ret = peci_pcs_write(priv->mgr, PECI_MBX_INDEX_PKG_POWER_LIMIT1, ++ PECI_PCS_PARAM_ZERO, power_limit_low.value); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to write package power limit 1\n"); ++ return ret; ++ } ++ ++ ret = peci_pcs_write(priv->mgr, PECI_MBX_INDEX_PKG_POWER_LIMIT2, ++ PECI_PCS_PARAM_ZERO, power_limit_high.value); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to write package power limit 2\n"); ++ return ret; ++ } ++ ++ dev_dbg(priv->dev, ++ "power limit %d, unit %u, raw package power limit 1 %u,\n", ++ val, priv->units.bits.pwr_unit, power_limit_low.bits.pwr_lim_1); ++ ++ return ret; ++} ++ ++static int ++peci_cpupower_read_max_power(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_cpupower *priv = (struct peci_cpupower *)ctx; ++ union peci_package_power_info_low power_info; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = sensor_data->value; ++ dev_dbg(priv->dev, "skip reading peci, max power %dmW\n", *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_cpupower_read_cpu_pkg_pwr_info_low(priv->mgr, &power_info); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read package power info\n"); ++ return ret; ++ } ++ ++ *val = peci_pcs_xn_to_munits(power_info.bits.pkg_tdp, ++ priv->units.bits.pwr_unit); ++ ++ sensor_data->value = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "raw max power %u, unit %u, max power %dmW\n", ++ power_info.bits.pkg_tdp, priv->units.bits.pwr_unit, *val); ++ ++ return ret; ++} ++ ++static int ++peci_cpupower_read_min_power(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_cpupower *priv = (struct peci_cpupower *)ctx; ++ union peci_package_power_info_low power_info; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = sensor_data->value; ++ dev_dbg(priv->dev, "skip reading peci, min power %dmW\n", ++ *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_cpupower_read_cpu_pkg_pwr_info_low(priv->mgr, &power_info); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read package power info\n"); ++ return ret; ++ } ++ ++ *val = peci_pcs_xn_to_munits(power_info.bits.pkg_min_pwr, ++ priv->units.bits.pwr_unit); ++ ++ sensor_data->value = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "raw min power %u, unit %u, min power %dmW\n", ++ power_info.bits.pkg_min_pwr, priv->units.bits.pwr_unit, *val); ++ ++ return ret; ++} ++ ++static struct peci_sensor_conf ++peci_cpupower_cfg[PECI_CPUPOWER_CHANNEL_COUNT][PECI_CPUPOWER_SENSOR_COUNT] = { ++ /* Channel 0 - Power */ ++ { ++ { ++ .attribute = hwmon_power_average, ++ .config = HWMON_P_AVERAGE, ++ .update_interval = UPDATE_INTERVAL_100MS, ++ .read = peci_cpupower_get_average_power, ++ .write = NULL, ++ }, ++ { ++ .attribute = hwmon_power_cap, ++ .config = HWMON_P_CAP, ++ .update_interval = UPDATE_INTERVAL_100MS, ++ .read = peci_cpupower_get_power_limit, ++ .write = peci_cpupower_set_power_limit, ++ }, ++ { ++ .attribute = hwmon_power_cap_max, ++ .config = HWMON_P_CAP_MAX, ++ .update_interval = UPDATE_INTERVAL_10S, ++ .read = peci_cpupower_read_max_power, ++ .write = NULL, ++ }, ++ { ++ .attribute = hwmon_power_cap_min, ++ .config = HWMON_P_CAP_MIN, ++ .update_interval = UPDATE_INTERVAL_10S, ++ .read = peci_cpupower_read_min_power, ++ .write = NULL, ++ }, ++ }, ++}; ++ ++static int ++peci_cpupower_read_string(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ if (attr != hwmon_power_label || channel >= PECI_CPUPOWER_CHANNEL_COUNT) + return -EOPNOTSUPP; +- *str = cpupower_label[channel]; ++ ++ if (str) ++ *str = peci_cpupower_labels[channel]; ++ else ++ return -EINVAL; + + return 0; + } + +-static int cpupower_read(struct device *dev, +- enum hwmon_sensor_types type, +- u32 attr, int channel, long *val) ++static int ++peci_cpupower_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) + { + struct peci_cpupower *priv = dev_get_drvdata(dev); ++ struct peci_sensor_conf *sensor_conf; ++ struct peci_sensor_data *sensor_data; + int ret; + +- if (channel >= POWER_DEFAULT_CHANNEL_NUMS || +- !(priv->power_config[channel] & BIT(attr))) ++ if (!priv || !val) ++ return -EINVAL; ++ ++ if (channel >= PECI_CPUPOWER_CHANNEL_COUNT) + return -EOPNOTSUPP; + +- switch (attr) { +- case hwmon_power_average: +- switch (channel) { +- case average_power: +- ret = get_average_power(priv); +- if (ret) +- break; +- +- *val = priv->avg_power_val; +- break; +- default: +- break; +- } +- break; +- default: ++ ret = peci_sensor_get_ctx(attr, peci_cpupower_cfg[channel], ++ &sensor_conf, priv->sensor_data_list[channel], ++ &sensor_data, ++ ARRAY_SIZE(peci_cpupower_cfg[channel])); ++ if (ret) ++ return ret; ++ ++ if (sensor_conf->read) { ++ s32 tmp; ++ ++ ret = sensor_conf->read(priv, sensor_conf, sensor_data, &tmp); ++ if (!ret) ++ *val = (long)tmp; ++ } else { + ret = -EOPNOTSUPP; +- break; + } + + return ret; + } + +-static umode_t cpupower_is_visible(const void *data, +- enum hwmon_sensor_types type, +- u32 attr, int channel) ++static int ++peci_cpupower_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) + { +- const struct peci_cpupower *priv = data; ++ struct peci_cpupower *priv = dev_get_drvdata(dev); ++ struct peci_sensor_conf *sensor_conf; ++ struct peci_sensor_data *sensor_data; ++ int ret; ++ ++ if (!priv) ++ return -EINVAL; + +- if (channel < POWER_DEFAULT_CHANNEL_NUMS || +- (priv->power_config[channel] & BIT(attr))) ++ if (channel >= PECI_CPUPOWER_CHANNEL_COUNT) ++ return -EOPNOTSUPP; ++ ++ ret = peci_sensor_get_ctx(attr, peci_cpupower_cfg[channel], ++ &sensor_conf, priv->sensor_data_list[channel], ++ &sensor_data, ++ ARRAY_SIZE(peci_cpupower_cfg[channel])); ++ if (ret) ++ return ret; ++ ++ if (sensor_conf->write) { ++ ret = sensor_conf->write(priv, sensor_conf, sensor_data, ++ (s32)val); ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static umode_t ++peci_cpupower_is_visible(const void *data, enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ struct peci_sensor_conf *sensor_conf; ++ umode_t mode = 0; ++ int ret; ++ ++ if (channel >= PECI_CPUPOWER_CHANNEL_COUNT) ++ return mode; ++ ++ if (attr == hwmon_power_label) + return 0444; + +- return 0; ++ ret = peci_sensor_get_ctx(attr, peci_cpupower_cfg[channel], ++ &sensor_conf, NULL, NULL, ++ ARRAY_SIZE(peci_cpupower_cfg[channel])); ++ if (!ret) { ++ if (sensor_conf->read) ++ mode |= 0444; ++ if (sensor_conf->write) ++ mode |= 0200; ++ } ++ ++ return mode; + } + +-static const struct hwmon_ops cpupower_ops = { +- .is_visible = cpupower_is_visible, +- .read_string = cpupower_read_string, +- .read = cpupower_read, ++static const struct hwmon_ops peci_cpupower_ops = { ++ .is_visible = peci_cpupower_is_visible, ++ .read_string = peci_cpupower_read_string, ++ .read = peci_cpupower_read, ++ .write = peci_cpupower_write, + }; + + static int peci_cpupower_probe(struct platform_device *pdev) +@@ -170,12 +489,11 @@ static int peci_cpupower_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct peci_cpupower *priv; + struct device *hwmon_dev; ++ u32 cmd_mask; + +- if ((mgr->client->adapter->cmd_mask & +- (BIT(PECI_CMD_RD_PKG_CFG))) != +- (BIT(PECI_CMD_RD_PKG_CFG))) { ++ cmd_mask = BIT(PECI_CMD_RD_PKG_CFG) | BIT(PECI_CMD_WR_PKG_CFG); ++ if ((mgr->client->adapter->cmd_mask & cmd_mask) != cmd_mask) + return -ENODEV; +- } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -184,25 +502,25 @@ static int peci_cpupower_probe(struct platform_device *pdev) + dev_set_drvdata(dev, priv); + priv->mgr = mgr; + priv->dev = dev; +- priv->gen_info = mgr->gen_info; + + snprintf(priv->name, PECI_NAME_SIZE, "peci_cpupower.cpu%d", + mgr->client->addr - PECI_BASE_ADDR); + +- priv->power_config[priv->config_idx++] = config_table[average_power]; ++ priv->power_config[priv->config_idx] = HWMON_P_LABEL | ++ peci_sensor_get_config(peci_cpupower_cfg[priv->config_idx], ++ ARRAY_SIZE(peci_cpupower_cfg ++ [priv->config_idx])); ++ priv->config_idx++; + +- priv->chip.ops = &cpupower_ops; ++ priv->chip.ops = &peci_cpupower_ops; + priv->chip.info = priv->info; +- + priv->info[0] = &priv->power_info; + + priv->power_info.type = hwmon_power; + priv->power_info.config = priv->power_config; + +- hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, +- priv->name, +- priv, +- &priv->chip, ++ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, priv->name, ++ priv, &priv->chip, + NULL); + + if (IS_ERR(hwmon_dev)) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0115-hwmon-peci-dimmpower-implementation.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0115-hwmon-peci-dimmpower-implementation.patch new file mode 100644 index 000000000..a1b8a5117 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0115-hwmon-peci-dimmpower-implementation.patch @@ -0,0 +1,677 @@ +From 9a616835a8fd6bcc08fc9302957a692c1eea3d4d Mon Sep 17 00:00:00 2001 +From: Zbigniew Lukwinski +Date: Wed, 17 Jun 2020 08:12:27 +0200 +Subject: [PATCH] hwmon: peci: dimmpower implementation + +1. Peci dimmpower module implementation. +2. Enable DIMM avarage power, power limit, power limit max setting, + power limit min setting reading and expose them under + power1_avarage, power1_cap, power1_cap_max, power1_cap_min in + sysfs. +3. Enable DIMM power limit writing through power1_cap. + +Tested: + * on WilsonCity platform, + * power1_avarage, power1_cap, power1_cap_max and power1_cap_min work + as expected + +Signed-off-by: Zbigniew Lukwinski +--- + Documentation/hwmon/index.rst | 1 + + Documentation/hwmon/peci-dimmpower.rst | 57 ++++ + arch/arm/configs/aspeed_g5_defconfig | 1 + + drivers/hwmon/Kconfig | 14 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/peci-dimmpower.c | 502 +++++++++++++++++++++++++++++++++ + drivers/mfd/intel-peci-client.c | 1 + + 7 files changed, 577 insertions(+) + create mode 100644 Documentation/hwmon/peci-dimmpower.rst + create mode 100644 drivers/hwmon/peci-dimmpower.c + +diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst +index 0bde0ef..61802e3 100644 +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -131,6 +131,7 @@ Hardware Monitoring Kernel Drivers + peci-cputemp + peci-dimmtemp + peci-cpupower ++ peci-dimmpower + pmbus + powr1220 + pxe1610 +diff --git a/Documentation/hwmon/peci-dimmpower.rst b/Documentation/hwmon/peci-dimmpower.rst +new file mode 100644 +index 0000000..0d9c58fd +--- /dev/null ++++ b/Documentation/hwmon/peci-dimmpower.rst +@@ -0,0 +1,57 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Kernel driver peci-dimmpower ++========================== ++ ++:Copyright: |copy| 2020 Intel Corporation ++ ++Supported chips: ++ One of Intel server CPUs listed below which is connected to a PECI bus. ++ * Intel Xeon E5/E7 v3 server processors ++ Intel Xeon E5-14xx v3 family ++ Intel Xeon E5-24xx v3 family ++ Intel Xeon E5-16xx v3 family ++ Intel Xeon E5-26xx v3 family ++ Intel Xeon E5-46xx v3 family ++ Intel Xeon E7-48xx v3 family ++ Intel Xeon E7-88xx v3 family ++ * Intel Xeon E5/E7 v4 server processors ++ Intel Xeon E5-16xx v4 family ++ Intel Xeon E5-26xx v4 family ++ Intel Xeon E5-46xx v4 family ++ Intel Xeon E7-48xx v4 family ++ Intel Xeon E7-88xx v4 family ++ * Intel Xeon Scalable server processors ++ Intel Xeon D family ++ Intel Xeon Bronze family ++ Intel Xeon Silver family ++ Intel Xeon Gold family ++ Intel Xeon Platinum family ++ ++ Addresses scanned: PECI client address 0x30 - 0x37 ++ Datasheet: Available from http://www.intel.com/design/literature.htm ++ ++Author: ++ Zbigniew Lukwinski ++ ++Description ++----------- ++ ++This driver implements a generic PECI hwmon feature which provides ++average power consumption readings of the memory basing on energy counter. ++Power value is average power since last measure given in milli Watt and ++will be measurable only when the target CPU is powered on. ++Driver provides current plane power limit, maximal and minimal power setting ++as well. ++All needed processor registers are accessible using the PECI Client Command ++Suite via the processor PECI client. ++ ++``sysfs`` interface ++------------------- ++======================= ======================================================= ++power1_label Provides string "dimm power". ++power1_average Provides average DRAM power since last read in milli Watt. ++power1_cap Provides current DRAM plane power limit. ++power1_cap_max Provides maximal DRAM power setting. ++power1_cap_min Provides minimal DRAM power setting. ++======================= ======================================================= +diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig +index 04c40fe..f35b81e 100644 +--- a/arch/arm/configs/aspeed_g5_defconfig ++++ b/arch/arm/configs/aspeed_g5_defconfig +@@ -183,6 +183,7 @@ CONFIG_SENSORS_OCC_P9_SBE=y + CONFIG_SENSORS_PECI_CPUTEMP=y + CONFIG_SENSORS_PECI_DIMMTEMP=y + CONFIG_SENSORS_PECI_CPUPOWER=y ++CONFIG_SENSORS_PECI_DIMMPOWER=y + CONFIG_PMBUS=y + CONFIG_SENSORS_ADM1275=y + CONFIG_SENSORS_IBM_CFFPS=y +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 807b489..3e229b7 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1375,6 +1375,20 @@ config SENSORS_PECI_CPUPOWER + This driver can also be built as a module. If so, the module + will be called peci-cpupower. + ++config SENSORS_PECI_DIMMPOWER ++ tristate "PECI DIMM power monitoring support" ++ depends on PECI ++ select MFD_INTEL_PECI_CLIENT ++ help ++ If you say yes here you get support for the generic Intel PECI ++ dimmpower driver which provides average engergy readings of the memory ++ package, current power limit, maximal and minimal power setting using ++ the PECI Client Command Suite via the processor PECI client. ++ Check Documentation/hwmon/peci-dimmpower for details. ++ ++ This driver can also be built as a module. If so, the module ++ will be called peci-dimmpower. ++ + source "drivers/hwmon/pmbus/Kconfig" + + config SENSORS_PWM_FAN +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index fab43fd..6d2751e 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -145,6 +145,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o + obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o + obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o + obj-$(CONFIG_SENSORS_PECI_CPUPOWER) += peci-cpupower.o ++obj-$(CONFIG_SENSORS_PECI_DIMMPOWER) += peci-dimmpower.o + obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o + obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o + obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o +diff --git a/drivers/hwmon/peci-dimmpower.c b/drivers/hwmon/peci-dimmpower.c +new file mode 100644 +index 0000000..69205d8 +--- /dev/null ++++ b/drivers/hwmon/peci-dimmpower.c +@@ -0,0 +1,502 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2020 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "peci-hwmon.h" ++ ++#define PECI_DIMMPOWER_CHANNEL_COUNT 1 /* Supported channels number */ ++ ++#define PECI_DIMMPOWER_SENSOR_COUNT 4 /* Supported sensors/readings number */ ++ ++struct peci_dimmpower { ++ struct device *dev; ++ struct peci_client_manager *mgr; ++ char name[PECI_NAME_SIZE]; ++ u32 power_config[PECI_DIMMPOWER_CHANNEL_COUNT + 1]; ++ u32 config_idx; ++ struct hwmon_channel_info power_info; ++ const struct hwmon_channel_info *info[2]; ++ struct hwmon_chip_info chip; ++ ++ struct peci_sensor_data ++ sensor_data_list[PECI_DIMMPOWER_CHANNEL_COUNT] ++ [PECI_DIMMPOWER_SENSOR_COUNT]; ++ ++ s32 avg_power_val; ++ union peci_pkg_power_sku_unit units; ++ bool units_valid; ++ ++ u32 dpl_time_window; ++ bool dpl_time_window_valid; ++}; ++ ++static const char *peci_dimmpower_labels[PECI_DIMMPOWER_CHANNEL_COUNT] = { ++ "dimm power", ++}; ++ ++/** ++ * peci_dimmpower_read_dram_power_limit - read PCS DRAM Power Limit ++ * @peci_mgr: PECI client manager handle ++ * @reg: Pointer to the variable read value is going to be put ++ * ++ * Return: 0 if succeeded, other values in case an error. ++ */ ++static inline int ++peci_dimmpower_read_dram_power_limit(struct peci_client_manager *peci_mgr, ++ union peci_dram_power_limit *reg) ++{ ++ return peci_pcs_read(peci_mgr, PECI_MBX_INDEX_DDR_RAPL_PL1, ++ PECI_PCS_PARAM_ZERO, ®->value); ++} ++ ++static int ++peci_dimmpower_get_avg_power(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_dimmpower *priv = (struct peci_dimmpower *)ctx; ++ u32 energy_cnt; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = priv->avg_power_val; ++ dev_dbg(priv->dev, "skip reading peci, average power %dmW\n", ++ *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_pcs_read(priv->mgr, PECI_MBX_INDEX_ENERGY_STATUS, ++ PECI_PKG_ID_DIMM, &energy_cnt); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read energy\n"); ++ return ret; ++ } ++ ++ ret = peci_pcs_calc_pwr_from_eng(priv->dev, sensor_data, energy_cnt, ++ priv->units.bits.eng_unit, val); ++ ++ priv->avg_power_val = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "average power %dmW, jif %lu, HZ is %d jiffies\n", ++ *val, jif, HZ); ++ ++ return ret; ++} ++ ++static int ++peci_dimmpower_get_power_limit(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_dimmpower *priv = (struct peci_dimmpower *)ctx; ++ union peci_dram_power_limit power_limit; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = sensor_data->value; ++ dev_dbg(priv->dev, "skip reading peci, power limit %dmW\n", ++ *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_dimmpower_read_dram_power_limit(priv->mgr, &power_limit); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read power limit\n"); ++ return ret; ++ } ++ ++ *val = peci_pcs_xn_to_munits(power_limit.bits.pp_pwr_lim, ++ priv->units.bits.pwr_unit); ++ ++ sensor_data->value = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "raw power limit %u, unit %u, power limit %d\n", ++ power_limit.bits.pp_pwr_lim, priv->units.bits.pwr_unit, *val); ++ ++ return ret; ++} ++ ++static int ++peci_dimmpower_set_power_limit(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 val) ++{ ++ struct peci_dimmpower *priv = (struct peci_dimmpower *)ctx; ++ union peci_dram_power_limit power_limit; ++ int ret; ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ ret = peci_dimmpower_read_dram_power_limit(priv->mgr, &power_limit); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read power limit\n"); ++ return ret; ++ } ++ ++ /* Calculate DPL time window if needed */ ++ if (!priv->dpl_time_window_valid) { ++ priv->dpl_time_window = ++ peci_pcs_calc_plxy_time_window(peci_pcs_munits_to_xn( ++ PECI_PCS_PPL1_TIME_WINDOW, ++ priv->units.bits.tim_unit)); ++ priv->dpl_time_window_valid = true; ++ } ++ ++ /* Enable or disable power limitation */ ++ if (val > 0) { ++ power_limit.bits.pp_pwr_lim = ++ peci_pcs_munits_to_xn(val, priv->units.bits.pwr_unit); ++ power_limit.bits.pwr_lim_ctrl_en = 1u; ++ power_limit.bits.ctrl_time_win = priv->dpl_time_window; ++ } else { ++ power_limit.bits.pp_pwr_lim = 0u; ++ power_limit.bits.pwr_lim_ctrl_en = 0u; ++ } ++ ++ ret = peci_pcs_write(priv->mgr, PECI_MBX_INDEX_DDR_RAPL_PL1, ++ PECI_PCS_PARAM_ZERO, power_limit.value); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to write power limit\n"); ++ return ret; ++ } ++ ++ dev_dbg(priv->dev, "power limit %d, unit %u, raw power limit %u,\n", ++ val, priv->units.bits.pwr_unit, power_limit.bits.pp_pwr_lim); ++ ++ return ret; ++} ++ ++static int ++peci_dimmpower_read_max_power(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_dimmpower *priv = (struct peci_dimmpower *)ctx; ++ union peci_dram_power_info_high power_info; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = sensor_data->value; ++ dev_dbg(priv->dev, "skip reading peci, max power %dmW\n", ++ *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_pcs_read(priv->mgr, PECI_MBX_INDEX_DDR_PWR_INFO_HIGH, ++ PECI_PCS_PARAM_ZERO, &power_info.value); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read power info\n"); ++ return ret; ++ } ++ ++ *val = peci_pcs_xn_to_munits(power_info.bits.max_pwr, ++ priv->units.bits.pwr_unit); ++ ++ sensor_data->value = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "raw max power %u, unit %u, max power %dmW\n", ++ power_info.bits.max_pwr, priv->units.bits.pwr_unit, *val); ++ ++ return ret; ++} ++ ++static int ++peci_dimmpower_read_min_power(void *ctx, struct peci_sensor_conf *sensor_conf, ++ struct peci_sensor_data *sensor_data, ++ s32 *val) ++{ ++ struct peci_dimmpower *priv = (struct peci_dimmpower *)ctx; ++ union peci_dram_power_info_low power_info; ++ ulong jif; ++ int ret; ++ ++ if (!peci_sensor_need_update_with_time(sensor_data, ++ sensor_conf->update_interval)) { ++ *val = sensor_data->value; ++ dev_dbg(priv->dev, "skip reading peci, min power %dmW\n", ++ *val); ++ return 0; ++ } ++ ++ ret = peci_pcs_get_units(priv->mgr, &priv->units, &priv->units_valid); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read units\n"); ++ return ret; ++ } ++ ++ jif = jiffies; ++ ret = peci_pcs_read(priv->mgr, PECI_MBX_INDEX_DDR_PWR_INFO_LOW, ++ PECI_PCS_PARAM_ZERO, &power_info.value); ++ if (ret) { ++ dev_dbg(priv->dev, "not able to read power info\n"); ++ return ret; ++ } ++ ++ *val = peci_pcs_xn_to_munits(power_info.bits.min_pwr, ++ priv->units.bits.pwr_unit); ++ ++ sensor_data->value = *val; ++ peci_sensor_mark_updated_with_time(sensor_data, jif); ++ ++ dev_dbg(priv->dev, "raw min power %u, unit %u, min power %dmW\n", ++ power_info.bits.min_pwr, priv->units.bits.pwr_unit, *val); ++ ++ return ret; ++} ++ ++static struct peci_sensor_conf ++peci_dimmpower_cfg[PECI_DIMMPOWER_CHANNEL_COUNT] ++ [PECI_DIMMPOWER_SENSOR_COUNT] = { ++ /* Channel 0 - Power */ ++ { ++ { ++ .attribute = hwmon_power_average, ++ .config = HWMON_P_AVERAGE, ++ .update_interval = UPDATE_INTERVAL_100MS, ++ .read = peci_dimmpower_get_avg_power, ++ .write = NULL, ++ }, ++ { ++ .attribute = hwmon_power_cap, ++ .config = HWMON_P_CAP, ++ .update_interval = UPDATE_INTERVAL_100MS, ++ .read = peci_dimmpower_get_power_limit, ++ .write = peci_dimmpower_set_power_limit, ++ }, ++ { ++ .attribute = hwmon_power_cap_max, ++ .config = HWMON_P_CAP_MAX, ++ .update_interval = UPDATE_INTERVAL_10S, ++ .read = peci_dimmpower_read_max_power, ++ .write = NULL, ++ }, ++ { ++ .attribute = hwmon_power_cap_min, ++ .config = HWMON_P_CAP_MIN, ++ .update_interval = UPDATE_INTERVAL_10S, ++ .read = peci_dimmpower_read_min_power, ++ .write = NULL, ++ }, ++ }, ++}; ++ ++static int ++peci_dimmpower_read_string(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ if (attr != hwmon_power_label || ++ channel >= PECI_DIMMPOWER_CHANNEL_COUNT) ++ return -EOPNOTSUPP; ++ ++ if (str) ++ *str = peci_dimmpower_labels[channel]; ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ++peci_dimmpower_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct peci_dimmpower *priv = dev_get_drvdata(dev); ++ struct peci_sensor_conf *sensor_conf; ++ struct peci_sensor_data *sensor_data; ++ int ret; ++ ++ if (!priv || !val) ++ return -EINVAL; ++ ++ if (channel >= PECI_DIMMPOWER_CHANNEL_COUNT) ++ return -EOPNOTSUPP; ++ ++ ret = peci_sensor_get_ctx(attr, peci_dimmpower_cfg[channel], ++ &sensor_conf, priv->sensor_data_list[channel], ++ &sensor_data, ++ ARRAY_SIZE(peci_dimmpower_cfg[channel])); ++ if (ret) ++ return ret; ++ ++ if (sensor_conf->read) { ++ s32 tmp; ++ ++ ret = sensor_conf->read(priv, sensor_conf, sensor_data, &tmp); ++ if (!ret) ++ *val = (long)tmp; ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int ++peci_dimmpower_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct peci_dimmpower *priv = dev_get_drvdata(dev); ++ struct peci_sensor_conf *sensor_conf; ++ struct peci_sensor_data *sensor_data; ++ int ret; ++ ++ if (!priv) ++ return -EINVAL; ++ ++ if (channel >= PECI_DIMMPOWER_CHANNEL_COUNT) ++ return -EOPNOTSUPP; ++ ++ ret = peci_sensor_get_ctx(attr, peci_dimmpower_cfg[channel], ++ &sensor_conf, priv->sensor_data_list[channel], ++ &sensor_data, ++ ARRAY_SIZE(peci_dimmpower_cfg[channel])); ++ if (ret) ++ return ret; ++ ++ if (sensor_conf->write) { ++ ret = sensor_conf->write(priv, sensor_conf, sensor_data, ++ (s32)val); ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static umode_t ++peci_dimmpower_is_visible(const void *data, enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ struct peci_sensor_conf *sensor_conf; ++ umode_t mode = 0; ++ int ret; ++ ++ if (channel >= PECI_DIMMPOWER_CHANNEL_COUNT) ++ return mode; ++ ++ if (attr == hwmon_power_label) ++ return 0444; ++ ++ ret = peci_sensor_get_ctx(attr, peci_dimmpower_cfg[channel], ++ &sensor_conf, NULL, NULL, ++ ARRAY_SIZE(peci_dimmpower_cfg[channel])); ++ if (!ret) { ++ if (sensor_conf->read) ++ mode |= 0444; ++ if (sensor_conf->write) ++ mode |= 0200; ++ } ++ ++ return mode; ++} ++ ++static const struct hwmon_ops peci_dimmpower_ops = { ++ .is_visible = peci_dimmpower_is_visible, ++ .read_string = peci_dimmpower_read_string, ++ .read = peci_dimmpower_read, ++ .write = peci_dimmpower_write, ++}; ++ ++static int peci_dimmpower_probe(struct platform_device *pdev) ++{ ++ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); ++ struct device *dev = &pdev->dev; ++ struct peci_dimmpower *priv; ++ struct device *hwmon_dev; ++ u32 cmd_mask; ++ ++ cmd_mask = BIT(PECI_CMD_RD_PKG_CFG) | BIT(PECI_CMD_WR_PKG_CFG); ++ if ((mgr->client->adapter->cmd_mask & cmd_mask) != cmd_mask) ++ return -ENODEV; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ priv->mgr = mgr; ++ priv->dev = dev; ++ ++ snprintf(priv->name, PECI_NAME_SIZE, "peci_dimmpower.cpu%d", ++ mgr->client->addr - PECI_BASE_ADDR); ++ ++ priv->power_config[priv->config_idx] = HWMON_P_LABEL | ++ peci_sensor_get_config(peci_dimmpower_cfg[priv->config_idx], ++ ARRAY_SIZE(peci_dimmpower_cfg ++ [priv->config_idx])); ++ priv->config_idx++; ++ ++ priv->chip.ops = &peci_dimmpower_ops; ++ priv->chip.info = priv->info; ++ priv->info[0] = &priv->power_info; ++ ++ priv->power_info.type = hwmon_power; ++ priv->power_info.config = priv->power_config; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, priv->name, ++ priv, &priv->chip, ++ NULL); ++ ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name); ++ ++ return 0; ++} ++ ++static const struct platform_device_id peci_dimmpower_ids[] = { ++ { .name = "peci-dimmpower", .driver_data = 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(platform, peci_dimmpower_ids); ++ ++static struct platform_driver peci_dimmpower_driver = { ++ .probe = peci_dimmpower_probe, ++ .id_table = peci_dimmpower_ids, ++ .driver = { .name = KBUILD_MODNAME, }, ++}; ++module_platform_driver(peci_dimmpower_driver); ++ ++MODULE_AUTHOR("Zbigniew Lukwinski "); ++MODULE_DESCRIPTION("PECI dimmpower driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c +index f0e8ecc..84e5be0 100644 +--- a/drivers/mfd/intel-peci-client.c ++++ b/drivers/mfd/intel-peci-client.c +@@ -22,6 +22,7 @@ static struct mfd_cell peci_functions[] = { + { .name = "peci-cputemp", }, + { .name = "peci-dimmtemp", }, + { .name = "peci-cpupower", }, ++ { .name = "peci-dimmpower", }, + }; + + static const struct cpu_gen_info cpu_gen_info_table[] = { +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2019-19770/0001-blktrace-fix-debugfs-use-after-free.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2019-19770/0001-blktrace-fix-debugfs-use-after-free.patch new file mode 100644 index 000000000..a455a43c5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2019-19770/0001-blktrace-fix-debugfs-use-after-free.patch @@ -0,0 +1,214 @@ +From 1e1cea6eb8838117f676aaf6e0a465dd6a9addad Mon Sep 17 00:00:00 2001 +From: Luis Chamberlain +Date: Fri, 19 Jun 2020 20:47:28 +0000 +Subject: [PATCH] blktrace: fix debugfs use after free + +On commit 6ac93117ab00 ("blktrace: use existing disk debugfs directory") +merged on v4.12 Omar fixed the original blktrace code for request-based +drivers (multiqueue). This however left in place a possible crash, if you +happen to abuse blktrace while racing to remove / add a device. + +We used to use asynchronous removal of the request_queue, and with that +the issue was easier to reproduce. Now that we have reverted to +synchronous removal of the request_queue, the issue is still possible to +reproduce, its however just a bit more difficult. + +We essentially run two instances of break-blktrace which add/remove +a loop device, and setup a blktrace and just never tear the blktrace +down. We do this twice in parallel. This is easily reproduced with the +script run_0004.sh from break-blktrace [0]. + +We can end up with two types of panics each reflecting where we +race, one a failed blktrace setup: + +[ 252.426751] debugfs: Directory 'loop0' with parent 'block' already present! +[ 252.432265] BUG: kernel NULL pointer dereference, address: 00000000000000a0 +[ 252.436592] #PF: supervisor write access in kernel mode +[ 252.439822] #PF: error_code(0x0002) - not-present page +[ 252.442967] PGD 0 P4D 0 +[ 252.444656] Oops: 0002 [#1] SMP NOPTI +[ 252.446972] CPU: 10 PID: 1153 Comm: break-blktrace Tainted: G E 5.7.0-rc2-next-20200420+ #164 +[ 252.452673] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 +[ 252.456343] RIP: 0010:down_write+0x15/0x40 +[ 252.458146] Code: eb ca e8 ae 22 8d ff cc cc cc cc cc cc cc cc cc cc cc cc + cc cc 0f 1f 44 00 00 55 48 89 fd e8 52 db ff ff 31 c0 ba 01 00 + 00 00 48 0f b1 55 00 75 0f 48 8b 04 25 c0 8b 01 00 48 89 + 45 08 5d +[ 252.463638] RSP: 0018:ffffa626415abcc8 EFLAGS: 00010246 +[ 252.464950] RAX: 0000000000000000 RBX: ffff958c25f0f5c0 RCX: ffffff8100000000 +[ 252.466727] RDX: 0000000000000001 RSI: ffffff8100000000 RDI: 00000000000000a0 +[ 252.468482] RBP: 00000000000000a0 R08: 0000000000000000 R09: 0000000000000001 +[ 252.470014] R10: 0000000000000000 R11: ffff958d1f9227ff R12: 0000000000000000 +[ 252.471473] R13: ffff958c25ea5380 R14: ffffffff8cce15f1 R15: 00000000000000a0 +[ 252.473346] FS: 00007f2e69dee540(0000) GS:ffff958c2fc80000(0000) knlGS:0000000000000000 +[ 252.475225] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 252.476267] CR2: 00000000000000a0 CR3: 0000000427d10004 CR4: 0000000000360ee0 +[ 252.477526] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[ 252.478776] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[ 252.479866] Call Trace: +[ 252.480322] simple_recursive_removal+0x4e/0x2e0 +[ 252.481078] ? debugfs_remove+0x60/0x60 +[ 252.481725] ? relay_destroy_buf+0x77/0xb0 +[ 252.482662] debugfs_remove+0x40/0x60 +[ 252.483518] blk_remove_buf_file_callback+0x5/0x10 +[ 252.484328] relay_close_buf+0x2e/0x60 +[ 252.484930] relay_open+0x1ce/0x2c0 +[ 252.485520] do_blk_trace_setup+0x14f/0x2b0 +[ 252.486187] __blk_trace_setup+0x54/0xb0 +[ 252.486803] blk_trace_ioctl+0x90/0x140 +[ 252.487423] ? do_sys_openat2+0x1ab/0x2d0 +[ 252.488053] blkdev_ioctl+0x4d/0x260 +[ 252.488636] block_ioctl+0x39/0x40 +[ 252.489139] ksys_ioctl+0x87/0xc0 +[ 252.489675] __x64_sys_ioctl+0x16/0x20 +[ 252.490380] do_syscall_64+0x52/0x180 +[ 252.491032] entry_SYSCALL_64_after_hwframe+0x44/0xa9 + +And the other on the device removal: + +[ 128.528940] debugfs: Directory 'loop0' with parent 'block' already present! +[ 128.615325] BUG: kernel NULL pointer dereference, address: 00000000000000a0 +[ 128.619537] #PF: supervisor write access in kernel mode +[ 128.622700] #PF: error_code(0x0002) - not-present page +[ 128.625842] PGD 0 P4D 0 +[ 128.627585] Oops: 0002 [#1] SMP NOPTI +[ 128.629871] CPU: 12 PID: 544 Comm: break-blktrace Tainted: G E 5.7.0-rc2-next-20200420+ #164 +[ 128.635595] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 +[ 128.640471] RIP: 0010:down_write+0x15/0x40 +[ 128.643041] Code: eb ca e8 ae 22 8d ff cc cc cc cc cc cc cc cc cc cc cc cc + cc cc 0f 1f 44 00 00 55 48 89 fd e8 52 db ff ff 31 c0 ba 01 00 + 00 00 48 0f b1 55 00 75 0f 65 48 8b 04 25 c0 8b 01 00 48 89 + 45 08 5d +[ 128.650180] RSP: 0018:ffffa9c3c05ebd78 EFLAGS: 00010246 +[ 128.651820] RAX: 0000000000000000 RBX: ffff8ae9a6370240 RCX: ffffff8100000000 +[ 128.653942] RDX: 0000000000000001 RSI: ffffff8100000000 RDI: 00000000000000a0 +[ 128.655720] RBP: 00000000000000a0 R08: 0000000000000002 R09: ffff8ae9afd2d3d0 +[ 128.657400] R10: 0000000000000056 R11: 0000000000000000 R12: 0000000000000000 +[ 128.659099] R13: 0000000000000000 R14: 0000000000000003 R15: 00000000000000a0 +[ 128.660500] FS: 00007febfd995540(0000) GS:ffff8ae9afd00000(0000) knlGS:0000000000000000 +[ 128.662204] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 128.663426] CR2: 00000000000000a0 CR3: 0000000420042003 CR4: 0000000000360ee0 +[ 128.664776] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[ 128.666022] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[ 128.667282] Call Trace: +[ 128.667801] simple_recursive_removal+0x4e/0x2e0 +[ 128.668663] ? debugfs_remove+0x60/0x60 +[ 128.669368] debugfs_remove+0x40/0x60 +[ 128.669985] blk_trace_free+0xd/0x50 +[ 128.670593] __blk_trace_remove+0x27/0x40 +[ 128.671274] blk_trace_shutdown+0x30/0x40 +[ 128.671935] blk_release_queue+0x95/0xf0 +[ 128.672589] kobject_put+0xa5/0x1b0 +[ 128.673188] disk_release+0xa2/0xc0 +[ 128.673786] device_release+0x28/0x80 +[ 128.674376] kobject_put+0xa5/0x1b0 +[ 128.674915] loop_remove+0x39/0x50 [loop] +[ 128.675511] loop_control_ioctl+0x113/0x130 [loop] +[ 128.676199] ksys_ioctl+0x87/0xc0 +[ 128.676708] __x64_sys_ioctl+0x16/0x20 +[ 128.677274] do_syscall_64+0x52/0x180 +[ 128.677823] entry_SYSCALL_64_after_hwframe+0x44/0xa9 + +The common theme here is: + +debugfs: Directory 'loop0' with parent 'block' already present + +This crash happens because of how blktrace uses the debugfs directory +where it places its files. Upon init we always create the same directory +which would be needed by blktrace but we only do this for make_request +drivers (multiqueue) block drivers. When you race a removal of these +devices with a blktrace setup you end up in a situation where the +make_request recursive debugfs removal will sweep away the blktrace +files and then later blktrace will also try to remove individual +dentries which are already NULL. The inverse is also possible and hence +the two types of use after frees. + +We don't create the block debugfs directory on init for these types of +block devices: + + * request-based block driver block devices + * every possible partition + * scsi-generic + +And so, this race should in theory only be possible with make_request +drivers. + +We can fix the UAF by simply re-using the debugfs directory for +make_request drivers (multiqueue) and only creating the ephemeral +directory for the other type of block devices. The new clarifications +on relying on the q->blk_trace_mutex *and* also checking for q->blk_trace +*prior* to processing a blktrace ensures the debugfs directories are +only created if no possible directory name clashes are possible. + +This goes tested with: + + o nvme partitions + o ISCSI with tgt, and blktracing against scsi-generic with: + o block + o tape + o cdrom + o media changer + o blktests + +This patch is part of the work which disputes the severity of +CVE-2019-19770 which shows this issue is not a core debugfs issue, but +a misuse of debugfs within blktace. + +Fixes: 6ac93117ab00 ("blktrace: use existing disk debugfs directory") +Reported-by: syzbot+603294af2d01acfdd6da@syzkaller.appspotmail.com +Signed-off-by: Luis Chamberlain +Reviewed-by: Christoph Hellwig +Cc: Bart Van Assche +Cc: Omar Sandoval +Cc: Hannes Reinecke +Cc: Nicolai Stange +Cc: Greg Kroah-Hartman +Cc: Michal Hocko +Cc: "Martin K. Petersen" +Cc: "James E.J. Bottomley" +Cc: yu kuai +Signed-off-by: Jens Axboe +Signed-off-by: Jae Hyun Yoo +--- + kernel/trace/blktrace.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c +index e7e483cdbea6..fc2ad395c61d 100644 +--- a/kernel/trace/blktrace.c ++++ b/kernel/trace/blktrace.c +@@ -508,10 +508,18 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, + if (!bt->msg_data) + goto err; + +- ret = -ENOENT; +- +- dir = debugfs_lookup(buts->name, blk_debugfs_root); +- if (!dir) ++#ifdef CONFIG_BLK_DEBUG_FS ++ /* ++ * When tracing whole make_request drivers (multiqueue) block devices, ++ * reuse the existing debugfs directory created by the block layer on ++ * init. For request-based block devices, all partitions block devices, ++ * and scsi-generic block devices we create a temporary new debugfs ++ * directory that will be removed once the trace ends. ++ */ ++ if (queue_is_mq(q) && bdev && bdev == bdev->bd_contains) ++ dir = q->debugfs_dir; ++ else ++#endif + bt->dir = dir = debugfs_create_dir(buts->name, blk_debugfs_root); + + bt->dev = dev; +@@ -552,8 +560,6 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, + + ret = 0; + err: +- if (dir && !bt->dir) +- dput(dir); + if (ret) + blk_trace_free(bt); + return ret; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0001-cgroup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0001-cgroup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch new file mode 100644 index 000000000..dd4fea693 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0001-cgroup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch @@ -0,0 +1,178 @@ +From ad0f75e5f57ccbceec13274e1e242f2b5a6397ed Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Thu, 2 Jul 2020 11:52:56 -0700 +Subject: [PATCH] cgroup: fix cgroup_sk_alloc() for sk_clone_lock() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When we clone a socket in sk_clone_lock(), its sk_cgrp_data is +copied, so the cgroup refcnt must be taken too. And, unlike the +sk_alloc() path, sock_update_netprioidx() is not called here. +Therefore, it is safe and necessary to grab the cgroup refcnt +even when cgroup_sk_alloc is disabled. + +sk_clone_lock() is in BH context anyway, the in_interrupt() +would terminate this function if called there. And for sk_alloc() +skcd->val is always zero. So it's safe to factor out the code +to make it more readable. + +The global variable 'cgroup_sk_alloc_disabled' is used to determine +whether to take these reference counts. It is impossible to make +the reference counting correct unless we save this bit of information +in skcd->val. So, add a new bit there to record whether the socket +has already taken the reference counts. This obviously relies on +kmalloc() to align cgroup pointers to at least 4 bytes, +ARCH_KMALLOC_MINALIGN is certainly larger than that. + +This bug seems to be introduced since the beginning, commit +d979a39d7242 ("cgroup: duplicate cgroup reference when cloning sockets") +tried to fix it but not compeletely. It seems not easy to trigger until +the recent commit 090e28b229af +("netprio_cgroup: Fix unlimited memory leak of v2 cgroups") was merged. + +Fixes: bd1060a1d671 ("sock, cgroup: add sock->sk_cgroup") +Reported-by: Cameron Berkenpas +Reported-by: Peter Geis +Reported-by: Lu Fengqi +Reported-by: Daniël Sonck +Reported-by: Zhang Qiang +Tested-by: Cameron Berkenpas +Tested-by: Peter Geis +Tested-by: Thomas Lamprecht +Cc: Daniel Borkmann +Cc: Zefan Li +Cc: Tejun Heo +Cc: Roman Gushchin +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Jae Hyun Yoo +--- + include/linux/cgroup-defs.h | 6 ++++-- + include/linux/cgroup.h | 4 +++- + kernel/cgroup/cgroup.c | 31 +++++++++++++++++++------------ + net/core/sock.c | 2 +- + 4 files changed, 27 insertions(+), 16 deletions(-) + +diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h +index 52661155f85f..4f1cd0edc57d 100644 +--- a/include/linux/cgroup-defs.h ++++ b/include/linux/cgroup-defs.h +@@ -790,7 +790,8 @@ struct sock_cgroup_data { + union { + #ifdef __LITTLE_ENDIAN + struct { +- u8 is_data; ++ u8 is_data : 1; ++ u8 no_refcnt : 1; + u8 padding; + u16 prioidx; + u32 classid; +@@ -800,7 +801,8 @@ struct sock_cgroup_data { + u32 classid; + u16 prioidx; + u8 padding; +- u8 is_data; ++ u8 no_refcnt : 1; ++ u8 is_data : 1; + } __packed; + #endif + u64 val; +diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h +index 4598e4da6b1b..618838c48313 100644 +--- a/include/linux/cgroup.h ++++ b/include/linux/cgroup.h +@@ -822,6 +822,7 @@ extern spinlock_t cgroup_sk_update_lock; + + void cgroup_sk_alloc_disable(void); + void cgroup_sk_alloc(struct sock_cgroup_data *skcd); ++void cgroup_sk_clone(struct sock_cgroup_data *skcd); + void cgroup_sk_free(struct sock_cgroup_data *skcd); + + static inline struct cgroup *sock_cgroup_ptr(struct sock_cgroup_data *skcd) +@@ -835,7 +836,7 @@ static inline struct cgroup *sock_cgroup_ptr(struct sock_cgroup_data *skcd) + */ + v = READ_ONCE(skcd->val); + +- if (v & 1) ++ if (v & 3) + return &cgrp_dfl_root.cgrp; + + return (struct cgroup *)(unsigned long)v ?: &cgrp_dfl_root.cgrp; +@@ -847,6 +848,7 @@ static inline struct cgroup *sock_cgroup_ptr(struct sock_cgroup_data *skcd) + #else /* CONFIG_CGROUP_DATA */ + + static inline void cgroup_sk_alloc(struct sock_cgroup_data *skcd) {} ++static inline void cgroup_sk_clone(struct sock_cgroup_data *skcd) {} + static inline void cgroup_sk_free(struct sock_cgroup_data *skcd) {} + + #endif /* CONFIG_CGROUP_DATA */ +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 1ea181a58465..dd247747ec14 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -6439,18 +6439,8 @@ void cgroup_sk_alloc_disable(void) + + void cgroup_sk_alloc(struct sock_cgroup_data *skcd) + { +- if (cgroup_sk_alloc_disabled) +- return; +- +- /* Socket clone path */ +- if (skcd->val) { +- /* +- * We might be cloning a socket which is left in an empty +- * cgroup and the cgroup might have already been rmdir'd. +- * Don't use cgroup_get_live(). +- */ +- cgroup_get(sock_cgroup_ptr(skcd)); +- cgroup_bpf_get(sock_cgroup_ptr(skcd)); ++ if (cgroup_sk_alloc_disabled) { ++ skcd->no_refcnt = 1; + return; + } + +@@ -6475,10 +6465,27 @@ void cgroup_sk_alloc(struct sock_cgroup_data *skcd) + rcu_read_unlock(); + } + ++void cgroup_sk_clone(struct sock_cgroup_data *skcd) ++{ ++ if (skcd->val) { ++ if (skcd->no_refcnt) ++ return; ++ /* ++ * We might be cloning a socket which is left in an empty ++ * cgroup and the cgroup might have already been rmdir'd. ++ * Don't use cgroup_get_live(). ++ */ ++ cgroup_get(sock_cgroup_ptr(skcd)); ++ cgroup_bpf_get(sock_cgroup_ptr(skcd)); ++ } ++} ++ + void cgroup_sk_free(struct sock_cgroup_data *skcd) + { + struct cgroup *cgrp = sock_cgroup_ptr(skcd); + ++ if (skcd->no_refcnt) ++ return; + cgroup_bpf_put(cgrp); + cgroup_put(cgrp); + } +diff --git a/net/core/sock.c b/net/core/sock.c +index d832c650287c..2e5b7870e5d3 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1926,7 +1926,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + /* sk->sk_memcg will be populated at accept() time */ + newsk->sk_memcg = NULL; + +- cgroup_sk_alloc(&newsk->sk_cgrp_data); ++ cgroup_sk_clone(&newsk->sk_cgrp_data); + + rcu_read_lock(); + filter = rcu_dereference(sk->sk_filter); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0002-cgroup-Fix-sock_cgroup_data-on-big-endian.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0002-cgroup-Fix-sock_cgroup_data-on-big-endian.patch new file mode 100644 index 000000000..e43c6489e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14356/0002-cgroup-Fix-sock_cgroup_data-on-big-endian.patch @@ -0,0 +1,39 @@ +From 14b032b8f8fce03a546dcf365454bec8c4a58d7d Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Thu, 9 Jul 2020 16:28:44 -0700 +Subject: [PATCH] cgroup: Fix sock_cgroup_data on big-endian. + +In order for no_refcnt and is_data to be the lowest order two +bits in the 'val' we have to pad out the bitfield of the u8. + +Fixes: ad0f75e5f57c ("cgroup: fix cgroup_sk_alloc() for sk_clone_lock()") +Reported-by: Guenter Roeck +Signed-off-by: David S. Miller +Signed-off-by: Jae Hyun Yoo +--- + include/linux/cgroup-defs.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h +index 4f1cd0edc57d..fee0b5547cd0 100644 +--- a/include/linux/cgroup-defs.h ++++ b/include/linux/cgroup-defs.h +@@ -792,6 +792,7 @@ struct sock_cgroup_data { + struct { + u8 is_data : 1; + u8 no_refcnt : 1; ++ u8 unused : 6; + u8 padding; + u16 prioidx; + u32 classid; +@@ -801,6 +802,7 @@ struct sock_cgroup_data { + u32 classid; + u16 prioidx; + u8 padding; ++ u8 unused : 6; + u8 no_refcnt : 1; + u8 is_data : 1; + } __packed; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-16166/0001-random32-update-the-net-random-state-on-interrupt-an.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-16166/0001-random32-update-the-net-random-state-on-interrupt-an.patch new file mode 100644 index 000000000..75633ae53 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-16166/0001-random32-update-the-net-random-state-on-interrupt-an.patch @@ -0,0 +1,116 @@ +From b99b4c8e75333bec61fd0a6683d1d856b2bb0c56 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Fri, 10 Jul 2020 15:23:19 +0200 +Subject: [PATCH] random32: update the net random state on interrupt and + activity + +This modifies the first 32 bits out of the 128 bits of a random CPU's +net_rand_state on interrupt or CPU activity to complicate remote +observations that could lead to guessing the network RNG's internal +state. + +Note that depending on some network devices' interrupt rate moderation +or binding, this re-seeding might happen on every packet or even almost +never. + +In addition, with NOHZ some CPUs might not even get timer interrupts, +leaving their local state rarely updated, while they are running +networked processes making use of the random state. For this reason, we +also perform this update in update_process_times() in order to at least +update the state when there is user or system activity, since it's the +only case we care about. + +Reported-by: Amit Klein +Suggested-by: Linus Torvalds +Cc: Eric Dumazet +Cc: "Jason A. Donenfeld" +Cc: Andy Lutomirski +Cc: Kees Cook +Cc: Thomas Gleixner +Cc: Peter Zijlstra +Cc: +Signed-off-by: Willy Tarreau +Signed-off-by: Linus Torvalds +Signed-off-by: Jae Hyun Yoo +--- + drivers/char/random.c | 1 + + include/linux/random.h | 3 +++ + kernel/time/timer.c | 8 ++++++++ + lib/random32.c | 2 +- + 4 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/char/random.c b/drivers/char/random.c +index 8ff28c14af7e..e877c20e0ee0 100644 +--- a/drivers/char/random.c ++++ b/drivers/char/random.c +@@ -1330,6 +1330,7 @@ void add_interrupt_randomness(int irq, int irq_flags) + + fast_mix(fast_pool); + add_interrupt_bench(cycles); ++ this_cpu_add(net_rand_state.s1, fast_pool->pool[cycles & 3]); + + if (unlikely(crng_init == 0)) { + if ((fast_pool->count >= 64) && +diff --git a/include/linux/random.h b/include/linux/random.h +index f189c927fdea..4d080e5ef6eb 100644 +--- a/include/linux/random.h ++++ b/include/linux/random.h +@@ -9,6 +9,7 @@ + + #include + #include ++#include + + #include + +@@ -117,6 +118,8 @@ struct rnd_state { + __u32 s1, s2, s3, s4; + }; + ++DECLARE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy; ++ + u32 prandom_u32_state(struct rnd_state *state); + void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes); + void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state); +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index 4820823515e9..226da9217f26 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1731,6 +1732,13 @@ void update_process_times(int user_tick) + scheduler_tick(); + if (IS_ENABLED(CONFIG_POSIX_TIMERS)) + run_posix_cpu_timers(); ++ ++ /* The current CPU might make use of net randoms without receiving IRQs ++ * to renew them often enough. Let's update the net_rand_state from a ++ * non-constant value that's not affine to the number of calls to make ++ * sure it's updated when there's some activity (we don't care in idle). ++ */ ++ this_cpu_add(net_rand_state.s1, rol32(jiffies, 24) + user_tick); + } + + /** +diff --git a/lib/random32.c b/lib/random32.c +index 763b920a6206..c4d317be2997 100644 +--- a/lib/random32.c ++++ b/lib/random32.c +@@ -48,7 +48,7 @@ static inline void prandom_state_selftest(void) + } + #endif + +-static DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy; ++DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy; + + /** + * prandom_u32_state - seeded pseudo-random number generator. +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend index 8250ec919..9bb40fe5c 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -83,10 +83,32 @@ SRC_URI += " \ file://0110-USB-gadget-fix-illegal-array-access-in-binding-with-.patch \ file://0111-Unconditionally-calculate-the-PECI-AW-FCS.patch \ file://0112-AST2600-enable-UART-routing.patch \ + file://0113-hwmon-peci-PCS-utils.patch \ + file://0114-hwmon-peci-cpupower-extension.patch \ + file://0115-hwmon-peci-dimmpower-implementation.patch \ file://0116-watchdog-aspeed-fix-AST2600-support.patch \ file://0117-Copy-raw-PECI-response-to-user-space-on-timeout.patch \ file://0118-Recalculate-AW-FCS-on-WrEndPointConfig-command.patch \ " +# CVE-2020-16166 vulnerability fix +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/CVE-2020-16166:" +SRC_URI += " \ + file://0001-random32-update-the-net-random-state-on-interrupt-an.patch \ + " + +# CVE-2019-19770 vulnerability fix +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/CVE-2019-19770:" +SRC_URI += " \ + file://0001-blktrace-fix-debugfs-use-after-free.patch \ + " + +# CVE-2020-14356 vulnerability fix +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/CVE-2020-14356:" +SRC_URI += " \ + file://0001-cgroup-fix-cgroup_sk_alloc-for-sk_clone_lock.patch \ + file://0002-cgroup-Fix-sock_cgroup_data-on-big-endian.patch \ + " + SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}" SRC_URI += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', 'file://debug.cfg', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor.bb b/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor.bb new file mode 100644 index 000000000..98d053219 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor.bb @@ -0,0 +1,25 @@ +SUMMARY = "Check for host in reset to disable the NCSI iface" +DESCRIPTION = "If the host is in reset, the NCSI NIC will not be \ + available, so this will manually disable the NIC" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:" + +PV = "1.0" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRC_URI = "\ + file://check-for-host-in-reset \ + file://${BPN}.service \ + " + +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "${BPN}.service" + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/check-for-host-in-reset ${D}/${bindir}/check-for-host-in-reset + +} diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/check-for-host-in-reset b/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/check-for-host-in-reset new file mode 100755 index 000000000..aa17aebf2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/check-for-host-in-reset @@ -0,0 +1,65 @@ +#!/bin/sh + +# PFR Boot Time Detection +# +# The Platform Firmware Recovery system is designed to confirm the server is +# running valid images. The server boot process is controlled with a +# programmable device. The programmable device prevents the system, and the +# BMC from booting until after it has confirmed the firmware images match a +# known checksum. Two reset controls are asserted while the checksum +# calculation is being performed. One prevents the BMC from booting, the other +# (RSMRST_N) prevents the main processors from leaving reset. +# +# If the BMC FW checksum is correct the BMC is allowed to boot. +# If the BIOS checksum fails the BIOS is not allowed to boot. +# In this condition the BMC will boot believing the NCSI NIC is functional. +# This will not be the case when RMSRST_N is asserted. The BIOS will not +# configure the shared NIC. The BMC will not be able to send or receive +# network traffic via the shared NIC. This becomes a problem depending on how +# the NCSI channel is configured. +# +# When the NCSI channel is configured using DHCP the BMC is unable to +# communicate to a DHCP server. Unable to acquire a valid IP state, the NCSI +# NIC is left DOWN. +# The problem that occurs is when the NIC is configured with a static +# address. The BMC is unable to determine the configuration state of the NCSI +# NIC, and behaves as if everything is working. The problem is the network +# routing table will, in most cases, be left in a state that prevents traffic +# from being sent/received from the dedicated NIC. This prevents network +# access to the BMC, which in turn leaves the system unrecoverable. +# +# The purpose of this script is to check for the assertion of the RSMRST_N +# control at BMC boot time. It will perform this test once. In the event the +# RSMRST_N is found to be asserted, the BMC will take the NCSI NIC down. No +# logic for detecting the deassertion will be performed. Once the new image +# for the BIOS has been transferred, and the checksum confirmed, the BMC will +# be reset by the programmable device. The programmable device will confirm +# the checksums, and release both the BMC and the BIOS to boot normally. +# +# Flow: +# The service will be a one-shot that waits for the network.target, as is done +# by BMCWeb. +# During a normal boot the RSMRST_N will not be asserted, and this script will +# not perform an action. +# When RSMRST_N is asserted the NCSI channel will be given a link down +# command. This regardless of static or DHCP configuration mode. + +GPIOFIND=/usr/bin/gpiofind +GPIOGET=/usr/bin/gpioget +RSMRST="RSMRST_N" + +# Read the assertion state from the RSMRST_N input +function get_rsmrst_state { + local __resultVal=$1 + local gpio_state=$($GPIOGET $($GPIOFIND "$RSMRST")) + eval $__resultVal="'$gpio_state'" + return 0 +} + +get_rsmrst_state rsmrst_val + +if [ "$rsmrst_val" -eq 0 ] +then + echo "RSMRST_N is asserted, take eth1 down" + ip link set down dev eth1 +fi diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/ncsi-monitor.service b/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/ncsi-monitor.service new file mode 100644 index 000000000..19554c94d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/ncsi-monitor/ncsi-monitor.service @@ -0,0 +1,11 @@ +[Unit] +Description=Check for host in reset +After=multi-user.target + +[Service] +Type=oneshot +Restart=no +ExecStart=/usr/bin/check-for-host-in-reset + +[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 index 2940610da..8976a4015 100644 --- 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 @@ -292,12 +292,6 @@ static void beep(const uint8_t& beepPriority) return; } - // Log into redfish event log - sd_journal_send("MESSAGE=BeepCode: Priority=%d", beepPriority, - "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", - "OpenBMC.0.1.BeepCode", "REDFISH_MESSAGE_ARGS=%d", - beepPriority, NULL); - beeper.beep(beepPriority); return; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch index 274dd044a..23eac280d 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch @@ -1,4 +1,4 @@ -From f388587781c3d874b13b50ad39e8674f0bc08049 Mon Sep 17 00:00:00 2001 +From 1f91d5708cbe30610c0c8bbc4910709b99b8f270 Mon Sep 17 00:00:00 2001 From: AppaRao Puli Date: Mon, 25 May 2020 16:14:39 +0530 Subject: [PATCH] EventService: https client support @@ -17,12 +17,12 @@ Tested: Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a Signed-off-by: AppaRao Puli --- - http/http_client.hpp | 270 +++++++++++++++++-------- + http/http_client.hpp | 325 +++++++++++++++++-------- redfish-core/include/event_service_manager.hpp | 2 +- - 2 files changed, 186 insertions(+), 86 deletions(-) + 2 files changed, 226 insertions(+), 101 deletions(-) diff --git a/http/http_client.hpp b/http/http_client.hpp -index e6a7db1..27d2af3 100644 +index e6a7db1..6d3d702 100644 --- a/http/http_client.hpp +++ b/http/http_client.hpp @@ -17,6 +17,7 @@ @@ -33,19 +33,42 @@ index e6a7db1..27d2af3 100644 #include #include -@@ -49,7 +50,10 @@ enum class ConnState +@@ -30,12 +31,14 @@ namespace crow + { + + static constexpr uint8_t maxRequestQueueSize = 50; ++static constexpr unsigned int httpReadBodyLimit = 1024; + + enum class ConnState + { + initialized, + connectInProgress, + connectFailed, ++ sslHandshakeInProgress, + connected, + sendInProgress, + sendFailed, +@@ -49,53 +52,97 @@ enum class ConnState class HttpClient : public std::enable_shared_from_this { private: -- boost::beast::tcp_stream conn; -+ boost::asio::io_context& ioc; + boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; -+ std::shared_ptr> sslConn; -+ std::shared_ptr conn; + boost::beast::tcp_stream conn; ++ std::optional> sslConn; boost::asio::steady_timer timer; - boost::beast::flat_buffer buffer; +- boost::beast::flat_buffer buffer; ++ boost::beast::flat_static_buffer buffer; ++ std::optional< ++ boost::beast::http::response_parser> ++ parser; boost::beast::http::request req; -@@ -62,14 +66,37 @@ class HttpClient : public std::enable_shared_from_this +- boost::beast::http::response res; + boost::asio::ip::tcp::resolver::results_type endpoint; +- std::vector> headers; ++ boost::beast::http::fields fields; + std::queue requestDataQueue; +- ConnState state; + std::string subId; std::string host; std::string port; std::string uri; @@ -55,59 +78,28 @@ index e6a7db1..27d2af3 100644 uint32_t retryIntervalSecs; std::string retryPolicyAction; bool runningTimer; ++ ConnState state; -+ inline boost::beast::tcp_stream& getConn() -+ { -+ if (useSsl) -+ { -+ return (boost::beast::get_lowest_layer(*sslConn)); -+ } -+ else -+ { -+ return (*conn); -+ } -+ } -+ void doConnect() { +- if (state == ConnState::connectInProgress) + if (useSsl) + { -+ sslConn = std::make_shared< -+ boost::beast::ssl_stream>(ioc, ctx); -+ } -+ else -+ { -+ conn = std::make_shared(ioc); ++ sslConn.emplace(conn, ctx); + } + - if (state == ConnState::connectInProgress) ++ if ((state == ConnState::connectInProgress) || ++ (state == ConnState::sslHandshakeInProgress)) { return; -@@ -77,25 +104,53 @@ class HttpClient : public std::enable_shared_from_this + } state = ConnState::connectInProgress; BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; - // Set a timeout on the operation -- conn.expires_after(std::chrono::seconds(30)); -- conn.async_connect(endpoint, [self(shared_from_this())]( -- const boost::beast::error_code& ec, -- const boost::asio::ip::tcp::resolver:: -- results_type::endpoint_type& ep) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "Connect " << ep -- << " failed: " << ec.message(); -- self->state = ConnState::connectFailed; -- self->checkQueue(); -- return; -- } -- self->state = ConnState::connected; -- BMCWEB_LOG_DEBUG << "Connected to: " << ep; - -- self->checkQueue(); -- }); ++ + auto respHandler = -+ [self(shared_from_this())](const boost::beast::error_code& ec, ++ [self(shared_from_this())](const boost::beast::error_code ec, + const boost::asio::ip::tcp::resolver:: + results_type::endpoint_type& ep) { + if (ec) @@ -119,7 +111,7 @@ index e6a7db1..27d2af3 100644 + return; + } + BMCWEB_LOG_DEBUG << "Connected to: " << ep; -+ if (self->useSsl) ++ if (self->sslConn) + { + self->performHandshake(); + } @@ -130,57 +122,91 @@ index e6a7db1..27d2af3 100644 + } + }; + -+ getConn().expires_after(std::chrono::seconds(30)); -+ getConn().async_connect(endpoint, std::move(respHandler)); + conn.expires_after(std::chrono::seconds(30)); +- conn.async_connect(endpoint, [self(shared_from_this())]( +- const boost::beast::error_code& ec, +- const boost::asio::ip::tcp::resolver:: +- results_type::endpoint_type& ep) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Connect " << ep +- << " failed: " << ec.message(); +- self->state = ConnState::connectFailed; +- self->checkQueue(); +- return; +- } +- self->state = ConnState::connected; +- BMCWEB_LOG_DEBUG << "Connected to: " << ep; ++ conn.async_connect(endpoint, std::move(respHandler)); + } -+ + +- self->checkQueue(); +- }); + void performHandshake() + { ++ if (state == ConnState::sslHandshakeInProgress) ++ { ++ return; ++ } ++ state = ConnState::sslHandshakeInProgress; ++ + sslConn->async_handshake( + boost::asio::ssl::stream_base::client, -+ [self(shared_from_this())](const boost::beast::error_code& ec) { ++ [self(shared_from_this())](const boost::beast::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "SSL handshake failed: " + << ec.message(); -+ self->state = ConnState::connectFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::connectFailed); + return; + } + self->state = ConnState::connected; -+ BMCWEB_LOG_DEBUG << "SSL Handshake successfull \n"; ++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull"; + + self->checkQueue(); + }); } void sendMessage(const std::string& data) -@@ -108,7 +163,10 @@ class HttpClient : public std::enable_shared_from_this - - BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; +@@ -106,100 +153,167 @@ class HttpClient : public std::enable_shared_from_this + } + state = ConnState::sendInProgress; +- BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; +- - req.version(static_cast(11)); // HTTP 1.1 +- req.target(uri); +- req.method(boost::beast::http::verb::post); ++ BMCWEB_LOG_DEBUG << host << ":" << port; + +- // Set headers +- for (const auto& [key, value] : headers) + req = {}; -+ res = {}; ++ for (const auto& field : fields) + { +- req.set(key, value); ++ req.set(field.name_string(), field.value()); + } + req.set(boost::beast::http::field::host, host); ++ req.set(boost::beast::http::field::content_type, "text/plain"); + -+ req.version(11); // HTTP 1.1 - req.target(uri); - req.method(boost::beast::http::verb::post); ++ req.version(static_cast(11)); // HTTP 1.1 ++ req.target(uri); ++ req.method(boost::beast::http::verb::post); + req.keep_alive(true); -@@ -123,83 +181,121 @@ class HttpClient : public std::enable_shared_from_this 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 boost::beast::error_code ec, + const std::size_t& bytesTransferred) { + if (ec) + { + BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); -+ self->state = ConnState::sendFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::sendFailed); + return; + } + BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " @@ -208,15 +234,15 @@ index e6a7db1..27d2af3 100644 - self->recvMessage(); - }); -+ getConn().expires_after(std::chrono::seconds(30)); -+ if (useSsl) ++ 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)); ++ boost::beast::http::async_write(conn, req, std::move(respHandler)); + } } @@ -227,109 +253,141 @@ index e6a7db1..27d2af3 100644 - conn, buffer, res, - [self(shared_from_this())](const boost::beast::error_code& ec, - const std::size_t& bytesTransferred) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "recvMessage() failed: " -- << ec.message(); -- self->state = ConnState::recvFailed; -- self->checkQueue(); -- return; -- } -- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " -- << bytesTransferred; -- boost::ignore_unused(bytesTransferred); + auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code& ec, ++ const boost::beast::error_code ec, + const std::size_t& bytesTransferred) { + if (ec && ec != boost::beast::http::error::partial_message) + { + BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message(); -+ self->state = ConnState::recvFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::recvFailed); + return; + } + BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " + << bytesTransferred; + boost::ignore_unused(bytesTransferred); - -- // Discard received data. We are not interested. -- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; -+ // Discard received data. We are not interested. -+ BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; - -- // Send is successful, Lets remove data from queue -- // check for next request data in queue. -- self->requestDataQueue.pop(); -- self->state = ConnState::idle; -- self->checkQueue(); -- }); ++ ++ // TODO: check for return status code and perform ++ // retry if fails(Ex: 40x). Take action depending on ++ // retry policy. ++ BMCWEB_LOG_DEBUG << "recvMessage() data: " ++ << self->parser->get().body(); ++ + // Send is successful, Lets remove data from queue + // check for next request data in queue. + self->requestDataQueue.pop(); -+ self->state = ConnState::idle; + -+ if (ec == boost::beast::http::error::partial_message) -+ { -+ // Least bothered about recv message. Partial -+ // message means, already data is sent. Lets close -+ // connection and let next request open connection -+ // to avoid truncated stream. -+ self->state = ConnState::closed; -+ self->doCloseAndCheckQueue(); -+ return; -+ } ++ // Transfer ownership of the response ++ self->parser->release(); + -+ self->checkQueue(); ++ // TODO: Implement the keep-alive connections. ++ // Most of the web servers close connection abruptly ++ // and might be reason due to which its observed that ++ // stream_truncated(Next read) or partial_message ++ // errors. So for now, closing connection and re-open ++ // for all cases. ++ self->doCloseAndCheckQueue(ConnState::closed); + }; + -+ getConn().expires_after(std::chrono::seconds(30)); -+ if (useSsl) ++ parser.emplace(std::piecewise_construct, std::make_tuple()); ++ parser->body_limit(httpReadBodyLimit); ++ buffer.consume(buffer.size()); ++ ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) + { -+ boost::beast::http::async_read(*sslConn, buffer, res, ++ boost::beast::http::async_read(*sslConn, buffer, *parser, + std::move(respHandler)); + } + else + { -+ boost::beast::http::async_read(*conn, buffer, res, ++ boost::beast::http::async_read(conn, buffer, *parser, + std::move(respHandler)); + } - } - ++ } ++ ++ void doCloseAndCheckQueue(const ConnState setState = ConnState::closed) ++ { ++ if (sslConn) ++ { ++ conn.expires_after(std::chrono::seconds(30)); ++ sslConn->async_shutdown([self = shared_from_this(), ++ setState{std::move(setState)}]( ++ const boost::system::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "recvMessage() failed: " +- << ec.message(); +- self->state = ConnState::recvFailed; +- self->checkQueue(); +- 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_ERROR ++ << "doCloseAndCheckQueue(): Connection " ++ "closed by server. "; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); ++ } + } +- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); +- +- // Discard received data. We are not interested. +- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; +- +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- self->requestDataQueue.pop(); +- self->state = ConnState::idle; ++ else ++ { ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; ++ } ++ self->conn.cancel(); ++ self->state = setState; + self->checkQueue(); + }); +- } +- - void doClose() -+ void doCloseAndCheckQueue() - { - boost::beast::error_code ec; +- { +- boost::beast::error_code ec; - conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); -+ getConn().cancel(); -+ getConn().expires_after(std::chrono::seconds(30)); -+ getConn().socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, -+ ec); - +- - state = ConnState::closed; - // not_connected happens sometimes so don't bother reporting it. - if (ec && ec != boost::beast::errc::not_connected) -+ if (ec && ec != boost::asio::error::eof) ++ } ++ else { - BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); - 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) ++ boost::beast::error_code ec; ++ conn.expires_after(std::chrono::seconds(30)); ++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ++ ec); ++ if (ec) + { -+ BMCWEB_LOG_DEBUG -+ << "doCloseAndCheckQueue(): Connection closed by server."; ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); + } + else + { -+ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " -+ << ec.message(); ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; + } - } + -+ getConn().close(); - BMCWEB_LOG_DEBUG << "Connection closed gracefully"; -+ checkQueue(); ++ conn.close(); ++ state = setState; ++ checkQueue(); + } +- BMCWEB_LOG_DEBUG << "Connection closed gracefully"; + return; } @@ -344,7 +402,7 @@ index e6a7db1..27d2af3 100644 BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; return; } -@@ -257,17 +353,20 @@ class HttpClient : public std::enable_shared_from_this +@@ -257,16 +371,17 @@ class HttpClient : public std::enable_shared_from_this BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs << " seconds. RetryCount = " << retryCount; timer.expires_after(std::chrono::seconds(retryIntervalSecs)); @@ -360,38 +418,66 @@ index e6a7db1..27d2af3 100644 + }); return; } - else +- else ++ ++ if (state == ConnState::idle) { - // reset retry count. -- retryCount = 0; -+ if (state == ConnState::idle) -+ { -+ // State idle means, previous attempt is successful. -+ retryCount = 0; -+ } ++ // State idle means, previous attempt is successful. + retryCount = 0; } connStateCheck(); - -@@ -310,10 +409,11 @@ class HttpClient : public std::enable_shared_from_this +@@ -279,6 +394,7 @@ class HttpClient : public std::enable_shared_from_this + switch (state) + { + case ConnState::connectInProgress: ++ case ConnState::sslHandshakeInProgress: + case ConnState::sendInProgress: + case ConnState::suspended: + case ConnState::terminated: +@@ -310,15 +426,19 @@ class HttpClient : public std::enable_shared_from_this public: explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, const std::string& destIP, const std::string& destPort, - const std::string& destUri) : -- conn(ioc), + const std::string& destUri, + const bool inUseSsl = true) : -+ ioc(ioc), + conn(ioc), timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), - retryCount(0), maxRetryAttempts(5), +- retryPolicyAction("TerminateAfterRetries"), runningTimer(false) + useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), - retryPolicyAction("TerminateAfterRetries"), runningTimer(false) ++ retryPolicyAction("TerminateAfterRetries"), runningTimer(false), ++ state(ConnState::initialized) { boost::asio::ip::tcp::resolver resolver(ioc); ++ // TODO: Use async_resolver. boost asio example ++ // code as is crashing with async_resolve(). ++ // It needs debug. + endpoint = resolver.resolve(host, port); +- state = ConnState::initialized; + } + + void sendData(const std::string& data) +@@ -344,7 +464,12 @@ class HttpClient : public std::enable_shared_from_this + void setHeaders( + const std::vector>& httpHeaders) + { +- headers = httpHeaders; ++ // Set headers ++ for (const auto& [key, value] : httpHeaders) ++ { ++ // TODO: Validate the header fileds before assign. ++ fields.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 6362112..3ab2605 100644 +index 9c42e06..2a02920 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp -@@ -383,7 +383,7 @@ class Subscription +@@ -384,7 +384,7 @@ class Subscription { conn = std::make_shared( crow::connections::systemBus->get_io_context(), id, host, port, diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch new file mode 100644 index 000000000..ccf13e2af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch @@ -0,0 +1,231 @@ +From 7e50451bc8d4c4e8fa5ee1b0e2af86c800ea2efc Mon Sep 17 00:00:00 2001 +From: jayaprakash Mutyala +Date: Mon, 13 Apr 2020 23:31:06 +0000 +Subject: [PATCH] cpudimm: get cpu details from Redfish + +Modified the code to fetch cpu details from Redfish + +Note: This patch will be removed after code is up streamed. +https://gerrit.openbmc-project.xyz/#/c/openbmc/bmcweb/+/31294/ + +Tested: +1. Verified redfish validator passed +2. Get cpu details from Redfish +GET: https:///redfish/v1/Systems/system/Processors/cpu0 +Response: +{ + "@odata.id": "/redfish/v1/Systems/system/Processors/cpu0", + "@odata.type": "#Processor.v1_7_0.Processor", + "Id": "cpu0", + "InstructionSet": "x86-64", + "Manufacturer": "Intel(R) Corporation", + "MaxSpeedMHz": 4000, + "Model": "", + "Name": "Central Processor", + "ProcessorArchitecture": "x86", + "ProcessorId": { + "EffectiveFamily": "Intel Xeon processor", + "VendorId": "329300" + }, + "ProcessorType": "CPU", + "SerialNumber": "", + "Socket": "CPU0", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + }, + "TotalCores": 18, + "TotalThreads": 36, + "Version": "Intel(R) Xeon(R) Gold 6139 CPU @ 2.30GHz" +} + +GET: https:///redfish/v1/Systems/system/Processors/cpu1 +Response: +{ + "@odata.id": "/redfish/v1/Systems/system/Processors/cpu1", + "@odata.type": "#Processor.v1_7_0.Processor", + "Id": "cpu1", + "Name": "Processor", + "ProcessorType": "CPU", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Absent" + } +} + +Signed-off-by: jayaprakash Mutyala +Change-Id: Idcad6e643684f4912f24c259b075a443e1da5007 +--- + redfish-core/lib/cpudimm.hpp | 81 ++++++++++++++++++++---------------- + 1 file changed, 46 insertions(+), 35 deletions(-) + +diff --git a/redfish-core/lib/cpudimm.hpp b/redfish-core/lib/cpudimm.hpp +index ed5e641..e332a11 100644 +--- a/redfish-core/lib/cpudimm.hpp ++++ b/redfish-core/lib/cpudimm.hpp +@@ -73,8 +73,13 @@ void getCpuDataByInterface(std::shared_ptr aResp, + { + BMCWEB_LOG_DEBUG << "Get CPU resources by interface."; + +- const bool* present = nullptr; +- const bool* functional = nullptr; ++ // Added for future purpose. Once present and functional attributes added ++ // in busctl call, need to add actual logic to fetch original values. ++ bool present = false; ++ const bool functional = true; ++ auto health = std::make_shared(aResp); ++ health->populate(); ++ + for (const auto& interface : cpuInterfacesProperties) + { + for (const auto& property : interface.second) +@@ -93,10 +98,13 @@ void getCpuDataByInterface(std::shared_ptr aResp, + { + // Slot is not populated, set status end return + aResp->res.jsonValue["Status"]["State"] = "Absent"; +- aResp->res.jsonValue["Status"]["Health"] = "OK"; + // HTTP Code will be set up automatically, just return + return; + } ++ else ++ { ++ aResp->res.jsonValue["Status"]["State"] = "Enabled"; ++ } + + aResp->res.jsonValue["TotalCores"] = *coresCount; + } +@@ -104,7 +112,7 @@ void getCpuDataByInterface(std::shared_ptr aResp, + { + aResp->res.jsonValue["Name"] = property.second; + } +- else if (property.first == "Manufacturer") ++ else if (property.first == "ProcessorManufacturer") + { + const std::string* value = + std::get_if(&property.second); +@@ -128,50 +136,48 @@ void getCpuDataByInterface(std::shared_ptr aResp, + { + aResp->res.jsonValue["MaxSpeedMHz"] = property.second; + } +- else if (property.first == "ProcessorThreadCount") +- { +- aResp->res.jsonValue["TotalThreads"] = property.second; +- } +- else if (property.first == "Model") ++ else if (property.first == "ProcessorSocket") + { + const std::string* value = + std::get_if(&property.second); + if (value != nullptr) + { +- aResp->res.jsonValue["Model"] = *value; ++ aResp->res.jsonValue["Socket"] = *value; + } + } +- else if (property.first == "PartNumber") ++ else if (property.first == "ProcessorThreadCount") + { +- aResp->res.jsonValue["PartNumber"] = property.second; ++ aResp->res.jsonValue["TotalThreads"] = property.second; + } +- else if (property.first == "SerialNumber") ++ else if (property.first == "ProcessorFamily") + { +- aResp->res.jsonValue["SerialNumber"] = property.second; ++ const std::string* value = ++ std::get_if(&property.second); ++ if (value != nullptr) ++ { ++ aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] = ++ *value; ++ } + } +- else if (property.first == "Version") ++ else if (property.first == "ProcessorVersion") + { + aResp->res.jsonValue["Version"] = property.second; + } +- else if (property.first == "Present") +- { +- present = std::get_if(&property.second); +- } +- else if (property.first == "Functional") ++ else if (property.first == "ProcessorId") + { +- functional = std::get_if(&property.second); ++ const uint32_t* value = std::get_if(&property.second); ++ ++ if (value != nullptr && *value != 0) ++ { ++ present = true; ++ aResp->res.jsonValue["ProcessorId"]["VendorId"] = ++ boost::lexical_cast(*value); ++ } + } + } + } + +- if ((present == nullptr) || (functional == nullptr)) +- { +- // Important property not in desired type +- messages::internalError(aResp->res); +- return; +- } +- +- if (*present == false) ++ if (present == false) + { + aResp->res.jsonValue["Status"]["State"] = "Absent"; + aResp->res.jsonValue["Status"]["Health"] = "OK"; +@@ -179,7 +185,7 @@ void getCpuDataByInterface(std::shared_ptr aResp, + else + { + aResp->res.jsonValue["Status"]["State"] = "Enabled"; +- if (*functional == true) ++ if (functional) + { + aResp->res.jsonValue["Status"]["Health"] = "OK"; + } +@@ -212,6 +218,7 @@ void getCpuDataByService(std::shared_ptr aResp, + aResp->res.jsonValue["Name"] = "Processor"; + aResp->res.jsonValue["ProcessorType"] = "CPU"; + ++ bool slotPresent = false; + std::string corePath = objPath + "/core"; + size_t totalCores = 0; + for (const auto& object : dbusData) +@@ -237,6 +244,7 @@ void getCpuDataByService(std::shared_ptr aResp, + { + if (*present == true) + { ++ slotPresent = true; + totalCores++; + } + } +@@ -249,13 +257,16 @@ void getCpuDataByService(std::shared_ptr aResp, + // In getCpuDataByInterface(), state and health are set + // based on the present and functional status. If core + // count is zero, then it has a higher precedence. +- if (totalCores == 0) ++ if (slotPresent) + { +- // Slot is not populated, set status end return +- aResp->res.jsonValue["Status"]["State"] = "Absent"; +- aResp->res.jsonValue["Status"]["Health"] = "OK"; ++ if (totalCores == 0) ++ { ++ // Slot is not populated, set status end return ++ aResp->res.jsonValue["Status"]["State"] = "Absent"; ++ aResp->res.jsonValue["Status"]["Health"] = "OK"; ++ } ++ aResp->res.jsonValue["TotalCores"] = totalCores; + } +- aResp->res.jsonValue["TotalCores"] = totalCores; + return; + }, + service, "/xyz/openbmc_project/inventory", +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch new file mode 100644 index 000000000..d210e3808 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch @@ -0,0 +1,138 @@ +From ea3f3da3b29c7ecca34c12f94ce1e0364cbf9d7c Mon Sep 17 00:00:00 2001 +From: jayaprakash Mutyala +Date: Fri, 29 May 2020 00:50:46 +0000 +Subject: [PATCH] systems: Fix for Processor Summary Model + +Issue: Processor summary is not showing model name as expected from + Redfish + +Fix: Add condition to fetch valid model name in processor summary + +Tested: +1. Verified redfish validator passed +2. Get system details from Redfish +GET: https:///redfish/v1/Systems/system/ +Before fix: +Response: + "ProcessorSummary": { + "Count": 2, + "Model": "Unknown Processor Family", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + } + }, + +After fix: +Response: + "ProcessorSummary": { + "Count": 1, + "Model": "Intel Xeon processor", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + } + }, + +Signed-off-by: jayaprakash Mutyala +Change-Id: I4af7132135aef26556839fabada623728b52be8b +--- + redfish-core/lib/systems.hpp | 73 +++++++++++++++++++++++------------- + 1 file changed, 46 insertions(+), 27 deletions(-) + +diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp +index 2baeaa7..884fbb6 100644 +--- a/redfish-core/lib/systems.hpp ++++ b/redfish-core/lib/systems.hpp +@@ -325,40 +325,59 @@ void getComputerSystem(std::shared_ptr aResp, + + if (properties.size() > 0) + { ++ const uint32_t* processorId = nullptr; ++ const std::string* procFamily = nullptr; ++ nlohmann::json& procSummary = ++ aResp->res.jsonValue["ProcessorSumm" ++ "ary"]; ++ nlohmann::json& procCount = ++ procSummary["Count"]; ++ ++ auto procCountPtr = procCount.get_ptr< ++ nlohmann::json:: ++ number_integer_t*>(); ++ if (procCountPtr == nullptr) ++ { ++ messages::internalError(aResp->res); ++ return; ++ } + for (const auto& property : properties) + { ++ ++ if (property.first == "ProcessorId") ++ { ++ processorId = ++ std::get_if( ++ &property.second); ++ if (nullptr != procFamily) ++ break; ++ continue; ++ } ++ + if (property.first == + "ProcessorFamily") + { +- const std::string* value = ++ procFamily = + std::get_if( + &property.second); +- if (value != nullptr) +- { +- nlohmann::json& +- procSummary = +- aResp->res.jsonValue +- ["ProcessorSumm" +- "ary"]; +- nlohmann::json& procCount = +- procSummary["Count"]; +- +- auto procCountPtr = +- procCount.get_ptr< +- nlohmann::json:: +- number_integer_t*>(); +- if (procCountPtr != nullptr) +- { +- // shouldn't be possible +- // to be nullptr +- *procCountPtr += 1; +- } +- procSummary["Status"] +- ["State"] = +- "Enabled"; +- procSummary["Model"] = +- *value; +- } ++ if (nullptr != processorId) ++ break; ++ continue; ++ } ++ } ++ ++ if (procFamily != nullptr && ++ processorId != nullptr) ++ { ++ if (procCountPtr != nullptr && ++ *processorId != 0) ++ { ++ *procCountPtr += 1; ++ procSummary["Status"]["State"] = ++ "Enabled"; ++ ++ procSummary["Model"] = ++ *procFamily; + } + } + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch new file mode 100644 index 000000000..64b3c1112 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch @@ -0,0 +1,112 @@ +From 455b1d4c687a5c14197af1c1aba80b579c75900e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Mon, 3 Aug 2020 22:23:12 +0530 +Subject: [PATCH 1/2] Fix: MetricReportDefinitions filter not working + +The metric reports are not sending when user configures +the MetricReportDefinitions filter. This is of odata json +object type. Corrected code to properly handle odata type +object and store it as string array to make filters faster. + +Tested: + - Created metric report EventService subscription type + with MetricReportDefinitions and events properly sent to + Event listener. + +Signed-off-by: AppaRao Puli +Change-Id: If96564219da7d38a2ee5e415b89824ba25cd686d +--- + redfish-core/include/event_service_manager.hpp | 4 ++-- + redfish-core/lib/event_service.hpp | 32 +++++++++++++++++++++----- + 2 files changed, 28 insertions(+), 8 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 214f1e4..7c47842 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -283,7 +283,7 @@ bool isFilterQuerySpecialChar(char c) + bool readSSEQueryParams(std::string sseFilter, std::string& formatType, + std::vector& messageIds, + std::vector& registryPrefixes, +- std::vector& metricReportDefinitions) ++ std::vector& metricReportDefinitions) + { + sseFilter.erase(std::remove_if(sseFilter.begin(), sseFilter.end(), + isFilterQuerySpecialChar), +@@ -369,7 +369,7 @@ class Subscription + std::vector registryMsgIds; + std::vector registryPrefixes; + std::vector httpHeaders; // key-value pair +- std::vector metricReportDefinitions; ++ std::vector metricReportDefinitions; + + Subscription(const Subscription&) = delete; + Subscription& operator=(const Subscription&) = delete; +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index 8bd30f5..f59d093 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -229,7 +229,7 @@ class EventDestinationCollection : public Node + std::optional> msgIds; + std::optional> regPrefixes; + std::optional> headers; +- std::optional> metricReportDefinitions; ++ std::optional> mrdJsonArray; + + if (!json_util::readJson( + req, res, "Destination", destUrl, "Context", context, +@@ -237,7 +237,7 @@ class EventDestinationCollection : public Node + "EventFormatType", eventFormatType, "HttpHeaders", headers, + "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, + "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", +- metricReportDefinitions)) ++ mrdJsonArray)) + { + return; + } +@@ -387,9 +387,24 @@ class EventDestinationCollection : public Node + subValue->retryPolicy = "TerminateAfterRetries"; + } + +- if (metricReportDefinitions) ++ if (mrdJsonArray) + { +- subValue->metricReportDefinitions = *metricReportDefinitions; ++ for (nlohmann::json& mrdObj : *mrdJsonArray) ++ { ++ std::string mrdUri; ++ if (json_util::getValueFromJsonObject(mrdObj, "@odata.id", ++ mrdUri)) ++ { ++ subValue->metricReportDefinitions.emplace_back(mrdUri); ++ } ++ else ++ { ++ messages::propertyValueFormatError( ++ asyncResp->res, mrdObj.dump(), ++ "MetricReportDefinitions"); ++ return; ++ } ++ } + } + + std::string id = +@@ -565,8 +580,13 @@ class EventDestination : public Node + subValue->registryPrefixes; + asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; + asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; +- asyncResp->res.jsonValue["MetricReportDefinitions"] = +- subValue->metricReportDefinitions; ++ ++ std::vector mrdJsonArray; ++ for (const auto& mdrUri : subValue->metricReportDefinitions) ++ { ++ mrdJsonArray.push_back({{"@odata.id", mdrUri}}); ++ } ++ asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; + } + + void doPatch(crow::Response& res, const crow::Request& req, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch new file mode 100644 index 000000000..90905762b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch @@ -0,0 +1,33 @@ +From f43d6ba7e32565a7881949070bd25cb13f50ebf7 Mon Sep 17 00:00:00 2001 +From: James Feist +Date: Thu, 27 Aug 2020 13:56:52 -0700 +Subject: [PATCH 1/1] Workaround: Fix memory leak + +Req caputures self not allowing the connection to +be freed. There is discussion in upstream about a +real fix, this should be kept downstream only. + +Tested: Sent 1000 connections, saw no VSZ increase + +Change-Id: I63440abbe0882ffe228395b5d3bc869f10048ddc +Signed-off-by: James Feist +--- + http/http_connection.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/http/http_connection.h b/http/http_connection.h +index 109a272..393c2e7 100644 +--- a/http/http_connection.h ++++ b/http/http_connection.h +@@ -422,6 +422,8 @@ class Connection : + { + adaptor.close(); + } ++ // HACK TO REMOVE MEMORY LEAK ++ req.reset(); + } + + void completeRequest() +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch new file mode 100644 index 000000000..d7df52ddf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch @@ -0,0 +1,67 @@ +From 27705854ade6832bc1e91dada33fee43ee4b2bc9 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Sun, 2 Aug 2020 17:03:10 +0530 +Subject: [PATCH 2/2] Fix: EventService stops sending events + +When redfish log file(/var/log/redfish) is recreated +by rsyslog daemon, EventService stops sending events +to subscribers. + +The rsyslog service take redfish log files to back up +as per design. EventService has inotify on redfish log +file modifications. It needs to be removed from inotify +watcher list and added with new File descriptor. +Corrected code to handle remove & add of new descriptor. +Also corrected code to properly handle last event timestamp. + +Tested: + - Ran stress test on redfish log file to create multiple + backup files and events sends to clients properly, in + all switching scenarios. + +Change-Id: Ic0378edfc2cae86d1f69f6df4c429d07c2744bdf +Signed-off-by: AppaRao Puli +--- + redfish-core/include/event_service_manager.hpp | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 7c47842..4671995 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -1019,6 +1019,7 @@ class EventServiceManager + #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES + void cacheLastEventTimestamp() + { ++ lastEventTStr.clear(); + std::ifstream logStream(redfishEventLogFile); + if (!logStream.good()) + { +@@ -1062,7 +1063,7 @@ class EventServiceManager + std::string logEntry; + while (std::getline(logStream, logEntry)) + { +- if (!startLogCollection) ++ if (!startLogCollection && !lastEventTStr.empty()) + { + if (boost::starts_with(logEntry, lastEventTStr)) + { +@@ -1160,9 +1161,12 @@ class EventServiceManager + if (fileWatchDesc != -1) + { + BMCWEB_LOG_DEBUG +- << "Redfish log file is already on " +- "inotify_add_watch."; +- return; ++ << "Remove and Add inotify watcher on " ++ "redfish event log file"; ++ // Remove existing inotify watcher and add ++ // with new redfish event log file. ++ inotify_rm_watch(inotifyFd, fileWatchDesc); ++ fileWatchDesc = -1; + } + + fileWatchDesc = inotify_add_watch( +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch new file mode 100644 index 000000000..57ec01c7b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch @@ -0,0 +1,32 @@ +From cf5ba2028909d4fa0ee3bba4b60620e72cd612f0 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Fri, 7 Aug 2020 01:37:28 +0530 +Subject: [PATCH] Deallocate memory during failed case + +Free memory during failed case inside +pamFunctionConversation() function. + +Tested: + - Pam authentication works as normal. + +Signed-off-by: AppaRao Puli +Change-Id: I81c06a3d674b0806c96e5847cda6f208795bd02c +--- + include/pam_authenticate.hpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp +index f2c7356..3e5c691 100644 +--- a/include/pam_authenticate.hpp ++++ b/include/pam_authenticate.hpp +@@ -30,6 +30,7 @@ inline int pamFunctionConversation(int numMsg, const struct pam_message** msg, + + if (resp == nullptr) + { ++ free(pass); + return PAM_AUTH_ERR; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch new file mode 100644 index 000000000..870b33249 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch @@ -0,0 +1,64 @@ +From e0e19506ac81b3fa858de30c90ed3d75e10df749 Mon Sep 17 00:00:00 2001 +From: srikanta mondal +Date: Wed, 12 Aug 2020 18:26:26 +0000 +Subject: [PATCH] System: Replace chassis name in Redfish + +Modify code to replace chassis name to WC_Baseboard + +Note: This patch will be removed after code is up streamed. +https://gerrit.openbmc-project.xyz/#/c/openbmc/bmcweb/+/31748/ + +Tested: +1. Verified redfish validator passed +2. Verified details from Redfish + +GET: https:///redfish/v1/Systems/system +Response: +{ + .... + "Links": { + "Chassis": [ + { + "@odata.id": "/redfish/v1/Chassis/WC_Baseboard" + } + ], + "ManagedBy": [ + { + "@odata.id": "/redfish/v1/Managers/bmc" + } + ] + }, + .... +} + +GET: https:///redfish/v1/Chassis/WC_Baseboard +Response: +{ + // SUCCESS +} + +Signed-off-by: James Feist +Signed-off-by: srikanta mondal +--- + redfish-core/lib/redfish_util.hpp | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/redfish-core/lib/redfish_util.hpp b/redfish-core/lib/redfish_util.hpp +index 5701712..3adb392 100644 +--- a/redfish-core/lib/redfish_util.hpp ++++ b/redfish-core/lib/redfish_util.hpp +@@ -57,9 +57,8 @@ void getMainChassisId(std::shared_ptr asyncResp, + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/inventory", 0, +- std::array{ +- "xyz.openbmc_project.Inventory.Item.Board", +- "xyz.openbmc_project.Inventory.Item.Chassis"}); ++ std::array{ ++ "xyz.openbmc_project.Inventory.Item.System"}); + } + } // namespace redfish + #endif +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch new file mode 100644 index 000000000..c7d4ca914 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch @@ -0,0 +1,54 @@ +From 6ab885e4cabe28f74050b7e996868e4d8387e94d Mon Sep 17 00:00:00 2001 +From: Ed Tanous +Date: Mon, 17 Aug 2020 15:04:58 -0700 +Subject: [PATCH] url_view throws if a parse error is found + +This causes a strange condition where the webserver crashes on bad urls. + +Tested: +Loaded on RPI. Verified that this particular crash no longer breaks the +fuzzer. + +Signed-off-by: Ed Tanous +Signed-off-by: James Feist +Signed-off-by: AppaRao Puli +Change-Id: I459421e27c8d07c2bc45099b5942f7c7c929610d +--- + http/http_connection.h | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/http/http_connection.h b/http/http_connection.h +index 8dba3d6..8db8108 100644 +--- a/http/http_connection.h ++++ b/http/http_connection.h +@@ -728,9 +728,24 @@ class Connection : + return; + } + +- req->urlView = boost::urls::url_view(req->target()); +- req->url = req->urlView.encoded_path(); +- ++ // Note, despite the bmcweb coding policy on use of exceptions ++ // for error handling, this one particular use of exceptions is ++ // deemed acceptible, as it solved a significant error handling ++ // problem that resulted in seg faults, the exact thing that the ++ // exceptions rule is trying to avoid. If at some point, ++ // boost::urls makes the parser object public (or we port it ++ // into bmcweb locally) this will be replaced with ++ // parser::parse, which returns a status code ++ ++ try ++ { ++ req->urlView = boost::urls::url_view(req->target()); ++ req->url = req->urlView.encoded_path(); ++ } ++ catch (std::exception& p) ++ { ++ BMCWEB_LOG_ERROR << p.what(); ++ } + crow::authorization::authenticate(*req, res, session); + + bool loggedIn = req && req->session; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch new file mode 100644 index 000000000..e6fd85f85 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch @@ -0,0 +1,44 @@ +From d7df47f5df9c6e389c3deeb418be8fb7c32bc6f4 Mon Sep 17 00:00:00 2001 +From: Chalapathi Venkataramashetty +Date: Tue, 25 Aug 2020 15:44:35 +0000 +Subject: [PATCH] add sufficient delay to create fw update object + +Add support to increase timeoutTimeSeconds to 10 secs to allow firmware +object to create successfully to proceed for firmware update. + +Tested: +Redfish validator passed. + +Updated the firmware using redfish for 16 times continuously. +POST: https:///redfish/v1/UpdateService/ + with binary file +firmware updated. +{ + "@odata.id": "/redfish/v1/TaskService/Tasks/0", + "@odata.type": "#Task.v1_4_3.Task", + "Id": "0", + "TaskState": "Running", + "TaskStatus": "OK" +} + +Signed-off-by: Chalapathi Venkataramashetty +--- + redfish-core/lib/update_service.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp +index 9407d75..ec5ab8c 100644 +--- a/redfish-core/lib/update_service.hpp ++++ b/redfish-core/lib/update_service.hpp +@@ -363,7 +363,7 @@ static void softwareInterfaceAdded(std::shared_ptr asyncResp, + static void monitorForSoftwareAvailable( + std::shared_ptr asyncResp, const crow::Request& req, + const std::string& url, const std::vector& imgUriTargets, +- int timeoutTimeSeconds = 5) ++ int timeoutTimeSeconds = 10) + { + // Only allow one FW update at a time + if (fwUpdateInProgress != false) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch new file mode 100644 index 000000000..6cc95eda5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch @@ -0,0 +1,72 @@ +From d61d668f6db81bed90f41c3a128ce6fd652cc98c Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" +Date: Wed, 12 Aug 2020 14:45:32 -0700 +Subject: [PATCH] Add firmware activation messages to the registry + +In some situations a firmware requires activation rather than +update. These messages are intended to cover those situations. + +Tested: +Logged these events and confirmed that they appear correctly in +Redfish. + +Change-Id: I6171b9584626e049349a26c414146f37c04768c7 +Signed-off-by: Jason M. Bills +--- + .../registries/openbmc_message_registry.hpp | 33 ++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp +index 236002e..58c085d 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.1.0", + "OpenBMC", + }; +-constexpr std::array registry = { ++constexpr std::array registry = { + MessageEntry{ + "ADDDCCorrectable", + { +@@ -443,6 +443,37 @@ constexpr std::array registry = { + {"string"}, + "None.", + }}, ++ MessageEntry{ ++ "FirmwareActivationCompleted", ++ { ++ "Indicates a firmware activation has completed successfully.", ++ "%1 firmware activation completed successfully.", ++ "OK", ++ "OK", ++ 1, ++ {"string"}, ++ "None.", ++ }}, ++ MessageEntry{"FirmwareActivationFailed", ++ { ++ "Indicates a firmware activation has failed.", ++ "%1 firmware activation failed: %2.", ++ "Warning", ++ "Warning", ++ 2, ++ {"string", "string"}, ++ "None.", ++ }}, ++ MessageEntry{"FirmwareActivationStarted", ++ { ++ "Indicates a firmware activation has started.", ++ "%1 firmware activation started.", ++ "OK", ++ "OK", ++ 1, ++ {"string"}, ++ "None.", ++ }}, + MessageEntry{"FirmwareUpdateCompleted", + { + "Indicates a firmware update has completed successfully.", +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-EventService-Fix-type-mismatch-in-MetricReport.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-EventService-Fix-type-mismatch-in-MetricReport.patch new file mode 100644 index 000000000..378ce6c47 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-EventService-Fix-type-mismatch-in-MetricReport.patch @@ -0,0 +1,83 @@ +From cdfc5cfad41bcfa3fc0e53023bd62bdadf15ad86 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" +Date: Fri, 24 Jul 2020 17:05:38 +0200 +Subject: [PATCH] EventService: Fix type mismatch in MetricReport + +Fix the type mismatch in MetricReport data which +is sent to Event Subscribers. Change below properties +type to match with MetricReport schema. + - Timestamp: It should be uint32_t type. + - MetricValue: It should be string type. + +Signed-off-by: Wludzik, Jozef +Signed-off-by: AppaRao Puli +Change-Id: I0a52b6963e7bedda89a216256f64764cd8799bf1 +--- + redfish-core/include/event_service_manager.hpp | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 3e3058f..0f5c6b7 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -38,7 +38,7 @@ namespace redfish + { + + using ReadingsObjType = +- std::vector>; ++ std::vector>; + using EventServiceConfig = std::tuple; + + static constexpr const char* eventFormatType = "Event"; +@@ -532,10 +532,12 @@ class Subscription + metricValuesArray.push_back({}); + nlohmann::json& entry = metricValuesArray.back(); + +- entry = {{"MetricId", std::get<0>(it)}, +- {"MetricProperty", std::get<1>(it)}, +- {"MetricValue", std::to_string(std::get<2>(it))}, +- {"Timestamp", std::get<3>(it)}}; ++ auto& [id, property, value, timestamp] = it; ++ ++ entry = {{"MetricId", id}, ++ {"MetricProperty", property}, ++ {"MetricValue", std::to_string(value)}, ++ {"Timestamp", crow::utility::getDateTime(timestamp)}}; + } + + nlohmann::json msg = { +@@ -1270,7 +1272,7 @@ class EventServiceManager + [idStr{std::move(idStr)}]( + const boost::system::error_code ec, + boost::container::flat_map< +- std::string, std::variant>& ++ std::string, std::variant>& + resp) { + if (ec) + { +@@ -1279,8 +1281,8 @@ class EventServiceManager + return; + } + +- const std::string* timestampPtr = +- std::get_if(&resp["Timestamp"]); ++ const int32_t* timestampPtr = ++ std::get_if(&resp["Timestamp"]); + if (!timestampPtr) + { + BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; +@@ -1307,8 +1309,9 @@ class EventServiceManager + std::shared_ptr entry = it.second; + if (entry->eventFormatType == metricReportFormatType) + { +- entry->filterAndSendReports(idStr, *timestampPtr, +- *readingsPtr); ++ entry->filterAndSendReports( ++ idStr, crow::utility::getDateTime(*timestampPtr), ++ *readingsPtr); + } + } + }, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch new file mode 100644 index 000000000..2b510e0b5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch @@ -0,0 +1,151 @@ +From 891a0a2deb616b7e3f135b5df8501947ce5d6ad4 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Tue, 8 Sep 2020 01:53:21 +0530 +Subject: [PATCH] Add MutualExclusiveProperties registry + +Add MutualExclusiveProperties message registry entry +and error message. +As per redfish specification, "RegistryPrefixes" and +"MessageIds" are mutually exclusive. So add check for +same in EventService and return MutualExclusiveProperties +error message. + +Tested: + - Create subscription failed with error(bad request) + when the request body contain both "RegistryPrefixes" + and "MessageIds". + +Change-Id: I4c14f946977bce2ced8a7f96eb85855117fde9a8 +Signed-off-by: AppaRao Puli +--- + redfish-core/include/error_messages.hpp | 14 +++++++++++ + .../include/registries/base_message_registry.hpp | 18 +++++++++++++- + redfish-core/lib/event_service.hpp | 10 ++++++++ + redfish-core/src/error_messages.cpp | 29 ++++++++++++++++++++++ + 4 files changed, 70 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp +index 0243be9..9a2d1ca 100644 +--- a/redfish-core/include/error_messages.hpp ++++ b/redfish-core/include/error_messages.hpp +@@ -787,6 +787,20 @@ nlohmann::json invalidUpload(const std::string& arg1, const std::string& arg2); + void invalidUpload(crow::Response& res, const std::string& arg1, + const std::string& arg2); + ++/** ++ * @brief Formats MutualExclusiveProperties message into JSON ++ * Message body: "The properties and are mutually exclusive." ++ * ++ * @param[in] arg1 Parameter of message that will replace %1 in its body. ++ * @param[in] arg2 Parameter of message that will replace %2 in its body. ++ * ++ * @returns Message MutualExclusiveProperties formatted to JSON */ ++nlohmann::json mutualExclusiveProperties(const std::string& arg1, ++ const std::string& arg2); ++ ++void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, ++ const std::string& arg2); ++ + } // namespace messages + + } // namespace redfish +diff --git a/redfish-core/include/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp +index 90aef56..7c385a0 100644 +--- a/redfish-core/include/registries/base_message_registry.hpp ++++ b/redfish-core/include/registries/base_message_registry.hpp +@@ -36,7 +36,7 @@ const Header header = { + constexpr const char* url = + "https://redfish.dmtf.org/registries/Base.1.8.1.json"; + +-constexpr std::array registry = { ++constexpr std::array registry = { + MessageEntry{ + "AccessDenied", + { +@@ -429,6 +429,22 @@ constexpr std::array registry = { + "Resolve other reported errors and retry the current operation.", + }}, + MessageEntry{ ++ "MutualExclusiveProperties", ++ { ++ "Indicates that the requested operation could not be completed, " ++ "because of a conflict properties.", ++ "The properties '%1' and '%2' are mutually exclusive.", ++ "Warning", ++ "Warning", ++ 2, ++ { ++ "string", ++ "string", ++ }, ++ "Ensure that the request body doesn't have mutually exclusive " ++ "properties and resubmit the request.", ++ }}, ++ MessageEntry{ + "NoOperation", + { + "Indicates that the requested operation will not perform any " +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index f59d093..4804d26 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -242,6 +242,16 @@ class EventDestinationCollection : public Node + return; + } + ++ if (regPrefixes && msgIds) ++ { ++ if (regPrefixes->size() && msgIds->size()) ++ { ++ messages::mutualExclusiveProperties( ++ asyncResp->res, "RegistryPrefixes", "MessageIds"); ++ return; ++ } ++ } ++ + // Validate the URL using regex expression + // Format: ://:/ + // protocol: http/https +diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp +index 160b73f..c6938ba 100644 +--- a/redfish-core/src/error_messages.cpp ++++ b/redfish-core/src/error_messages.cpp +@@ -1750,6 +1750,35 @@ nlohmann::json invalidUpload(const std::string& arg1, const std::string& arg2) + {"Resolution", "None."}}; + } + ++/** ++ * @internal ++ * @brief Formats MutualExclusiveProperties into JSON ++ * ++ * See header file for more information ++ * @endinternal ++ */ ++nlohmann::json mutualExclusiveProperties(const std::string& arg1, ++ const std::string& arg2) ++{ ++ return nlohmann::json{ ++ {"@odata.type", "#Message.v1_0_0.Message"}, ++ {"MessageId", "Base.1.5.0.MutualExclusiveProperties"}, ++ {"Message", "The properties " + arg1 + " and " + arg2 + ++ " are mutually exclusive."}, ++ {"MessageArgs", {arg1, arg2}}, ++ {"Severity", "Warning"}, ++ {"Resolution", ++ "Ensure that the request body doesn't contain mutually exclusive " ++ "properties and resubmit the request."}}; ++} ++ ++void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, ++ const std::string& arg2) ++{ ++ res.result(boost::beast::http::status::bad_request); ++ addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2)); ++} ++ + } // namespace messages + + } // namespace redfish +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch new file mode 100644 index 000000000..e2b8644d8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch @@ -0,0 +1,74 @@ +From c03fa3c7b6c98d299f18e106c1aabf655db10327 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Fri, 4 Sep 2020 16:44:52 +0530 +Subject: [PATCH] Add sse event sequence number + +Add sequence number to sse events. +This is different for event ID's. + +Tested: + - The sequence number increments properly + after sending sse events. + +Change-Id: I8f48082497094a0435d4a400cb8068c3af506a7a +Signed-off-by: AppaRao Puli +--- + redfish-core/include/event_service_manager.hpp | 2 +- + redfish-core/include/server_sent_events.hpp | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 4671995..1a99e54 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -415,7 +415,7 @@ class Subscription + + if (sseConn != nullptr) + { +- sseConn->sendData(eventSeqNum, msg); ++ sseConn->sendData(msg); + } + } + +diff --git a/redfish-core/include/server_sent_events.hpp b/redfish-core/include/server_sent_events.hpp +index 1c4d2a5..23517ca 100644 +--- a/redfish-core/include/server_sent_events.hpp ++++ b/redfish-core/include/server_sent_events.hpp +@@ -56,6 +56,7 @@ class ServerSentEvents : public std::enable_shared_from_this + SseConnState state; + int retryCount; + int maxRetryAttempts; ++ uint64_t sseEventId; + + void sendEvent(const std::string& id, const std::string& msg) + { +@@ -260,7 +261,7 @@ class ServerSentEvents : public std::enable_shared_from_this + + ServerSentEvents(const std::shared_ptr& adaptor) : + sseConn(std::move(adaptor)), state(SseConnState::startInit), +- retryCount(0), maxRetryAttempts(5) ++ retryCount(0), maxRetryAttempts(5), sseEventId(1) + { + startSSE(); + } +@@ -268,7 +269,7 @@ class ServerSentEvents : public std::enable_shared_from_this + ~ServerSentEvents() + {} + +- void sendData(const uint64_t& id, const std::string& data) ++ void sendData(const std::string& data) + { + if (state == SseConnState::suspended) + { +@@ -277,7 +278,7 @@ class ServerSentEvents : public std::enable_shared_from_this + + if (requestDataQueue.size() <= maxReqQueueSize) + { +- requestDataQueue.push(std::pair(id, data)); ++ requestDataQueue.push(std::pair(sseEventId++, data)); + checkQueue(true); + } + else +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch new file mode 100644 index 000000000..c6c0634ce --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch @@ -0,0 +1,108 @@ +From eb1f888660bd34bde0c049e48db2404803b57d6e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Tue, 8 Sep 2020 02:37:19 +0530 +Subject: [PATCH] EventService: Limit SSE connections as per design + +Limit the number of SSE connections for event service. + +Tested: + - Tried creating more than 10 SSE connections and it fails. + +Change-Id: I4c7aa5c05a832115717e1261e330350ce59ab630 +Signed-off-by: AppaRao Puli +--- + redfish-core/include/event_service_manager.hpp | 17 +++++++++++++++++ + redfish-core/lib/event_service.hpp | 14 +++++++++----- + 2 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 502a6f7..22d1f10 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -44,6 +44,9 @@ using EventServiceConfig = std::tuple; + static constexpr const char* eventFormatType = "Event"; + static constexpr const char* metricReportFormatType = "MetricReport"; + ++static constexpr const char* subscriptionTypeRedfishEvent = "RedfishEvent"; ++static constexpr const char* subscriptionTypeSSE = "SSE"; ++ + static constexpr const char* eventServiceFile = + "/var/lib/bmcweb/eventservice_config.json"; + +@@ -983,6 +986,20 @@ class EventServiceManager + return subscriptionsMap.size(); + } + ++ size_t getNumberOfSSESubscriptions() ++ { ++ size_t count = 0; ++ for (const auto& it : this->subscriptionsMap) ++ { ++ std::shared_ptr entry = it.second; ++ if (entry->subscriptionType == subscriptionTypeSSE) ++ { ++ count++; ++ } ++ } ++ return count; ++ } ++ + std::vector getAllIDs() + { + std::vector idList; +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index 4804d26..f14c03e 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -27,6 +27,7 @@ static constexpr const std::array supportedRetryPolicies = { + "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; + + static constexpr const uint8_t maxNoOfSubscriptions = 20; ++static constexpr const uint8_t maxNoOfSSESubscriptions = 10; + + class EventService : public Node + { +@@ -307,7 +308,7 @@ class EventDestinationCollection : public Node + + if (subscriptionType) + { +- if (*subscriptionType != "RedfishEvent") ++ if (*subscriptionType != subscriptionTypeRedfishEvent) + { + messages::propertyValueNotInList( + asyncResp->res, *subscriptionType, "SubscriptionType"); +@@ -317,7 +318,8 @@ class EventDestinationCollection : public Node + } + else + { +- subValue->subscriptionType = "RedfishEvent"; // Default ++ subValue->subscriptionType = ++ subscriptionTypeRedfishEvent; // Default + } + + if (protocol != "Redfish") +@@ -450,8 +452,10 @@ class EventServiceSSE : public Node + void doGet(crow::Response& res, const crow::Request& req, + const std::vector& params) override + { +- if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= +- maxNoOfSubscriptions) ++ if ((EventServiceManager::getInstance().getNumberOfSubscriptions() >= ++ maxNoOfSubscriptions) || ++ EventServiceManager::getInstance().getNumberOfSSESubscriptions() >= ++ maxNoOfSSESubscriptions) + { + messages::eventSubscriptionLimitExceeded(res); + res.end(); +@@ -464,7 +468,7 @@ class EventServiceSSE : public Node + std::make_shared(sseConn); + + // GET on this URI means, Its SSE subscriptionType. +- subValue->subscriptionType = "SSE"; ++ subValue->subscriptionType = subscriptionTypeSSE; + + // Default values + subValue->protocol = "Redfish"; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch new file mode 100644 index 000000000..8f3e1fc9b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch @@ -0,0 +1,262 @@ +From 5fd71f098aad2f6d64e94343738c43ffdff5709e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli +Date: Tue, 8 Sep 2020 16:19:30 +0530 +Subject: [PATCH] EventService: Validate SSE query filters + +Validate the query filters which are specified in +requested url and return with error if not supported. +Also RegistryPrefix and MessageId are mutually exclusive +as per redfish specification. so return error if user +specifies both. + +Tested: + - Checked with invalid query filters and it returns + the error. + +Change-Id: If07341f39d8c6b9bc229baae966f8569ebdd7b19 +Signed-off-by: AppaRao Puli +--- + redfish-core/include/error_messages.hpp | 9 ++ + .../include/registries/base_message_registry.hpp | 14 ++- + redfish-core/lib/event_service.hpp | 99 +++++++++++++++------- + redfish-core/src/error_messages.cpp | 26 ++++++ + 4 files changed, 116 insertions(+), 32 deletions(-) + +diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp +index 9a2d1ca..fd6bb48 100644 +--- a/redfish-core/include/error_messages.hpp ++++ b/redfish-core/include/error_messages.hpp +@@ -801,6 +801,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/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp +index 7c385a0..18085c8 100644 +--- a/redfish-core/include/registries/base_message_registry.hpp ++++ b/redfish-core/include/registries/base_message_registry.hpp +@@ -36,7 +36,7 @@ const Header header = { + constexpr const char* url = + "https://redfish.dmtf.org/registries/Base.1.8.1.json"; + +-constexpr std::array registry = { ++constexpr std::array registry = { + MessageEntry{ + "AccessDenied", + { +@@ -403,6 +403,18 @@ constexpr std::array registry = { + "Either the object is malformed or the URI is not correct. " + "Correct the condition and resubmit the request if it failed.", + }}, ++ MessageEntry{ ++ "InvalidQueryFilter", ++ { ++ "Indicates the request url contains invalid query filter.", ++ "The requested url contains the invalid query filter.", ++ "Warning", ++ "Warning", ++ 0, ++ {}, ++ "Ensure the correct query filter is specified in requested url " ++ "and resubmit the request if the operation failed.", ++ }}, + MessageEntry{"MalformedJSON", + { + "Indicates that the request body was malformed JSON. " +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index f14c03e..b91b745 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -462,73 +462,110 @@ class EventServiceSSE : public Node + return; + } + +- std::shared_ptr sseConn = +- std::make_shared(std::move(req.socket())); +- std::shared_ptr subValue = +- std::make_shared(sseConn); +- +- // GET on this URI means, Its SSE subscriptionType. +- subValue->subscriptionType = subscriptionTypeSSE; +- +- // Default values +- subValue->protocol = "Redfish"; +- subValue->retryPolicy = "TerminateAfterRetries"; +- +- boost::urls::url_view::params_type::iterator it = +- req.urlParams.find("$filter"); +- if (it == req.urlParams.end()) ++ // It supports only "$filter" query param. ++ if (req.urlParams.size() > 1) + { +- subValue->eventFormatType = "Event"; ++ messages::invalidQueryFilter(res); ++ res.end(); ++ return; + } + ++ 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; ++ } ++ else ++ { ++ queryFilters = it->value(); ++ } ++ } + else + { +- std::string filters = it->value(); +- // Reading from query params. +- bool status = readSSEQueryParams( +- filters, subValue->eventFormatType, subValue->registryMsgIds, +- subValue->registryPrefixes, subValue->metricReportDefinitions); ++ eventFormatType = "Event"; ++ } + ++ std::vector msgIds; ++ std::vector regPrefixes; ++ std::vector mrdsArray; ++ if (!queryFilters.empty()) ++ { ++ // Reading from query params. ++ bool status = readSSEQueryParams(queryFilters, eventFormatType, ++ msgIds, regPrefixes, mrdsArray); + if (!status) + { +- messages::invalidObject(res, filters); ++ messages::invalidObject(res, queryFilters); ++ res.end(); + return; + } + +- if (!subValue->eventFormatType.empty()) ++ // RegsitryPrefix and messageIds are mutuly exclusive as per redfish ++ // specification. ++ if (regPrefixes.size() && msgIds.size()) ++ { ++ messages::mutualExclusiveProperties(res, "RegistryPrefix", ++ "MessageId"); ++ res.end(); ++ return; ++ } ++ ++ if (!eventFormatType.empty()) + { + if (std::find(supportedEvtFormatTypes.begin(), + supportedEvtFormatTypes.end(), +- subValue->eventFormatType) == +- supportedEvtFormatTypes.end()) ++ eventFormatType) == supportedEvtFormatTypes.end()) + { +- messages::propertyValueNotInList( +- res, subValue->eventFormatType, "EventFormatType"); ++ messages::propertyValueNotInList(res, eventFormatType, ++ "EventFormatType"); ++ res.end(); + return; + } + } + else + { + // If nothing specified, using default "Event" +- subValue->eventFormatType.assign({"Event"}); ++ eventFormatType.assign({"Event"}); + } + +- if (!subValue->registryPrefixes.empty()) ++ if (!regPrefixes.empty()) + { +- for (const std::string& it : subValue->registryPrefixes) ++ for (const std::string& it : regPrefixes) + { + if (std::find(supportedRegPrefixes.begin(), + supportedRegPrefixes.end(), + it) == supportedRegPrefixes.end()) + { + messages::propertyValueNotInList(res, it, +- "RegistryPrefixes"); ++ "RegistryPrefix"); ++ res.end(); + return; + } + } + } + } + ++ std::shared_ptr sseConn = ++ std::make_shared(std::move(req.socket())); ++ std::shared_ptr subValue = ++ std::make_shared(sseConn); ++ ++ // GET on this URI means, Its SSE subscriptionType. ++ subValue->subscriptionType = subscriptionTypeSSE; ++ subValue->protocol = "Redfish"; ++ subValue->retryPolicy = "TerminateAfterRetries"; ++ subValue->eventFormatType = eventFormatType; ++ subValue->registryMsgIds = msgIds; ++ subValue->registryPrefixes = regPrefixes; ++ subValue->metricReportDefinitions = mrdsArray; ++ + std::string id = + EventServiceManager::getInstance().addSubscription(subValue, false); + if (id.empty()) +diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp +index c6938ba..290d3f2 100644 +--- a/redfish-core/src/error_messages.cpp ++++ b/redfish-core/src/error_messages.cpp +@@ -1779,6 +1779,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.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch deleted file mode 100644 index 75d49b6d6..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch +++ /dev/null @@ -1,78 +0,0 @@ -From b71f087a173c36a16526156fa34581673e2b860c Mon Sep 17 00:00:00 2001 -From: "Wludzik, Jozef" -Date: Fri, 24 Jul 2020 17:05:38 +0200 -Subject: [PATCH 6/6] Fix MetricReport timestamp for EventService - -Changed MetricReport timestamp type from std::string to int32_t. - -Signed-off-by: Wludzik, Jozef -Change-Id: I0a52b6963e7bedda89a216256f64764cd8799bf1 ---- - redfish-core/include/event_service_manager.hpp | 23 +++++++++++++---------- - 1 file changed, 13 insertions(+), 10 deletions(-) - -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index d2f4f2a..dc04ccb 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -38,7 +38,7 @@ namespace redfish - { - - using ReadingsObjType = -- std::vector>; -+ std::vector>; - using EventServiceConfig = std::tuple; - - static constexpr const char* eventFormatType = "Event"; -@@ -532,10 +532,12 @@ class Subscription - metricValuesArray.push_back({}); - nlohmann::json& entry = metricValuesArray.back(); - -- entry = {{"MetricId", std::get<0>(it)}, -- {"MetricProperty", std::get<1>(it)}, -- {"MetricValue", std::to_string(std::get<2>(it))}, -- {"Timestamp", std::get<3>(it)}}; -+ auto& [id, property, value, timestamp] = it; -+ -+ entry = {{"MetricId", id}, -+ {"MetricProperty", property}, -+ {"MetricValue", value}, -+ {"Timestamp", crow::utility::getDateTime(timestamp)}}; - } - - nlohmann::json msg = { -@@ -1266,7 +1268,7 @@ class EventServiceManager - [idStr{std::move(idStr)}]( - const boost::system::error_code ec, - boost::container::flat_map< -- std::string, std::variant>& -+ std::string, std::variant>& - resp) { - if (ec) - { -@@ -1275,8 +1277,8 @@ class EventServiceManager - return; - } - -- const std::string* timestampPtr = -- std::get_if(&resp["Timestamp"]); -+ const int32_t* timestampPtr = -+ std::get_if(&resp["Timestamp"]); - if (!timestampPtr) - { - BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; -@@ -1303,8 +1305,9 @@ class EventServiceManager - std::shared_ptr entry = it.second; - if (entry->eventFormatType == metricReportFormatType) - { -- entry->filterAndSendReports(idStr, *timestampPtr, -- *readingsPtr); -+ entry->filterAndSendReports( -+ idStr, crow::utility::getDateTime(*timestampPtr), -+ *readingsPtr); - } - } - }, --- -2.16.6 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend index 5a44eec78..52598bf15 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -20,6 +20,21 @@ SRC_URI += "file://0001-Firmware-update-support-for-StandBySpare.patch \ file://0005-EventService-https-client-support.patch \ file://0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch \ file://0006-Fix-Image-and-ImageName-values-in-schema.patch \ + file://0007-cpudimm-get-cpu-details-from-Redfish.patch \ + file://0008-systems-Fix-for-Processor-Summary-Model.patch \ + file://0009-Fix-MetricReportDefinitions-filter-not-working.patch \ + file://0010-Fix-EventService-stops-sending-events.patch \ + file://0011-Deallocate-memory-during-failed-case.patch \ + file://0012-System-Replace-chassis-name-in-Redfish.patch \ + file://0013-url_view-throws-if-a-parse-error-is-found.patch \ + file://0014-add-sufficient-delay-to-create-fw-update-object.patch \ + file://0009-Workaround-Fix-memory-leak.patch \ + file://0015-Add-firmware-activation-messages-to-the-registry.patch \ + file://0016-EventService-Fix-type-mismatch-in-MetricReport.patch \ + file://0017-Add-MutualExclusiveProperties-registry.patch \ + file://0018-Add-sse-event-sequence-number.patch \ + file://0019-EventService-Limit-SSE-connections-as-per-design.patch \ + file://0020-EventService-Validate-SSE-query-filters.patch \ " # Temporary downstream mirror of upstream patches, see telemetry\README for details @@ -28,7 +43,6 @@ SRC_URI += "file://telemetry/0001-Redfish-TelemetryService-schema-implementation file://telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch \ file://telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch \ file://telemetry/0005-Add-support-for-MetricDefinition-scheme.patch \ - file://telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch \ " # Temporary fix: Move it to service file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-transporthandler-Fix-for-invalid-VLAN-id.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-transporthandler-Fix-for-invalid-VLAN-id.patch new file mode 100644 index 000000000..6c55e54fe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-transporthandler-Fix-for-invalid-VLAN-id.patch @@ -0,0 +1,94 @@ +From 84c49dc17fecc69bdb88dbc7cfb4b67eff81a4e6 Mon Sep 17 00:00:00 2001 +From: jayaprakash Mutyala +Date: Mon, 18 May 2020 23:12:13 +0000 +Subject: [PATCH] transporthandler: Fix for invalid VLAN id + +Issue: Set LAN configuration, allowing invalid VLAN ID's and giving +exception when user trying to set VLAN. + +Fix: Add condition to return proper error for invalid VLAN ID's and add +a condition to skip exception temporarily. + +Tested: +Verified using ipmitool raw commands +Command: ipmitool raw 0x0c 0x01 0x1 0x14 0x00 0x80 //Set Lan, vlan id=0 +Response: Unable to send RAW command (channel=0x0 netfn=0xc lun=0x0 + cmd=0x1 rsp=0xcc): Invalid data field in request +Command: ipmitool raw 0x0c 0x01 0x1 0x14 0xff 0x8f + //Set Lan, vlan id=4095 +Response: Unable to send RAW command (channel=0x0 netfn=0xc lun=0x0 + cmd=0x1 rsp=0xcc): Invalid data field in request +Command: ipmitool raw 0x0c 0x01 0x1 0x14 0x00 0x82 +Response: //Success + +Command: ipmitool lan print 1 +Response: +Set in Progress : Set Complete +Auth Type Support : +Auth Type Enable : Callback : + : User : + : Operator : + : Admin : + : OEM : +IP Address Source : DHCP Address +IP Address : 0.0.0.0 +Subnet Mask : 255.255.255.255 +MAC Address : a6:41:81:e8:39:33 +Default Gateway IP : 10.190.164.1 +Default Gateway MAC : 00:00:00:00:00:00 +802.1q VLAN ID : 512 +RMCP+ Cipher Suites : 17 +Cipher Suite Priv Max : aaaaaaaaaaaaaaa + : X=Cipher Suite Unused + : c=CALLBACK + : u=USER + : o=OPERATOR + : a=ADMIN + : O=OEM +Bad Password Threshold : Not Available + +Command: ipmitool raw 0x0c 0x01 0x1 0x14 0x00 0x00 +Response: //Success +Command: ipmitool lan print 1 +Response: +...... +802.1q VLAN ID : Disabled + +Signed-off-by: jayaprakash Mutyala +Change-Id: I3d3fe1c9fa5d629fc88f13577d2ac138e9fd4933 +--- + transporthandler.cpp | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 3813d05..6e11535 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -772,7 +772,9 @@ void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service, + } + catch (const sdbusplus::exception::SdBusError& e) + { +- if (strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0) ++ if (strcmp(e.name(), ++ "xyz.openbmc_project.Common.Error.InternalFailure") != 0 && ++ strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0) + { + // We want to rethrow real errors + throw; +@@ -1538,8 +1540,12 @@ RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1, + lastDisabledVlan[channel] = vlan; + vlan = 0; + } +- channelCall(channel, vlan); ++ else if (vlan == 0 || vlan == VLAN_VALUE_MASK) ++ { ++ return responseInvalidFieldRequest(); ++ } + ++ channelCall(channel, vlan); + return responseSuccess(); + } + case LanParam::CiphersuiteSupport: +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0065-apphandler-Fix-for-set-system-Info-parameter-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0065-apphandler-Fix-for-set-system-Info-parameter-cmd.patch new file mode 100644 index 000000000..3366e309a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0065-apphandler-Fix-for-set-system-Info-parameter-cmd.patch @@ -0,0 +1,98 @@ +From 3c5e413b55e60bdf4c7c34d06485e00915a969dd Mon Sep 17 00:00:00 2001 +From: jayaprakash Mutyala +Date: Mon, 27 Apr 2020 23:00:05 +0000 +Subject: [PATCH] apphandler: Fix for set system Info parameter cmd + +Issue: Get System Info parameter command returning incorrect response if + set system info command set the values less than 16 bytes. + +Fix: Appending zero's if user setting less than 16 bytes data using set + system info parameter API. + +Tested: +Before: +Command: ipmitool raw 0x06 0x58 0x02 0x00 0x00 0x69 0x6e 0x74 0x65 0x6c + 0x2d 0x6f 0x70 0x65 0x6e 0x62 0x6d 0x63 //Set system info +Response: //success +Commands: ipmitool raw 0x06 0x59 0x00 0x02 0x00 0x00 //Get system info +Response: 11 00 00 69 6e 74 65 6c 2d 6f 70 65 6e 62 6d 63 + 2d 6d +Commands: ipmitool raw 0x06 0x58 0x08 0x00 0x00 0x69 0x6e 0x74 0x65 0x6c + 0x2d 0x6f 0x70 0x65 0x6e 0x62 0x6d 0x63 +Response: //success +Commands: ipmitool raw 0x06 0x58 0xff 0x00 0x00 0x69 0x6e 0x74 0x65 0x6c + 0x2d 0x6f 0x70 0x65 0x6e 0x62 0x6d 0x63 0x10 +Response: //success + +After: +Commands: ipmitool raw 0x06 0x58 0x02 0x00 0x00 0x69 0x6e 0x74 0x65 0x6c + 0x2d 0x6f 0x70 0x65 0x6e 0x62 0x6d 0x63 //Set system info +Response: //success +Commands: ipmitool raw 0x06 0x59 0x00 0x02 0x00 0x00 //Get system info +Response: 11 00 00 69 6e 74 65 6c 2d 6f 70 65 6e 62 6d 63 + 00 00 +Commands: ipmitool raw 0x06 0x58 0x08 0x00 0x00 0x69 0x6e 0x74 0x65 + 0x6c 0x2d 0x6f 0x70 0x65 0x6e 0x62 0x6d 0x63 //Set system info +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x58 rsp=0xcc): Invalid data field in request +Commands: ipmitool raw 0x06 0x58 0xff 0x00 0x00 0x69 0x6e 0x74 0x65 + 0x6c 0x2d 0x6f 0x70 0x65 0x6e 0x62 0x6d 0x63 0x10 + //Set system info +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x58 rsp=0x80): Unknown (0x80) + +Signed-off-by: jayaprakash Mutyala +Change-Id: I10be443df0bd5828f447919f919a9824352cc36b +--- + apphandler.cpp | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/apphandler.cpp b/apphandler.cpp +index d567fe3..8baff39 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -89,6 +89,10 @@ static constexpr const char* cmdMaskStr = "commandMask"; + static constexpr int base_16 = 16; + #endif // ENABLE_I2C_WHITELIST_CHECK + static constexpr uint8_t maxIPMIWriteReadSize = 144; ++static constexpr uint8_t oemCmdStart = 192; ++static constexpr uint8_t oemCmdEnd = 255; ++static constexpr uint8_t invalidParamSelectorStart = 8; ++static constexpr uint8_t invalidParamSelectorEnd = 191; + + /** + * @brief Returns the Version info from primary s/w object +@@ -1350,6 +1354,16 @@ ipmi::RspType ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1, + std::vector configData) + { ++ if (paramSelector >= invalidParamSelectorStart && ++ paramSelector <= invalidParamSelectorEnd) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd)) ++ { ++ return ipmi::responseParmNotSupported(); ++ } ++ + if (paramSelector == 0) + { + // attempt to set the 'set in progress' value (in parameter #0) +@@ -1375,6 +1389,13 @@ ipmi::RspType<> ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1, + return ipmi::responseInvalidFieldRequest(); + } + ++ // Append zero's to remaining bytes ++ if (configData.size() < configParameterLength) ++ { ++ fill_n(back_inserter(configData), ++ (configParameterLength - configData.size()), 0x00); ++ } ++ + if (!sysInfoParamStore) + { + sysInfoParamStore = std::make_unique(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-apphandler-Fix-for-total-session-slots-count.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-apphandler-Fix-for-total-session-slots-count.patch new file mode 100644 index 000000000..fd32f30b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-apphandler-Fix-for-total-session-slots-count.patch @@ -0,0 +1,64 @@ +From 80207e6202d0f2dad62e8c5d9e83704bfe68c07c Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala +Date: Sat, 4 Jul 2020 16:34:15 +0000 +Subject: [PATCH] apphandler: Fix for total session slots count + +Issue: Get session info shows 60 sessions as total number of sessions + for all medium_type as lan-802 channels instead actual sessions. + +Fix: Initialize the channel Info structure to empty to avoid wrong + calculation of total number of session slots for all channels + which are having medium_type as lan-802. + +Tested: +Verified using ipmitool command. +Before: +Command: ipmitool -I lanplus -H -C 17 -U root -P session info all +Response: +session handle : 129 +slot count : 60 +active sessions : 1 +user id : 1 +privilege level : ADMINISTRATOR +session type : IPMIv2/RMCP+ +channel number : 0x03 +console ip : 10.190.201.113 +console mac : 00:00:00:00:00:00 +console port : 42963 + +After: +Command: ipmitool -I lanplus -H -C 17 -U root -P session info all +Response: +session handle : 129 +slot count : 30 +active sessions : 1 +user id : 1 +privilege level : ADMINISTRATOR +session type : IPMIv2/RMCP+ +channel number : 0x03 +console ip : 10.190.201.113 +console mac : 00:00:00:00:00:00 +console port : 48994 + +Signed-off-by: Jayaprakash Mutyala +Change-Id: I9a4523bfbaeb0178f15e8b40f034b43d7ce4b8a0 +--- + apphandler.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 8baff39..4ba637f 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -944,7 +944,7 @@ uint8_t getTotalSessionCount() + while (ch < ipmi::maxIpmiChannels && + count < session::maxNetworkInstanceSupported) + { +- ipmi::ChannelInfo chInfo; ++ ipmi::ChannelInfo chInfo{}; + ipmi::getChannelInfo(ch, chInfo); + if (static_cast(chInfo.mediumType) == + ipmi::EChannelMediumType::lan8032) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0067-Fix-for-get-Channel-Info-cmd-for-reserved-channels.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0067-Fix-for-get-Channel-Info-cmd-for-reserved-channels.patch new file mode 100644 index 000000000..4b14110a6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0067-Fix-for-get-Channel-Info-cmd-for-reserved-channels.patch @@ -0,0 +1,61 @@ +From afd12b4ecc381e21b05e90368ccd29a96ff644b4 Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala +Date: Tue, 7 Jul 2020 01:06:57 +0000 +Subject: [PATCH] Fix for get Channel Info cmd for reserved channels + +Issue: Get channel info command returning improper response as "0x82" + which is not expected for reserved channels 5, 11, 12, 13. + +Fix: Return proper completion code for reserved channels. + +Tested: +Verified using ipmitool raw commands +Before: +Command: ipmitool raw 6 0x42 0x05 //get Channel Info +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0x82): Unknown (0x82) +Command: ipmitool raw 6 0x42 0x0b +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0x82): Unknown (0x82) +Command: ipmitool raw 6 0x42 0x0c +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0x82): Unknown (0x82) +Command: ipmitool raw 6 0x42 0x0d +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0x82): Unknown (0x82) +After: +Command: ipmitool raw 6 0x42 0x05 //get Channel Info +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0xcc): Invalid data field in request +Command: ipmitool raw 6 0x42 0x0b +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0xcc): Invalid data field in request +Command: ipmitool raw 6 0x42 0x0c +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0xcc): Invalid data field in request +Command: ipmitool raw 6 0x42 0x0d +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x42 rsp=0xcc): Invalid data field in request + +Signed-off-by: Jayaprakash Mutyala +Change-Id: Ic5a5bb2317ee301a1ecc37350cbe1b289d33ca38 +--- + user_channel/channelcommands.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/user_channel/channelcommands.cpp b/user_channel/channelcommands.cpp +index 4bf8071..6987e04 100644 +--- a/user_channel/channelcommands.cpp ++++ b/user_channel/channelcommands.cpp +@@ -258,7 +258,7 @@ RspType("Get channel Info - No support on channel"); +- return response(ccActionNotSupportedForChannel); ++ return responseInvalidFieldRequest(); + } + + ChannelInfo chInfo; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0068-Removal-of-OEM-privilege-setting-for-User.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0068-Removal-of-OEM-privilege-setting-for-User.patch new file mode 100644 index 000000000..d66f6fe32 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0068-Removal-of-OEM-privilege-setting-for-User.patch @@ -0,0 +1,43 @@ +From 785223a6867f7914e9f549cf06655034eea95b4e Mon Sep 17 00:00:00 2001 +From: srikanta mondal +Date: Fri, 10 Apr 2020 11:35:32 +0000 +Subject: [PATCH] Removal of OEM privilege setting for User + +Issue: Set OEM user Privilege is success for Set user access command + +Fix: Set user access - provided fix to deny set OEM user privilege + for all channel. + +Tested: +Before: +Command: ipmitool raw 0x06 0x43 0x93 0x07 0x05 0x00 // Set user access +Response: // Success + +After: +Command: ipmitool raw 0x06 0x43 0x93 0x07 0x05 0x00 // Set user access +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x43 rsp=0xcc): Invalid data field in request + +Signed-off-by: srikanta mondal +Change-Id: Iec38bd15d087a34b2178b8b578dc599817b7e3d1 +--- + user_channel/channel_layer.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/user_channel/channel_layer.cpp b/user_channel/channel_layer.cpp +index 38fd43f..03b1729 100644 +--- a/user_channel/channel_layer.cpp ++++ b/user_channel/channel_layer.cpp +@@ -45,7 +45,8 @@ bool doesDeviceExist(const uint8_t chNum) + bool isValidPrivLimit(const uint8_t privLimit) + { + // Callback privilege is deprecated in OpenBMC +- return ((privLimit > PRIVILEGE_CALLBACK) && (privLimit <= PRIVILEGE_OEM)); ++ // At present, "OEM Privilege" is not used in OpenBMC ++ return ((privLimit > PRIVILEGE_CALLBACK) && (privLimit < PRIVILEGE_OEM)); + } + + bool isValidAccessMode(const uint8_t accessMode) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0069-apphandler-Fix-for-get-system-info-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0069-apphandler-Fix-for-get-system-info-command.patch new file mode 100644 index 000000000..1d6410a6d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0069-apphandler-Fix-for-get-system-info-command.patch @@ -0,0 +1,89 @@ +From a5ae77282bdd60172f7ef1baca117069b8809bb5 Mon Sep 17 00:00:00 2001 +From: Snehalatha V +Date: Sat, 2 May 2020 18:18:57 +0000 +Subject: [PATCH] apphandler: Fix for get system info command + +Issue: Get system info parameters command giving improper default + results for parameters 1,3,4,5,6,7. + +Fix: Provided fix to return proper default response + +Tested: +Verified using ipmitool raw commands +Command : ipmitool raw 0x06 0x59 0x00 0x01 0x00 0x00 +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x59 rsp=0xcb): Requested sensor, data, or record not + found +Command : ipmitool raw 0x06 0x59 0x00 0x02 0x00 0x00 +Response: 11 00 00 0a 69 6e 74 65 6c 2d 6f 62 6d 63 00 00 + 00 00 +Command : ipmitool raw 0x06 0x59 0x00 0x03 0x00 0x00 +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x59 rsp=0xcb): Requested sensor, data, or record not + found +Command : ipmitool raw 0x06 0x59 0x00 0x07 0x00 0x00 +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x59 rsp=0xcb): Requested sensor, data, or record not + found +Command : ipmitool raw 0x06 0x59 0x00 0x08 0x00 0x00 +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x59 rsp=0xcc): Invalid data field in request +Command : ipmitool raw 0x06 0x59 0x00 0x3f 0x00 0x00 +Response: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 + cmd=0x59 rsp=0xcc): Invalid data field in request + +Signed-off-by: Snehalatha V +Change-Id: I2a98b91bad199dc4eeac68b68972c3355cb5ec2f +--- + apphandler.cpp | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 4ba637f..90818a9 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -1289,10 +1289,15 @@ ipmi::RspType= invalidParamSelectorStart && ++ paramSelector <= invalidParamSelectorEnd)) + { + return ipmi::responseInvalidFieldRequest(); + } ++ if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd)) ++ { ++ return ipmi::responseParmNotSupported(); ++ } + if (getRevision) + { + return ipmi::responseSuccess(paramRevision, std::nullopt, std::nullopt); +@@ -1322,7 +1327,7 @@ ipmi::RspType(ret); + if (!found) + { +- return ipmi::responseParmNotSupported(); ++ return ipmi::responseSensorInvalid(); + } + std::string& paramString = std::get<1>(ret); + std::vector configData; +@@ -1334,7 +1339,14 @@ ipmi::RspType +Date: Mon, 13 Jul 2020 16:43:59 +0530 +Subject: [PATCH 1/4] minor fix: corrected cc for get channel access + +As per IPMI spec, get channel access don't have +specific cc code 0x83(Access mode not supported). +Whereas set channel access has that specific cc. +So changed cc to generic 0xcc(invalid field request) +in get channel access mode command. + +Tested: +For reserved access mode byte 2 request, return 0xCC. +ipmitool -I lanplus -U <> -P <> -H raw 6 0x41 0x01 0x00 +Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0 +cmd=0x41 rsp=0xcc): Invalid data field in request + +Change-Id: I75256b9f74eddaf95a9f78d95730332877d21dfd +Signed-off-by: AppaRao Puli +--- + user_channel/channelcommands.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/user_channel/channelcommands.cpp b/user_channel/channelcommands.cpp +index 6987e04..b774d3f 100644 +--- a/user_channel/channelcommands.cpp ++++ b/user_channel/channelcommands.cpp +@@ -180,7 +180,7 @@ ipmi ::RspType("Get channel access - Invalid Access mode"); +- return response(ccAccessModeNotSupportedForChannel); ++ return responseInvalidFieldRequest(); + } + + const uint8_t chNum = +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0071-chassishandler-SetSystemBootOptions-to-new-API.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0071-chassishandler-SetSystemBootOptions-to-new-API.patch new file mode 100644 index 000000000..f6a9e9f35 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0071-chassishandler-SetSystemBootOptions-to-new-API.patch @@ -0,0 +1,821 @@ +From 8133e8bd818f986a9c5d373b3c56683560103214 Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala +Date: Thu, 3 Sep 2020 19:53:10 +0000 +Subject: [PATCH] chassishandler: SetSystemBootOptions to new API + +Rewrite ipmiChassisSetSysBootOptions to use newly introduced IPMI +provider API + +Tested: +verified using IPMI chassis bootparam command and raw commands +Command: ipmitool chassis bootparam set bootflag force_disk +Response: Set Boot Device to force_disk +Command: ipmitool chassis bootparam set bootflag force_pxe +Response: Set Boot Device to force_pxe +Command: ipmitool chassis bootdev pxe options=persistent +Response: Set Boot Device to pxe +Command: ipmitool chassis bootparam set bootflag force_bios +Response: Set Boot Device to force_bios +Command: ipmitool chassis bootparam set bootflag force_safe +Response: Set Chassis Boot Parameter 5 failed: Invalid data field in + request + +Command: ipmitool raw 0 8 0x5 0 0 0 0 0 //setBootOptions param 5 +Response: //Success +Command: ipmitool raw 0 8 0x4 0 0 //setBootOptions param 4 +Response: //Success +Command: ipmitool raw 0 8 0x61 0x21 0x70 0x62 0x21 0x00 0x01 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0x01 0x01 0x04 0 0 0 0 1 1 1 1 //setBootOptions param 61 +Response: //Success +Command: ipmitool raw 0 8 0 0 //setBootOptions param 0 +Response: //Success + +Signed-off-by: srikanta mondal +Signed-off-by: Jayaprakash Mutyala + +%% original patch: 0071-chassishandler-SetSystemBootOptions-to-new-API.patch +--- + chassishandler.cpp | 465 +++++++++++++++++++++++++++++---------------- + chassishandler.hpp | 15 +- + 2 files changed, 305 insertions(+), 175 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index f5e7375..ca7cd2c 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -35,37 +35,33 @@ + #include + #include + +-// Defines +-#define SET_PARM_VERSION 0x01 +-#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 +-#define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 +-#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 +- + std::unique_ptr identifyTimer + __attribute__((init_priority(101))); + + static ChassisIDState chassisIDState = ChassisIDState::reserved; +- +-constexpr size_t SIZE_MAC = 18; +-constexpr size_t SIZE_BOOT_OPTION = (uint8_t) +- BootOptionResponseSize::OPAL_NETWORK_SETTINGS; // Maximum size of the boot +- // option parametrs +-constexpr size_t SIZE_PREFIX = 7; +-constexpr size_t MAX_PREFIX_VALUE = 32; +-constexpr size_t SIZE_COOKIE = 4; +-constexpr size_t SIZE_VERSION = 2; ++static constexpr uint8_t setParmVersion = 0x01; ++static constexpr uint8_t setParmBootFlagsPermanent = 0x40; ++static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80; ++static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0; ++ ++constexpr size_t SIZE_BOOT_OPTION = static_cast( ++ BootOptionResponseSize::opalNetworkSettings); // Maximum size of the boot ++ // option parameters ++constexpr size_t sizeVersion = 2; + constexpr size_t DEFAULT_IDENTIFY_TIME_OUT = 15; + + // PetiBoot-Specific +-static constexpr uint8_t net_conf_initial_bytes[] = {0x80, 0x21, 0x70, 0x62, +- 0x21, 0x00, 0x01, 0x06}; +- +-static constexpr size_t COOKIE_OFFSET = 1; +-static constexpr size_t VERSION_OFFSET = 5; +-static constexpr size_t ADDR_SIZE_OFFSET = 8; +-static constexpr size_t MAC_OFFSET = 9; +-static constexpr size_t ADDRTYPE_OFFSET = 16; +-static constexpr size_t IPADDR_OFFSET = 17; ++static constexpr uint8_t netConfInitialBytes[] = {0x80, 0x21, 0x70, 0x62, ++ 0x21, 0x00, 0x01, 0x06}; ++static constexpr uint8_t oemParmStart = 96; ++static constexpr uint8_t oemParmEnd = 127; ++ ++static constexpr size_t cookieOffset = 1; ++static constexpr size_t versionOffset = 5; ++static constexpr size_t addrSizeOffset = 8; ++static constexpr size_t macOffset = 9; ++static constexpr size_t addrTypeOffset = 16; ++static constexpr size_t ipAddrOffset = 17; + + static constexpr uint4_t RESERVED = 0; + static constexpr uint8_t CHANNEL_NOT_SUPPORTED = 0; +@@ -75,6 +71,16 @@ static constexpr size_t chassisIdentifyReqLength = 2; + static constexpr size_t identifyIntervalPos = 0; + static constexpr size_t forceIdentifyPos = 1; + ++namespace ipmi ++{ ++constexpr Cc ccParmNotSupported = 0x80; ++ ++static inline auto responseParmNotSupported() ++{ ++ return response(ccParmNotSupported); ++} ++} // namespace ipmi ++ + void register_netfn_chassis_functions() __attribute__((constructor)); + + // Host settings in dbus +@@ -180,12 +186,6 @@ struct get_sys_boot_options_response_t + uint8_t data[SIZE_BOOT_OPTION]; + } __attribute__((packed)); + +-struct set_sys_boot_options_t +-{ +- uint8_t parameter; +- uint8_t data[SIZE_BOOT_OPTION]; +-} __attribute__((packed)); +- + int getHostNetworkData(get_sys_boot_options_response_t* respptr) + { + ipmi::PropertyMap properties; +@@ -255,15 +255,15 @@ int getHostNetworkData(get_sys_boot_options_response_t* respptr) + } + } + +- sscanf( +- MACAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, +- (respptr->data + MAC_OFFSET), (respptr->data + MAC_OFFSET + 1), +- (respptr->data + MAC_OFFSET + 2), (respptr->data + MAC_OFFSET + 3), +- (respptr->data + MAC_OFFSET + 4), (respptr->data + MAC_OFFSET + 5)); ++ sscanf(MACAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (respptr->data + macOffset), (respptr->data + macOffset + 1), ++ (respptr->data + macOffset + 2), (respptr->data + macOffset + 3), ++ (respptr->data + macOffset + 4), ++ (respptr->data + macOffset + 5)); + +- respptr->data[MAC_OFFSET + 6] = 0x00; ++ respptr->data[macOffset + 6] = 0x00; + +- std::memcpy(respptr->data + ADDRTYPE_OFFSET, &isStatic, ++ std::memcpy(respptr->data + addrTypeOffset, &isStatic, + sizeof(isStatic)); + + uint8_t addressFamily = (std::get(properties["Type"]) == +@@ -277,9 +277,9 @@ int getHostNetworkData(get_sys_boot_options_response_t* respptr) + + // ipaddress and gateway would be in IPv4 format + inet_pton(addressFamily, ipAddress.c_str(), +- (respptr->data + IPADDR_OFFSET)); ++ (respptr->data + ipAddrOffset)); + +- uint8_t prefixOffset = IPADDR_OFFSET + addrSize; ++ uint8_t prefixOffset = ipAddrOffset + addrSize; + + std::memcpy(respptr->data + prefixOffset, &prefix, sizeof(prefix)); + +@@ -298,10 +298,10 @@ int getHostNetworkData(get_sys_boot_options_response_t* respptr) + + // PetiBoot-Specific + // If success then copy the first 9 bytes to the data +- std::memcpy(respptr->data, net_conf_initial_bytes, +- sizeof(net_conf_initial_bytes)); ++ std::memcpy(respptr->data, netConfInitialBytes, ++ sizeof(netConfInitialBytes)); + +- std::memcpy(respptr->data + ADDR_SIZE_OFFSET, &addrSize, sizeof(addrSize)); ++ std::memcpy(respptr->data + addrSizeOffset, &addrSize, sizeof(addrSize)); + + #ifdef _IPMI_DEBUG_ + std::printf("\n===Printing the IPMI Formatted Data========\n"); +@@ -361,19 +361,18 @@ std::string getAddrStr(uint8_t family, uint8_t* data, uint8_t offset, + return ipAddr; + } + +-int setHostNetworkData(set_sys_boot_options_t* reqptr) ++ipmi::Cc setHostNetworkData(ipmi::message::Payload& data) + { + using namespace std::string_literals; +- std::string host_network_config; +- char mac[]{"00:00:00:00:00:00"}; ++ std::string hostNetworkConfig; ++ std::string mac("00:00:00:00:00:00"); + std::string ipAddress, gateway; +- char addrOrigin{0}; ++ std::string addrOrigin{0}; + uint8_t addrSize{0}; + std::string addressOrigin = + "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; + std::string addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; + uint8_t prefix{0}; +- uint32_t zeroCookie = 0; + uint8_t family = AF_INET; + + // cookie starts from second byte +@@ -384,13 +383,33 @@ int setHostNetworkData(set_sys_boot_options_t* reqptr) + do + { + // cookie == 0x21 0x70 0x62 0x21 +- if (memcmp(&(reqptr->data[COOKIE_OFFSET]), +- (net_conf_initial_bytes + COOKIE_OFFSET), +- SIZE_COOKIE) != 0) ++ data.trailingOk = true; ++ auto msgLen = data.size(); ++ std::vector msgPayloadBytes(msgLen); ++ if (data.unpack(msgPayloadBytes) != 0 || !data.fullyUnpacked()) ++ { ++ log( ++ "Error in unpacking message of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ ++ uint8_t* msgPayloadStartingPos = msgPayloadBytes.data(); ++ constexpr size_t cookieSize = 4; ++ if (msgLen < cookieOffset + cookieSize) ++ { ++ log( ++ "Error in cookie getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ if (std::equal(msgPayloadStartingPos + cookieOffset, ++ msgPayloadStartingPos + cookieOffset + cookieSize, ++ (netConfInitialBytes + cookieOffset)) != 0) + { +- // cookie == 0 +- if (memcmp(&(reqptr->data[COOKIE_OFFSET]), &zeroCookie, +- SIZE_COOKIE) == 0) ++ // all cookie == 0 ++ if (std::all_of(msgPayloadStartingPos + cookieOffset, ++ msgPayloadStartingPos + cookieOffset + ++ cookieSize, ++ [](int i) { return i == 0; }) == true) + { + // need to zero out the network settings. + break; +@@ -401,59 +420,106 @@ int setHostNetworkData(set_sys_boot_options_t* reqptr) + } + + // vesion == 0x00 0x01 +- if (memcmp(&(reqptr->data[VERSION_OFFSET]), +- (net_conf_initial_bytes + VERSION_OFFSET), +- SIZE_VERSION) != 0) ++ if (msgLen < versionOffset + sizeVersion) ++ { ++ log( ++ "Error in version getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ if (std::equal(msgPayloadStartingPos + versionOffset, ++ msgPayloadStartingPos + versionOffset + sizeVersion, ++ (netConfInitialBytes + versionOffset)) != 0) + { +- + log("Invalid Version"); + elog(); + } + +- std::snprintf( +- mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, +- reqptr->data[MAC_OFFSET], reqptr->data[MAC_OFFSET + 1], +- reqptr->data[MAC_OFFSET + 2], reqptr->data[MAC_OFFSET + 3], +- reqptr->data[MAC_OFFSET + 4], reqptr->data[MAC_OFFSET + 5]); ++ if (msgLen < macOffset + 6) ++ { ++ log( ++ "Error in mac address getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ std::stringstream result; ++ std::copy((msgPayloadStartingPos + macOffset), ++ (msgPayloadStartingPos + macOffset + 5), ++ std::ostream_iterator(result, ":")); ++ mac = result.str(); + +- std::memcpy(&addrOrigin, &(reqptr->data[ADDRTYPE_OFFSET]), +- sizeof(decltype(addrOrigin))); ++ if (msgLen < addrTypeOffset + sizeof(decltype(addrOrigin))) ++ { ++ log( ++ "Error in original address getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ std::copy(msgPayloadStartingPos + addrTypeOffset, ++ msgPayloadStartingPos + addrTypeOffset + ++ sizeof(decltype(addrOrigin)), ++ std::ostream_iterator(result, "")); ++ addrOrigin = result.str(); + +- if (addrOrigin) ++ if (!addrOrigin.empty()) + { + addressOrigin = + "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; + } + ++ if (msgLen < addrSizeOffset + sizeof(decltype(addrSize))) ++ { ++ log( ++ "Error in address size getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } + // Get the address size +- std::memcpy(&addrSize, &reqptr->data[ADDR_SIZE_OFFSET], +- sizeof(addrSize)); ++ std::copy(msgPayloadStartingPos + addrSizeOffset, ++ (msgPayloadStartingPos + addrSizeOffset + ++ sizeof(decltype(addrSize))), ++ &addrSize); + +- uint8_t prefixOffset = IPADDR_OFFSET + addrSize; +- +- std::memcpy(&prefix, &(reqptr->data[prefixOffset]), +- sizeof(decltype(prefix))); ++ uint8_t prefixOffset = ipAddrOffset + addrSize; ++ if (msgLen < prefixOffset + sizeof(decltype(prefix))) ++ { ++ log( ++ "Error in prefix getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ std::copy(msgPayloadStartingPos + prefixOffset, ++ (msgPayloadStartingPos + prefixOffset + ++ sizeof(decltype(prefix))), ++ &prefix); + + uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix)); +- + if (addrSize != ipmi::network::IPV4_ADDRESS_SIZE_BYTE) + { + addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; + family = AF_INET6; + } + +- ipAddress = +- getAddrStr(family, reqptr->data, IPADDR_OFFSET, addrSize); ++ if (msgLen < ipAddrOffset + addrSize) ++ { ++ log( ++ "Error in IP address getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ ipAddress = getAddrStr(family, msgPayloadStartingPos, ipAddrOffset, ++ addrSize); + +- gateway = getAddrStr(family, reqptr->data, gatewayOffset, addrSize); ++ if (msgLen < gatewayOffset + addrSize) ++ { ++ log( ++ "Error in gateway address getting of setHostNetworkData"); ++ return ipmi::ccReqDataLenInvalid; ++ } ++ gateway = getAddrStr(family, msgPayloadStartingPos, gatewayOffset, ++ addrSize); + + } while (0); + + // Cookie == 0 or it is a valid cookie +- host_network_config += "ipaddress="s + ipAddress + ",prefix="s + +- std::to_string(prefix) + ",gateway="s + gateway + +- ",mac="s + mac + ",addressOrigin="s + +- addressOrigin; ++ hostNetworkConfig += "ipaddress="s + ipAddress + ",prefix="s + ++ std::to_string(prefix) + ",gateway="s + gateway + ++ ",mac="s + mac + ",addressOrigin="s + ++ addressOrigin; + + sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); + +@@ -476,17 +542,17 @@ int setHostNetworkData(set_sys_boot_options_t* reqptr) + ipmi::setDbusProperty(bus, macObjectInfo.second, macObjectInfo.first, + MAC_INTERFACE, "MACAddress", std::string(mac)); + +- log( +- "Network configuration changed", +- entry("NETWORKCONFIG=%s", host_network_config.c_str())); ++ log("Network configuration changed", ++ entry("NETWORKCONFIG=%s", hostNetworkConfig.c_str())); + } +- catch (InternalFailure& e) ++ catch (sdbusplus::exception_t& e) + { + commit(); +- return -1; ++ log("Error in ipmiChassisSetSysBootOptions call"); ++ return ipmi::ccUnspecifiedError; + } + +- return 0; ++ return ipmi::ccSuccess; + } + + uint32_t getPOHCounter() +@@ -1444,7 +1510,7 @@ std::map modeDbusToIpmi = { + * @param[in] source - boot source value + * @return On failure return IPMI error. + */ +-static ipmi_ret_t setBootSource(const Source::Sources& source) ++static ipmi::Cc setBootSource(const Source::Sources& source) + { + using namespace chassis::internal; + using namespace chassis::internal::cache; +@@ -1461,16 +1527,16 @@ static ipmi_ret_t setBootSource(const Source::Sources& source) + { + log("Error in BootSource Set"); + report(); +- return IPMI_CC_UNSPECIFIED_ERROR; ++ return ipmi::ccUnspecifiedError; + } +- return IPMI_CC_OK; ++ return ipmi::ccSuccess; + } + + /** @brief Set the property value for boot mode + * @param[in] mode - boot mode value + * @return On failure return IPMI error. + */ +-static ipmi_ret_t setBootMode(const Mode::Modes& mode) ++static ipmi::Cc setBootMode(const Mode::Modes& mode) + { + using namespace chassis::internal; + using namespace chassis::internal::cache; +@@ -1487,9 +1553,9 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + { + log("Error in BootMode Set"); + report(); +- return IPMI_CC_UNSPECIFIED_ERROR; ++ return ipmi::ccUnspecifiedError; + } +- return IPMI_CC_OK; ++ return ipmi::ccSuccess; + } + + static constexpr uint8_t setComplete = 0x0; +@@ -1511,29 +1577,28 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + IpmiValue bootOption = ipmiDefault; + + if (reqptr->parameter == +- static_cast(BootOptionParameter::SET_IN_PROGRESS)) ++ static_cast(BootOptionParameter::setInProgress)) + { +- *data_len = +- static_cast(BootOptionResponseSize::SET_IN_PROGRESS); +- resp->version = SET_PARM_VERSION; +- resp->parm = static_cast(BootOptionParameter::SET_IN_PROGRESS); ++ *data_len = static_cast(BootOptionResponseSize::setInProgress); ++ resp->version = setParmVersion; ++ resp->parm = static_cast(BootOptionParameter::setInProgress); + resp->data[0] = transferStatus; + return IPMI_CC_OK; + } + + std::memset(resp, 0, sizeof(*resp)); +- resp->version = SET_PARM_VERSION; ++ resp->version = setParmVersion; + resp->parm = 5; +- resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; ++ resp->data[0] = setParmBootFlagsValidOneTime; + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. + */ + if (reqptr->parameter == +- static_cast(BootOptionParameter::BOOT_FLAGS)) ++ static_cast(BootOptionParameter::bootFlags)) + { + +- *data_len = static_cast(BootOptionResponseSize::BOOT_FLAGS); ++ *data_len = static_cast(BootOptionResponseSize::bootFlags); + using namespace chassis::internal; + using namespace chassis::internal::cache; + +@@ -1592,9 +1657,8 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + } + resp->data[1] = (bootOption << 2); + +- resp->data[0] = oneTimeEnabled +- ? SET_PARM_BOOT_FLAGS_VALID_ONE_TIME +- : SET_PARM_BOOT_FLAGS_VALID_PERMANENT; ++ resp->data[0] = oneTimeEnabled ? setParmBootFlagsValidOneTime ++ : setParmBootFlagsValidPermanent; + + rc = IPMI_CC_OK; + } +@@ -1607,14 +1671,14 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + } + } + else if (reqptr->parameter == +- static_cast(BootOptionParameter::OPAL_NETWORK_SETTINGS)) ++ static_cast(BootOptionParameter::opalNetworkSettings)) + { + + *data_len = +- static_cast(BootOptionResponseSize::OPAL_NETWORK_SETTINGS); ++ static_cast(BootOptionResponseSize::opalNetworkSettings); + + resp->parm = +- static_cast(BootOptionParameter::OPAL_NETWORK_SETTINGS); ++ static_cast(BootOptionParameter::opalNetworkSettings); + + int ret = getHostNetworkData(resp); + +@@ -1646,32 +1710,37 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return rc; + } + +-ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, +- ipmi_request_t request, +- ipmi_response_t response, +- ipmi_data_len_t data_len, +- ipmi_context_t context) ++ipmi::RspType<> ipmiChassisSetSysBootOptions(ipmi::Context::ptr ctx, ++ uint7_t parameterSelector, ++ bool parameterIsValid, ++ ipmi::message::Payload& data) + { + using namespace boot_options; +- ipmi_ret_t rc = IPMI_CC_OK; +- set_sys_boot_options_t* reqptr = (set_sys_boot_options_t*)request; +- +- std::printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n", +- reqptr->parameter); +- +- // This IPMI command does not have any resposne data +- *data_len = 0; ++ ipmi::Cc rc; + +- if (reqptr->parameter == +- static_cast(BootOptionParameter::SET_IN_PROGRESS)) ++ if (parameterSelector == ++ static_cast(BootOptionParameter::setInProgress)) + { ++ uint2_t setStatus; ++ uint6_t rsvd; ++ ++ if (data.unpack(rsvd, setStatus) != 0 || !data.fullyUnpacked()) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if (rsvd || setStatus != static_cast(setComplete)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } + if ((transferStatus == setInProgress) && +- (reqptr->data[0] != setComplete)) ++ (static_cast(setStatus) != setComplete)) + { +- return IPMI_CC_FAIL_SET_IN_PROGRESS; ++ constexpr ipmi::Cc ccFailSetInProgress = 0x81; ++ return ipmi::response(ccFailSetInProgress); + } +- transferStatus = reqptr->data[0]; +- return IPMI_CC_OK; ++ transferStatus = static_cast(setStatus); ++ ++ return ipmi::responseSuccess(); + } + + /* 000101 +@@ -1679,9 +1748,37 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + * This is the only parameter used by petitboot. + */ + +- if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) +- { +- IpmiValue bootOption = ((reqptr->data[1] & 0x3C) >> 2); ++ if (parameterSelector == ++ static_cast(BootOptionParameter::bootFlags)) ++ { ++ uint5_t rsvd; ++ bool validFlag; ++ bool permanent; ++ bool biosBootType; ++ bool lockOutResetButton; ++ bool screenBlank; ++ uint4_t bootDeviceSelector; ++ bool lockKeyboard; ++ bool cmosClear; ++ uint8_t data3; ++ uint4_t biosInfo; ++ uint4_t rsvd1; ++ uint5_t deviceInstance; ++ uint3_t rsvd2; ++ ++ if (data.unpack(rsvd, biosBootType, permanent, validFlag, ++ lockOutResetButton, screenBlank, bootDeviceSelector, ++ lockKeyboard, cmosClear, data3, biosInfo, rsvd1, ++ deviceInstance, rsvd2) != 0 || ++ !data.fullyUnpacked()) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if (rsvd || rsvd1 || rsvd2) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ + using namespace chassis::internal; + using namespace chassis::internal::cache; + auto oneTimeEnabled = false; +@@ -1691,10 +1788,6 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + try + { +- bool permanent = +- (reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) == +- SET_PARM_BOOT_FLAGS_PERMANENT; +- + settings::Objects& objects = getObjects(); + + auto bootSetting = settings::boot::setting(objects, bootSourceIntf); +@@ -1720,15 +1813,19 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + "Enabled", !permanent); + } + +- auto modeItr = modeIpmiToDbus.find(bootOption); +- auto sourceItr = sourceIpmiToDbus.find(bootOption); ++ auto modeItr = ++ modeIpmiToDbus.find(static_cast(bootDeviceSelector)); ++ auto sourceItr = ++ sourceIpmiToDbus.find(static_cast(bootDeviceSelector)); + if (sourceIpmiToDbus.end() != sourceItr) + { + rc = setBootSource(sourceItr->second); +- if (rc != IPMI_CC_OK) ++ ++ if (rc != ipmi::ccSuccess) + { +- *data_len = 0; +- return rc; ++ log("ipmiChassisSetSysBootOptions: Error in " ++ "setting boot source"); ++ return ipmi::responseUnspecifiedError(); + } + // If a set boot device is mapping to a boot source, then reset + // the boot mode D-Bus property to default. +@@ -1742,10 +1839,11 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + if (modeIpmiToDbus.end() != modeItr) + { + rc = setBootMode(modeItr->second); +- if (rc != IPMI_CC_OK) ++ if (rc != ipmi::ccSuccess) + { +- *data_len = 0; +- return rc; ++ log("ipmiChassisSetSysBootOptions: Error in " ++ "setting boot mode"); ++ return ipmi::responseUnspecifiedError(); + } + // If a set boot device is mapping to a boot mode, then reset + // the boot source D-Bus property to default. +@@ -1760,48 +1858,79 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + (sourceIpmiToDbus.end() == sourceItr)) + { + // return error if boot option is not supported +- *data_len = 0; +- return IPMI_CC_INVALID_FIELD_REQUEST; ++ log( ++ "ipmiChassisSetSysBootOptions: Boot option not supported"); ++ return ipmi::responseInvalidFieldRequest(); + } + } +- catch (InternalFailure& e) ++ catch (sdbusplus::exception_t& e) + { + objectsPtr.reset(); + report(); +- *data_len = 0; +- return IPMI_CC_UNSPECIFIED_ERROR; ++ log( ++ "ipmiChassisSetSysBootOptions: Error in setting Boot " ++ "flag parameters"); ++ return ipmi::responseUnspecifiedError(); + } + } +- else if (reqptr->parameter == +- (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) ++ else if (parameterSelector == ++ static_cast(BootOptionParameter::bootInfo)) + { ++ uint8_t writeMak; ++ uint5_t bootInitiatorAckData; ++ uint3_t rsvd; + +- int ret = setHostNetworkData(reqptr); +- if (ret < 0) ++ if (data.unpack(writeMak, bootInitiatorAckData, rsvd) != 0 || ++ !data.fullyUnpacked()) + { +- log( +- "setHostNetworkData failed for set_sys_boot_options"); +- rc = IPMI_CC_UNSPECIFIED_ERROR; ++ return ipmi::responseReqDataLenInvalid(); + } +- } +- else if (reqptr->parameter == +- static_cast(BootOptionParameter::BOOT_INFO)) +- { +- // Handle parameter #4 and return command completed normally +- // (IPMI_CC_OK). There is no implementation in OpenBMC for this ++ if (rsvd) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ // (ccSuccess). There is no implementation in OpenBMC for this + // parameter. This is added to support the ipmitool command `chassis + // bootdev` which sends set on parameter #4, before setting the boot + // flags. +- rc = IPMI_CC_OK; ++ log("ipmiChassisSetSysBootOptions: bootInfo parameter set " ++ "successfully"); ++ data.trailingOk = true; ++ return ipmi::responseSuccess(); + } + else + { +- log("Unsupported parameter", +- entry("PARAM=0x%x", reqptr->parameter)); +- rc = IPMI_CC_PARM_NOT_SUPPORTED; ++ if ((parameterSelector >= static_cast(oemParmStart)) && ++ (parameterSelector <= static_cast(oemParmEnd))) ++ { ++ if (parameterSelector == ++ static_cast(BootOptionParameter::opalNetworkSettings)) ++ { ++ ipmi::Cc ret = setHostNetworkData(data); ++ if (ret != ipmi::ccSuccess) ++ { ++ log("ipmiChassisSetSysBootOptions: Error in " ++ "setHostNetworkData"); ++ data.trailingOk = true; ++ return ipmi::response(ret); ++ } ++ data.trailingOk = true; ++ return ipmi::responseSuccess(); ++ } ++ else ++ { ++ log( ++ "ipmiChassisSetSysBootOptions: Unsupported parameters", ++ entry("PARAM=0x%x", ++ static_cast(parameterSelector))); ++ data.trailingOk = true; ++ return ipmi::responseParmNotSupported(); ++ } ++ } ++ data.trailingOk = true; ++ return ipmi::responseParmNotSupported(); + } +- +- return rc; ++ return ipmi::responseSuccess(); + } + + /** @brief implements Get POH counter command +@@ -1963,9 +2092,11 @@ void register_netfn_chassis_functions() + ipmi::Privilege::Operator, ipmiChassisIdentify); + + // +- ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, +- ipmi_chassis_set_sys_boot_options, +- PRIVILEGE_OPERATOR); ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, ++ ipmi::chassis::cmdSetSystemBootOptions, ++ ipmi::Privilege::Operator, ++ ipmiChassisSetSysBootOptions); ++ + // + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, + ipmi::chassis::cmdGetPohCounter, +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 353a929..479563a 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -25,7 +25,6 @@ enum ipmi_chassis_return_codes + { + IPMI_OK = 0x0, + IPMI_CC_PARM_NOT_SUPPORTED = 0x80, +- IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81, + }; + + // Generic completion codes, +@@ -47,17 +46,17 @@ enum ipmi_chassis_control_cmds : uint8_t + }; + enum class BootOptionParameter : size_t + { +- SET_IN_PROGRESS = 0x0, +- BOOT_INFO = 0x4, +- BOOT_FLAGS = 0x5, +- OPAL_NETWORK_SETTINGS = 0x61 ++ setInProgress = 0x0, ++ bootInfo = 0x4, ++ bootFlags = 0x5, ++ opalNetworkSettings = 0x61 + }; + + enum class BootOptionResponseSize : size_t + { +- SET_IN_PROGRESS = 3, +- BOOT_FLAGS = 5, +- OPAL_NETWORK_SETTINGS = 50 ++ setInProgress = 3, ++ bootFlags = 5, ++ opalNetworkSettings = 50 + }; + + enum class ChassisIDState : uint8_t +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0072-chassishandler-GetSystemBootOptions-to-new-API.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0072-chassishandler-GetSystemBootOptions-to-new-API.patch new file mode 100644 index 000000000..272626e07 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0072-chassishandler-GetSystemBootOptions-to-new-API.patch @@ -0,0 +1,429 @@ +From cab3769b39ae6f3cce0119fce2c823ec8e11af11 Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala +Date: Fri, 4 Sep 2020 12:53:17 +0000 +Subject: [PATCH] chassishandler: GetSystemBootOptions to new API + +Rewrite ipmiChassisGetSytemBootOptions to use newly introduced +IPMI provider API + +Tested: +Verified using ipmi chassis bootparam command + +Command: ipmitool chassis bootparam get 0 +Response: +Boot parameter version: 0 +Boot parameter 0 is valid/unlocked +Boot parameter data: + Set In Progress : set complete + +Command: ipmitool chassis bootparam get 5 +Response: +Boot parameter version: 1 +Boot parameter 5 is valid/unlocked +Boot parameter data: 8008000000 + Boot Flags : + - Boot Flag Valid + - Options apply to only next boot + - BIOS PC Compatible (legacy) boot + - Boot Device Selector : Force Boot from default Hard-Drive + - BIOS verbosity : System Default + - Console Redirection control : Console redirection occurs per BIOS + configuration setting (default) + - BIOS Mux Control Override : BIOS uses recommended setting of the + mux at the end of POST + +Signed-off-by: srikanta mondal +Signed-off-by: Jayaprakash Mutyala +--- + chassishandler.cpp | 231 +++++++++++++++++++++++---------------------- + chassishandler.hpp | 7 -- + 2 files changed, 119 insertions(+), 119 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index ca7cd2c..bbb3f81 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -44,9 +44,6 @@ static constexpr uint8_t setParmBootFlagsPermanent = 0x40; + static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80; + static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0; + +-constexpr size_t SIZE_BOOT_OPTION = static_cast( +- BootOptionResponseSize::opalNetworkSettings); // Maximum size of the boot +- // option parameters + constexpr size_t sizeVersion = 2; + constexpr size_t DEFAULT_IDENTIFY_TIME_OUT = 15; + +@@ -172,21 +169,7 @@ constexpr auto minutesPerCount = 60; + + } // namespace poh + +-struct get_sys_boot_options_t +-{ +- uint8_t parameter; +- uint8_t set; +- uint8_t block; +-} __attribute__((packed)); +- +-struct get_sys_boot_options_response_t +-{ +- uint8_t version; +- uint8_t parm; +- uint8_t data[SIZE_BOOT_OPTION]; +-} __attribute__((packed)); +- +-int getHostNetworkData(get_sys_boot_options_response_t* respptr) ++int getHostNetworkData(ipmi::message::Payload& payload) + { + ipmi::PropertyMap properties; + int rc = 0; +@@ -238,7 +221,6 @@ int getHostNetworkData(get_sys_boot_options_response_t* respptr) + // don't send blank override. + if ((MACAddress == ipmi::network::DEFAULT_MAC_ADDRESS)) + { +- std::memset(respptr->data, 0, SIZE_BOOT_OPTION); + rc = -1; + return rc; + } +@@ -249,22 +231,27 @@ int getHostNetworkData(get_sys_boot_options_response_t* respptr) + if ((ipAddress == ipmi::network::DEFAULT_ADDRESS) || + (gateway == ipmi::network::DEFAULT_ADDRESS) || (!prefix)) + { +- std::memset(respptr->data, 0, SIZE_BOOT_OPTION); + rc = -1; + return rc; + } + } + +- sscanf(MACAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, +- (respptr->data + macOffset), (respptr->data + macOffset + 1), +- (respptr->data + macOffset + 2), (respptr->data + macOffset + 3), +- (respptr->data + macOffset + 4), +- (respptr->data + macOffset + 5)); ++ std::string token; ++ std::stringstream ss(MACAddress); ++ ++ // First pack macOffset no of bytes in payload. ++ // Latter this PetiBoot-Specific data will be populated. ++ std::vector payloadInitialBytes(macOffset); ++ payload.pack(payloadInitialBytes); ++ ++ while (std::getline(ss, token, ':')) ++ { ++ payload.pack(stoi(token, nullptr, 16)); ++ } + +- respptr->data[macOffset + 6] = 0x00; ++ payload.pack(0x00); + +- std::memcpy(respptr->data + addrTypeOffset, &isStatic, +- sizeof(isStatic)); ++ payload.pack(isStatic); + + uint8_t addressFamily = (std::get(properties["Type"]) == + "xyz.openbmc_project.Network.IP.Protocol.IPv4") +@@ -276,39 +263,58 @@ int getHostNetworkData(get_sys_boot_options_response_t* respptr) + : ipmi::network::IPV6_ADDRESS_SIZE_BYTE; + + // ipaddress and gateway would be in IPv4 format ++ std::vector addrInBinary(addrSize); + inet_pton(addressFamily, ipAddress.c_str(), +- (respptr->data + ipAddrOffset)); ++ reinterpret_cast(addrInBinary.data())); + +- uint8_t prefixOffset = ipAddrOffset + addrSize; ++ payload.pack(addrInBinary); + +- std::memcpy(respptr->data + prefixOffset, &prefix, sizeof(prefix)); +- +- uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix)); ++ payload.pack(prefix); + ++ std::vector gatewayDetails(addrSize); + inet_pton(addressFamily, gateway.c_str(), +- (respptr->data + gatewayOffset)); ++ reinterpret_cast(gatewayDetails.data())); ++ payload.pack(gatewayDetails); + } + catch (InternalFailure& e) + { + commit(); +- std::memset(respptr->data, 0, SIZE_BOOT_OPTION); + rc = -1; + return rc; + } + + // PetiBoot-Specific +- // If success then copy the first 9 bytes to the data +- std::memcpy(respptr->data, netConfInitialBytes, +- sizeof(netConfInitialBytes)); ++ // If success then copy the first 9 bytes to the payload message ++ // payload first 2 bytes contain the parameter values. Skip that 2 bytes. ++ uint8_t skipFirstTwoBytes = 2; ++ size_t payloadSize = payload.size(); ++ uint8_t* configDataStartingAddress = payload.data() + skipFirstTwoBytes; + +- std::memcpy(respptr->data + addrSizeOffset, &addrSize, sizeof(addrSize)); ++ if (payloadSize < skipFirstTwoBytes + sizeof(netConfInitialBytes)) ++ { ++ log("Invalid net config "); ++ rc = -1; ++ return rc; ++ } ++ std::copy(netConfInitialBytes, ++ netConfInitialBytes + sizeof(netConfInitialBytes), ++ configDataStartingAddress); ++ ++ if (payloadSize < skipFirstTwoBytes + addrSizeOffset + sizeof(addrSize)) ++ { ++ log("Invalid length of address size"); ++ rc = -1; ++ return rc; ++ } ++ std::copy(&addrSize, &(addrSize) + sizeof(addrSize), ++ configDataStartingAddress + addrSizeOffset); + + #ifdef _IPMI_DEBUG_ + std::printf("\n===Printing the IPMI Formatted Data========\n"); + + for (uint8_t pos = 0; pos < index; pos++) + { +- std::printf("%02x ", respptr->data[pos]); ++ std::printf("%02x ", payloadStartingAddress[pos]); + } + #endif + +@@ -1561,44 +1567,52 @@ static ipmi::Cc setBootMode(const Mode::Modes& mode) + static constexpr uint8_t setComplete = 0x0; + static constexpr uint8_t setInProgress = 0x1; + static uint8_t transferStatus = setComplete; ++/** @brief implements the Get Chassis system boot option ++ * @param bootOptionParameter - boot option parameter selector ++ * @param reserved1 - reserved bit ++ * @param setSelector - selects a particular block or set of parameters ++ * under the given parameter selector ++ * write as 00h if parameter doesn't use a setSelector ++ * @param blockSelector- selects a particular block within a set of ++ * parameters write as 00h if parameter doesn't use a ++ * blockSelector ++ * ++ * @return IPMI completion code plus response data ++ * @return Payload contains below parameters: ++ * version - parameter version ++ * bootOptionParameter - boot option parameter selector ++ * parmIndicator - parameter vaild/invaild indicator ++ * data - configuration parameter data ++ */ ++ipmi::RspType ++ ipmiChassisGetSysBootOptions(uint7_t bootOptionParameter, bool reserved1, + +-ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, +- ipmi_request_t request, +- ipmi_response_t response, +- ipmi_data_len_t data_len, +- ipmi_context_t context) ++ uint8_t setSelector, uint8_t blockSelector) + { ++ if (reserved1) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ constexpr uint4_t version = 0x01; ++ ipmi::message::Payload response; ++ response.pack(version, uint4_t{}); + using namespace boot_options; +- ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED; +- char* p = NULL; +- get_sys_boot_options_response_t* resp = +- (get_sys_boot_options_response_t*)response; +- get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; +- IpmiValue bootOption = ipmiDefault; + +- if (reqptr->parameter == ++ IpmiValue bootOption = ipmiDefault; ++ if (static_cast(bootOptionParameter) == + static_cast(BootOptionParameter::setInProgress)) + { +- *data_len = static_cast(BootOptionResponseSize::setInProgress); +- resp->version = setParmVersion; +- resp->parm = static_cast(BootOptionParameter::setInProgress); +- resp->data[0] = transferStatus; +- return IPMI_CC_OK; ++ return ipmi::response(transferStatus); + } + +- std::memset(resp, 0, sizeof(*resp)); +- resp->version = setParmVersion; +- resp->parm = 5; +- resp->data[0] = setParmBootFlagsValidOneTime; + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. + */ +- if (reqptr->parameter == ++ if (static_cast(bootOptionParameter) == + static_cast(BootOptionParameter::bootFlags)) + { +- +- *data_len = static_cast(BootOptionResponseSize::bootFlags); + using namespace chassis::internal; + using namespace chassis::internal::cache; + +@@ -1619,8 +1633,7 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + { + log("Error in BootSource Get"); + report(); +- *data_len = 0; +- return IPMI_CC_UNSPECIFIED_ERROR; ++ return ipmi::responseUnspecifiedError(); + } + std::variant result; + reply.read(result); +@@ -1638,8 +1651,7 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + { + log("Error in BootMode Get"); + report(); +- *data_len = 0; +- return IPMI_CC_UNSPECIFIED_ERROR; ++ return ipmi::responseUnspecifiedError(); + } + reply.read(result); + auto bootMode = +@@ -1655,59 +1667,54 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + { + bootOption = modeDbusToIpmi.at(bootMode); + } +- resp->data[1] = (bootOption << 2); + +- resp->data[0] = oneTimeEnabled ? setParmBootFlagsValidOneTime +- : setParmBootFlagsValidPermanent; +- +- rc = IPMI_CC_OK; ++ uint8_t bootOptionParam = oneTimeEnabled ++ ? setParmBootFlagsValidOneTime ++ : setParmBootFlagsValidPermanent; ++ response.pack(bootOptionParameter, reserved1, bootOptionParam, ++ uint2_t{}, uint4_t{bootOption}, uint2_t{}, uint8_t{}, ++ uint8_t{}, uint8_t{}); ++ return ipmi::responseSuccess(std::move(response)); + } + catch (InternalFailure& e) + { + cache::objectsPtr.reset(); + report(); +- *data_len = 0; +- return IPMI_CC_UNSPECIFIED_ERROR; ++ return ipmi::responseUnspecifiedError(); + } + } +- else if (reqptr->parameter == +- static_cast(BootOptionParameter::opalNetworkSettings)) ++ else + { +- +- *data_len = +- static_cast(BootOptionResponseSize::opalNetworkSettings); +- +- resp->parm = +- static_cast(BootOptionParameter::opalNetworkSettings); +- +- int ret = getHostNetworkData(resp); +- +- if (ret < 0) ++ if ((bootOptionParameter >= oemParmStart) && ++ (bootOptionParameter <= oemParmEnd)) + { +- +- log( +- "getHostNetworkData failed for get_sys_boot_options."); +- rc = IPMI_CC_UNSPECIFIED_ERROR; ++ if (static_cast(bootOptionParameter) == ++ static_cast(BootOptionParameter::opalNetworkSettings)) ++ { ++ response.pack(bootOptionParameter, reserved1); ++ int ret = getHostNetworkData(response); ++ if (ret < 0) ++ { ++ response.trailingOk = true; ++ log( ++ "getHostNetworkData failed for GetSysBootOptions."); ++ return ipmi::responseUnspecifiedError(); ++ } ++ else ++ { ++ return ipmi::responseSuccess(std::move(response)); ++ } ++ } + } + else +- rc = IPMI_CC_OK; +- } +- +- else +- { +- log("Unsupported parameter", +- entry("PARAM=0x%x", reqptr->parameter)); +- } +- +- if (p) +- free(p); +- +- if (rc == IPMI_CC_OK) +- { +- *data_len += 2; ++ { ++ log( ++ "Unsupported parameter", ++ entry("PARAM=0x%x", static_cast(bootOptionParameter))); ++ return ipmi::responseUnspecifiedError(); ++ } + } +- +- return rc; ++ return ipmi::responseUnspecifiedError(); + } + + ipmi::RspType<> ipmiChassisSetSysBootOptions(ipmi::Context::ptr ctx, +@@ -1820,7 +1827,6 @@ ipmi::RspType<> ipmiChassisSetSysBootOptions(ipmi::Context::ptr ctx, + if (sourceIpmiToDbus.end() != sourceItr) + { + rc = setBootSource(sourceItr->second); +- + if (rc != ipmi::ccSuccess) + { + log("ipmiChassisSetSysBootOptions: Error in " +@@ -2067,9 +2073,10 @@ void register_netfn_chassis_functions() + ipmi::Privilege::User, ipmiSetChassisCap); + + // +- ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, +- ipmi_chassis_get_sys_boot_options, +- PRIVILEGE_OPERATOR); ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, ++ ipmi::chassis::cmdGetSystemBootOptions, ++ ipmi::Privilege::Operator, ++ ipmiChassisGetSysBootOptions); + + // + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 479563a..92c165e 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -20,13 +20,6 @@ enum ipmi_netfn_chassis_cmds + IPMI_CMD_GET_POH_COUNTER = 0x0F, + }; + +-// Command specific completion codes +-enum ipmi_chassis_return_codes +-{ +- IPMI_OK = 0x0, +- IPMI_CC_PARM_NOT_SUPPORTED = 0x80, +-}; +- + // Generic completion codes, + // see IPMI doc section 5.2 + enum ipmi_generic_return_codes +-- +2.17.1 + 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 index 98420b2ef..afd9fdcf1 100644 --- 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 @@ -10,6 +10,15 @@ SRC_URI += "file://phosphor-ipmi-host.service \ file://0062-Update-IPMI-Chassis-Control-command.patch \ file://0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch \ file://0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch \ + file://0064-transporthandler-Fix-for-invalid-VLAN-id.patch \ + file://0065-apphandler-Fix-for-set-system-Info-parameter-cmd.patch \ + file://0066-apphandler-Fix-for-total-session-slots-count.patch \ + file://0067-Fix-for-get-Channel-Info-cmd-for-reserved-channels.patch \ + file://0068-Removal-of-OEM-privilege-setting-for-User.patch \ + file://0069-apphandler-Fix-for-get-system-info-command.patch \ + file://0070-minor-fix-corrected-cc-for-get-channel-access.patch \ + file://0071-chassishandler-SetSystemBootOptions-to-new-API.patch \ + file://0072-chassishandler-GetSystemBootOptions-to-new-API.patch \ " EXTRA_OECONF_append = " --disable-i2c-whitelist-check" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch index dc7f7357c..5f749af45 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch @@ -1,4 +1,4 @@ -From 97c21a556702a0d65096b30c07ef23f15cb6a7d9 Mon Sep 17 00:00:00 2001 +From e5ab844259f569656e95f5324f7428229dd811a7 Mon Sep 17 00:00:00 2001 From: Cheng C Yang Date: Wed, 3 Jul 2019 07:39:47 +0800 Subject: [PATCH] Add dbus interface for sol commands @@ -25,18 +25,18 @@ to 0 and other properties will not reset to default value. Signed-off-by: Cheng C Yang --- - command/payload_cmds.cpp | 3 ++ - command/sol_cmds.cpp | 84 ------------------------------- - sol/sol_manager.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++++ + command/payload_cmds.cpp | 3 + + command/sol_cmds.cpp | 84 -------------------------- + sol/sol_manager.cpp | 124 +++++++++++++++++++++++++++++++++++++++ sol/sol_manager.hpp | 1 + - sol_module.cpp | 6 --- - 5 files changed, 129 insertions(+), 90 deletions(-) + sol_module.cpp | 6 -- + 5 files changed, 128 insertions(+), 90 deletions(-) diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp -index c32a510..17167a7 100644 +index c8e682e..bc987c5 100644 --- a/command/payload_cmds.cpp +++ b/command/payload_cmds.cpp -@@ -34,6 +34,9 @@ std::vector activatePayload(const std::vector& inPayload, +@@ -41,6 +41,9 @@ std::vector activatePayload(const std::vector& inPayload, return outPayload; } @@ -47,10 +47,10 @@ index c32a510..17167a7 100644 { response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp -index a8fa410..804b5ea 100644 +index fda3e91..a1e820f 100644 --- a/command/sol_cmds.cpp +++ b/command/sol_cmds.cpp -@@ -65,90 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) +@@ -71,90 +71,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) outPayload); } @@ -142,14 +142,12 @@ index a8fa410..804b5ea 100644 const message::Handler& handler) { diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp -index 2046fe4..eedd28a 100644 +index a118457..55d269a 100644 --- a/sol/sol_manager.cpp +++ b/sol/sol_manager.cpp -@@ -12,7 +12,13 @@ - #include - #include +@@ -14,6 +14,11 @@ #include -+#include + #include #include +#include + @@ -159,7 +157,7 @@ index 2046fe4..eedd28a 100644 namespace sol { -@@ -93,6 +99,125 @@ void Manager::stopHostConsole() +@@ -103,6 +108,125 @@ void Manager::stopHostConsole() } } @@ -286,10 +284,10 @@ index 2046fe4..eedd28a 100644 session::SessionID sessionID) { diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp -index 5d96890..00da9fb 100644 +index 5b48add..4e797d4 100644 --- a/sol/sol_manager.hpp +++ b/sol/sol_manager.hpp -@@ -248,6 +248,7 @@ class Manager +@@ -252,6 +252,7 @@ class Manager * @return 0 on success and errno on failure. */ int writeConsoleSocket(const std::vector& input) const; @@ -315,5 +313,5 @@ index 8200e74..2b1fb46 100644 {{(static_cast(message::PayloadType::IPMI) << 16) | static_cast(::command::NetFns::TRANSPORT) | 0x22}, -- -2.7.4 +2.17.1 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 index 10d0d8c94..fcf8df18d 100644 --- 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 @@ -3,7 +3,7 @@ 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 = "ecb32fbc699aaacee4d6a42bb986575c4c5780dc" +SRCREV = "2b1edef0b1e395591dcf751d7ccf45a85bb58d4c" USERADD_PACKAGES = "${PN}" # add a group called ipmi 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 index ac45a8114..daa64f159 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -1,4 +1,4 @@ -SRCREV = "623723b9e827f52a05cfe2dac8b4ef5d285fb6af" +SRCREV = "2456dde72421cd4086ac43e619fb0817a55bf0a7" #SRC_URI = "git://github.com/openbmc/dbus-sensors.git" DEPENDS_append = " libgpiod libmctp" diff --git a/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0002-Add-a-workaround-for-spurious-CPU-errors.patch b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0002-Add-a-workaround-for-spurious-CPU-errors.patch new file mode 100644 index 000000000..2a573311f --- /dev/null +++ b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0002-Add-a-workaround-for-spurious-CPU-errors.patch @@ -0,0 +1,133 @@ +From d0e4130b2d1e0e44efc8fd6e180487853625edd6 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" +Date: Mon, 17 Aug 2020 15:52:22 -0700 +Subject: [PATCH] Add a workaround for spurious CPU errors + +There is a possible issue where GPIO event interrupts are getting +missed causing false errors to be logged. + +This adds a check that the host is still on and the error is still +asserted before logging an error. + +Tested: +Confirmed that a spurious SMI event was ignored correctly after +this change. + +Change-Id: Id83d9d67b15dcf9035e6448086b140e5c7dab4fe +Signed-off-by: Jason M. Bills +--- + src/host_error_monitor.cpp | 77 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +diff --git a/src/host_error_monitor.cpp b/src/host_error_monitor.cpp +index ca089f70d..fd453ccdc 100644 +--- a/src/host_error_monitor.cpp ++++ b/src/host_error_monitor.cpp +@@ -797,6 +797,18 @@ static void caterrAssertHandler() + } + return; + } ++ // Confirm that this is a real failure by checking that the host is on ++ if (hostOff) ++ { ++ return; ++ } ++ // And that the signal is still asserted ++ if (caterrLine.get_value() != 0) ++ { ++ std::cerr ++ << "CPU_CATERR not asserted after timeout. Error ignored.\n"; ++ return; ++ } + std::cerr << "CATERR asserted for " << std::to_string(caterrTimeoutMs) + << " ms\n"; + beep(beepCPUIERR); +@@ -1270,6 +1282,48 @@ static void errXAssertHandler(const int errPin, + } + return; + } ++ // Confirm that this is a real failure by checking that the host is on ++ if (hostOff) ++ { ++ return; ++ } ++ // And that the signal is still asserted ++ switch (errPin) ++ { ++ case 0: ++ { ++ if (err0Line.get_value() != 0) ++ { ++ std::cerr << "CPU_ERR0 not asserted after timeout. Error " ++ "ignored.\n"; ++ return; ++ } ++ break; ++ } ++ case 1: ++ { ++ if (err1Line.get_value() != 0) ++ { ++ std::cerr << "CPU_ERR1 not asserted after timeout. Error " ++ "ignored.\n"; ++ return; ++ } ++ break; ++ } ++ case 2: ++ { ++ if (err2Line.get_value() != 0) ++ { ++ std::cerr << "CPU_ERR2 not asserted after timeout. Error " ++ "ignored.\n"; ++ return; ++ } ++ break; ++ } ++ default: ++ std::cerr << "Invalid ERR pin asserted\n"; ++ return; ++ } + std::cerr << "ERR" << std::to_string(errPin) << " asserted for " + << std::to_string(errTimeoutMs) << " ms\n"; + if (errPinCPUs.count()) +@@ -1379,6 +1433,18 @@ static void err2AssertHandler() + } + return; + } ++ // Confirm that this is a real failure by checking that the host is on ++ if (hostOff) ++ { ++ return; ++ } ++ // And that the signal is still asserted ++ if (err2Line.get_value() != 0) ++ { ++ std::cerr ++ << "CPU_ERR2 not asserted after timeout. Error ignored.\n"; ++ return; ++ } + conn->async_method_call( + [](boost::system::error_code ec, + const std::variant& property) { +@@ -1447,6 +1513,17 @@ static void smiAssertHandler() + } + return; + } ++ // Confirm that this is a real failure by checking that the host is on ++ if (hostOff) ++ { ++ return; ++ } ++ // And that the signal is still asserted ++ if (smiLine.get_value() != 0) ++ { ++ std::cerr << "SMI not asserted after timeout. Error ignored.\n"; ++ return; ++ } + std::cerr << "SMI asserted for " << std::to_string(smiTimeoutMs) + << " ms\n"; + smiTimeoutLog(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0003-Override-crashdump-timeout-to-30-minutes.patch b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0003-Override-crashdump-timeout-to-30-minutes.patch new file mode 100644 index 000000000..7511cc218 --- /dev/null +++ b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor/0003-Override-crashdump-timeout-to-30-minutes.patch @@ -0,0 +1,41 @@ +From 6d3f28619226c0dbfca6feb320a2fa292aa11f40 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" +Date: Wed, 2 Sep 2020 18:23:00 -0700 +Subject: [PATCH] Override crashdump timeout to 30 minutes + +The current crashdump timeout is set to 5 minutes, so if it takes +longer than 5 minutes to complete the crashdump, then +host-error-monitor will not reset the system to recover from the +error. + +My current crashdump on a single socket is taking about 11 minutes +to complete. This is a workaround to change the timeout to 30 +minutes to give enough time for crashdump to complete before timing +out. + +Tested: +Confirmed that when I inject an IERR on my system, it will correctly +reset after 11 minutes when crashdump completes. + +Change-Id: I36ac3f0c83ae1634e486d9f8413b38fae5efb561 +Signed-off-by: Jason M. Bills +--- + src/host_error_monitor.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/host_error_monitor.cpp b/src/host_error_monitor.cpp +index fd453ccdc..9dabb52bb 100644 +--- a/src/host_error_monitor.cpp ++++ b/src/host_error_monitor.cpp +@@ -46,7 +46,7 @@ static size_t caterrTimeoutMs = 2000; + const static constexpr size_t caterrTimeoutMsMax = 600000; // 10 minutes maximum + const static constexpr size_t errTimeoutMs = 90000; + const static constexpr size_t smiTimeoutMs = 90000; +-const static constexpr size_t crashdumpTimeoutS = 300; ++const static constexpr size_t crashdumpTimeoutS = 1800; + + // Timers + // Timer for CATERR asserted +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend index 4b79757c0..9853a4abc 100644 --- a/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend +++ b/meta-openbmc-mods/meta-wht/recipes-core/host-error-monitor/host-error-monitor_%.bbappend @@ -2,4 +2,6 @@ FILESEXTRAPATHS_append := "${THISDIR}/${PN}:" SRC_URI += " \ file://0001-Filter-memory-thermtrip-events-based-on-DIMM-status.patch \ + file://0002-Add-a-workaround-for-spurious-CPU-errors.patch \ + file://0003-Override-crashdump-timeout-to-30-minutes.patch \ " -- cgit v1.2.3