diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common')
370 files changed, 30745 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/COPYING.MIT b/meta-openbmc-mods/meta-common/COPYING.MIT new file mode 100644 index 000000000..89de35479 --- /dev/null +++ b/meta-openbmc-mods/meta-common/COPYING.MIT @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/meta-openbmc-mods/meta-common/README b/meta-openbmc-mods/meta-common/README new file mode 100644 index 000000000..9d4a8a1e6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/README @@ -0,0 +1,64 @@ +This README file contains information on the contents of the +common layer. + +Please see the corresponding sections below for details. + + +Dependencies +============ + +This layer depends on: + + URI: git://git.openembedded.org/bitbake + branch: master + + URI: git://git.openembedded.org/openembedded-core + layers: meta + branch: master + + URI: git://git.yoctoproject.org/xxxx + layers: xxxx + branch: master + + +Patches +======= + +Please submit any patches against the common layer to the +xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer: + +Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com> + + +Table of Contents +================= + + I. Adding the common layer to your build + II. Misc + + +I. Adding the common layer to your build +================================================= + +--- replace with specific instructions for the common layer --- + +In order to use this layer, you need to make the build system aware of +it. + +Assuming the common layer exists at the top-level of your +yocto build tree, you can add it to the build system by adding the +location of the common layer to bblayers.conf, along with any +other layers needed. e.g.: + + BBLAYERS ?= " \ + /path/to/yocto/meta \ + /path/to/yocto/meta-poky \ + /path/to/yocto/meta-yocto-bsp \ + /path/to/yocto/meta-common \ + " + + +II. Misc +======== + +--- replace with specific information about the common layer --- diff --git a/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass new file mode 100644 index 000000000..2161cdf8d --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass @@ -0,0 +1,166 @@ + + +inherit obmc-phosphor-full-fitimage +inherit image_types_phosphor_auto +DEPENDS += "obmc-intel-pfr-image-native python3-native intel-blocksign-native" + +require recipes-core/os-release/version-vars.inc + +IMAGE_TYPES += "intel-pfr" + +IMAGE_TYPEDEP_intel-pfr = "mtd-auto" +IMAGE_TYPES_MASKED += "intel-pfr" + +# PFR images directory +PFR_IMAGES_DIR = "${DEPLOY_DIR_IMAGE}/pfr_images" + +# PFR image generation script directory +PFR_SCRIPT_DIR = "${STAGING_DIR_NATIVE}${bindir}" + +# PFR image config directory +PFR_CFG_DIR = "${STAGING_DIR_NATIVE}${datadir}/pfrconfig" + +# Refer flash map in manifest.json for the addresses offset +PFM_OFFSET = "0x80000" + +# 0x80000/1024 = 0x200 or 512, 1K Page size. +PFM_OFFSET_PAGE = "512" + +# RC_IMAGE +RC_IMAGE_OFFSET = "0x02a00000" + +# RC_IMAGE_PAGE= 0x02a00000/1024 = 0xA800 or 43008 +RC_IMAGE_PAGE = "43008" + +do_image_pfr_internal () { + local manifest_json="pfr_manifest${bld_suffix}.json" + local pfmconfig_xml="pfm_config${bld_suffix}.xml" + local bmcconfig_xml="bmc_config${bld_suffix}.xml" + local pfm_signed_bin="pfm_signed${bld_suffix}.bin" + local signed_cap_bin="bmc_signedcap${bld_suffix}.bin" + local unsigned_cap_bin="bmc_unsigned_cap${bld_suffix}.bin" + local unsigned_cap_align_bin="bmc_unsigned_cap${bld_suffix}.bin_aligned" + local output_bin="image-mtd-pfr${bld_suffix}" + + # python script that does creating PFM & BMC unsigned, compressed image (from BMC 128MB raw binary file). + ${PFR_SCRIPT_DIR}/pfr_image.py -m ${PFR_CFG_DIR}/${manifest_json} -i ${DEPLOY_DIR_IMAGE}/image-mtd -n ${build_version} -b ${build_number} \ + -h ${build_hash} -s ${SHA} -o ${output_bin} + + # sign the PFM region + ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/${pfmconfig_xml} -o ${PFR_IMAGES_DIR}/${pfm_signed_bin} ${PFR_IMAGES_DIR}/pfm.bin -v + + # Add the signed PFM to rom image + dd bs=1k conv=notrunc seek=${PFM_OFFSET_PAGE} if=${PFR_IMAGES_DIR}/${pfm_signed_bin} of=${PFR_IMAGES_DIR}/${output_bin} + + # Create unsigned BMC update capsule - append with 1. pfm_signed, 2. pbc, 3. bmc compressed + dd if=${PFR_IMAGES_DIR}/${pfm_signed_bin} bs=1k >> ${PFR_IMAGES_DIR}/${unsigned_cap_bin} + + dd if=${PFR_IMAGES_DIR}/pbc.bin bs=1k >> ${PFR_IMAGES_DIR}/${unsigned_cap_bin} + + dd if=${PFR_IMAGES_DIR}/bmc_compressed.bin bs=1k >> ${PFR_IMAGES_DIR}/${unsigned_cap_bin} + + # Sign the BMC update capsule + ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/${bmcconfig_xml} -o ${PFR_IMAGES_DIR}/${signed_cap_bin} ${PFR_IMAGES_DIR}/${unsigned_cap_bin} -v + + # Add the signed bmc update capsule to full rom image @ 0x2a00000 + dd bs=1k conv=notrunc seek=${RC_IMAGE_PAGE} if=${PFR_IMAGES_DIR}/${signed_cap_bin} of=${PFR_IMAGES_DIR}/${output_bin} + + # Rename all PFR output images by appending date and time, so that they don't meddle with subsequent call to this function. + mv ${PFR_IMAGES_DIR}/${pfm_signed_bin} ${PFR_IMAGES_DIR}/pfm_signed${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/${unsigned_cap_bin} ${PFR_IMAGES_DIR}/bmc_unsigned_cap${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/${unsigned_cap_align_bin} ${PFR_IMAGES_DIR}/bmc_unsigned_cap${bld_suffix}-${DATETIME}.bin_aligned + mv ${PFR_IMAGES_DIR}/${signed_cap_bin} ${PFR_IMAGES_DIR}/bmc_signed_cap${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/${output_bin} ${PFR_IMAGES_DIR}/image-mtd-pfr${bld_suffix}-${DATETIME}.bin + # Append date and time to all 'pfr_image.py' output binaries. + mv ${PFR_IMAGES_DIR}/pfm.bin ${PFR_IMAGES_DIR}/pfm${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/pfm.bin_aligned ${PFR_IMAGES_DIR}/pfm${bld_suffix}-${DATETIME}.bin_aligned + mv ${PFR_IMAGES_DIR}/pbc.bin ${PFR_IMAGES_DIR}/pbc${bld_suffix}-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/bmc_compressed.bin ${PFR_IMAGES_DIR}/bmc_compressed${bld_suffix}-${DATETIME}.bin + + # Use relative links. The build process removes some of the build + # artifacts and that makes fully qualified pathes break. Relative links + # work because of the 'cd "${PFR_IMAGES_DIR}"' at the start of this section. + ln -sf image-mtd-pfr${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/image-mtd-pfr${bld_suffix}.bin + ln -sf image-mtd-pfr${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/OBMC${bld_suffix}-${@ do_get_version(d)}-pfr-full.ROM + ln -sf bmc_signed_cap${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/bmc_signed_cap${bld_suffix}.bin + ln -sf bmc_signed_cap${bld_suffix}-${DATETIME}.bin ${PFR_IMAGES_DIR}/OBMC${bld_suffix}-${@ do_get_version(d)}-pfr-oob.bin +} + +do_image_pfr () { + # PFR image, additional build components information suffix. + local bld_suffix="" + + bbplain "Generating Intel PFR compliant BMC image for '${PRODUCT_GENERATION}'" + + bbplain "Build Version = ${build_version}" + bbplain "Build Number = ${build_number}" + bbplain "Build Hash = ${build_hash}" + bbplain "Build SHA = ${SHA_NAME}" + + mkdir -p "${PFR_IMAGES_DIR}" + cd "${PFR_IMAGES_DIR}" + + # First, Build default image. + bld_suffix="" + do_image_pfr_internal + + if [ ${PRODUCT_GENERATION} = "wht" ]; then + #Build additional component images also, for whitley generation, if needed. + if ! [ -z ${BUILD_SEGD} ] && [ ${BUILD_SEGD} = "yes" ]; then + bld_suffix="_d" + do_image_pfr_internal + fi + fi +} + +# Include 'do_image_pfr_internal' in 'vardepsexclude';Else Taskhash mismatch error will occur. +do_image_pfr[vardepsexclude] += "do_image_pfr_internal DATE DATETIME BUILD_SEGD" +do_image_pfr[vardeps] += "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16" +do_image_pfr[depends] += " \ + obmc-intel-pfr-image-native:do_populate_sysroot \ + intel-blocksign-native:do_populate_sysroot \ + " + +python() { + product_gen = d.getVar('PRODUCT_GENERATION', True) + if product_gen == "wht": + d.setVar('SHA', "1")# 1- SHA256 + d.setVar('SHA_NAME', "SHA256") + + types = d.getVar('IMAGE_FSTYPES', True).split() + + if 'intel-pfr' in types: + + bld_ver1 = d.getVar('IPMI_MAJOR', True) + bld_ver1 = int(bld_ver1) << 8 + + bld_ver2 = d.getVar('IPMI_MINOR', True) + bld_ver2 = int(bld_ver2) + + bld_ver = bld_ver1 | bld_ver2 + d.setVar('build_version', str(bld_ver)) + + bld_num = d.getVar('IPMI_AUX13', True) + + d.setVar('build_number', bld_num) + + bld_hash1 = d.getVar('IPMI_AUX14', True) + bld_hash2 = d.getVar('IPMI_AUX15', True) + bld_hash3 = d.getVar('IPMI_AUX16', True) + + bld_hash1 = int(bld_hash1, 16) + bld_hash2 = int(bld_hash2, 16) + bld_hash3 = int(bld_hash3, 16) + + bld_hash = bld_hash3 << 16 + bld_hash |= bld_hash2 << 8 + bld_hash |= bld_hash1 + + d.setVar('build_hash', str(bld_hash)) + + bb.build.addtask(# task, depends_on_task, task_depends_on, d ) + 'do_image_pfr', + 'do_build', + 'do_generate_auto', d) +} + diff --git a/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass b/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass new file mode 100644 index 000000000..0c32e0e53 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass @@ -0,0 +1,80 @@ +# Base image class extension, inlined into every image. + +# Phosphor image types +# +# New image types based on DTS partition information +# +inherit logging + +# Image composition +FLASH_FULL_IMAGE ?= "fitImage-rootfs-${MACHINE}.bin" + +IMAGE_BASETYPE ?= "squashfs-xz" +OVERLAY_BASETYPE ?= "jffs2" + +IMAGE_TYPES += "mtd-auto" + +IMAGE_TYPEDEP_mtd-auto = "${IMAGE_BASETYPE}" +IMAGE_TYPES_MASKED += "mtd-auto" + +# Flash characteristics in KB unless otherwise noted +python() { + types = d.getVar('IMAGE_FSTYPES', True).split() + + # TODO: find partition list in DTS + d.setVar('FLASH_UBOOT_OFFSET', str(0)) + if 'intel-pfr' in types: + d.setVar('FLASH_SIZE', str(128*1024)) + DTB_FULL_FIT_IMAGE_OFFSETS = [0xb00000] + else: + d.setVar('FLASH_SIZE', str(64*1024)) + DTB_FULL_FIT_IMAGE_OFFSETS = [0x80000, 0x2480000] + + d.setVar('FLASH_RUNTIME_OFFSETS', ' '.join( + [str(int(x/1024)) for x in DTB_FULL_FIT_IMAGE_OFFSETS] + ) + ) +} + +mk_nor_image() { + image_dst="$1" + image_size_kb=$2 + dd if=/dev/zero bs=1k count=$image_size_kb \ + | tr '\000' '\377' > $image_dst +} + +do_generate_auto() { + bbdebug 1 "do_generate_auto IMAGE_TYPES=${IMAGE_TYPES} size=${FLASH_SIZE}KB (${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.auto.mtd)" + # Assemble the flash image + mk_nor_image ${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd ${FLASH_SIZE} + dd bs=1k conv=notrunc seek=${FLASH_UBOOT_OFFSET} \ + if=${DEPLOY_DIR_IMAGE}/u-boot.${UBOOT_SUFFIX} \ + of=${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd + + for OFFSET in ${FLASH_RUNTIME_OFFSETS}; do + dd bs=1k conv=notrunc seek=${OFFSET} \ + if=${DEPLOY_DIR_IMAGE}/${FLASH_FULL_IMAGE} \ + of=${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd + done + + ln ${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd \ + ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.auto.mtd + ln -sf ${IMAGE_NAME}.auto.mtd ${DEPLOY_DIR_IMAGE}/image-mtd + ln -sf ${IMAGE_NAME}.auto.mtd ${DEPLOY_DIR_IMAGE}/OBMC-${@ do_get_version(d)}.ROM +} +do_generate_auto[dirs] = "${S}/auto" +do_generate_auto[depends] += " \ + ${PN}:do_image_${@d.getVar('IMAGE_BASETYPE', True).replace('-', '_')} \ + virtual/kernel:do_deploy \ + u-boot:do_populate_sysroot \ + " + +python() { + types = d.getVar('IMAGE_FSTYPES', True).split() + + if 'mtd-auto' in types: + bb.build.addtask(# task, depends_on_task, task_depends_on, d ) + 'do_generate_auto', + 'do_build', + 'do_image_complete', d) +} 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 new file mode 100644 index 000000000..6e0411a5c --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass @@ -0,0 +1,573 @@ +inherit uboot-sign logging + +DEPENDS += "u-boot-mkimage-native" + +SIGNING_KEY ?= "${STAGING_DIR_NATIVE}${datadir}/OpenBMC.priv" +INSECURE_KEY = "${@'${SIGNING_KEY}' == '${STAGING_DIR_NATIVE}${datadir}/OpenBMC.priv'}" +SIGNING_KEY_DEPENDS = "${@oe.utils.conditional('INSECURE_KEY', 'True', 'phosphor-insecure-signing-key-native:do_populate_sysroot', '', d)}" + +DEPS = " ${PN}:do_image_${@d.getVar('IMAGE_BASETYPE', True).replace('-', '_')} \ + virtual/kernel:do_deploy \ + u-boot:do_populate_sysroot " + +# Options for the device tree compiler passed to mkimage '-D' feature: +UBOOT_MKIMAGE_DTCOPTS ??= "" + +# +# Emit the fitImage ITS header +# +# $1 ... .its filename +fitimage_emit_fit_header() { + cat << EOF >> ${1} +/dts-v1/; + +/ { + description = "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"; + #address-cells = <1>; +EOF +} + +# +# Emit the fitImage section bits +# +# $1 ... .its filename +# $2 ... Section bit type: imagestart - image section start +# confstart - configuration section start +# sectend - section end +# fitend - fitimage end +# +fitimage_emit_section_maint() { + case $2 in + imagestart) + cat << EOF >> ${1} + + images { +EOF + ;; + confstart) + cat << EOF >> ${1} + + configurations { +EOF + ;; + sectend) + cat << EOF >> ${1} + }; +EOF + ;; + fitend) + cat << EOF >> ${1} +}; +EOF + ;; + esac +} + +# +# Emit the fitImage ITS kernel section +# +# $1 ... .its filename +# $2 ... Image counter +# $3 ... Path to kernel image +# $4 ... Compression type +# $5 ... Hash type +fitimage_emit_section_kernel() { + + kernel_csum="${5}" + + if [ -n "${kernel_csum}" ]; then + hash_blk=$(cat << EOF + hash-1 { + algo = "${kernel_csum}"; + }; +EOF + ) + fi + + ENTRYPOINT=${UBOOT_ENTRYPOINT} + if [ -n "${UBOOT_ENTRYSYMBOL}" ]; then + ENTRYPOINT=`${HOST_PREFIX}nm vmlinux | \ + awk '$3=="${UBOOT_ENTRYSYMBOL}" {print "0x"$1;exit}'` + fi + + cat << EOF >> ${1} + kernel-${2} { + description = "Linux kernel"; + data = /incbin/("${3}"); + type = "kernel"; + arch = "${UBOOT_ARCH}"; + os = "linux"; + compression = "${4}"; + load = <${UBOOT_LOADADDRESS}>; + entry = <${ENTRYPOINT}>; + ${hash_blk} + }; +EOF +} + +# +# Emit the fitImage ITS DTB section +# +# $1 ... .its filename +# $2 ... Image counter +# $3 ... Path to DTB image +# $4 ... Hash type +fitimage_emit_section_dtb() { + + dtb_csum="${4}" + if [ -n "${dtb_csum}" ]; then + hash_blk=$(cat << EOF + hash-1 { + algo = "${dtb_csum}"; + }; +EOF + ) + fi + + cat << EOF >> ${1} + fdt-${2} { + description = "Flattened Device Tree blob"; + data = /incbin/("${3}"); + type = "flat_dt"; + arch = "${UBOOT_ARCH}"; + compression = "none"; + ${hash_blk} + }; +EOF +} + +# +# Emit the fitImage ITS setup section +# +# $1 ... .its filename +# $2 ... Image counter +# $3 ... Path to setup image +# $4 ... Hash type +fitimage_emit_section_setup() { + + setup_csum="${4}" + if [ -n "${setup_csum}" ]; then + hash_blk=$(cat << EOF + hash-1 { + algo = "${setup_csum}"; + }; +EOF + ) + fi + + cat << EOF >> ${1} + setup-${2} { + description = "Linux setup.bin"; + data = /incbin/("${3}"); + type = "x86_setup"; + arch = "${UBOOT_ARCH}"; + os = "linux"; + compression = "none"; + load = <0x00090000>; + entry = <0x00090000>; + ${hash_blk} + }; +EOF +} + +# +# Emit the fitImage ITS ramdisk section +# +# $1 ... .its filename +# $2 ... Image counter +# $3 ... Path to ramdisk image +# $4 ... Hash type +fitimage_emit_section_ramdisk() { + + ramdisk_csum="${4}" + if [ -n "${ramdisk_csum}" ]; then + hash_blk=$(cat << EOF + hash-1 { + algo = "${ramdisk_csum}"; + }; +EOF + ) + fi + ramdisk_ctype="none" + ramdisk_loadline="" + ramdisk_entryline="" + + if [ -n "${UBOOT_RD_LOADADDRESS}" ]; then + ramdisk_loadline="load = <${UBOOT_RD_LOADADDRESS}>;" + fi + if [ -n "${UBOOT_RD_ENTRYPOINT}" ]; then + ramdisk_entryline="entry = <${UBOOT_RD_ENTRYPOINT}>;" + fi + + case $3 in + *.gz) + ramdisk_ctype="gzip" + ;; + *.bz2) + ramdisk_ctype="bzip2" + ;; + *.lzma) + ramdisk_ctype="lzma" + ;; + *.lzo) + ramdisk_ctype="lzo" + ;; + *.lz4) + ramdisk_ctype="lz4" + ;; + esac + + cat << EOF >> ${1} + ramdisk-${2} { + description = "${INITRAMFS_IMAGE}"; + data = /incbin/("${3}"); + type = "ramdisk"; + arch = "${UBOOT_ARCH}"; + os = "linux"; + compression = "${ramdisk_ctype}"; + ${ramdisk_loadline} + ${ramdisk_entryline} + ${hash_blk} + }; +EOF +} + +# +# Emit the fitImage ITS configuration section +# +# $1 ... .its filename +# $2 ... Linux kernel ID +# $3 ... DTB image name +# $4 ... ramdisk ID +# $5 ... config ID +# $6 ... default flag +# $7 ... Hash type +# $8 ... DTB index +fitimage_emit_section_config() { + + conf_csum="${7}" + if [ -n "${conf_csum}" ]; then + hash_blk=$(cat << EOF + hash-1 { + algo = "${conf_csum}"; + }; +EOF + ) + fi + if [ -n "${UBOOT_SIGN_ENABLE}" ] ; then + conf_sign_keyname="${UBOOT_SIGN_KEYNAME}" + fi + + # Test if we have any DTBs at all + conf_desc="Linux kernel" + kernel_line="kernel = \"kernel-${2}\";" + fdt_line="" + ramdisk_line="" + setup_line="" + default_line="" + + if [ -n "${3}" ]; then + conf_desc="${conf_desc}, FDT blob" + fdt_line="fdt = \"fdt-${3}\";" + fi + + if [ -n "${4}" ]; then + conf_desc="${conf_desc}, ramdisk" + ramdisk_line="ramdisk = \"ramdisk-${4}\";" + fi + + if [ -n "${5}" ]; then + conf_desc="${conf_desc}, setup" + setup_line="setup = \"setup-${5}\";" + fi + + if [ "${6}" = "1" ]; then + default_line="default = \"conf-${3}\";" + fi + + cat << EOF >> ${1} + ${default_line} + conf-${3} { + description = "${6} ${conf_desc}"; + ${kernel_line} + ${fdt_line} + ${ramdisk_line} + ${setup_line} + ${hash_blk} +EOF + + if [ ! -z "${conf_sign_keyname}" ] ; then + + sign_line="sign-images = \"kernel\"" + + if [ -n "${3}" ]; then + sign_line="${sign_line}, \"fdt\"" + fi + + if [ -n "${4}" ]; then + sign_line="${sign_line}, \"ramdisk\"" + fi + + if [ -n "${5}" ]; then + sign_line="${sign_line}, \"setup\"" + fi + + sign_line="${sign_line};" + + cat << EOF >> ${1} + signature-1 { + algo = "${conf_csum},rsa2048"; + key-name-hint = "${conf_sign_keyname}"; + ${sign_line} + }; +EOF + fi + + cat << EOF >> ${1} + }; +EOF +} + +# +# Assemble fitImage +# +# $1 ... .its filename +# $2 ... fitImage name +# $3 ... include rootfs +fitimage_assemble() { + kernelcount=1 + dtbcount="" + DTBS="" + ramdiskcount=${3} + setupcount="" + #hash_type="sha256" + hash_type="" + rm -f ${1} ${2} + + # + # Step 0: find the kernel image in the deploy/images/$machine dir + # + KIMG="" + for KTYPE in zImage bzImage vmlinuz; do + if [ -e "${DEPLOY_DIR_IMAGE}/${ktype}" ]; then + KIMG="${DEPLOY_DIR_IMAGE}/${KTYPE}" + break + fi + done + if [ -z "${KIMG}" ]; then + bbdebug 1 "Failed to find kernel image to pack into full fitimage" + return 1 + fi + + fitimage_emit_fit_header ${1} + + # + # Step 1: Prepare a kernel image section. + # + fitimage_emit_section_maint ${1} imagestart + + fitimage_emit_section_kernel ${1} "${kernelcount}" "${KIMG}" "none" "${hash_type}" + + # + # Step 2: Prepare a DTB image section + # + if [ -n "${KERNEL_DEVICETREE}" ]; then + dtbcount=1 + for DTB in ${KERNEL_DEVICETREE}; do + if echo ${DTB} | grep -q '/dts/'; then + bberror "${DTB} contains the full path to the the dts file, but only the dtb name should be used." + DTB=`basename ${DTB} | sed 's,\.dts$,.dtb,g'` + fi + DTB_PATH="${DEPLOY_DIR_IMAGE}/${DTB}" + if [ ! -e "${DTB_PATH}" ]; then + bbwarn "${DTB_PATH} does not exist" + continue + fi + + DTB=$(echo "${DTB}" | tr '/' '_') + DTBS="${DTBS} ${DTB}" + fitimage_emit_section_dtb ${1} ${DTB} ${DTB_PATH} "${hash_type}" + done + fi + + # + # Step 3: Prepare a setup section. (For x86) + # + if [ -e arch/${ARCH}/boot/setup.bin ]; then + setupcount=1 + fitimage_emit_section_setup ${1} "${setupcount}" arch/${ARCH}/boot/setup.bin "${hash_type}" + fi + + # + # Step 4: Prepare a ramdisk section. + # + if [ "x${ramdiskcount}" = "x1" ] ; then + bbdebug 1 "searching for requested rootfs" + # Find and use the first initramfs image archive type we find + for img in squashfs-lz4 squashfs-xz squashfs cpio.lz4 cpio.lzo cpio.lzma cpio.xz cpio.gz cpio; do + initramfs_path="${DEPLOY_DIR_IMAGE}/${IMAGE_BASENAME}-${MACHINE}.${img}" + bbdebug 1 "looking for ${initramfs_path}" + if [ -e "${initramfs_path}" ]; then + bbdebug 1 "Found ${initramfs_path}" + fitimage_emit_section_ramdisk ${1} "${ramdiskcount}" "${initramfs_path}" "${hash_type}" + break + fi + done + fi + + fitimage_emit_section_maint ${1} sectend + + # Force the first Kernel and DTB in the default config + kernelcount=1 + if [ -n "${dtbcount}" ]; then + dtbcount=1 + fi + + # + # Step 5: Prepare a configurations section + # + fitimage_emit_section_maint ${1} confstart + + 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}" "${i}" + i=`expr ${i} + 1` + done + fi + + fitimage_emit_section_maint ${1} sectend + + fitimage_emit_section_maint ${1} fitend + + # + # Step 6: Assemble the image + # + uboot-mkimage \ + ${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \ + -f ${1} ${2} + + # + # Step 7: Sign the image and add public key to U-Boot dtb + # + if [ "x${UBOOT_SIGN_ENABLE}" = "x1" ] ; then + uboot-mkimage \ + ${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \ + -F -k "${UBOOT_SIGN_KEYDIR}" \ + -K "${DEPLOY_DIR_IMAGE}/${UBOOT_DTB_BINARY}" \ + -r ${2} + fi +} + +python do_generate_phosphor_manifest() { + import os.path + b = d.getVar('B', True) + manifest_filename = os.path.join(b, "MANIFEST") + version = do_get_version(d) + with open(manifest_filename, 'w') as fd: + fd.write('purpose=xyz.openbmc_project.Software.Version.VersionPurpose.BMC\n') + fd.write('version={}\n'.format(version.strip('"'))) + fd.write('KeyType={}\n'.format("OpenBMC")) + 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] + +def get_pubkey_path(d): + return os.path.join( + get_pubkey_basedir(d), + get_pubkey_type(d), + 'publickey') +python do_copy_signing_pubkey() { + with open(get_pubkey_path(d), 'r') as read_fd: + with open('publickey', 'w') as write_fd: + write_fd.write(read_fd.read()) +} + +do_copy_signing_pubkey[dirs] = "${S}" +do_copy_signing_pubkey[depends] += " \ + phosphor-image-signing:do_populate_sysroot \ + " + +do_image_fitimage_rootfs() { + bbdebug 1 "check for rootfs phosphor fitimage" + cd ${B} + bbdebug 1 "building rootfs phosphor fitimage" + fitimage_assemble fitImage-rootfs-${MACHINE}-${DATETIME}.its \ + fitImage-rootfs-${MACHINE}-${DATETIME}.bin 1 + + for SFX in its bin; do + SRC="fitImage-rootfs-${MACHINE}-${DATETIME}.${SFX}" + SYM="fitImage-rootfs-${MACHINE}.${SFX}" + if [ -e "${B}/${SRC}" ]; then + install -m 0644 "${B}/${SRC}" "${DEPLOY_DIR_IMAGE}/${SRC}" + ln -sf "${SRC}" "${DEPLOY_DIR_IMAGE}/${SYM}" + fi + done + ln -sf "${DEPLOY_DIR_IMAGE}/fitImage-rootfs-${MACHINE}.bin" "image-runtime" + # build a tarball with the right parts: MANIFEST, signatures, etc. + # create a directory for the tarball + mkdir -p "${B}/img" + cd "${B}/img" + # add symlinks for the contents + ln -sf "${DEPLOY_DIR_IMAGE}/u-boot.${UBOOT_SUFFIX}" "image-u-boot" + ln -sf "${DEPLOY_DIR_IMAGE}/fitImage-rootfs-${MACHINE}.bin" "image-runtime" + # add the manifest + bbdebug 1 "Manifest file: ${B}/MANIFEST" + ln -sf ${B}/MANIFEST . + # touch the required files to minimize change + touch image-kernel image-rofs image-rwfs + + 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" +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 new file mode 100644 index 000000000..e61eb2dae --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass @@ -0,0 +1,90 @@ +inherit obmc-phosphor-image + +IMAGE_FEATURES += " \ + obmc-bmc-state-mgmt \ + obmc-bmcweb \ + obmc-chassis-mgmt \ + obmc-chassis-state-mgmt \ + obmc-devtools \ + obmc-fan-control \ + obmc-fan-mgmt \ + obmc-flash-mgmt \ + obmc-host-ctl \ + obmc-host-ipmi \ + obmc-host-state-mgmt \ + obmc-inventory \ + obmc-leds \ + obmc-logging-mgmt \ + obmc-remote-logging-mgmt \ + obmc-net-ipmi \ + obmc-sensors \ + obmc-software \ + obmc-system-mgmt \ + obmc-user-mgmt \ + ${@bb.utils.contains('DISTRO_FEATURES', 'obmc-ubi-fs', 'read-only-rootfs', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'phosphor-mmc', 'read-only-rootfs', '', d)} \ + ssh-server-dropbear \ + obmc-debug-collector \ + obmc-network-mgmt \ + obmc-settings-mgmt \ + obmc-console \ + " + +IMAGE_INSTALL_append = " \ + dbus-broker \ + entity-manager \ + fru-device \ + ipmitool \ + intel-ipmi-oem \ + phosphor-ipmi-ipmb \ + phosphor-node-manager-proxy \ + dbus-sensors \ + webui-vue \ + at-scale-debug \ + phosphor-pid-control \ + phosphor-host-postd \ + phosphor-certificate-manager \ + phosphor-sel-logger \ + smbios-mdrv2 \ + obmc-ikvm \ + system-watchdog \ + frb2-watchdog \ + srvcfg-manager \ + callback-manager \ + phosphor-post-code-manager \ + preinit-mounts \ + mtd-utils-ubifs \ + special-mode-mgr \ + rsyslog \ + static-mac-addr \ + phosphor-u-boot-mgr \ + prov-mode-mgr \ + ac-boot-check \ + host-error-monitor \ + beepcode-mgr \ + psu-manager \ + kernel-panic-check \ + id-led-off \ + hsbp-manager \ + security-registers-check \ + pch-time-sync \ + nv-sync \ + security-manager \ + multi-node-nl \ + virtual-media \ + enable-nics \ + host-misc-comm-manager \ + biosconfig-manager \ + telemetry \ + i3c-tools \ + configure-usb-c \ + " + +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" + +BAD_RECOMMENDATIONS += "phosphor-settings-manager" diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass new file mode 100644 index 000000000..6a1ac3f14 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass @@ -0,0 +1,7 @@ +IMAGE_INSTALL_append = " \ + mtd-util \ + io-app \ + intel-fw-update \ + lpc-cmds \ + beeper-test \ + " diff --git a/meta-openbmc-mods/meta-common/classes/print-src.bbclass b/meta-openbmc-mods/meta-common/classes/print-src.bbclass new file mode 100644 index 000000000..f305a5433 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/print-src.bbclass @@ -0,0 +1,7 @@ +python do_print_src () { + srcuri = d.getVar('SRC_URI', True).split() + srcrev = d.getVar('SRCREV', True).split() + bb.warn("SRC_URI: %s SRCREV: %s" % (srcuri, srcrev)) +} + +addtask do_print_src before do_fetch diff --git a/meta-openbmc-mods/meta-common/conf/layer.conf b/meta-openbmc-mods/meta-common/conf/layer.conf new file mode 100644 index 000000000..5d4becae0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/conf/layer.conf @@ -0,0 +1,11 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "common" +BBFILE_PATTERN_common = "^${LAYERDIR}/" +BBFILE_PRIORITY_common = "9" +LAYERSERIES_COMPAT_common = "gatesgarth hardknott" diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config new file mode 100644 index 000000000..19ace4b88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config @@ -0,0 +1,25 @@ +# Configuration file for fw_(printenv/setenv) utility. +# Up to two entries are valid, in this case the redundant +# environment sector is assumed present. +# Notice, that the "Number of sectors" is ignored on NOR and SPI-dataflash. +# Furthermore, if the Flash sector size is omitted, this value is assumed to +# be the same as the Environment size, which is valid for NOR and SPI-dataflash + +# NOR example +# MTD device name Device offset Env. size Flash sector size Number of sectors +#/dev/mtd1 0x0000 0x20000 0x20000 +#/dev/mtd2 0x0000 0x4000 0x4000 + +# MTD SPI-dataflash example +# MTD device name Device offset Env. size Flash sector size Number of sectors +#/dev/mtd2 0x00000 0x20000 +/dev/mtd/u-boot-env 0x00000 0x10000 +/dev/mtd/u-boot-env 0x10000 0x10000 +#/dev/mtd5 0x4200 0x4200 +#/dev/mtd6 0x4200 0x4200 + +# NAND example +#/dev/mtd0 0x4000 0x4000 0x20000 2 + +# Block device example +#/dev/mmcblk0 0xc0000 0x20000 diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend new file mode 100644 index 000000000..eee5194fb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += " \ + file://fw_env.config \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/files/environment.d-openssl.sh b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/files/environment.d-openssl.sh new file mode 100644 index 000000000..b9cc24a7a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/files/environment.d-openssl.sh @@ -0,0 +1 @@ +export OPENSSL_CONF="$OECORE_NATIVE_SYSROOT/usr/lib/ssl/openssl.cnf" diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/0001-buildinfo-strip-sysroot-and-debug-prefix-map-from-co.patch b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/0001-buildinfo-strip-sysroot-and-debug-prefix-map-from-co.patch new file mode 100644 index 000000000..949c78834 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/0001-buildinfo-strip-sysroot-and-debug-prefix-map-from-co.patch @@ -0,0 +1,76 @@ +From 3e1d00481093e10775eaf69d619c45b32a4aa7dc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= <martin@geanix.com> +Date: Tue, 6 Nov 2018 14:50:47 +0100 +Subject: [PATCH] buildinfo: strip sysroot and debug-prefix-map from compiler + info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The openssl build system generates buildinf.h containing the full +compiler command line used to compile objects. This breaks +reproducibility, as the compile command is baked into libcrypto, where +it is used when running `openssl version -f`. + +Add stripped build variables for the compiler and cflags lines, and use +those when generating buildinfo.h. + +This is based on a similar patch for older openssl versions: +https://patchwork.openembedded.org/patch/147229/ + +Upstream-Status: Inappropriate [OE specific] +Signed-off-by: Martin Hundebøll <martin@geanix.com> + + +Update to fix buildpaths qa issue for '-fmacro-prefix-map'. + +Signed-off-by: Kai Kang <kai.kang@windriver.com> +--- + Configurations/unix-Makefile.tmpl | 10 +++++++++- + crypto/build.info | 2 +- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl +index 16af4d2087..54c162784c 100644 +--- a/Configurations/unix-Makefile.tmpl ++++ b/Configurations/unix-Makefile.tmpl +@@ -317,13 +317,22 @@ BIN_LDFLAGS={- join(' ', $target{bin_lflags} || (), + '$(CNF_LDFLAGS)', '$(LDFLAGS)') -} + BIN_EX_LIBS=$(CNF_EX_LIBS) $(EX_LIBS) + +-# CPPFLAGS_Q is used for one thing only: to build up buildinf.h ++# *_Q variables are used for one thing only: to build up buildinf.h + CPPFLAGS_Q={- $cppflags1 =~ s|([\\"])|\\$1|g; + $cppflags2 =~ s|([\\"])|\\$1|g; + $lib_cppflags =~ s|([\\"])|\\$1|g; + join(' ', $lib_cppflags || (), $cppflags2 || (), + $cppflags1 || ()) -} + ++CFLAGS_Q={- for (@{$config{CFLAGS}}) { ++ s|-fdebug-prefix-map=[^ ]+|-fdebug-prefix-map=|g; ++ s|-fmacro-prefix-map=[^ ]+|-fmacro-prefix-map=|g; ++ } ++ join(' ', @{$config{CFLAGS}}) -} ++ ++CC_Q={- $config{CC} =~ s|--sysroot=[^ ]+|--sysroot=recipe-sysroot|g; ++ join(' ', $config{CC}) -} ++ + PERLASM_SCHEME= {- $target{perlasm_scheme} -} + + # For x86 assembler: Set PROCESSOR to 386 if you want to support +diff --git a/crypto/build.info b/crypto/build.info +index b515b7318e..8c9cee2a09 100644 +--- a/crypto/build.info ++++ b/crypto/build.info +@@ -10,7 +10,7 @@ EXTRA= ../ms/uplink-x86.pl ../ms/uplink.c ../ms/applink.c \ + ppccpuid.pl pariscid.pl alphacpuid.pl arm64cpuid.pl armv4cpuid.pl + + DEPEND[cversion.o]=buildinf.h +-GENERATE[buildinf.h]=../util/mkbuildinf.pl "$(CC) $(LIB_CFLAGS) $(CPPFLAGS_Q)" "$(PLATFORM)" ++GENERATE[buildinf.h]=../util/mkbuildinf.pl "$(CC_Q) $(CFLAGS_Q) $(CPPFLAGS_Q)" "$(PLATFORM)" + DEPEND[buildinf.h]=../configdata.pm + + GENERATE[uplink-x86.s]=../ms/uplink-x86.pl $(PERLASM_SCHEME) +-- +2.19.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/0001-skip-test_symbol_presence.patch b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/0001-skip-test_symbol_presence.patch new file mode 100644 index 000000000..d8d9651b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/0001-skip-test_symbol_presence.patch @@ -0,0 +1,46 @@ +From a9401b2289656c5a36dd1b0ecebf0d23e291ce70 Mon Sep 17 00:00:00 2001 +From: Hongxu Jia <hongxu.jia@windriver.com> +Date: Tue, 2 Oct 2018 23:58:24 +0800 +Subject: [PATCH] skip test_symbol_presence + +We cannot skip `01-test_symbol_presence.t' by configuring option `no-shared' +as INSTALL told us the shared libraries will not be built. + +[INSTALL snip] + Notes on shared libraries + ------------------------- + + For most systems the OpenSSL Configure script knows what is needed to + build shared libraries for libcrypto and libssl. On these systems + the shared libraries will be created by default. This can be suppressed and + only static libraries created by using the "no-shared" option. On systems + where OpenSSL does not know how to build shared libraries the "no-shared" + option will be forced and only static libraries will be created. +[INSTALL snip] + +Hence directly modification the case to skip it. + +Upstream-Status: Inappropriate [OE Specific] + +Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> +--- + test/recipes/01-test_symbol_presence.t | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/test/recipes/01-test_symbol_presence.t b/test/recipes/01-test_symbol_presence.t +index 7f2a2d7..0b93745 100644 +--- a/test/recipes/01-test_symbol_presence.t ++++ b/test/recipes/01-test_symbol_presence.t +@@ -14,8 +14,7 @@ use OpenSSL::Test::Utils; + + setup("test_symbol_presence"); + +-plan skip_all => "Only useful when building shared libraries" +- if disabled("shared"); ++plan skip_all => "The case needs debug symbols then we just disable it"; + + my @libnames = ("crypto", "ssl"); + my $testcount = scalar @libnames; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/afalg.patch b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/afalg.patch new file mode 100644 index 000000000..b7c0e9697 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/afalg.patch @@ -0,0 +1,31 @@ +Don't refuse to build afalgeng if cross-compiling or the host kernel is too old. + +Upstream-Status: Submitted [hhttps://github.com/openssl/openssl/pull/7688] +Signed-off-by: Ross Burton <ross.burton@intel.com> + +diff --git a/Configure b/Configure +index 3baa8ce..9ef52ed 100755 +--- a/Configure ++++ b/Configure +@@ -1550,20 +1550,7 @@ unless ($disabled{"crypto-mdebug-backtrace"}) + unless ($disabled{afalgeng}) { + $config{afalgeng}=""; + if (grep { $_ eq 'afalgeng' } @{$target{enable}}) { +- my $minver = 4*10000 + 1*100 + 0; +- if ($config{CROSS_COMPILE} eq "") { +- my $verstr = `uname -r`; +- my ($ma, $mi1, $mi2) = split("\\.", $verstr); +- ($mi2) = $mi2 =~ /(\d+)/; +- my $ver = $ma*10000 + $mi1*100 + $mi2; +- if ($ver < $minver) { +- disable('too-old-kernel', 'afalgeng'); +- } else { +- push @{$config{engdirs}}, "afalg"; +- } +- } else { +- disable('cross-compiling', 'afalgeng'); +- } ++ push @{$config{engdirs}}, "afalg"; + } else { + disable('not-linux', 'afalgeng'); + } diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/reproducible.patch b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/reproducible.patch new file mode 100644 index 000000000..a24260c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/reproducible.patch @@ -0,0 +1,32 @@ +The value for perl_archname can vary depending on the host, e.g. +x86_64-linux-gnu-thread-multi or x86_64-linux-thread-multi which +makes the ptest package non-reproducible. Its unused other than +these references so drop it. + +RP 2020/2/6 + +Upstream-Status: Pending +Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> + +Index: openssl-1.1.1d/Configure +=================================================================== +--- openssl-1.1.1d.orig/Configure ++++ openssl-1.1.1d/Configure +@@ -286,7 +286,7 @@ if (defined env($local_config_envname)) + # Save away perl command information + $config{perl_cmd} = $^X; + $config{perl_version} = $Config{version}; +-$config{perl_archname} = $Config{archname}; ++#$config{perl_archname} = $Config{archname}; + + $config{prefix}=""; + $config{openssldir}=""; +@@ -2517,7 +2517,7 @@ _____ + @{$config{perlargv}}), "\n"; + print "\nPerl information:\n\n"; + print ' ',$config{perl_cmd},"\n"; +- print ' ',$config{perl_version},' for ',$config{perl_archname},"\n"; ++ print ' ',$config{perl_version},"\n"; + } + if ($dump || $options) { + my $longest = 0; diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/run-ptest b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/run-ptest new file mode 100644 index 000000000..3fb22471f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl/run-ptest @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +# Optional arguments are 'list' to lists all tests, or the test name (base name +# ie test_evp, not 03_test_evp.t). + +export TOP=. +# OPENSSL_ENGINES is relative from the test binaries +export OPENSSL_ENGINES=../engines + +perl ./test/run_tests.pl $* | perl -0pe 's#(.*) \.*.ok#PASS: \1#g; s#(.*) \.*.skipped: (.*)#SKIP: \1 (\2)#g; s#(.*) \.*.\nDubious#FAIL: \1#;' diff --git a/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl_1.1.1k.bb b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl_1.1.1k.bb new file mode 100644 index 000000000..034cc610d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-connectivity/openssl/openssl_1.1.1k.bb @@ -0,0 +1,211 @@ +SUMMARY = "Secure Socket Layer" +DESCRIPTION = "Secure Socket Layer (SSL) binary and related cryptographic tools." +HOMEPAGE = "http://www.openssl.org/" +BUGTRACKER = "http://www.openssl.org/news/vulnerabilities.html" +SECTION = "libs/network" + +# "openssl" here actually means both OpenSSL and SSLeay licenses apply +# (see meta/files/common-licenses/OpenSSL to which "openssl" is SPDXLICENSEMAPped) +LICENSE = "openssl" +LIC_FILES_CHKSUM = "file://LICENSE;md5=d343e62fc9c833710bbbed25f27364c8" + +DEPENDS = "hostperl-runtime-native" + +SRC_URI = "http://www.openssl.org/source/openssl-${PV}.tar.gz \ + file://run-ptest \ + file://0001-skip-test_symbol_presence.patch \ + file://0001-buildinfo-strip-sysroot-and-debug-prefix-map-from-co.patch \ + file://afalg.patch \ + file://reproducible.patch \ + " + +SRC_URI_append_class-nativesdk = " \ + file://environment.d-openssl.sh \ + " + +SRC_URI[sha256sum] = "892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5" + +inherit lib_package multilib_header multilib_script ptest +MULTILIB_SCRIPTS = "${PN}-bin:${bindir}/c_rehash" + +PACKAGECONFIG ?= "" +PACKAGECONFIG_class-native = "" +PACKAGECONFIG_class-nativesdk = "" + +PACKAGECONFIG[cryptodev-linux] = "enable-devcryptoeng,disable-devcryptoeng,cryptodev-linux,,cryptodev-module" + +B = "${WORKDIR}/build" +do_configure[cleandirs] = "${B}" + +#| ./libcrypto.so: undefined reference to `getcontext' +#| ./libcrypto.so: undefined reference to `setcontext' +#| ./libcrypto.so: undefined reference to `makecontext' +EXTRA_OECONF_append_libc-musl = " no-async" +EXTRA_OECONF_append_libc-musl_powerpc64 = " no-asm" + +# adding devrandom prevents openssl from using getrandom() which is not available on older glibc versions +# (native versions can be built with newer glibc, but then relocated onto a system with older glibc) +EXTRA_OECONF_class-native = "--with-rand-seed=os,devrandom" +EXTRA_OECONF_class-nativesdk = "--with-rand-seed=os,devrandom" + +# Relying on hardcoded built-in paths causes openssl-native to not be relocateable from sstate. +CFLAGS_append_class-native = " -DOPENSSLDIR=/not/builtin -DENGINESDIR=/not/builtin" +CFLAGS_append_class-nativesdk = " -DOPENSSLDIR=/not/builtin -DENGINESDIR=/not/builtin" + +do_configure () { + os=${HOST_OS} + case $os in + linux-gnueabi |\ + linux-gnuspe |\ + linux-musleabi |\ + linux-muslspe |\ + linux-musl ) + os=linux + ;; + *) + ;; + esac + target="$os-${HOST_ARCH}" + case $target in + linux-arm*) + target=linux-armv4 + ;; + linux-aarch64*) + target=linux-aarch64 + ;; + linux-i?86 | linux-viac3) + target=linux-x86 + ;; + linux-gnux32-x86_64 | linux-muslx32-x86_64 ) + target=linux-x32 + ;; + linux-gnu64-x86_64) + target=linux-x86_64 + ;; + linux-mips | linux-mipsel) + # specifying TARGET_CC_ARCH prevents openssl from (incorrectly) adding target architecture flags + target="linux-mips32 ${TARGET_CC_ARCH}" + ;; + linux-gnun32-mips*) + target=linux-mips64 + ;; + linux-*-mips64 | linux-mips64 | linux-*-mips64el | linux-mips64el) + target=linux64-mips64 + ;; + linux-microblaze* | linux-nios2* | linux-sh3 | linux-sh4 | linux-arc*) + target=linux-generic32 + ;; + linux-powerpc) + target=linux-ppc + ;; + linux-powerpc64) + target=linux-ppc64 + ;; + linux-powerpc64le) + target=linux-ppc64le + ;; + linux-riscv32) + target=linux-generic32 + ;; + linux-riscv64) + target=linux-generic64 + ;; + linux-sparc | linux-supersparc) + target=linux-sparcv9 + ;; + esac + + useprefix=${prefix} + if [ "x$useprefix" = "x" ]; then + useprefix=/ + fi + # WARNING: do not set compiler/linker flags (-I/-D etc.) in EXTRA_OECONF, as they will fully replace the + # environment variables set by bitbake. Adjust the environment variables instead. + HASHBANGPERL="/usr/bin/env perl" PERL=perl PERL5LIB="${S}/external/perl/Text-Template-1.46/lib/" \ + perl ${S}/Configure ${EXTRA_OECONF} ${PACKAGECONFIG_CONFARGS} --prefix=$useprefix --openssldir=${libdir}/ssl-1.1 --libdir=${libdir} $target + perl ${B}/configdata.pm --dump +} + +do_install () { + oe_runmake DESTDIR="${D}" MANDIR="${mandir}" MANSUFFIX=ssl install + + oe_multilib_header openssl/opensslconf.h + + # Create SSL structure for packages such as ca-certificates which + # contain hard-coded paths to /etc/ssl. Debian does the same. + install -d ${D}${sysconfdir}/ssl + mv ${D}${libdir}/ssl-1.1/certs \ + ${D}${libdir}/ssl-1.1/private \ + ${D}${libdir}/ssl-1.1/openssl.cnf \ + ${D}${sysconfdir}/ssl/ + + # Although absolute symlinks would be OK for the target, they become + # invalid if native or nativesdk are relocated from sstate. + ln -sf ${@oe.path.relative('${libdir}/ssl-1.1', '${sysconfdir}/ssl/certs')} ${D}${libdir}/ssl-1.1/certs + ln -sf ${@oe.path.relative('${libdir}/ssl-1.1', '${sysconfdir}/ssl/private')} ${D}${libdir}/ssl-1.1/private + ln -sf ${@oe.path.relative('${libdir}/ssl-1.1', '${sysconfdir}/ssl/openssl.cnf')} ${D}${libdir}/ssl-1.1/openssl.cnf +} + +do_install_append_class-native () { + create_wrapper ${D}${bindir}/openssl \ + OPENSSL_CONF=${libdir}/ssl-1.1/openssl.cnf \ + SSL_CERT_DIR=${libdir}/ssl-1.1/certs \ + SSL_CERT_FILE=${libdir}/ssl-1.1/cert.pem \ + OPENSSL_ENGINES=${libdir}/engines-1.1 +} + +do_install_append_class-nativesdk () { + mkdir -p ${D}${SDKPATHNATIVE}/environment-setup.d + install -m 644 ${WORKDIR}/environment.d-openssl.sh ${D}${SDKPATHNATIVE}/environment-setup.d/openssl.sh + sed 's|/usr/lib/ssl/|/usr/lib/ssl-1.1/|g' -i ${D}${SDKPATHNATIVE}/environment-setup.d/openssl.sh +} + +PTEST_BUILD_HOST_FILES += "configdata.pm" +PTEST_BUILD_HOST_PATTERN = "perl_version =" +do_install_ptest () { + # Prune the build tree + rm -f ${B}/fuzz/*.* ${B}/test/*.* + + cp ${S}/Configure ${B}/configdata.pm ${D}${PTEST_PATH} + cp -r ${S}/external ${B}/test ${S}/test ${B}/fuzz ${S}/util ${B}/util ${D}${PTEST_PATH} + + # For test_shlibload + ln -s ${libdir}/libcrypto.so.1.1 ${D}${PTEST_PATH}/ + ln -s ${libdir}/libssl.so.1.1 ${D}${PTEST_PATH}/ + + install -d ${D}${PTEST_PATH}/apps + ln -s ${bindir}/openssl ${D}${PTEST_PATH}/apps + install -m644 ${S}/apps/*.pem ${S}/apps/*.srl ${S}/apps/openssl.cnf ${D}${PTEST_PATH}/apps + install -m755 ${B}/apps/CA.pl ${D}${PTEST_PATH}/apps + + install -d ${D}${PTEST_PATH}/engines + install -m755 ${B}/engines/ossltest.so ${D}${PTEST_PATH}/engines +} + +# Add the openssl.cnf file to the openssl-conf package. Make the libcrypto +# package RRECOMMENDS on this package. This will enable the configuration +# file to be installed for both the openssl-bin package and the libcrypto +# package since the openssl-bin package depends on the libcrypto package. + +PACKAGES =+ "libcrypto libssl openssl-conf ${PN}-engines ${PN}-misc" + +FILES_libcrypto = "${libdir}/libcrypto${SOLIBS}" +FILES_libssl = "${libdir}/libssl${SOLIBS}" +FILES_openssl-conf = "${sysconfdir}/ssl/openssl.cnf" +FILES_${PN}-engines = "${libdir}/engines-1.1" +FILES_${PN}-misc = "${libdir}/ssl-1.1/misc" +FILES_${PN} =+ "${libdir}/ssl-1.1/*" +FILES_${PN}_append_class-nativesdk = " ${SDKPATHNATIVE}/environment-setup.d/openssl.sh" + +CONFFILES_openssl-conf = "${sysconfdir}/ssl/openssl.cnf" + +RRECOMMENDS_libcrypto += "openssl-conf" +RDEPENDS_${PN}-ptest += "openssl-bin perl perl-modules bash" + +BBCLASSEXTEND = "native nativesdk" + +CVE_PRODUCT = "openssl:openssl" + +# Only affects OpenSSL >= 1.1.1 in combination with Apache < 2.4.37 +# Apache in meta-webserver is already recent enough +CVE_CHECK_WHITELIST += "CVE-2019-0190" diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service new file mode 100644 index 000000000..e8b563850 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service @@ -0,0 +1,10 @@ +[Unit] +Description=Check for AC boot +After=xyz.openbmc_project.Settings.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/ac-boot-check.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh new file mode 100644 index 000000000..b9ea1127c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +bitWiseAnd() { + local IFS='&' + printf "%s\n" "$(( $* ))" +} + +ACBOOT="False" + +while IFS=' ' read -ra OPTIONS; do + for i in "${OPTIONS[@]}"; do + while IFS='=' read option param; do + if [ "resetreason" == "$option" ]; then + if [ $(bitWiseAnd "$param" "0x1") -ne 0 ]; then + ACBOOT="True" + fi + fi + done <<< $i + done +done < /proc/cmdline + +busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/control/host0/ac_boot xyz.openbmc_project.Common.ACBoot ACBoot s "$ACBOOT" + diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb new file mode 100644 index 000000000..2a30696dc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb @@ -0,0 +1,24 @@ +SUMMARY = "AC Boot Check" +DESCRIPTION = "Script to check the resetreason for AC boot" + +S = "${WORKDIR}" +SRC_URI = "file://ac-boot-check.sh \ + file://ac-boot-check.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/ac-boot-check.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/ac-boot-check.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/ac-boot-check.sh ${D}/${bindir}/ac-boot-check.sh +} + +SYSTEMD_SERVICE_${PN} += " ac-boot-check.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb new file mode 100644 index 000000000..10df9dd59 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb @@ -0,0 +1,34 @@ +inherit obmc-phosphor-systemd + +SUMMARY = "At Scale Debug Service" +DESCRIPTION = "At Scale Debug Service exposes remote JTAG target debug capabilities" + +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://LICENSE;md5=0d1c657b2ba1e8877940a8d1614ec560" + + +inherit cmake +DEPENDS = "sdbusplus openssl libpam libgpiod safec" + +do_configure[depends] += "virtual/kernel:do_shared_workdir" + +SRC_URI = "git://github.com/Intel-BMC/asd;protocol=git" +SRC_URI += "file://0001-Fix-build-error-in-kernel-v5.10.patch" +SRCREV = "1.4.4" + +inherit useradd + +USERADD_PACKAGES = "${PN}" + +# add a special user asdbg +USERADD_PARAM_${PN} = "-u 999 asdbg" + +S = "${WORKDIR}/git" + +SYSTEMD_SERVICE_${PN} += "com.intel.AtScaleDebug.service" + +# Specify any options you want to pass to cmake using EXTRA_OECMAKE: +EXTRA_OECMAKE = "-DBUILD_UT=OFF" + +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/" diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/0001-Fix-build-error-in-kernel-v5.10.patch b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/0001-Fix-build-error-in-kernel-v5.10.patch new file mode 100644 index 000000000..7ebedeee3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/0001-Fix-build-error-in-kernel-v5.10.patch @@ -0,0 +1,62 @@ +From 7ed9ba9738d8f27578ea2d00019f8245ee2a5556 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 22 Feb 2021 15:32:13 -0800 +Subject: [PATCH] Fix build error in kernel v5.10 + +Kernel headers should be added as last headers to prevent unexpected +build breaks. + +Change-Id: Ie7d1a054baf2af88b9c46f928d0d84a64d8febd9 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + i2c_handler.c | 5 +++-- + i2c_msg_builder.c | 5 +++-- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/i2c_handler.c b/i2c_handler.c +index 21fb931..05470f4 100644 +--- a/i2c_handler.c ++++ b/i2c_handler.c +@@ -29,8 +29,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #include <errno.h> + #include <fcntl.h> +-#include <linux/i2c-dev.h> +-#include <linux/i2c.h> + #include <stdint.h> + #include <stdio.h> + #include <stdlib.h> +@@ -40,6 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #include "logging.h" + ++#include <linux/i2c-dev.h> ++#include <linux/i2c.h> ++ + #define FILE_NAME "/dev/i2c" + #define MAX_I2C_DEV_FILENAME 256 + +diff --git a/i2c_msg_builder.c b/i2c_msg_builder.c +index 6ae06a0..05dc340 100644 +--- a/i2c_msg_builder.c ++++ b/i2c_msg_builder.c +@@ -27,13 +27,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #include "i2c_msg_builder.h" + +-#include <linux/i2c-dev.h> +-#include <linux/i2c.h> + #include <stdint.h> + #include <stdlib.h> + + #include "logging.h" + ++#include <linux/i2c-dev.h> ++#include <linux/i2c.h> ++ + STATUS copy_i2c_to_asd(asd_i2c_msg* asd, struct i2c_msg* i2c); + STATUS copy_asd_to_i2c(const asd_i2c_msg* asd, struct i2c_msg* i2c); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service new file mode 100644 index 000000000..4411de11c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service @@ -0,0 +1,12 @@ +[Unit] +Description=Intel BMC At Scale Debug +Requires=network-online.target + +[Service] +Restart=always +RestartSec=30 +ExecStart={bindir}/asd +Type=simple +SyslogIdentifier=asd + + diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service new file mode 100644 index 000000000..281d1a993 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service @@ -0,0 +1,12 @@ +[Unit] +Description=Intel BMC At Scale Debug JTAG test to check if remote debug setting is enabled + +[Service] +Type=oneshot +ExecStartPre=/bin/sleep 10 +ExecStart={bindir}/jtag_test +SyslogIdentifier=jtag_test +RemainAfterExit=true + +[Install] +WantedBy=obmc-host-start@0.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab new file mode 100644 index 000000000..0b53093ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab @@ -0,0 +1,10 @@ +/dev/root / auto defaults 1 1 +proc /proc proc defaults 0 0 +devpts /dev/pts devpts mode=0620,gid=5 0 0 +tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 +tmpfs /var/lib/systemd/coredump tmpfs rw,nosuid,nodev,size=67108864 0 0 +tmpfs /media tmpfs rw 0 0 + +# uncomment this if your device has a SD/MMC/Transflash slot +#/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend new file mode 100644 index 000000000..79e529179 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend @@ -0,0 +1,2 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI_append = " file://fstab" diff --git a/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/dev-only.cfg b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/dev-only.cfg new file mode 100644 index 000000000..f8f49e001 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/dev-only.cfg @@ -0,0 +1,4 @@ +CONFIG_NC=y +CONFIG_NETSTAT=y +CONFIG_TFTP=y +CONFIG_WGET=y diff --git a/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/disable.cfg b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/disable.cfg new file mode 100644 index 000000000..2550ffaf5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/disable.cfg @@ -0,0 +1,6 @@ +CONFIG_NC=n +CONFIG_NETSTAT=n +CONFIG_TELNET=n +CONFIG_TFTP=n +CONFIG_WGET=n +CONFIG_UDHCPD=n diff --git a/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/enable.cfg b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/enable.cfg new file mode 100644 index 000000000..7e1b90da6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox/enable.cfg @@ -0,0 +1 @@ +CONFIG_TRUNCATE=y diff --git a/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox_%.bbappend new file mode 100644 index 000000000..c72975ccc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/busybox/busybox_%.bbappend @@ -0,0 +1,7 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " \ + file://disable.cfg \ + file://enable.cfg \ + " + +SRC_URI += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks','file://dev-only.cfg','',d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/clear-guid_from_server-if-send_negotiate_unix_f.patch b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/clear-guid_from_server-if-send_negotiate_unix_f.patch new file mode 100644 index 000000000..6bb6d9c82 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/clear-guid_from_server-if-send_negotiate_unix_f.patch @@ -0,0 +1,104 @@ +From b8f84bd39485d3977625c9a8b8e8cff5d23be56f Mon Sep 17 00:00:00 2001 +From: Roy Li <rongqing.li@windriver.com> +Date: Thu, 27 Feb 2014 09:05:02 +0800 +Subject: [PATCH] dbus: clear guid_from_server if send_negotiate_unix_fd + failed + +Upstream-Status: Submitted + +bus-test dispatch test failed with below information: + ./bus/bus-test: Running message dispatch test + Activating service name='org.freedesktop.DBus.TestSuiteEchoService' + Successfully activated service 'org.freedesktop.DBus.TestSuiteEchoService' + 6363: assertion failed "_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0" file "dbus-auth.c" line 1545 function process_ok + ./bus/bus-test(_dbus_print_backtrace+0x29) [0x80cb969] + ./bus/bus-test(_dbus_abort+0x14) [0x80cfb44] + ./bus/bus-test(_dbus_real_assert+0x53) [0x80b52c3] + ./bus/bus-test() [0x80e24da] + ./bus/bus-test(_dbus_auth_do_work+0x388) [0x80e3848] + ./bus/bus-test() [0x80aea49] + ./bus/bus-test() [0x80affde] + ./bus/bus-test(_dbus_transport_handle_watch+0xb1) [0x80ad841] + ./bus/bus-test(_dbus_connection_handle_watch+0x104) [0x8089174] + ./bus/bus-test(dbus_watch_handle+0xd8) [0x80b15e8] + ./bus/bus-test(_dbus_loop_iterate+0x4a9) [0x80d1509] + ./bus/bus-test(bus_test_run_clients_loop+0x5d) [0x808129d] + ./bus/bus-test() [0x806cab0] + ./bus/bus-test() [0x806e0ca] + ./bus/bus-test() [0x806da6f] + ./bus/bus-test(_dbus_test_oom_handling+0x18c) [0x80b5c8c] + ./bus/bus-test() [0x806f723] + ./bus/bus-test(bus_dispatch_test+0x3c) [0x8071aac] + ./bus/bus-test(main+0x1b7) [0x805acc7] + /lib/libc.so.6(__libc_start_main+0xf3) [0x45f919b3] + ./bus/bus-test() [0x805ae39] + +The stack is below: + #0 0xffffe425 in __kernel_vsyscall () + #1 0x45fa62d6 in raise () from /lib/libc.so.6 + #2 0x45fa9653 in abort () from /lib/libc.so.6 + #3 0x080cfb65 in _dbus_abort () at dbus-sysdeps.c:94 + #4 0x080b52c3 in _dbus_real_assert (condition=0, + condition_text=condition_text@entry=0x8117a38 "_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0", + file=file@entry=0x8117273 "dbus-auth.c", line=line@entry=1545, + func=func@entry=0x8117f8e <__FUNCTION__.3492> "process_ok") + data=0x8157290) at dbus-connection.c:1515 + #0 0x00000033fee353e9 in raise () from /lib64/libc.so.6 + #1 0x00000033fee38508 in abort () from /lib64/libc.so.6 + #2 0x000000000047d585 in _dbus_abort () at dbus-sysdeps.c:94 + #3 0x0000000000466486 in _dbus_real_assert (condition=<optimized out>, + condition_text=condition_text@entry=0x4c2988 "_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0", + file=file@entry=0x4c21a5 "dbus-auth.c", line=line@entry=1546, + func=func@entry=0x4c2fce <__FUNCTION__.3845> "process_ok") + at dbus-internals.c:931 + #4 0x000000000048d424 in process_ok (args_from_ok=0x7fffffffe480, + auth=0x6ff340) at dbus-auth.c:1546 + #5 handle_client_state_waiting_for_data (auth=0x6ff340, + command=<optimized out>, args=0x7fffffffe480) at dbus-auth.c:1996 + #6 0x000000000048e789 in process_command (auth=0x6ff340) at dbus-auth.c:2208 + #7 _dbus_auth_do_work (auth=0x6ff340) at dbus-auth.c:2458 + #8 0x000000000046091d in do_authentication ( + transport=transport@entry=0x6ffaa0, do_reading=do_reading@entry=1, + do_writing=do_writing@entry=0, + auth_completed=auth_completed@entry=0x7fffffffe55c) + at dbus-transport-socket.c:442 + #9 0x0000000000461d08 in socket_handle_watch (transport=0x6ffaa0, + watch=0x6f4190, flags=1) at dbus-transport-socket.c:921 + #10 0x000000000045fa3a in _dbus_transport_handle_watch (transport=0x6ffaa0, + +Once send_negotiate_unix_fd failed, this failure will happen, since +auth->guid_from_server has been set to some value before +send_negotiate_unix_fd. send_negotiate_unix_fd failure will lead to +this auth be handled by process_ok again, but this auth->guid_from_server +is not zero. + +So we should clear auth->guid_from_server if send_negotiate_unix_fd failed + +Signed-off-by: Roy Li <rongqing.li@windriver.com> +--- + dbus/dbus-auth.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c +index d2c37a7..37b45c6 100644 +--- a/dbus/dbus-auth.c ++++ b/dbus/dbus-auth.c +@@ -1571,8 +1571,13 @@ process_ok(DBusAuth *auth, + _dbus_verbose ("Got GUID '%s' from the server\n", + _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); + +- if (auth->unix_fd_possible) +- return send_negotiate_unix_fd(auth); ++ if (auth->unix_fd_possible) { ++ if (!send_negotiate_unix_fd(auth)) { ++ _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); ++ return FALSE; ++ } ++ return TRUE; ++ } + + _dbus_verbose("Not negotiating unix fd passing, since not possible\n"); + return send_begin (auth); +-- +1.7.10.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/dbus-1.init b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/dbus-1.init new file mode 100644 index 000000000..90e167e57 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/dbus-1.init @@ -0,0 +1,123 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: dbus +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +# Short-Description: D-Bus systemwide message bus +# Description: D-Bus is a simple interprocess messaging system, used +# for sending messages between applications. +### END INIT INFO +# +# -*- coding: utf-8 -*- +# Debian init.d script for D-BUS +# Copyright © 2003 Colin Walters <walters@debian.org> + +# set -e + +# Source function library. +. /etc/init.d/functions + +DAEMON=@bindir@/dbus-daemon +NAME=dbus +DAEMONUSER=messagebus # must match /usr/share/dbus-1/system.conf +PIDFILE=/var/run/dbus/pid # must match /usr/share/dbus-1/system.conf +UUIDDIR=/var/lib/dbus +DESC="system message bus" +EVENTDIR=/etc/dbus-1/event.d + +test -x $DAEMON || exit 0 + +# Source defaults file; edit that file to configure this script. +ENABLED=1 +PARAMS="" +if [ -e /etc/default/dbus ]; then + . /etc/default/dbus +fi + +test "$ENABLED" != "0" || exit 0 + +start_it_up() +{ + mkdir -p "`dirname $PIDFILE`" + if [ -e $PIDFILE ]; then + PIDDIR=/proc/$(cat $PIDFILE) + if [ -d ${PIDDIR} -a "$(readlink -f ${PIDDIR}/exe)" = "${DAEMON}" ]; then + echo "$DESC already started; not starting." + else + echo "Removing stale PID file $PIDFILE." + rm -f $PIDFILE + fi + fi + + if [ ! -d $UUIDDIR ]; then + mkdir -p $UUIDDIR + chown $DAEMONUSER $UUIDDIR + chgrp $DAEMONUSER $UUIDDIR + fi + + dbus-uuidgen --ensure + + echo -n "Starting $DESC: " + start-stop-daemon -o --start --quiet --pidfile $PIDFILE \ + --user $DAEMONUSER --exec $DAEMON -- --system $PARAMS + echo "$NAME." + if [ -d $EVENTDIR ]; then + run-parts --arg=start $EVENTDIR + fi +} + +shut_it_down() +{ + if [ -d $EVENTDIR ]; then + # TODO: --reverse when busybox supports it + run-parts --arg=stop $EVENTDIR + fi + echo -n "Stopping $DESC: " + start-stop-daemon -o --stop --quiet --pidfile $PIDFILE \ + --user $DAEMONUSER + # We no longer include these arguments so that start-stop-daemon + # can do its job even given that we may have been upgraded. + # We rely on the pidfile being sanely managed + # --exec $DAEMON -- --system $PARAMS + echo "$NAME." + rm -f $PIDFILE +} + +reload_it() +{ + echo -n "Reloading $DESC config: " + dbus-send --print-reply --system --type=method_call \ + --dest=org.freedesktop.DBus \ + / org.freedesktop.DBus.ReloadConfig > /dev/null + # hopefully this is enough time for dbus to reload it's config file. + echo "done." +} + +case "$1" in + start) + start_it_up + ;; + stop) + shut_it_down + ;; + status) + status $DAEMON + exit $? + ;; + reload|force-reload) + reload_it + ;; + restart) + shut_it_down + sleep 1 + start_it_up + ;; + *) + echo "Usage: /etc/init.d/$NAME {start|stop|status|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/tmpdir.patch b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/tmpdir.patch new file mode 100644 index 000000000..bf086e178 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus/tmpdir.patch @@ -0,0 +1,44 @@ +From 5105fedd7fa13dadd2d0d864fb77873b83b79a4b Mon Sep 17 00:00:00 2001 +From: Koen Kooi <koen@dominion.thruhere.net> +Date: Thu, 23 Jun 2011 13:52:09 +0200 +Subject: [PATCH] buildsys: hardcode socketdir to /tmp + +the TMPDIR env var isn't always pointing to the right target path + +Upstream-Status: Inappropriate [embedded] + +Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> + +Original comment: + + avoid to check tmp dir at build time. instead uses hard coded /tmp here + comment added by Kevin Tian <kevin.tian@intel.com> +--- + configure.ac | 11 +---------- + 1 files changed, 1 insertions(+), 10 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 408054b..6d26180 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1483,16 +1483,7 @@ AC_SUBST(TEST_LAUNCH_HELPER_BINARY) + AC_DEFINE_UNQUOTED(DBUS_TEST_LAUNCH_HELPER_BINARY, "$TEST_LAUNCH_HELPER_BINARY", + [Full path to the launch helper test program in the builddir]) + +-#### Find socket directories +-if ! test -z "$TMPDIR" ; then +- DEFAULT_SOCKET_DIR=$TMPDIR +-elif ! test -z "$TEMP" ; then +- DEFAULT_SOCKET_DIR=$TEMP +-elif ! test -z "$TMP" ; then +- DEFAULT_SOCKET_DIR=$TMP +-else +- DEFAULT_SOCKET_DIR=/tmp +-fi ++DEFAULT_SOCKET_DIR=/tmp + + DEFAULT_SOCKET_DIR=`echo $DEFAULT_SOCKET_DIR | sed 's/+/%2B/g'` + +-- +1.6.6.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus_%.bbappend new file mode 100644 index 000000000..288c80f06 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dbus/dbus_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PV = "1.12.18" + +SRC_URI = "https://dbus.freedesktop.org/releases/dbus/dbus-${PV}.tar.gz \ + file://tmpdir.patch \ + file://dbus-1.init \ + file://clear-guid_from_server-if-send_negotiate_unix_f.patch \ + " +SRC_URI[md5sum] = "4ca570c281be35d0b30ab83436712242" +SRC_URI[sha256sum] = "64cf4d70840230e5e9bc784d153880775ab3db19d656ead8a0cb9c0ab5a95306" diff --git a/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend new file mode 100644 index 000000000..cfa1d0711 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend @@ -0,0 +1,22 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://enable-ssh.sh" + +add_manual_ssh_enable() { + install -d ${D}/usr/share/misc + install -m 0755 ${D}/${systemd_unitdir}/system/dropbear@.service ${D}/usr/share/misc/dropbear@.service + install -m 0755 ${D}/${systemd_unitdir}/system/dropbear.socket ${D}/usr/share/misc/dropbear.socket + install -m 0755 ${WORKDIR}/enable-ssh.sh ${D}${bindir}/enable-ssh.sh + # Remove dropbear service and socket by default, if debug-tweaks is disabled + rm ${D}/${systemd_unitdir}/system/dropbear@.service + rm ${D}/${systemd_unitdir}/system/dropbear.socket +} + +do_install_append() { + # Add manual ssh enable script if debug-tweaks is disabled + ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'add_manual_ssh_enable', d)} +} + +FILES_${PN} += "/usr/share/misc" +SYSTEMD_SERVICE_${PN} += "dropbearkey.service" +SYSTEMD_SERVICE_${PN}_remove += " ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'dropbear.socket', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh b/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh new file mode 100755 index 000000000..e97995cc1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ -e /etc/systemd/system/dropbear@.service ] && \ + [ -e /etc/systemd/system/sockets.target.wants/dropbear.socket ] +then + echo "SSH is already enabled" +else + cp /usr/share/misc/dropbear@.service /etc/systemd/system/dropbear@.service + cp /usr/share/misc/dropbear.socket /etc/systemd/system/dropbear.socket + ln -s /etc/systemd/system/dropbear.socket /etc/systemd/system/sockets.target.wants/dropbear.socket + groupmems -g priv-admin -a root + systemctl daemon-reload + systemctl restart dropbear.socket + echo "Enabled SSH service for root user successful" +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh new file mode 100644 index 000000000..96ec876cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh @@ -0,0 +1,366 @@ +#!/bin/sh + +log() { + echo "$@" +} + +FWTYPE="" +FWVER="" +redfish_log_fw_evt() { + local evt=$1 + local sev="" + local msg="" + [ -z "$FWTYPE" ] && return + [ -z "$FWVER" ] && return + case "$evt" in + start) + evt=OpenBMC.0.1.FirmwareUpdateStarted + msg="${FWTYPE} firmware update to version ${FWVER} started." + sev=OK + ;; + success) + evt=OpenBMC.0.1.FirmwareUpdateCompleted + msg="${FWTYPE} firmware update to version ${FWVER} completed successfully." + sev=OK + ;; + abort) + evt=OpenBMC.0.1.FirmwareUpdateFailed + msg="${FWTYPE} firmware update to version ${FWVER} failed." + sev=Warning + ;; + *) return ;; + esac + logger-systemd --journald <<-EOF + MESSAGE=$msg + PRIORITY=2 + SEVERITY=${sev} + REDFISH_MESSAGE_ID=${evt} + REDFISH_MESSAGE_ARGS=${FWTYPE},${FWVER} + EOF +} + +wait_for_log_sync() +{ + sync + sleep 5 +} + +PFR_BUS=4 +PFR_ADDR=0x38 +PFR_ID_REG=0x00 +PFR_STATE_REG=0x03 +PFR_PROV_REG=0x0a +PFR_INTENT_REG=0x13 +pfr_read() { + [ $# -ne 1 ] && return 1 + local reg=$1 + i2cget -y $PFR_BUS $PFR_ADDR $reg 2>/dev/null +} + +pfr_write() { + [ $# -ne 2 ] && return 1 + local reg=$1 + local val=$2 + i2cset -y $PFR_BUS $PFR_ADDR $reg $val >&/dev/null +} + +pfr_active_update() { + local factory_reset="" + local recovery_offset=0x2a00000 + systemctl stop nv-sync.service || \ + log "BMC NV sync failed to stop" + # transition from non-PFR to PFR image requires factory reset + if [ ! -e /usr/share/pfr ]; then + factory_reset="-r" + mtd-util pfr stage $LOCAL_PATH $recovery_offset + fi + mtd-util $factory_reset pfr write $LOCAL_PATH + redfish_log_fw_evt success + # only wait for logging if not transitioning from non-PFR to PFR + if [ -e /usr/share/pfr ]; then + # exit bmc no nv mode + systemctl start nv-sync.service || log "failed to start nv-sync" + wait_for_log_sync + fi + reboot -f +} + +pfr_staging_update() { + log "Updating $(basename $TGT)" + flash_erase $TGT $erase_offset $blk_cnt + log "Writing $(stat -c "%s" "$LOCAL_PATH") bytes" + # cat "$LOCAL_PATH" > "$TGT" + dd bs=4k seek=$(($erase_offset / 0x1000)) if=$LOCAL_PATH of=$TGT 2>/dev/null + + # remove the updated image from /tmp + rm -f $LOCAL_PATH + redfish_log_fw_evt success + log "Setting update intent in PFR CPLD" + wait_for_log_sync + + # write to PFRCPLD about BMC update intent. + pfr_write 0x13 $upd_intent_val +} + +pfr_active_mode() { + # check for 0xde in register file 0 + local id=$(pfr_read $PFR_ID_REG) || return 1 + [ "$id" == "0xde" ] || return 1 + local state=$(pfr_read $PFR_STATE_REG) || return 1 + local prov=$(pfr_read $PFR_PROV_REG) || return 1 + prov=$((prov & 0x20)) + [ "$prov" == "32" ] && return 0 + return 1 +} + +blk0blk1_update() { + # PFR-style image update section + # read the image type from the uploaded image + # Byte at location 0x8 gives image type + TGT="/dev/mtd/image-stg" + img_type=$(hexdump -s 8 -n 1 -e '/1 "%02x\n"' $LOCAL_PATH) + log "image-type=$img_type" + + if [ $local_file -eq 0 ]; then + img_type_str=$(busctl get-property xyz.openbmc_project.Software.BMC.Updater /xyz/openbmc_project/software/$img_obj xyz.openbmc_project.Software.Version Purpose | cut -d " " -f 2 | cut -d "." -f 6 | sed 's/.\{1\}$//') + img_target=$(busctl get-property xyz.openbmc_project.Software.BMC.Updater /xyz/openbmc_project/software/$img_obj xyz.openbmc_project.Software.Activation RequestedActivation | cut -d " " -f 2| cut -d "." -f 6 | sed 's/.\{1\}$//') + else + img_type_str='BMC' + img_target='Active' + fi + + apply_time=$(busctl get-property xyz.openbmc_project.Settings /xyz/openbmc_project/software/apply_time xyz.openbmc_project.Software.ApplyTime RequestedApplyTime | cut -d " " -f 2 | cut -d "." -f 6 | sed 's/.\{1\}$//') + log "image-name=$img_type_str" + log "image-target=$img_target" + log "apply_time=$apply_time" + + case "$img_type" in + 04) + if [ "$img_type_str" == 'BMC' ]; then + # BMC image - max size 32MB + log "BMC firmware image" + img_size=33554432 + if [ "$img_target" == 'StandbySpare' ]; then + upd_intent_val=0x10 + else + upd_intent_val=0x08 + fi + erase_offset=0 + FWTYPE="BMC" + FWVER="${RANDOM}-fixme" + else + # log error the image selected for update is not same as downloaded. + log "Mismatch: image selected for update and image parsed are different" + redfish_log_fw_evt abort + return 1 + fi + ;; + 00) + if [ "$img_type_str" == 'Other' ]; then + log "CPLD firmware image" + # CPLD image- max size 1MB + img_size=1048576 + if [ "$img_target" == 'StandbySpare' ]; then + upd_intent_val=0x20 + else + upd_intent_val=0x04 + fi + erase_offset=0x3000000 + FWTYPE="CPLD" + FWVER="${RANDOM}-fixme" + else + # log error the image selected for update is not same as downloaded. + log "Mismatch: image selected for update and image parsed are different" + redfish_log_fw_evt abort + return 1 + fi + ;; + 02) + if [ "$img_type_str" = 'Host' ]; then + # BIOS image- max size 16MB + log "BIOS firmware image" + img_size=16777216 + if [ "$img_target" == 'StandbySpare' ]; then + upd_intent_val=0x02 + else + upd_intent_val=0x41 + fi + erase_offset=0x2000000 + # TODO: parse out the fwtype and fwver once that is specified + FWTYPE="BIOS" + FWVER="${RANDOM}-fixme" + else + # log error the image selected for update is not same as downloaded. + log "Mismatch: image selected for update and image parsed are different" + redfish_log_fw_evt abort + return 1 + fi + ;; + *) + log "Unknown image type ${img_type}" + return 1 + ;; + esac + + # For deferred updates + if [ "$apply_time" == 'OnReset' ]; then + upd_intent_val=$(( "$upd_intent_val"|0x80 )) + fi + + # do a quick sanity check on the image + if [ $(stat -c "%s" "$LOCAL_PATH") -gt $img_size ]; then + log "Update file "$LOCAL_PATH" is bigger than the supported image size" + redfish_log_fw_evt abort + return 1 + fi + blk_cnt=$((img_size / 0x10000)) + + if pfr_active_mode; then + # pfr enforcing mode; any b0b1 image type + pfr_staging_update + elif [ "$img_type" == '04' ]; then + # legacy mode; pfr is not present but we got a pfr image + log "Updating BMC active firmware- PFR unprovisioned mode" + pfr_active_update + else + # error; pfr is not present but we got a pfr image, + # an invalid image, or nonBMC image + log "PFR inactive or invalid image type:${img_type}, cowardly refusing to process image" + redfish_log_fw_evt abort + return 1 + fi +} + +ping_pong_update() { + # if some one tries to update with non-PFR on PFR image + # just exit + if [ -e /usr/share/pfr ]; then + log "Update exited as non-PFR image is tried onto PFR image" + redfish_log_fw_evt abort + return 1 + fi + # do a quick sanity check on the image + if [ $(stat -c "%s" "$LOCAL_PATH") -lt 10000000 ]; then + log "Update file "$LOCAL_PATH" seems to be too small" + redfish_log_fw_evt abort + return 1 + fi + dtc -I dtb -O dtb "$LOCAL_PATH" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "Update file $LOCAL_PATH doesn't seem to be in the proper format" + redfish_log_fw_evt abort + return 1 + fi + + # guess based on fw_env which partition we booted from + local BOOTADDR=$(fw_printenv bootcmd | awk '{print $2}') + local TGT="/dev/mtd/image-a" + case "$BOOTADDR" in + 20080000) TGT="/dev/mtd/image-b"; BOOTADDR="22480000" ;; + 22480000) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;; + *) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;; + esac + log "Updating $(basename $TGT) (use bootm $BOOTADDR)" + flash_erase $TGT 0 0 + log "Writing $(stat -c "%s" "$LOCAL_PATH") bytes" + cat "$LOCAL_PATH" > "$TGT" + fw_setenv "bootcmd" "bootm ${BOOTADDR}" + redfish_log_fw_evt success + wait_for_log_sync + # reboot + reboot -f +} + +fetch_fw() { + PROTO=$(echo "$URI" | sed 's,\([a-z]*\)://.*$,\1,') + REMOTE=$(echo "$URI" | sed 's,.*://\(.*\)$,\1,') + REMOTE_HOST=$(echo "$REMOTE" | sed 's,\([^/]*\)/.*$,\1,') + if [ "$PROTO" = 'scp' ]; then + REMOTE_PATH=$(echo "$REMOTE" | cut -d':' -f2) + else + REMOTE_PATH=$(echo "$REMOTE" | sed 's,[^/]*/\(.*\)$,\1,') + fi + LOCAL_PATH="/tmp/$(basename $REMOTE_PATH)" + log "PROTO=$PROTO" + log "REMOTE=$REMOTE" + log "REMOTE_HOST=$REMOTE_HOST" + log "REMOTE_PATH=$REMOTE_PATH" + if [ ! -e $LOCAL_PATH ] || [ $(stat -c %s $LOCAL_PATH) -eq 0 ]; then + log "Download '$REMOTE_PATH' from $PROTO $REMOTE_HOST $REMOTE_PATH" + case "$PROTO" in + scp) + mkdir -p $HOME/.ssh + if [ -e "$SSH_ID" ]; then + ARG_ID="-i $SSH_ID" + fi + scp $ARG_ID $REMOTE_HOST$REMOTE_PATH $LOCAL_PATH + if [ $? -ne 0 ]; then + log "scp $REMOTE $LOCAL_PATH failed!" + return 1 + fi + ;; + tftp) + cd /tmp + tftp -g -r "$REMOTE_PATH" "$REMOTE_HOST" + if [ $? -ne 0 ]; then + log "tftp -g -r \"$REMOTE_PATH\" \"$REMOTE_HOST\" failed!" + return 1 + fi + ;; + http|https|ftp) + wget --no-check-certificate "$URI" -O "$LOCAL_PATH" + if [ $? -ne 0 ]; then + log "wget $URI failed!" + return 1 + fi + ;; + file) + LOCAL_PATH=$(echo $URI | sed 's,^file://,,') + ;; + *) + log "Invalid URI $URI" + return 1 + ;; + esac + fi +} + +update_fw() { + redfish_log_fw_evt start + # determine firmware file type + local magic=$(hexdump -n 4 -v -e '/1 "%02x"' "$LOCAL_PATH") + case "$magic" in + d00dfeed) ping_pong_update ;; + 19fdeab6) blk0blk1_update ;; + *) log "Uknown file type ${magic}" + esac +} + +# if this script was sourced, just return without executing anything +[ "$_" != "$0" ] && return 0 >&/dev/null + +usage() { + echo "usage: $(basename $0) uri" + echo " uri is something like: file:///path/to/fw" + echo " tftp://tftp.server.ip.addr/path/to/fw" + echo " scp://[user@]scp.server.ip.addr:/path/to/fw" + echo " http[s]://web.server.ip.addr/path/to/fw" + echo " ftp://[user@]ftp.server.ip.addr/path/to/fw" + exit 1 +} + +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage; fi +if [ $# -eq 0 ]; then + # set DEFURI in $HOME/.fwupd.defaults + URI="$DEFURI" +else + if [[ "$1" == *"/"* ]]; then + URI=$1 # local file + local_file=1 ; + else + URI="file:////tmp/images/$1/image-runtime" + img_obj=$1 + local_file=0 ; + fi +fi +fetch_fw && update_fw diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl new file mode 100644 index 000000000..ae9f54263 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl @@ -0,0 +1,136 @@ +#!/bin/sh + +setup_image() +{ + set -x + local storage="$1" + local sz_mb="$2" + # create the backing store + dd if=/dev/zero of=$storage bs=1M seek=$sz_mb count=0 2>/dev/null + # this shows up as 23FC-F676 in /dev/disk/by-uuid + local diskid=0x23FCF676 + mkdosfs -n 'OPENBMC-FW' -i $diskid -I $storage >/dev/null 2>&1 +} + +mount_image() +{ + set -x + local storage="$1" + local stormnt="$2" + mkdir -p $stormnt || exit 1 + mount -o loop -t vfat $storage $stormnt +} + +cleanup_image() +{ + set -x + local storage="$1" + local stormnt="$2" + umount -f "$stormnt" + rm -f "$storage" + rmdir "$stormnt" +} + +GADGET_BASE=/sys/kernel/config/usb_gadget + +which_dev() +{ + local in_use=$(cat $GADGET_BASE/*/UDC) + cd /sys/class/udc + for D in *; do + case "$in_use" in + *"$D"*) ;; + *) echo "$D"; return 0;; + esac + done + return 1 +} + +usb_ms_insert() +{ + local name="$1" + local storage="$2" + + if [ -d $GADGET_BASE/$name ]; then + echo "device $name already exists" >&2 + return 1 + fi + mkdir $GADGET_BASE/$name + cd $GADGET_BASE/$name + + echo 0x1d6b > idVendor # Linux Foundation + echo 0x0105 > idProduct # FunctionFS Gadget + mkdir strings/0x409 + local machineid=$(cat /etc/machine-id) + local data="OpenBMC USB mass storage gadget device serial number" + local serial=$( echo -n "${machineid}${data}${machineid}" | \ + sha256sum | cut -b 0-12 ) + echo $serial > strings/0x409/serialnumber + echo OpenBMC > strings/0x409/manufacturer + echo "OpenBMC Mass Storage" > strings/0x409/product + + mkdir configs/c.1 + mkdir functions/mass_storage.$name + echo $storage > functions/mass_storage.$name/lun.0/file + echo 0 > functions/mass_storage.$name/lun.0/removable + mkdir configs/c.1/strings/0x409 + + echo "Conf 1" > configs/c.1/strings/0x409/configuration + echo 120 > configs/c.1/MaxPower + ln -s functions/mass_storage.$name configs/c.1 + local dev=$(which_dev) + echo $dev > UDC +} + +usb_ms_eject() +{ + local name="$1" + + echo '' > $GADGET_BASE/$name/UDC + + rm -f $GADGET_BASE/$name/configs/c.1/mass_storage.$name + rmdir $GADGET_BASE/$name/configs/c.1/strings/0x409 + rmdir $GADGET_BASE/$name/configs/c.1 + rmdir $GADGET_BASE/$name/functions/mass_storage.$name + rmdir $GADGET_BASE/$name/strings/0x409 + rmdir $GADGET_BASE/$name +} + +usage() +{ + echo "Usage: $0 <action> ..." + echo " $0 setup <file> <sizeMB>" + echo " $0 insert <name> <file>" + echo " $0 eject <name>" + echo " $0 mount <file> <mnt>" + echo " $0 cleanup <file> <mnt>" + exit 1 +} + +echo "$#: $0 $@" +case "$1" in + insert) + shift + usb_ms_insert "$@" + ;; + eject) + shift + usb_ms_eject "$@" + ;; + setup) + shift + setup_image "$@" + ;; + mount) + shift + mount_image "$@" + ;; + cleanup) + shift + cleanup_image "$@" + ;; + *) + usage + ;; +esac +exit $? diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb new file mode 100644 index 000000000..118d6aab8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb @@ -0,0 +1,32 @@ +SUMMARY = "Temporary intel-fw-update script" +DESCRIPTION = "At runtime, perform a firmware update and reboot" +PR = "r1" + +# flash_eraseall +RDEPENDS_intel-fw-update += "mtd-utils" +# wget tftp scp +RDEPENDS_intel-fw-update += "busybox dropbear" +# mkfs.vfat, parted +RDEPENDS_intel-fw-update += "dosfstools dtc" + +RDEPENDS_intel-fw-update += "bash" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +PFR_EN = "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'pfr', '', d)}" + +SRC_URI += "file://fwupd.sh" +SRC_URI += "file://usb-ctrl" + +FILES_${PN} += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '${datadir}/pfr', '', d)}" + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/fwupd.sh ${D}${bindir} + install -m 0755 ${WORKDIR}/usb-ctrl ${D}${bindir} + + if [ "${PFR_EN}" = "pfr" ]; then + install -d ${D}${datadir} + touch ${D}${datadir}/pfr + fi +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/glibc/glibc/0035-Fix-build-error.patch b/meta-openbmc-mods/meta-common/recipes-core/glibc/glibc/0035-Fix-build-error.patch new file mode 100644 index 000000000..6cf56c64f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/glibc/glibc/0035-Fix-build-error.patch @@ -0,0 +1,26 @@ +From 2a246ee8129e7cd4660fe76f7ab656191be7bc5e Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 11 Mar 2021 11:23:00 -0800 +Subject: [PATCH] Fix build error + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + stdlib/canonicalize.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c +index 698f9ede2557..cac1f73d7471 100644 +--- a/stdlib/canonicalize.c ++++ b/stdlib/canonicalize.c +@@ -198,7 +198,7 @@ static char * + realpath_stk (const char *name, char *resolved, + struct scratch_buffer *rname_buf) + { +- char *dest; ++ char *dest = NULL; + char const *start; + char const *end; + int num_links = 0; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/glibc/glibc_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/glibc/glibc_%.bbappend new file mode 100644 index 000000000..327c1ce64 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/glibc/glibc_%.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " \ + file://0035-Fix-build-error.patch \ + " 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 new file mode 100644 index 000000000..eec234e96 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend @@ -0,0 +1,4 @@ +SRC_URI = "git://github.com/openbmc/host-error-monitor" +SRCREV = "4a6e45c4c2f38bc64afe5faac05ea82b3adb8d93" + +EXTRA_OECMAKE = "-DYOCTO=1" diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format new file mode 100644 index 000000000..86a2a9d63 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format @@ -0,0 +1,21 @@ +--- +BasedOnStyle: LLVM +Language: Cpp +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Linux +AlwaysBreakBeforeMultilineStrings: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +IndentCaseLabels: false +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AlignAfterOpenBracket: true +SpaceAfterCStyleCast: false +MaxEmptyLinesToKeep: 2 +BreakBeforeBinaryOperators: NonAssignment +BreakStringLiterals: false +SortIncludes: true +ContinuationIndentWidth: 8 diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch new file mode 100644 index 000000000..d537b5db7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch @@ -0,0 +1,121 @@ +From 8e3ae96546010c5d4f3fce6df9c32aece1093458 Mon Sep 17 00:00:00 2001 +From: Nikhil Potade <nikhil.potade@linux.intel.com> +Date: Tue, 19 Feb 2019 14:16:20 +0800 +Subject: [PATCH 1/1] Smbus changes for libmctp + +Signed-off-by: James Feist <james.feist@linux.intel.com> + +--- + core.c | 2 ++ + libmctp.h | 40 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +diff --git a/core.c b/core.c +index 6e59993..3b11672 100644 +--- a/core.c ++++ b/core.c +@@ -19,6 +19,7 @@ + + /* Internal data structures */ + ++/* clang-format off */ + struct mctp_bus { + mctp_eid_t eid; + struct mctp_binding *binding; +@@ -58,6 +59,7 @@ struct mctp { + ROUTE_BRIDGE, + } route_policy; + }; ++/* clang-format on */ + + #ifndef BUILD_ASSERT + #define BUILD_ASSERT(x) \ +diff --git a/libmctp.h b/libmctp.h +index 40e5371..766473b 100644 +--- a/libmctp.h ++++ b/libmctp.h +@@ -19,6 +19,7 @@ typedef uint8_t mctp_eid_t; + #define MCTP_EID_BROADCAST 0xff + + /* MCTP packet definitions */ ++/* clang-format off */ + struct mctp_hdr { + uint8_t ver; + uint8_t dest; +@@ -34,20 +35,57 @@ struct mctp_hdr { + #define MCTP_HDR_SEQ_MASK (0x3) + #define MCTP_HDR_TAG_SHIFT (0) + #define MCTP_HDR_TAG_MASK (0x7) ++/* clang-format on */ + + /* Baseline Transmission Unit and packet size */ + #define MCTP_BTU 64 + #define MCTP_PACKET_SIZE(unit) ((unit) + sizeof(struct mctp_hdr)) + #define MCTP_BODY_SIZE(unit) ((unit) - sizeof(struct mctp_hdr)) + ++#define MCTP_CONTROL_MESSAGE_TYPE 0x00 ++ ++enum MCTP_COMMAND_CODE { ++ MCTP_COMMAND_CODE_SET_EID = 0x01, ++ MCTP_COMMAND_CODE_GET_EID = 0x02, ++ MCTP_COMMAND_CODE_GET_ENDPOINT_UUID = 0x03, ++ MCTP_COMMAND_CODE_GET_MCTP_VERSION_SUPPORT = 0x04, ++ MCTP_COMMAND_CODE_GET_MESSAGE_TYPE_SUPPORT = 0x05, ++ MCTP_COMMAND_CODE_GET_VENDOR_DEFINED_MSG_SUPPORT= 0x06, ++ MCTP_COMMAND_CODE_RESOLVE_ENDPOINT_ID = 0x07, ++ MCTP_COMMAND_CODE_ALLOCATE_ENDPOINT_IDS = 0x08, ++ MCTP_COMMAND_CODE_ROUTING_INFORMATION_UPDATE = 0x09, ++ MCTP_COMMAND_CODE_GET_ROUTING_TABLE_ENTRIES = 0x0A, ++ MCTP_COMMAND_CODE_PREPARE_FOR_ENDPOINT_DISCOVERY= 0x0B, ++ MCTP_COMMAND_CODE_ENDPOINT_DISCOVERY = 0x0C, ++ MCTP_COMMAND_CODE_DISCOVERY_NOTIFY = 0x0D, ++ MCTP_COMMAND_CODE_GET_NETWORK_ID = 0x0E, ++ MCTP_COMMAND_CODE_QUERY_HOP = 0x0F, ++ MCTP_COMMAND_CODE_RESOLVE_UUID = 0x10, ++ MCTP_COMMAND_CODE_QUERY_RATE_LIMIT = 0x11, ++ MCTP_COMMAND_CODE_REQUEST_TX_RATE_LIMIT = 0x12, ++ MCTP_COMMAND_CODE_UPDATE_RATE_LIMIT = 0x13, ++ MCTP_COMMAND_CODE_QUERY_SUPPORTED_INTERFACES = 0x14 ++}; ++ ++enum MCTP_CONTROL_MSG_COMPLETION_CODE { ++ MCTP_CONTROL_MSG_STATUS_SUCCESS = 0x00, ++ MCTP_CONTROL_MSG_STATUS_ERROR = 0x01, ++ MCTP_CONTROL_MSG_STATUS_ERROR_INVALID_DATA = 0x02, ++ MCTP_CONTROL_MSG_STATUS_ERROR_INVALID_LENGTH = 0x03, ++ MCTP_CONTROL_MSG_STATUS_ERROR_NOT_READY = 0x04, ++ MCTP_CONTROL_MSG_STATUS_ERROR_UNSUPPORTED_CMD = 0x05 ++}; ++ + /* packet buffers */ + ++/* clang-format off */ + struct mctp_pktbuf { + size_t start, end, size; + size_t mctp_hdr_off; + struct mctp_pktbuf *next; + unsigned char data[]; + }; ++/* clang-format on */ + + struct mctp_binding; + +@@ -96,6 +134,7 @@ int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, + void *msg, size_t msg_len); + + /* hardware bindings */ ++/* clang-format off */ + struct mctp_binding { + const char *name; + uint8_t version; +@@ -108,6 +147,7 @@ struct mctp_binding { + mctp_rx_fn control_rx; + void *control_rx_data; + }; ++/* clang-format on */ + + void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0002-Fix-Memory-Leak.patch b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0002-Fix-Memory-Leak.patch new file mode 100644 index 000000000..52acac1ab --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0002-Fix-Memory-Leak.patch @@ -0,0 +1,36 @@ +From bda505bc62f95ee927b75f87c52e04584dab4d79 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Fri, 26 Jun 2020 13:50:08 -0700 +Subject: [PATCH 1/1] Fix Memory Leak + +In mctp_send_tx_queue if rc is of an error, +the packet does not get freed, causing a leak. + +Change-Id: Ic39b0920b454608841e6e879cc028e455520e67d +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/core.c b/core.c +index 6e59993..c251b72 100644 +--- a/core.c ++++ b/core.c +@@ -543,11 +543,11 @@ static void mctp_send_tx_queue(struct mctp_bus *bus) + int rc; + + rc = mctp_packet_tx(bus, pkt); +- if (rc) +- break; +- + bus->tx_queue_head = pkt->next; + mctp_pktbuf_free(pkt); ++ ++ if (rc) ++ break; + } + + if (!bus->tx_queue_head) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt new file mode 100644 index 000000000..28354123e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +add_definitions(-DMCTP_LOG_STDERR) +add_definitions(-DMCTP_HAVE_FILEIO) +add_definitions(-DMCTP_HAVE_STDIO) +add_definitions(-DMCTP_DEFAULT_ALLOC) + +add_library( + libmctp STATIC alloc.c core.c log.c libmctp.h serial.c smbus.c crc32c.c) + +target_include_directories(libmctp + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + $<INSTALL_INTERFACE:include/libmctp) + +enable_testing() + +add_executable(test_eid tests/test_eid.c tests/test-utils.c) +target_link_libraries(test_eid libmctp) + +add_executable(test_seq tests/test_seq.c tests/test-utils.c) +target_link_libraries(test_seq libmctp) + +install(TARGETS libmctp DESTINATION lib) +install( + FILES libmctp.h libmctp-smbus.h libmctp-serial.h crc32c.h DESTINATION include) + diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c new file mode 100644 index 000000000..0d5090e2c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c @@ -0,0 +1,93 @@ +#include "crc32c.h" +/*****************************************************************/ +/* */ +/* CRC LOOKUP TABLE */ +/* ================ */ +/* The following CRC lookup table was generated automagically */ +/* by the Rocksoft^tm Model CRC Algorithm Table Generation */ +/* Program V1.0 using the following model parameters: */ +/* */ +/* Width : 4 bytes. */ +/* Poly : 0x1EDC6F41L */ +/* Reverse : TRUE. */ +/* */ +/* For more information on the Rocksoft^tm Model CRC Algorithm, */ +/* see the document titled "A Painless Guide to CRC Error */ +/* Detection Algorithms" by Ross Williams */ +/* (ross@guest.adelaide.edu.au.). This document is likely to be */ +/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/*****************************************************************/ + +unsigned long crctable[256] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, + 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, + 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, + 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, + 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, + 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, + 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, + 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, + 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, + 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, + 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, + 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, + 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, + 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, + 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, + 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, + 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, + 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, + 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, + 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, + 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, + 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, + 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, + 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, + 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, + 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, + 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, + 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, + 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, + 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, + 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, + 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, + 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, + 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, + 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, + 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, + 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, + 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, + 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, + 0xAD7D5351L}; + +/*****************************************************************/ +/* End of CRC Lookup Table */ +/*****************************************************************/ + +uint32_t crc32c(uint8_t *data, int length) +{ + const uint32_t CRC_INIT = 0xffffffffL; + const uint32_t XO_ROT = 0xffffffffL; + + uint32_t crc = CRC_INIT; + + while (length--) { + crc = crctable[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); + } + crc = crc ^ XO_ROT; + + return crc; +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h new file mode 100644 index 000000000..4586547e6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h @@ -0,0 +1,16 @@ +#ifndef CRC32C_H +#define CRC32C_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdlib.h> + +uint32_t crc32c(uint8_t *buf, int len); + +#ifdef __cplusplus +} +#endif +#endif /* CRC32C_H */ diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h new file mode 100644 index 000000000..67690bcb3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef _LIBMCTP_SMBUS_H +#define _LIBMCTP_SMBUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libmctp.h" + +struct mctp_binding_smbus; + +struct mctp_binding_smbus *mctp_smbus_init(void); +int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus); +int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus); +void mctp_smbus_register_bus(struct mctp_binding_smbus *smbus, + struct mctp *mctp, mctp_eid_t eid); +int mctp_smbus_read(struct mctp_binding_smbus *smbus); +int mctp_smbus_open_bus(struct mctp_binding_smbus *smbus, int out_bus_num, + int root_bus_num); +void mctp_smbus_free(struct mctp_binding_smbus *smbus); +int mctp_smbus_open_in_bus(struct mctp_binding_smbus *smbus, int in_bus); +int mctp_smbus_open_out_bus(struct mctp_binding_smbus *smbus, int out_bus); +int mctp_smbus_set_in_fd(struct mctp_binding_smbus *smbus, int fd); +int mctp_smbus_set_out_fd(struct mctp_binding_smbus *smbus, int fd); + +#ifdef __cplusplus +} +#endif +#endif /* _LIBMCTP_SMBUS_H */ diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c new file mode 100644 index 000000000..2f099a7e5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c @@ -0,0 +1,467 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef MCTP_HAVE_FILEIO +#include <fcntl.h> +#endif + +#define pr_fmt(x) "smbus: " x + +#include <i2c/smbus.h> +#include <linux/i2c-dev.h> +#include <linux/i2c.h> +#include <sys/ioctl.h> + +#include "libmctp-alloc.h" +#include "libmctp-log.h" +#include "libmctp-smbus.h" +#include "libmctp.h" + +struct mctp_binding_smbus { + struct mctp_binding binding; + int out_fd; + int in_fd; + + unsigned long bus_id; + + /* receive buffer */ + uint8_t rxbuf[1024]; + struct mctp_pktbuf *rx_pkt; + + /* temporary transmit buffer */ + uint8_t txbuf[256]; +}; + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char *)(ptr) - (char *)&((type *)0)->member) +#endif + +#define binding_to_smbus(b) container_of(b, struct mctp_binding_smbus, binding) + +#define MCTP_COMMAND_CODE 0x0F +#define MCTP_SLAVE_ADDRESS 0x1d +#define MCTP_SOURCE_SLAVE_ADDRESS 0x21 + +#define SMBUS_PEC_BYTE_SIZE 1 +#define SMBUS_COMMAND_CODE_SIZE 1 +#define SMBUS_LENGTH_FIELD_SIZE 1 +#define SMBUS_ADDR_OFFSET_SLAVE 0x1000 + +struct mctp_smbus_header_tx { + uint8_t source_slave_address; +}; + +struct mctp_smbus_header_rx { + uint8_t destination_slave_address; + uint8_t command_code; + uint8_t byte_count; + uint8_t source_slave_address; +}; + +#define POLYCHECK (0x1070U << 3) +static uint8_t crc8_calculate(uint16_t d) +{ + int i; + + for (i = 0; i < 8; i++) { + if (d & 0x8000) { + d = d ^ POLYCHECK; + } + d = d << 1; + } + + return (uint8_t)(d >> 8); +} + +/* Incremental CRC8 over count bytes in the array pointed to by p */ +static uint8_t pec_calculate(uint8_t crc, uint8_t *p, size_t count) +{ + int i; + + for (i = 0; i < count; i++) { + crc = crc8_calculate((crc ^ p[i]) << 8); + } + + return crc; +} + +static uint8_t calculate_pec_byte(uint8_t *buf, size_t len, uint8_t address, + uint16_t flags) +{ + uint8_t addr = (address << 1) | (flags & I2C_M_RD ? 1 : 0); + uint8_t pec = pec_calculate(0, &addr, 1); + pec = pec_calculate(pec, buf, len); + + return pec; +} + +static int mctp_smbus_tx(struct mctp_binding_smbus *smbus, uint8_t len) +{ + +#ifdef I2C_M_HOLD + /* Hold message */ + static uint16_t holdtimeout = 1000; // timeout in ms. + struct i2c_msg msg[2] = +#else // !I2C_M_HOLD + struct i2c_msg msg[1] = +#endif // I2C_M_HOLD + {{.addr = MCTP_SLAVE_ADDRESS, + .flags = 0, + .len = len, + .buf = (__uint8_t *)smbus->txbuf} +#ifdef I2C_M_HOLD + , + {.addr = 0, + .flags = I2C_M_HOLD, + .len = sizeof(holdtimeout), + .buf = (__uint8_t *)&holdtimeout} +#endif // I2C_M_HOLD + }; + +#ifdef I2C_M_HOLD + struct i2c_rdwr_ioctl_data msgrdwr = {&msg, 2}; +#else // !I2C_M_HOLD + struct i2c_rdwr_ioctl_data msgrdwr = {&msg, 1}; +#endif // I2C_M_HOLD + + return ioctl(smbus->out_fd, I2C_RDWR, &msgrdwr); +} + +#ifdef I2C_M_HOLD +static int mctp_smbus_unhold_bus(struct mctp_binding_smbus *smbus) +{ + /* Unhold message */ + static uint16_t holdtimeout = 0; // unhold + struct i2c_msg holdmsg = {0, I2C_M_HOLD, sizeof(holdtimeout), + (__uint8_t *)&holdtimeout}; + + struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg, 1}; + + return ioctl(smbus->out_fd, I2C_RDWR, &msgrdwr); +} +#endif // I2C_M_HOLD + +static int mctp_binding_smbus_tx(struct mctp_binding *b, + struct mctp_pktbuf *pkt) +{ + struct mctp_binding_smbus *smbus = binding_to_smbus(b); + struct mctp_smbus_header_tx *hdr; + size_t pkt_length; + + uint8_t i2c_message_buf[256]; + uint8_t *buf_ptr; + uint8_t i2c_message_len; + + uint16_t timeout = 1000; + + /* the length field in the header excludes smbus framing + * and escape sequences */ + pkt_length = mctp_pktbuf_size(pkt); + + buf_ptr = (void *)smbus->txbuf; + *buf_ptr = MCTP_COMMAND_CODE; + buf_ptr++; + *buf_ptr = pkt_length + sizeof(*hdr); + buf_ptr++; + + hdr = (void *)buf_ptr; + hdr->source_slave_address = MCTP_SOURCE_SLAVE_ADDRESS; + buf_ptr = (buf_ptr + sizeof(*hdr)); + memcpy(buf_ptr, &pkt->data[pkt->start], pkt_length); + buf_ptr = buf_ptr + pkt_length; + + uint8_t pec_byte = calculate_pec_byte( + smbus->txbuf, + SMBUS_COMMAND_CODE_SIZE + SMBUS_LENGTH_FIELD_SIZE + sizeof(*hdr) + + pkt_length, + MCTP_SLAVE_ADDRESS, 0); + + *buf_ptr = pec_byte; + + i2c_message_len = SMBUS_COMMAND_CODE_SIZE + SMBUS_LENGTH_FIELD_SIZE + + sizeof(*hdr) + pkt_length + + SMBUS_PEC_BYTE_SIZE; // command code, length, + // header, data, pec byte + + if (mctp_smbus_tx(smbus, i2c_message_len)) { + mctp_prerr("Can't hold mux"); + return -1; + } + + return 0; +} + +#ifdef MCTP_HAVE_FILEIO +int mctp_smbus_read(struct mctp_binding_smbus *smbus) +{ + ssize_t len = 0; + struct mctp_smbus_header_rx *hdr; + int ret = 0; + + do { + ret = lseek(smbus->in_fd, 0, SEEK_SET); + if (ret < 0) { + mctp_prerr("Failed to seek"); + ret = -1; + } + + len = read(smbus->in_fd, smbus->rxbuf, sizeof(smbus->rxbuf)); + if (len < sizeof(*hdr)) { + // This condition hits from from time to time, even with + // a properly written poll loop, although it's not clear + // why. Return an error so that the upper layer can + // retry. + ret = 0; + break; + } + + hdr = (void *)smbus->rxbuf; + if (hdr->destination_slave_address + != (MCTP_SOURCE_SLAVE_ADDRESS & ~1)) { + mctp_prerr("Got bad slave address %d", + hdr->destination_slave_address); + ret = 0; + break; + } + if (hdr->command_code != MCTP_COMMAND_CODE) { + mctp_prerr("Got bad command code %d", + hdr->command_code); + // Not a payload intended for us + ret = 0; + break; + } + + if (hdr->byte_count != (len - sizeof(*hdr))) { + // Got an incorrectly sized payload + mctp_prerr("Got smbus payload sized %d, expecting %d", + hdr->byte_count, len - sizeof(*hdr)); + ret = 0; + break; + } + + if (len < 0) { + mctp_prerr("can't read from smbus device: %m"); + ret = -1; + break; + } + + smbus->rx_pkt = mctp_pktbuf_alloc(&(smbus->binding), 0); + assert(smbus->rx_pkt); + + if (mctp_pktbuf_push(smbus->rx_pkt, &smbus->rxbuf[sizeof(*hdr)], + len - sizeof(*hdr) - SMBUS_PEC_BYTE_SIZE) + != 0) { + mctp_prerr("Can't push tok pktbuf: %m"); + ret = -1; + break; + } + + mctp_bus_rx(&(smbus->binding), smbus->rx_pkt); + + smbus->rx_pkt = NULL; + + } while (0); + +#ifdef I2C_M_HOLD + if (mctp_smbus_unhold_bus(smbus)) { + mctp_prerr("Can't hold mux"); + ret = -1; + } +#endif // I2C_M_HOLD + + return ret; +} + +int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus) +{ + return smbus->in_fd; +} + + +int mctp_smbus_set_in_fd(struct mctp_binding_smbus *smbus, int fd) +{ + smbus->in_fd = fd; +} + +int mctp_smbus_set_out_fd(struct mctp_binding_smbus *smbus, int fd) +{ + smbus->out_fd = fd; +} + +int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus) +{ + return smbus->out_fd; +} + +int mctp_smbus_open_in_bus(struct mctp_binding_smbus *smbus, int in_bus) +{ + char filename[60]; + size_t filename_size = 0; + char slave_mqueue[20]; + size_t mqueue_size = 0; + int fd = 0; + size_t size = sizeof(filename); + int address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1; + int ret = -1; + + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", in_bus, + in_bus, SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + ret = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (ret >= 0) { + return ret; + } + + // Device doesn't exist. Create it. + filename_size = sizeof(filename); + snprintf(filename, filename_size, + "/sys/bus/i2c/devices/i2c-%d/new_device", in_bus); + filename[filename_size - 1] = '\0'; + + fd = open(filename, O_WRONLY); + if (fd < 0) { + mctp_prerr("can't open root device %s: %m", filename); + return -1; + } + + mqueue_size = sizeof(slave_mqueue); + snprintf(slave_mqueue, mqueue_size, "slave-mqueue %#04x", + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + size = write(fd, slave_mqueue, mqueue_size); + close(fd); + if (size != mqueue_size) { + mctp_prerr("can't create mqueue device on %s: %m", filename); + return -1; + } + + size = sizeof(filename); + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", in_bus, + in_bus, SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + return open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); +} + +int mctp_smbus_open_out_bus(struct mctp_binding_smbus *smbus, int out_bus) +{ + char filename[60]; + size_t size = sizeof(filename); + snprintf(filename, size, "/dev/i2c-%d", out_bus); + filename[size - 1] = '\0'; + + return open(filename, O_RDWR | O_NONBLOCK); +} + +/* +int mctp_smbus_open_bus(struct mctp_binding_smbus *smbus, int out_bus_num, + int root_bus_num) +{ + char filename[60]; + size_t filename_size = 0; + char slave_mqueue[20]; + size_t mqueue_size = 0; + int fd = 0; + size_t size = sizeof(filename); + int address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1; + + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", + root_bus_num, root_bus_num, + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + smbus->in_fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (smbus->in_fd < 0) { + // Device doesn't exist. Create it. + filename_size = sizeof(filename); + snprintf(filename, filename_size, + "/sys/bus/i2c/devices/i2c-%d/new_device", + root_bus_num); + filename[filename_size - 1] = '\0'; + + fd = open(filename, O_WRONLY); + if (fd < 0) { + mctp_prerr("can't open root device %s: %m", filename); + return -1; + } + + mqueue_size = sizeof(slave_mqueue); + snprintf(slave_mqueue, mqueue_size, "slave-mqueue %#04x", + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + size = write(fd, slave_mqueue, mqueue_size); + close(fd); + if (size != mqueue_size) { + mctp_prerr("can't create mqueue device on %s: %m", + filename); + return -1; + } + + size = sizeof(filename); + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", + root_bus_num, root_bus_num, + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + smbus->in_fd = + open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (smbus->in_fd < 0) { + mctp_prerr("can't open mqueue device on %s: %m", + filename); + return -2; + } + } + + size = sizeof(filename); + snprintf(filename, size, "/dev/i2c-%d", out_bus_num); + filename[size - 1] = '\0'; + + smbus->out_fd = open(filename, O_RDWR | O_NONBLOCK); + if (smbus->out_fd < 0) { + close(smbus->in_fd); + mctp_prerr("can't open device %s: %m", filename); + } + + return 0; +} +*/ +#endif + +void mctp_smbus_register_bus(struct mctp_binding_smbus *smbus, + struct mctp *mctp, mctp_eid_t eid) +{ + smbus->bus_id = mctp_register_bus(mctp, &smbus->binding, eid); + mctp_binding_set_tx_enabled(&smbus->binding, true); +} + +struct mctp_binding_smbus *mctp_smbus_init(void) +{ + struct mctp_binding_smbus *smbus; + + smbus = __mctp_alloc(sizeof(*smbus)); + memset(&(smbus->binding), 0, sizeof(smbus->binding)); + + smbus->in_fd = -1; + smbus->out_fd = -1; + + smbus->rx_pkt = NULL; + smbus->binding.name = "smbus"; + smbus->binding.version = 1; + smbus->binding.pkt_size = sizeof(smbus->rxbuf); + + smbus->binding.tx = mctp_binding_smbus_tx; + return smbus; +} + +void mctp_smbus_free(struct mctp_binding_smbus *smbus) +{ + __mctp_free(smbus); +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb new file mode 100644 index 000000000..ead001a7c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb @@ -0,0 +1,43 @@ +SUMMARY = "libmctp" +DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" + +SRC_URI = "git://github.com/openbmc/libmctp.git" +SRCREV = "eba19a3b122a39ef2b5dbda49b418a202f78a48d" + +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0 | GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=0d30807bb7a4f16d36e96b78f9ed8fae" + +inherit cmake + +S = "${WORKDIR}/git" + +DEPENDS += "i2c-tools" + +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Smbus-changes-for-libmctp.patch \ + file://0002-Fix-Memory-Leak.patch \ + file://CMakeLists.txt \ + file://crc32c.c \ + file://crc32c.h \ + file://libmctp-smbus.h \ + file://smbus.c" + +do_configure_prepend() { + cp -f ${WORKDIR}/*.c ${S} + cp -f ${WORKDIR}/*.h ${S} + cp -f ${WORKDIR}/CMakeLists.txt ${S} +} + +# linux-libc-headers guides this way to include custom uapi headers +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" + +do_configure[depends] += "virtual/kernel:do_shared_workdir" 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 new file mode 100644 index 000000000..d1aa797a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend @@ -0,0 +1,5 @@ +EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DINTEL_PFR_ENABLED=ON', '', d)}" +EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" +EXTRA_OECMAKE += "-DUSING_ENTITY_MANAGER_DECORATORS=OFF" +SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git" +SRCREV = "01fbd0176c403feb29bf2a9ddd17469d0a27c3ef" diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb new file mode 100644 index 000000000..955ed1921 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb @@ -0,0 +1,26 @@ +SUMMARY = "Kernel panic Check" +DESCRIPTION = "script tool to check if the reboot is caused by kernel panic \ + log the kernel panic to systemd journal, and also log to redfish \ + " + +S = "${WORKDIR}" +SRC_URI = "file://kernel-panic-check.sh \ + file://kernel-panic-check.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash logger-systemd" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/kernel-panic-check.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/kernel-panic-check.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/kernel-panic-check.sh ${D}/${bindir}/kernel-panic-check.sh +} + +SYSTEMD_SERVICE_${PN} += " kernel-panic-check.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service new file mode 100644 index 000000000..afe017baf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service @@ -0,0 +1,9 @@ +[Unit] +Description=Check for kernel panic + +[Service] +Type=oneshot +ExecStart=/usr/bin/kernel-panic-check.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh new file mode 100755 index 000000000..815f50b71 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh @@ -0,0 +1,16 @@ +#!/bin/sh +panicFile="/sys/fs/pstore/dmesg-ramoops-0" +if [ -f $panicFile ] +then + # log the detailed last kernel panic messages + logger -t kernel-panic-check "Reboot from kernel panic! Log as following:" + cat $panicFile | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.BMCKernelPanic +PRIORITY=4 +MESSAGE=BMC rebooted due to kernel panic +EOF + + rm -rf $panicFile +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend new file mode 100644 index 000000000..817e164a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend @@ -0,0 +1,3 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/libpeci" +SRCREV = "ff44e549c44c7658ec11e0c19c13c4c45900cfe4" diff --git a/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend new file mode 100644 index 000000000..f47a3c866 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend @@ -0,0 +1,5 @@ +# libxcrypt fails to compile under gcc with the -Os flag. Because we want to +# be able to compile the rest of the system with -Os, override the global +# setting here to fall back to -O3 +CFLAGS_append = " --param max-inline-insns-single=1000" +FULL_OPTIMIZATION = "-O3 -pipe ${DEBUG_FLAGS}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc new file mode 100644 index 000000000..abad9d12d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc @@ -0,0 +1,43 @@ +SUMMARY = "logger tool in util-linux with systemd support" +HOMEPAGE = "http://userweb.kernel.org/~kzak/util-linux/" +DESCRIPTION = "logger tool with systemd support, used to add log to systemd journald." + +SECTION = "base" + +LICENSE = "GPLv2+ & LGPLv2.1+ & BSD-3-Clause & BSD-4-Clause" + +LIC_FILES_CHKSUM = "file://README.licensing;md5=972a134f1e14b2b060e365df2fab0099 \ + file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \ + file://Documentation/licenses/COPYING.GPL-2.0-or-later;md5=b234ee4d69f5fce4486a80fdaf4a4263 \ + file://Documentation/licenses/COPYING.LGPL-2.1-or-later;md5=4fbd65380cdd255951079008b364516c \ + file://Documentation/licenses/COPYING.BSD-3-Clause;md5=58dcd8452651fc8b07d1f65ce07ca8af \ + file://Documentation/licenses/COPYING.BSD-4-Clause-UC;md5=263860f8968d8bafa5392cab74285262 \ + file://libuuid/COPYING;md5=6d2cafc999feb2c2de84d4d24b23290c \ + file://libmount/COPYING;md5=7c7e39fb7d70ffe5d693a643e29987c2 \ + file://libblkid/COPYING;md5=693bcbbe16d3a4a4b37bc906bc01cc04" + +inherit autotools gettext pkgconfig +DEPENDS = "libcap-ng ncurses virtual/crypt zlib systemd " +#DEPENDS_intel-ast2500 += " systemd " +#RDEPENDS_${PN} += " libsystemd" + +MAJOR_VERSION = "${@'.'.join(d.getVar('PV').split('.')[0:2])}" +SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-linux-${MAJOR_VERSION}.tar.xz \ + " + +S = "${WORKDIR}/util-linux-${MAJOR_VERSION}" + +EXTRA_OECONF = " --disable-nls --disable-all-programs \ + --disable-libuuid --disable-libblkid --disable-libmount \ + --disable-libsmartcols --disable-libfdisk --disable-pylibmount \ + --with-systemd \ + --enable-logger \ + " + +do_install_append () { + mv ${D}${bindir}/logger ${D}${bindir}/logger-systemd + rm -rf ${D}${sbindir} + rm -rf ${D}${base_libdir} + rm -rf ${D}${libdir} + rm -rf ${D}${datadir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch new file mode 100644 index 000000000..748b6ef09 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch @@ -0,0 +1,20 @@ +Ptest needs buildtest-TESTS and runtest-TESTS targets. +serial-tests is required to generate those targets. +Revert run.sh script accordingly to serialize running tests + +Signed-off-by: Tudor Florea <tudor.florea@enea.com> +Upstream-Status: Inappropriate + +Index: util-linux-2.32/configure.ac +=================================================================== +--- util-linux-2.32.orig/configure.ac ++++ util-linux-2.32/configure.ac +@@ -11,7 +11,7 @@ AC_CONFIG_MACRO_DIR([m4]) + dnl AC_USE_SYSTEM_EXTENSIONS must be called before any macros that run + dnl the compiler (like AC_PROG_LIBTOOL) to avoid autoconf errors. + AC_USE_SYSTEM_EXTENSIONS +-AM_INIT_AUTOMAKE([-Wall foreign 1.10 tar-pax no-dist-gzip dist-xz subdir-objects]) ++AM_INIT_AUTOMAKE([-Wall foreign 1.10 tar-pax no-dist-gzip dist-xz subdir-objects serial-tests]) + + m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], + [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])]) diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch new file mode 100644 index 000000000..e475289f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch @@ -0,0 +1,23 @@ +util-linux: take ${sbindir} from the environment if it is set there +fix the test, the [ ] syntax was getting eaten by autoconf + +Signed-off-by: Phil Blundell <pb@pbcl.net> +Signed-off-by: Saul Wold <sgw@linux.intel.com +Upstream-Status: Inappropriate [configuration] + +Index: util-linux-2.31/configure.ac +=================================================================== +--- util-linux-2.31.orig/configure.ac ++++ util-linux-2.31/configure.ac +@@ -89,7 +89,10 @@ AC_SUBST([runstatedir]) + usrbin_execdir='${exec_prefix}/bin' + AC_SUBST([usrbin_execdir]) + +-usrsbin_execdir='${exec_prefix}/sbin' ++if test -z "$usrsbin_execdir" ; ++then ++ usrsbin_execdir='${exec_prefix}/sbin' ++fi + AC_SUBST([usrsbin_execdir]) + + AS_CASE([$libdir], diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch new file mode 100644 index 000000000..417ca1d98 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch @@ -0,0 +1,25 @@ +Display testname for subtest + +Signed-off-by: Tudor Florea <tudor.florea@enea.com> +Upstream-Status: Pending + +--- + tests/functions.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/functions.sh b/tests/functions.sh +index 5246605..b24dc15 100644 +--- a/tests/functions.sh ++++ b/tests/functions.sh +@@ -320,7 +320,7 @@ function ts_init_subtest { + + if [ "$TS_PARSABLE" != "yes" ]; then + [ $TS_NSUBTESTS -eq 1 ] && echo +- printf "%16s: %-27s ..." "" "$TS_SUBNAME" ++ printf "%13s: %-30s ..." "$TS_COMPONENT" "$TS_SUBNAME" + fi + } + +-- +2.8.3 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch new file mode 100644 index 000000000..0537f7d85 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch @@ -0,0 +1,23 @@ +Define TESTS variable + +Signed-off-by: Tudor Florea <tudor.florea@enea.com> +Upstream-Status: Pending +--- + Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Makefile.am b/Makefile.am +index bbaccb1..7d5a6bb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -48,6 +48,7 @@ systemdsystemunit_DATA = + dist_bashcompletion_DATA = + check_PROGRAMS = + dist_check_SCRIPTS = ++TESTS = $(check_PROGRAMS) + + PATHFILES = + +-- +2.8.3 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest new file mode 100644 index 000000000..e135ee583 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest @@ -0,0 +1,43 @@ +#!/bin/sh + + +# When udevd (from eudev) is running most eject/mount tests will fail because +# of automount. We need to stop udevd before executing util-linux's tests. +# The systemd-udevd daemon doesn't change the outcome of util-linux's tests. +UDEV_PID="`pidof "@base_sbindir@/udevd"`" +if [ "x$UDEV_PID" != "x" ]; then + /etc/init.d/udev stop +fi + +current_path=$(readlink -f $0) +export bindir=$(dirname $current_path) +export PATH=$bindir/bin:$PATH + +cd tests || exit 1 + +comps=$(find ts/ -type f -perm -111 -regex ".*/[^\.~]*" | sort) + + +echo +echo "-------------------- util-linux regression tests --------------------" +echo +echo " For development purpose only. " +echo " Don't execute on production system! " +echo + +res=0 +count=0 +for ts in $comps; +do + $ts | sed -u '{ + s/^\(.*\):\(.*\) \.\.\. OK$/PASS: \1:\2/ + s/^\(.*\):\(.*\) \.\.\. FAILED \(.*\)$/FAIL: \1:\2 \3/ + s/^\(.*\):\(.*\) \.\.\. SKIPPED \(.*\)$/SKIP: \1:\2 \3/ + }' +done + + +if [ "x$UDEV_PID" != "x" ]; then + /etc/init.d/udev start +fi + diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd new file mode 100644 index 000000000..4b368ccf5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd @@ -0,0 +1,3 @@ +auth include runuser +session optional pam_keyinit.so force revoke +session include runuser diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd new file mode 100644 index 000000000..48d133b9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd @@ -0,0 +1,4 @@ +auth sufficient pam_rootok.so +session optional pam_keyinit.so revoke +session required pam_limits.so +session required pam_unix.so diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb new file mode 100644 index 000000000..b58628667 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb @@ -0,0 +1,12 @@ +require logger-systemd.inc + +SRC_URI += "file://configure-sbindir.patch \ + file://runuser.pamd \ + file://runuser-l.pamd \ + file://ptest.patch \ + file://run-ptest \ + file://display_testname_for_subtest.patch \ + file://avoid_parallel_tests.patch \ +" +SRC_URI[md5sum] = "a78cbeaed9c39094b96a48ba8f891d50" +SRC_URI[sha256sum] = "743f9d0c7252b6db246b659c1e1ce0bd45d8d4508b4dfa427bbb4a3e9b9f62b5"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb new file mode 100644 index 000000000..f8e5505ef --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb @@ -0,0 +1,24 @@ +# Add GSL: Guideline Support Library for c++ +# https://github.com/Microsoft/GSL + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://LICENSE;md5=363055e71e77071107ba2bb9a54bd9a7" + +SRC_URI = "git://github.com/Microsoft/GSL.git;protocol=https;nobranch=1" + +# Modify these as desired +PV = "1.0+git${SRCPV}" +#SRCREV = "${AUTOREV}" +SRCREV = "be43c79742dc36ee55b21c5d531a5ff301d0ef8d" + +S = "${WORKDIR}/git" + +do_install () { + install -d ${D}/usr/include + install -d ${D}/usr/include/gsl + for F in ${S}/include/gsl/*; do + install -m 0644 ${F} ${D}/usr/include/gsl + done +} + +ALLOW_EMPTY_${PN} = "1" diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync-tmp.conf b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync-tmp.conf new file mode 100644 index 000000000..e73e47129 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync-tmp.conf @@ -0,0 +1,2 @@ +x /tmp/.rwfs - - - - +x /tmp/.overlay - - - - 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 new file mode 100644 index 000000000..4595541c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service @@ -0,0 +1,11 @@ +[Unit] +Description=Overlay sync to NV storage + +[Service] +# 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 + +[Install] +WantedBy=multi-user.target 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 new file mode 100644 index 000000000..fa74149d4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb @@ -0,0 +1,29 @@ +SUMMARY = "NV Overlay Sync" +DESCRIPTION = "Script to periodically sync the overlay to NV storage" + +S = "${WORKDIR}" +SRC_URI = "file://nv-sync.service \ + file://nv-syncd \ + file://nv-sync-tmp.conf \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +inherit systemd + +RDEPENDS_${PN} += "bash" + +FILES_${PN} += "${systemd_system_unitdir}/nv-sync.service \ + ${libdir}/tmpfiles.d/nv-sync-tmp.conf" + +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 + install -d ${D}${libdir}/tmpfiles.d + install -m 0644 ${WORKDIR}/nv-sync-tmp.conf ${D}${libdir}/tmpfiles.d/ +} + +SYSTEMD_SERVICE_${PN} += " nv-sync.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend new file mode 100644 index 000000000..ba95727b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend @@ -0,0 +1,36 @@ +# WARNING! +# +# These modifications to os-release disable the bitbake parse +# cache (for the os-release recipe only). Before copying +# and pasting into another recipe ensure it is understood +# what that means! + +require version-vars.inc + +OS_RELEASE_FIELDS_append = " OPENBMC_VERSION IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16" + +OS_RELEASE_FIELDS_remove = "BUILD_ID" + +python do_compile_append () { + import glob + with open(d.expand('${B}/os-release'), 'a') as f: + corebase = d.getVar('COREBASE', True) + f.write('\n# Build Configuration Details\n') + repo_status(d, f, corebase, '') + repo_status(d, f, os.path.join(corebase, 'meta-openbmc-mods'), '--tags') + appends_dir = os.path.join(d.getVar('TOPDIR', True), 'workspace', 'appends') + + for fn in glob.glob(os.path.join(appends_dir, '*.bbappend')): + with open(fn, 'r') as bb_f: + for line in bb_f: + if line.startswith('# srctreebase: '): + srctreebase = line.split(':', 1)[1].strip() + repo_status(d, f, srctreebase, '--tags') +} + + +# Ensure the git commands run every time bitbake is invoked. +BB_DONT_CACHE = "1" + +# Make os-release available to other recipes. +SYSROOT_DIRS_append = " ${sysconfdir}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc b/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc new file mode 100644 index 000000000..95061a570 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc @@ -0,0 +1,81 @@ +def irun_git(d, oeroot, git_cmd, **kwargs): + err = None + try: + cmd = 'git --work-tree {} --git-dir {}/.git {}'.format(oeroot, oeroot, git_cmd) + ret, err = bb.process.run(cmd, **kwargs) + 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.strip('\n') + +def repo_status(d, f, repo, tagargs): + import subprocess + + cmd_list = [['HEAD', 'rev-parse HEAD'], + ['TAG', 'describe {} --dirty --long'.format(tagargs)], + ['STATUS', 'status -sb']] + + f.write(('\n# REPOSITORY: {} '.format(os.path.basename(repo))).ljust(80, '+') + '\n') + for item in cmd_list: + f.write('# {}: '.format(item[0])) + sb = irun_git(d, repo, item[1]) + if sb: + sb_lines = sb.split('\n') + if len(sb_lines) == 1: + f.write(sb_lines[0]) + else: + f.write('\n# ' + '\n# '.join(sb_lines)) + f.write('\n') + +python() { + import re + + gen = d.getVar('PRODUCT_GENERATION', True) + if gen is None: + gen = 'unknown' + + corebase = d.getVar('COREBASE', True) + mibase = os.path.join(corebase, 'meta-openbmc-mods') + obmc_vers = irun_git(d, corebase, 'describe --dirty --long') + if obmc_vers is None: + raise bb.build.FuncFailed("Missing version tag for openbmc-openbmc") + d.setVar('OPENBMC_VERSION', obmc_vers) + + obmc_hash = irun_git(d, corebase, 'rev-parse HEAD') + meta_vers = irun_git(d, mibase, + 'describe --long --abbrev=6 ' + + '--match \'{}-[0-9]*\.[0-9]*\''.format(gen)) + + # If no tag in meta-openbmc-mods, provide default version + if meta_vers.startswith('fatal:'): + meta_vers = '{}-0.0-0'.format(gen) + + meta_hash = irun_git(d, mibase, 'rev-parse HEAD') + # If no hash from meta-openbmc-mods, provide default + if meta_hash.startswith('fatal:'): + meta_hash = '00000000' + version_id = '{}-{}'.format(meta_vers, obmc_hash[0:7]) + if version_id: + d.setVar('VERSION_ID', version_id) + versionList = version_id.split('-') + versionList = re.split('-|\.', version_id) + version = '{}.{}-{}'.format(versionList[0], versionList[1], versionList[2]) + d.setVar('VERSION', version) + d.setVar('IPMI_MAJOR', versionList[1]) + d.setVar('IPMI_MINOR', versionList[2]) + d.setVar('IPMI_AUX13', hex(min(int(versionList[3]), 0xff))) + d.setVar('IPMI_AUX14', '0x{}'.format(meta_hash[0:2])) + d.setVar('IPMI_AUX15', '0x{}'.format(meta_hash[2:4])) + d.setVar('IPMI_AUX16', '0x{}'.format(meta_hash[4:6])) + + build_id = irun_git(d, mibase, 'describe --abbrev=0') + if build_id: + d.setVar('BUILD_ID', build_id) +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend b/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend new file mode 100644 index 000000000..87a4c8503 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend @@ -0,0 +1 @@ +RRECOMMENDS_${PN}_append = " vim cmake sdbusplus" diff --git a/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc b/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc new file mode 100644 index 000000000..7b84c9916 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc @@ -0,0 +1,61 @@ +# /etc/inputrc - global inputrc for libreadline +# See readline(3readline) and `info rluserman' for more information. + +# Be 8 bit clean. +set input-meta on +set output-meta on + +# To allow the use of 8bit-characters like the german umlauts, comment out +# the line below. However this makes the meta key not work as a meta key, +# which is annoying to those which don't need to type in 8-bit characters. + +# set convert-meta off + +# try to enable the application keypad when it is called. Some systems +# need this to enable the arrow keys. +# set enable-keypad on + +# see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys + +# do not bell on tab-completion +# set bell-style none + +# some defaults / modifications for the emacs mode +$if mode=emacs + +# allow the use of the Home/End keys + "\e[1~": beginning-of-line + "\e[4~": end-of-line + +# allow the use of the Delete/Insert keys + "\e[3~": delete-char +# "\e[2~": quoted-insert + +# mappings for "page up" and "page down" to step to the beginning/end +# of the history +# "\e[5~": beginning-of-history +# "\e[6~": end-of-history + +# alternate mappings for "page up" and "page down" to search the history +# "\e[5~": history-search-backward +# "\e[6~": history-search-forward + +# # mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving +# "\e[5C": forward-word +# "\e[5D": backward-word +# "\e\e[C": forward-word +# "\e\e[D": backward-word + +# $if term=rxvt +# "\e[8~": end-of-line +# $endif + +# for non RH/Debian xterm, can't hurt for RH/DEbian xterm +# "\eOH": beginning-of-line +# "\eOF": end-of-line + +# for freebsd console +# "\e[H": beginning-of-line +# "\e[F": end-of-line + +$endif diff --git a/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend new file mode 100644 index 000000000..c63a45dd4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend @@ -0,0 +1,2 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI_append = " file://inputrc" diff --git a/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend new file mode 100644 index 000000000..4ce29534d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend @@ -0,0 +1,11 @@ +RDEPENDS_${PN} = "" +do_install_append() { + F=$(find ${D} -name check_for_unsafe_apis) + if [ -n "${F}" ]; then + # remove the unused perl script + rm -f "${F}" + # remove the script's destination directory, only if it is empty + rmdir "$(dirname ${F})" 2>/dev/null || : + fi +} + diff --git a/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb new file mode 100644 index 000000000..bc62305e8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb @@ -0,0 +1,15 @@ +SUMMARY = "Safe C Library" + +LICENSE = "safec" +LIC_FILES_CHKSUM = "file://COPYING;md5=6d0eb7dfc57806a006fcbc4e389cf164" +SECTION = "lib" + +inherit autotools pkgconfig + +S = "${WORKDIR}/git" +SRCREV = "bfc9f8bb8a9bfd02fde8ef3fd78fcd61411d070d" +SRC_URI = "git://github.com/rurban/safeclib.git" + +COMPATIBLE_HOST = '(x86_64|i.86|powerpc|powerpc64|arm|aarch64).*-linux' + +RDEPENDS_${PN} = "perl" diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb new file mode 100644 index 000000000..cfea1a910 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb @@ -0,0 +1,26 @@ +SUMMARY = "Security registers check" +DESCRIPTION = "script tool to check if registers value are security \ + log the security event to systemd journal, and also log to redfish \ + " + +S = "${WORKDIR}" +SRC_URI = "file://security-registers-check.sh \ + file://security-registers-check.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash logger-systemd" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/security-registers-check.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/security-registers-check.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/security-registers-check.sh ${D}/${bindir}/security-registers-check.sh +} + +SYSTEMD_SERVICE_${PN} += " security-registers-check.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service new file mode 100644 index 000000000..b824dbe3e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service @@ -0,0 +1,10 @@ +[Unit] +Description=Check for security registers + +[Service] +Type=oneshot +ExecStart=/usr/bin/security-registers-check.sh +Nice=5 + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh new file mode 100644 index 000000000..211120c78 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh @@ -0,0 +1,42 @@ +#!/bin/sh +value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/uart_port_debug` +if [ $value == 0 ] + then + # log the detailed last security registers check messages + logger -t security-registers-check "Uart port debug is enabled! Log as following:" + echo "Uart port debug is enabled." | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityUartPortDebugEnabled +PRIORITY=4 +MESSAGE=BMC Uart port debug is enabled +EOF +fi + +value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/p2a-bridge` +if [ $value == 1 ] + then + # log the detailed last security registers check messages + logger -t security-registers-check "P2A(PCIe to AHB) bridge is enabled! Log as following:" + echo "P2A(PCIe to AHB) bridge is enabled." | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityP2aBridgeEnabled +PRIORITY=4 +MESSAGE=BMC P2A(PCIe to AHB) bridge is enabled +EOF +fi + +value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/boot-2nd-flash` +if [ $value == 1 ] + then + # log the detailed last security registers check messages + logger -t security-registers-check "BMC 2nd boot flash is enabled! Log as following:" + echo "BMC 2nd boot flash is enabled." | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityBoot2ndFlashEnabled +PRIORITY=4 +MESSAGE=BMC 2nd boot flash is enabled +EOF +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend new file mode 100644 index 000000000..3d4e594a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend @@ -0,0 +1,10 @@ +# Remove these files since they are provided by obmc-intel-targets +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-start@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-stop@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-shutdown@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-reboot@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-startmin@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweron@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweroff@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-hard-poweroff@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-powerreset@.target" diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf new file mode 100644 index 000000000..48c60d36b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf @@ -0,0 +1,42 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# Entries in this file show the compile time defaults. +# You can change settings by editing this file. +# Defaults can be restored by simply deleting this file. +# +# See journald.conf(5) for details. + +[Journal] +Storage=volatile +#Compress=yes +#Seal=yes +#SplitMode=uid +#SyncIntervalSec=5m +#RateLimitIntervalSec=30s +#RateLimitBurst=10000 +#SystemMaxUse=6M +#SystemKeepFree= +#SystemMaxFileSize=512K +#SystemMaxFiles=32 +RuntimeMaxUse=32M +#RuntimeKeepFree= +#RuntimeMaxFileSize= +#RuntimeMaxFiles=4 +#MaxRetentionSec= +#MaxFileSec=1month +#ForwardToSyslog=no +#ForwardToKMsg=no +#ForwardToConsole=no +#ForwardToWall=yes +#TTYPath=/dev/console +#MaxLevelStore=notice +#MaxLevelSyslog=debug +#MaxLevelKMsg=notice +#MaxLevelConsole=info +#MaxLevelWall=emerg +#LineMax=48K diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf new file mode 100644 index 000000000..aa455cbcb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf @@ -0,0 +1,2 @@ +[Service] +ExecStop=touch /var/lib/systemd/timesync/clock
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend new file mode 100644 index 000000000..b3c318e15 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://journald.conf \ + file://systemd-timesyncd-save-time.conf \ + " + +FILES_${PN} += " ${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf" + +do_install_append() { + install -m 644 -D ${WORKDIR}/systemd-timesyncd-save-time.conf ${D}${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch new file mode 100644 index 000000000..5b9f17006 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch @@ -0,0 +1,28 @@ +From e02932693f92d6230b5520f431e127f7b6e2183e Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Tue, 6 Mar 2018 16:06:33 -0800 +Subject: [PATCH 1/1] Modfiy system.conf DefaultTimeoutStopSec + +Current time is 5 minutes, change it to 10 seconds. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + src/core/system.conf.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 8112125468..f7a35a56bb 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -39,7 +39,7 @@ + #DefaultStandardOutput=journal + #DefaultStandardError=inherit + #DefaultTimeoutStartSec=90s +-#DefaultTimeoutStopSec=90s ++DefaultTimeoutStopSec=10s + #DefaultTimeoutAbortSec= + #DefaultRestartSec=100ms + #DefaultStartLimitIntervalSec=10s +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service new file mode 100644 index 000000000..f71aea39d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: LGPL-2.1+ +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Wait Until Kernel Time Synchronized +Documentation=man:systemd-time-wait-sync.service(8) + +# Note that this tool doesn't need CAP_SYS_TIME itself, but it's primary +# usecase is to run in conjunction with a local NTP service such as +# systemd-timesyncd.service, which is conditioned this way. There might be +# niche usecases where running this service independently is desired, but let's +# make this all "just work" for the general case, and leave it to local +# modifications to make it work in the remaining cases. + +ConditionCapability=CAP_SYS_TIME +ConditionVirtualization=!container + +DefaultDependencies=no +Before=time-sync.target shutdown.target +Wants=time-sync.target +Conflicts=shutdown.target + +[Service] +Type=oneshot +ExecStart=/lib/systemd/systemd-time-wait-sync +TimeoutStartSec=10 +RemainAfterExit=yes + +[Install] +WantedBy=sysinit.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend new file mode 100644 index 000000000..19843d892 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend @@ -0,0 +1,19 @@ +# add some configuration overrides for systemd defaults + +LICENSE = "GPL-2.0" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch \ + file://systemd-time-wait-sync.service \ + " + +USERADD_PACKAGES_remove = "${PN}-journal-gateway ${PN}-journal-upload ${PN}-journal-remote" + +do_install_append(){ + rm -rf ${D}/lib/udev/rules.d/80-drivers.rules + cp -f ${WORKDIR}/systemd-time-wait-sync.service ${D}/lib/systemd/system/ +} + +PACKAGECONFIG_remove = " kmod" +PACKAGECONFIG_append = " logind" diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/cjson/cjson_%.bbappend b/meta-openbmc-mods/meta-common/recipes-devtools/cjson/cjson_%.bbappend new file mode 100644 index 000000000..666bc5991 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/cjson/cjson_%.bbappend @@ -0,0 +1,3 @@ +FILES_${PN}-dev += "${libdir}/cmake/cJSON/*" + +EXTRA_OECMAKE += " -DENABLE_CUSTOM_COMPILER_FLAGS=OFF -DENABLE_TARGET_EXPORT=OFF" diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb new file mode 100644 index 000000000..32bfba4b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb @@ -0,0 +1,21 @@ +DESCRIPTION = "OpenBMC mtd-util" + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://COPYING;md5=b77c43ae4eaf67bd73fb6452b2f113a3" + +SRC_URI = "git://github.com/Intel-BMC/mtd-util;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "69016601a521a95732cc49a3f4c8c7fe4b0ee058" + + +S = "${WORKDIR}/git" + +DEPENDS += "dbus systemd sdbusplus openssl zlib boost microsoft-gsl i2c-tools" + +inherit cmake pkgconfig + +# Specify any options you want to pass to cmake using EXTRA_OECMAKE: +EXTRA_OECMAKE = "" + +EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '-DDEVELOPER_OPTIONS=ON', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend new file mode 100644 index 000000000..96439ffc7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend @@ -0,0 +1,7 @@ +RDEPENDS_${PN}-runtime += "${MLPREFIX}pam-plugin-localuser-${libpam_suffix}" + +#Default settings lockout duration to 300 seconds and threshold value to 10 +do_install_append() { + sed -i 's/deny=0/deny=10/' ${D}${sysconfdir}/pam.d/common-auth + sed -i 's/unlock_time=0/unlock_time=300/' ${D}${sysconfdir}/pam.d/common-auth +} diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend new file mode 100644 index 000000000..55fb00a77 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend @@ -0,0 +1,4 @@ +do_install_append () { +# Remove ipmi_pass from image, if debug-tweaks is not enabled + ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'rm ${D}/${sysconfdir}/ipmi_pass', d)} +} diff --git a/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0001-Revert-server-Check-return-code-for-sd_bus_add_objec.patch b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0001-Revert-server-Check-return-code-for-sd_bus_add_objec.patch new file mode 100644 index 000000000..9aaf2f952 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus/0001-Revert-server-Check-return-code-for-sd_bus_add_objec.patch @@ -0,0 +1,34 @@ +From baff58f6e8f7aef4fd56be959fdd2e5e3c429eef Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Mon, 13 Jul 2020 11:51:54 -0700 +Subject: [PATCH] Revert "server: Check return code for + sd_bus_add_object_vtable()" + +This reverts commit 017a19da5f67a74daedf4d63111569902d4764e6. +--- + src/server/interface.cpp | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/src/server/interface.cpp b/src/server/interface.cpp +index a72c656..0155b6d 100644 +--- a/src/server/interface.cpp ++++ b/src/server/interface.cpp +@@ -17,13 +17,8 @@ interface::interface(sdbusplus::bus::bus& bus, const char* path, + _interface_added(false) + { + sd_bus_slot* slot = nullptr; +- int r = _intf->sd_bus_add_object_vtable(_bus.get(), &slot, _path.c_str(), +- _interf.c_str(), vtable, context); +- if (r < 0) +- { +- throw exception::SdBusError(-r, "sd_bus_add_object_vtable"); +- } +- ++ _intf->sd_bus_add_object_vtable(_bus.get(), &slot, _path.c_str(), ++ _interf.c_str(), vtable, context); + _slot = decltype(_slot){slot}; + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend new file mode 100644 index 000000000..5e3751ded --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI = "git://github.com/openbmc/sdbusplus.git;nobranch=1" +SRCREV = "95874d930f0bcc8390cd47ab3bb1e5e46db45278" + +SRC_URI += " \ + file://0001-Revert-server-Check-return-code-for-sd_bus_add_objec.patch \ + " + diff --git a/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login new file mode 100644 index 000000000..51dd3a83b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login @@ -0,0 +1,90 @@ +# +# The PAM configuration file for the Shadow `login' service +# + +# Enforce a minimal delay in case of failure (in microseconds). +# (Replaces the `FAIL_DELAY' setting from login.defs) +# Note that other modules may require another minimal delay. (for example, +# to disable any delay, you should add the nodelay option to pam_unix) +auth optional pam_faildelay.so delay=3000000 + +# Outputs an issue file prior to each login prompt (Replaces the +# ISSUE_FILE option from login.defs). Uncomment for use +# auth required pam_issue.so issue=/etc/issue + +# Disallows root logins except on tty's listed in /etc/securetty +# (Replaces the `CONSOLE' setting from login.defs) +# Note that it is included as a "requisite" module. No password prompts will +# be displayed if this module fails to avoid having the root password +# transmitted on unsecure ttys. +# You can change it to a "required" module if you think it permits to +# guess valid user names of your system (invalid user names are considered +# as possibly being root). +auth [success=ok ignore=ignore user_unknown=ignore default=die] pam_securetty.so + +# Disallows other than root logins when /etc/nologin exists +# (Replaces the `NOLOGINS_FILE' option from login.defs) +auth requisite pam_nologin.so + +# This module parses environment configuration file(s) +# and also allows you to use an extended config +# file /etc/security/pam_env.conf. +# +# parsing /etc/environment needs "readenv=1" +session required pam_env.so readenv=1 + +# Allow only uid 0 for login prompt authentication +auth required pam_succeed_if.so uid eq 0 + +# Do regular pam unix based authentication. Allow null password. +auth [success=2 default=ignore] pam_unix.so quiet nullok_secure +# here's the fallback if no module succeeds +auth requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +auth required pam_permit.so + +# This allows certain extra groups to be granted to a user +# based on things like time of day, tty, service, and user. +# Please edit /etc/security/group.conf to fit your needs +# (Replaces the `CONSOLE_GROUPS' option in login.defs) +auth optional pam_group.so + +# Uncomment and edit /etc/security/time.conf if you need to set +# time restrainst on logins. +# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs +# as well as /etc/porttime) +# account requisite pam_time.so + +# Uncomment and edit /etc/security/access.conf if you need to +# set access limits. +# (Replaces /etc/login.access file) +# account required pam_access.so + +# Sets up user limits according to /etc/security/limits.conf +# (Replaces the use of /etc/limits in old login) +session required pam_limits.so + +# Prints the last login info upon succesful login +# (Replaces the `LASTLOG_ENAB' option from login.defs) +session optional pam_lastlog.so + +# Prints the motd upon succesful login +# (Replaces the `MOTD_FILE' option in login.defs) +session optional pam_motd.so + +# Prints the status of the user's mailbox upon succesful login +# (Replaces the `MAIL_CHECK_ENAB' option from login.defs). +# +# This also defines the MAIL environment variable +# However, userdel also needs MAIL_DIR and MAIL_FILE variables +# in /etc/login.defs to make sure that removing a user +# also removes the user's mail spool file. +# See comments in /etc/login.defs +session optional pam_mail.so standard + +# Standard Un*x account and session +account include common-account +password include common-password +session include common-session diff --git a/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend new file mode 100644 index 000000000..283d787e5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PAM_SRC_URI += "file://pam.d/login \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend new file mode 100644 index 000000000..f42119baa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +# Use the latest to support obmc-ikvm properly +SRC_URI = "git://github.com/LibVNC/libvncserver" +SRCREV = "2b6d595e3ea89597b3bebbf545eb7d3c0a1224a8" diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch new file mode 100644 index 000000000..43600ac8a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch @@ -0,0 +1,162 @@ +From 0c0b7b5da551c99161bda98820a529ba29cbaac1 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +Date: Wed, 21 Aug 2019 16:52:30 -0700 +Subject: [PATCH] Fix keyboard and mouse input events dropping issue + +Restarting of HID input devices causes input events dropping issue +which is critical for BMC KVM uses. For an example, user can't enter +to BIOS by doing keep pressing 'F2' or 'Del' key because of this issue. + +To fix the issue, this commit removes the input device restarting +logic and refines error log journaling logic using errno checking. + +Tested: + 1. Open BMCweb -> Server control -> KVM. + 2. Make a host reset and keep pressing 'F2' key. + 3. Was able to enter to BIOS using the key press. + +Change-Id: Iec1bfad1d9e5825858844cab658bbfa3e6bc24f6 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +--- + ikvm_input.cpp | 58 +++++++--------------------------------------------------- + ikvm_input.hpp | 4 ---- + ikvm_video.cpp | 3 +-- + 3 files changed, 8 insertions(+), 57 deletions(-) + +diff --git a/ikvm_input.cpp b/ikvm_input.cpp +index d95e6313f62c..df12f2715585 100644 +--- a/ikvm_input.cpp ++++ b/ikvm_input.cpp +@@ -23,9 +23,9 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::File::Error; + + Input::Input(const std::string& kbdPath, const std::string& ptrPath) : +- pointerError(false), sendKeyboard(false), sendPointer(false), +- keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0}, +- keyboardPath(kbdPath), pointerPath(ptrPath) ++ sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1), ++ keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath), ++ pointerPath(ptrPath) + { + if (!keyboardPath.empty()) + { +@@ -156,36 +156,6 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl) + rfbDefaultPtrAddEvent(buttonMask, x, y, cl); + } + +-void Input::restart() +-{ +- if (!keyboardPath.empty() && keyboardFd < 0) +- { +- keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC); +- if (keyboardFd < 0) +- { +- log<level::ERR>("Failed to open input device", +- entry("PATH=%s", keyboardPath.c_str()), +- entry("ERROR=%s", strerror(errno))); +- } +- +- sendKeyboard = false; +- } +- +- if (!pointerPath.empty() && pointerFd < 0) +- { +- pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK); +- if (pointerFd < 0) +- { +- log<level::ERR>("Failed to open input device", +- entry("PATH=%s", pointerPath.c_str()), +- entry("ERROR=%s", strerror(errno))); +- } +- +- pointerError = false; +- sendPointer = false; +- } +-} +- + void Input::sendWakeupPacket() + { + uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0}; +@@ -459,13 +429,10 @@ bool Input::writeKeyboard(const uint8_t *report) + { + if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH) + { +- log<level::ERR>("Failed to write keyboard report", +- entry("ERROR=%s", strerror(errno))); +- +- if (errno == ESHUTDOWN) ++ if (errno != ESHUTDOWN && errno != EAGAIN) + { +- close(keyboardFd); +- keyboardFd = -1; ++ log<level::ERR>("Failed to write keyboard report", ++ entry("ERROR=%s", strerror(errno))); + } + + return false; +@@ -478,23 +445,12 @@ void Input::writePointer(const uint8_t *report) + { + if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH) + { +- if (!pointerError) ++ if (errno != ESHUTDOWN && errno != EAGAIN) + { + log<level::ERR>("Failed to write pointer report", + entry("ERROR=%s", strerror(errno))); +- pointerError = true; +- } +- +- if (errno == ESHUTDOWN) +- { +- close(pointerFd); +- pointerFd = -1; + } + } +- else +- { +- pointerError = false; +- } + } + + } // namespace ikvm +diff --git a/ikvm_input.hpp b/ikvm_input.hpp +index 953333263e2d..2adc7c106755 100644 +--- a/ikvm_input.hpp ++++ b/ikvm_input.hpp +@@ -48,8 +48,6 @@ class Input + */ + static void pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl); + +- /* @brief Re-opens USB device in case the endpoint shutdown */ +- void restart(); + /* @brief Sends a wakeup data packet to the USB input device */ + void sendWakeupPacket(); + /* @brief Sends an HID report to the USB input device */ +@@ -90,8 +88,6 @@ class Input + bool writeKeyboard(const uint8_t *report); + void writePointer(const uint8_t *report); + +- /* @brief Indicates whether or not a pointer report error has occurred */ +- bool pointerError; + /* @brief Indicates whether or not to send a keyboard report */ + bool sendKeyboard; + /* @brief Indicates whether or not to send a pointer report */ +diff --git a/ikvm_video.cpp b/ikvm_video.cpp +index 6a5aa6c10927..7bd4b4eb6c98 100644 +--- a/ikvm_video.cpp ++++ b/ikvm_video.cpp +@@ -163,10 +163,9 @@ bool Video::needsResize() + restart(); + return false; + } +- else if (timingsError) ++ else + { + timingsError = false; +- input.restart(); + } + + if (timings.bt.width != width || timings.bt.height != height) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch new file mode 100644 index 000000000..0fe93c604 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch @@ -0,0 +1,494 @@ +From 9a0f78ab773b33fd0445b23358097ddcd175a58f Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 22 Jul 2020 23:39:18 -0700 +Subject: [PATCH] Connect HID gadget device dynamically + +Connecting HID gadget device statically from the beginning of this +service causes an issue on WHLK test. To prevent the issue, this +commit changes the HID gadget device handling as dynamic so that +the HID gadget device can be connected when this service has at +least one KVM client. + +Tested: /dev/hidg0 and /dev/hidg1 created only when at least one +KVM client is connected. + +Change-Id: I5f6596b9e4e297fb6b507000499fc041460659f7 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + create_usbhid.sh | 278 ++++++++++++++++++++++++-------------------- + ikvm_input.cpp | 64 +++++++++- + ikvm_input.hpp | 14 +++ + ikvm_server.cpp | 2 + + start-ipkvm.service | 2 +- + 5 files changed, 230 insertions(+), 130 deletions(-) + +diff --git a/create_usbhid.sh b/create_usbhid.sh +index 656299102d7f..d1fa4e036bbe 100644 +--- a/create_usbhid.sh ++++ b/create_usbhid.sh +@@ -1,135 +1,157 @@ + #!/bin/sh + +-new_directory="/sys/kernel/config/usb_gadget/obmc_hid" ++hid_conf_directory="/sys/kernel/config/usb_gadget/obmc_hid" ++dev_name="1e6a0000.usb-vhub" + +-if [ -e "${new_directory}" ]; then +- exit 0 +-fi ++create_hid() { ++ # create gadget ++ mkdir "${hid_conf_directory}" ++ cd "${hid_conf_directory}" ++ ++ # add basic information ++ echo 0x0100 > bcdDevice ++ echo 0x0200 > bcdUSB ++ echo 0x0104 > idProduct # Multifunction Composite Gadget ++ echo 0x1d6b > idVendor # Linux Foundation ++ ++ # create English locale ++ mkdir strings/0x409 ++ ++ echo "OpenBMC" > strings/0x409/manufacturer ++ echo "virtual_input" > strings/0x409/product ++ echo "OBMC0001" > strings/0x409/serialnumber ++ ++ # Create HID keyboard function ++ mkdir functions/hid.0 ++ ++ echo 1 > functions/hid.0/protocol # 1: keyboard ++ echo 8 > functions/hid.0/report_length ++ echo 1 > functions/hid.0/subclass ++ ++ # Binary HID keyboard descriptor ++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop) ++ # 0x09, 0x06, // USAGE (Keyboard) ++ # 0xa1, 0x01, // COLLECTION (Application) ++ # 0x05, 0x07, // USAGE_PAGE (Keyboard) ++ # 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) ++ # 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x25, 0x01, // LOGICAL_MAXIMUM (1) ++ # 0x75, 0x01, // REPORT_SIZE (1) ++ # 0x95, 0x08, // REPORT_COUNT (8) ++ # 0x81, 0x02, // INPUT (Data,Var,Abs) ++ # 0x95, 0x01, // REPORT_COUNT (1) ++ # 0x75, 0x08, // REPORT_SIZE (8) ++ # 0x81, 0x03, // INPUT (Data,Var,Abs) ++ # 0x95, 0x05, // REPORT_COUNT (5) ++ # 0x75, 0x01, // REPORT_SIZE (1) ++ # 0x05, 0x08, // USAGE_PAGE (LEDs) ++ # 0x19, 0x01, // USAGE_MINIMUM (Num Lock) ++ # 0x29, 0x05, // USAGE_MAXIMUM (Kana) ++ # 0x91, 0x02, // OUTPUT (Data,Var,Abs) ++ # 0x95, 0x01, // REPORT_COUNT (1) ++ # 0x75, 0x03, // REPORT_SIZE (3) ++ # 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) ++ # 0x95, 0x06, // REPORT_COUNT (6) ++ # 0x75, 0x08, // REPORT_SIZE (8) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x25, 0x65, // LOGICAL_MAXIMUM (101) ++ # 0x05, 0x07, // USAGE_PAGE (Keyboard) ++ # 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) ++ # 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) ++ # 0x81, 0x00, // INPUT (Data,Ary,Abs) ++ # 0xc0 // END_COLLECTION ++ echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc ++ ++ # Create HID mouse function ++ mkdir functions/hid.1 ++ ++ echo 2 > functions/hid.1/protocol # 2: mouse ++ echo 5 > functions/hid.1/report_length ++ echo 1 > functions/hid.1/subclass ++ ++ # Binary HID mouse descriptor (absolute coordinate) ++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop) ++ # 0x09, 0x02, // USAGE (Mouse) ++ # 0xa1, 0x01, // COLLECTION (Application) ++ # 0x09, 0x01, // USAGE (Pointer) ++ # 0xa1, 0x00, // COLLECTION (Physical) ++ # 0x05, 0x09, // USAGE_PAGE (Button) ++ # 0x19, 0x01, // USAGE_MINIMUM (Button 1) ++ # 0x29, 0x03, // USAGE_MAXIMUM (Button 3) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x25, 0x01, // LOGICAL_MAXIMUM (1) ++ # 0x95, 0x03, // REPORT_COUNT (3) ++ # 0x75, 0x01, // REPORT_SIZE (1) ++ # 0x81, 0x02, // INPUT (Data,Var,Abs) ++ # 0x95, 0x01, // REPORT_COUNT (1) ++ # 0x75, 0x05, // REPORT_SIZE (5) ++ # 0x81, 0x03, // INPUT (Cnst,Var,Abs) ++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop) ++ # 0x09, 0x30, // USAGE (X) ++ # 0x09, 0x31, // USAGE (Y) ++ # 0x35, 0x00, // PHYSICAL_MINIMUM (0) ++ # 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) ++ # 0x15, 0x00, // LOGICAL_MINIMUM (0) ++ # 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) ++ # 0x65, 0x11, // UNIT (SI Lin:Distance) ++ # 0x55, 0x00, // UNIT_EXPONENT (0) ++ # 0x75, 0x10, // REPORT_SIZE (16) ++ # 0x95, 0x02, // REPORT_COUNT (2) ++ # 0x81, 0x02, // INPUT (Data,Var,Abs) ++ # 0xc0, // END_COLLECTION ++ # 0xc0 // END_COLLECTION ++ echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc ++ ++ # Create configuration ++ mkdir configs/c.1 ++ mkdir configs/c.1/strings/0x409 ++ ++ echo 0x80 > configs/c.1/bmAttributes ++ echo 200 > configs/c.1/MaxPower ++ echo "" > configs/c.1/strings/0x409/configuration ++ ++ # Link HID functions to configuration ++ ln -s functions/hid.0 configs/c.1 ++ ln -s functions/hid.1 configs/c.1 ++} ++ ++connect_hid() { ++ if ! [[ `cat UDC` =~ "${dev_name}:p" ]]; then ++ i=0 ++ num_ports=5 ++ base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p" ++ while [ $i -lt $num_ports ]; do ++ port=$(($i + 1)) ++ i=$port ++ if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then ++ break ++ fi ++ done ++ echo "${dev_name}:p${port}" > UDC ++ fi ++} ++ ++disconnect_hid() { ++ if [[ `cat UDC` =~ "${dev_name}:p" ]]; then ++ echo "" > UDC ++ fi ++} + +-# create gadget + original_directory="$(pwd)" +-mkdir "${new_directory}" +-cd "${new_directory}" +- +-# add basic information +-echo 0x0100 > bcdDevice +-echo 0x0200 > bcdUSB +-echo 0x0104 > idProduct # Multifunction Composite Gadget +-echo 0x1d6b > idVendor # Linux Foundation +- +-# create English locale +-mkdir strings/0x409 +- +-echo "OpenBMC" > strings/0x409/manufacturer +-echo "virtual_input" > strings/0x409/product +-echo "OBMC0001" > strings/0x409/serialnumber +- +-# Create HID keyboard function +-mkdir functions/hid.0 +- +-echo 1 > functions/hid.0/protocol # 1: keyboard +-echo 8 > functions/hid.0/report_length +-echo 1 > functions/hid.0/subclass +- +-# Binary HID keyboard descriptor +-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +-# 0x09, 0x06, // USAGE (Keyboard) +-# 0xa1, 0x01, // COLLECTION (Application) +-# 0x05, 0x07, // USAGE_PAGE (Keyboard) +-# 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) +-# 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x25, 0x01, // LOGICAL_MAXIMUM (1) +-# 0x75, 0x01, // REPORT_SIZE (1) +-# 0x95, 0x08, // REPORT_COUNT (8) +-# 0x81, 0x02, // INPUT (Data,Var,Abs) +-# 0x95, 0x01, // REPORT_COUNT (1) +-# 0x75, 0x08, // REPORT_SIZE (8) +-# 0x81, 0x03, // INPUT (Data,Var,Abs) +-# 0x95, 0x05, // REPORT_COUNT (5) +-# 0x75, 0x01, // REPORT_SIZE (1) +-# 0x05, 0x08, // USAGE_PAGE (LEDs) +-# 0x19, 0x01, // USAGE_MINIMUM (Num Lock) +-# 0x29, 0x05, // USAGE_MAXIMUM (Kana) +-# 0x91, 0x02, // OUTPUT (Data,Var,Abs) +-# 0x95, 0x01, // REPORT_COUNT (1) +-# 0x75, 0x03, // REPORT_SIZE (3) +-# 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) +-# 0x95, 0x06, // REPORT_COUNT (6) +-# 0x75, 0x08, // REPORT_SIZE (8) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x25, 0x65, // LOGICAL_MAXIMUM (101) +-# 0x05, 0x07, // USAGE_PAGE (Keyboard) +-# 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) +-# 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) +-# 0x81, 0x00, // INPUT (Data,Ary,Abs) +-# 0xc0 // END_COLLECTION +-echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc +- +-# Create HID mouse function +-mkdir functions/hid.1 +- +-echo 2 > functions/hid.1/protocol # 2: mouse +-echo 5 > functions/hid.1/report_length +-echo 1 > functions/hid.1/subclass +- +-# Binary HID mouse descriptor (absolute coordinate) +-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +-# 0x09, 0x02, // USAGE (Mouse) +-# 0xa1, 0x01, // COLLECTION (Application) +-# 0x09, 0x01, // USAGE (Pointer) +-# 0xa1, 0x00, // COLLECTION (Physical) +-# 0x05, 0x09, // USAGE_PAGE (Button) +-# 0x19, 0x01, // USAGE_MINIMUM (Button 1) +-# 0x29, 0x03, // USAGE_MAXIMUM (Button 3) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x25, 0x01, // LOGICAL_MAXIMUM (1) +-# 0x95, 0x03, // REPORT_COUNT (3) +-# 0x75, 0x01, // REPORT_SIZE (1) +-# 0x81, 0x02, // INPUT (Data,Var,Abs) +-# 0x95, 0x01, // REPORT_COUNT (1) +-# 0x75, 0x05, // REPORT_SIZE (5) +-# 0x81, 0x03, // INPUT (Cnst,Var,Abs) +-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop) +-# 0x09, 0x30, // USAGE (X) +-# 0x09, 0x31, // USAGE (Y) +-# 0x35, 0x00, // PHYSICAL_MINIMUM (0) +-# 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) +-# 0x15, 0x00, // LOGICAL_MINIMUM (0) +-# 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) +-# 0x65, 0x11, // UNIT (SI Lin:Distance) +-# 0x55, 0x00, // UNIT_EXPONENT (0) +-# 0x75, 0x10, // REPORT_SIZE (16) +-# 0x95, 0x02, // REPORT_COUNT (2) +-# 0x81, 0x02, // INPUT (Data,Var,Abs) +-# 0xc0, // END_COLLECTION +-# 0xc0 // END_COLLECTION +-echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc +- +-# Create configuration +-mkdir configs/c.1 +-mkdir configs/c.1/strings/0x409 +- +-echo 0x80 > configs/c.1/bmAttributes +-echo 200 > configs/c.1/MaxPower +-echo "" > configs/c.1/strings/0x409/configuration +- +-# Link HID functions to configuration +-ln -s functions/hid.0 configs/c.1 +-ln -s functions/hid.1 configs/c.1 +- +-# Enable gadget +-dev_name="1e6a0000.usb-vhub" +-i=0 +-num_ports=5 +-base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p" +-while [ $i -lt $num_ports ]; do +- port=$(($i + 1)) +- i=$port +- if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then +- break +- fi +-done +-echo "${dev_name}:p${port}" > UDC ++ ++if [ ! -e "${hid_conf_directory}" ]; then ++ create_hid ++else ++ cd "${hid_conf_directory}" ++fi ++ ++if [ "$1" = "connect" ]; then ++ connect_hid ++elif [ "$1" = "disconnect" ]; then ++ disconnect_hid ++else ++ echo "Invalid option: $1. Use 'connect' or 'disconnect'." ++fi + + cd "${original_directory}" +diff --git a/ikvm_input.cpp b/ikvm_input.cpp +index df12f2715585..c4cce5088461 100644 +--- a/ikvm_input.cpp ++++ b/ikvm_input.cpp +@@ -16,6 +16,8 @@ + + #include "scancodes.hpp" + ++namespace fs = std::filesystem; ++ + namespace ikvm + { + +@@ -27,6 +29,54 @@ Input::Input(const std::string& kbdPath, const std::string& ptrPath) : + 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); ++} ++ ++Input::~Input() ++{ ++ if (keyboardFd >= 0) ++ { ++ close(keyboardFd); ++ } ++ ++ if (pointerFd >= 0) ++ { ++ close(pointerFd); ++ } ++ ++ disconnect(); ++ hidUdcStream.close(); ++} ++ ++void Input::connect() ++{ ++ try ++ { ++ for (const auto& port : fs::directory_iterator(usbVirtualHubPath)) ++ { ++ if (fs::is_directory(port) && !fs::is_symlink(port) && ++ !fs::exists(port.path() / "gadget/suspended")) ++ { ++ const std::string portId = port.path().filename(); ++ hidUdcStream << portId << std::endl; ++ break; ++ } ++ } ++ } ++ catch (fs::filesystem_error& e) ++ { ++ log<level::ERR>("Failed to search USB virtual hub port", ++ entry("ERROR=%s", e.what())); ++ return; ++ } ++ catch (std::ofstream::failure& e) ++ { ++ log<level::ERR>("Failed to connect HID gadget", ++ entry("ERROR=%s", e.what())); ++ return; ++ } ++ + if (!keyboardPath.empty()) + { + keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC); +@@ -56,16 +106,28 @@ Input::Input(const std::string& kbdPath, const std::string& ptrPath) : + } + } + +-Input::~Input() ++void Input::disconnect() + { + if (keyboardFd >= 0) + { + close(keyboardFd); ++ keyboardFd = -1; + } + + if (pointerFd >= 0) + { + close(pointerFd); ++ pointerFd = -1; ++ } ++ ++ try ++ { ++ hidUdcStream << "" << std::endl; ++ } ++ catch (std::ofstream::failure& e) ++ { ++ log<level::ERR>("Failed to disconnect HID gadget", ++ entry("ERROR=%s", e.what())); + } + } + +diff --git a/ikvm_input.hpp b/ikvm_input.hpp +index 2adc7c106755..aae7cefbef6e 100644 +--- a/ikvm_input.hpp ++++ b/ikvm_input.hpp +@@ -2,6 +2,8 @@ + + #include <rfb/rfb.h> + ++#include <filesystem> ++#include <fstream> + #include <map> + #include <string> + +@@ -29,6 +31,10 @@ class Input + Input(Input&&) = default; + Input& operator=(Input&&) = default; + ++ /* @brief Connects HID gadget to host */ ++ void connect(); ++ /* @brief Disconnects HID gadget from host */ ++ void disconnect(); + /* + * @brief RFB client key event handler + * +@@ -72,6 +78,12 @@ class Input + 0x04, // left alt + 0x40 // right alt + }; ++ /* @brief Path to the HID gadget UDC */ ++ static constexpr const char* hidUdcPath = ++ "/sys/kernel/config/usb_gadget/obmc_hid/UDC"; ++ /* @brief Path to the USB virtual hub */ ++ static constexpr const char* usbVirtualHubPath = ++ "/sys/bus/platform/devices/1e6a0000.usb-vhub"; + /* + * @brief Translates a RFB-specific key code to HID modifier bit + * +@@ -109,6 +121,8 @@ class Input + * of which keys are down + */ + std::map<int, int> keysDown; ++ /* @brief Handle of the HID gadget UDC */ ++ std::ofstream hidUdcStream; + }; + + } // namespace ikvm +diff --git a/ikvm_server.cpp b/ikvm_server.cpp +index ebeaef049d04..1c2e981b7a72 100644 +--- a/ikvm_server.cpp ++++ b/ikvm_server.cpp +@@ -178,6 +178,7 @@ void Server::clientGone(rfbClientPtr cl) + + if (server->numClients-- == 1) + { ++ server->input.disconnect(); + rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(), + server->video.getHeight()); + } +@@ -193,6 +194,7 @@ enum rfbNewClientAction Server::newClient(rfbClientPtr cl) + cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest; + if (!server->numClients++) + { ++ server->input.connect(); + server->pendingResize = false; + server->frameCounter = 0; + } +diff --git a/start-ipkvm.service b/start-ipkvm.service +index 5f945b329a26..60234b231da3 100644 +--- a/start-ipkvm.service ++++ b/start-ipkvm.service +@@ -4,7 +4,7 @@ ConditionPathIsMountPoint=/sys/kernel/config + + [Service] + Restart=always +-ExecStartPre=/usr/bin/create_usbhid.sh ++ExecStartPre=/usr/bin/create_usbhid.sh disconnect + ExecStart=/usr/bin/obmc-ikvm -v /dev/video0 -k /dev/hidg0 -p /dev/hidg1 + + [Install] +-- +2.17.1 + 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 <jae.hyun.yoo@intel.com> +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 <jae.hyun.yoo@intel.com> +--- + 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<level::ERR>("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<std::mutex> 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<level::ERR>("Failed to write keyboard report", +- entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ ++ if (errno != EAGAIN) ++ { ++ if (errno != ESHUTDOWN) ++ { ++ log<level::ERR>("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<std::mutex> 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<level::ERR>("Failed to write pointer report", +- entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ ++ if (errno != EAGAIN) ++ { ++ if (errno != ESHUTDOWN) ++ { ++ log<level::ERR>("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 <filesystem> + #include <fstream> + #include <map> ++#include <mutex> + #include <string> + + 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<int, int> 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 new file mode 100644 index 000000000..9ea9e1a4e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend @@ -0,0 +1,10 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +#SRC_URI = "git://github.com/openbmc/obmc-ikvm" +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/configure-usb-c/configure-usb-c.bb b/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/configure-usb-c.bb new file mode 100644 index 000000000..66481543b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/configure-usb-c.bb @@ -0,0 +1,25 @@ +SUMMARY = "Configure USB Type C controller" +DESCRIPTION = "Configure USB Type C CC controller which requires basic initialization on every G3 to S5 cycle" + +S = "${WORKDIR}" +SRC_URI = " \ + file://configure-usb-c.sh \ + file://configure-usb-c.service \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/configure-usb-c.service" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${S}/configure-usb-c.sh ${D}/${bindir}/configure-usb-c.sh + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${S}/configure-usb-c.service ${D}${base_libdir}/systemd/system +} + +SYSTEMD_SERVICE_${PN} = "configure-usb-c.service" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/files/configure-usb-c.service b/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/files/configure-usb-c.service new file mode 100644 index 000000000..465ddd77f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/files/configure-usb-c.service @@ -0,0 +1,9 @@ +[Unit] +Description=Configure USB Type C controller + +[Service] +ExecStart=/usr/bin/configure-usb-c.sh +Type=oneshot + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/files/configure-usb-c.sh b/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/files/configure-usb-c.sh new file mode 100644 index 000000000..c7cc4a231 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/configure-usb-c/files/configure-usb-c.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +I2C_BUS=7 +CHIP_ADDR=0x47 + +read_id() { + local idx=0 + local result=0 + local value=0 + for ((idx=0; idx<6; idx++)) + do + typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N")) + value=$((value << idx)) + result=$((result | value)) + done + echo $result +} + +BOARD_ID=$(read_id) +if grep -q 'CPU part\s*: 0xc07' /proc/cpuinfo; then # AST2600 + if [[ $BOARD_ID == 62 || $BOARD_ID == 61 ]]; then + # Write 0x01 data into General Control Register (offset 0x0A) + # Write 0x21 data into General Control Register (offset 0x0A) + # Write 0x80 data into Connection Status Register (offset 0x08) + # Write 0x20 data into General Control Register (offset 0x0A) + i2cset -y $I2C_BUS $CHIP_ADDR 0x0a 0x01; i2cset -y $I2C_BUS $CHIP_ADDR 0x0a 0x21; i2cset -y $I2C_BUS $CHIP_ADDR 0x08 0x80; i2cset -y $I2C_BUS $CHIP_ADDR 0x0a 0x20 + echo "Configured USB Type C controller" + fi +fi diff --git a/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb new file mode 100644 index 000000000..a562636ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb @@ -0,0 +1,19 @@ +SUMMARY = "Miscellaneous host interface communication manager" +DESCRIPTION = "Daemon exposes Miscellaneous host interface communications like \ + platform reset, mail box & scratch pad" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/host-misc-comm-manager.git;protocol=ssh" + +SRCREV = "0d8577404fd321841fc84de547fe3d1d2a36909f" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Host.Misc.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb new file mode 100644 index 000000000..ed4ab4930 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb @@ -0,0 +1,21 @@ +SUMMARY = "HSBP Manager" +DESCRIPTION = "HSBP Manager monitors HSBPs through SMBUS" + +SRC_URI = "git://github.com/openbmc/s2600wf-misc.git" +SRCREV = "291d6388e0b770e89091935bc4edc7f371874666" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +SYSTEMD_SERVICE_${PN} = "hsbp-manager.service" + +DEPENDS = "boost \ + i2c-tools \ + sdbusplus" + +S = "${WORKDIR}/git/hsbp-manager" +inherit cmake systemd + +EXTRA_OECMAKE = "-DYOCTO=1" + diff --git a/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb new file mode 100644 index 000000000..086832b9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb @@ -0,0 +1,18 @@ +DESCRIPTION = "Image with Intel content based upon Phosphor, an OpenBMC framework." + +inherit obmc-phosphor-full-fitimage +inherit obmc-phosphor-image-common +inherit obmc-phosphor-image-dev +inherit ${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'image_types_intel_pfr', '', d)} + +DEPENDS += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'obmc-intel-pfr-image-native', '', d)}" +DEPENDS += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'pfr-manager', '', d)}" + +FEATURE_PACKAGES_obmc-sensors = "" +FEATURE_PACKAGES_obmc-debug-collector = "" + +fix_shadow_perms() { + chgrp shadow ${IMAGE_ROOTFS}${sysconfdir}/shadow + chmod u=rw,g+r ${IMAGE_ROOTFS}${sysconfdir}/shadow +} +ROOTFS_POSTPROCESS_COMMAND += "fix_shadow_perms ; " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py new file mode 100755 index 000000000..baa174349 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py @@ -0,0 +1,439 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# coding: utf-8 +# our image is contained as parts, including the hash +# then it gets zipped up and signed again + +# this internal signature is for boot and recovery, but +# will be checked prior to writing to flash as well. + +# the internal signature format is a PFR-specific block +# including a hash bitmap, certificates (public keys), +# and the actual signature data as well, for both active +# and recovery images + +# TODO: figure out if active and recovery actually have different sigs +# TODO: build hashmap from payload manifest +# TODO: figure out exact struct layout for PFR metadata +import os, hashlib, struct, json, sys, subprocess, mmap, io, array, binascii, copy, shutil, re, getopt +from array import array +from binascii import unhexlify +from hashlib import sha1, sha256, sha384, sha512 +from shutil import copyfile +# Flash Map +# ----------------------------------------------- +# Start addr Contents +# 0x00000000 S U-Boot +# 0x00080000 S+ PFM +# 0x000a0000 U U-boot Env +# 0x000C0000 U SOFS +# 0x002c0000 U RWFS +# 0x00b00000 S fit-image +# 0x02a00000 S+ rc-image +# 0x04a00000 U staging-image +# * partially signed (not full 64k page) +# + unsigned, owned by pfr + +# TODO: The below defines should go to manifest files. +# Keeping it here hard coded for now. +# The pages to be skipped for HASH and PBC +# Pages: 0x80 to 0x9f - starting PFM region until end of pfm +# Pages: 0x2a00 to 0x7FFF - starting RC-image until end of flash +EXCLUDE_PAGES =[[0x80, 0x9f],[0x2a00,0x7fff]] + +# SPI PFM globals +PFM_OFFSET = 0x80000 +PFM_SPI = 0x1 +PFM_I2C = 0x2 +PFM_DEF_SIZE = 32 # 32 bytes of PFM header +PFM_SPI_SIZE_DEF = 16 # 16 bytes of SPI PFM +PFM_I2C_SIZE = 40 # 40 bytes of i2c rules region in PFM +PAGE_SIZE = 0x1000 # 4KB size of page + +def load_manifest(fname): + manifest = {} + with open(fname, 'r') as fd: + manifest = json.load(fd) + return manifest + +class pfm_spi(object): + + def __init__(self, prot_mask, start_addr, end_addr, hash, hash_pres): + self.spi_pfm = PFM_SPI + self.spi_prot_mask = prot_mask + self.spi_hash_pres = hash_pres + print("hash_pres={}".format(self.spi_hash_pres)) + print("spi_hash={}".format(hash)) + print("spi_start_addr={}".format(start_addr)) + print("spi_end_addr={}".format(end_addr)) + if hash_pres != 0: + self.spi_hash = hash + self.spi_pfm_rsvd = 0xffffffff # b'\xff'*4 + self.spi_start_addr = start_addr + self.spi_end_addr = end_addr + +class pfm_i2c(object): + + def __init__(self, bus_id, rule_id, address, cmd_map): + self.i2c_pfm = PFM_I2C + self.i2c_pfm_rsvd = 0xffffffff # b'\xff'*4 + self.i2c_bus_id = bus_id + self.i2c_rule_id = rule_id + self.i2c_address = address + self.i2c_cmd_whitelist = cmd_map + +class pfr_bmc_image(object): + +# json_file, firmware_file + def __init__(self, manifest, firmware_file, build_ver, build_num, build_hash, sha, output_filename): + + self.manifest = load_manifest(manifest) + self.firmware_file = firmware_file + self.build_version = build_ver + self.build_number = build_num + self.build_hash = build_hash + self.sha = sha + if self.sha == "2": + self.sha_version = 0x2 + self.pfm_spi_size_hash = 48 + if self.sha == "1": + self.pfm_spi_size_hash = 32 + self.sha_version = 0x1 + self.pfr_rom_file = output_filename + open(self.pfr_rom_file, 'a').close() + + self.page_size = PAGE_SIZE + self.empty = b'\xff' * self.page_size + + self.image_parts = [] + for p in self.manifest['image-parts']: + # the json should have in the order- filename, index, offset, size and protection byte + self.image_parts.append((p['name'], p['index'], p['offset'], p['size'], p['prot_mask'], p['pfm'], p['hash'], p['compress'])) + if self.sha == "1": + self.act_dgst = hashlib.sha256() + if self.sha == "2": + self.act_dgst = hashlib.sha384() + # SPI regions PFM array + self.pfm_spi_regions = [] + self.pfm_bytes = PFM_DEF_SIZE # PFM definition bytes (SPI regions + SMBUS) + + # hash, erase and compression bit maps for 128MB + self.pbc_erase_bitmap = bytearray(4096) + self.pbc_comp_bitmap = bytearray(4096) + + self.pbc_comp_payload = 0 + self.sec_rev = 1 + + # fill in the calculated data + self.hash_and_map() + + self.i2c_rules = [] + for i in self.manifest['i2c-rules']: + # the json should have in the order- bus-id, rule-id, address, size and cmd-whitelist + self.i2c_rules.append((i['bus-id'], i['rule-id'], i['address'], i['cmd-whitelist'])) + + # I2C rules PFM array + self.pfm_i2c_rules = [] + + # Generate the i2c rules + self.build_i2c_rules() + + # Generate PFM region binary - pfm.bin + self.build_pfm() + print("PFM build done") + + # Generate PBC region - pbc.bin + self.pbc_hdr() + print("PBC build done") + + def hash_compress_regions(self, p, upd): + + # JSON format as below + # 0. "name": <image region name> + # 1. "index": 1, + # 2. "offset": <start addr>, + # 3. "size": <size of the region>, + # 4. "prot_mask": <PFR protection mask>, + # 5. "pfm": <1|0 -add in PFM or not>, + # 6. "hash": <hashing of the region needed>, + # 7. "compress": <region to be compressed> + + image_name = p[0] + start_addr = int(p[2],16) #image part start address + size = int(p[3],16) #size of the image part + pfm_prot_mask = p[4] # pfm protection mask + pfm_flag = p[5] # pfm needed? + hash_flag = p[6] #to be hashed? + compress = p[7] #compress flag + index = p[1] # image part index + # 1 page is 4KB + page = start_addr >> 12 + + with open(self.firmware_file, "rb") as f: + f.seek(start_addr) + skip = False + + if hash_flag == 1: + if self.sha == "1": + hash_dgst = hashlib.sha256() + if self.sha == "2": + hash_dgst = hashlib.sha384() + for chunk in iter(lambda: f.read(self.page_size), b''): + chunk_len = len(chunk) + if chunk_len != self.page_size: + chunk = b''.join([chunk, b'\xff' * (self.page_size - chunk_len)]) + + for p in EXCLUDE_PAGES: + if (page >= p[0]) and (page <= p[1]): + #print("Exclude page={}".format(page)) + skip = True + break + + if not skip: + # add to the hash + if hash_flag == 1: + # HASH for the region + self.act_dgst.update(chunk) + hash_dgst.update(chunk) + + if compress == 1: + self.pbc_erase_bitmap[page >> 3] |= 1 << (7- (page % 8)) # Big endian bit map + # add to the pbc map + if chunk != self.empty: + #print("compressed page ={}".format(page)) + upd.write(chunk) + self.pbc_comp_bitmap[page >> 3] |= 1 << (7- (page % 8)) # Big Endian bit map + self.pbc_comp_payload += chunk_len # compressed payload bytes + + page += 1 + + if (page * self.page_size) >= (size + start_addr): + break + + if pfm_flag == 1: + self.pfm_bytes += PFM_SPI_SIZE_DEF + + hash = bytearray(self.pfm_spi_size_hash) + hash_pres = 0 + + if hash_flag == 1: + # region's hash + hash = hash_dgst.hexdigest() + hash_pres = self.sha_version + self.pfm_bytes += self.pfm_spi_size_hash + # append to SPI regions in PFM + self.pfm_spi_regions.append(pfm_spi(pfm_prot_mask, start_addr, (start_addr+size), hash, hash_pres)) + + def add_i2c_rules(self, i): + bus_id = i[0] # I2C Bus number + rule_id = i[1] # I2C rule number + addr = i[2] # I2C device address + cmds = i[3] # I2C white listed commands for which i2c write to be allowed + whitelist_map = bytearray(32) + + self.pfm_bytes += PFM_I2C_SIZE # add upto PFM size + + for c in cmds: + if c == "all": + for i in range(32): + whitelist_map[i] = 0xff + break + else: + idx = int(c,16) // 8 # index in the 32 bytes of white list i2c cmds + bit = int(c,16) % 8 # bit position to set + whitelist_map[idx] |= (1 << bit) + + # append to I2C rules in PFM + self.pfm_i2c_rules.append(pfm_i2c(bus_id, rule_id, addr, whitelist_map)) + + def build_i2c_rules(self): + for i in self.i2c_rules: + self.add_i2c_rules(i) + + def hash_and_map(self): + + # have copy of the update file for appending with PFR meta and compression + copyfile(self.firmware_file, self.pfr_rom_file) + with open("bmc_compressed.bin", "wb+") as upd: + for p in self.image_parts: + #filename, index, offset, size, protection. + print(p[0], p[1], p[2], p[3], p[4]) + self.hash_compress_regions(p, upd) + + def pbc_hdr(self): + ''' + typedef struct { + uint8_t tag[4]; /* PBC tag */ + uint32_t version; /* PBC Version- 0x0000_0002 */ + uint32_t page_size; /* NOR Flash page size = 0x0000_1000 */ + uint32_t pattern_size; /* 0xFF as pattern 1byte = 0x0000_0001 */ + uint32_t pattern; /* 0xFF pattern = 0x0000_00FF */ + uint32_t bitmap_size; /* 32768 pages for 128MB- 0x0000_8000 */ + uint32_t payload_length /* payload */ + uint8_t reserved[100]; /* Reserved 100bytes */ + uint8_t erase_bitmap[4096]; /* erase bit map for 32768 pages */ + uint8_t comp_bitmap[4096]; /* compression bit map for 32768 pages */ + uint8_t comp_payload; /* compressed payload */ + ''' + names = [ + 'tag', 'pbc_ver', 'page_sz', 'pattern_sz', 'pattern', 'bitmap_sz', + 'payload_size', 'resvd0', 'erase_bitmap', 'comp_bitmap', + ] + parts = { + 'tag': b'CBP_', + 'pbc_ver': struct.pack('<i',0x00000002), + 'page_sz': struct.pack('<i',0x00001000), + 'pattern_sz': struct.pack('<i',0x00000001), + 'pattern': struct.pack('<i',0x000000FF), + 'bitmap_sz': struct.pack('<i',0x00008000), + 'payload_size': struct.pack('<i',self.pbc_comp_payload), + 'resvd0' : b'\x00'*100, + 'erase_bitmap': bytes(self.pbc_erase_bitmap), + 'comp_bitmap': bytes(self.pbc_comp_bitmap), + } + + with open("pbc.bin", "wb+") as pbf: + pbf.write(b''.join([parts[n] for n in names])) + pbf.seek(0) # rewind to beginning of PBC file + self.act_dgst.update(pbf.read()) # add up PBC data for hashing + + def build_pfm(self): + ''' + typedef struct { + uint32_t tag; /* PFM_HDR_TAG above, no terminating null */ + uint8_t SVN; /* SVN- security revision of associated image data */ + uint8_t bkc; /* bkc */ + uint8_t pfm_ver_major; /* PFM revision */ + uint8_t pfm_ver_minor; + uint8_t reserved0[4]; + uint8_t build_num; + uint8_t build_hash[3]; + uint8_t reserved1[12]; /* reserved */ + uint32_t pfm_length; /* PFM size in bytes */ + pfm_spi pfm_spi[2]; /* PFM SPI regions - u-boot & fit-image */ + pfm_smbus pfm_smbus[4]; /* defined smbus rules for PSUs and HSBP */ + } __attribute__((packed)) pfm_hdr; + ''' + names = [ + 'tag', 'sec_rev', 'bkc', 'pfm_ver_major', 'pfm_ver_minor', 'resvd0', 'build_num', 'build_hash1', 'build_hash2', 'build_hash3', 'resvd1', 'pfm_len', + ] + parts = { + 'tag': struct.pack("<I", 0x02b3ce1d), + 'sec_rev': struct.pack('<B', self.sec_rev), + 'bkc': struct.pack('<B', 0x01), + 'pfm_ver_major': struct.pack('<B', ((int(self.build_version) >> 8) & 0xff)), + 'pfm_ver_minor': struct.pack('<B', (int(self.build_version) & 0x00ff)), + 'resvd0': b'\xff'* 4, + 'build_num': struct.pack('<B', int(self.build_number,16)), + 'build_hash1': struct.pack('<B', (int(self.build_hash) & 0xff)), + 'build_hash2': struct.pack('<B', ((int(self.build_hash) >> 8) & 0xff)), + 'build_hash3': struct.pack('<B', ((int(self.build_hash) >> 16) & 0xff)), + 'resvd1': b'\xff'* 12, + 'pfm_len': '' + } + + # PFM should be 128bytes aligned, find the padding bytes + padding_bytes = 0 + if (self.pfm_bytes % 128) != 0: + padding_bytes = 128 - (self.pfm_bytes % 128) + + print("padding={}".format(padding_bytes)) + print("PFM size1={}".format(self.pfm_bytes)) + self.pfm_bytes += padding_bytes + parts['pfm_len'] = struct.pack('<I', self.pfm_bytes) + print("PFM size2={}".format(self.pfm_bytes)) + + with open("pfm.bin", "wb+") as f: + f.write(b''.join([parts[n] for n in names])) + for i in self.pfm_spi_regions: + f.write(struct.pack('<B', int(i.spi_pfm))) + f.write(struct.pack('<B', int(i.spi_prot_mask))) + f.write(struct.pack('<h', int(i.spi_hash_pres))) + f.write(struct.pack('<I', int(i.spi_pfm_rsvd))) + f.write(struct.pack('<I', int(i.spi_start_addr))) + f.write(struct.pack('<I', int(i.spi_end_addr))) + + if i.spi_hash_pres != 0: + f.write(bytearray.fromhex(i.spi_hash)) + + for r in self.pfm_i2c_rules: + f.write(struct.pack('<B', int(r.i2c_pfm))) + f.write(struct.pack('<I', int(r.i2c_pfm_rsvd))) + f.write(struct.pack('<B', int(r.i2c_bus_id))) + f.write(struct.pack('<B', int(r.i2c_rule_id))) + f.write(struct.pack('<B', int(r.i2c_address, 16))) + f.write(r.i2c_cmd_whitelist) + + # write the padding bytes at the end + f.write(b'\xff' * padding_bytes) + +def usage(prog): + sys.stderr.write(prog + + " -m manifest -i rom-image -n build_version -b build_number -h build_hash -s sha -o output_file_name\n") + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "m:i:n:b:h:s:o:", + ["manifest=", "image=", "build_version=","build_number=","build_hash=","sha=", "output_file_name="]) + except getopt.GetoptError as err: + sys.stderr.write(str(err) + "\n") + sys.exit(2) + json_file = None + firmware_file = None + build_ver = None + build_num = None + build_hash = None + sha = None + output_filename = None + + for o, a in opts: + if o in ("-m", "--manifest"): + json_file = a + elif o in ("-i", "--image"): + firmware_file = a + elif o in ("-n", "--build_version"): + build_ver = a + elif o in ("-b", "--build_number"): + build_num = a + elif o in ("-h", "--build_hash"): + build_hash = a + elif o in ("-s", "--sha"): + sha = a + elif o in ("-o", "--output_file_name"): + output_filename = a + else: + usage(sys.argv[0]) + assert False, "unhandled argument: " + o + + if json_file is None or firmware_file is None or build_ver is None or build_num is None or build_hash is None or sha is None or output_filename is None: + usage(sys.argv[0]) + sys.exit(-1) + + print("manifest: %s" % json_file) + print("image: %s" % firmware_file) + print("build_ver: %s" % build_ver) + print("build_number: %s" % build_num) + print("build_hash: %s" % build_hash) + print("Sha: %s" % sha) + print("output_filename: %s" % output_filename) + + + # function to generate BMC PFM, PBC header and BMC compressed image + pfr_bmc_image(json_file, firmware_file, build_ver, build_num, build_hash, sha ,output_filename) + +if __name__ == '__main__': + main() diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb new file mode 100644 index 000000000..95ecf30fc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb @@ -0,0 +1,20 @@ +SUMMARY = "Intel Blocksign tool for PFR image" +DESCRIPTION = "Image signing tool for BMC PFR image" + +inherit cmake native + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +DEPENDS = "openssl-native libxml2-native " + +SRC_URI = "git://git@github.com/Intel-BMC/blocksign;protocol=ssh" + +SRCREV = "966d16f680c1b14c338640d35a12d5e2f9a6937a" + +S = "${WORKDIR}/git" + +do_install_append() { + install -d ${D}/${bindir} + install -m 775 ${B}/blocksign ${D}/${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb new file mode 100644 index 000000000..bb0f9ba7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb @@ -0,0 +1,23 @@ +SUMMARY = "Intel PFR image manifest and image signing keys" +DESCRIPTION = "This copies PFR image generation scripts and image signing keys to staging area" + +PR = "r1" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +inherit native + +DEPENDS += " intel-blocksign-native" + +SRC_URI = " \ + file://pfr_image.py \ + " + +do_install () { + bbplain "Copying intel pfr image generation scripts and image signing keys" + + install -d ${D}${bindir} + install -d ${D}/${datadir}/pfrconfig + install -m 775 ${WORKDIR}/pfr_image.py ${D}${bindir}/pfr_image.py +} + 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 new file mode 100644 index 000000000..f89a2fbb0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/pfr-manager_%.bbappend @@ -0,0 +1,5 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/pfr-manager" +SRCREV = "2dfaf507da581ed4c71d41c02976e4efafc1d634" +DEPENDS += " libgpiod \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb new file mode 100644 index 000000000..50c8bd63e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb @@ -0,0 +1,24 @@ +SUMMARY = "One time automatically enable every NIC" +DESCRIPTION = "Re-enable NIC accidentally disabled by earlier BMC firmware." + +S = "${WORKDIR}" +SRC_URI = "file://enable-nics.sh \ + file://enable-nics.service \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/enable-nics.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/enable-nics.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/enable-nics.sh ${D}/${bindir}/enable-nics.sh +} + +SYSTEMD_SERVICE_${PN} += " enable-nics.service" 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 new file mode 100644 index 000000000..c1d0f602f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service @@ -0,0 +1,10 @@ +[Unit] +Description=Re-enable NICs mistakenly disabled by earlier BMC firmware +Wants=multi-user.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/enable-nics.sh + +[Install] +WantedBy=network.target diff --git a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh new file mode 100755 index 000000000..ce1473be1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +SEMAPHORE_FILE=/var/cache/private/nic_fixup_complete + +if [ -a $SEMAPHORE_FILE ]; then + exit 0 +fi + +for nicFile in /etc/systemd/network/*.network +do + sed -i -e"/Unmanaged/d" $nicFile +done + +touch $SEMAPHORE_FILE diff --git a/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb new file mode 100644 index 000000000..4d91ac673 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb @@ -0,0 +1,38 @@ +SUMMARY = "OpenBMC for Intel - Applications" +PR = "r1" + +inherit packagegroup + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES = "${PACKAGES}" +PACKAGES = " \ + ${PN}-chassis \ + ${PN}-fans \ + ${PN}-flash \ + ${PN}-system \ + " + +PROVIDES += "virtual/obmc-chassis-mgmt" +PROVIDES += "virtual/obmc-fan-mgmt" +PROVIDES += "virtual/obmc-flash-mgmt" +PROVIDES += "virtual/obmc-system-mgmt" + +RPROVIDES_${PN}-chassis += "virtual-obmc-chassis-mgmt" +RPROVIDES_${PN}-fans += "virtual-obmc-fan-mgmt" +RPROVIDES_${PN}-flash += "virtual-obmc-flash-mgmt" +RPROVIDES_${PN}-system += "virtual-obmc-system-mgmt" + +SUMMARY_${PN}-chassis = "Intel Chassis" +RDEPENDS_${PN}-chassis = " \ + x86-power-control \ + " + +SUMMARY_${PN}-fans = "Intel Fans" +RDEPENDS_${PN}-fans = " \ + phosphor-pid-control \ + " + +SUMMARY_${PN}-flash = "Intel Flash" +RDEPENDS_${PN}-flash = "" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend new file mode 100644 index 000000000..7d61ea5c7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend @@ -0,0 +1,7 @@ +RDEPENDS_${PN}-extrasdevtools = "libgpiod-tools" +RDEPENDS_${PN}-chassis-state-mgmt_remove = "obmc-phosphor-power" +RDEPENDS_${PN}-devtools_remove = "ffdc" + +PACKAGES_remove = "${PN}-debug-collector" + +RDEPENDS_${PN}-settings = "settings" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb b/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb new file mode 100644 index 000000000..482738d25 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb @@ -0,0 +1,26 @@ +SUMMARY = "Power supply manager for Intel based platform" +DESCRIPTION = "Power supply manager which include PSU Cold Redundancy service" + +SRC_URI = "git://github.com/Intel-BMC/psu-manager.git;protocol=ssh" +SRCREV = "d14c350c2dfcf9da3e6088ef29a8c5be4e40079b" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake +inherit systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.coldredundancy.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + boost \ + i2c-tools \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb new file mode 100644 index 000000000..34352acef --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb @@ -0,0 +1,31 @@ +SUMMARY = "SMBIOS MDR version 1 service for Intel based platform" +DESCRIPTION = "SMBIOS MDR version 1 service for Intel based platfrom" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh;nobranch=1" +SRCREV = "6aab8bcc8fd0550753c87265036b1b7c4c8a9f71" + +S = "${WORKDIR}/git/services/smbios" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake pkgconfig +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "smbios-mdrv1.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service new file mode 100644 index 000000000..edfd3bf70 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service @@ -0,0 +1,13 @@ +[Unit] +Description=Intel BMC SMBIOS MDR V1 + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStartPre=/bin/mkdir -p /etc/smbios +ExecStart=/usr/bin/env smbiosapp +SyslogIdentifier=smbiosapp + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb new file mode 100644 index 000000000..fa591872a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb @@ -0,0 +1,34 @@ +SUMMARY = "SMBIOS MDR version 2 service for Intel based platform" +DESCRIPTION = "SMBIOS MDR version 2 service for Intel based platfrom" + +SRC_URI = "git://github.com/openbmc/smbios-mdr.git" +SRCREV = "2285be4fd22709c1dcfba10c2c604528353b428a" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake pkgconfig +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "smbios-mdrv2.service" +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.cpuinfo.service" + +DEPENDS += " \ + autoconf-archive-native \ + boost \ + systemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + libpeci \ + i2c-tools \ + " + +EXTRA_OECMAKE="-DYOCTO=1" + +PACKAGECONFIG ??= "${@bb.utils.filter('DISTRO_FEATURES', 'smbios-no-dimm', d)}" +PACKAGECONFIG[smbios-no-dimm] = "-DDIMM_DBUS=OFF, -DDIMM_DBUS=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-peci-Add-debug-printing-to-check-caller-PID.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-peci-Add-debug-printing-to-check-caller-PID.patch new file mode 100644 index 000000000..fbd51df7a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-peci-Add-debug-printing-to-check-caller-PID.patch @@ -0,0 +1,43 @@ +From 7474fe190f770e064a5ce5e939bd713ce2aa1de5 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 3 Feb 2021 16:18:37 -0800 +Subject: [PATCH] peci: Add debug printing to check caller PID + +This commit adds debug printing out to check caller PID for traffic +profiling. + +The printing can be enabled by this command: +echo -n 'file drivers/peci/peci-core.c line 218 +p' > /sys/kernel/debug/dynamic_debug/control +echo '8' > /proc/sys/kernel/printk + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/peci/peci-core.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index 10375e6087a5..02c8502fd846 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -194,6 +194,7 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + bool do_retry, bool has_aw_fcs) + { + uint interval_us = PECI_DEV_RETRY_INTERVAL_MIN_USEC; ++ char task_name[TASK_COMM_LEN]; + ulong timeout = jiffies; + u8 aw_fcs; + int ret; +@@ -214,6 +215,10 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + } + } + ++ get_task_comm(task_name, current); ++ dev_dbg(&adapter->dev, "%s is called by %s(%d) through %s\n", ++ __func__, task_name, current->pid, adapter->name); ++ + /* + * For some commands, the PECI originator may need to retry a command if + * the processor PECI client responds with a 0x8x completion code. In +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-soc-aspeed-add-AST2600-A0-specific-fix-into-mbox-dri.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-soc-aspeed-add-AST2600-A0-specific-fix-into-mbox-dri.patch new file mode 100644 index 000000000..1e1dac7a8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-soc-aspeed-add-AST2600-A0-specific-fix-into-mbox-dri.patch @@ -0,0 +1,42 @@ +From ae96ce5f2a5bd76b234cea6fc3f0bf1df74387f3 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 4 Feb 2021 00:29:55 -0800 +Subject: [PATCH] soc: aspeed: add AST2600 A0 specific fix into mbox driver + +AST2600 A0 has the same LPC mbox register structure with AST2500 +but AST2600 A1 and later revision is different so this commit adds +AST2600 A0 specific fix into the mbox driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/soc/aspeed/aspeed-lpc-mbox.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/soc/aspeed/aspeed-lpc-mbox.c b/drivers/soc/aspeed/aspeed-lpc-mbox.c +index 8dd3345682c7..12bb436dda78 100644 +--- a/drivers/soc/aspeed/aspeed-lpc-mbox.c ++++ b/drivers/soc/aspeed/aspeed-lpc-mbox.c +@@ -363,6 +363,20 @@ static int aspeed_mbox_probe(struct platform_device *pdev) + return -EINVAL; + + config = match->data; ++ ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2600-mbox")) { ++ #define REV_ID_IO_OFFSET 0x1e6e2014 ++ #define REV_ID_AST2600A0 0x05000303 ++ void __iomem *chip_id_base = devm_ioremap(&pdev->dev, ++ REV_ID_IO_OFFSET, ++ sizeof(u32)); ++ ++ if (!IS_ERR(chip_id_base) && ++ readl(chip_id_base) == REV_ID_AST2600A0) ++ config = &ast2500_config; ++ } ++ + memcpy(&mbox->configs, config, sizeof(mbox->configs)); + + rc = of_property_read_u32(dev->of_node, "reg", &mbox->base); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Fix-libmctp-build-error.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Fix-libmctp-build-error.patch new file mode 100644 index 000000000..b9a6ca527 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Fix-libmctp-build-error.patch @@ -0,0 +1,116 @@ +From af414e45bade3cf7277215d82b59a31c9b459cea Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 22 Feb 2021 15:27:22 -0800 +Subject: [PATCH] Fix libmctp build error + +This is a quick fix for libmctp building which includes staging +kernel headers. It's a temporary fix until kernel tree fixes the +rwonce.h including issue. + +Note: Do not upstream it. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + include/asm/rwonce.h | 90 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 90 insertions(+) + create mode 100644 include/asm/rwonce.h + +diff --git a/include/asm/rwonce.h b/include/asm/rwonce.h +new file mode 100644 +index 000000000000..11619bdbebae +--- /dev/null ++++ b/include/asm/rwonce.h +@@ -0,0 +1,90 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Prevent the compiler from merging or refetching reads or writes. The ++ * compiler is also forbidden from reordering successive instances of ++ * READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some ++ * particular ordering. One way to make the compiler aware of ordering is to ++ * put the two invocations of READ_ONCE or WRITE_ONCE in different C ++ * statements. ++ * ++ * These two macros will also work on aggregate data types like structs or ++ * unions. ++ * ++ * Their two major use cases are: (1) Mediating communication between ++ * process-level code and irq/NMI handlers, all running on the same CPU, ++ * and (2) Ensuring that the compiler does not fold, spindle, or otherwise ++ * mutilate accesses that either do not require ordering or that interact ++ * with an explicit memory barrier or atomic instruction that provides the ++ * required ordering. ++ */ ++#ifndef __ASM_GENERIC_RWONCE_H ++#define __ASM_GENERIC_RWONCE_H ++ ++#ifndef __ASSEMBLY__ ++ ++#include <linux/compiler_types.h> ++#include <linux/kasan-checks.h> ++#include <linux/kcsan-checks.h> ++ ++/* ++ * Yes, this permits 64-bit accesses on 32-bit architectures. These will ++ * actually be atomic in some cases (namely Armv7 + LPAE), but for others we ++ * rely on the access being split into 2x32-bit accesses for a 32-bit quantity ++ * (e.g. a virtual address) and a strong prevailing wind. ++ */ ++#define compiletime_assert_rwonce_type(t) \ ++ compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \ ++ "Unsupported access size for {READ,WRITE}_ONCE().") ++ ++/* ++ * Use __READ_ONCE() instead of READ_ONCE() if you do not require any ++ * atomicity. Note that this may result in tears! ++ */ ++#ifndef __READ_ONCE ++#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x)) ++#endif ++ ++#define READ_ONCE(x) \ ++({ \ ++ compiletime_assert_rwonce_type(x); \ ++ __READ_ONCE(x); \ ++}) ++ ++#define __WRITE_ONCE(x, val) \ ++do { \ ++ *(volatile typeof(x) *)&(x) = (val); \ ++} while (0) ++ ++#define WRITE_ONCE(x, val) \ ++do { \ ++ compiletime_assert_rwonce_type(x); \ ++ __WRITE_ONCE(x, val); \ ++} while (0) ++ ++static __always_inline ++unsigned long __read_once_word_nocheck(const void *addr) ++{ ++ return __READ_ONCE(*(unsigned long *)addr); ++} ++ ++/* ++ * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need to load a ++ * word from memory atomically but without telling KASAN/KCSAN. This is ++ * usually used by unwinding code when walking the stack of a running process. ++ */ ++#define READ_ONCE_NOCHECK(x) \ ++({ \ ++ compiletime_assert(sizeof(x) == sizeof(unsigned long), \ ++ "Unsupported access size for READ_ONCE_NOCHECK()."); \ ++ (typeof(x))__read_once_word_nocheck(&(x)); \ ++}) ++ ++static __always_inline ++unsigned long read_word_at_a_time(const void *addr) ++{ ++ kasan_check_read(addr, 1); ++ return *(unsigned long *)addr; ++} ++ ++#endif /* __ASSEMBLY__ */ ++#endif /* __ASM_GENERIC_RWONCE_H */ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0004-Add-a-quick-fix-to-resolve-USB-gadget-DMA-issue.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0004-Add-a-quick-fix-to-resolve-USB-gadget-DMA-issue.patch new file mode 100644 index 000000000..2d435c796 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0004-Add-a-quick-fix-to-resolve-USB-gadget-DMA-issue.patch @@ -0,0 +1,33 @@ +From cdd7104850d34cfe22902c45d69dac6cb506b087 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 26 Feb 2021 11:00:54 -0800 +Subject: [PATCH] Add a quick fix to resolve USB gadget DMA issue. + +This is a quick fix to resolve USB gadget DMA issue and it should +be removed when a real fix is added. + +Tested: Keyboard and mouse in KVM feature worked. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + kernel/dma/mapping.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c +index 51bb8fa8eb89..7bcfedeb1e30 100644 +--- a/kernel/dma/mapping.c ++++ b/kernel/dma/mapping.c +@@ -146,8 +146,10 @@ dma_addr_t dma_map_page_attrs(struct device *dev, struct page *page, + + BUG_ON(!valid_dma_direction(dir)); + ++#if 0 /* Quick fix to resolve USB gadget issue */ + if (WARN_ON_ONCE(!dev->dma_mask)) + return DMA_MAPPING_ERROR; ++#endif + + if (dma_map_direct(dev, ops)) + addr = dma_direct_map_page(dev, page, offset, size, dir, attrs); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch new file mode 100755 index 000000000..7dd9990a9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch @@ -0,0 +1,45 @@ +From ca0fa975d066b15637188e8fe37dd6d12e0e2bc4 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 28 Apr 2020 22:32:41 +0800 +Subject: [PATCH] Selecting 128MB for PFR + +PFR platforms requires 128MB flash mapping. +This will override the existing 64MB flash map +and loads 128MB flash map. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 2 +- + arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +index 13b94bdf5d62..2cab5fb38d4f 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +@@ -96,7 +96,7 @@ + flash@0 { + status = "okay"; + m25p,fast-read; +-#include "openbmc-flash-layout-intel-64MB.dtsi" ++#include "openbmc-flash-layout-intel-128MB.dtsi" + }; + }; + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts +index a95b5ac828b3..bf66e1b6c0fd 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts +@@ -94,7 +94,7 @@ + spi-max-frequency = <40000000>; + spi-tx-bus-width = <4>; + m25p,fast-read; +-#include "openbmc-flash-layout-intel-64MB.dtsi" ++#include "openbmc-flash-layout-intel-128MB.dtsi" + }; + }; + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg new file mode 100644 index 000000000..bbc7fa5b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg @@ -0,0 +1,2 @@ +CONFIG_DEVMEM = y +CONFIG_DEVMEM_BOOTPARAM = n diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg new file mode 100644 index 000000000..21bfcf792 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg @@ -0,0 +1,93 @@ +CONFIG_BLK_DEV_RAM=y +CONFIG_HWMON=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_IIO=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_ASPEED_ADC=y +CONFIG_SGPIO_ASPEED=y +CONFIG_CRC8=y +CONFIG_PECI=y +CONFIG_PECI_CHARDEV=y +CONFIG_PECI_ASPEED=y +CONFIG_SENSORS_PECI_CPUTEMP=y +CONFIG_SENSORS_PECI_DIMMTEMP=y +CONFIG_SENSORS_PECI_CPUPOWER=y +CONFIG_SENSORS_PECI_DIMMPOWER=y +CONFIG_SENSORS_PECI_PLATFORMPOWER=y +CONFIG_CONFIGFS_FS=y +CONFIG_BLK_DEV_RAM_SIZE=49152 +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_ASPEED_ESPI_SLAVE=y +CONFIG_ASPEED_KCS_IPMI_BMC=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_MQUEUE=y +CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE=256 +CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE=32 +CONFIG_ASPEED_BT_IPMI_BMC=n +CONFIG_ASPEED_LPC_CTRL=n +CONFIG_ASPEED_LPC_MBOX=y +CONFIG_ASPEED_LPC_SIO=y +CONFIG_JTAG=y +CONFIG_JTAG_ASPEED=y +CONFIG_FRAME_VECTOR=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_ASPEED=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_V4L2=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_HID=y +CONFIG_USB_GADGET=y +CONFIG_U_SERIAL_CONSOLE=y +CONFIG_USB_ASPEED_VHUB=y +CONFIG_USB_MASS_STORAGE=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_ASPEED_UART_ROUTING=y +CONFIG_ASPEED_VGA_SHAREDMEM=y +CONFIG_PWM=y +CONFIG_PWM_FTTMR010=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PWM_BEEPER=y +CONFIG_VFAT_FS=y +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_UTF8=y +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_CIFS=y +CONFIG_CIFS_XATTR=y +CONFIG_PSTORE=y +CONFIG_PSTORE_ZLIB_COMPRESS=y +CONFIG_PSTORE_RAM=y +CONFIG_FSI=n +CONFIG_FSI_MASTER_HUB=n +CONFIG_FSI_MASTER_ASPEED=n +CONFIG_FSI_SCOM=n +CONFIG_FSI_SBEFIFO=n +CONFIG_FSI_OCC=n +CONFIG_ASPEED_P2A_CTRL=n +CONFIG_USB=n +CONFIG_USB_ANNOUNCE_NEW_DEVICES=n +CONFIG_USB_DYNAMIC_MINORS=n +CONFIG_USB_EHCI_HCD=n +CONFIG_USB_EHCI_ROOT_HUB_TT=n +CONFIG_USB_EHCI_HCD_PLATFORM=n +CONFIG_IPMB_DEVICE_INTERFACE=y +CONFIG_BPF_SYSCALL=n +CONFIG_IPV6_SIT=n 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 new file mode 100644 index 000000000..591e86160 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -0,0 +1,23 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +KBRANCH = "dev-5.10-intel" +KSRC = "git://github.com/Intel-BMC/linux;protocol=ssh;branch=${KBRANCH}" +# Include this as a comment only for downstream auto-bump +# SRC_URI = "git://github.com/Intel-BMC/linux;protocol=ssh;branch=dev-5.10-intel" +SRCREV="faadf371d041eb0d2c8b1d4cc729f19cf53e6a92" + +do_compile_prepend(){ + # device tree compiler flags + export DTC_FLAGS=-@ +} + +SRC_URI += " \ + file://intel.cfg \ + file://0001-peci-Add-debug-printing-to-check-caller-PID.patch \ + file://0002-soc-aspeed-add-AST2600-A0-specific-fix-into-mbox-dri.patch \ + file://0003-Fix-libmctp-build-error.patch \ + file://0004-Add-a-quick-fix-to-resolve-USB-gadget-DMA-issue.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-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch new file mode 100644 index 000000000..6bfe783af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch @@ -0,0 +1,411 @@ +From 07bba51a168b769563a649f1c0f3a9126f480e57 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Thu, 2 Apr 2020 17:06:07 +0530 +Subject: [PATCH] Adding channel specific privilege to network + + - Adding the channel access information to the network + interface object. This privilege will be used in + channel specific authorization. + - Get supported priv from user manager service dynamically. + - Signal handling for capturing the supported priv list + changes from user managerment. + +Tested-by: +Verified channel access through ipmitool get/set channel +access command + +Change-Id: I3b592a19363eef684e31d5f7c34dad8f2f9211df +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + ethernet_interface.cpp | 124 +++++++++++++++++++++++++++++++++++++++++ + ethernet_interface.hpp | 37 +++++++++++- + network_manager.cpp | 102 +++++++++++++++++++++++++++++++++ + network_manager.hpp | 9 +++ + 4 files changed, 271 insertions(+), 1 deletion(-) + +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index c47a759..d7a4168 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -45,6 +45,10 @@ constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; + constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/"; + constexpr auto METHOD_GET = "Get"; + ++static constexpr const char* networkChannelCfgFile = ++ "/var/channel_intf_data.json"; ++static constexpr const char* defaultChannelPriv = "priv-admin"; ++ + struct EthernetIntfSocket + { + EthernetIntfSocket(int domain, int type, int protocol) +@@ -128,6 +132,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); + #endif ++ getChannelPrivilege(intfName); + + // Emit deferred signal. + if (emitSignal) +@@ -1148,5 +1153,124 @@ std::string EthernetInterface::defaultGateway6(std::string gateway) + manager.writeToConfigurationFile(); + return gw; + } ++ ++nlohmann::json EthernetInterface::readJsonFile(const std::string& configFile) ++{ ++ std::ifstream jsonFile(configFile); ++ if (!jsonFile.good()) ++ { ++ log<level::ERR>("JSON file not found"); ++ return nullptr; ++ } ++ ++ nlohmann::json data = nullptr; ++ try ++ { ++ data = nlohmann::json::parse(jsonFile, nullptr, false); ++ } ++ catch (nlohmann::json::parse_error& e) ++ { ++ log<level::DEBUG>("Corrupted channel config.", ++ entry("MSG: %s", e.what())); ++ throw std::runtime_error("Corrupted channel config file"); ++ } ++ ++ return data; ++} ++ ++int EthernetInterface::writeJsonFile(const std::string& configFile, ++ const nlohmann::json& jsonData) ++{ ++ std::ofstream jsonFile(configFile); ++ if (!jsonFile.good()) ++ { ++ log<level::ERR>("JSON file open failed", ++ entry("FILE=%s", networkChannelCfgFile)); ++ return -1; ++ } ++ ++ // Write JSON to file ++ jsonFile << jsonData; ++ ++ jsonFile.flush(); ++ return 0; ++} ++ ++std::string ++ EthernetInterface::getChannelPrivilege(const std::string& interfaceName) ++{ ++ std::string priv(defaultChannelPriv); ++ std::string retPriv; ++ ++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile); ++ if (jsonData != nullptr) ++ { ++ try ++ { ++ priv = jsonData[interfaceName].get<std::string>(); ++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv)); ++ return retPriv; ++ } ++ catch (const nlohmann::json::exception& e) ++ { ++ jsonData[interfaceName] = priv; ++ } ++ } ++ else ++ { ++ jsonData[interfaceName] = priv; ++ } ++ ++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0) ++ { ++ log<level::DEBUG>("Error in write JSON data to file", ++ entry("FILE=%s", networkChannelCfgFile)); ++ elog<InternalFailure>(); ++ } ++ ++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv)); ++ ++ return retPriv; ++} ++ ++std::string EthernetInterface::maxPrivilege(std::string priv) ++{ ++ std::string intfName = interfaceName(); ++ ++ if (manager.supportedPrivList.empty()) ++ { ++ // Populate the supported privilege list ++ manager.initSupportedPrivilges(); ++ } ++ ++ if (!priv.empty() && (std::find(manager.supportedPrivList.begin(), ++ manager.supportedPrivList.end(), ++ priv) == manager.supportedPrivList.end())) ++ { ++ log<level::ERR>("Invalid privilege"); ++ elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"), ++ Argument::ARGUMENT_VALUE(priv.c_str())); ++ } ++ ++ if (ChannelAccessIntf::maxPrivilege() == priv) ++ { ++ // No change in privilege so just return. ++ return priv; ++ } ++ ++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile); ++ jsonData[intfName] = priv; ++ ++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0) ++ { ++ log<level::DEBUG>("Error in write JSON data to file", ++ entry("FILE=%s", networkChannelCfgFile)); ++ elog<InternalFailure>(); ++ } ++ ++ // Property change signal will be sent ++ return ChannelAccessIntf::maxPrivilege(std::move(priv)); ++} ++ + } // namespace network + } // namespace phosphor +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index e2418a2..60fd272 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -2,11 +2,14 @@ + + #include "types.hpp" + #include "util.hpp" ++#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp" + #include "xyz/openbmc_project/Network/IP/Create/server.hpp" + #include "xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp" + + #include <filesystem> ++#include <nlohmann/json.hpp> + #include <sdbusplus/bus.hpp> ++#include <sdbusplus/bus/match.hpp> + #include <sdbusplus/server/object.hpp> + #include <string> + #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp> +@@ -23,7 +26,8 @@ using Ifaces = sdbusplus::server::object::object< + sdbusplus::xyz::openbmc_project::Network::server::MACAddress, + sdbusplus::xyz::openbmc_project::Network::IP::server::Create, + sdbusplus::xyz::openbmc_project::Network::Neighbor::server::CreateStatic, +- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>; ++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll, ++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess>; + + using IP = sdbusplus::xyz::openbmc_project::Network::server::IP; + +@@ -31,11 +35,14 @@ using EthernetInterfaceIntf = + sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; + using MacAddressIntf = + sdbusplus::xyz::openbmc_project::Network::server::MACAddress; ++using ChannelAccessIntf = ++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess; + + using ServerList = std::vector<std::string>; + using ObjectPath = sdbusplus::message::object_path; + + namespace fs = std::filesystem; ++using DbusVariant = std::variant<std::string, std::vector<std::string>>; + + class Manager; // forward declaration of network manager. + +@@ -233,6 +240,14 @@ class EthernetInterface : public Ifaces + */ + std::string defaultGateway6(std::string gateway) override; + ++ /** @brief sets the channel maxium privilege. ++ * @param[in] value - Channel privilege which needs to be set on the ++ * system. ++ * @returns privilege of the interface or throws an error. ++ */ ++ std::string maxPrivilege(std::string value) override; ++ ++ using ChannelAccessIntf::maxPrivilege; + using EthernetInterfaceIntf::dHCPEnabled; + using EthernetInterfaceIntf::interfaceName; + using EthernetInterfaceIntf::linkUp; +@@ -356,6 +371,26 @@ class EthernetInterface : public Ifaces + * @returns true/false value if the address is static + */ + bool originIsManuallyAssigned(IP::AddressOrigin origin); ++ ++ /** @brief gets the channel privilege. ++ * @param[in] interfaceName - Network interface name. ++ * @returns privilege of the interface ++ */ ++ std::string getChannelPrivilege(const std::string& interfaceName); ++ ++ /** @brief reads the channel access info from file. ++ * @param[in] configFile - channel access filename ++ * @returns json file data ++ */ ++ nlohmann::json readJsonFile(const std::string& configFile); ++ ++ /** @brief writes the channel access info to file. ++ * @param[in] configFile - channel access filename ++ * @param[in] jsonData - json data to write ++ * @returns success or failure ++ */ ++ int writeJsonFile(const std::string& configFile, ++ const nlohmann::json& jsonData); + }; + + } // namespace network +diff --git a/network_manager.cpp b/network_manager.cpp +index c55c9bb..50ff908 100644 +--- a/network_manager.cpp ++++ b/network_manager.cpp +@@ -36,6 +36,13 @@ extern std::unique_ptr<Timer> restartTimer; + using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + ++static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user"; ++static constexpr const char* userMgrInterface = ++ "xyz.openbmc_project.User.Manager"; ++static constexpr const char* propNameAllPrivileges = "AllPrivileges"; ++ ++std::unique_ptr<sdbusplus::bus::match_t> usrMgmtSignal(nullptr); ++ + Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, + const std::string& path) : + details::VLANCreateIface(bus, objPath, true), +@@ -43,6 +50,101 @@ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, + { + fs::path confDir(path); + setConfDir(confDir); ++ initSupportedPrivilges(); ++} ++ ++std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf, ++ const std::string& path) ++{ ++ auto mapperCall = ++ bus.new_method_call("xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject"); ++ ++ mapperCall.append(path); ++ mapperCall.append(std::vector<std::string>({intf})); ++ ++ auto mapperResponseMsg = bus.call(mapperCall); ++ ++ std::map<std::string, std::vector<std::string>> mapperResponse; ++ mapperResponseMsg.read(mapperResponse); ++ ++ if (mapperResponse.begin() == mapperResponse.end()) ++ { ++ throw std::runtime_error("ERROR in reading the mapper response"); ++ } ++ ++ return mapperResponse.begin()->first; ++} ++ ++std::string Manager::getUserServiceName() ++{ ++ static std::string userMgmtService; ++ if (userMgmtService.empty()) ++ { ++ try ++ { ++ userMgmtService = ++ getUserService(bus, userMgrInterface, userMgrObjBasePath); ++ } ++ catch (const std::exception& e) ++ { ++ log<level::ERR>("Exception caught in getUserServiceName."); ++ userMgmtService.clear(); ++ } ++ } ++ return userMgmtService; ++} ++ ++void Manager::initSupportedPrivilges() ++{ ++ std::string userServiceName = getUserServiceName(); ++ if (!userServiceName.empty()) ++ { ++ auto method = bus.new_method_call( ++ getUserServiceName().c_str(), userMgrObjBasePath, ++ "org.freedesktop.DBus.Properties", "Get"); ++ method.append(userMgrInterface, propNameAllPrivileges); ++ ++ auto reply = bus.call(method); ++ if (reply.is_method_error()) ++ { ++ log<level::DEBUG>("get-property AllPrivileges failed", ++ entry("OBJPATH:%s", userMgrObjBasePath), ++ entry("INTERFACE:%s", userMgrInterface)); ++ return; ++ } ++ ++ std::variant<std::vector<std::string>> result; ++ reply.read(result); ++ ++ supportedPrivList = std::get<std::vector<std::string>>(result); ++ } ++ ++ // Resgister the signal ++ if (usrMgmtSignal == nullptr) ++ { ++ log<level::DEBUG>("Registering User.Manager propertychange signal."); ++ usrMgmtSignal = std::make_unique<sdbusplus::bus::match_t>( ++ bus, ++ sdbusplus::bus::match::rules::propertiesChanged(userMgrObjBasePath, ++ userMgrInterface), ++ [&](sdbusplus::message::message& msg) { ++ log<level::DEBUG>("UserMgr properties changed signal"); ++ std::map<std::string, DbusVariant> props; ++ std::string iface; ++ msg.read(iface, props); ++ for (const auto& t : props) ++ { ++ if (t.first == propNameAllPrivileges) ++ { ++ supportedPrivList = ++ std::get<std::vector<std::string>>(t.second); ++ } ++ } ++ }); ++ } ++ return; + } + + bool Manager::createDefaultNetworkFiles(bool force) +diff --git a/network_manager.hpp b/network_manager.hpp +index 6815d3f..96e20a6 100644 +--- a/network_manager.hpp ++++ b/network_manager.hpp +@@ -151,6 +151,12 @@ class Manager : public details::VLANCreateIface + return (interfaces.find(intf) != interfaces.end()); + } + ++ /** supported privilege list **/ ++ std::vector<std::string> supportedPrivList; ++ ++ /** @brief initializes the supportedPrivilege List */ ++ void initSupportedPrivilges(); ++ + protected: + /** @brief Persistent sdbusplus DBus bus connection. */ + sdbusplus::bus::bus& bus; +@@ -173,6 +179,9 @@ class Manager : public details::VLANCreateIface + + /** @brief Network Configuration directory. */ + fs::path confDir; ++ ++ /** Get the user management service name dynamically **/ ++ std::string getUserServiceName(); + }; + + } // namespace network +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend new file mode 100644 index 000000000..3540e93b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += "nlohmann-json boost" + +SRC_URI = "git://github.com/openbmc/phosphor-networkd" +SRCREV = "ee5b2c9469a56205567a8b1b120ecf34fc9f5ef4" + +SRC_URI += "file://0003-Adding-channel-specific-privilege-to-network.patch \ + " + +EXTRA_OECONF_append = " --enable-nic-ethtool=yes" diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb new file mode 100644 index 000000000..0dab0fc1a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb @@ -0,0 +1,24 @@ +SUMMARY = "Enforce static MAC addresses" +DESCRIPTION = "Set a priority on MAC addresses to run with: \ + factory-specified > u-boot-specified > random" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PV = "1.0" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRC_URI = "\ + file://mac-check \ + file://${PN}.service \ + " + +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "${PN}.service" + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/mac-check ${D}${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check new file mode 100644 index 000000000..2578785b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check @@ -0,0 +1,115 @@ +#!/bin/sh +# Copyright 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SOFS_MNT=/var/sofs +SOFS_MACDIR=${SOFS_MNT}/factory-settings/network/mac + +read_hw_mac() { + local iface="$1" + cat /sys/class/net/"$iface"/address 2>/dev/null | tr [:upper:] [:lower:] 2>/dev/null +} + +set_hw_mac() { + local iface="$1" + local mac="$2" + ip link show dev "$iface" | grep -q "${iface}:.*\<UP\>" 2>/dev/null + local up=$? + [[ $up -eq 0 ]] && ip link set dev "$iface" down + ip link set dev "$iface" address "$mac" + [[ $up -eq 0 ]] && ip link set dev "$iface" up +} + +read_sofs_mac() { + local iface="$1" + cat "${SOFS_MACDIR}/${iface}" 2>/dev/null | tr [:upper:] [:lower:] 2>/dev/null +} + +read_fw_env_mac() { + local envname="$1" + fw_printenv "$envname" 2>/dev/null | sed "s/^$envname=//" 2>/dev/null | tr [:upper:] [:lower:] 2>/dev/null +} + +set_fw_env_mac() { + local envname="$1" + local mac="$2" + fw_setenv "$envname" "$mac" +} + +create_macdir() { +if [ -a ${SOFS_MACDIR} ]; then + if [ ! -d ${SOFS_MACDIR} ]; then + rm -rf ${SOFS_MACDIR} + mkdir -p ${SOFS_MACDIR} + fi +else + mkdir -p ${SOFS_MACDIR} +fi +return 0 +} + +mac_check() { + local iface="$1" + local envname="$2" + + # Read the MAC address in use by the NIC + local hw_mac=$(read_hw_mac "$iface") + + # Read the MAC address stored in the non-volatile file provisioned in + # manufacturing. + local sofs_mac=$(read_sofs_mac "$iface") + + if [ -n "$sofs_mac" ] && [ "$hw_mac" != "$sofs_mac" ]; then + # A factory assigned address was found, and it is newly assigned. + # Update the active interface and save the new value to the u-boot + # environment. + set_hw_mac "$iface" "$sofs_mac" + set_fw_env_mac "$envname" "$sofs_mac" + return $? + elif [ -n "$hw_mac" ]; then + # Read the MAC address stored by U-Boot + local fw_env_mac=$(read_fw_env_mac "$envname") + if [ -z "$fw_env_mac" ] || [ "$fw_env_mac" != "$hw_mac" ]; then + set_fw_env_mac "$envname" "$hw_mac" + return $? + fi + else + # Could not identify a MAC address + return 255 + fi + return 0 +} + +create_macdir + +error=0 +first_error_seen=0 + +while read IFACE UBDEV; do + # Try to configure the MAC address if the kernel finds the NIC. Blindly + # trying all of the interfaces listed in the DOCSTRING (END_CONF) below + # may result in first_error_seen being set to a non-zero value. If that + # happens the journal log will report the error, which is undesirable. + if [ -h /sys/class/net/$IFACE ]; then + mac_check "$IFACE" "$UBDEV" + error=$? + if [ $error -ne 0 ] && [ $first_error_seen -eq 0 ]; then + first_error_seen=$error + fi + fi +done <<-END_CONF + eth0 eth1addr + eth1 ethaddr +END_CONF +exit $first_error_seen diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service new file mode 100644 index 000000000..86371db11 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service @@ -0,0 +1,11 @@ +[Unit] +Description=Enforce Static MAC addr mapping + +[Service] +Type=oneshot +Restart=no +ExecStart=/usr/bin/mac-check + +[Install] +WantedBy=network.target + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb new file mode 100644 index 000000000..1bf81d953 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb @@ -0,0 +1,25 @@ + +SUMMARY = "Beep code manager service" +DESCRIPTION = "The beep code manager service will provide a method for beep code" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://beepcode_mgr.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +SYSTEMD_SERVICE_${PN} = "beepcode-mgr.service" + +inherit cmake +inherit obmc-phosphor-systemd + +DEPENDS += " \ + sdbusplus \ + phosphor-logging \ + boost \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt new file mode 100644 index 000000000..472257279 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (beepcode-mgr CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +add_executable (beepcode-mgr beepcode_mgr.cpp) + +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES} + phosphor_logging) + +install (TARGETS beepcode-mgr DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service new file mode 100644 index 000000000..8099e2541 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service @@ -0,0 +1,12 @@ +[Unit] +Description=Beep code manager + +[Service] +Restart=always +RestartSec=2 +ExecStart=/usr/bin/beepcode-mgr +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp new file mode 100644 index 000000000..5a2deceaf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp @@ -0,0 +1,321 @@ +/* Copyright 2019 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <linux/input.h> + +#include <boost/asio/io_service.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <chrono> +#include <iostream> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> + +static constexpr uint32_t defaultBeepFrequence = 2000; +static constexpr uint32_t defaultBeepDurationMs = 300; +// Duration between two beeps +static constexpr uint32_t defaultInterBeepDurationMs = 300; +// Duration between two 4-bit digitals +static constexpr uint32_t defaultInterDigitBeepDurationMs = 800; +// Duration between two patterns +static constexpr uint32_t defaultPostBeepDurationMs = 1000; + +static constexpr uint8_t offBeepState = 0; +static constexpr uint8_t onBeepState = 1; +// finish 1 bit beep +static constexpr uint8_t interBeepState = 2; +// finish 4 bits beep +static constexpr uint8_t interDigitBeepState = 3; +// finish all bits beep +static constexpr uint8_t postBeepState = 4; + +static const std::vector<uint32_t> beepDelayTable = { + 0, defaultBeepDurationMs, defaultInterBeepDurationMs, + defaultInterDigitBeepDurationMs, defaultPostBeepDurationMs}; + +static constexpr uint32_t bpBitCount = 4; +static constexpr uint32_t bpShiftCount = 32; +static constexpr uint32_t bpMask = 0xf0000000; + +// beep code priority +static constexpr uint8_t beepOff = 0; +static constexpr uint8_t beepVRWatchdogTimeout = 1; +static constexpr uint8_t beepPSUFailure = 2; +static constexpr uint8_t beepCPUMIssing = 3; +static constexpr uint8_t beepCPUCatError = 4; +static constexpr uint8_t beepCPUErr2 = 5; +static constexpr uint8_t beepVoltageMismatch = 6; +static constexpr uint8_t beepCPUConfigError = 7; +static constexpr uint8_t beepPowerFail = 8; +static constexpr uint8_t beepPowerGoodTimeOut = 9; +static constexpr uint8_t beepMax = 10; + +// priority, abbrev name map +static const std::map<uint8_t, std::string> beepCodeNameList = { + {beepVRWatchdogTimeout, "VRWatchdogTimeout"}, + {beepPSUFailure, "PSUFailure"}, + {beepCPUMIssing, "CPUMissing"}, + {beepCPUCatError, "CPUCatError"}, + {beepCPUErr2, "CPUErr2"}, + {beepVoltageMismatch, "VoltageMismatch"}, + {beepCPUConfigError, "CPUConfigError"}, + {beepPowerFail, "PowerFail"}, + {beepPowerGoodTimeOut, "PowerGoodTimeOut"}, +}; + +// priority, code pattern map +static const std::map<uint8_t, std::string> beepCodePatternList = { + {beepVRWatchdogTimeout, "1-5-1-2"}, {beepPSUFailure, "1-5-1-4"}, + {beepCPUMIssing, "1-5-2-1"}, {beepCPUCatError, "1-5-2-2"}, + {beepCPUErr2, "1-5-2-3"}, {beepVoltageMismatch, "1-5-2-4"}, + {beepCPUConfigError, "1-5-2-5"}, {beepPowerFail, "1-5-4-2"}, + {beepPowerGoodTimeOut, "1-5-4-4"}, +}; + +static const std::vector<uint32_t> beepCodeTable = { + 0, 0x1512, 0x1514, 0x1521, 0x1522, 0x1523, 0x1524, 0x1525, 0x1542, 0x1544}; + +static constexpr char bpDevName[] = "/dev/input/event0"; +static constexpr char bpBusName[] = "xyz.openbmc_project.BeepCode"; +static constexpr char bpObjName[] = "/xyz/openbmc_project/BeepCode"; +static constexpr char bpIntfName[] = "xyz.openbmc_project.BeepCode"; +static constexpr char bpMethodName[] = "Beep"; + +static std::shared_ptr<sdbusplus::asio::dbus_interface> bpIface; +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); + +class Beeper +{ + public: + Beeper(boost::asio::io_service& io) + { + timer = std::make_unique<boost::asio::steady_timer>(io); + fdBeepDev = -1; + currentCount = 0; + currentBeepCode = 0; + currentMask = bpMask; + currentShift = bpShiftCount; + currentState = offBeepState; + timerRunning = false; + } + + ~Beeper() + { + } + + void beep(const uint8_t& beepPriority) + { + if (timerRunning) + { + pendingList.push_back(beepPriority); + pendingList.sort(std::greater<uint8_t>()); + return; + } + + performBeep(beepPriority); + } + + private: + void performBeep(const uint8_t& beepPriority) + { + currentBeepCode = beepCodeTable[beepPriority]; + currentCount = 0; + currentMask = bpMask; + currentShift = bpShiftCount; + getCurrentCount(); + startBeep(defaultBeepFrequence); + currentState = onBeepState; + currentCount--; + timerRunning = true; + startBeepTimer(); + } + + void startBeepTimer() + { + timer->expires_after( + std::chrono::milliseconds(beepDelayTable[currentState])); + timer->async_wait([this](const boost::system::error_code& ec) { + // timer timeout + switch (currentState) + { + case onBeepState: + stopBeep(); + if (currentCount == 0) + { + // finished the current 4-bit + if (currentBeepCode == 0) + { + // finished all bits + currentState = postBeepState; + } + else + { + // start next 4-bit + currentState = interDigitBeepState; + getCurrentCount(); + currentCount--; + } + } + else + { + // still in 4-bit processing + currentCount--; + currentState = interBeepState; + } + startBeepTimer(); + break; + + case interBeepState: + case interDigitBeepState: + startBeep(defaultBeepFrequence); + currentState = onBeepState; + startBeepTimer(); + break; + case postBeepState: + if (pendingList.size() != 0) + { + // continue the next new beepcode + uint8_t beepPriority = pendingList.front(); + pendingList.pop_front(); + performBeep(beepPriority); + } + else + { + timerRunning = false; + } + break; + + default: + std::cerr << "Incorrect beepState: " + << static_cast<unsigned int>(currentState) + << std::endl; + break; + } + }); + } + + void startBeep(uint32_t freq) + { + if (fdBeepDev != -1) + { + std::cerr << "beep device is opening already!" << std::endl; + ::close(fdBeepDev); + fdBeepDev = -1; + } + + if ((fdBeepDev = ::open(bpDevName, O_RDWR | O_CLOEXEC)) < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Failed to open input device"); + return; + } + + struct input_event event; + event.type = EV_SND; + event.code = SND_TONE; + event.value = freq; + + if (::write(fdBeepDev, &event, sizeof(struct input_event)) != + sizeof(struct input_event)) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Failed to write a tone sound event"); + ::close(fdBeepDev); + fdBeepDev = -1; + return; + } + return; + } + + void stopBeep() + { + if (fdBeepDev == -1) + { + std::cerr << "beep device is closed!" << std::endl; + return; + } + + ::close(fdBeepDev); + fdBeepDev = -1; + } + + // Split the beep code based on bpBitCount, for example 0x1544, + // currentCount=1, 5, 4, 4 + void getCurrentCount() + { + while (currentCount == 0) + { + currentCount = currentMask & currentBeepCode; + currentShift -= bpBitCount; + currentCount >>= currentShift; + currentBeepCode = currentBeepCode & ~currentMask; + currentMask >>= bpBitCount; + if (currentMask == 0) + { + break; + } + } + } + + int fdBeepDev; + bool timerRunning; + uint32_t currentCount; + uint32_t currentBeepCode; + uint32_t currentMask; + uint32_t currentShift; + uint8_t currentState; + std::unique_ptr<boost::asio::steady_timer> timer; + std::list<uint8_t> pendingList; +}; + +static Beeper beeper(io); + +// dbus method +static void beep(const uint8_t& beepPriority) +{ + if ((beepPriority >= beepMax) || (beepPriority == beepOff)) + { + std::cerr << "Incorrect input: " + << static_cast<unsigned int>(beepPriority) << std::endl; + return; + } + + beeper.beep(beepPriority); + + return; +} + +int main(int argc, char** argv) +{ + phosphor::logging::log<phosphor::logging::level::INFO>( + "Starting BeepCode service"); + + conn->request_name(bpBusName); + sdbusplus::asio::object_server server = + sdbusplus::asio::object_server(conn); + bpIface = server.add_interface(bpObjName, bpIntfName); + + bpIface->register_property("BeepCodeNameList", beepCodeNameList, + sdbusplus::asio::PropertyPermission::readOnly); + bpIface->register_property("BeepCodePatternList", beepCodePatternList, + sdbusplus::asio::PropertyPermission::readOnly); + bpIface->register_method(bpMethodName, beep); + bpIface->initialize(); + + io.run(); + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb new file mode 100644 index 000000000..b91cc5e9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/biosconfig-manager/biosconfig-manager_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "BIOS Config Manager daemon for managing the BIOS configuration" +DESCRIPTION = "To view and modify BIOS setup configuration remotely via BMC" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +inherit meson systemd + +SRC_URI = "git://github.com/openbmc/bios-settings-mgr.git" +SRCREV = "c0f926d6cbf9636a42f4bc3d33b9602e4633c478" + +SYSTEMD_SERVICE_${PN} += " \ + xyz.openbmc_project.biosconfig_manager.service \ + xyz.openbmc_project.biosconfig_password.service \ + " + +DEPENDS += " \ + systemd \ + sdbusplus \ + libgpiod \ + phosphor-logging \ + boost \ + nlohmann-json \ + libtinyxml2 \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch new file mode 100644 index 000000000..e47111c56 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0001-Improve-initialization-of-I2C-sensors.patch @@ -0,0 +1,493 @@ +From a85d4c9cf702965593ec771e57a975e30d1d5853 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Tue, 13 Oct 2020 15:00:51 -0700 +Subject: [PATCH] Improve initialization of I2C sensors + +After an AC cycle validation has witnessed some systems sensors are +missing. As Entity Manager begins the process of scanning for +sesnsors, and creating the hardware monitoring nodes, there are +occassionally some failures to correctly create the node. This +manifests itself by the 'dd' kernel driver emitting an -EBUSY error +message. Unfortunately the 'dd' driver also eats the error code, and +continues. This is by design. + +This commit modifies how the nodes are initialized. The steps taken: +1. Determine if the node is already present +2. Create the node if it is not +3. Set a timer, to give the kernel time to create the node +4. For those sensors that create a "hwmon" subdir, search for that +directory after the timer elapses. +5. If the subdir is not present, delete the device, and try again by +initiating another timer. +6. Continue until the subdir exists, or a retry count expires. + +Tested: +Ran AC cycles via a script. +After each cycle, wait for the SUT to DC on, and arrive at the EFI +Shell> propmt. +Issue "ipmitool sensor list", capturing the results +Search the list for all of the sensors that have been reported as +missing after AC cycles. + +Change-Id: I118df674162677d66e7d211b089430fce384086b +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + include/devices.hpp | 167 +++++++++++++++++++++----------------- + src/Overlay.cpp | 192 ++++++++++++++++++++++++++++++++++---------- + 2 files changed, 243 insertions(+), 116 deletions(-) + +diff --git a/include/devices.hpp b/include/devices.hpp +index 50fbe63..2e299a0 100644 +--- a/include/devices.hpp ++++ b/include/devices.hpp +@@ -31,107 +31,130 @@ struct CmpStr + + struct ExportTemplate + { +- ExportTemplate(const char* params, const char* dev) : +- parameters(params), device(dev){}; ++ ExportTemplate(const char* params, const char* dev, const char* constructor, ++ const char* destructor, bool createsHWMon) : ++ parameters(params), ++ devicePath(dev), add(constructor), remove(destructor), ++ createsHWMon(createsHWMon){}; + const char* parameters; +- const char* device; ++ const char* devicePath; ++ const char* add; ++ const char* remove; ++ bool createsHWMon; + }; + + const boost::container::flat_map<const char*, ExportTemplate, CmpStr> + exportTemplates{ + {{"EEPROM_24C02", + ExportTemplate("24c02 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ "/sys/bus/i2c/devices/i2c-$Bus/new_device", ++ "new_device", "delete_device", false)}, + {"EEPROM_24C64", + ExportTemplate("24c64 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"ADM1266", +- ExportTemplate("adm1266 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ "/sys/bus/i2c/devices/i2c-$Bus/new_device", ++ "new_device", "delete_device", false)}, ++ {"24C02", ++ ExportTemplate("24c02 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, ++ {"24C64", ++ ExportTemplate("24c64 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, ++ {"ADM1266", ExportTemplate("adm1266 $Address", ++ "/sys/bus/i2c/devices/i2c-$Bus/new_device", ++ "new_device", "delete_device", false)}, + {"ADM1272", +- ExportTemplate("adm1272 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"EEPROM", ExportTemplate("eeprom $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("adm1272 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, ++ {"EEPROM", ++ ExportTemplate("eeprom $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, + {"EMC1412", +- ExportTemplate("emc1412 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("emc1412 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"EMC1413", +- ExportTemplate("emc1413 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("emc1413 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"EMC1414", +- ExportTemplate("emc1414 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"Gpio", ExportTemplate("$Index", "/sys/class/gpio/export")}, +- {"INA230", ExportTemplate("ina230 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("emc1414 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"Gpio", ExportTemplate("$Index", "/sys/class/gpio", "export", ++ "unexport", false)}, ++ {"INA230", ++ ExportTemplate("ina230 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"ISL68137", +- ExportTemplate("isl68137 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("isl68137 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"ISL68223", +- ExportTemplate("isl68223 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("isl68223 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"ISL69243", +- ExportTemplate("isl69243 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("isl69243 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX16601", +- ExportTemplate("max16601 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max16601 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX20710", +- ExportTemplate("max20710 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max20710 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX20730", +- ExportTemplate("max20730 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max20730 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX20734", +- ExportTemplate("max20734 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max20734 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX20796", +- ExportTemplate("max20796 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max20796 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX31725", +- ExportTemplate("max31725 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max31725 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX31730", +- ExportTemplate("max31730 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"MAX34440", +- ExportTemplate("max34440 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max31730 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"MAX34440", ExportTemplate("max34440 $Address", ++ "/sys/bus/i2c/devices/i2c-$Bus/new_device", ++ "new_device", "delete_device", true)}, + {"MAX34451", +- ExportTemplate("max34451 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max34451 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"MAX6654", +- ExportTemplate("max6654 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("max6654 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"PCA9543Mux", +- ExportTemplate("pca9543 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("pca9543 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, + {"PCA9544Mux", +- ExportTemplate("pca9544 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("pca9544 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, + {"PCA9545Mux", +- ExportTemplate("pca9545 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("pca9545 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, + {"PCA9546Mux", +- ExportTemplate("pca9546 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("pca9546 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, + {"PCA9547Mux", +- ExportTemplate("pca9547 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"SBTSI", ExportTemplate("sbtsi $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"pmbus", ExportTemplate("pmbus $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"TMP112", ExportTemplate("tmp112 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"TMP175", ExportTemplate("tmp175 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"TMP421", ExportTemplate("tmp421 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, +- {"TMP441", ExportTemplate("tmp441 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}, ++ ExportTemplate("pca9547 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", false)}, ++ {"SBTSI", ++ ExportTemplate("sbtsi $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"pmbus", ++ ExportTemplate("pmbus $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"TMP112", ++ ExportTemplate("tmp112 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"TMP175", ++ ExportTemplate("tmp175 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"TMP421", ++ ExportTemplate("tmp421 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, ++ {"TMP441", ++ ExportTemplate("tmp441 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}, + {"TMP75", +- ExportTemplate("tmp75 $Address", +- "/sys/bus/i2c/devices/i2c-$Bus/new_device")}}}; ++ ExportTemplate("tmp75 $Address", "/sys/bus/i2c/devices/i2c-$Bus", ++ "new_device", "delete_device", true)}}}; + } // namespace devices +diff --git a/src/Overlay.cpp b/src/Overlay.cpp +index cb6ed10..7a3089e 100644 +--- a/src/Overlay.cpp ++++ b/src/Overlay.cpp +@@ -21,6 +21,8 @@ + #include "devices.hpp" + + #include <boost/algorithm/string/predicate.hpp> ++#include <boost/asio/io_context.hpp> ++#include <boost/asio/steady_timer.hpp> + #include <boost/container/flat_map.hpp> + #include <boost/container/flat_set.hpp> + #include <boost/process/child.hpp> +@@ -32,6 +34,8 @@ + #include <regex> + #include <string> + ++extern boost::asio::io_context io; ++ + constexpr const char* OUTPUT_DIR = "/tmp/overlays"; + constexpr const char* TEMPLATE_CHAR = "$"; + constexpr const char* HEX_FORMAT_STR = "0x"; +@@ -113,16 +117,149 @@ void linkMux(const std::string& muxName, size_t busIndex, size_t address, + } + } + ++static int deleteDevice(const std::string& devicePath, ++ std::shared_ptr<uint64_t> address, ++ const std::string& destructor) ++{ ++ if (!address) ++ { ++ return -1; ++ } ++ std::filesystem::path deviceDestructor(devicePath); ++ deviceDestructor /= destructor; ++ std::ofstream deviceFile(deviceDestructor); ++ if (!deviceFile.good()) ++ { ++ std::cerr << "Error writing " << deviceDestructor << "\n"; ++ return -1; ++ } ++ deviceFile << std::to_string(*address); ++ deviceFile.close(); ++ return 0; ++} ++ ++static int createDevice(const std::string& devicePath, ++ const std::string& parameters, ++ const std::string& constructor) ++{ ++ std::filesystem::path deviceConstructor(devicePath); ++ deviceConstructor /= constructor; ++ std::ofstream deviceFile(deviceConstructor); ++ if (!deviceFile.good()) ++ { ++ std::cerr << "Error writing " << deviceConstructor << "\n"; ++ return -1; ++ } ++ deviceFile << parameters; ++ deviceFile.close(); ++ ++ return 0; ++} ++ ++static bool deviceIsCreated(const std::string& devicePath, ++ std::shared_ptr<uint64_t> bus, ++ std::shared_ptr<uint64_t> address, ++ const bool retrying) ++{ ++ // Prevent the device from being created a second time. ++ if (bus && address) ++ { ++ std::ostringstream hex; ++ hex << std::hex << *address; ++ std::string addressHex = hex.str(); ++ std::string busStr = std::to_string(*bus); ++ ++ if (std::filesystem::is_directory(devicePath)) ++ { ++ for (const auto& path : ++ std::filesystem::directory_iterator(devicePath)) ++ { ++ if (!std::filesystem::is_directory(path)) ++ { ++ continue; ++ } ++ ++ const std::string& directoryName = path.path().filename(); ++ if (boost::starts_with(directoryName, busStr) && ++ boost::ends_with(directoryName, addressHex)) ++ { ++ if (retrying) ++ { ++ // subsequent attempts should find the hwmon subdir. ++ std::filesystem::path hwmonDir(devicePath); ++ hwmonDir /= directoryName; ++ hwmonDir /= "hwmon"; ++ bool dirFound = ++ (std::filesystem::is_directory(hwmonDir)); ++ return dirFound; ++ } ++ else ++ { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ } ++ return false; ++} ++ ++constexpr size_t totalBuildDeviceRetries = 5; ++static int buildDevice(const std::string& devicePath, ++ const std::string& parameters, ++ std::shared_ptr<uint64_t> bus, ++ std::shared_ptr<uint64_t> address, ++ const std::string& constructor, ++ const std::string& destructor, const bool createsHWMon, ++ const size_t retries = totalBuildDeviceRetries) ++{ ++ bool tryAgain = false; ++ if (!retries) ++ { ++ return -1; ++ } ++ ++ if (!deviceIsCreated(devicePath, bus, address, false)) ++ { ++ createDevice(devicePath, parameters, constructor); ++ tryAgain = true; ++ } ++ else if (createsHWMon && !deviceIsCreated(devicePath, bus, address, true)) ++ { ++ // device is present, hwmon subdir missing ++ deleteDevice(devicePath, address, destructor); ++ tryAgain = true; ++ } ++ ++ if (tryAgain) ++ { ++ std::shared_ptr<boost::asio::steady_timer> createTimer = ++ std::make_shared<boost::asio::steady_timer>(io); ++ createTimer->expires_after(std::chrono::milliseconds(500)); ++ createTimer->async_wait([createTimer, devicePath, parameters, bus, ++ address, constructor, destructor, createsHWMon, ++ retries](const boost::system::error_code&) { ++ buildDevice(devicePath, parameters, bus, address, constructor, ++ destructor, createsHWMon, retries - 1); ++ }); ++ } ++ return 0; ++} ++ + void exportDevice(const std::string& type, + const devices::ExportTemplate& exportTemplate, + const nlohmann::json& configuration) + { + + std::string parameters = exportTemplate.parameters; +- std::string device = exportTemplate.device; ++ std::string devicePath = exportTemplate.devicePath; ++ std::string constructor = exportTemplate.add; ++ std::string destructor = exportTemplate.remove; ++ bool createsHWMon = exportTemplate.createsHWMon; + std::string name = "unknown"; +- const uint64_t* bus = nullptr; +- const uint64_t* address = nullptr; ++ std::shared_ptr<uint64_t> bus = nullptr; ++ std::shared_ptr<uint64_t> address = nullptr; + const nlohmann::json::array_t* channels = nullptr; + + for (auto keyPair = configuration.begin(); keyPair != configuration.end(); +@@ -144,11 +281,13 @@ void exportDevice(const std::string& type, + + if (keyPair.key() == "Bus") + { +- bus = keyPair.value().get_ptr<const uint64_t*>(); ++ bus = std::make_shared<uint64_t>( ++ *keyPair.value().get_ptr<const uint64_t*>()); + } + else if (keyPair.key() == "Address") + { +- address = keyPair.value().get_ptr<const uint64_t*>(); ++ address = std::make_shared<uint64_t>( ++ *keyPair.value().get_ptr<const uint64_t*>()); + } + else if (keyPair.key() == "ChannelNames") + { +@@ -157,49 +296,14 @@ void exportDevice(const std::string& type, + } + boost::replace_all(parameters, TEMPLATE_CHAR + keyPair.key(), + subsituteString); +- boost::replace_all(device, TEMPLATE_CHAR + keyPair.key(), ++ boost::replace_all(devicePath, TEMPLATE_CHAR + keyPair.key(), + subsituteString); + } + +- // if we found bus and address we can attempt to prevent errors +- if (bus != nullptr && address != nullptr) +- { +- std::ostringstream hex; +- hex << std::hex << *address; +- const std::string& addressHex = hex.str(); +- std::string busStr = std::to_string(*bus); ++ int err = buildDevice(devicePath, parameters, bus, address, constructor, ++ destructor, createsHWMon); + +- std::filesystem::path devicePath(device); +- std::filesystem::path parentPath = devicePath.parent_path(); +- if (std::filesystem::is_directory(parentPath)) +- { +- for (const auto& path : +- std::filesystem::directory_iterator(parentPath)) +- { +- if (!std::filesystem::is_directory(path)) +- { +- continue; +- } +- +- const std::string& directoryName = path.path().filename(); +- if (boost::starts_with(directoryName, busStr) && +- boost::ends_with(directoryName, addressHex)) +- { +- return; // already exported +- } +- } +- } +- } +- +- std::ofstream deviceFile(device); +- if (!deviceFile.good()) +- { +- std::cerr << "Error writing " << device << "\n"; +- return; +- } +- deviceFile << parameters; +- deviceFile.close(); +- if (boost::ends_with(type, "Mux") && bus && address && channels) ++ if (!err && boost::ends_with(type, "Mux") && bus && address && channels) + { + linkMux(name, static_cast<size_t>(*bus), static_cast<size_t>(*address), + *channels); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch new file mode 100644 index 000000000..8682e2cad --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0002-Entity-manager-Add-support-to-update-assetTag.patch @@ -0,0 +1,173 @@ +From ff5dbca96d12b1c2aaaec0bb891125990af3f218 Mon Sep 17 00:00:00 2001 +From: mansijos <mansi.joshi@intel.com> +Date: Tue, 6 Apr 2021 02:12:56 +0530 +Subject: [PATCH] Entity-manager: Add support to update assetTag + +Asset tag is an updateable property from User level interface like +Redfish. User-level interface will update Asset tag in entity-manager, +which will further update the needed FRU interface property exposed. + +Tested: +Successfully updated in assetTag interface as well as in fru interface +while using set-property and using redfish as well. +The new value is preserved after BMC resets. + +Change-Id: If7fbfd8325488280f500ab0e2c8b38475813cc3f +Signed-off-by: mansijos <mansi.joshi@intel.com> +--- + src/EntityManager.cpp | 92 +++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 88 insertions(+), 4 deletions(-) + +diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp +index 932b6f9..67b8f95 100644 +--- a/src/EntityManager.cpp ++++ b/src/EntityManager.cpp +@@ -47,9 +47,17 @@ constexpr const char* lastConfiguration = "/tmp/configuration/last.json"; + constexpr const char* currentConfiguration = "/var/configuration/system.json"; + constexpr const char* globalSchema = "global.json"; + constexpr const int32_t MAX_MAPPER_DEPTH = 0; ++constexpr const char* foundObject = "FoundProbe"; + + constexpr const bool DEBUG = false; + ++using foundProbeData = std::map<std::string, std::string>; ++static foundProbeData foundData; ++static std::map<std::string, foundProbeData> mapFoundData; ++ ++constexpr const char* fruConn = "xyz.openbmc_project.FruDevice"; ++constexpr const char* fruIntf = "xyz.openbmc_project.FruDevice"; ++ + struct cmp_str + { + bool operator()(const char* a, const char* b) const +@@ -575,6 +583,43 @@ void addArrayToDbus(const std::string& name, const nlohmann::json& array, + } + } + ++template <typename PropertyType> ++bool persistAssetTag(const PropertyType& newVal, ++ const std::string& jsonPointerString) ++{ ++ std::size_t found = jsonPointerString.find_last_of("/\\"); ++ std::string jsonPointerPath = jsonPointerString.substr(0, found); ++ ++ auto it = mapFoundData.find(jsonPointerPath); ++ if (it == mapFoundData.end()) ++ { ++ std::cerr << "Error in finding jsonPointerPath in mapFoundData" ++ << "\n"; ++ return false; ++ } ++ ++ foundProbeData& tmpMap = it->second; ++ auto foundPath = tmpMap.find("foundPath"); ++ if (foundPath == tmpMap.end()) ++ { ++ std::cerr << "No prob object data is avaliable in foundProbeData" ++ << "\n"; ++ return false; ++ } ++ ++ SYSTEM_BUS->async_method_call( ++ [](const boost::system::error_code& ec) { ++ if (ec) ++ { ++ std::cerr << "Error setting AssetTag in FRU interface " << ec ++ << "\n"; ++ } ++ }, ++ fruConn, foundPath->second, "org.freedesktop.DBus.Properties", "Set", ++ fruIntf, "PRODUCT_ASSET_TAG", std::variant<PropertyType>(newVal)); ++ return true; ++} ++ + template <typename PropertyType> + void addProperty(const std::string& propertyName, const PropertyType& value, + sdbusplus::asio::dbus_interface* iface, +@@ -589,9 +634,18 @@ void addProperty(const std::string& propertyName, const PropertyType& value, + } + iface->register_property( + propertyName, value, +- [&systemConfiguration, ++ [propertyName, &systemConfiguration, + jsonPointerString{std::string(jsonPointerString)}]( + const PropertyType& newVal, PropertyType& val) { ++ if (propertyName == "AssetTag") ++ { ++ if (!persistAssetTag(newVal, jsonPointerString)) ++ { ++ std::cerr << "error setting AssetTag in FRU interface\n"; ++ return -1; ++ } ++ } ++ + val = newVal; + if (!setJsonFromPointer(jsonPointerString, val, + systemConfiguration)) +@@ -989,6 +1043,9 @@ void postToDbus(const nlohmann::json& newConfiguration, + populateInterfaceFromJson(systemConfiguration, jsonPointerPath, + boardIface, boardValues, objServer); + jsonPointerPath += "/"; ++ ++ std::string foundPath; ++ + // iterate through board properties + for (auto& boardField : boardValues.items()) + { +@@ -998,9 +1055,28 @@ void postToDbus(const nlohmann::json& newConfiguration, + createInterface(objServer, boardName, boardField.key(), + boardKeyOrig); + +- populateInterfaceFromJson(systemConfiguration, +- jsonPointerPath + boardField.key(), +- iface, boardField.value(), objServer); ++ if (boardField.key() == "FoundProbe") ++ { ++ foundPath = boardField.value()["Path"]; ++ } ++ if (boardField.key() == ++ "xyz.openbmc_project.Inventory.Decorator.AssetTag") ++ { ++ foundData["foundPath"] = foundPath; ++ mapFoundData[jsonPointerPath + boardField.key()] = ++ foundData; ++ ++ populateInterfaceFromJson( ++ systemConfiguration, jsonPointerPath + boardField.key(), ++ iface, boardField.value(), objServer, ++ sdbusplus::asio::PropertyPermission::readWrite); ++ } ++ else ++ { ++ populateInterfaceFromJson( ++ systemConfiguration, jsonPointerPath + boardField.key(), ++ iface, boardField.value(), objServer); ++ } + } + } + +@@ -1349,6 +1425,10 @@ void PerformScan::run() + continue; + } + ++ nlohmann::json recordVal = *recordPtr; ++ // Save the dbus path info of the device ++ recordVal[foundObject]["Path"] = std::get<1>(*itr); ++ + int index = std::stoi( + nameIt->get<std::string>().substr(indexIdx), + nullptr, 0); +@@ -1421,6 +1501,10 @@ void PerformScan::run() + } + } + ++ // Save the dbus path info of the device ++ record[foundObject]["Path"] = ++ std::get<1>(foundDeviceAndPath); ++ + if (replaceStr) + { + std::cerr << "Duplicates found, replacing " +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch new file mode 100644 index 000000000..94af67967 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/0003-Add-logs-to-fwVersionIsSame.patch @@ -0,0 +1,56 @@ +From 28525b56161e1b659e85e85c33fc00dc397758aa Mon Sep 17 00:00:00 2001 +From: Helen Huang <he.huang@intel.com> +Date: Mon, 19 Apr 2021 16:06:15 +0800 +Subject: [PATCH] Add logs to fwVersionIsSame() + +Add logs to fwVersionIsSame() to indicate whether the firmware +version is changed or not. + +Tested: +Logs are printed as expected when firmware updating and BMC rebooting. + +Log of rebooting: +The firmware version is similiar as the last boot, +Hash value of versionFile is:3336889560 + +Log of Firmware update: +The firmware version is changed since the last boot, +hash value of current versionFile is:3336889560, +hash value of versionFile of last boot is:834871226 + +Change-Id: I5306917329d2e2e015af58cad1e9c59881f0b217 +Signed-off-by: Helen Huang <he.huang@intel.com> +--- + include/Utils.hpp | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/include/Utils.hpp b/include/Utils.hpp +index 657af92..8238807 100644 +--- a/include/Utils.hpp ++++ b/include/Utils.hpp +@@ -116,13 +116,22 @@ inline bool fwVersionIsSame(void) + + if (expectedHash == hashString) + { ++ std::cout << "The firmware version is similiar as the last boot, " ++ "hash value of versionFile is:" ++ << hashString.c_str() << "\n"; + return true; + } ++ std::cout << "The firmware version is changed since the last boot, hash " ++ "value of current versionFile is:" ++ << expectedHash.c_str() ++ << ", hash value of versionFile of last boot is:" ++ << hashString.c_str() << "\n"; + hashFile.close(); + } + + std::ofstream output(versionHashFile); + output << expectedHash; ++ + return false; + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend new file mode 100644 index 000000000..9d891c620 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend @@ -0,0 +1,11 @@ +# this is here just to bump faster than upstream +# SRC_URI = "git://github.com/openbmc/entity-manager.git" +SRCREV = "1694ef625a1075599e40faa695a40d61ccd91095" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " file://0001-Improve-initialization-of-I2C-sensors.patch \ + file://0002-Entity-manager-Add-support-to-update-assetTag.patch \ + file://0003-Add-logs-to-fwVersionIsSame.patch \ + " + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf new file mode 100644 index 000000000..1d332e2a2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console.conf @@ -0,0 +1,3 @@ +baud = 921600 +local-tty = ttyS3 +local-tty-baud = 921600 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service new file mode 100644 index 000000000..a242dba08 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/obmc-console@.service @@ -0,0 +1,14 @@ +[Unit] +Description=Phosphor Console Muxer listening on device /dev/%I +BindsTo=dev-%i.device +After=dev-%i.device + +[Service] +ExecStartPre=/usr/bin/sol-option-check.sh +ExecStart=/usr/bin/env obmc-console-server --config {sysconfdir}/obmc-console.conf %i +ExecStopPost=/bin/sh -c 'echo -n "0" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/raw' +SyslogIdentifier=obmc-console-server +Restart=always + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh new file mode 100755 index 000000000..19179c497 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console/sol-option-check.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# Copyright 2017-2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +CPUPART="CPU part" +AST2500_ID="0xb76" +AST2600_ID="0xc07" + +if ([ $(grep "$CPUPART" /proc/cpuinfo | grep "$AST2500_ID" | wc -l) != 0 ] && \ + [ $(grep 192000000 /sys/class/tty/ttyS0/uartclk | wc -l) != 0 ]) || \ + ([ $(grep "$CPUPART" /proc/cpuinfo | grep "$AST2600_ID" | wc -l) != 0 ] && \ + [ $(grep 14769216 /sys/class/tty/ttyS0/uartclk | wc -l) != 0 ]); then + echo "hs-uart" + sed -i -e 's/115200/921600/g' /etc/obmc-console.conf +else + echo "normal uart" + sed -i -e 's/921600/115200/g' /etc/obmc-console.conf +fi diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend new file mode 100644 index 000000000..09510fec8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/console/obmc-console_%.bbappend @@ -0,0 +1,17 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" +OBMC_CONSOLE_HOST_TTY = "ttyS2" +SRC_URI += "file://sol-option-check.sh \ + file://obmc-console@.service \ + " +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += " \ + ${PN}@${OBMC_CONSOLE_HOST_TTY}.service \ + " + +do_install_append() { + rm -rf ${D}${base_libdir}/udev/rules.d/80-obmc-console-uart.rules + install -m 0644 ${WORKDIR}/${PN}@.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/sol-option-check.sh ${D}${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb new file mode 100644 index 000000000..089aaf59f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb @@ -0,0 +1,26 @@ + +SUMMARY = "PCH BMC time service" +DESCRIPTION = "This service will read date/time from PCH device periodically, and set the BMC system time accordingly" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://pch-time-sync.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +SYSTEMD_SERVICE_${PN} = "pch-time-sync.service" + +inherit cmake +inherit obmc-phosphor-systemd + +DEPENDS += " \ + sdbusplus \ + phosphor-logging \ + boost \ + i2c-tools \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt new file mode 100644 index 000000000..a4cf8155f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (pch-time-sync CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +add_executable (pch-time-sync pch-time-sync.cpp) + +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES} + phosphor_logging) +target_link_libraries (${PROJECT_NAME} i2c) + +install (TARGETS pch-time-sync DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp new file mode 100644 index 000000000..00e2b53fe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp @@ -0,0 +1,417 @@ +/* Copyright 2019 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <time.h> + +#include <boost/asio/io_service.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <chrono> +#include <filesystem> +#include <iostream> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> +extern "C" { +#include <i2c/smbus.h> +#include <linux/i2c-dev.h> +} + +static constexpr uint32_t syncIntervalNormalMS = 60000; +static constexpr uint32_t syncIntervalFastMS = (syncIntervalNormalMS / 2); +static constexpr uint32_t syncIntervalBootMS = 5000; + +static uint32_t syncIntervalMS = syncIntervalNormalMS; + +// will update bmc time if the time difference beyond this value +static constexpr uint8_t timeDiffAllowedSecond = 1; +static uint8_t pchDevI2cBusNo = 0; +static uint8_t pchDevI2cSlaveAddr = 0; +static bool getPCHI2cAddrFlag = false; +static constexpr const char* clockFile = "/var/lib/systemd/timesync/clock"; +static inline uint8_t bcd2Decimal(uint8_t hex) +{ + uint8_t dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F); + return dec; +} + +class I2CFile +{ + private: + int fd = -1; + + public: + I2CFile(const int& i2cBus, const int& slaveAddr, const int& flags) + { + std::string i2cDev = "/dev/i2c-" + std::to_string(i2cBus); + + fd = open(i2cDev.c_str(), flags); + if (fd < 0) + { + throw std::runtime_error("Unable to open i2c device."); + } + + if (ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0) + { + close(fd); + fd = -1; + throw std::runtime_error("Unable to set i2c slave address."); + } + } + + uint8_t i2cReadByteData(const uint8_t& offset) + { + int ret = i2c_smbus_read_byte_data(fd, offset); + + if (ret < 0) + { + throw std::runtime_error("i2c read failed"); + } + return static_cast<uint8_t>(ret); + } + + ~I2CFile() + { + if (!(fd < 0)) + { + close(fd); + } + } +}; + +static void getPCHI2cAddr(std::shared_ptr<sdbusplus::asio::connection>& conn, + const std::string& service, const std::string& object, + const std::string& interface) +{ + conn->async_method_call( + [](boost::system::error_code ec, + const std::vector< + std::pair<std::string, std::variant<std::string, uint64_t>>>& + propertiesList) { + if (ec) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "DBUS response error: cannot get I2c address of PCH timer", + phosphor::logging::entry("ECVALUE=%x", ec.value()), + phosphor::logging::entry("ECMESSAGE=%s", + ec.message().c_str())); + return; + } + const uint64_t* i2cBusNoValue = nullptr; + const uint64_t* i2cSlaveAddrValue = nullptr; + for (const auto& property : propertiesList) + { + + if (property.first == "PchSmbusSlaveI2cBus") + { + i2cBusNoValue = std::get_if<uint64_t>(&property.second); + } + if (property.first == "PchSmbusSlaveI2cAddress") + { + i2cSlaveAddrValue = std::get_if<uint64_t>(&property.second); + } + } + if ((i2cBusNoValue != nullptr) && (i2cSlaveAddrValue != nullptr)) + { + pchDevI2cBusNo = static_cast<uint8_t>(*i2cBusNoValue); + pchDevI2cSlaveAddr = static_cast<uint8_t>(*i2cSlaveAddrValue); + getPCHI2cAddrFlag = true; + } + }, + service, object, "org.freedesktop.DBus.Properties", "GetAll", + interface); +} + +static void + getPCHTimerConfiguration(std::shared_ptr<sdbusplus::asio::connection>& conn) +{ + conn->async_method_call( + [&conn]( + boost::system::error_code ec, + const std::vector<std::pair< + std::string, + std::vector<std::pair<std::string, std::vector<std::string>>>>>& + subtree) { + if (ec) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "DBUS response error:cannot get PCH configuration", + phosphor::logging::entry("ECVALUE=%x", ec.value()), + phosphor::logging::entry("ECMESSAGE=%s", + ec.message().c_str())); + return; + } + if (subtree.empty()) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "subtree empty"); + return; + } + getPCHI2cAddr(conn, subtree[0].second[0].first, subtree[0].first, + "xyz.openbmc_project.Configuration.PchSmbusSlave"); + return; + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/", 0, + std::array<const char*, 1>{ + "xyz.openbmc_project.Configuration.PchSmbusSlave"}); + + return; +} + +class PCHSync +{ + private: + bool getPCHDate(uint8_t& year, uint8_t& month, uint8_t& day, uint8_t& hour, + uint8_t& minute, uint8_t& second) + { + try + { + constexpr uint8_t pchDevRegRTCYear = 0x0f; + constexpr uint8_t pchDevRegRTCMonth = 0x0e; + constexpr uint8_t pchDevRegRTCDay = 0x0d; + constexpr uint8_t pchDevRegRTCHour = 0x0b; + constexpr uint8_t pchDevRegRTCMinute = 0x0a; + constexpr uint8_t pchDevRegRTCSecond = 0x09; + I2CFile pchDev(pchDevI2cBusNo, pchDevI2cSlaveAddr, + O_RDWR | O_CLOEXEC); + year = pchDev.i2cReadByteData(pchDevRegRTCYear); + year = bcd2Decimal(year); + if (year > 99) + { + return false; + } + + month = pchDev.i2cReadByteData(pchDevRegRTCMonth); + month = bcd2Decimal(month); + if ((month < 1) || (month > 12)) + { + return false; + } + + day = pchDev.i2cReadByteData(pchDevRegRTCDay); + day = bcd2Decimal(day); + if ((day < 1) || (day > 31)) + { + return false; + } + + hour = pchDev.i2cReadByteData(pchDevRegRTCHour); + hour = bcd2Decimal(hour); + if (hour >= 24) + { + return false; + } + + minute = pchDev.i2cReadByteData(pchDevRegRTCMinute); + minute = bcd2Decimal(minute); + if (minute >= 60) + { + return false; + } + + second = pchDev.i2cReadByteData(pchDevRegRTCSecond); + second = bcd2Decimal(second); + if (second >= 60) + { + return false; + } + } + catch (const std::exception& e) + { + return false; + } + + return true; + } + + bool getSystemTime(time_t& timeSeconds) + { + struct timespec sTime = {0}; + int ret = 0; + + ret = clock_gettime(CLOCK_REALTIME, &sTime); + + if (ret != 0) + { + return false; + } + timeSeconds = sTime.tv_sec; + return true; + } + + bool updateClockFileTimestamp() + { + if (!std::filesystem::exists(clockFile)) + { + phosphor::logging::log<phosphor::logging::level::WARNING>( + "The systemd timestamp synchronization file doesn't exist: ", + phosphor::logging::entry("PATHNAME=%s", clockFile)); + return false; + } + int rc = utimensat(AT_FDCWD, clockFile, nullptr, 0); + if (rc) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "utimensat systemd timestamp synchronization file fail: ", + phosphor::logging::entry("PATHNAME=%s", clockFile), + phosphor::logging::entry("ERRCODE=%x", errno)); + return false; + } + return true; + } + bool setSystemTime(uint32_t timeSeconds) + { + struct timespec sTime = {0}; + int ret = 0; + + sTime.tv_sec = timeSeconds; + sTime.tv_nsec = 0; + + ret = clock_settime(CLOCK_REALTIME, &sTime); + + return (ret == 0); + } + + bool updateBMCTime() + { + int ret = 0; + time_t BMCTimeSeconds = 0; + time_t PCHTimeSeconds = 0; + struct tm tm = {0}; + + // get PCH and system time + + if (!getPCHDate(year, month, day, hour, minute, second)) + { + return false; + }; + if (!getSystemTime(BMCTimeSeconds)) + { + return false; + } + // fix error when year is set to 2000-2009. + std::string dateString = + std::to_string(2000 + year) + "-" + std::to_string(month) + "-" + + std::to_string(day) + " " + std::to_string(hour) + ":" + + std::to_string(minute) + ":" + std::to_string(second); + + strptime(dateString.c_str(), "%Y-%m-%d %H:%M:%S", &tm); + + PCHTimeSeconds = mktime(&tm); + if (PCHTimeSeconds == -1) + { + return false; + } + + if (std::abs(PCHTimeSeconds - BMCTimeSeconds) > timeDiffAllowedSecond) + { + if (!setSystemTime(PCHTimeSeconds)) + { + return false; + } + phosphor::logging::log<phosphor::logging::level::INFO>( + "Update BMC time to: ", + phosphor::logging::entry("TIME=%s", dateString.c_str())); + } + + // During the boot time, systemd-timesyncd.service checks + // "/var/lib/systemd/timesync/clock" and updates the system time with + // the timestamp of the file + if (!updateClockFileTimestamp()) + { + return false; + } + + return true; + } + + void startSyncTimer(std::shared_ptr<sdbusplus::asio::connection>& conn) + { + // retry 10 times (10 * 5s = 50s ) to get the pch timer + // configuration. + static uint8_t retrytimes = 10; + if (!getPCHI2cAddrFlag) + { + if (retrytimes == 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Get pch timer configuration fail"); + return; + } + syncIntervalMS = syncIntervalBootMS; + getPCHTimerConfiguration(conn); + retrytimes--; + } + else + { + if (updateBMCTime()) + { + syncIntervalMS = syncIntervalNormalMS; + } + else + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Update BMC time Fail"); + syncIntervalMS = syncIntervalFastMS; + } + } + + syncTimer->expires_after(std::chrono::milliseconds(syncIntervalMS)); + syncTimer->async_wait( + [this, &conn](const boost::system::error_code& ec) { + if (ec) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Timer cancelled", + phosphor::logging::entry("ECVALUE=%x", ec.value()), + phosphor::logging::entry("ECMESSAGE=%s", + ec.message().c_str())); + return; + } + startSyncTimer(conn); + }); + } + + std::unique_ptr<boost::asio::steady_timer> syncTimer; + uint8_t year, month, day, hour, minute, second; + + public: + PCHSync(boost::asio::io_service& io, + std::shared_ptr<sdbusplus::asio::connection>& conn) + { + syncTimer = std::make_unique<boost::asio::steady_timer>(io); + startSyncTimer(conn); + } + + ~PCHSync() = default; +}; + +int main(int argc, char** argv) +{ + boost::asio::io_service io; + std::shared_ptr<sdbusplus::asio::connection> conn = + std::make_shared<sdbusplus::asio::connection>(io); + sdbusplus::asio::object_server server = + sdbusplus::asio::object_server(conn); + PCHSync pchSyncer(io, conn); + + phosphor::logging::log<phosphor::logging::level::INFO>( + "Starting PCH time sync service"); + + io.run(); + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service new file mode 100644 index 000000000..bf4e2a30e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service @@ -0,0 +1,15 @@ +[Unit] +Description=PCH BMC time sync service +Conflicts=systemd-timesyncd.service +Requires=xyz.openbmc_project.EntityManager.service +After=xyz.openbmc_project.EntityManager.service + +[Service] +Restart=always +RestartSec=10 +ExecStart=/usr/bin/pch-time-sync +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend new file mode 100644 index 000000000..18780dfdd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend @@ -0,0 +1,2 @@ +RDEPENDS_${PN}_remove = "phosphor-settings-manager" +RDEPENDS_${PN} += " settings" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch new file mode 100644 index 000000000..3d2cc43e2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/0027-Apply-Options-interface-for-Software.patch @@ -0,0 +1,47 @@ +From 153b125043c28f933579330727d82658979caef3 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Mon, 18 May 2020 20:16:04 +0530 +Subject: [PATCH] Apply Options interface for Software + +Apply Options interface is used to pass the settings related to +firmware image activation such as ClearConfig. +ClearConfig property is used to denote whether to clear firmware +configurations along with firmware image activation or not. + +Example case: +BIOS usually requires its NVRAM configuration to be updated or +erased for certain BIOS firmware updates. Current implementation +doesn't support to take this option and provide interface to do +the necessary actions. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + .../Software/ApplyOptions.interface.yaml | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + create mode 100644 xyz/openbmc_project/Software/ApplyOptions.interface.yaml + +diff --git a/xyz/openbmc_project/Software/ApplyOptions.interface.yaml b/xyz/openbmc_project/Software/ApplyOptions.interface.yaml +new file mode 100644 +index 0000000..45a68ab +--- /dev/null ++++ b/xyz/openbmc_project/Software/ApplyOptions.interface.yaml +@@ -0,0 +1,16 @@ ++description: > ++ To implement the Activation apply options for a newly uploaded firmware ++ image. The apply options property is global and is specifically used with ++ each firmware update and is used during firmware activation. ++ ApplyOptions usage during firmware activation is implementation specific, ++ not all firmware targets need ApplyOptions. ++ The default value of this property is false. ++properties: ++ - name: ClearConfig ++ type: boolean ++ default: false ++ description: > ++ This property indicates whether to clear the software configurations ++ when the firmware image update is getting applied. A value of true ++ indicates the firmware configurations should be cleared along with ++ firmware image activation. +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch new file mode 100644 index 000000000..c87b2d89d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch @@ -0,0 +1,32 @@ +From 49debd0955b672d591f35e74119b288bd6df2992 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 11:40:49 +0800 +Subject: [PATCH] [ipmi] set BIOS id + +change#2 +add new dbus interface for BIOS attributes + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + xyz/openbmc_project/Inventory/Item/Bios.interface.yaml | 9 +++++++++ + 1 file changed, 9 insertions(+) + create mode 100644 xyz/openbmc_project/Inventory/Item/Bios.interface.yaml + +diff --git a/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml +new file mode 100644 +index 0000000..d7a6b95 +--- /dev/null ++++ b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml +@@ -0,0 +1,9 @@ ++description: > ++ Implement to provide BIOS attributes. ++properties: ++ - name: BiosId ++ type: string ++ description: > ++ BIOS ID (version) string ++ ++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch new file mode 100644 index 000000000..2c9344306 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch @@ -0,0 +1,34 @@ +From 631deef0ca88a77283741edeae8078d2185f414c Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 10 Aug 2018 16:23:13 +0800 +Subject: [PATCH] Increase the default watchdog timeout value + +The default timeout for poweron is 30 seconds, +but currently the host power on needs 120+ seconds +due to unimplemented ipmi commands for BIOS. + +Increase the value as a workaround, +to avoid the watchdog timeout during power on. +Will adjust this value in the future + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index f76dbf2..402e1a8 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -37,7 +37,7 @@ properties: + type: uint64 + description: > + Time interval to arm the watchdog, in milli-second. +- default: 30000 ++ default: 600000 + - name: TimeRemaining + type: uint64 + description: > +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch new file mode 100644 index 000000000..9052435ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch @@ -0,0 +1,34 @@ +From eeac4cf4528994aeb213d549daf4c033ac9d3bbc Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 24 Aug 2018 17:55:35 +0800 +Subject: [PATCH] Add RestoreDelay interface for power restore delay + +Which provide one property "PowerRestoreDelay" + +Change-Id: I4e6d3e45948b1e288301b4aa52cc08cace4f1bc2 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../Control/Power/RestoreDelay.interface.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml +new file mode 100644 +index 0000000..55ee80a +--- /dev/null ++++ b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml +@@ -0,0 +1,11 @@ ++description: > ++ Implement to specify power transition behavior on a BMC reset. ++ The implementation based on restore policy and set a delay time ++ for power restore. ++ ++properties: ++ - name: PowerRestoreDelay ++ type: uint16 ++ description: > ++ The delay time for power restore. ++ Power Restore Delay is NOT applied on power policy is "Always Off" +-- +2.17.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch new file mode 100644 index 000000000..9471c7ab2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch @@ -0,0 +1,86 @@ +From 7260c24b201759f3a5168eebfee215072c13e641 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Thu, 30 Aug 2018 16:22:43 +0800 +Subject: [PATCH] Add ErrConfig.yaml interface for processor error + configuration. + +Which provide 3 properties: + ResetCfg + type: byte + description: > + Reset Configuration + [0]: CATERR Reset Enabled + 0b: Disabled + 1b: Enabled + [1]: ERR2 Reset Enabled + 0b: Disabled + 1b: Enabled + [7:2]: Reserved + ResetErrorOccurrenceCounts + type: byte + description: > + Reset Error Occurrence Counts + [0]: Reset CPU Error Counts + 0b: Keep CPU Error Counts + 1b: Reset all CPU Error Counts to zero + [7:1]: Reserved + CATERRStatus + type: array[byte] + description: > + For all CPUs including the non-legacy socket CPU + CPU CATERR (Core Error) occurrence + [5:0]: Error Occurrence Count + [7:6]: CPU Status + 00b: Disabled + 01b: Enabled + 11b: Not Present + +Change-Id: Ibc5a7a5e15c998e56c04e23b1043d99243a91171 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../Processor/ErrConfig.interface.yaml | 33 +++++++++++++++++++ + 1 file changed, 33 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml +new file mode 100644 +index 0000000..2304263 +--- /dev/null ++++ b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml +@@ -0,0 +1,33 @@ ++description: > ++ This defines processor error configuration. ++properties: ++ - name: ResetCfg ++ type: byte ++ description: > ++ Reset Configuration ++ [0]: CATERR Reset Enabled ++ 0b: Disabled ++ 1b: Enabled ++ [1]: ERR2 Reset Enabled ++ 0b: Disabled ++ 1b: Enabled ++ [7:2]: Reserved ++ ++ - name: ResetErrorOccurrenceCounts ++ type: byte ++ description: > ++ Reset Error Occurrence Counts ++ [0]: Reset CPU Error Counts ++ 0b: Keep CPU Error Counts ++ 1b: Reset all CPU Error Counts to zero ++ [7:1]: Reserved ++ - name: CATERRStatus ++ type: array[byte] ++ description: > ++ For all CPUs including the non-legacy socket CPU ++ CPU CATERR (Core Error) occurrence ++ [5:0]: Error Occurrence Count ++ [7:6]: CPU Status ++ 00b: Disabled ++ 01b: Enabled ++ 11b: Not Present +-- +2.17.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch new file mode 100644 index 000000000..67fa59090 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch @@ -0,0 +1,57 @@ +From 6e9a19c43acac7d4254910906329d98d7b59085a Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Fri, 24 May 2019 14:55:10 +0800 +Subject: [PATCH] Add the pre-timeout interrupt defined in IPMI spec + +The IPMI watchdog pre-timeout interrupt is used to set the different +pre-timeout interrupt source. Add them as a dbus property, +IPMI set/get watchdog commands will use it. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index 2fc47d8..6dfa9b9 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -33,6 +33,11 @@ properties: + description: > + The action the watchdog should perform when it expires. + default: 'HardReset' ++ - name: PreTimeoutInterrupt ++ type: enum[self.PreTimeoutInterruptAction] ++ description: > ++ The BMC generates the selected interrupt before the timer expires. ++ default: 'None' + - name: Interval + type: uint64 + description: > +@@ -73,6 +78,23 @@ enumerations: + description: > + Perform a power cycle of the system. + ++ - name: PreTimeoutInterruptAction ++ description: > ++ The type of PreTimeout Interrupt. ++ values: ++ - name: 'None' ++ description: > ++ Do nothing. ++ - name: 'SMI' ++ description: > ++ SMI. ++ - name: 'NMI' ++ description: > ++ NMI / Diagnostic Interrupt. ++ - name: 'MI' ++ description: > ++ Messaging Interrupt. ++ + - name: TimerUse + description: > + The type of timer use. +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch new file mode 100644 index 000000000..d7e66abd2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch @@ -0,0 +1,39 @@ +From b7c487750c05dcc081219ccdd4ef539beef6aa30 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Mon, 29 Jul 2019 10:51:12 +0800 +Subject: [PATCH] Add PreInterruptFlag properity in DBUS. + +PreTimeoutInterruptOccurFlag in DBUS would be set 'true' +when watchdog pre-timeout interrupt occurred. + +Tested: +Enable command(raw 0x06 0x31) that get message flag +can set right bit about watchdog, +need record PreTimeoutInterruptOccurFlag +at xyz.openbmmc_project.State.Watchdog when watchdog +pre-timeout interrupt occurred. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index bf4cca0..6579368 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -59,6 +59,11 @@ properties: + description: > + The timer user at the time of expiration. + default: 'Reserved' ++ - name: PreTimeoutInterruptOccurFlag ++ type: boolean ++ description: > ++ PreTimeoutInterruptOccurFlag that preTimeoutInterrupt action occurred. ++ default: false + + enumerations: + - name: Action +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch new file mode 100644 index 000000000..36c63ec58 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch @@ -0,0 +1,55 @@ +From 0d6556539be9bda478a3cabb6127eace5764fa11 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Wed, 15 Jan 2020 10:01:04 +0800 +Subject: [PATCH] Add StandbySpare support for software inventory + +Add support to allow update for active / recovery +regions of specified firmware. This update enables +the backend modules to advertise whether the +software object is active or recovery (StandbySpare) +image. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + xyz/openbmc_project/Software/Activation.interface.yaml | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/xyz/openbmc_project/Software/Activation.interface.yaml b/xyz/openbmc_project/Software/Activation.interface.yaml +index efeeeb6..6c9ce75 100644 +--- a/xyz/openbmc_project/Software/Activation.interface.yaml ++++ b/xyz/openbmc_project/Software/Activation.interface.yaml +@@ -28,12 +28,20 @@ enumerations: + - name: Activating + description: > + The Software.Version is in the process of being Activated. ++ - name: ActivatingAsStandbySpare ++ description: > ++ The Software.Version is in the process of being processed ++ as StandbySpare. + - name: Active + description: > + The Software.Version is currently Active. + - name: Failed + description: > + The Software.Version failed during or after Activation. ++ - name: StandbySpare ++ description: > ++ The Software.Version is part of a redundancy set and awaits ++ a failover or external action to activate. + - name: Staged + description: > + The Software.Version is currently in staged flash area. +@@ -48,6 +56,10 @@ enumerations: + - name: Active + description: > + The Software.Version has been requested for Activation. ++ - name: StandbySpare ++ description: > ++ The Software.Version has been requested to be enabled as ++ StandbySpare. + # TODO: Specify "EAGAIN" type error when requested is unable to be acted on + # due to current system state. Currently, sdbusplus does not support + # errors on properties. +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch new file mode 100644 index 000000000..e6afc0117 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0028-MCTP-Daemon-D-Bus-interface-definition.patch @@ -0,0 +1,457 @@ +From 65d1772312a76ebfdac6391bb97287c62f18c43f Mon Sep 17 00:00:00 2001 +From: "Kowalski, Mariusz" <mariusz.kowalski@intel.com> +Date: Thu, 27 Feb 2020 15:48:56 +0100 +Subject: [PATCH] MCTP Daemon D-Bus interface definition. + +This interface definition was created on base of the MCTP design +proposed in this document: +https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/28424/9/designs/mctp.md + +Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com> +Signed-off-by: Mariusz Kowalski <mariusz.kowalski@intel.com> +Signed-off-by: Karol Wachowski <karol.wachowski@intel.com> +Change-Id: Ida66f8ffcf00003655edcb0fb0112202797b8e1a +--- + xyz/openbmc_project/MCTP/Base.interface.yaml | 227 ++++++++++++++++++ + .../MCTP/Binding/PCIe.interface.yaml | 29 +++ + .../MCTP/Binding/SMBus.interface.yaml | 17 ++ + .../MCTP/BusOwner.interface.yaml | 17 ++ + .../MCTP/Endpoint.interface.yaml | 13 + + xyz/openbmc_project/MCTP/README.md | 43 ++++ + .../MCTP/SupportedMessageTypes.interface.yaml | 36 +++ + 7 files changed, 382 insertions(+) + create mode 100644 xyz/openbmc_project/MCTP/Base.interface.yaml + create mode 100644 xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml + create mode 100644 xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml + create mode 100644 xyz/openbmc_project/MCTP/BusOwner.interface.yaml + create mode 100644 xyz/openbmc_project/MCTP/Endpoint.interface.yaml + create mode 100644 xyz/openbmc_project/MCTP/README.md + create mode 100644 xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml + +diff --git a/xyz/openbmc_project/MCTP/Base.interface.yaml b/xyz/openbmc_project/MCTP/Base.interface.yaml +new file mode 100644 +index 0000000..9438551 +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/Base.interface.yaml +@@ -0,0 +1,227 @@ ++description: > ++ Mandatory interface for each instance of the MCTP Daemon to expose ++ the base MCTP daemon and medium type interfaces. ++ ++methods: ++ - name: SendMctpMessagePayload ++ description: > ++ Sends message over MCTP interface ++ parameters: ++ - name: DestinationEID ++ type: byte ++ description: > ++ Destination Endpoint ID. The logical address used to route MCTP ++ messages to a specific MCTP endpoint. ++ - name: MsgTag ++ type: byte ++ description: > ++ Message tag. Field that, along with the Source Endpoint IDs and the ++ Tag Owner (TO) field, identifies a unique message at the MCTP ++ transport level. ++ - name: TagOwner ++ type: boolean ++ description: > ++ Tag Owner bit identifies whether the message tag was originated by ++ the endpoint that is the source of the message or by the endpoint ++ that is the destination of the message. ++ - name: Payload ++ type: array[byte] ++ description: Payload of message. ++ returns: ++ - name: Status ++ type: byte ++ description: 0 - if success ++ errors: ++ - xyz.openbmc_project.Common.Error.Timeout ++ - xyz.openbmc_project.Common.Error.InvalidArgument ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ ++ - name: SendMctpMessageFileDescriptor ++ description: > ++ Sends message over MCTP interface ++ parameters: ++ - name: DestinationEID ++ type: byte ++ description: > ++ Destination Endpoint ID. The logical address used to route MCTP ++ messages to a specific MCTP endpoint. ++ - name: MsgTag ++ type: byte ++ description: > ++ Message tag. Field that, along with the Source Endpoint IDs and the ++ Tag Owner (TO) field, identifies a unique message at the MCTP ++ transport level. ++ - name: TagOwner ++ type: boolean ++ description: > ++ Tag Owner bit identifies whether the message tag was originated by ++ the endpoint that is the source of the message or by the endpoint ++ that is the destination of the message. ++ - name: FileDescriptor ++ type: unixfd ++ description: File descriptor of message. ++ returns: ++ - name: Status ++ type: byte ++ description: 0 - if success ++ errors: ++ - xyz.openbmc_project.Common.Error.Timeout ++ - xyz.openbmc_project.Common.Error.InvalidArgument ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ ++signals: ++ - name: MessageReceivedSignal ++ description: > ++ Signal indicating upper layers about arrival of a MCTP message. ++ properties: ++ - name: MessageType ++ type: enum[self.MessageTypes] ++ description: > ++ Defines the values for the Message Type field for different message ++ types transported through MCTP. ++ - name: SrcEid ++ type: byte ++ description: > ++ Source Endpoint ID. The logical address used to route MCTP messages ++ to a specific MCTP endpoint. ++ - name: MsgTag ++ type: byte ++ description: > ++ Message tag. Field that, along with the Source Endpoint IDs and the ++ Tag Owner (TO) field, identifies a unique message at the MCTP ++ transport level. ++ - name: TagOwner ++ type: boolean ++ description: > ++ Tag Owner bit identifies whether the message tag was originated by ++ the endpoint that is the source of the message or by the endpoint ++ that is the destination of the message. ++ - name: Payload ++ type: array[byte] ++ description: Payload of message. ++ ++properties: ++ - name: Eid ++ type: byte ++ description: > ++ Endpoint ID. The logical address used to route MCTP messages to a ++ specific MCTP endpoint. ++ ++ - name: BindingID ++ type: enum[self.BindingTypes] ++ ++ - name: BindingMediumID ++ type: enum[self.MctpPhysicalMediumIdentifiers] ++ ++ - name: StaticEid ++ type: boolean ++ description: Support for statically/dynamicly allocated IDs ++ ++ - name: BindingMode ++ type: enum[self.BindingModeTypes] ++ description: Bus Owner / Endpoint / Bridge ++ ++enumerations: ++ - name: BindingTypes ++ description: > ++ All other values than described are reserved. ++ values: ++ - name: MctpOverSmbus ++ - name: MctpOverPcieVdm ++ - name: MctpOverUsb ++ description: Reserved for MCTP over USB ++ - name: MctpOverKcs ++ - name: MctpOverSerial ++ - name: VendorDefined ++ ++ - name: MctpPhysicalMediumIdentifiers ++ description: > ++ Identifies MCTP physical medium identifiers. see DSP0239. ++ values: ++ - name: Smbus ++ descritpion: SMBus 2.0 100 kHz compatible ++ - name: SmbusI2c ++ descritpion: SMBus 2.0 + I2C 100 kHz compatible ++ - name: I2cCompatible ++ description: I2C 100 kHz compatible (Standard-mode) ++ - name: Smbus3OrI2c400khzCompatible ++ description: SMBus 3.0 or I2C 400 kHz compatible (Fast-mode) ++ - name: Smbus3OrI2c1MhzCompatible ++ description: SMBus 3.0 or I2C 1 MHz compatible (Fast-mode Plus) ++ - name: I2c3Mhz4Compatible ++ description: I2C 3.4 MHz compatible (High-speed mode) ++ - name: Pcie11 ++ description: PCIe revision 1.1 compatible ++ - name: Pcie2 ++ description: PCIe revision 2.0 compatible ++ - name: Pcie21 ++ description: PCIe revision 2.1 compatible ++ - name: Pcie3 ++ description: PCIe revision 3.0 compatible ++ - name: Pcie4 ++ description: PCIe revision 4.0 compatible ++ - name: Pcie5 ++ description: PCIe revision 4.0 compatible ++ - name: PciCompatible ++ description: > ++ PCI compatible (PCI 1.0,2.0,2.1,2.2,2.3,3.0,PCI-X 1.0, PCI-X 2.0) ++ - name: Usb11Compatible ++ description: USB 1.1 compatible ++ - name: Usb20Compatible ++ description: USB 2.0 compatible ++ - name: Usb30Compatible ++ description: USB 3.0 compatible ++ - name: NcSiOverRbt ++ description: > ++ NC-SI over RBT (A physical interface based on RMII as defined in ++ DSP0222) ++ - name: KcsLegacy ++ description: KCS1 / Legacy (Fixed Address Decoding) ++ - name: KcsPci ++ description: KCS1 / PCI (Base Class 0xC0 Subclass 0x01) ++ - name: SerialHostLegacy ++ description: Serial Host2 / Legacy (Fixed Address Decoding) ++ - name: SerialHostPci ++ description: Serial Host2 / PCI (Base Class 0x07 Subclass 0x00) ++ - name: AsynchronousSerial ++ description: Asynchronous Serial (Between MCs and IMDs) ++ - name: I3cSDR ++ description: I3C 12.5 MHz compatible (SDR) ++ - name: I3cHDRDDR ++ description: I3C 25 MHz compatible (HDR-DDR) ++ ++ - name: BindingModeTypes ++ values: ++ - name: Endpoint ++ description: > ++ An MCTP communication terminus. An MCTP endpoint is a terminus or ++ origin of MCTP packets or messages. That is, the combined ++ functionality within a physical device that communicates using the ++ MCTP transport protocol and handles MCTP control commands. This ++ includes MCTP-capable management controllers and managed devices. ++ Also referred to in this document as "endpoint". ++ - name: BusOwner ++ description: > ++ The party responsible for managing address assignments (can be ++ logical or physical addresses) on a bus (for example, in MCTP, the ++ bus owner is the party responsible for managing EID assignments for ++ a given bus). A bus owner may also have additional media-specific ++ responsibilities, such as assignment of physical addresses. ++ - name: Bridge ++ description: > ++ An MCTP endpoint that can route MCTP messages not destined for ++ itself that it receives on one interconnect onto another without ++ interpreting them. The ingress and egress media at the bridge may ++ be either homogeneous or heterogeneous. Also referred to in this ++ document as a "bridge". ++ ++ - name: MessageTypes ++ values: ++ - name: MctpControl ++ - name: PLDM ++ - name: NCSI ++ - name: Ethernet ++ - name: NVMeMgmtMsg ++ - name: SPDM ++ - name: VDPCI ++ - name: VDIANA +diff --git a/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml b/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml +new file mode 100644 +index 0000000..1bd2881 +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml +@@ -0,0 +1,29 @@ ++description: > ++ Interface exposed by MCTP daemon for PCIe binding ++ ++properties: ++ - name: DiscoveredFlag ++ type: enum[self.DiscoveryFlags] ++ description: > ++ Each endpoint (except the bus owner) on the PCIe bus maintains an ++ internal flag called the Discovered flag. The flag is set to the ++ discovered state when the Set Endpoint ID command is received. ++ ++ - name: BDF ++ type: uint16 ++ description: > ++ Byte 1 [7:0] Bus number ++ Byte 2 [7:3] Device number [2:0] Function Number ++ ++enumerations: ++ - name: DiscoveryFlags ++ description: > ++ The Prepare for Endpoint Discovery message causes each recipient ++ endpoint on the PCIe bus to set their respective Discovered flag to ++ the undiscovered state. For the Prepare for Endpoint Discovery request ++ message, the routing in the physical transport header should be set to ++ 011b (Broadcast from Root Complex). ++ values: ++ - name: Discovered ++ - name: Undiscovered ++ - name: NotApplicable +diff --git a/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml b/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml +new file mode 100644 +index 0000000..9219ad0 +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml +@@ -0,0 +1,17 @@ ++description: > ++ Interface exposed by MCTP daemon for SMBus binding ++ ++properties: ++ - name: ArpMasterSupport ++ type: boolean ++ description: > ++ The SMBus binding can also run ARP Master protocol and ++ assign SMBus addresses to the devices on the bus. ++ ++ - name: BusNumber ++ type: byte ++ description: I2C bus number of the medium used ++ ++ - name: SlaveAddress ++ type: byte ++ description: Slave address to be used for this medium +diff --git a/xyz/openbmc_project/MCTP/BusOwner.interface.yaml b/xyz/openbmc_project/MCTP/BusOwner.interface.yaml +new file mode 100644 +index 0000000..d46298e +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/BusOwner.interface.yaml +@@ -0,0 +1,17 @@ ++description: > ++ Interface exposed by MCTP root object, when executing in Bus Owner mode. ++ ++properties: ++ - name: EidPool ++ type: array[struct[byte, byte]] ++ description: > ++ Pool of allowed EIDs to be used. ++ EID pool of 10-100 can be specified as {{10,100}}. ++ ++ - name: TopMostBusOwner ++ type: boolean ++ description: To indicate whether BMC is topmost Bus Owner ++ ++ - name: OwnEidPool ++ type: boolean ++ description: Indicates Eid pool is managed by self +diff --git a/xyz/openbmc_project/MCTP/Endpoint.interface.yaml b/xyz/openbmc_project/MCTP/Endpoint.interface.yaml +new file mode 100644 +index 0000000..e4ba4d0 +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/Endpoint.interface.yaml +@@ -0,0 +1,13 @@ ++description: ++ Interface exposed by discovered MCTP endpoints. ++ ++properties: ++ - name: Mode ++ type: enum[xyz.openbmc_project.MCTP.Base.BindingModeTypes] ++ description: Endpoint / BusOwner / Bridge ++ ++ - name: NetworkId ++ type: uint16 ++ description: > ++ MCTP network ID a unique identifier to distinguish each independent ++ MCTP network within a platform. +diff --git a/xyz/openbmc_project/MCTP/README.md b/xyz/openbmc_project/MCTP/README.md +new file mode 100644 +index 0000000..c819dbb +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/README.md +@@ -0,0 +1,43 @@ ++# MCTP Daemon ++ ++## Overview ++MCTP service exposes D-Bus methods / properties / signals for managing ++MCTP devices or work as MCTP Endpoint. MCTP daemon will either ++work in Bus Owner or Endpoint mode for the specified physical medium. ++ ++### MCTP service ++MCTP service can be started either in Bus Owner mode or Endpoint mode. ++It will expose following objects. ++1. Base object ++2. MCTP Endpoints (discovered in case of Bus Owner mode, queried using ++routing table in case of Endpoint mode) ++Please refer individual yaml file for details about the ++methods / signals / properties exposed in the interfaces. ++ ++#### Base object ++Exposed under the path `/xyz/openbmc_project/mctp` with the following ++interfaces. ++1. `xyz.openbmc_project.MCTP.Base` which exposes all the common properties ++needed for MCTP Daemon. ++2. `xyz.openbmc_project.MCTP.BusOwner` available only in Bus Owner mode ++which exposes the properties needed by Bus Owner MCTP Daemon. ++3. `xyz.openbmc_project.MCTP.SupportedMessageTypes` which exposes the message ++types supported. ++4. Binding interface `xyz.openbmc_project.MCTP.Binding.PCIe` or ++`xyz.openbmc_project.MCTP.Binding.SMBus` as per the physical medium in which ++this MCTP Daemon is instantiated. ++5. Common UUID interface `xyz.openbmc_project.Common.UUID` which exposes UUID ++in RFC4122 format. ++ ++#### Endpoint object ++Exposed under the path `/xyz/openbmc_project/mctp/device/<eid>` with the ++following interfaces. ++1. `xyz.openbmc_project.MCTP.SupportedMessageTypes` which exposes supported MCTP ++message types for the discovered MCTP Endpoint. ++2. `xyz.openbmc_project.MCTP.Endpoint` which exposes properties like Network ID ++and endpoint mode (to identify Bus Owner or Bridge or Endpoint) for the discovered ++MCTP Endpoint. ++3. `xyz.openbmc_project.MCTP.Bridge` available only for discovered MCTP Bridges to ++expose properties like EID pool. (TBD) ++4. Common UUID interface `xyz.openbmc_project.Common.UUID` which exposes UUID ++in RFC4122 format. +diff --git a/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml b/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml +new file mode 100644 +index 0000000..fa447ee +--- /dev/null ++++ b/xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml +@@ -0,0 +1,36 @@ ++description: ++ Interface used to represent the supported MCTP message types. ++ This will be exposed by all MCTP endpoints. ++ ++properties: ++ - name: MctpControl ++ type: boolean ++ description: Indicates support availability ++ ++ - name: PLDM ++ type: boolean ++ description: Indicates support availability ++ ++ - name: NCSI ++ type: boolean ++ description: Indicates support availability ++ ++ - name: Ethernet ++ type: boolean ++ description: Indicates support availability ++ ++ - name: NVMeMgmtMsg ++ type: boolean ++ description: Indicates support availability ++ ++ - name: SPDM ++ type: boolean ++ description: Indicates support availability ++ ++ - name: VDPCI ++ type: boolean ++ description: Indicates support availability ++ ++ - name: VDIANA ++ type: boolean ++ description: Indicates support availability +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch new file mode 100644 index 000000000..5ee550eaa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch @@ -0,0 +1,494 @@ +From e7ba5f63a551099e1b5f934683e163963f28f28e Mon Sep 17 00:00:00 2001 +From: "Gade-RajasekharReddy@" <raja.sekhar.reddy.gade@linux.intel.com> +Date: Wed, 16 Sep 2020 03:19:41 +0530 +Subject: [PATCH] Add D-Bus interfaces for PLDM FW update + +Added PLDM FW update base interface, which exposes a method. Using +this method PLDM FWU can be initiated. + +Added interfaces for exposing PLDM FW update inventory info. + +Test +supporting files are created for the yaml files. + +Signed-off-by: Gade-RajasekharReddy@ <raja.sekhar.reddy.gade@linux.intel.com> +--- + .../PLDM/FWU/ACPIDescriptor.interface.yaml | 14 +++ + ...ActiveComponentImageSetInfo.interface.yaml | 9 ++ + .../FWU/ActiveComponentInfo.interface.yaml | 55 ++++++++++ + .../CapabilitiesDuringUpdate.interface.yaml | 32 ++++++ + .../ComponentActivationMethods.interface.yaml | 40 +++++++ + .../PLDM/FWU/FWUBase.interface.yaml | 21 ++++ + .../PLDM/FWU/IANADescriptor.interface.yaml | 10 ++ + .../PLDM/FWU/PCIDescriptor.interface.yaml | 30 +++++ + ...endingComponentImageSetInfo.interface.yaml | 10 ++ + .../FWU/PendingComponentInfo.interface.yaml | 40 +++++++ + .../PLDM/FWU/PnPDescriptor.interface.yaml | 14 +++ + xyz/openbmc_project/PLDM/FWU/README.md | 103 ++++++++++++++++++ + 12 files changed, 378 insertions(+) + create mode 100644 xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml + create mode 100644 xyz/openbmc_project/PLDM/FWU/README.md + +diff --git a/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml b/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml +new file mode 100644 +index 0000000..e225bad +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml +@@ -0,0 +1,14 @@ ++description : > ++ This interface has ACPI descriptor properties. ++ ++properties : ++ ++ - name : ACPIVendorID ++ type : string ++ description: > ++ Property containing ACPI Vendor ID. ++ ++ - name : ACPIProductIdentifier ++ type : string ++ description: > ++ Property containing ACPI Product Identifier. +diff --git a/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml b/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml +new file mode 100644 +index 0000000..94115a3 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml +@@ -0,0 +1,9 @@ ++description : > ++ This interface has the PLDM FWU active component image set properties. ++ ++properties : ++ ++ - name : ActiveComponentImageSetVersionString ++ type : string ++ description: > ++ String describing the active component image set version. +diff --git a/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml b/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml +new file mode 100644 +index 0000000..77a7566 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml +@@ -0,0 +1,55 @@ ++description: > ++ This interface has the component entries for all of the updatable ++ active components that reside on the FD. ++ ++properties: ++ ++ - name: ComponentClassification ++ type: uint16 ++ description: > ++ Vendor specific component classification information. ++ Special values: 0x0000, 0xFFFF are reserved. ++ ++ - name: ComponentIdentifier ++ type: uint16 ++ description: > ++ FD vendor selected unique value to distinguish between ++ component images. ++ ++ - name: ComponentClassificationIndex ++ type: byte ++ description: > ++ Used to distinguish identical components that have the same ++ classification and identifier that can use the same component ++ image but the images are stored in different locations in the FD. ++ ++ - name: ActiveComponentComparisonStamp ++ type: uint32 ++ description: > ++ Optional Firmware component comparison stamp that is currently ++ active. If the firmware component does not provide a component ++ comparison stamp, this value should be set to 0x00000000. ++ ++ - name: ActiveComponentReleaseDate ++ type: string ++ description: > ++ Containing the date corresponding to the component version ++ level being reported – Format YYYYMMDD. ++ If the firmware component does not provide a date, this string ++ shall be empty. ++ ++ - name: ComponentAutoApply ++ type: boolean ++ description: > ++ Firmware Device performs an ‘auto-apply’ during transfer ++ phase and apply step will be completed immediately if this ++ property is true. ++ Firmware Device will execute an operation during the APPLY ++ state that will include migrating the new component image to its ++ final non-volatile storage destination if this property is ++ false. ++ ++ - name: ActiveComponentVersionString ++ type: string ++ description: > ++ String describing the active component version. +diff --git a/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml b/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml +new file mode 100644 +index 0000000..36560ff +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml +@@ -0,0 +1,32 @@ ++description : > ++ This interface describes the capabilities during update. ++ ++properties : ++ ++ - name : UpdateModeRestrictions ++ type : boolean ++ description: > ++ This property tells whether update mode restrictions are ++ supported or not. ++ ++ - name : PartialUpdates ++ type : boolean ++ description: > ++ This property tells whether partial updates are supported or not. ++ ++ - name : HostFunctionalityDuringFirmwareUpdate ++ type : boolean ++ description: > ++ This property tells whether the host device functionality ++ during firmware update is reduced or not. ++ ++ - name : ComponentUpdateFailureRetryCapability ++ type : boolean ++ description: > ++ This property shows the component update failure retry capability. ++ ++ - name : ComponentUpdateFailureRecoveryCapability ++ type : boolean ++ description: > ++ This property shows the component update failure recovery ++ capability. +diff --git a/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml b/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml +new file mode 100644 +index 0000000..d5ec47c +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml +@@ -0,0 +1,40 @@ ++description: > ++ This interface has the component activation methods. ++ ++properties: ++ ++ - name: ACPowerCycle ++ type: boolean ++ description: > ++ Property that tells whether AC power cycle is an activation ++ method or not. ++ ++ - name: DCPowerCycle ++ type: boolean ++ description: > ++ Property that tells whether DC power cycle is an activation ++ method or not. ++ ++ - name: SystemReboot ++ type: boolean ++ description: > ++ Property that tells whether System reboot is an activation ++ method or not. ++ ++ - name: MediumSpecificReset ++ type: boolean ++ description: > ++ Property that tells whether Medium-specific reset is an ++ activation method or not. ++ ++ - name: SelfContained ++ type: boolean ++ description: > ++ Property that tells whether Self-Contained option is activation ++ method or not. ++ ++ - name: Automatic ++ type: boolean ++ description: > ++ Property that tells whether the component can be activated ++ automatically once apply completes. +diff --git a/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml b/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml +new file mode 100644 +index 0000000..2ba15e2 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml +@@ -0,0 +1,21 @@ ++description: > ++ This interface provides a method to initiate the PLDM FW update. ++ ++methods: ++ - name: StartFWUpdate ++ description: > ++ This method initiates the PLDM FW update. ++ parameters: ++ - name: filePath ++ type: string ++ description: > ++ PLDM FW update package path. ++ returns: ++ - name: status ++ type: byte ++ description: > ++ PLDM FW update status. ++ errors: ++ - xyz.openbmc_project.Common.Error.NotAllowed ++ - xyz.openbmc_project.Common.Error.InvalidArgument ++ - xyz.openbmc_project.Common.Error.ResourceNotFound +diff --git a/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml b/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml +new file mode 100644 +index 0000000..c013955 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml +@@ -0,0 +1,10 @@ ++description : > ++ This interface has device identification info, in which IANA ++ Enterprise ID is used as descriptor. ++ ++properties : ++ ++ - name : IANAEnterpriseID ++ type : string ++ description: > ++ Property containing the IANA Enterprise ID. +diff --git a/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml b/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml +new file mode 100644 +index 0000000..8d758ed +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml +@@ -0,0 +1,30 @@ ++description : > ++ This interface has device identification info,in which PCI Vendor ID ++ is used as descriptor. ++ ++properties : ++ ++ - name : PCIVendorID ++ type : string ++ description: > ++ Property containing the PCI Vendor ID. ++ ++ - name : PCIDeviceID ++ type : string ++ description: > ++ Property containing the PCI Device ID. ++ ++ - name : PCISubsystemVendorID ++ type : string ++ description: > ++ Property containing the PCI Subsystem Vendor ID. ++ ++ - name : PCISubsystemID ++ type : string ++ description: > ++ Property containing the PCI Subsystem ID. ++ ++ - name : PCIRevisionID ++ type : string ++ description: > ++ Property containing the PCI Revision ID. +diff --git a/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml b/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml +new file mode 100644 +index 0000000..3861572 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml +@@ -0,0 +1,10 @@ ++description : > ++ This interface has the PLDM FWU pending component image set ++ properties. ++ ++properties : ++ ++ - name : PendingComponentImageSetVersionString ++ type : string ++ description: > ++ String describing the pending component image set version. +diff --git a/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml b/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml +new file mode 100644 +index 0000000..59a2ad8 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml +@@ -0,0 +1,40 @@ ++description: > ++ This interface has the component entries for all of the pending ++ components that reside on the FD. ++ ++properties: ++ ++ - name: PendingComponentComparisonStamp ++ type: uint32 ++ description: > ++ Optional firmware component comparison stamp that is pending ++ activation. This field, and all other pending component fields, ++ are valid once the firmware device has received the ++ ActivateFirmware command to prepare the firmware component for ++ activation, but the activation method requires further action ++ to enable the pending image to become the actively running code ++ image. ++ If no pending firmware component exists, this value shall be ++ set to 0x00000000 ++ ++ - name: PendingComponentReleaseDate ++ type: string ++ description: > ++ Eight byte field containing the date corresponding to the ++ component version level being reported – Format YYYYMMDD. ++ If no pending firmware component exists, this string ++ shall be empty. ++ ++ ++ - name: PendingComponentVersionString ++ type: string ++ description: > ++ Firmware component version, which is pending activation. The ++ version reported here should be the one that will become active ++ on the next initialization or activation of the component. The ++ pending component version value may be same as the active ++ component version. Contains a variable type string describing ++ the pending component version. Refer to ++ PendingComponentComparisonStamp field for additional details. ++ If no pending firmware component exists, this field is zero ++ bytes in length. +diff --git a/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml b/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml +new file mode 100644 +index 0000000..801db6d +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml +@@ -0,0 +1,14 @@ ++description : > ++ This interface has PnP descriptor properties. ++ ++properties : ++ ++ - name : PnPVendorID ++ type : string ++ description: > ++ Property containing the PnP Vendor ID. ++ ++ - name : PnPProductIdentifier ++ type : string ++ description: > ++ Property containing the PnP Product Identifier. +diff --git a/xyz/openbmc_project/PLDM/FWU/README.md b/xyz/openbmc_project/PLDM/FWU/README.md +new file mode 100644 +index 0000000..2931739 +--- /dev/null ++++ b/xyz/openbmc_project/PLDM/FWU/README.md +@@ -0,0 +1,103 @@ ++#PLDM FW Update ++ ++##Overview ++ ++The PLDM FW update package contains two major sections: the FW package ++header, and the FW package payload. The FW package header is required to ++describe the target device that the package is intended to update and ++the component images that the FW update package contains. The FW ++package payload is the actual FW image which can be used by FW device ++for FW update. ++ ++Update Agent(BMC) will send the inventory commands to the all the ++devices which are capable of PLDM FW update and exposes the inventory ++info to the D-Bus. How PLDM FW update package reaches BMC is out of ++scope of PLDM FWU spec 1.0.1. Once BMC receives the FW package, it ++matches the package header with the inventory info, if matches proceeds ++for FW update. ++ ++###PLDM FW update interfaces overview and hierarchy ++ ++/xyz/openbmc_project/pldm/fwu ++|--xyz.openbmc_project.PLDM.FWU.FWUBase ++| ++|__/xyz/openbmc_project/pldm/fwu/<tid> ++ | ++ |__/xyz/openbmc_project/pldm/fwu/<tid>/deviceDescriptors ++ | |--xyz.openbmc_project.PLDM.FWU.PCIDescriptor ++ | |--xyz.openbmc_project.PLDM.FWU.IANADescriptor ++ | |--xyz.openbmc_project.PLDM.FWU.PnPDescriptor ++ | |--xyz.openbmc_project.PLDM.FWU.ACPIDescriptor ++ | ++ |__/xyz/openbmc_project/pldm/fwu/<tid>/componentImageSetInfo ++ | |--xyz.openbmc_project.PLDM.FWU.ActiveComponentImageSetInfo ++ | |--xyz.openbmc_project.PLDM.FWU.PendingComponentImageSetInfo ++ | ++ |__/xyz/openbmc_project/pldm/fwu/<tid>/componentImageSetInfo/component_<component_no> ++ |--xyz.openbmc_project.PLDM.FWU.ActiveComponentInfo ++ |--xyz.openbmc_project.PLDM.FWU.PendingComponentInfo ++ |--xyz.openbmc_project.PLDM.FWU.ComponentActivationMethods ++ |--xyz.openbmc_project.PLDM.FWU.CapabilitiesDuringUpdate ++ ++Note: ++Descriptor for a device shall be defined by one of the following ++(PCI Vendor ID, IANA Enterprise ID, UUID, PnP Vendor ID, or ACPI Vendor ++ID) and the corresponding descriptor`s interface is exposed by the. ++Device Descriptors object. ++No new UUID descriptor incterface is defined as the existing UUID ++interface will be used. ++ ++####FW Update Base ++It is exposed by the object `/xyz/openbmc_project/pldm/fwu` with the ++following interface ++1. `xyz.openbmc_project.pldm.FWUBase` exposes a method by which PLDM ++FWU can be initiated. ++ ++Each FW update capable device info is exposed by the object ++`/xyz/openbmc_project/pldm/fwu/<tid>`. ++It will have the following objects. ++1. Device Descriptors ++2. Component Image Set Info ++3. Component Image Info (Each component is exposed as an object) ++ ++####Device Descriptors ++Device Descriptors are exposed under the object path ++`/xyz/openbmc_project/pldm/fwu/deviceDescriptors` with one of the ++following interfaces. ++1. `xyz.openbmc_project.PLDM.FWU.PCIDescriptor` which exposes the PCI ++device descriptors. If the FD is a PCI device then this interface will ++be exposed by the device descriptors object. ++2. `xyz.openbmc_project.PLDM.FWU.IANADescriptor` which exposes IANA ++descriptor properties. If FD have IANA Enterprise ID as the descriptor ++type then this interface will be exposed by the device descriptors ++object. ++3. `xyz.openbmc_project.PLDM.FWU.PnPDescriptor` which exposes the Pnp ++descriptor properties. If FD have PnP vendor ID as the descriptor ++type then this interface will be exposed by the device descriptors ++object. ++4. `xyz.openbmc_project.PLDM.FWU.ACPIDescriptor` which exposes the ACPI ++descriptor properties. If FD have ACPI vendor ID as the descriptor ++type then this interface will be exposed by the device descriptors ++object. ++ ++####Component Image Set Info ++Component Image Set Info is exposed under the object path ++`/xyz/openbmc_project/pldm/fwu/componentImageSetInfo` with the ++following interface. ++1. `xyz.openbmc_project.PLDM.FWU.ActiveComponentImageSetInfo` which ++exposes the active component image set properties. ++2. `xyz.openbmc_project.PLDM.FWU.PendingComponentImageSetInfo` which ++exposes the pending component image set properties. ++ ++####Component Image Info ++Component Image Info is exposed under the object path ++`/xyz/openbmc_project/pldm/fwu/componentImageSetInfo/componentInfo_<component_no>' ++with the following interface ++1. `xyz.openbmc_project.PLDM.FWU.ActiveComponentInfo` which exposes the ++component Image properties. ++2. `xyz.openbmc_project.PLDM.FWU.PendingComponentInfo` which exposes the ++component Image properties. ++3. `xyz.openbmc_project.PLDM.FWU.CapabilitiesDuringUpdate` which exposes ++the capabilities of the component during update. ++4. `xyz.openbmc_project.PLDM.FWU.ComponentActivationMethods` which ++exposes the component activation methods. +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch new file mode 100644 index 000000000..3a1ae57fb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0030-Add-PLDM-version-purpose-enumeration.patch @@ -0,0 +1,28 @@ +From 007c07561e03a005e90858f77266f4fba3e8e2c9 Mon Sep 17 00:00:00 2001 +From: Ayushi Smriti <smriti.ayushi@intel.com> +Date: Wed, 23 Sep 2020 22:01:25 +0530 +Subject: [PATCH] Add PLDM version purpose enumeration + +This change is to add PLDM in enumeration of possible purposes +of the version to support pldm type version purpose + +Change-Id: I7b914d4323bfe44a4e3cd60ed4a627aeceb6b56f +Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com> +--- + xyz/openbmc_project/Software/Version.interface.yaml | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/xyz/openbmc_project/Software/Version.interface.yaml b/xyz/openbmc_project/Software/Version.interface.yaml +index 345e5b5..f2efbec 100644 +--- a/xyz/openbmc_project/Software/Version.interface.yaml ++++ b/xyz/openbmc_project/Software/Version.interface.yaml +@@ -38,3 +38,6 @@ enumerations: + - name: PSU + description: > + The version is a version for a PSU. ++ - name: PLDM ++ description: > ++ The version is a version for PLDM. +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch new file mode 100644 index 000000000..fd31665dc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0031-update-meson-build-files-for-control-and-bios.patch @@ -0,0 +1,156 @@ +From cd3c2ff290e6ff205c32b386c7c8a73d4a8980e5 Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Tue, 8 Dec 2020 15:08:21 -0800 +Subject: [PATCH 1/4] update meson build files for control and bios + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +--- + .../Control/Power/RestoreDelay/meson.build | 14 ++++++++++++++ + gen/xyz/openbmc_project/Control/Power/meson.build | 15 +++++++++++++++ + .../Control/Processor/ErrConfig/meson.build | 14 ++++++++++++++ + .../openbmc_project/Control/Processor/meson.build | 15 +++++++++++++++ + .../Inventory/Item/Bios/meson.build | 14 ++++++++++++++ + .../openbmc_project/Inventory/Item/meson.build | 15 +++++++++++++++ + 6 files changed, 87 insertions(+) + create mode 100644 gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build + create mode 100644 gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build + create mode 100644 gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build + +diff --git a/gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build b/gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build +new file mode 100644 +index 0000000..91581fd +--- /dev/null ++++ b/gen/xyz/openbmc_project/Control/Power/RestoreDelay/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/Control/Power/RestoreDelay__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/Control/Power/RestoreDelay', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/Control/Power/meson.build b/gen/xyz/openbmc_project/Control/Power/meson.build +index 05628ec..ad04479 100644 +--- a/gen/xyz/openbmc_project/Control/Power/meson.build ++++ b/gen/xyz/openbmc_project/Control/Power/meson.build +@@ -29,6 +29,21 @@ generated_others += custom_target( + build_by_default: true, + ) + ++subdir('RestoreDelay') ++generated_others += custom_target( ++ 'xyz/openbmc_project/Control/Power/RestoreDelay__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml', ], ++ output: [ 'RestoreDelay.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/Control/Power/RestoreDelay', ++ ], ++ build_by_default: true, ++) ++ + subdir('RestorePolicy') + generated_others += custom_target( + 'xyz/openbmc_project/Control/Power/RestorePolicy__markdown'.underscorify(), +diff --git a/gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build b/gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build +new file mode 100644 +index 0000000..12961c2 +--- /dev/null ++++ b/gen/xyz/openbmc_project/Control/Processor/ErrConfig/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/Control/Processor/ErrConfig__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/Control/Processor/ErrConfig', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/Control/Processor/meson.build b/gen/xyz/openbmc_project/Control/Processor/meson.build +index adbff0a..816c30d 100644 +--- a/gen/xyz/openbmc_project/Control/Processor/meson.build ++++ b/gen/xyz/openbmc_project/Control/Processor/meson.build +@@ -14,3 +14,18 @@ generated_others += custom_target( + build_by_default: true, + ) + ++subdir('ErrConfig') ++generated_others += custom_target( ++ 'xyz/openbmc_project/Control/Processor/ErrConfig__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml', ], ++ output: [ 'ErrConfig.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/Control/Processor/ErrConfig', ++ ], ++ build_by_default: true, ++) ++ +diff --git a/gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build b/gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build +new file mode 100644 +index 0000000..5c6fce0 +--- /dev/null ++++ b/gen/xyz/openbmc_project/Inventory/Item/Bios/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/Inventory/Item/Bios__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/Inventory/Item/Bios.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/Inventory/Item/Bios', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/Inventory/Item/meson.build b/gen/xyz/openbmc_project/Inventory/Item/meson.build +index 145bba2..3e036bd 100644 +--- a/gen/xyz/openbmc_project/Inventory/Item/meson.build ++++ b/gen/xyz/openbmc_project/Inventory/Item/meson.build +@@ -27,6 +27,21 @@ generated_others += custom_target( + build_by_default: true, + ) + ++subdir('Bios') ++generated_others += custom_target( ++ 'xyz/openbmc_project/Inventory/Item/Bios__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/Inventory/Item/Bios.interface.yaml', ], ++ output: [ 'Bios.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/Inventory/Item/Bios', ++ ], ++ build_by_default: true, ++) ++ + subdir('Bmc') + generated_others += custom_target( + 'xyz/openbmc_project/Inventory/Item/Bmc__markdown'.underscorify(), +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch new file mode 100644 index 000000000..5f41a1348 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0032-update-meson-build-for-MCTP-interfaces.patch @@ -0,0 +1,266 @@ +From b25ae31fa674a287bc100081a9dfc243bcf53f19 Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Tue, 8 Dec 2020 15:16:25 -0800 +Subject: [PATCH] update meson build for MCTP interfaces + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +--- + gen/xyz/openbmc_project/MCTP/Base/meson.build | 14 +++++ + .../MCTP/Binding/PCIe/meson.build | 14 +++++ + .../MCTP/Binding/SMBus/meson.build | 14 +++++ + .../openbmc_project/MCTP/Binding/meson.build | 31 ++++++++++ + .../openbmc_project/MCTP/BusOwner/meson.build | 14 +++++ + .../openbmc_project/MCTP/Endpoint/meson.build | 14 +++++ + .../MCTP/SupportedMessageTypes/meson.build | 14 +++++ + gen/xyz/openbmc_project/MCTP/meson.build | 62 +++++++++++++++++++ + gen/xyz/openbmc_project/meson.build | 1 + + 9 files changed, 178 insertions(+) + create mode 100644 gen/xyz/openbmc_project/MCTP/Base/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/Binding/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/BusOwner/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/Endpoint/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build + create mode 100644 gen/xyz/openbmc_project/MCTP/meson.build + +diff --git a/gen/xyz/openbmc_project/MCTP/Base/meson.build b/gen/xyz/openbmc_project/MCTP/Base/meson.build +new file mode 100644 +index 0000000..81aeb86 +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/Base/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/MCTP/Base__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Base.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Base', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build b/gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build +new file mode 100644 +index 0000000..0da866c +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/Binding/PCIe/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/MCTP/Binding/PCIe__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Binding/PCIe', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build b/gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build +new file mode 100644 +index 0000000..a0f97bd +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/Binding/SMBus/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/MCTP/Binding/SMBus__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Binding/SMBus', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/Binding/meson.build b/gen/xyz/openbmc_project/MCTP/Binding/meson.build +new file mode 100644 +index 0000000..6e3407c +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/Binding/meson.build +@@ -0,0 +1,31 @@ ++# Generated file; do not modify. ++subdir('PCIe') ++generated_others += custom_target( ++ 'xyz/openbmc_project/MCTP/Binding/PCIe__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Binding/PCIe.interface.yaml', ], ++ output: [ 'PCIe.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Binding/PCIe', ++ ], ++ build_by_default: true, ++) ++ ++subdir('SMBus') ++generated_others += custom_target( ++ 'xyz/openbmc_project/MCTP/Binding/SMBus__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Binding/SMBus.interface.yaml', ], ++ output: [ 'SMBus.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Binding/SMBus', ++ ], ++ build_by_default: true, ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/BusOwner/meson.build b/gen/xyz/openbmc_project/MCTP/BusOwner/meson.build +new file mode 100644 +index 0000000..190a640 +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/BusOwner/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/MCTP/BusOwner__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/BusOwner.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/BusOwner', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/Endpoint/meson.build b/gen/xyz/openbmc_project/MCTP/Endpoint/meson.build +new file mode 100644 +index 0000000..cababfb +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/Endpoint/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/MCTP/Endpoint__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Endpoint.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Endpoint', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build b/gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build +new file mode 100644 +index 0000000..f58fa44 +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/SupportedMessageTypes/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/MCTP/meson.build b/gen/xyz/openbmc_project/MCTP/meson.build +new file mode 100644 +index 0000000..94ab2c2 +--- /dev/null ++++ b/gen/xyz/openbmc_project/MCTP/meson.build +@@ -0,0 +1,62 @@ ++# Generated file; do not modify. ++subdir('Base') ++generated_others += custom_target( ++ 'xyz/openbmc_project/MCTP/Base__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Base.interface.yaml', ], ++ output: [ 'Base.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Base', ++ ], ++ build_by_default: true, ++) ++ ++subdir('Binding') ++subdir('BusOwner') ++generated_others += custom_target( ++ 'xyz/openbmc_project/MCTP/BusOwner__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/BusOwner.interface.yaml', ], ++ output: [ 'BusOwner.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/BusOwner', ++ ], ++ build_by_default: true, ++) ++ ++subdir('Endpoint') ++generated_others += custom_target( ++ 'xyz/openbmc_project/MCTP/Endpoint__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/Endpoint.interface.yaml', ], ++ output: [ 'Endpoint.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/Endpoint', ++ ], ++ build_by_default: true, ++) ++ ++subdir('SupportedMessageTypes') ++generated_others += custom_target( ++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/MCTP/SupportedMessageTypes.interface.yaml', ], ++ output: [ 'SupportedMessageTypes.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/MCTP/SupportedMessageTypes', ++ ], ++ build_by_default: true, ++) ++ +diff --git a/gen/xyz/openbmc_project/meson.build b/gen/xyz/openbmc_project/meson.build +index 3c4750f..e4372b0 100644 +--- a/gen/xyz/openbmc_project/meson.build ++++ b/gen/xyz/openbmc_project/meson.build +@@ -68,6 +68,7 @@ generated_others += custom_target( + subdir('Ipmi') + subdir('Led') + subdir('Logging') ++subdir('MCTP') + subdir('Memory') + subdir('Network') + subdir('Nvme') +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch new file mode 100644 index 000000000..9d3a8f197 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0033-update-meson-build-for-PLDM-FWU-interfaces.patch @@ -0,0 +1,441 @@ +From 32d4d17843bcc96a6d17b3d975fc92fac82ef081 Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Tue, 8 Dec 2020 15:28:42 -0800 +Subject: [PATCH] update meson build for PLDM FWU interfaces + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +--- + .../PLDM/FWU/ACPIDescriptor/meson.build | 14 ++ + .../ActiveComponentImageSetInfo/meson.build | 14 ++ + .../PLDM/FWU/ActiveComponentInfo/meson.build | 14 ++ + .../FWU/CapabilitiesDuringUpdate/meson.build | 14 ++ + .../ComponentActivationMethods/meson.build | 14 ++ + .../PLDM/FWU/FWUBase/meson.build | 14 ++ + .../PLDM/FWU/IANADescriptor/meson.build | 14 ++ + .../PLDM/FWU/PCIDescriptor/meson.build | 14 ++ + .../PendingComponentImageSetInfo/meson.build | 14 ++ + .../PLDM/FWU/PendingComponentInfo/meson.build | 14 ++ + .../PLDM/FWU/PnPDescriptor/meson.build | 14 ++ + gen/xyz/openbmc_project/PLDM/FWU/meson.build | 166 ++++++++++++++++++ + gen/xyz/openbmc_project/PLDM/meson.build | 1 + + 13 files changed, 321 insertions(+) + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build + create mode 100644 gen/xyz/openbmc_project/PLDM/FWU/meson.build + +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build +new file mode 100644 +index 0000000..2ec794d +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/ACPIDescriptor/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build +new file mode 100644 +index 0000000..d415ec9 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build +new file mode 100644 +index 0000000..e2be862 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build +new file mode 100644 +index 0000000..62d9894 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build +new file mode 100644 +index 0000000..2e379b6 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build +new file mode 100644 +index 0000000..149662b +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/FWUBase/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/FWUBase__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/FWUBase', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build +new file mode 100644 +index 0000000..6661829 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/IANADescriptor/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build +new file mode 100644 +index 0000000..00f54e2 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/PCIDescriptor/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build +new file mode 100644 +index 0000000..5349f0f +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build +new file mode 100644 +index 0000000..5c44acf +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/PendingComponentInfo/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build +new file mode 100644 +index 0000000..d77e841 +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/PnPDescriptor/meson.build +@@ -0,0 +1,14 @@ ++# Generated file; do not modify. ++generated_sources += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor__cpp'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml', ], ++ output: [ 'server.cpp', 'server.hpp', 'client.hpp', ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'cpp', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor', ++ ], ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/FWU/meson.build b/gen/xyz/openbmc_project/PLDM/FWU/meson.build +new file mode 100644 +index 0000000..27e89fc +--- /dev/null ++++ b/gen/xyz/openbmc_project/PLDM/FWU/meson.build +@@ -0,0 +1,166 @@ ++# Generated file; do not modify. ++subdir('ACPIDescriptor') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor.interface.yaml', ], ++ output: [ 'ACPIDescriptor.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ACPIDescriptor', ++ ], ++ build_by_default: true, ++) ++ ++subdir('ActiveComponentImageSetInfo') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo.interface.yaml', ], ++ output: [ 'ActiveComponentImageSetInfo.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentImageSetInfo', ++ ], ++ build_by_default: true, ++) ++ ++subdir('ActiveComponentInfo') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo.interface.yaml', ], ++ output: [ 'ActiveComponentInfo.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ActiveComponentInfo', ++ ], ++ build_by_default: true, ++) ++ ++subdir('CapabilitiesDuringUpdate') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate.interface.yaml', ], ++ output: [ 'CapabilitiesDuringUpdate.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/CapabilitiesDuringUpdate', ++ ], ++ build_by_default: true, ++) ++ ++subdir('ComponentActivationMethods') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods.interface.yaml', ], ++ output: [ 'ComponentActivationMethods.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/ComponentActivationMethods', ++ ], ++ build_by_default: true, ++) ++ ++subdir('FWUBase') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/FWUBase__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/FWUBase.interface.yaml', ], ++ output: [ 'FWUBase.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/FWUBase', ++ ], ++ build_by_default: true, ++) ++ ++subdir('IANADescriptor') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/IANADescriptor.interface.yaml', ], ++ output: [ 'IANADescriptor.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/IANADescriptor', ++ ], ++ build_by_default: true, ++) ++ ++subdir('PCIDescriptor') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor.interface.yaml', ], ++ output: [ 'PCIDescriptor.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PCIDescriptor', ++ ], ++ build_by_default: true, ++) ++ ++subdir('PendingComponentImageSetInfo') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo.interface.yaml', ], ++ output: [ 'PendingComponentImageSetInfo.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentImageSetInfo', ++ ], ++ build_by_default: true, ++) ++ ++subdir('PendingComponentInfo') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo.interface.yaml', ], ++ output: [ 'PendingComponentInfo.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PendingComponentInfo', ++ ], ++ build_by_default: true, ++) ++ ++subdir('PnPDescriptor') ++generated_others += custom_target( ++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor__markdown'.underscorify(), ++ input: [ meson.source_root() / 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor.interface.yaml', ], ++ output: [ 'PnPDescriptor.md' ], ++ command: [ ++ sdbuspp_gen_meson_prog, '--command', 'markdown', ++ '--output', meson.current_build_dir(), ++ '--tool', sdbusplusplus_prog, ++ '--directory', meson.source_root(), ++ 'xyz/openbmc_project/PLDM/FWU/PnPDescriptor', ++ ], ++ build_by_default: true, ++) ++ +diff --git a/gen/xyz/openbmc_project/PLDM/meson.build b/gen/xyz/openbmc_project/PLDM/meson.build +index 9087286..02e4234 100644 +--- a/gen/xyz/openbmc_project/PLDM/meson.build ++++ b/gen/xyz/openbmc_project/PLDM/meson.build +@@ -14,6 +14,7 @@ generated_others += custom_target( + build_by_default: true, + ) + ++subdir('FWU') + subdir('PDR') + generated_others += custom_target( + 'xyz/openbmc_project/PLDM/PDR__markdown'.underscorify(), +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend new file mode 100644 index 000000000..e935531ee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend @@ -0,0 +1,21 @@ +# Keep this as a comment to enable the auto-bump script without +# stomping on SRC_URI from previous .bbappend files +#SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git" +SRCREV = "33458d4432a8323616622881f314a73cf0b04d97" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0007-ipmi-set-BIOS-id.patch \ + file://0010-Increase-the-default-watchdog-timeout-value.patch \ + file://0012-Add-RestoreDelay-interface-for-power-restore-delay.patch \ + file://0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch \ + file://0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch \ + file://0025-Add-PreInterruptFlag-properity-in-DBUS.patch \ + file://0026-Add-StandbySpare-support-for-software-inventory.patch \ + file://0028-MCTP-Daemon-D-Bus-interface-definition.patch \ + file://0029-Add-D-Bus-interfaces-for-PLDM-FW-update.patch \ + file://0031-update-meson-build-files-for-control-and-bios.patch \ + file://0030-Add-PLDM-version-purpose-enumeration.patch \ + file://0032-update-meson-build-for-MCTP-interfaces.patch \ + file://0033-update-meson-build-for-PLDM-FWU-interfaces.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service new file mode 100644 index 000000000..9af9af254 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service @@ -0,0 +1,20 @@ +[Unit] +Description=Phosphor DBus Service Discovery Manager +Before=obmc-mapper.target +After=dbus.socket + +[Service] +Restart=always +Type=dbus +ExecStart=/usr/bin/env mapperx \ + --service-namespaces="xyz. com. org." \ + --interface-namespaces="org. com. xyz." \ + --service-blacklists="org.freedesktop.systemd1" +SyslogIdentifier=phosphor-mapper +BusName={BUSNAME} +TimeoutStartSec=300 +RestartSec=5 +EnvironmentFile={envfiledir}/obmc/mapper + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend new file mode 100644 index 000000000..72d991c7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service new file mode 100644 index 000000000..0e80b554a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service @@ -0,0 +1,14 @@ +[Unit] +Description=Phosphor-Pid-Control Margin-based Fan Control Daemon +After=xyz.openbmc_project.EntityManager.service +After=xyz.openbmc_project.ObjectMapper.service + +[Service] +Restart=always +ExecStart={bindir}/swampd +RestartSec=5 +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend new file mode 100644 index 000000000..ab1cd3742 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend @@ -0,0 +1,10 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +inherit obmc-phosphor-systemd +SYSTEMD_SERVICE_${PN} = "phosphor-pid-control.service" +EXTRA_OECONF = "--enable-configure-dbus=yes" + +SRC_URI = "git://github.com/openbmc/phosphor-pid-control.git" +SRCREV = "cb4c1a27574a7fe121a851ae7ba67aec254a1129" + +FILES_${PN} = "${bindir}/swampd ${bindir}/setsensor" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch new file mode 100644 index 000000000..2a4c7e9b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch @@ -0,0 +1,44 @@ +From b6b3051c8078267153712ed8cf514373924fd07a Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Mon, 16 Jul 2018 19:15:04 -0700 +Subject: [PATCH 2/6] Redfish firmware activation -- Modified flash.cpp to + call to customized flash service + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I81c3185e9c4c2ee907feeb53620faa22723c04d4 +--- + ubi/flash.cpp | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/ubi/flash.cpp b/ubi/flash.cpp +index ffa9348..5af2a17 100644 +--- a/ubi/flash.cpp ++++ b/ubi/flash.cpp +@@ -15,10 +15,13 @@ void Activation::flashWrite() + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); +- method.append("obmc-flash-bmc-ubirw.service", "replace"); ++ std::string rwServiceFile = ++ "obmc-flash-bmc-ubirw@" + versionId + ".service"; ++ method.append(rwServiceFile, "replace"); + bus.call_noreply(method); + +- auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; ++ std::string roServiceFile = ++ "obmc-flash-bmc-ubiro@" + versionId + ".service"; + method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); + method.append(roServiceFile, "replace"); +@@ -37,7 +40,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- auto rwServiceFile = "obmc-flash-bmc-ubirw.service"; ++ auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service"; + auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + auto ubootVarsServiceFile = + "obmc-flash-bmc-updateubootvars@" + versionId + ".service"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch new file mode 100644 index 000000000..bcf692f5e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch @@ -0,0 +1,41 @@ +From 1b00440d0c8fabfa2e3eda984a21c0f004ca2150 Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Fri, 26 Oct 2018 11:54:05 -0700 +Subject: [PATCH 4/6] Changed the condition of software version service + watching deamon + + Originally it watches only files that are "written" into /tmp/images directory. +This change modified the condition to also watch files that are "moved" into this directory. + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I3e9cf1ffc3f5350d4649d32d3d3837991322a65b +--- + watch.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/watch.cpp b/watch.cpp +index e46b8aa..eee1bc3 100644 +--- a/watch.cpp ++++ b/watch.cpp +@@ -46,7 +46,7 @@ Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) : + std::strerror(error)); + } + +- wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE); ++ wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE | IN_MOVED_TO); + if (-1 == wd) + { + auto error = errno; +@@ -97,7 +97,8 @@ int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents, + while (offset < bytes) + { + auto event = reinterpret_cast<inotify_event*>(&buffer[offset]); +- if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR)) ++ if ((event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) && ++ !(event->mask & IN_ISDIR)) + { + auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name; + auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch new file mode 100644 index 000000000..cfaa077eb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch @@ -0,0 +1,215 @@ +From df1281792f6886b41c99919e8197c2c2d369d0ca Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Mon, 10 Dec 2018 10:36:44 -0800 +Subject: [PATCH] Modified firmware activation to launch fwupd.sh through + + non-ubi fs code path to match more closely to the upstream design - + Added option FWUPD_SCRIPT to saperate intel customized code - Adopted + ActivationProgress from ubi fs activation code mainly for progress indicator + for ipmi update + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + activation.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- + meson.build | 1 + + meson_options.txt | 3 +++ + static/flash.cpp | 42 ++++++++++++++++++++++++++++++++++++++++-- + ubi/flash.cpp | 9 +++------ + 5 files changed, 91 insertions(+), 9 deletions(-) + +diff --git a/activation.cpp b/activation.cpp +index eb57587..901caf3 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -92,7 +92,50 @@ auto Activation::activation(Activations value) -> Activations + value == + softwareServer::Activation::Activations::ActivatingAsStandbySpare) + { ++#ifdef FWUPD_SCRIPT ++ if (!activationProgress) ++ { ++ // Enable systemd signals ++ Activation::subscribeToSystemdSignals(); ++ parent.freeSpace(*this); ++ ++ activationProgress = ++ std::make_unique<ActivationProgress>(bus, path); + ++#ifdef WANT_SIGNATURE_VERIFY ++ fs::path uploadDir(IMG_UPLOAD_DIR); ++ if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH)) ++ { ++ onVerifyFailed(); ++ // Stop the activation process, if fieldMode is enabled. ++ if (parent.control::FieldMode::fieldModeEnabled()) ++ { ++ return softwareServer::Activation::activation( ++ softwareServer::Activation::Activations::Failed); ++ } ++ } ++#endif ++ flashWrite(); ++ } ++ else if (activationProgress->progress() == 100) ++ { ++ log<level::ERR>("[Jennifer] progress == 100..."); ++ if (!redundancyPriority) ++ { ++ redundancyPriority = ++ std::make_unique<RedundancyPriority>(bus, path, *this, 0); ++ } ++ ++ // Remove version object from image manager ++ Activation::deleteImageManagerObject(); ++ ++ // Create active association ++ parent.createActiveAssociation(path); ++ ++ return softwareServer::Activation::activation( ++ softwareServer::Activation::Activations::Active); ++ } ++#else // !FWUPD_SCRIPT + #ifdef HOST_BIOS_UPGRADE + auto purpose = parent.versions.find(versionId)->second->purpose(); + if (purpose == VersionPurpose::Host) +@@ -115,7 +158,6 @@ auto Activation::activation(Activations value) -> Activations + return softwareServer::Activation::activation(value); + } + #endif +- + auto versionStr = parent.versions.find(versionId)->second->version(); + + if (!minimum_ship_level::verify(versionStr)) +@@ -179,6 +221,7 @@ auto Activation::activation(Activations value) -> Activations + return softwareServer::Activation::activation( + softwareServer::Activation::Activations::Active); + #endif ++#endif // FWUPD_SCRIPT + } + else + { +diff --git a/meson.build b/meson.build +index 0a7a6a6..5990168 100644 +--- a/meson.build ++++ b/meson.build +@@ -57,6 +57,7 @@ conf.set('WANT_SIGNATURE_VERIFY', \ + get_option('verify-signature').enabled() or \ + get_option('verify-full-signature').enabled()) + conf.set('WANT_SIGNATURE_FULL_VERIFY', get_option('verify-full-signature').enabled()) ++conf.set('FWUPD_SCRIPT', get_option('fwupd-script').enabled()) + + # Configurable variables + conf.set('ACTIVE_BMC_MAX_ALLOWED', get_option('active-bmc-max-allowed')) +diff --git a/meson_options.txt b/meson_options.txt +index 355773c..f0c8730 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -25,6 +25,9 @@ option('verify-signature', type: 'feature', + option('verify-full-signature', type: 'feature', + description: 'Enable image full signature validation.') + ++option('fwupd-script', type: 'feature', ++ description: 'Enable fwupd script support.') ++ + # Variables + option( + 'active-bmc-max-allowed', type: 'integer', +diff --git a/static/flash.cpp b/static/flash.cpp +index 101828b..5506a59 100644 +--- a/static/flash.cpp ++++ b/static/flash.cpp +@@ -22,9 +22,11 @@ namespace updater + + namespace fs = std::filesystem; + using namespace phosphor::software::image; ++namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server; + + void Activation::flashWrite() + { ++#ifndef FWUPD_SCRIPT + // For static layout code update, just put images in /run/initramfs. + // It expects user to trigger a reboot and an updater script will program + // the image to flash during reboot. +@@ -36,11 +38,47 @@ void Activation::flashWrite() + fs::copy_file(uploadDir / versionId / bmcImage, toPath / bmcImage, + fs::copy_options::overwrite_existing); + } ++ ++#else ++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, ++ SYSTEMD_INTERFACE, "StartUnit"); ++ method.append("fwupd@" + versionId + ".service", "replace"); ++ bus.call_noreply(method); ++#endif + } + +-void Activation::onStateChanges(sdbusplus::message::message& /*msg*/) ++void Activation::onStateChanges(__attribute__((unused)) ++ sdbusplus::message::message& msg) + { +- // Empty ++#ifndef FWUPD_SCRIPT ++ uint32_t newStateID{}; ++ sdbusplus::message::object_path newStateObjPath; ++ std::string newStateUnit{}; ++ std::string newStateResult{}; ++ ++ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); ++ ++ auto rwServiceFile = "fwupdw@" + versionId + ".service"; ++ ++ if (newStateUnit == rwServiceFile && newStateResult == "done") ++ { ++ activationProgress->progress(100); ++ } ++ ++ if (newStateUnit == rwServiceFile) ++ { ++ if (newStateResult == "failed" || newStateResult == "dependency") ++ { ++ Activation::activation( ++ softwareServer::Activation::Activations::Failed); ++ } ++ else ++ { ++ Activation::activation( ++ softwareServer::Activation::Activations::Activating); ++ } ++ } ++#endif + } + + } // namespace updater +diff --git a/ubi/flash.cpp b/ubi/flash.cpp +index a263bfb..c58eefc 100644 +--- a/ubi/flash.cpp ++++ b/ubi/flash.cpp +@@ -15,13 +15,10 @@ void Activation::flashWrite() + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); +- std::string rwServiceFile = +- "obmc-flash-bmc-ubirw@" + versionId + ".service"; +- method.append(rwServiceFile, "replace"); ++ method.append("obmc-flash-bmc-ubirw.service", "replace"); + bus.call_noreply(method); + +- std::string roServiceFile = +- "obmc-flash-bmc-ubiro@" + versionId + ".service"; ++ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); + method.append(roServiceFile, "replace"); +@@ -40,7 +37,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service"; ++ auto rwServiceFile = "obmc-flash-bmc-ubirw.service"; + auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + auto ubootVarsServiceFile = + "obmc-flash-bmc-updateubootvars@" + versionId + ".service"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch new file mode 100644 index 000000000..1f2a86fb9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch @@ -0,0 +1,44 @@ +From 9b3c44e9fb3d907c0152f14b967e23ab964c0e0b Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Thu, 14 Feb 2019 14:54:45 -0800 +Subject: [PATCH 6/6] Modify the ID of software image updater object on DBus to + allow force update onto same version image + +In the original design of image update, it does not allow the same version of image to be flashed onto itself. +But this blocks validation tests and in most of the cases we don't prevent user from doing such update. + +This patch appends a random number after the version ID hash string to unblock such limitation. + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I16aba4804ae1bc2e8784320f91c0419fb8b23c35 +--- + image_manager.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/image_manager.cpp b/image_manager.cpp +index 5b2ff49..e3d26e3 100644 +--- a/image_manager.cpp ++++ b/image_manager.cpp +@@ -9,6 +9,7 @@ + #include <stdlib.h> + #include <sys/stat.h> + #include <sys/wait.h> ++#include <time.h> + #include <unistd.h> + + #include <elog-errors.hpp> +@@ -174,6 +175,11 @@ int Manager::processImage(const std::string& tarFilePath) + // Compute id + auto id = Version::getId(version); + ++ // Append a random number after the original version hash ++ // This will allow forcing image update onto the same version ++ srand(time(NULL)); ++ id = id + "_" + std::to_string(rand()); ++ + fs::path imageDirPath = std::string{IMG_UPLOAD_DIR}; + imageDirPath /= id; + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch new file mode 100644 index 000000000..6039be44b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch @@ -0,0 +1,76 @@ +From c2ae3ac444f7a5e9674a82f47086874f947bcec6 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +Date: Thu, 5 Dec 2019 12:38:21 +0530 +Subject: [PATCH] Adding StandBySpare for firmware activation + +Added new states 'StandBySpare', 'ActivatingAsStandbySpare' for +firmware activation. If the uploaded firmware image is for +backup/recovery, then it sets the "StandBySpare" value for +Activations. When backup/recovery image is in activating state, +then activations will be set to "ActivatingAsStandbySpare". + +Tested: +Tested using redfish interface. +Did the GET on "/redfish/v1/UpdateService/FirmwareInventory/<backup image>" +Response: + .... + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "StandbySpare" + } +....... + +Change-Id: I7f1608fac3196774a6d593b6128d58da3f5c88fc +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +--- + activation.cpp | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/activation.cpp b/activation.cpp +index 2966b2f..a098784 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -81,12 +81,16 @@ void Activation::unsubscribeFromSystemdSignals() + auto Activation::activation(Activations value) -> Activations + { + if ((value != softwareServer::Activation::Activations::Active) && +- (value != softwareServer::Activation::Activations::Activating)) ++ (value != softwareServer::Activation::Activations::Activating) && ++ (value != ++ softwareServer::Activation::Activations::ActivatingAsStandbySpare)) + { + redundancyPriority.reset(nullptr); + } + +- if (value == softwareServer::Activation::Activations::Activating) ++ if (value == softwareServer::Activation::Activations::Activating || ++ value == ++ softwareServer::Activation::Activations::ActivatingAsStandbySpare) + { + #ifdef FWUPD_SCRIPT + if (!activationProgress) +@@ -309,6 +313,20 @@ auto Activation::requestedActivation(RequestedActivations value) + softwareServer::Activation::Activations::Activating); + } + } ++ else if ((value == ++ softwareServer::Activation::RequestedActivations::StandbySpare) && ++ (softwareServer::Activation::requestedActivation() != ++ softwareServer::Activation::RequestedActivations::StandbySpare)) ++ { ++ if ((softwareServer::Activation::activation() == ++ softwareServer::Activation::Activations::Ready) || ++ (softwareServer::Activation::activation() == ++ softwareServer::Activation::Activations::Failed)) ++ { ++ Activation::activation(softwareServer::Activation::Activations:: ++ ActivatingAsStandbySpare); ++ } ++ } + return softwareServer::Activation::requestedActivation(value); + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch new file mode 100644 index 000000000..49bdc138f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch @@ -0,0 +1,435 @@ +From 030f918b90ea45104bccf68082c2d634c6694238 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Tue, 13 Aug 2019 22:43:12 +0530 +Subject: [PATCH] PFR images support in phosphor-software-manager + +This commit adds support for handling the PFR images +upload and processing. + +Testing: +tested PFR image uploads and updates + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> + +--- + activation.cpp | 2 +- + item_updater.cpp | 7 +- + meson.build | 7 +- + meson_options.txt | 3 + + pfr_image_manager.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++ + pfr_image_manager.hpp | 75 +++++++++++++++ + 6 files changed, 306 insertions(+), 5 deletions(-) + create mode 100644 pfr_image_manager.cpp + create mode 100644 pfr_image_manager.hpp + +diff --git a/activation.cpp b/activation.cpp +index bad17b8..3363230 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -119,7 +119,7 @@ auto Activation::activation(Activations value) -> Activations + } + else if (activationProgress->progress() == 100) + { +- log<level::ERR>("[Jennifer] progress == 100..."); ++ log<level::INFO>("progress == 100..."); + if (!redundancyPriority) + { + redundancyPriority = +diff --git a/item_updater.cpp b/item_updater.cpp +index df8595c..694975f 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -64,10 +64,10 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg) + auto value = SVersion::convertVersionPurposeFromString( + std::get<std::string>(property.second)); + if (value == VersionPurpose::BMC || +-#ifdef HOST_BIOS_UPGRADE ++#if defined(HOST_BIOS_UPGRADE) || defined(PFR_UPDATE) + value == VersionPurpose::Host || + #endif +- value == VersionPurpose::System) ++ value == VersionPurpose::Other) + { + purpose = value; + } +@@ -399,6 +399,7 @@ void ItemUpdater::deleteAll() + ItemUpdater::ActivationStatus + ItemUpdater::validateSquashFSImage(const std::string& filePath) + { ++#ifndef PFR_UPDATE + bool valid = true; + + // Record the images which are being updated +@@ -416,7 +417,7 @@ ItemUpdater::ActivationStatus + return ItemUpdater::ActivationStatus::invalid; + } + } +- ++#endif + return ItemUpdater::ActivationStatus::ready; + } + +@@ -690,8 +691,8 @@ void ItemUpdater::freeSpace(Activation& caller) + // Failed activations don't have priority, assign them a large value + // for sorting purposes. + auto priority = 999; +- if ((iter.second.get()->activation() == +- server::Activation::Activations::Active)&& ++ if ((iter.second.get()->activation() == ++ server::Activation::Activations::Active) && + iter.second->redundancyPriority.get()) + { + priority = iter.second->redundancyPriority.get()->priority(); +diff --git a/meson.build b/meson.build +index 08d6f71..c61d59f 100644 +--- a/meson.build ++++ b/meson.build +@@ -55,6 +55,7 @@ conf.set('MMC_LAYOUT', get_option('bmc-layout').contains('mmc')) + conf.set('HOST_BIOS_UPGRADE', get_option('host-bios-upgrade').enabled()) + conf.set('WANT_SIGNATURE_VERIFY', get_option('verify-signature').enabled()) + conf.set('FWUPD_SCRIPT', get_option('fwupd-script').enabled()) ++conf.set('PFR_UPDATE', get_option('pfr-update').enabled()) + + # Configurable variables + conf.set('ACTIVE_BMC_MAX_ALLOWED', get_option('active-bmc-max-allowed')) +@@ -195,12 +196,16 @@ executable( + install: true + ) + ++image_manager_source = files('image_manager.cpp') ++if get_option('pfr-update').enabled() ++ image_manager_source = files('pfr_image_manager.cpp') ++endif + executable( + 'phosphor-version-software-manager', + image_error_cpp, + image_error_hpp, +- 'image_manager.cpp', + 'image_manager_main.cpp', ++ image_manager_source, + 'version.cpp', + 'watch.cpp', + dependencies: [deps, ssl], +diff --git a/meson_options.txt b/meson_options.txt +index 4f7e62a..1593502 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -25,6 +25,9 @@ option('verify-signature', type: 'feature', + option('fwupd-script', type: 'feature', + description: 'Enable fwupd script support.') + ++option('pfr-update', type: 'feature', ++ description: 'Enable fwupd script support.') ++ + # Variables + option( + 'active-bmc-max-allowed', type: 'integer', +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +new file mode 100644 +index 0000000..242a6ca +--- /dev/null ++++ b/pfr_image_manager.cpp +@@ -0,0 +1,218 @@ ++#include "config.h" ++ ++#include "pfr_image_manager.hpp" ++ ++#include "version.hpp" ++#include "watch.hpp" ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/stat.h> ++#include <sys/wait.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <elog-errors.hpp> ++#include <xyz/openbmc_project/Software/Image/error.hpp> ++ ++#include <algorithm> ++#include <cstring> ++#include <filesystem> ++#include <fstream> ++#include <iomanip> ++#include <sstream> ++#include <string> ++ ++namespace phosphor ++{ ++namespace software ++{ ++namespace manager ++{ ++ ++using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; ++namespace Software = phosphor::logging::xyz::openbmc_project::Software; ++ ++static constexpr const uint32_t pfmPos = 2054; ++ ++static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, ++ std::string& version) ++{ ++ struct pfrImgBlock0 block0Data; ++ uint8_t verData[2]; ++ ++ if (std::filesystem::exists(imgPath)) ++ { ++ try ++ { ++ std::ifstream imgFile(imgPath, std::ios::binary | std::ios::in); ++ ++ if (!imgFile.good()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image file read failed"); ++ return -1; ++ } ++ ++ imgFile.read(reinterpret_cast<char*>(&block0Data), ++ sizeof(block0Data)); ++ imgType = block0Data.pcType[0]; ++ imgFile.seekg(pfmPos, ++ std::ios::beg); // Version is at 0x806 in the PFM ++ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData)); ++ imgFile.close(); ++ version = ++ std::to_string(verData[0]) + "." + std::to_string(verData[1]); ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "PFR image", ++ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]), ++ phosphor::logging::entry("VERSION=%s", version.c_str())); ++ } ++ catch (std::exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++int Manager::processImage(const std::string& imgFilePath) ++{ ++ std::filesystem::path imgPath(imgFilePath); ++ ++ if (!std::filesystem::exists(imgPath)) ++ return -1; ++ ++ uint8_t imgType; ++ int retry = 3; ++ std::string ver; ++ std::string purposeString; ++ ++ if (0 != getPFRImgInfo(imgFilePath, imgType, ver)) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error reading uploaded image type and version"); ++ return -1; ++ } ++ ++ if (ver.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Empty version from image file"); ++ return -1; ++ } ++ ++ if (imgType == pfrBMCUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; ++ } ++ else if (imgType == pfrPCHUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; ++ } ++ else if (imgType == pfrCPLDUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; ++ } ++ else ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown"; ++ ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unknown image type"); ++ return -1; ++ } ++ ++ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose ++ purpose = Version::VersionPurpose::Unknown; ++ try ++ { ++ purpose = Version::convertVersionPurposeFromString(purposeString); ++ } ++ catch (const sdbusplus::exception::InvalidEnumString& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: Failed to convert purpose to enum." ++ " Setting to Unknown."); ++ } ++ ++ // Compute id ++ std::string id = Version::getId(ver); ++ ++ // Append a random number after the original version hash ++ // This will allow forcing image update onto the same version ++ // with 3 retries on random number generation. ++ do ++ { ++ srand(time(NULL)); ++ id = id + "_" + std::to_string(rand()); ++ } while ((versions.find(id) != versions.end()) && retry--); ++ ++ if (versions.find(id) != versions.end()) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Software Object with the same version already exists, exiting " ++ "the update", ++ phosphor::logging::entry("VERSION_ID=%s", id.c_str())); ++ ++ return -1; ++ } ++ ++ std::filesystem::path imageDirPath(IMG_UPLOAD_DIR); ++ imageDirPath /= id; ++ ++ std::filesystem::create_directory(imageDirPath); ++ ++ std::filesystem::path newFileName = imageDirPath / "image-runtime"; ++ std::filesystem::rename(imgFilePath, newFileName); ++ ++ // Create Version object ++ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; ++ ++ auto versionPtr = std::make_unique<Version>( ++ bus, objPath, ver, purpose, imageDirPath.string(), ++ std::bind(&Manager::erase, this, std::placeholders::_1)); ++ versionPtr->deleteObject = ++ std::make_unique<phosphor::software::manager::Delete>(bus, objPath, ++ *versionPtr); ++ versions.insert(std::make_pair(id, std::move(versionPtr))); ++ ++ return 0; ++} ++ ++void Manager::erase(std::string entryId) ++{ ++ auto it = versions.find(entryId); ++ if (it == versions.end()) ++ { ++ return; ++ } ++ ++ if (it->second->isFunctional()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ ("Error: Version " + entryId + ++ " is currently running on the BMC." ++ " Unable to remove.") ++ .c_str()); ++ return; ++ } ++ ++ // Delete image dir ++ std::filesystem::path imageDirPath = (*(it->second)).path(); ++ if (std::filesystem::exists(imageDirPath)) ++ { ++ std::filesystem::remove_all(imageDirPath); ++ } ++ this->versions.erase(entryId); ++} ++ ++} // namespace manager ++} // namespace software ++} // namespace phosphor +diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp +new file mode 100644 +index 0000000..c6ee6a4 +--- /dev/null ++++ b/pfr_image_manager.hpp +@@ -0,0 +1,76 @@ ++#pragma once ++#include "version.hpp" ++ ++#include <sdbusplus/server.hpp> ++ ++namespace phosphor ++{ ++namespace software ++{ ++namespace manager ++{ ++ ++enum pfrImgPCType ++{ ++ pfrCPLDUpdateCap = 0x00, ++ pfrPCHPFM = 0x01, ++ pfrPCHUpdateCap = 0x02, ++ pfrBMCPFM = 0x03, ++ pfrBMCUpdateCap = 0x04 ++}; ++ ++/* PFR image block 0 - As defined in HAS */ ++struct pfrImgBlock0 ++{ ++ uint8_t tag[4]; ++ uint8_t pcLength[4]; ++ uint8_t pcType[4]; ++ uint8_t reserved1[4]; ++ uint8_t hash256[32]; ++ uint8_t hash384[48]; ++ uint8_t reserved2[32]; ++} __attribute__((packed)); ++ ++/** @class Manager ++ * @brief Contains a map of Version dbus objects. ++ * @details The software image manager class that contains the Version dbus ++ * objects and their version ids. ++ */ ++class Manager ++{ ++ public: ++ /** @brief Constructs Manager Class ++ * ++ * @param[in] bus - The Dbus bus object ++ */ ++ Manager(sdbusplus::bus::bus& bus) : bus(bus){}; ++ ++ /** ++ * @brief Verify the image and provide the image to updater. ++ * Create and populate the version and file path interfaces. ++ * ++ * @param[in] uploaded image. ++ * @param[out] result - 0 if successful. ++ */ ++ int processImage(const std::string& imageFilePath); ++ ++ /** ++ * @brief Erase specified entry d-bus object ++ * and deletes the image file. ++ * ++ * @param[in] entryId - unique identifier of the entry ++ */ ++ void erase(std::string entryId); ++ ++ private: ++ /** @brief Persistent map of Version dbus objects and their ++ * version id */ ++ std::map<std::string, std::unique_ptr<Version>> versions; ++ ++ /** @brief Persistent sdbusplus DBus bus connection. */ ++ sdbusplus::bus::bus& bus; ++}; ++ ++} // namespace manager ++} // namespace software ++} // namespace phosphor +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch new file mode 100644 index 000000000..72eb0beba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch @@ -0,0 +1,415 @@ +From ac6e0c217a1b136d82f93b691aff1acb40009f26 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +Date: Thu, 5 Dec 2019 11:55:36 +0530 +Subject: [PATCH] PFR image HASH verification + +This adds HASH verification on PFR images uploaded for +firmware updates + +Tested: tested firmware update with good and bad HASH images. + +A) +1. Upload the corrupted image for fw update. +2. Image present in /tmp/images/ +-rw-r--r-- 1 root root 22969344 Jun 3 09:27 +5dea710b-8b85-4065-8af7-3149ada81edf + +3. Journalctl logs during image verification +Jun 03 09:27:20 intel-obmc phosphor-version-software-manager[4755]: +Firmware image HASH verification failed +Jun 03 09:27:20 intel-obmc phosphor-version-software-manager[4755]: +Error verifying uploaded image +Jun 03 09:27:20 intel-obmc phosphor-version-software-manager[4755]: +Error processing image + +4. image deleted from /tmp/images/ + +B) +1. Upload the correct image. +POST: https://<BMC_IP>/redfish/v1/UpdateService/ + with <BMC_signed_cap> binary file +2. Image verification is success and proceeds with update. +{ + "@odata.id": "/redfish/v1/TaskService/Tasks/0", + "@odata.type": "#Task.v1_4_3.Task", + "Id": "0", + "TaskState": "Running", + "TaskStatus": "OK" +} + +Change-Id: I9336980bfb74c8136690024782bfef45f6b08d56 +Signed-off-by: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com> + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +--- + pfr_image_manager.cpp | 150 +++++++++++++++++++++++++++++++++---------- + pfr_image_manager.hpp | 112 +++++++++++++++++++++++++++++-- + 2 files changed, 222 insertions(+), 40 deletions(-) + +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index 242a6ca..1a41cbe 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -5,6 +5,8 @@ + #include "version.hpp" + #include "watch.hpp" + ++#include <fcntl.h> ++#include <openssl/err.h> + #include <stdio.h> + #include <stdlib.h> + #include <sys/stat.h> +@@ -20,6 +22,7 @@ + #include <filesystem> + #include <fstream> + #include <iomanip> ++#include <set> + #include <sstream> + #include <string> + +@@ -34,12 +37,21 @@ using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; + namespace Software = phosphor::logging::xyz::openbmc_project::Software; + + static constexpr const uint32_t pfmPos = 2054; ++static constexpr const uint32_t block0Magic = 0xB6EAFD19; ++static constexpr const uint32_t lengthBlk0Blk1 = 1024; + +-static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, +- std::string& version) ++int Manager::verifyPFRImage(const std::filesystem::path imgPath, ++ std::string& version, std::string& purposeString) + { +- struct pfrImgBlock0 block0Data; +- uint8_t verData[2]; ++ uint8_t imgType = 0; ++ uint32_t imgMagic = 0; ++ uint8_t verData[2] = {0}; ++ uint32_t hashLen = 0; ++ struct pfrImgBlock0 block0Data = {}; ++ ++ std::string imageName; ++ ++ EVP_MD_CTX* ctx; + + if (std::filesystem::exists(imgPath)) + { +@@ -56,17 +68,101 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, + + imgFile.read(reinterpret_cast<char*>(&block0Data), + sizeof(block0Data)); ++ ++ imgMagic = block0Data.tag; ++ ++ if (imgMagic != block0Magic) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image magic number match failed", ++ phosphor::logging::entry("IMAGEMAGIC=0x%x", imgMagic)); ++ return -1; ++ } ++ + imgType = block0Data.pcType[0]; ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Image Type", phosphor::logging::entry( ++ "IMAGETYPE=0x%x", static_cast<int>(imgType))); ++ ++ if (imgType == pfrBMCUpdateCap || imgType == pfrBMCPFM) ++ { ++ imageName = "BMC"; ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; ++ } ++ else if (imgType == pfrPCHUpdateCap || imgType == pfrPCHPFM) ++ { ++ imageName = "BIOS"; ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; ++ } ++ else if (imgType == pfrCPLDUpdateCap) ++ { ++ imageName = "CPLD"; ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; ++ } ++ else ++ { ++ purposeString = "xyz.openbmc_project.Software.Version." ++ "VersionPurpose.Unknown"; ++ ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unknown image type"); ++ return -1; ++ } ++ + imgFile.seekg(pfmPos, + std::ios::beg); // Version is at 0x806 in the PFM + imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData)); + imgFile.close(); +- version = +- std::to_string(verData[0]) + "." + std::to_string(verData[1]); ++ ++ auto size = std::filesystem::file_size(imgPath); ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Image Size", phosphor::logging::entry("IMAGESIZE=0x%x", ++ static_cast<int>(size))); ++ ++ // Adds all digest algorithms to the internal table ++ OpenSSL_add_all_digests(); ++ ++ ctx = EVP_MD_CTX_create(); ++ EVP_DigestInit(ctx, EVP_sha256()); ++ ++ // Hash the image file and update the digest ++ auto dataPtr = mapFile(imgPath, size); ++ ++ EVP_DigestUpdate(ctx, ((uint8_t*)dataPtr() + lengthBlk0Blk1), ++ (size - lengthBlk0Blk1)); ++ ++ std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256())); ++ std::vector<uint8_t> expectedDigest(block0Data.hash256, ++ &block0Data.hash256[0] + 32); ++ ++ EVP_DigestFinal(ctx, digest.data(), &hashLen); ++ EVP_MD_CTX_destroy(ctx); ++ ++ std::string redfishMsgID = "OpenBMC.0.1"; ++ ++ if (expectedDigest != digest) ++ { ++ redfishMsgID += ".GeneralFirmwareSecurityViolation"; ++ sd_journal_send("MESSAGE=%s", ++ "Firmware image HASH verification failed", ++ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s", ++ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s", ++ "Image HASH check fail", NULL); ++ return -1; ++ } ++ + phosphor::logging::log<phosphor::logging::level::INFO>( + "PFR image", + phosphor::logging::entry("PCType=%d", block0Data.pcType[0]), + phosphor::logging::entry("VERSION=%s", version.c_str())); ++ ++ version = ++ std::to_string(verData[0]) + "." + std::to_string(verData[1]); + } + catch (std::exception& e) + { +@@ -80,20 +176,21 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, + + int Manager::processImage(const std::string& imgFilePath) + { ++ + std::filesystem::path imgPath(imgFilePath); + + if (!std::filesystem::exists(imgPath)) + return -1; + +- uint8_t imgType; + int retry = 3; + std::string ver; + std::string purposeString; + +- if (0 != getPFRImgInfo(imgFilePath, imgType, ver)) ++ if (0 != verifyPFRImage(imgFilePath, ver, purposeString)) + { + phosphor::logging::log<phosphor::logging::level::ERR>( +- "Error reading uploaded image type and version"); ++ "Error verifying uploaded image"); ++ std::filesystem::remove_all(imgFilePath); + return -1; + } + +@@ -104,31 +201,6 @@ int Manager::processImage(const std::string& imgFilePath) + return -1; + } + +- if (imgType == pfrBMCUpdateCap) +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; +- } +- else if (imgType == pfrPCHUpdateCap) +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; +- } +- else if (imgType == pfrCPLDUpdateCap) +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; +- } +- else +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown"; +- +- phosphor::logging::log<phosphor::logging::level::ERR>( +- "Unknown image type"); +- return -1; +- } +- + sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose + purpose = Version::VersionPurpose::Unknown; + try +@@ -170,6 +242,7 @@ int Manager::processImage(const std::string& imgFilePath) + std::filesystem::create_directory(imageDirPath); + + std::filesystem::path newFileName = imageDirPath / "image-runtime"; ++ + std::filesystem::rename(imgFilePath, newFileName); + + // Create Version object +@@ -213,6 +286,14 @@ void Manager::erase(std::string entryId) + this->versions.erase(entryId); + } + ++CustomMap Manager::mapFile(const std::filesystem::path& path, size_t size) ++{ ++ ++ CustomFd fd(open(path.c_str(), O_RDONLY)); ++ ++ return CustomMap(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd(), 0), ++ size); ++} + } // namespace manager + } // namespace software + } // namespace phosphor +diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp +index c6ee6a4..5b7b2c3 100644 +--- a/pfr_image_manager.hpp ++++ b/pfr_image_manager.hpp +@@ -1,8 +1,16 @@ + #pragma once + #include "version.hpp" + ++#include <openssl/evp.h> ++#include <openssl/pem.h> ++#include <openssl/rsa.h> ++#include <sys/mman.h> ++#include <unistd.h> ++ + #include <sdbusplus/server.hpp> + ++#include <filesystem> ++ + namespace phosphor + { + namespace software +@@ -22,7 +30,7 @@ enum pfrImgPCType + /* PFR image block 0 - As defined in HAS */ + struct pfrImgBlock0 + { +- uint8_t tag[4]; ++ uint32_t tag; + uint8_t pcLength[4]; + uint8_t pcType[4]; + uint8_t reserved1[4]; +@@ -31,6 +39,82 @@ struct pfrImgBlock0 + uint8_t reserved2[32]; + } __attribute__((packed)); + ++/** @struct CustomFd ++ * ++ * RAII wrapper for file descriptor. ++ */ ++struct CustomFd ++{ ++ public: ++ CustomFd() = delete; ++ CustomFd(const CustomFd&) = delete; ++ CustomFd& operator=(const CustomFd&) = delete; ++ CustomFd(CustomFd&&) = default; ++ CustomFd& operator=(CustomFd&&) = default; ++ /** @brief Saves File descriptor and uses it to do file operation ++ * ++ * @param[in] fd - File descriptor ++ */ ++ CustomFd(int fd) : fd(fd) ++ {} ++ ++ ~CustomFd() ++ { ++ if (fd >= 0) ++ { ++ close(fd); ++ } ++ } ++ ++ int operator()() const ++ { ++ return fd; ++ } ++ ++ private: ++ /** @brief File descriptor */ ++ int fd = -1; ++}; ++ ++/** @struct CustomMap ++ * ++ * RAII wrapper for mmap. ++ */ ++struct CustomMap ++{ ++ private: ++ /** @brief starting address of the map */ ++ void* addr; ++ ++ /** @brief length of the mapping */ ++ size_t length; ++ ++ public: ++ CustomMap() = delete; ++ CustomMap(const CustomMap&) = delete; ++ CustomMap& operator=(const CustomMap&) = delete; ++ CustomMap(CustomMap&&) = default; ++ CustomMap& operator=(CustomMap&&) = default; ++ ++ /** @brief Saves starting address of the map and ++ * and length of the file. ++ * @param[in] addr - Starting address of the map ++ * @param[in] length - length of the map ++ */ ++ CustomMap(void* addr, size_t length) : addr(addr), length(length) ++ {} ++ ++ ~CustomMap() ++ { ++ munmap(addr, length); ++ } ++ ++ void* operator()() const ++ { ++ return addr; ++ } ++}; ++ + /** @class Manager + * @brief Contains a map of Version dbus objects. + * @details The software image manager class that contains the Version dbus +@@ -63,6 +147,22 @@ class Manager + void erase(std::string entryId); + + private: ++ /** ++ * @brief Memory map the file ++ * @param[in] - file path ++ * @param[in] - file size ++ * @param[out] - Custom Mmap address ++ */ ++ CustomMap mapFile(const std::filesystem::path& path, size_t size); ++ ++ /** ++ * @brief Verify the PFR image and return version and purpose ++ * @param[in] - file path ++ * @param[out] - version ++ * @param[out] - purpose ++ */ ++ int verifyPFRImage(const std::filesystem::path imgPath, ++ std::string& version, std::string& purposeString); + /** @brief Persistent map of Version dbus objects and their + * version id */ + std::map<std::string, std::unique_ptr<Version>> versions; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch new file mode 100644 index 000000000..e0ff79795 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-item_updater-update-the-bmc_active-objectPath.patch @@ -0,0 +1,50 @@ +From d9e50ecf8bd8bc764838e7244084184644a3f0fc Mon Sep 17 00:00:00 2001 +From: Chalapathi <chalapathix.venkataramashetty@intel.com> +Date: Thu, 23 Apr 2020 19:06:19 +0000 +Subject: [PATCH] item_updater: update the bmc_active objectPath + +Update the Software object path to bmc_active instead of random Id. + +Signed-off-by: Chalapathi <chalapathix.venkataramashetty@intel.com> + +--- + item_updater.cpp | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/item_updater.cpp b/item_updater.cpp +index e6dd298..c3a846d 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -175,7 +175,8 @@ void ItemUpdater::processBMCImage() + if (0 == + iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX)) + { +- // Get the version to calculate the id ++ std::string id = "bmc_active"; ++ // upstream changed this to relative_path ... is that right? + fs::path releaseFile(OS_RELEASE_FILE); + auto osRelease = iter.path() / releaseFile.relative_path(); + if (!fs::is_regular_file(osRelease)) +@@ -189,7 +190,6 @@ void ItemUpdater::processBMCImage() + // volumes created by the UBI layout for example have the id in + // the mount directory name. The worst that can happen is that + // erase() is called with an non-existent id and returns. +- auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); + ItemUpdater::erase(id); + + continue; +@@ -203,14 +203,11 @@ void ItemUpdater::processBMCImage() + + // Try to delete the version, same as above if the + // OS_RELEASE_FILE does not exist. +- auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); + ItemUpdater::erase(id); + + continue; + } + +- auto id = VersionClass::getId(version); +- + // Check if the id has already been added. This can happen if the + // BMC partitions / devices were manually flashed with the same + // image. diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch new file mode 100644 index 000000000..f150c1027 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0009-Add-ApplyOptions-D-bus-property-under-Software.patch @@ -0,0 +1,44 @@ +From 76f169e71be10b50b9617e606c38aff9553e6de8 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Fri, 15 May 2020 21:17:08 +0530 +Subject: [PATCH] Add ApplyOptions D-bus property under Software + +This change adds the ApplyOptions D-bus property +under xyz.openbmc_project.Software.BMC.Updater. +ApplyOptions is needed for BIOS NVRAM clear during +BIOS firmware update. ClearConfig attribute is passed +from RF to fwupd script. + +Tested: Set and Get of ClearConfig from fwupd.sh works + fine. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + item_updater.hpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/item_updater.hpp b/item_updater.hpp +index 3f0530f..5c1a779 100644 +--- a/item_updater.hpp ++++ b/item_updater.hpp +@@ -9,6 +9,7 @@ + #include <xyz/openbmc_project/Association/Definitions/server.hpp> + #include <xyz/openbmc_project/Common/FactoryReset/server.hpp> + #include <xyz/openbmc_project/Control/FieldMode/server.hpp> ++#include <xyz/openbmc_project/Software/ApplyOptions/server.hpp> + + #include <string> + #include <vector> +@@ -24,7 +25,8 @@ using ItemUpdaterInherit = sdbusplus::server::object::object< + sdbusplus::xyz::openbmc_project::Common::server::FactoryReset, + sdbusplus::xyz::openbmc_project::Control::server::FieldMode, + sdbusplus::xyz::openbmc_project::Association::server::Definitions, +- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>; ++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll, ++ sdbusplus::xyz::openbmc_project::Software::server::ApplyOptions>; + + namespace MatchRules = sdbusplus::bus::match::rules; + using VersionClass = phosphor::software::manager::Version; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch new file mode 100644 index 000000000..e72398efd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0010-Add-error-reporting-to-pfr_image_manager.patch @@ -0,0 +1,190 @@ +From ffa3642e436b559d8062f777f00458cc7b5ecb01 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Thu, 11 Jun 2020 13:30:02 -0700 +Subject: [PATCH 1/1] Add error reporting to pfr_image_manager + +This uses report functionality to update error +return status for redfish updates. + +Tested: Got 400 error with different messages based +on failure type + +{ + "error": { + "@Message.ExtendedInfo": [ + { + "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", + "Message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid archive.", + "MessageArgs": [ + "/redfish/v1/UpdateService", + "invalid archive" + ], + "MessageId": "OpenBMC.0.1.0.InvalidFile", + "Resolution": "None.", + "Severity": "Warning" + } + ], + "code": "OpenBMC.0.1.0.InvalidFile", + "message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid archive." + } +} + +{ + "error": { + "@Message.ExtendedInfo": [ + { + "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", + "Message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid image format.", + "MessageArgs": [ + "/redfish/v1/UpdateService", + "invalid image format" + ], + "MessageId": "OpenBMC.0.1.0.InvalidFile", + "Resolution": "None.", + "Severity": "Warning" + } + ], + "code": "OpenBMC.0.1.0.InvalidFile", + "message": "Invalid file uploaded to /redfish/v1/UpdateService: invalid image format." + } +} + +{ + "error": { + "@Message.ExtendedInfo": [ + { + "@odata.type": "#Message.v1_0_0.Message", + "Message": "The resource /redfish/v1/UpdateService was unable to satisfy the request due to unavailability of resources.", + "MessageArgs": [ + "/redfish/v1/UpdateService" + ], + "MessageId": "Base.1.4.0.ResourceExhaustion", + "Resolution": "Ensure that the resources are available and resubmit the request.", + "Severity": "Critical" + } + ], + "code": "Base.1.4.0.ResourceExhaustion", + "message": "The resource /redfish/v1/UpdateService was unable to satisfy the request due to unavailability of resources." + } +} + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + dbus_helpers.hpp | 30 ++++++++++++++++++++++++++++++ + pfr_image_manager.cpp | 18 ++++++++++++++++++ + 2 files changed, 48 insertions(+) + create mode 100644 dbus_helpers.hpp + +diff --git a/dbus_helpers.hpp b/dbus_helpers.hpp +new file mode 100644 +index 0000000..b9ffa36 +--- /dev/null ++++ b/dbus_helpers.hpp +@@ -0,0 +1,30 @@ ++#pragma once ++ ++#include "config.h" ++ ++#include <sdbusplus/bus.hpp> ++inline bool isFwupdScriptRunning(sdbusplus::bus::bus& bus) ++{ ++ using ObjectPath = sdbusplus::message::object_path; ++ // type is ssssssouso ++ using ListUnitsType = ++ std::tuple<std::string, std::string, std::string, std::string, ++ std::string, std::string, ObjectPath, uint32_t, std::string, ++ ObjectPath>; ++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, ++ SYSTEMD_INTERFACE, "ListUnits"); ++ ++ auto reply = bus.call(method); ++ std::vector<ListUnitsType> resp; ++ reply.read(resp); ++ ++ for (const auto& unit : resp) ++ { ++ if (std::get<0>(unit).find("fwupd@") != std::string::npos && ++ std::get<3>(unit) != "failed") ++ { ++ return true; ++ } ++ } ++ return false; ++} +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index 1a41cbe..fe1e6f9 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -2,6 +2,7 @@ + + #include "pfr_image_manager.hpp" + ++#include "dbus_helpers.hpp" + #include "version.hpp" + #include "watch.hpp" + +@@ -33,6 +34,9 @@ namespace manager + + using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; + namespace Software = phosphor::logging::xyz::openbmc_project::Software; ++using UnTarFail = Software::Image::UnTarFailure; ++using ImageFail = Software::Image::ImageFailure; ++using BusyFail = Software::Image::BusyFailure; + + static constexpr const uint32_t pfmPos = 2054; + static constexpr const uint32_t block0Magic = 0xB6EAFD19; +@@ -76,6 +80,8 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath, + phosphor::logging::log<phosphor::logging::level::ERR>( + "Image magic number match failed", + phosphor::logging::entry("IMAGEMAGIC=0x%x", imgMagic)); ++ phosphor::logging::report<UnTarFailure>( ++ UnTarFail::PATH(imgPath.c_str())); + return -1; + } + +@@ -110,6 +116,9 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath, + + phosphor::logging::log<phosphor::logging::level::ERR>( + "Unknown image type"); ++ phosphor::logging::report<ImageFailure>( ++ ImageFail::FAIL("Unknown image type"), ++ ImageFail::PATH(imgPath.c_str())); + return -1; + } + +@@ -153,6 +162,9 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath, + "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s", + redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s", + "Image HASH check fail", NULL); ++ phosphor::logging::report<ImageFailure>( ++ ImageFail::FAIL("Security violation: hash mismatch"), ++ ImageFail::PATH(imgPath.c_str())); + return -1; + } + +@@ -167,6 +179,9 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath, + catch (std::exception& e) + { + phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ phosphor::logging::report<ImageFailure>( ++ ImageFail::FAIL("Unhandled exception"), ++ ImageFail::PATH(imgPath.c_str())); + return -1; + } + } +@@ -182,6 +197,12 @@ int Manager::processImage(const std::string& imgFilePath) + if (!std::filesystem::exists(imgPath)) + return -1; + ++ if (isFwupdScriptRunning(bus)) ++ { ++ phosphor::logging::report<BusyFailure>(BusyFail::PATH(imgPath.c_str())); ++ return -1; ++ } ++ + int retry = 3; + std::string ver; + std::string purposeString; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0011-Fix-for-RedudancyPriority-in-item_updater.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0011-Fix-for-RedudancyPriority-in-item_updater.patch new file mode 100644 index 000000000..156e6fe7c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0011-Fix-for-RedudancyPriority-in-item_updater.patch @@ -0,0 +1,36 @@ +From f6022e25d0b47af502522913773e589fcdd1568e Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Sun, 5 Jul 2020 00:54:57 +0530 +Subject: [PATCH] Fix for RedudancyPriority in item_updater + +This fixes accessing RedudancyPriority property for the +activated image in item_updater. The downloaded image object +is not actually associated with RedudancyPriority before and +after activation. There exists no RedundancyPriority property +for downloaded image, accessing it causing a crash in +item_updater. + +Tested: Tested for coredumps during Seamless firmware update. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> + +--- + item_updater.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/item_updater.cpp b/item_updater.cpp +index c3a846d..b299b4d 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -690,8 +690,9 @@ void ItemUpdater::freeSpace(Activation& caller) + // Failed activations don't have priority, assign them a large value + // for sorting purposes. + auto priority = 999; +- if (iter.second.get()->activation() == +- server::Activation::Activations::Active) ++ if ((iter.second.get()->activation() == ++ server::Activation::Activations::Active)&& ++ iter.second->redundancyPriority.get()) + { + priority = iter.second->redundancyPriority.get()->priority(); + } diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch new file mode 100644 index 000000000..d5d0f513e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0013-remove-image-file-on-pre-script-failures.patch @@ -0,0 +1,40 @@ +From ae3a9616b44677f20b4ca534c3f55ccb478fdf55 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Thu, 16 Jul 2020 14:16:28 -0700 +Subject: [PATCH] remove image file on pre-script failures + +Multiple back-to-back updates of bad images will cause the software +manager to leave junk images hanging around. This is part of a fix that +will remove them if the software manager never gets around to launching +the fwupd.sh script. The other part is that the fwupd.sh script must +always delete the image file on exit, success or failure. + +Tested: posted a garbage file, saw that it was deleted even though + fwupd.sh was never invoked. + +Change-Id: I6b049916a3edcb48f9d4ebe0d4715b94214b4feb +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +--- + watch.cpp | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/watch.cpp b/watch.cpp +index ccdf594..c738945 100644 +--- a/watch.cpp ++++ b/watch.cpp +@@ -106,6 +106,15 @@ int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents, + { + log<level::ERR>("Error processing image", + entry("IMAGE=%s", tarballPath.c_str())); ++ std::error_code ec{}; ++ fs::remove_all(tarballPath, ec); ++ if (!ec) ++ { ++ log<level::ERR>( ++ "Unable to remove image on processing failure", ++ entry("ERROR=%s", ec.message().c_str()), ++ entry("IMAGE=%s", tarballPath.c_str())); ++ } + } + } + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch new file mode 100644 index 000000000..dfc7f2e58 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0014-PFR-image-verification.patch @@ -0,0 +1,116 @@ +From 9d82d53b50769506926dd99273f197a268d68fa3 Mon Sep 17 00:00:00 2001 +From: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com> +Date: Thu, 30 Jul 2020 09:50:40 +0000 +Subject: [PATCH] PFR-image-verification + +Add support verify the complete fw image by using mtd-util repo's +pfr_authenticate function. + +Tested. +1. Upload the corrupted image. +POST: https://<BMC_IP>/redfish/v1/UpdateService/ + with <Corrupted BMC_signed_cap> binary file +Response: +{ + "error": { + "@Message.ExtendedInfo": [ + { + "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message", + "Message": "Invalid file uploaded to /redfish/v1/UpdateService: + Invalid image format.", + "MessageArgs": [ + "/redfish/v1/UpdateService", + "Invalid image format" + ], + "MessageId": "OpenBMC.0.1.0.InvalidUpload", + "Resolution": "None.", + "Severity": "Warning" + } + ], + "code": "OpenBMC.0.1.0.InvalidUpload", + "message": "Invalid file uploaded to /redfish/v1/UpdateService: + Invalid image format." + } +} + +2. Upload the correct image. +POST: https://<BMC_IP>/redfish/v1/UpdateService/ + with <BMC_signed_cap> binary file + +Image verified and firmware updated. +{ + "@odata.id": "/redfish/v1/TaskService/Tasks/0", + "@odata.type": "#Task.v1_4_3.Task", + "Id": "0", + "TaskState": "Running", + "TaskStatus": "OK" +} + +Command: +GET: https://<BMC_IP>/redfish/v1/Systems/system/LogServices/EventLog/ + Entries + +Response: +{ + "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/ + Entries/1596082187", + "@odata.type": "#LogEntry.v1_4_0.LogEntry", + "Created": "2020-07-30T04:09:47+00:00", + "EntryType": "Event", + "Id": "1596082187", + "Message": "BMC firmware update to version 00.72 completed + successfully.", + "MessageArgs": [ + "BMC", + "00.72" + ], + "MessageId": "OpenBMC.0.1.FirmwareUpdateCompleted", + "Name": "System Event Log Entry", + "Severity": "OK" + }, + +Signed-off-by: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com> +--- + pfr_image_manager.cpp | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index eeed4fe..16231fa 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -15,6 +15,7 @@ + #include <time.h> + #include <unistd.h> + ++#include <boost/process/child.hpp> + #include <elog-errors.hpp> + #include <xyz/openbmc_project/Software/Image/error.hpp> + +@@ -122,6 +123,24 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath, + return -1; + } + ++ // Verify the complete image ++ std::string mtdUtilfile = "/usr/bin/mtd-util"; ++ std::vector<std::string> mtdUtilCmd = {"p", "a"}; ++ mtdUtilCmd.push_back(imgPath); ++ ++ boost::process::child execProg(mtdUtilfile, mtdUtilCmd); ++ execProg.wait(); ++ if (execProg.exit_code()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image authentication failed"); ++ phosphor::logging::report<ImageFailure>( ++ ImageFail::FAIL( ++ "Security violation: image authentication failure"), ++ ImageFail::PATH(imgPath.c_str())); ++ return -1; ++ } ++ + imgFile.seekg(pfmPos, + std::ios::beg); // Version is at 0x806 in the PFM + imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData)); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch new file mode 100644 index 000000000..bc94f00af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0016-Process-PLDM-image-type.patch @@ -0,0 +1,234 @@ +From a78b7a609f58ac82623c357426ef0590d6d76971 Mon Sep 17 00:00:00 2001 +From: Ayushi Smriti <smriti.ayushi@intel.com> +Date: Mon, 9 Nov 2020 23:04:58 +0530 +Subject: [PATCH] Process PLDM image type + +This change is to check whether the image uploaded is of PLDM image +type based on the PackageHeaderIdentifier check which is a 16 bytes +uuid field in the pldm package header. + +Also, determine image purpose and version. +Purpose is set to pldm enum type and for version, PackageVersionString +is concluded based on PackageVersionStringLength value. + +Tested: +- On uploading a pldm image through Redfish. Uuid is identified and +matched correctly. +- Purpose and version is given to the image as expected and activation +intf got added. + - verified same with busctl cmd on xyz.openbmc_project.Software.Version + and xyz.openbmc_project.Software.BMC.Updater +- Verified the regular PFR update procedure works + - received expected redfish response from postman + - verified fwupd.sh script is reached + +Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com> +--- + item_updater.cpp | 4 +- + pfr_image_manager.cpp | 95 +++++++++++++++++++++++++++++++++++++++++-- + pfr_image_manager.hpp | 6 +-- + pldm.hpp | 21 ++++++++++ + 4 files changed, 119 insertions(+), 7 deletions(-) + create mode 100644 pldm.hpp + +diff --git a/item_updater.cpp b/item_updater.cpp +index db255d6..7af80e3 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -67,6 +67,7 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg) + #if defined(HOST_BIOS_UPGRADE) || defined(PFR_UPDATE) + value == VersionPurpose::Host || + #endif ++ value == VersionPurpose::PLDM || + value == VersionPurpose::Other) + { + purpose = value; +@@ -397,7 +398,8 @@ void ItemUpdater::deleteAll() + } + + ItemUpdater::ActivationStatus +- ItemUpdater::validateSquashFSImage(const std::string& filePath) ++ ItemUpdater::validateSquashFSImage(__attribute__((unused)) ++ const std::string& filePath) + { + #ifndef PFR_UPDATE + bool valid = true; +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index 178367f..c923494 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -3,6 +3,7 @@ + #include "pfr_image_manager.hpp" + + #include "dbus_helpers.hpp" ++#include "pldm.hpp" + #include "version.hpp" + #include "watch.hpp" + +@@ -44,9 +45,10 @@ using BusyFail = Software::Image::BusyFailure; + static constexpr const uint32_t pfmPos = 2054; + static constexpr const uint32_t block0Magic = 0xB6EAFD19; + static constexpr const uint32_t lengthBlk0Blk1 = 1024; ++static constexpr const uint32_t pldmMagic = 0xF018878C; + +-int Manager::verifyPFRImage(const std::filesystem::path imgPath, +- std::string& version, std::string& purposeString) ++int Manager::verifyImage(const std::filesystem::path imgPath, ++ std::string& version, std::string& purposeString) + { + uint8_t imgType = 0; + uint32_t imgMagic = 0; +@@ -76,6 +78,93 @@ int Manager::verifyPFRImage(const std::filesystem::path imgPath, + + imgMagic = block0Data.tag; + ++ if (htobe32(imgMagic) == pldmMagic) ++ { ++ if (!version.empty()) ++ { ++ version.clear(); ++ } ++ ++ imgFile.seekg(0, std::ios_base::end); ++ ++ const size_t length = imgFile.tellg(); ++ constexpr size_t readBytes = 36; ++ ++ if (length < readBytes) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Insufficient file length to read the required " ++ "bytes"); ++ return -1; ++ } ++ ++ imgFile.seekg(0, std::ios::beg); ++ ++ std::array<char, readBytes> buffer = {}; ++ ++ imgFile.read( ++ buffer.data(), ++ buffer.size()); // read 36 bytes of PLDM Package Header ++ ++ if (!imgFile.good()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image file read is not successful"); ++ return -1; ++ } ++ ++ if (!std::equal(buffer.begin(), ++ buffer.begin() + pldm::headerIdLen, ++ pldm::pldmPkgHeaderId ++ .begin())) // comparing 16 bytes of ++ // PackageHeaderIdentifier field ++ { ++ std::string redfishMsgID = ++ "OpenBMC.0.1.FirmwareUpdateFailed"; ++ sd_journal_send( ++ "MESSAGE=%s", "Firmware image verification failed", ++ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s", ++ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s", ++ "PLDM Image package header identifier check fail", ++ NULL); ++ ++ return -1; ++ } ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Package header identifier matched"); ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.PLDM"; ++ ++ const uint8_t pkgVerStrLen = static_cast<uint8_t>( ++ buffer[35]); // PackageVersionStringLen byte ++ ++ imgFile.seekg(readBytes, ++ std::ios::beg); // point to the begin of ++ // PackageVersionString field ++ // i.e. 36th pos ++ ++ std::array<char, 255> ver = {}; ++ imgFile.read(ver.data(), ++ pkgVerStrLen); // read PackageVersionString bytes ++ ++ if (!imgFile.good()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image file read is not successful"); ++ return -1; ++ } ++ ++ version.assign(ver.data(), pkgVerStrLen); ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Package version string value", ++ phosphor::logging::entry("IMAGE_VERSION=%s", ++ version.c_str())); ++ ++ imgFile.close(); ++ return 0; ++ } ++ + if (imgMagic != block0Magic) + { + phosphor::logging::log<phosphor::logging::level::ERR>( +@@ -226,7 +315,7 @@ int Manager::processImage(const std::string& imgFilePath) + std::string ver; + std::string purposeString; + +- if (0 != verifyPFRImage(imgFilePath, ver, purposeString)) ++ if (0 != verifyImage(imgFilePath, ver, purposeString)) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Error verifying uploaded image"); +diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp +index 3591f1a..2facfe6 100644 +--- a/pfr_image_manager.hpp ++++ b/pfr_image_manager.hpp +@@ -156,13 +156,13 @@ class Manager + CustomMap mapFile(const std::filesystem::path& path, size_t size); + + /** +- * @brief Verify the PFR image and return version and purpose ++ * @brief Verify the uploaded image type and return version and purpose + * @param[in] - file path + * @param[out] - version + * @param[out] - purpose + */ +- int verifyPFRImage(const std::filesystem::path imgPath, +- std::string& version, std::string& purposeString); ++ int verifyImage(const std::filesystem::path imgPath, std::string& version, ++ std::string& purposeString); + /** @brief Persistent map of Version dbus objects and their + * version id */ + std::map<std::string, std::unique_ptr<Version>> versions; +diff --git a/pldm.hpp b/pldm.hpp +new file mode 100644 +index 0000000..edbd6ae +--- /dev/null ++++ b/pldm.hpp +@@ -0,0 +1,21 @@ ++namespace pldm ++{ ++ ++struct PldmPkgHeader ++{ ++ uint8_t uuid[16]; // PackageHeaderIdentifier ++ uint8_t formatRev; // PackageHeaderFormatRevision ++ uint16_t headerSize; // PackageHeaderSize ++ uint8_t timestamp[13]; // PackageReleaseDateTime ++ uint16_t bitmapLen; // ComponentBitmapBitLength ++ uint8_t verStringType; // PackageVersionStringType ++ uint8_t verStringLen; // PackageVersionStringLength ++} __attribute__((packed)); ++ ++constexpr size_t headerIdLen = 16; ++ ++const std::array<char, headerIdLen> pldmPkgHeaderId = { ++ 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43, ++ 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02}; // 16 bytes package header ++ // identifier uuid ++} // namespace pldm +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch new file mode 100644 index 000000000..d21dbd63c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0017-Fix-build-error.patch @@ -0,0 +1,34 @@ +From 1f3531eff8a05bb5375dea89c1ca9292f69863b0 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 11 Mar 2021 11:42:39 -0800 +Subject: [PATCH] Fix build error + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + pfr_image_manager.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index f844b8e79565..55ad21f8a3d4 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -333,6 +333,7 @@ int Manager::processImage(const std::string& imgFilePath) + + int retry = 3; + std::string ver; ++ std::string extVer; + std::string purposeString; + + if (0 != verifyImage(imgFilePath, ver, purposeString)) +@@ -398,7 +399,7 @@ int Manager::processImage(const std::string& imgFilePath) + std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; + + auto versionPtr = std::make_unique<Version>( +- bus, objPath, ver, purpose, imageDirPath.string(), ++ bus, objPath, ver, purpose, extVer, imageDirPath.string(), + std::bind(&Manager::erase, this, std::placeholders::_1)); + versionPtr->deleteObject = + std::make_unique<phosphor::software::manager::Delete>(bus, objPath, +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch new file mode 100644 index 000000000..587421044 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch @@ -0,0 +1,175 @@ +From 19661c1173d9d82dfbb879f8cc89c05a0883dffa Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 21 Apr 2021 21:16:47 +0000 +Subject: [PATCH] Fix delete image by ID and inhibit removal of bmc_active + +Delete image by ID was broken because when hitting the delete dbus +interface, it recalculated the ID from the parent version, which then +does not match because of the random number addition that was added +to the ID when the parent interface was created. This saves away the +parent interface ID and recalls it rather than recalculating it. + +Also, there was a logic error in deleting images that would delete the +active BMC image. This fixes up that error. + +Tested: run multiple back-to back updates and see that when the fwupd + script calls delete on the seamless images, the interfaces are + deleted and that the bmc_active interface is not deleted. + +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + image_manager.cpp | 2 +- + item_updater.cpp | 20 +++++++++++++------- + pfr_image_manager.cpp | 2 +- + version.cpp | 2 +- + version.hpp | 19 +++++++++++++++---- + 5 files changed, 31 insertions(+), 14 deletions(-) + +diff --git a/image_manager.cpp b/image_manager.cpp +index 4be357f..311a63f 100644 +--- a/image_manager.cpp ++++ b/image_manager.cpp +@@ -219,7 +219,7 @@ int Manager::processImage(const std::string& tarFilePath) + { + // Create Version object + auto versionPtr = std::make_unique<Version>( +- bus, objPath, version, purpose, extendedVersion, ++ bus, objPath, id, version, purpose, extendedVersion, + imageDirPath.string(), + std::bind(&Manager::erase, this, std::placeholders::_1)); + versionPtr->deleteObject = +diff --git a/item_updater.cpp b/item_updater.cpp +index 6efd519..6685bf5 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -145,7 +145,7 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg) + activationState, associations))); + + auto versionPtr = std::make_unique<VersionClass>( +- bus, path, version, purpose, extendedVersion, filePath, ++ bus, path, versionId, version, purpose, extendedVersion, filePath, + std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); + versionPtr->deleteObject = + std::make_unique<phosphor::software::manager::Delete>(bus, path, +@@ -263,7 +263,7 @@ void ItemUpdater::processBMCImage() + + // Create Version instance for this version. + auto versionPtr = std::make_unique<VersionClass>( +- bus, path, version, purpose, extendedVersion, "", ++ bus, path, id, version, purpose, extendedVersion, "", + std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); + auto isVersionFunctional = versionPtr->isFunctional(); + if (!isVersionFunctional) +@@ -338,11 +338,11 @@ void ItemUpdater::erase(std::string entryId) + auto it = versions.find(entryId); + if (it != versions.end()) + { +- if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1) ++ if (it->second->isFunctional()) + { +- log<level::ERR>("Error: Version is currently running on the BMC. " +- "Unable to remove.", +- entry("VERSIONID=%s", entryId.c_str())); ++ log<level::INFO>("Error: Version is currently running on the BMC. " ++ "Unable to remove.", ++ entry("VERSIONID=%s", entryId.c_str())); + return; + } + } +@@ -681,6 +681,12 @@ void ItemUpdater::freeSpace(Activation& caller) + std::size_t count = 0; + for (const auto& iter : activations) + { ++ if (versions.find(iter.second->versionId)->second->isFunctional()) ++ { ++ // don't bother with function versions ++ continue; ++ } ++ + if ((iter.second.get()->activation() == + server::Activation::Activations::Active) || + (iter.second.get()->activation() == +@@ -775,7 +781,7 @@ void ItemUpdater::createBIOSObject() + // Do nothing; + }; + biosVersion = std::make_unique<VersionClass>( +- bus, path, version, VersionPurpose::Host, "", "", ++ bus, path, versionId, version, VersionPurpose::Host, "", "", + std::bind(dummyErase, std::placeholders::_1)); + biosVersion->deleteObject = + std::make_unique<phosphor::software::manager::Delete>(bus, path, +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index 55ad21f..e2dcc80 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -399,7 +399,7 @@ int Manager::processImage(const std::string& imgFilePath) + std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; + + auto versionPtr = std::make_unique<Version>( +- bus, objPath, ver, purpose, extVer, imageDirPath.string(), ++ bus, objPath, id, ver, purpose, extVer, imageDirPath.string(), + std::bind(&Manager::erase, this, std::placeholders::_1)); + versionPtr->deleteObject = + std::make_unique<phosphor::software::manager::Delete>(bus, objPath, +diff --git a/version.cpp b/version.cpp +index 04f40c4..44ef571 100644 +--- a/version.cpp ++++ b/version.cpp +@@ -206,7 +206,7 @@ void Delete::delete_() + { + if (parent.eraseCallback) + { +- parent.eraseCallback(parent.getId(parent.version())); ++ parent.eraseCallback(parent.getExtId()); + } + } + +diff --git a/version.hpp b/version.hpp +index 8a68cb5..afc589c 100644 +--- a/version.hpp ++++ b/version.hpp +@@ -77,11 +77,11 @@ class Version : public VersionInherit + * @param[in] callback - The eraseFunc callback + */ + Version(sdbusplus::bus::bus& bus, const std::string& objPath, +- const std::string& versionString, VersionPurpose versionPurpose, +- const std::string& extVersion, const std::string& filePath, +- eraseFunc callback) : ++ const std::string& extId, const std::string& versionString, ++ VersionPurpose versionPurpose, const std::string& extVersion, ++ const std::string& filePath, eraseFunc callback) : + VersionInherit(bus, (objPath).c_str(), true), +- eraseCallback(callback), versionStr(versionString) ++ eraseCallback(callback), versionStr(versionString), extId(extId) + { + // Set properties. + extendedVersion(extVersion); +@@ -150,6 +150,15 @@ class Version : public VersionInherit + */ + bool isFunctional(); + ++ /* @brief Return the extended ID of this version object ++ * ++ * @ return - returns the extended ID string ++ */ ++ std::string getExtId() ++ { ++ return extId; ++ } ++ + /** @brief Persistent Delete D-Bus object */ + std::unique_ptr<Delete> deleteObject; + +@@ -159,6 +168,8 @@ class Version : public VersionInherit + private: + /** @brief This Version's version string */ + const std::string versionStr; ++ /** @brief This is extended version string */ ++ const std::string extId; + }; + + } // namespace manager +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service new file mode 100644 index 000000000..d21647611 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service @@ -0,0 +1,8 @@ +[Unit]
+Description=Flash BMC with fwupd script : %I
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/bin/systemd-inhibit --what=shutdown:sleep --who=fwupd --why "Firmware Update %i" --mode=block /usr/bin/fwupd.sh %i
+SyslogIdentifier=fwupd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend new file mode 100644 index 000000000..63e0aff25 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend @@ -0,0 +1,30 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +EXTRA_OEMESON += "-Dfwupd-script=enabled" + +SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service" + +EXTRA_OEMESON += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-Dpfr-update=enabled', '', d)}" + +SRC_URI += " \ + file://0002-Redfish-firmware-activation.patch \ + file://0004-Changed-the-condition-of-software-version-service-wa.patch \ + file://0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch \ + file://0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch \ + file://0007-Adding-StandBySpare-for-firmware-activation.patch \ + file://0008-item_updater-update-the-bmc_active-objectPath.patch \ + file://0009-Add-ApplyOptions-D-bus-property-under-Software.patch \ + file://0011-Fix-for-RedudancyPriority-in-item_updater.patch \ + file://0013-remove-image-file-on-pre-script-failures.patch \ + " + +SRC_URI_PFR = " \ + file://0007-PFR-images-support.patch \ + file://0008-PFR-image-HASH-verification.patch \ + file://0010-Add-error-reporting-to-pfr_image_manager.patch \ + file://0014-PFR-image-verification.patch \ + file://0016-Process-PLDM-image-type.patch \ + file://0017-Fix-build-error.patch \ + file://0018-Fix-delete-image-by-ID-and-inhibit-removal-of-bmc_ac.patch \ + " + +SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', SRC_URI_PFR, '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb new file mode 100644 index 000000000..da8fc846e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb @@ -0,0 +1,32 @@ +SUMMARY = "Default Fru" +DESCRIPTION = "Builds a default FRU file at runtime based on board ID" + +inherit systemd +inherit cmake + +SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service" + +S = "${WORKDIR}" +SRC_URI = "file://checkFru.sh \ + file://decodeBoardID.sh \ + file://SetBaseboardFru.service \ + file://mkfru.cpp \ + file://CMakeLists.txt \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "\ + file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \ + file://mkfru.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \ + " + +RDEPENDS_${PN} = "bash" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh + install -m 0755 ${S}/decodeBoardID.sh ${D}/${bindir}/decodeBoardID.sh + + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/SetBaseboardFru.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt new file mode 100644 index 000000000..a8e633644 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(mkfru CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(mkfru mkfru.cpp) +install(TARGETS mkfru DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service new file mode 100644 index 000000000..d8c2a75ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service @@ -0,0 +1,9 @@ +[Unit] +Description=Check for FRU presence + +[Service] +ExecStart=/usr/bin/checkFru.sh +Type=oneshot + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh new file mode 100755 index 000000000..18a6c7260 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# this script checks the gpio id and loads the correct baseboard fru +FRUPATH="/etc/fru" +PRODIDPATH="/var/cache/private" +fruFile="$FRUPATH/baseboard.fru.bin" +prodIDFile="$PRODIDPATH/prodID" +source decodeBoardID.sh + +read_id() { + local idx=0 + local result=0 + local value=0 + for ((idx=0; idx<6; idx++)) + do + typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N")) + value=$((value << idx)) + result=$((result | value)) + done + echo $result +} + +if [ -f $fruFile -a -f $prodIDFile ] && + grep -q 'CPU part\s*: 0xc07' /proc/cpuinfo; then + exit 0 +fi + +NAME="Unknown" +PRODID="0x00" +EEPROM_FRU=false + +BOARD_ID=$(read_id) +decode_board_id + +if [ ! -e $prodIDFile ] +then + echo $PRODID >$prodIDFile +fi + +if $EEPROM_FRU; +then + # Remove baseboard filesystem FRU(if any), as this platform has EEPROM FRU. + rm -f $fruFile + exit 0 +fi + +if [ ! -f $fruFile ] +then + cd /tmp + mkdir -p $FRUPATH + mkfru $NAME + mv $NAME.fru.bin $fruFile +fi + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh new file mode 100644 index 000000000..80710ae26 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/decodeBoardID.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# this script uses the BOARD_ID set from checkFru.sh and provides the NAME, +# PRODID, and EEPROM_FRU values for this platform +decode_board_id() { +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp new file mode 100644 index 000000000..afadbd324 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp @@ -0,0 +1,219 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: default FRU generation +// +*/ + +#include <fstream> +#include <iostream> +#include <iterator> +#include <numeric> +#include <string> +#include <vector> + +constexpr uint8_t fillChar = '.'; +constexpr uint8_t eof = 0xc1; +const std::string intel = "Intel Corporation"; + +// round up to nearest block size (power of 2) +constexpr size_t blockRound(size_t len, size_t blk) +{ + return ((len) + (((blk) - ((len) & ((blk)-1))) & ((blk)-1))); +} + +uint8_t mklen(uint8_t len) +{ + return static_cast<uint8_t>((0x3 << 6) | len); +} + +struct FruEntry +{ + static constexpr size_t fruBlockSize = 8; // type, length, checksum + static constexpr size_t fixedBytes = 3; // type, length, checksum + FruEntry() = delete; + FruEntry(const std::vector<uint8_t>& contents) + { + constexpr size_t verOffset = 0; + constexpr size_t lenOffset = 1; + value.resize(blockRound(fixedBytes + contents.size(), fruBlockSize)); + value[verOffset] = 1; + value[lenOffset] = blocks(); + std::copy(contents.begin(), contents.end(), value.begin() + 2); + addChecksum(); + } + + void addChecksum() + { + int sum = std::accumulate(value.begin(), value.end(), 0); + value.back() = static_cast<uint8_t>(256 - sum & 0xff); + } + + uint8_t blocks() const + { + return static_cast<uint8_t>(value.size() / 8); + } + + std::vector<uint8_t> value; +}; + +size_t fillDots(std::vector<uint8_t>::iterator start, size_t count) +{ + *start++ = mklen(count); // prefix with (0xc0 | count) + auto end = start + count++; + std::fill(start, end, '.'); + return count; +} + +size_t fillStr(std::vector<uint8_t>::iterator start, const std::string& str) +{ + size_t count = str.size(); + *start++ = mklen(count++); // prefix with (0xc0 | count) + std::copy(str.begin(), str.end(), start); + return count; +} + +std::vector<uint8_t> genChassisContents() +{ + constexpr size_t pnSize = 18; + constexpr size_t snSize = 18; + constexpr size_t amSize = 31; + constexpr size_t headerSize = 1; + constexpr size_t contentSize = headerSize + 1 + pnSize + 1 + snSize + 1 + + amSize + 1 + amSize + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0x17; + // chassis part number + offset += fillDots(data.begin() + offset, pnSize); + // chassis serial number + offset += fillDots(data.begin() + offset, snSize); + // info am1 + offset += fillDots(data.begin() + offset, amSize); + // info am2 + offset += fillDots(data.begin() + offset, amSize); + data[offset] = eof; + + return data; +} + +std::vector<uint8_t> genBoardContents(const std::string& name) +{ + constexpr size_t headerSize = 4; + constexpr size_t snSize = 12; + constexpr size_t pnSize = 10; + const std::string version = "FRU Ver 0.01"; + size_t contentSize = headerSize + 1 + name.size() + 1 + intel.size() + 1 + + snSize + 1 + pnSize + 1 + version.size() + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0; // language code + data[offset++] = 0; // mfg date/time + data[offset++] = 0; // mfg date/time + data[offset++] = 0; // mfg date/time + // manufacturer name + offset += fillStr(data.begin() + offset, intel); + // product name + offset += fillStr(data.begin() + offset, name); + // board sn + offset += fillDots(data.begin() + offset, snSize); + // board pn + offset += fillDots(data.begin() + offset, pnSize); + // fru version string + offset += fillStr(data.begin() + offset, version); + data[offset] = eof; + + return data; +} + +std::vector<uint8_t> genProductContents(const std::string& name) +{ + constexpr size_t headerSize = 1; + constexpr size_t pnSize = 10; + constexpr size_t pvSize = 20; + constexpr size_t snSize = 12; + constexpr size_t atSize = 20; + constexpr size_t idSize = 0; + const std::string version = "FRU Ver 0.01"; + size_t contentSize = headerSize + 1 + intel.size() + 1 + name.size() + 1 + + pnSize + 1 + pvSize + 1 + snSize + 1 + atSize + 1 + + idSize + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0; // language code + // manufacturer name + offset += fillStr(data.begin() + offset, intel); + // product name + offset += fillStr(data.begin() + offset, name); + // product part number + offset += fillDots(data.begin() + offset, pnSize); + // product version + offset += fillDots(data.begin() + offset, pvSize); + // product serial number + offset += fillDots(data.begin() + offset, snSize); + // product asset tag + offset += fillDots(data.begin() + offset, atSize); + // empty fru file id + offset += fillDots(data.begin() + offset, idSize); + data[offset] = eof; + + return data; +} + +int createFru(const std::string& name) +{ + std::vector<uint8_t> internal{1, 0, 0, 0, 0, 0, 0, 1}; // fixed data + FruEntry chassis(genChassisContents()); + FruEntry board(genBoardContents(name)); + FruEntry product(genProductContents(name)); + uint8_t offset = 1; // room for header's offset + FruEntry header({ + offset += 1, // internal size + offset += chassis.blocks(), + offset += board.blocks(), + }); + std::string filename = name + ".fru.bin"; + std::ofstream output(filename); + std::ostream_iterator<uint8_t> outputIter(output); + std::copy(header.value.begin(), header.value.end(), outputIter); + std::copy(internal.begin(), internal.end(), outputIter); + std::copy(chassis.value.begin(), chassis.value.end(), outputIter); + std::copy(board.value.begin(), board.value.end(), outputIter); + std::copy(product.value.begin(), product.value.end(), outputIter); + constexpr size_t minFruSize = 0x1ff; + size_t fruSize = header.value.size() + internal.size() + + chassis.value.size() + board.value.size() + + product.value.size(); + if (fruSize < minFruSize) + { + std::vector<uint8_t> padding(minFruSize - fruSize); + std::copy(padding.begin(), padding.end(), outputIter); + } + output.close(); + return 0; +} + +int main(int argc, const char* argv[]) +{ + if (argc != 2) + { + std::cerr << "Usage: " << argv[0] << " <'Product Name'>\n"; + return 1; + } + return createFru(argv[1]); +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend new file mode 100644 index 000000000..5326680f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend @@ -0,0 +1,6 @@ +SYSTEMD_LINK_${PN}_remove += "../op-start-host@.service:obmc-host-startmin@0.target.requires/op-start-host@0.service" +SYSTEMD_LINK_${PN}_remove += "../op-init-pnor@.service:obmc-host-startmin@0.target.requires/op-init-pnor@0.service" + +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-start-host@0.service" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-init-pnor@0.service"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend new file mode 100644 index 000000000..ff30bacfb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/phosphor-host-postd_git.bbappend @@ -0,0 +1,4 @@ +DEPENDS += " gtest" + +#SRC_URI = "git://github.com/openbmc/phosphor-host-postd.git" +SRCREV = "2a744b2d70ce9de8519a7c716da5009cb049db17" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Add-ConnectedVia-property-to-virtual-media-item-temp.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Add-ConnectedVia-property-to-virtual-media-item-temp.patch new file mode 100644 index 000000000..ec6d70df1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Add-ConnectedVia-property-to-virtual-media-item-temp.patch @@ -0,0 +1,25 @@ +From 4af788655c5b5a5fae4d85b365a70dc619810fe0 Mon Sep 17 00:00:00 2001 +From: Karol Wachowski <karol.wachowski@intel.com> +Date: Thu, 11 Feb 2021 08:35:41 +0000 +Subject: [PATCH] Add ConnectedVia property to virtual media item template + +Tested: Verified that ConnectedVia property is returned and set to + "NotConnected" for disconnected media. + +Signed-off-by: Karol Wachowski <karol.wachowski@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 188248a..80e7315 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -192,6 +192,7 @@ static nlohmann::json vmItemTemplate(const std::string& name, + item["@odata.id"] = + "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName; + item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia"; ++ item["ConnectedVia"] = "NotConnected"; + item["Name"] = "Virtual Removable Media"; + item["Id"] = resName; + item["WriteProtected"] = true; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch new file mode 100755 index 000000000..193461baf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch @@ -0,0 +1,696 @@ +From 10cb7cb14974725a29b3ead4c543ca5e58234c07 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Wed, 18 Nov 2020 17:14:41 +0530 +Subject: [PATCH] Firmware update configuration changes + +This commit will provide user to PATCH the below firmware update +attributes before uploding the firmware image. + +1. This will have PATCH support for 'HttpPushUriTargets' and +'HttpPushUriTargetsBusy' attributes. These attributes enables +'HttpPushUri' to distinguish between the firmware update targets. + +2. ApplyOptions are used to specify firmware update specific options +such as ClearConfig which is used while activating the updated +firmware. This setting is maintained in a local static variable +when set using PATCH method. Its used in activate image as input +parameter. This attribute is added as Oem as the default +UpdateService interface doesn't specify any relevant or appropriate +attribute for this. + +Tested: + - GET on "/redfish/v1/UpdateService", got below response +......... + "HttpPushUriTargets": [], + "HttpPushUriTargetsBusy": false +........ + + - PATCH on "/redfish/v1/UpdateService" and works fine. +{ + "HttpPushUriTargets": ["bmc_recovery"], + "HttpPushUriTargetsBusy": true +} + + - Did Firmware update and verified end to end functionality + for both bmc active and backup images. + + - Tested setting ClearConfig to true or false using PATCH + method. + + - Successfully ran redfish validater with no new errors. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> + +%% original patch: 0001-Firmware-update-configuration-changes.patch + +Change-Id: I44e1743fd76aa37c7b8affa49a3e05f808187037 +Signed-off-by: Helen Huang <he.huang@intel.com> +--- + redfish-core/lib/update_service.hpp | 339 ++++++++++++++++-- + static/redfish/v1/$metadata/index.xml | 3 + + .../JsonSchemas/OemUpdateService/index.json | 69 ++++ + .../redfish/v1/schema/OemUpdateService_v1.xml | 40 +++ + 4 files changed, 421 insertions(+), 30 deletions(-) + create mode 100644 static/redfish/v1/JsonSchemas/OemUpdateService/index.json + create mode 100644 static/redfish/v1/schema/OemUpdateService_v1.xml + +diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp +index 6d44171..8eda265 100644 +--- a/redfish-core/lib/update_service.hpp ++++ b/redfish-core/lib/update_service.hpp +@@ -32,6 +32,17 @@ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher; + static bool fwUpdateInProgress = false; + // Timer for software available + static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer; ++static constexpr const char* versionIntf = ++ "xyz.openbmc_project.Software.Version"; ++static constexpr const char* activationIntf = ++ "xyz.openbmc_project.Software.Activation"; ++static constexpr const char* reqActivationPropName = "RequestedActivation"; ++static constexpr const char* reqActivationsActive = ++ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"; ++static constexpr const char* reqActivationsStandBySpare = ++ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare"; ++static constexpr const char* activationsStandBySpare = ++ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare"; + + static void cleanUp() + { +@@ -40,27 +51,119 @@ static void cleanUp() + fwUpdateErrorMatcher = nullptr; + } + static void activateImage(const std::string& objPath, +- const std::string& service) ++ const std::string& service, ++ const std::vector<std::string>& imgUriTargets) + { + BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; ++ // If targets is empty, it will apply to the active. ++ if (imgUriTargets.size() == 0) ++ { ++ crow::connections::systemBus->async_method_call( ++ [](const boost::system::error_code error_code) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "RequestedActivation failed: error_code = " ++ << error_code; ++ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); ++ } ++ }, ++ service, objPath, "org.freedesktop.DBus.Properties", "Set", ++ activationIntf, reqActivationPropName, ++ std::variant<std::string>(reqActivationsActive)); ++ return; ++ } ++ ++ // TODO: Now we support only one target becuase software-manager ++ // code support one activation per object. It will be enhanced ++ // to multiple targets for single image in future. For now, ++ // consider first target alone. + crow::connections::systemBus->async_method_call( +- [](const boost::system::error_code errorCode) { +- if (errorCode) ++ [objPath, service, imgTarget{imgUriTargets[0]}]( ++ const boost::system::error_code ec, ++ const crow::openbmc_mapper::GetSubTreeType& subtree) { ++ if (ec || !subtree.size()) + { +- BMCWEB_LOG_DEBUG << "error_code = " << errorCode; +- BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message(); ++ return; ++ } ++ ++ for (const auto& [invObjPath, invDict] : subtree) ++ { ++ std::size_t idPos = invObjPath.rfind("/"); ++ if ((idPos == std::string::npos) || ++ ((idPos + 1) >= invObjPath.size())) ++ { ++ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; ++ return; ++ } ++ std::string swId = invObjPath.substr(idPos + 1); ++ ++ if (swId != imgTarget) ++ { ++ continue; ++ } ++ ++ if (invDict.size() < 1) ++ { ++ continue; ++ } ++ BMCWEB_LOG_DEBUG << "Image target matched with object " ++ << invObjPath; ++ crow::connections::systemBus->async_method_call( ++ [objPath, ++ service](const boost::system::error_code error_code, ++ const std::variant<std::string> value) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "Error in querying activation value"; ++ // not all fwtypes are updateable, ++ // this is ok ++ return; ++ } ++ std::string activationValue = ++ std::get<std::string>(value); ++ BMCWEB_LOG_DEBUG << "Activation Value: " ++ << activationValue; ++ std::string reqActivation = reqActivationsActive; ++ if (activationValue == activationsStandBySpare) ++ { ++ reqActivation = reqActivationsStandBySpare; ++ } ++ BMCWEB_LOG_DEBUG ++ << "Setting RequestedActivation value as " ++ << reqActivation << " for " << service << " " ++ << objPath; ++ crow::connections::systemBus->async_method_call( ++ [](const boost::system::error_code error_code) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "RequestedActivation failed: ec = " ++ << error_code; ++ } ++ return; ++ }, ++ service, objPath, "org.freedesktop.DBus.Properties", ++ "Set", activationIntf, reqActivationPropName, ++ std::variant<std::string>(reqActivation)); ++ }, ++ invDict[0].first, ++ "/xyz/openbmc_project/software/" + imgTarget, ++ "org.freedesktop.DBus.Properties", "Get", activationIntf, ++ "Activation"); + } + }, +- service, objPath, "org.freedesktop.DBus.Properties", "Set", +- "xyz.openbmc_project.Software.Activation", "RequestedActivation", +- std::variant<std::string>( +- "xyz.openbmc_project.Software.Activation.RequestedActivations." +- "Active")); ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", ++ static_cast<int32_t>(0), std::array<const char*, 1>{versionIntf}); + } + + // Note that asyncResp can be either a valid pointer or nullptr. If nullptr + // then no asyncResp updates will occur + static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, ++ const std::vector<std::string> imgUriTargets, + sdbusplus::message::message& m, + const crow::Request& req) + { +@@ -73,22 +176,24 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, + + m.read(objPath, interfacesProperties); + +- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; ++ BMCWEB_LOG_DEBUG << "Software Interface Added. obj path = " << objPath.str; + for (auto& interface : interfacesProperties) + { + BMCWEB_LOG_DEBUG << "interface = " << interface.first; + +- if (interface.first == "xyz.openbmc_project.Software.Activation") ++ if (interface.first == activationIntf) + { + // Retrieve service and activate + crow::connections::systemBus->async_method_call( +- [objPath, asyncResp, ++ [objPath, asyncResp, imgTargets{imgUriTargets}, + req](const boost::system::error_code errorCode, + const std::vector<std::pair< + std::string, std::vector<std::string>>>& objInfo) { + if (errorCode) + { +- BMCWEB_LOG_DEBUG << "error_code = " << errorCode; ++ BMCWEB_LOG_DEBUG ++ << "GetSoftwareObject path failed: error_code = " ++ << errorCode; + BMCWEB_LOG_DEBUG << "error msg = " + << errorCode.message(); + if (asyncResp) +@@ -115,7 +220,7 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, + // is added + fwAvailableTimer = nullptr; + +- activateImage(objPath.str, objInfo[0].first); ++ activateImage(objPath.str, objInfo[0].first, imgTargets); + if (asyncResp) + { + std::shared_ptr<task::TaskData> task = +@@ -247,8 +352,7 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, +- std::array<const char*, 1>{ +- "xyz.openbmc_project.Software.Activation"}); ++ std::array<const char*, 1>{activationIntf}); + } + } + } +@@ -257,7 +361,8 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, + // then no asyncResp updates will occur + static void monitorForSoftwareAvailable( + const std::shared_ptr<AsyncResp>& asyncResp, const crow::Request& req, +- const std::string& url, int timeoutTimeSeconds = 10) ++ const std::string& url, const std::vector<std::string>& imgUriTargets, ++ int timeoutTimeSeconds = 10) + { + // Only allow one FW update at a time + if (fwUpdateInProgress != false) +@@ -297,9 +402,10 @@ static void monitorForSoftwareAvailable( + } + }); + +- auto callback = [asyncResp, req](sdbusplus::message::message& m) { ++ auto callback = [asyncResp, imgTargets{imgUriTargets}, ++ req](sdbusplus::message::message& m) { + BMCWEB_LOG_DEBUG << "Match fired"; +- softwareInterfaceAdded(asyncResp, m, req); ++ softwareInterfaceAdded(asyncResp, imgTargets, m, req); + }; + + fwUpdateInProgress = true; +@@ -475,12 +581,15 @@ class UpdateServiceActionsSimpleUpdate : public Node + std::string fwFile = imageURI.substr(separator + 1); + BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; + ++ // We will pass empty targets and its handled in activation. ++ std::vector<std::string> httpUriTargets; ++ + // Setup callback for when new software detected + // Give TFTP 10 minutes to complete + monitorForSoftwareAvailable( + asyncResp, req, + "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", +- 600); ++ httpUriTargets, 600); + + // TFTP can take up to 10 minutes depending on image size and + // connection speed. Return to caller as soon as the TFTP operation +@@ -514,7 +623,8 @@ class UpdateServiceActionsSimpleUpdate : public Node + class UpdateService : public Node + { + public: +- UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/") ++ UpdateService(App& app) : ++ Node(app, "/redfish/v1/UpdateService/"), httpPushUriTargetBusy(false) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, +@@ -526,6 +636,8 @@ class UpdateService : public Node + } + + private: ++ std::vector<std::string> httpPushUriTargets; ++ bool httpPushUriTargetBusy; + void doGet(crow::Response& res, const crow::Request&, + const std::vector<std::string>&) override + { +@@ -536,6 +648,8 @@ class UpdateService : public Node + res.jsonValue["Description"] = "Service for Software Update"; + res.jsonValue["Name"] = "Update Service"; + res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; ++ res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets; ++ res.jsonValue["HttpPushUriTargetsBusy"] = httpPushUriTargetBusy; + // UpdateService cannot be disabled + res.jsonValue["ServiceEnabled"] = true; + res.jsonValue["FirmwareInventory"] = { +@@ -585,6 +699,31 @@ class UpdateService : public Node + "/xyz/openbmc_project/software/apply_time", + "org.freedesktop.DBus.Properties", "Get", + "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); ++ ++ // Get the ApplyOptions value ++ crow::connections::systemBus->async_method_call( ++ [aResp](const boost::system::error_code ec, ++ const std::variant<bool> applyOption) { ++ if (ec) ++ { ++ BMCWEB_LOG_DEBUG << "DBUS response error " << ec; ++ messages::internalError(aResp->res); ++ return; ++ } ++ ++ const bool* b = std::get_if<bool>(&applyOption); ++ ++ if (b) ++ { ++ aResp->res.jsonValue["Oem"]["ApplyOptions"]["@odata.type"] = ++ "#OemUpdateService.ApplyOptions"; ++ aResp->res.jsonValue["Oem"]["ApplyOptions"]["ClearConfig"] = ++ *b; ++ } ++ }, ++ "xyz.openbmc_project.Software.BMC.Updater", ++ "/xyz/openbmc_project/software", "org.freedesktop.DBus.Properties", ++ "Get", "xyz.openbmc_project.Software.ApplyOptions", "ClearConfig"); + } + + void doPatch(crow::Response& res, const crow::Request& req, +@@ -595,12 +734,61 @@ class UpdateService : public Node + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + std::optional<nlohmann::json> pushUriOptions; +- if (!json_util::readJson(req, res, "HttpPushUriOptions", +- pushUriOptions)) ++ std::optional<std::vector<std::string>> imgTargets; ++ std::optional<bool> imgTargetBusy; ++ std::optional<nlohmann::json> oemProps; ++ ++ if (!json_util::readJson(req, res, "HttpPushUriOptions", pushUriOptions, ++ "HttpPushUriTargets", imgTargets, ++ "HttpPushUriTargetsBusy", imgTargetBusy, "Oem", ++ oemProps)) + { ++ BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body"; + return; + } + ++ if (oemProps) ++ { ++ std::optional<nlohmann::json> applyOptions; ++ ++ if (!json_util::readJson(*oemProps, res, "ApplyOptions", ++ applyOptions)) ++ { ++ return; ++ } ++ ++ if (applyOptions) ++ { ++ std::optional<bool> clearConfig; ++ if (!json_util::readJson(*applyOptions, res, "ClearConfig", ++ clearConfig)) ++ { ++ return; ++ } ++ ++ if (clearConfig) ++ { ++ // Set the requested image apply time value ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "D-Bus responses error: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ messages::success(asyncResp->res); ++ }, ++ "xyz.openbmc_project.Software.BMC.Updater", ++ "/xyz/openbmc_project/software", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Software.ApplyOptions", ++ "ClearConfig", std::variant<bool>{*clearConfig}); ++ } ++ } ++ } ++ + if (pushUriOptions) + { + std::optional<nlohmann::json> pushUriApplyTime; +@@ -665,6 +853,98 @@ class UpdateService : public Node + } + } + } ++ ++ if (imgTargetBusy) ++ { ++ if ((httpPushUriTargetBusy) && (*imgTargetBusy)) ++ { ++ BMCWEB_LOG_DEBUG ++ << "Other client has reserved the HttpPushUriTargets " ++ "property for firmware updates."; ++ messages::resourceInUse(asyncResp->res); ++ return; ++ } ++ ++ if (imgTargets) ++ { ++ if (!(*imgTargetBusy)) ++ { ++ BMCWEB_LOG_DEBUG ++ << "UpdateService doPatch: httpPushUriTargetBusy " ++ "should be " ++ "true before setting httpPushUriTargets"; ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargetsBusy"); ++ return; ++ } ++ if ((*imgTargets).size() != 0) ++ { ++ // TODO: Now we support max one target becuase ++ // software-manager code support one activation per object. ++ // It will be enhanced to multiple targets for single image ++ // in future. For now, consider first target alone. ++ if ((*imgTargets).size() != 1) ++ { ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargets"); ++ return; ++ } ++ crow::connections::systemBus->async_method_call( ++ [this, asyncResp, uriTargets{*imgTargets}, ++ targetBusy{*imgTargetBusy}]( ++ const boost::system::error_code ec, ++ const std::vector<std::string> swInvPaths) { ++ if (ec) ++ { ++ return; ++ } ++ ++ bool swInvObjFound = false; ++ for (const std::string& path : swInvPaths) ++ { ++ std::size_t idPos = path.rfind("/"); ++ if ((idPos == std::string::npos) || ++ ((idPos + 1) >= path.size())) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_DEBUG ++ << "Can't parse firmware ID!!"; ++ return; ++ } ++ std::string swId = path.substr(idPos + 1); ++ ++ if (swId == uriTargets[0]) ++ { ++ swInvObjFound = true; ++ break; ++ } ++ } ++ if (!swInvObjFound) ++ { ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargets"); ++ return; ++ } ++ this->httpPushUriTargetBusy = targetBusy; ++ this->httpPushUriTargets = uriTargets; ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", ++ "/", static_cast<int32_t>(0), ++ std::array<const char*, 1>{versionIntf}); ++ } ++ else ++ { ++ httpPushUriTargetBusy = *imgTargetBusy; ++ httpPushUriTargets = *imgTargets; ++ } ++ } ++ else ++ { ++ httpPushUriTargetBusy = *imgTargetBusy; ++ } ++ } + } + + void doPost(crow::Response& res, const crow::Request& req, +@@ -675,8 +955,8 @@ class UpdateService : public Node + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + // Setup callback for when new software detected +- monitorForSoftwareAvailable(asyncResp, req, +- "/redfish/v1/UpdateService"); ++ monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService", ++ httpPushUriTargets); + + std::string filepath( + "/tmp/images/" + +@@ -761,7 +1041,7 @@ class SoftwareInventoryCollection : public Node + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/software", static_cast<int32_t>(0), +- std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"}); ++ std::array<const char*, 1>{versionIntf}); + } + }; + +@@ -943,7 +1223,7 @@ class SoftwareInventory : public Node + }, + obj.second[0].first, obj.first, + "org.freedesktop.DBus.Properties", "GetAll", +- "xyz.openbmc_project.Software.Version"); ++ versionIntf); + } + if (!found) + { +@@ -964,8 +1244,7 @@ class SoftwareInventory : public Node + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", +- static_cast<int32_t>(0), +- std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"}); ++ static_cast<int32_t>(0), std::array<const char*, 1>{versionIntf}); + } + }; + +diff --git a/static/redfish/v1/$metadata/index.xml b/static/redfish/v1/$metadata/index.xml +index 514f3dd..c068d4f 100644 +--- a/static/redfish/v1/$metadata/index.xml ++++ b/static/redfish/v1/$metadata/index.xml +@@ -2142,6 +2142,9 @@ + <edmx:Reference Uri="/redfish/v1/schema/OemManager_v1.xml"> + <edmx:Include Namespace="OemManager"/> + </edmx:Reference> ++ <edmx:Reference Uri="/redfish/v1/schema/OemUpdateService_v1.xml"> ++ <edmx:Include Namespace="OemUpdateService"/> ++ </edmx:Reference> + <edmx:Reference Uri="/redfish/v1/schema/OemCrashdump_v1.xml"> + <edmx:Include Namespace="OemCrashdump.v1_0_0"/> + </edmx:Reference> +diff --git a/static/redfish/v1/JsonSchemas/OemUpdateService/index.json b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json +new file mode 100644 +index 0000000..74e39cd +--- /dev/null ++++ b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json +@@ -0,0 +1,69 @@ ++{ ++ "$id": "http://redfish.dmtf.org/schemas/v1/OemUpdateService.json", ++ "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json", ++ "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright", ++ "definitions": { ++ "ApplyOptions": { ++ "additionalProperties": false, ++ "description": "An indication by boolean value whether to update firmware configuration along with firmware image update.", ++ "patternProperties": { ++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { ++ "description": "This property shall specify a valid odata or Redfish property.", ++ "type": [ ++ "array", ++ "boolean", ++ "integer", ++ "number", ++ "null", ++ "object", ++ "string" ++ ] ++ } ++ }, ++ "properties": { ++ "ClearConfig": { ++ "description": "This indicates whether to update firmware configuration or not.", ++ "longDescription": "The value of this property is used to indicate the firmware configuration update.", ++ "readonly": false, ++ "type": [ ++ "boolean", ++ "null" ++ ] ++ } ++ }, ++ "type": "object" ++ }, ++ "Oem": { ++ "additionalProperties": true, ++ "description": "OemUpdateService Oem properties.", ++ "patternProperties": { ++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { ++ "description": "This property shall specify a valid odata or Redfish property.", ++ "type": [ ++ "array", ++ "boolean", ++ "integer", ++ "number", ++ "null", ++ "object", ++ "string" ++ ] ++ } ++ }, ++ "properties": { ++ "ApplyOptions": { ++ "anyOf": [ ++ { ++ "$ref": "#/definitions/ApplyOptions" ++ }, ++ { ++ "type": "null" ++ } ++ ] ++ } ++ }, ++ "type": "object" ++ } ++ }, ++ "title": "#OemUpdateService" ++} +diff --git a/static/redfish/v1/schema/OemUpdateService_v1.xml b/static/redfish/v1/schema/OemUpdateService_v1.xml +new file mode 100644 +index 0000000..cbb7aa4 +--- /dev/null ++++ b/static/redfish/v1/schema/OemUpdateService_v1.xml +@@ -0,0 +1,40 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0"> ++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml"> ++ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData" /> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml"> ++ <edmx:Include Namespace="Validation.v1_0_0" Alias="Validation"/> ++ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/UpdateService_v1.xml"> ++ <edmx:Include Namespace="UpdateService"/> ++ <edmx:Include Namespace="UpdateService.v1_4_0"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml"> ++ <edmx:Include Namespace="Resource"/> ++ <edmx:Include Namespace="Resource.v1_0_0"/> ++ </edmx:Reference> ++ ++ <edmx:DataServices> ++ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemUpdateService"> ++ <ComplexType Name="Oem" BaseType="Resource.OemObject"> ++ <Annotation Term="OData.AdditionalProperties" Bool="true" /> ++ <Annotation Term="OData.Description" String="OemUpdateService Oem properties." /> ++ <Annotation Term="OData.AutoExpand"/> ++ <Property Name="ApplyOptions" Type="OemUpdateService.ApplyOptions"/> ++ </ComplexType> ++ ++ <ComplexType Name="ApplyOptions" BaseType="Resource.OemObject"> ++ <Annotation Term="OData.AdditionalProperties" Bool="false" /> ++ <Annotation Term="OData.Description" String="An indication by boolean value whether to update firmware configuration along with firmware image update." /> ++ <Property Name="ClearConfig" Type="Edm.Boolean"> ++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/> ++ <Annotation Term="OData.Description" String="This indicates whether to update firmware configuration or not."/> ++ <Annotation Term="OData.LongDescription" String="The value of this property is used to indicate the firmware configuration update."/> ++ </Property> ++ </ComplexType> ++ ++ </Schema> ++ </edmx:DataServices> ++</edmx:Edmx> +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Invalid-status-code-from-InsertMedia-REST-methods.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Invalid-status-code-from-InsertMedia-REST-methods.patch new file mode 100644 index 000000000..c9a4119a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Invalid-status-code-from-InsertMedia-REST-methods.patch @@ -0,0 +1,182 @@ + +From 1bbabe4ecdeea20da809b9f1d8e194683629517c Mon Sep 17 00:00:00 2001 +From: Alicja Rybak <alicja.rybak@intel.com> +Date: Tue, 20 Apr 2021 16:32:37 +0200 +Subject: [PATCH] Invalid status code from InsertMedia REST methods GET, PUT, + DELETE, PATCH in proxy mode + +Add handlers for GET, PUT, DELETE, PATCH method and function that +checks which mode is used and set suitable status code: +Not allowed for Legacy and Not found for Proxy. + +Change-Id: Ib4c0a3e9a2a8853caa74c59239d9fcfed99c5e8b +Signed-off-by: Alicja Rybak <alicja.rybak@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 154 +++++++++++++++++++++++++++++ + 1 file changed, 154 insertions(+) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 8353ce7..66bf220 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -530,6 +530,160 @@ class VirtualMediaActionInsertMedia : public Node + return true; + } + ++ /** ++ * @brief Function checks if insert media request is Legacy or Proxy type ++ * and sets suitable response code for unsupported REST method. ++ * ++ */ ++ void CheckProxyMode(crow::Response& res, ++ const crow::Request& req, ++ const std::vector<std::string>& params) ++ { ++ auto aResp = std::make_shared<AsyncResp>(res); ++ ++ if (params.size() != 2) ++ { ++ messages::internalError(res); ++ return; ++ } ++ ++ // take resource name from URL ++ const std::string& resName = params[1]; ++ ++ if (params[0] != "bmc") ++ { ++ messages::resourceNotFound(res, "VirtualMedia.Insert", resName); ++ ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [this, aResp{std::move(aResp)}, req, ++ resName](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " ++ << ec; ++ aResp->res.result( ++ boost::beast::http::status::not_found); ++ ++ return; ++ } ++ std::string service = getObjectType.begin()->first; ++ BMCWEB_LOG_DEBUG << "GetObjectType: " << service; ++ ++ crow::connections::systemBus->async_method_call( ++ [this, service, resName, req, ++ aResp{aResp}](const boost::system::error_code ec, ++ ManagedObjectType& subtree) { ++ if (ec) ++ { ++ BMCWEB_LOG_DEBUG << "DBUS response error"; ++ ++ return; ++ } ++ ++ for (auto& item : subtree) ++ { ++ std::string thispath = item.first.filename(); ++ if (thispath.empty()) ++ { ++ continue; ++ } ++ ++ if (thispath != resName) ++ { ++ continue; ++ } ++ ++ auto mode = item.first.parent_path(); ++ auto type = mode.parent_path(); ++ if (mode.filename().empty() || ++ type.filename().empty()) ++ { ++ continue; ++ } ++ ++ if (type.filename() != "VirtualMedia") ++ { ++ continue; ++ } ++ ++ // Check if dbus path is Legacy type ++ if (mode.filename() == "Legacy") ++ { ++ BMCWEB_LOG_DEBUG << "InsertMedia only allowed " ++ "with POST method " ++ "in legacy mode"; ++ aResp->res.result( ++ boost::beast::http::status:: ++ method_not_allowed); ++ ++ return; ++ } ++ // Check if dbus path is Proxy type ++ if (mode.filename() == "Proxy") ++ { ++ // Not possible in proxy mode ++ BMCWEB_LOG_DEBUG << "InsertMedia not " ++ "allowed in proxy mode"; ++ aResp->res.result( ++ boost::beast::http::status::not_found); ++ ++ return; ++ } ++ } ++ ++ BMCWEB_LOG_DEBUG << "Parent item not found"; ++ aResp->res.result( ++ boost::beast::http::status::not_found); ++ }, ++ service, "/xyz/openbmc_project/VirtualMedia", ++ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>()); ++ } ++ ++ /** ++ * @brief Function handles GET method request. ++ */ ++ void doGet(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ CheckProxyMode(res, req, params); ++ } ++ ++ /** ++ * @brief Function handles PATCH method request. ++ */ ++ void doPatch(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ CheckProxyMode(res, req, params); ++ } ++ ++ /** ++ * @brief Function handles PUT method request. ++ */ ++ void doPut(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ CheckProxyMode(res, req, params); ++ } ++ ++ /** ++ * @brief Function handles DELETE method request. ++ */ ++ void doDelete(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>& params) override ++ { ++ CheckProxyMode(res, req, params); ++ } ++ + /** + * @brief Function handles POST method request. + * diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch new file mode 100644 index 000000000..02f843bb8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch @@ -0,0 +1,74 @@ +From 034920eca21bc25899565484928ee72025e21ff8 Mon Sep 17 00:00:00 2001 +From: Wiktor Golgowski <wiktor.golgowski@linux.intel.com> +Date: Thu, 30 Apr 2020 11:09:35 +0200 +Subject: [PATCH] Use chip id-based UUID for Service Root. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the sysfs-provided chip id is available, it will be used as +payload to generate Service Root UUID from hardcoded namespace. + +Tested: +Generated UUID is consistent between BMC image reflashes. +If the sysfs node is not available, code falls back to randomly +generated UUID. + +Signed-off-by: Wiktor Gołgowski <wiktor.golgowski@linux.intel.com> +--- + include/persistent_data.hpp | 32 +++++++++++++++++++++++++++++--- + 1 file changed, 29 insertions(+), 3 deletions(-) + +diff --git a/include/persistent_data.hpp b/include/persistent_data.hpp +index 24f7afd..8826b06 100644 +--- a/include/persistent_data.hpp ++++ b/include/persistent_data.hpp +@@ -25,6 +25,10 @@ class ConfigFile + public: + // todo(ed) should read this from a fixed location somewhere, not CWD + static constexpr const char* filename = "bmcweb_persistent_data.json"; ++ static constexpr const char* chipIdSysfsNode = "/sys/devices/platform" ++ "/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/chip_id"; ++ static constexpr const char* UuidNs = "{b7b0553a-54cc-4162-982d-" ++ "944847ed76f5}"; + + ConfigFile() + { +@@ -144,9 +148,31 @@ class ConfigFile + + if (systemUuid.empty()) + { +- systemUuid = +- boost::uuids::to_string(boost::uuids::random_generator()()); +- needWrite = true; ++ // Try to retrieve chip id-based uuid. ++ std::ifstream chipIdFile(chipIdSysfsNode); ++ if (chipIdFile.is_open()) ++ { ++ std::string chipId; ++ std::getline(chipIdFile, chipId); ++ if (!chipId.empty()) ++ { ++ boost::uuids::name_generator_sha1 gen( ++ boost::uuids::string_generator()(UuidNs)); ++ systemUuid = boost::uuids::to_string(gen(chipId.c_str())); ++ needWrite = true; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "Cannot get chip id-based System UUID."; ++ } ++ } ++ // If the above fails, generate random uuid. ++ if (systemUuid.empty()) ++ { ++ systemUuid = ++ boost::uuids::to_string(boost::uuids::random_generator()()); ++ needWrite = true; ++ } + } + if (fileRevision < jsonRevision) + { +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-Set-Inserted-redfish-property-for-not-inserted-resou.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-Set-Inserted-redfish-property-for-not-inserted-resou.patch new file mode 100644 index 000000000..eaba041d5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-Set-Inserted-redfish-property-for-not-inserted-resou.patch @@ -0,0 +1,40 @@ +From dab4adbf211b6867f86fcf6080b34a0e41f6f4a1 Mon Sep 17 00:00:00 2001 +From: Karol Wachowski <karol.wachowski@intel.com> +Date: Tue, 23 Feb 2021 15:53:16 +0000 +Subject: [PATCH] Set Inserted redfish property for not inserted resources + +Tested: Verified that Inserted property is returned and set to + "false" for not inserted media. +Signed-off-by: Karol Wachowski <karol.wachowski@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 188248a..f477f63 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -95,6 +95,7 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, + BMCWEB_LOG_DEBUG << "Value Active not found"; + return; + } ++ aResp->res.jsonValue["Inserted"] = *activeValue; + + const std::string* endpointIdValue = + std::get_if<std::string>(&endpointIdProperty->second); +@@ -106,7 +107,6 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, + aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] = + *endpointIdValue; + aResp->res.jsonValue["TransferProtocolType"] = "OEM"; +- aResp->res.jsonValue["Inserted"] = *activeValue; + if (*activeValue == true) + { + aResp->res.jsonValue["ConnectedVia"] = "Applet"; +@@ -137,7 +137,6 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, + } + + aResp->res.jsonValue["Image"] = *imageUrlValue; +- aResp->res.jsonValue["Inserted"] = *activeValue; + aResp->res.jsonValue["TransferProtocolType"] = + getTransferProtocolTypeFromUri(*imageUrlValue); + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Bmcweb-handle-permission-denied-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Bmcweb-handle-permission-denied-exception.patch new file mode 100644 index 000000000..074718349 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Bmcweb-handle-permission-denied-exception.patch @@ -0,0 +1,44 @@ +From 81f2c022b22ef75990f30e5ba5bfd4ba5bd41754 Mon Sep 17 00:00:00 2001 +From: Alicja Rybak <alicja.rybak@intel.com> +Date: Wed, 14 Apr 2021 16:26:59 +0200 +Subject: [PATCH] Bmcweb handle permission denied exception + +Add handling of permission denied exception (EPERM) that +can be thrown by VirtualMedia service during Mount/Unmount dbus operations. + +Tested: +Verified that after mounting/unmounting HTTPS resource twice in a row in legacy mode, +VirtualMedia returns EPERM, which bmcweb handles as 403 status code. + +Change-Id: Ibc18d5ec822c5072605b1fc4651389982002798b +Signed-off-by: Alicja Rybak <alicja.rybak@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 365290b..bbdc91b 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -900,6 +900,10 @@ class VirtualMediaActionInsertMedia : public Node + { + messages::resourceInUse(asyncResp->res); + } ++ else if (ec == boost::system::errc::permission_denied) ++ { ++ messages::accessDenied(asyncResp->res, "VirtualMedia.Insert"); ++ } + else + { + messages::internalError(asyncResp->res); +@@ -1092,6 +1096,10 @@ class VirtualMediaActionEjectMedia : public Node + { + messages::resourceInUse(asyncResp->res); + } ++ else if (ec == boost::system::errc::permission_denied) ++ { ++ messages::accessDenied(asyncResp->res, "VirtualMedia.Eject"); ++ } + else + { + messages::internalError(asyncResp->res); diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch new file mode 100644 index 000000000..01c1c858c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch @@ -0,0 +1,219 @@ +From 76480c6a5b1708113f28aecab32a85984371243c Mon Sep 17 00:00:00 2001 +From: Karol Wachowski <karol.wachowski@intel.com> +Date: Fri, 10 Jul 2020 09:54:06 +0000 +Subject: [PATCH] bmcweb handle device or resource busy exception + +Use async_method_call_timed() for mount/unmount dbus oprations. +Long mount/unmount times are supported by VirtualMedia service, +this works because of settable timeout property, available for each block +device. +Default dbus calls will timeout when mount/unmount timeout is long enough. + +Get mount/unmount timeout property and use it for mount/unmount calls. +Add handling of device or resource busy exception (EBUSY) that +can be thrown by VirtualMedia service during Mount/Unmount dbus operations. + +Tested: Verified that after mounting non-existing HTTPS resource + in proxy mode, VirtualMedia recovers restoring ready state + and returns EBUSY during that transition. + Verfied that resources can be mounted/unmounted in both legacy + and proxy mode. +Signed-off-by: Karol Wachowski <karol.wachowski@intel.com> +Change-Id: Ica62c34db0cce24c4c6169fc661edfde49e948d0 +--- + redfish-core/lib/virtual_media.hpp | 144 ++++++++++++++++++++++------- + 1 file changed, 110 insertions(+), 34 deletions(-) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 95a8881..188248a 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -24,6 +24,8 @@ + #include <account_service.hpp> + #include <boost/url/url_view.hpp> + ++#include <chrono> ++ + namespace redfish + + { +@@ -160,6 +162,26 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, + } + } + ++/** ++ * @brief parses Timeout property and converts to microseconds ++ */ ++static std::optional<uint64_t> ++ vmParseTimeoutProperty(const std::variant<int>& timeoutProperty) ++{ ++ const int* timeoutValue = std::get_if<int>(&timeoutProperty); ++ if (timeoutValue) ++ { ++ constexpr int timeoutMarginSeconds = 10; ++ return std::chrono::duration_cast<std::chrono::microseconds>( ++ std::chrono::seconds(*timeoutValue + timeoutMarginSeconds)) ++ .count(); ++ } ++ else ++ { ++ return std::nullopt; ++ } ++} ++ + /** + * @brief Fill template for Virtual Media Item. + */ +@@ -856,22 +878,54 @@ class VirtualMediaActionInsertMedia : public Node + } + + crow::connections::systemBus->async_method_call( +- [asyncResp, secretPipe](const boost::system::error_code ec, +- bool success) { ++ [asyncResp, service, name, imageUrl, rw, unixFd, ++ secretPipe](const boost::system::error_code ec, ++ const std::variant<int> timeoutProperty) { + if (ec) + { + BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; + messages::internalError(asyncResp->res); ++ return; + } +- else if (!success) ++ ++ auto timeout = vmParseTimeoutProperty(timeoutProperty); ++ if (timeout == std::nullopt) + { +- BMCWEB_LOG_ERROR << "Service responded with error"; +- messages::generalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "Timeout property is empty."; ++ messages::internalError(asyncResp->res); ++ return; + } ++ ++ crow::connections::systemBus->async_method_call_timed( ++ [asyncResp, secretPipe](const boost::system::error_code ec, ++ bool success) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " ++ << ec; ++ if (ec == ++ boost::system::errc::device_or_resource_busy) ++ { ++ messages::resourceInUse(asyncResp->res); ++ } ++ else ++ { ++ messages::internalError(asyncResp->res); ++ } ++ } ++ else if (!success) ++ { ++ BMCWEB_LOG_ERROR << "Service responded with error"; ++ messages::generalError(asyncResp->res); ++ } ++ }, ++ service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, ++ "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", ++ *timeout, imageUrl, rw, unixFd); + }, + service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, +- "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw, +- unixFd); ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout"); + } + }; + +@@ -1003,38 +1057,60 @@ class VirtualMediaActionEjectMedia : public Node + const std::string& service, const std::string& name, + bool legacy) + { +- +- // Legacy mount requires parameter with image ++ std::string objectPath = "/xyz/openbmc_project/VirtualMedia/"; ++ std::string ifaceName = "xyz.openbmc_project.VirtualMedia"; + if (legacy) + { +- crow::connections::systemBus->async_method_call( +- [asyncResp](const boost::system::error_code ec) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; +- +- messages::internalError(asyncResp->res); +- return; +- } +- }, +- service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, +- "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount"); ++ objectPath += "Legacy/"; ++ ifaceName += ".Legacy"; + } +- else // proxy ++ else + { +- crow::connections::systemBus->async_method_call( +- [asyncResp](const boost::system::error_code ec) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; +- +- messages::internalError(asyncResp->res); +- return; +- } +- }, +- service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, +- "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount"); ++ objectPath += "Proxy/"; ++ ifaceName += ".Proxy"; + } ++ objectPath += name; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp, service, name, objectPath, ++ ifaceName](const boost::system::error_code ec, ++ const std::variant<int> timeoutProperty) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ auto timeout = vmParseTimeoutProperty(timeoutProperty); ++ if (timeout == std::nullopt) ++ { ++ BMCWEB_LOG_ERROR << "Timeout property is empty."; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ crow::connections::systemBus->async_method_call_timed( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " ++ << ec; ++ if (ec == ++ boost::system::errc::device_or_resource_busy) ++ { ++ messages::resourceInUse(asyncResp->res); ++ } ++ else ++ { ++ messages::internalError(asyncResp->res); ++ } ++ return; ++ } ++ }, ++ service, objectPath, ifaceName, "Unmount", *timeout); ++ }, ++ service, objectPath, "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout"); + } + }; + +-- +2.17.1 + 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 new file mode 100644 index 000000000..54f00aa39 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch @@ -0,0 +1,547 @@ +From d340953bc925ff8535c5a8fac54db24b243ba8ad Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 19 Oct 2020 13:21:42 +0530 +Subject: [PATCH] EventService: https client support + +Add https client support for push style +eventing. Using this BMC can push the event +logs/telemetry data to event listener over +secure http channel. + +Tested: + - Created subscription with https destination + url. Using SubmitTestEvent action set the + event and can see event on event listener. + - Validator passed. + +Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> +--- + http/http_client.hpp | 370 +++++++++++++----- + .../include/event_service_manager.hpp | 2 +- + 2 files changed, 267 insertions(+), 105 deletions(-) + +diff --git a/http/http_client.hpp b/http/http_client.hpp +index 5c7b13f..d782dee 100644 +--- a/http/http_client.hpp ++++ b/http/http_client.hpp +@@ -31,12 +31,17 @@ namespace crow + { + + static constexpr uint8_t maxRequestQueueSize = 50; ++static constexpr unsigned int httpReadBodyLimit = 1024; + + enum class ConnState + { + initialized, ++ resolveInProgress, ++ resolveFailed, ++ resolved, + connectInProgress, + connectFailed, ++ sslHandshakeInProgress, + connected, + sendInProgress, + sendFailed, +@@ -50,53 +55,124 @@ enum class ConnState + class HttpClient : public std::enable_shared_from_this<HttpClient> + { + private: ++ boost::asio::ip::tcp::resolver resolver; ++ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; + boost::beast::tcp_stream conn; ++ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn; + boost::asio::steady_timer timer; +- boost::beast::flat_buffer buffer; ++ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; ++ std::optional< ++ boost::beast::http::response_parser<boost::beast::http::string_body>> ++ parser; + boost::beast::http::request<boost::beast::http::string_body> req; +- boost::beast::http::response<boost::beast::http::string_body> res; + boost::asio::ip::tcp::resolver::results_type endpoint; +- std::vector<std::pair<std::string, std::string>> headers; ++ boost::beast::http::fields fields; + std::queue<std::string> requestDataQueue; +- ConnState state; + std::string subId; + std::string host; + std::string port; + std::string uri; ++ bool useSsl; + uint32_t retryCount; + uint32_t maxRetryAttempts; + uint32_t retryIntervalSecs; + std::string retryPolicyAction; + bool runningTimer; ++ ConnState state; ++ ++ void doResolve() ++ { ++ BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port; ++ if (state == ConnState::resolveInProgress) ++ { ++ return; ++ } ++ state = ConnState::resolveInProgress; ++ // TODO: Use async_resolver. boost asio example ++ // code as is crashing with async_resolve(). ++ try ++ { ++ endpoint = resolver.resolve(host, port); ++ } ++ catch (const std::exception& e) ++ { ++ BMCWEB_LOG_ERROR << "Failed to resolve hostname: " << host << " - " ++ << e.what(); ++ state = ConnState::resolveFailed; ++ checkQueue(); ++ return; ++ } ++ state = ConnState::resolved; ++ checkQueue(); ++ } + + void doConnect() + { +- if (state == ConnState::connectInProgress) ++ if (useSsl) ++ { ++ sslConn.emplace(conn, ctx); ++ } ++ ++ if ((state == ConnState::connectInProgress) || ++ (state == ConnState::sslHandshakeInProgress)) + { + return; + } + state = ConnState::connectInProgress; + + BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; +- // Set a timeout on the operation ++ ++ auto respHandler = ++ [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; ++ } ++ BMCWEB_LOG_DEBUG << "Connected to: " << ep; ++ if (self->sslConn) ++ { ++ self->performHandshake(); ++ } ++ else ++ { ++ self->state = ConnState::connected; ++ self->checkQueue(); ++ } ++ }; ++ + 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)); ++ } ++ ++ 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) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "SSL handshake failed: " ++ << ec.message(); ++ self->doCloseAndCheckQueue(ConnState::connectFailed); ++ return; ++ } ++ self->state = ConnState::connected; ++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull"; + +- self->checkQueue(); +- }); ++ self->checkQueue(); ++ }); + } + + void sendMessage(const std::string& data) +@@ -107,100 +183,170 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } + state = ConnState::sendInProgress; + +- BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; ++ BMCWEB_LOG_DEBUG << host << ":" << port; + +- req.version(static_cast<int>(11)); // HTTP 1.1 +- req.target(uri); +- req.method(boost::beast::http::verb::post); +- +- // Set headers +- for (const auto& [key, value] : headers) ++ req = {}; ++ 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(static_cast<int>(11)); // HTTP 1.1 ++ req.target(uri); ++ req.method(boost::beast::http::verb::post); + req.keep_alive(true); + + req.body() = data; + req.prepare_payload(); + +- // Set a timeout on the operation +- conn.expires_after(std::chrono::seconds(30)); ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code ec, ++ const std::size_t& bytesTransferred) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); ++ self->doCloseAndCheckQueue(ConnState::sendFailed); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " ++ << bytesTransferred; ++ boost::ignore_unused(bytesTransferred); + +- // Send the HTTP request to the remote host +- boost::beast::http::async_write( +- conn, req, +- [self(shared_from_this())](const boost::beast::error_code& ec, +- const std::size_t& bytesTransferred) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "sendMessage() failed: " +- << ec.message(); +- self->state = ConnState::sendFailed; +- self->checkQueue(); +- return; +- } +- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); ++ self->recvMessage(); ++ }; + +- self->recvMessage(); +- }); ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) ++ { ++ boost::beast::http::async_write(*sslConn, req, ++ std::move(respHandler)); ++ } ++ else ++ { ++ boost::beast::http::async_write(conn, req, std::move(respHandler)); ++ } + } + + void recvMessage() + { +- // Receive the HTTP response +- boost::beast::http::async_read( +- conn, buffer, res, +- [self(shared_from_this())](const boost::beast::error_code& ec, +- const std::size_t& bytesTransferred) { ++ auto respHandler = [self(shared_from_this())]( ++ 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->doCloseAndCheckQueue(ConnState::recvFailed); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " ++ << bytesTransferred; ++ boost::ignore_unused(bytesTransferred); ++ ++ // 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(); ++ ++ // Transfer ownership of the response ++ self->parser->release(); ++ ++ // 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); ++ }; ++ ++ parser.emplace(std::piecewise_construct, std::make_tuple()); ++ parser->body_limit(httpReadBodyLimit); ++ // Since these are all push style eventing, we are not ++ // bothered about response parsing. ++ parser->skip(true); ++ buffer.consume(buffer.size()); ++ ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) ++ { ++ boost::beast::http::async_read(*sslConn, buffer, *parser, ++ std::move(respHandler)); ++ } ++ else ++ { ++ boost::beast::http::async_read(conn, buffer, *parser, ++ std::move(respHandler)); ++ } ++ } ++ ++ void 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() +- { +- boost::beast::error_code ec; +- conn.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) ++ } ++ else + { +- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); +- return; ++ 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_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); ++ } ++ else ++ { ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; ++ } ++ ++ conn.close(); ++ state = setState; ++ checkQueue(); + } +- BMCWEB_LOG_DEBUG << "Connection closed gracefully"; ++ return; + } + + void checkQueue(const bool newRecord = false) + { + if (requestDataQueue.empty()) + { +- // TODO: Having issue in keeping connection alive. So lets close if +- // nothing to be transferred. +- doClose(); +- + BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; + return; + } +@@ -232,6 +378,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } + + if ((state == ConnState::connectFailed) || ++ (state == ConnState::resolveFailed) || + (state == ConnState::sendFailed) || + (state == ConnState::recvFailed)) + { +@@ -256,14 +403,18 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + << " seconds. RetryCount = " << retryCount; + timer.expires_after(std::chrono::seconds(retryIntervalSecs)); + timer.async_wait( +- [self = shared_from_this()](const boost::system::error_code&) { ++ [self = shared_from_this()](boost::system::error_code) { + self->runningTimer = false; + self->connStateCheck(); + }); + return; + } +- // reset retry count. +- retryCount = 0; ++ ++ if (state == ConnState::idle) ++ { ++ // State idle means, previous attempt is successful. ++ retryCount = 0; ++ } + connStateCheck(); + + return; +@@ -273,15 +424,21 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + { + switch (state) + { ++ case ConnState::initialized: ++ case ConnState::resolveFailed: ++ case ConnState::connectFailed: ++ doResolve(); ++ break; + case ConnState::connectInProgress: ++ case ConnState::resolveInProgress: ++ case ConnState::sslHandshakeInProgress: + case ConnState::sendInProgress: + case ConnState::suspended: + case ConnState::terminated: + // do nothing + break; +- case ConnState::initialized: + case ConnState::closed: +- case ConnState::connectFailed: ++ case ConnState::resolved: + case ConnState::sendFailed: + case ConnState::recvFailed: + { +@@ -297,22 +454,22 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + sendMessage(data); + break; + } ++ default: ++ break; + } + } + + 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), +- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), +- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), +- retryPolicyAction("TerminateAfterRetries"), runningTimer(false) +- { +- boost::asio::ip::tcp::resolver resolver(ioc); +- endpoint = resolver.resolve(host, port); +- state = ConnState::initialized; +- } ++ const std::string& destUri, ++ const bool inUseSsl = true) : ++ resolver(ioc), ++ conn(ioc), timer(ioc), subId(id), host(destIP), port(destPort), ++ uri(destUri), useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), ++ retryPolicyAction("TerminateAfterRetries"), runningTimer(false), ++ state(ConnState::initialized) ++ {} + + void sendData(const std::string& data) + { +@@ -337,7 +494,12 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + void setHeaders( + const std::vector<std::pair<std::string, std::string>>& 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 54dafb4..f68ae1d 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -387,7 +387,7 @@ class Subscription + { + conn = std::make_shared<crow::HttpClient>( + crow::connections::systemBus->get_io_context(), id, host, port, +- path); ++ path, (uriProto == "https" ? true : false)); + } + + Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) : +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-Fix-unmounting-image-in-proxy-mode.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-Fix-unmounting-image-in-proxy-mode.patch new file mode 100644 index 000000000..acfd9225b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-Fix-unmounting-image-in-proxy-mode.patch @@ -0,0 +1,32 @@ +From 9493bb8e2f5c708e187313c86e6033de5f103c51 Mon Sep 17 00:00:00 2001 +From: Alicja Rybak <alicja.rybak@intel.com> +Date: Fri, 23 Apr 2021 17:35:52 +0200 +Subject: [PATCH] Fix unmounting image in proxy mode. + +Sometimes Slot0 got higher key than Slot1 and erase function for Slot1 +invalidates elements with keys not less than the erased element. +In that case invalid slot0 will be unmounted. +Change order of calling close() and erase() functions to +unmount correct device. + +Change-Id: I7a40a4518982f697d3eed635cde6d06978149cf0 +Signed-off-by: Alicja Rybak <alicja.rybak@intel.com> +--- + include/nbd_proxy.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp +index 7b90e90..fa7f647 100644 +--- a/include/nbd_proxy.hpp ++++ b/include/nbd_proxy.hpp +@@ -428,9 +428,9 @@ inline void requestRoutes(App& app) + BMCWEB_LOG_DEBUG << "No session to close"; + return; + } ++ session->second->close(); + // Remove reference to session in global map + sessions.erase(session); +- session->second->close(); + }) + .onmessage([](crow::websocket::Connection& conn, + const std::string& data, bool) { diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch new file mode 100644 index 000000000..b2627644b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch @@ -0,0 +1,850 @@ +From c645c011bb3ea2a2aaf52560cb9fcc461d048cae Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 4 Sep 2020 19:24:25 +0800 +Subject: [PATCH] Define Redfish interface "/Registries/Bios" and enable + Attributes property + +1. Define Redfish interface "/Registries/Bios" for BIOS Attribute Registry + RBC Daemon provide method to get BIOS attribute registry. +2. Eanble Attributes property for BIOS resource +3. Define Redfish interface "/Systems/system/Bios/Settings" for BIOS +settings +4. RBC daemon is at +https://gerrit.openbmc-project.xyz/#/c/openbmc/bios-settings-mgr/+/35563/ +5. IPMI command implementation is at +https://gerrit.openbmc-project.xyz/#/c/openbmc/intel-ipmi-oem/+/30827/ +6. Property design is at +https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/xyz/openbmc_project/BIOSConfig +7. Design doc is at +https://github.com/openbmc/docs/blob/master/designs/remote-bios-configuration.md +8. There will be 95 test cases for this feature in the validation team. + +Tested: + +1. Use postman (Redfish tool) could get all the attributes in bios +resouce, get bios settings, get bios attribute +registry. +https://IP_ADDR/redfish/v1/Systems/system/Bios +{ + "@Redfish.Settings": { + "@odata.type": "#Settings.v1_3_0.Settings", + "SettingsObject": { + "@odata.id": "/redfish/v1/Systems/system/Bios/Settings" + } + }, + "@odata.id": "/redfish/v1/Systems/system/Bios", + "@odata.type": "#Bios.v1_1_0.Bios", + "Actions": { + "#Bios.ChangePassword": { + "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword" + }, + "#Bios.ResetBios": { + "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios" + } + }, + "AttributeRegistry": "BiosAttributeRegistry", + "Attributes": { + "attr0": "current value" + }, + "Description": "BIOS Configuration Service", + "Id": "BIOS", + "Links": { + "ActiveSoftwareImage": { + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active" + }, + "SoftwareImages": [ + { + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active" + } + ], + "SoftwareImages@odata.count": 1 + }, + "Name": "BIOS Configuration" +} + +Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry +{ + "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry", + "@odata.type": "#MessageRegistryFile.v1_1_0.MessageRegistryFile", + "Description": "BiosAttributeRegistry Message Registry File Location", + "Id": "BiosAttributeRegistry", + "Languages": [ + "en" + ], + "Languages@odata.count": 1, + "Location": [ + { + "Language": "en", + "Uri": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry" + } + ], + "Location@odata.count": 1, + "Name": "BiosAttributeRegistry Message Registry File", + "Registry": "BiosAttributeRegistry.1.0.0" +} + +Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry +{ + "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry", + "@odata.type": "#AttributeRegistry.v1_3_2.AttributeRegistry", + "Id": "BiosAttributeRegistry", + "Language": "en", + "Name": "Bios Attribute Registry", + "OwningEntity": "OpenBMC", + "RegistryEntries": { + "Attributes": [ + { + "AttributeName": "attr0", + "CurrentValue": "current value", + "DefaultValue": "default value", + "DisplayName": "display name for attr0", + "HelpText": "description for attr0", + "MenuPath": "./menu/path/for/attr0", + "ReadOnly": false, + "Type": "String", + "Value": [] + } + ] + }, + "RegistryVersion": "1.0.0" +} + +https://BMC_IPADDR/redfish/v1/Systems/system/Bios/Settings +{ + "@odata.id": "/redfish/v1/Systems/system/Bios/Settings", + "@odata.type": "#Bios.v1_1_0.Bios", + "AttributeRegistry": "BiosAttributeRegistry", + "Attributes": { + "QuietBoot": "0x0" + }, + "Id": "BiosSettingsV1", + "Name": "Bios Settings Version 1" +} + +2. Passed Validator check for bios resource and bios attribute registry +*** /redfish/v1/Systems/system/Bios +INFO - Type (#Bios.v1_1_0.Bios), GET SUCCESS (time: 1.57377) +INFO - PASS +*** /redfish/v1/Registries/BiosAttributeRegistry +INFO - Type (#MessageRegistryFile.v1_1_0.MessageRegistryFile), GET SUCCESS (time: 0.075438) +INFO - PASS +INFO - +*** /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry +INFO - Type (#AttributeRegistry.v1_3_2.AttributeRegistry), GET SUCCESS (time: 0.075751) +INFO - PASS + +@odata.id /redfish/v1/Systems/system/Bios odata Exists PASS +@odata.type #Settings.v1_3_0.Settings odata Exists PASS +Links [JSON Object] Bios.v1_1_0.Links Yes complex +Links.ActiveSoftwareImage Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active link to: SoftwareInventory Yes PASS +Links.SoftwareImages Array (size: 1) array of: SoftwareInventory Yes ... +Links.SoftwareImages[0] Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active SoftwareInventory Yes PASS +Links.Oem - Resource.Oem No Optional +SoftwareImages@odata.count 1 odata Exists PASS +AttributeRegistry BiosAttributeRegistry string Yes PASS +Actions [JSON Object] Bios.v1_0_0.Actions Yes complex +Actions.#Bios.ResetBios Action - Yes PASS +Actions.#Bios.ChangePassword Action - Yes PASS +Attributes [JSON Object] Bios.v1_0_0.Attributes Yes complex +Attributes.attr0 current value primitive Yes PASS +Id BIOS string Yes PASS +Description BIOS Configuration Service string Yes PASS +Name BIOS Configuration string Yes PASS +Oem - Resource.Oem No Optional +@Redfish.Settings [JSON Object] Settings.Settings Yes complex +@Redfish.Settings.MaintenanceWindowResource - link to: ItemOrCollection No Optional +@Redfish.Settings.SupportedApplyTimes - string (enum) No Optional +@Redfish.Settings.Time - date No Optional +@Redfish.Settings.ETag - string No Optional +@Redfish.Settings.SettingsObject Link: /redfish/v1/Systems/system/Bios/Settings link to: Item Yes PASS +@Redfish.Settings.Messages - Message No Optional + +@odata.id /redfish/v1/Registries/BiosAttributeRegistry odata Exists PASS +@odata.type #MessageRegistryFile.v1_1_0.MessageRegistryFile odata Exists PASS +Languages@odata.count 1 odata Exists PASS +Location@odata.count 1 odata Exists PASS +Actions - MessageRegistryFile.v1_1_0.Actions No Optional +Languages Array (size: 1) string Yes ... +Languages[0] en string Yes PASS +Registry BiosAttributeRegistry.1.0.0 string Yes PASS +Location Array (size: 1) array of: Location Yes ... +Location[0] [JSON Object] Location Yes complex +Location[0].Language en string Yes PASS +Location[0].Uri /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry string Yes PASS +Location[0].ArchiveUri - string No Optional +Location[0].PublicationUri - string No Optional +Location[0].ArchiveFile - string No Optional +Id BiosAttributeRegistry string Yes PASS +Description BiosAttributeRegistry Message Registry File Location string Yes PASS +Name BiosAttributeRegistry Message Registry File string Yes PASS +Oem - Resource.Oem No Optional + +@odata.id /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry odata Exists PASS +@odata.type #AttributeRegistry.v1_3_2.AttributeRegistry odata Exists PASS +Actions - AttributeRegistry.v1_1_0.Actions No Optional +Language en string Yes PASS +RegistryVersion 1.0.0 string Yes PASS +OwningEntity OpenBMC string Yes PASS +SupportedSystems - SupportedSystems No Optional +RegistryEntries [JSON Object] AttributeRegistry.v1_0_0.RegistryEntries Yes complex +RegistryEntries.Attributes Array (size: 1) array of: Attributes Yes ... +RegistryEntries.Attributes[0] [JSON Object] Attributes Yes complex +RegistryEntries.Attributes[0].Oem - Resource.Oem No Optional +RegistryEntries.Attributes[0].ResetRequired - boolean No Optional +RegistryEntries.Attributes[0].UefiDevicePath - string No Optional +RegistryEntries.Attributes[0].UefiKeywordName - string No Optional +RegistryEntries.Attributes[0].UefiNamespaceId - string No Optional +RegistryEntries.Attributes[0].AttributeName attr0 string Yes PASS +RegistryEntries.Attributes[0].Type String string (enum) Yes PASS +RegistryEntries.Attributes[0].Value Array (size: 0) array of: AttributeValue Yes ... +RegistryEntries.Attributes[0].DisplayName display name for attr0 string Yes PASS +RegistryEntries.Attributes[0].HelpText description for attr0 string Yes PASS +RegistryEntries.Attributes[0].WarningText - string No Optional +RegistryEntries.Attributes[0].CurrentValue current value primitive Yes PASS +RegistryEntries.Attributes[0].DefaultValue default value primitive Yes PASS +RegistryEntries.Attributes[0].DisplayOrder - number No Optional +RegistryEntries.Attributes[0].MenuPath ./menu/path/for/attr0 string Yes PASS +RegistryEntries.Attributes[0].ReadOnly False boolean Yes PASS +RegistryEntries.Attributes[0].WriteOnly - boolean No Optional +RegistryEntries.Attributes[0].GrayOut - boolean No Optional +RegistryEntries.Attributes[0].Hidden - boolean No Optional +RegistryEntries.Attributes[0].Immutable - boolean No Optional +RegistryEntries.Attributes[0].IsSystemUniqueProperty - boolean No Optional +RegistryEntries.Attributes[0].MaxLength - number No Optional +RegistryEntries.Attributes[0].MinLength - number No Optional +RegistryEntries.Attributes[0].ScalarIncrement - number No Optional +RegistryEntries.Attributes[0].UpperBound - number No Optional +RegistryEntries.Attributes[0].LowerBound - number No Optional +RegistryEntries.Attributes[0].ValueExpression - string No Optional +RegistryEntries.Menus - Menus No Optional +RegistryEntries.Dependencies - Dependencies No Optional +Id BiosAttributeRegistry string Yes PASS +Description - string No Optional +Name Bios Attribute Registry string Yes PASS +Oem - Resource.Oem No Optional + +Change-Id: Iecc61018c350f0b8c89df59b2864b941508b1916 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + redfish-core/include/redfish.hpp | 2 + + .../include/registries/bios_registry.hpp | 31 ++ + redfish-core/lib/bios.hpp | 503 ++++++++++++++++++ + redfish-core/lib/message_registries.hpp | 9 +- + 4 files changed, 544 insertions(+), 1 deletion(-) + create mode 100644 redfish-core/include/registries/bios_registry.hpp + +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index 5d5eb7b..a8e5cf2 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -157,6 +157,8 @@ class RedfishService + nodes.emplace_back(std::make_unique<SystemActionsReset>(app)); + nodes.emplace_back(std::make_unique<SystemResetActionInfo>(app)); + nodes.emplace_back(std::make_unique<BiosService>(app)); ++ nodes.emplace_back(std::make_unique<BiosSettings>(app)); ++ nodes.emplace_back(std::make_unique<BiosAttributeRegistry>(app)); + nodes.emplace_back(std::make_unique<BiosReset>(app)); + #ifdef BMCWEB_ENABLE_VM_NBDPROXY + nodes.emplace_back(std::make_unique<VirtualMedia>(app)); +diff --git a/redfish-core/include/registries/bios_registry.hpp b/redfish-core/include/registries/bios_registry.hpp +new file mode 100644 +index 0000000..88ef782 +--- /dev/null ++++ b/redfish-core/include/registries/bios_registry.hpp +@@ -0,0 +1,31 @@ ++/* ++// Copyright (c) 2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++#pragma once ++ ++namespace redfish::message_registries::bios ++{ ++const Header header = { ++ "Copyright 2020 OpenBMC. All rights reserved.", ++ "#MessageRegistry.v1_4_0.MessageRegistry", ++ "BiosAttributeRegistry.1.0.0", ++ "Bios Attribute Registry", ++ "en", ++ "This registry defines the messages for bios attribute registry.", ++ "BiosAttributeRegistry", ++ "1.0.0", ++ "OpenBMC", ++}; ++} // namespace redfish::message_registries::bios +\ No newline at end of file +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index 2c31077..5f8c91b 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -3,8 +3,140 @@ + #include "node.hpp" + + #include <utils/fw_utils.hpp> ++ + namespace redfish + { ++ ++/*baseBIOSTable ++map{attributeName,struct{attributeType,readonlyStatus,displayname, ++ description,menuPath,current,default, ++ array{struct{optionstring,optionvalue}}}} ++*/ ++using BiosBaseTableType = std::vector<std::pair< ++ std::string, ++ std::tuple< ++ std::string, bool, std::string, std::string, std::string, ++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>, ++ std::vector< ++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>>; ++using BiosBaseTableItemType = std::pair< ++ std::string, ++ std::tuple< ++ std::string, bool, std::string, std::string, std::string, ++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>, ++ std::vector< ++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>; ++using OptionsItemType = ++ std::tuple<std::string, std::variant<int64_t, std::string>>; ++ ++enum BiosBaseTableIndex ++{ ++ biosBaseAttrType = 0, ++ biosBaseReadonlyStatus, ++ biosBaseDisplayName, ++ biosBaseDescription, ++ biosBaseMenuPath, ++ biosBaseCurrValue, ++ biosBaseDefaultValue, ++ biosBaseOptions ++}; ++enum OptionsItemIndex ++{ ++ optItemType = 0, ++ optItemValue ++}; ++/* ++ The Pending attribute name and new value. ++ ex- { {"QuietBoot",Type.Integer, 0x1}, ++ { "DdrFreqLimit",Type.String,"2933"} ++ } ++*/ ++using PendingAttributesType = std::vector<std::pair< ++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>; ++using PendingAttributesItemType = ++ std::pair<std::string, ++ std::tuple<std::string, std::variant<int64_t, std::string>>>; ++enum PendingAttributesIndex ++{ ++ pendingAttrType = 0, ++ pendingAttrValue ++}; ++static std::string mapAttrTypeToRedfish(const std::string_view typeDbus) ++{ ++ std::string ret; ++ if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager." ++ "AttributeType.Enumeration") ++ { ++ ret = "Enumeration"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.String") ++ { ++ ret = "String"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.Password") ++ { ++ ret = "Password"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.Integer") ++ { ++ ret = "Integer"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.Boolean") ++ { ++ ret = "Boolean"; ++ } ++ else ++ { ++ ret = "UNKNOWN"; ++ } ++ ++ return ret; ++} ++static std::string mapBoundTypeToRedfish(const std::string_view typeDbus) ++{ ++ std::string ret; ++ if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.ScalarIncrement") ++ { ++ ret = "ScalarIncrement"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.LowerBound") ++ { ++ ret = "LowerBound"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.UpperBound") ++ { ++ ret = "UpperBound"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MinStringLength") ++ { ++ ret = "MinStringLength"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MaxStringLength") ++ { ++ ret = "MaxStringLength"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf") ++ { ++ ret = "OneOf"; ++ } ++ else ++ { ++ ret = "UNKNOWN"; ++ } ++ ++ return ret; ++} ++ + /** + * BiosService class supports handle get method for bios. + */ +@@ -35,6 +167,377 @@ class BiosService : public Node + // Get the ActiveSoftwareImage and SoftwareImages + fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose, + "", true); ++ asyncResp->res.jsonValue["@Redfish.Settings"] = { ++ {"@odata.type", "#Settings.v1_3_0.Settings"}, ++ {"SettingsObject", ++ {{"@odata.id", "/redfish/v1/Systems/system/Bios/Settings"}}}}; ++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["Attributes"] = {}; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ const std::string& service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp]( ++ const boost::system::error_code ec, ++ const std::variant<BiosBaseTableType>& retBiosTable) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "getBiosAttributes DBUS error: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ const BiosBaseTableType* baseBiosTable = ++ std::get_if<BiosBaseTableType>(&retBiosTable); ++ nlohmann::json& attributesJson = ++ asyncResp->res.jsonValue["Attributes"]; ++ if (baseBiosTable == nullptr) ++ { ++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr "; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ for (const BiosBaseTableItemType& item : *baseBiosTable) ++ { ++ const std::string& key = item.first; ++ const std::string& itemType = ++ std::get<biosBaseAttrType>(item.second); ++ std::string attrType = ++ mapAttrTypeToRedfish(itemType); ++ if (attrType == "String") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<biosBaseCurrValue>( ++ item.second)); ++ attributesJson.emplace(key, currValue != nullptr ++ ? *currValue ++ : ""); ++ } ++ else if (attrType == "Integer") ++ { ++ const int64_t* currValue = std::get_if<int64_t>( ++ &std::get<biosBaseCurrValue>(item.second)); ++ attributesJson.emplace( ++ key, currValue != nullptr ? *currValue : 0); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR ++ << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ } ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); ++ } ++}; ++ ++/** ++ * BiosSettings class supports handle GET/PATCH method for ++ * BIOS configuration pending settings. ++ */ ++class BiosSettings : public Node ++{ ++ public: ++ BiosSettings(App& app) : ++ Node(app, "/redfish/v1/Systems/system/Bios/Settings") ++ { ++ entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ asyncResp->res.jsonValue["@odata.id"] = ++ "/redfish/v1/Systems/system/Bios/Settings"; ++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios"; ++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1"; ++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1"; ++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["Attributes"] = {}; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ std::string service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const std::variant<PendingAttributesType>& ++ retPendingAttributes) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "getBiosSettings DBUS error: " ++ << ec; ++ messages::resourceNotFound(asyncResp->res, ++ "Systems/system/Bios", ++ "Settings"); ++ return; ++ } ++ const PendingAttributesType* pendingAttributes = ++ std::get_if<PendingAttributesType>( ++ &retPendingAttributes); ++ nlohmann::json& attributesJson = ++ asyncResp->res.jsonValue["Attributes"]; ++ if (pendingAttributes == nullptr) ++ { ++ BMCWEB_LOG_ERROR << "pendingAttributes == nullptr "; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ for (const PendingAttributesItemType& item : ++ *pendingAttributes) ++ { ++ const std::string& key = item.first; ++ const std::string& itemType = ++ std::get<pendingAttrType>(item.second); ++ std::string attrType = ++ mapAttrTypeToRedfish(itemType); ++ if (attrType == "String") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<pendingAttrValue>( ++ item.second)); ++ attributesJson.emplace(key, currValue != nullptr ++ ? *currValue ++ : ""); ++ } ++ else if (attrType == "Integer") ++ { ++ const int64_t* currValue = std::get_if<int64_t>( ++ &std::get<pendingAttrValue>(item.second)); ++ attributesJson.emplace( ++ key, currValue != nullptr ? *currValue : 0); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR ++ << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ } ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", ++ "PendingAttributes"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); ++ } ++}; ++/** ++ * BiosAttributeRegistry class supports handle get method for BIOS attribute ++ * registry. ++ */ ++class BiosAttributeRegistry : public Node ++{ ++ public: ++ BiosAttributeRegistry(App& app) : ++ Node(app, "/redfish/v1/Registries/BiosAttributeRegistry/" ++ "BiosAttributeRegistry") ++ { ++ entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ asyncResp->res.jsonValue["@odata.id"] = ++ "/redfish/v1/Registries/BiosAttributeRegistry/" ++ "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["@odata.type"] = ++ "#AttributeRegistry.v1_3_2.AttributeRegistry"; ++ asyncResp->res.jsonValue["Name"] = "Bios Attribute Registry"; ++ asyncResp->res.jsonValue["Id"] = "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["RegistryVersion"] = "1.0.0"; ++ asyncResp->res.jsonValue["Language"] = "en"; ++ asyncResp->res.jsonValue["OwningEntity"] = "OpenBMC"; ++ asyncResp->res.jsonValue["RegistryEntries"]["Attributes"] = ++ nlohmann::json::array(); ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ std::string service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp]( ++ const boost::system::error_code ec, ++ const std::variant<BiosBaseTableType>& retBiosTable) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "getBiosAttributeRegistry DBUS error: " ++ << ec; ++ messages::resourceNotFound( ++ asyncResp->res, "Registries/Bios", "Bios"); ++ return; ++ } ++ const BiosBaseTableType* baseBiosTable = ++ std::get_if<BiosBaseTableType>(&retBiosTable); ++ nlohmann::json& attributeArray = ++ asyncResp->res ++ .jsonValue["RegistryEntries"]["Attributes"]; ++ nlohmann::json optionsArray = nlohmann::json::array(); ++ if (baseBiosTable == nullptr) ++ { ++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr "; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ for (const BiosBaseTableItemType& item : *baseBiosTable) ++ { ++ const std::string& itemType = ++ std::get<biosBaseAttrType>(item.second); ++ std::string attrType = ++ mapAttrTypeToRedfish(itemType); ++ if (attrType == "UNKNOWN") ++ { ++ BMCWEB_LOG_ERROR << "attrType == UNKNOWN"; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ nlohmann::json attributeItem; ++ attributeItem["AttributeName"] = item.first; ++ attributeItem["Type"] = attrType; ++ attributeItem["ReadOnly"] = ++ std::get<biosBaseReadonlyStatus>(item.second); ++ attributeItem["DisplayName"] = ++ std::get<biosBaseDisplayName>(item.second); ++ attributeItem["HelpText"] = ++ std::get<biosBaseDescription>(item.second); ++ attributeItem["MenuPath"] = ++ std::get<biosBaseMenuPath>(item.second); ++ ++ if (attrType == "String") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<biosBaseCurrValue>( ++ item.second)); ++ const std::string* defValue = ++ std::get_if<std::string>( ++ &std::get<biosBaseDefaultValue>( ++ item.second)); ++ attributeItem["CurrentValue"] = ++ currValue != nullptr ? *currValue : ""; ++ attributeItem["DefaultValue"] = ++ defValue != nullptr ? *defValue : ""; ++ } ++ else if (attrType == "Integer") ++ { ++ const int64_t* currValue = std::get_if<int64_t>( ++ &std::get<biosBaseCurrValue>(item.second)); ++ const int64_t* defValue = std::get_if<int64_t>( ++ &std::get<biosBaseDefaultValue>( ++ item.second)); ++ attributeItem["CurrentValue"] = ++ currValue != nullptr ? *currValue : 0; ++ attributeItem["DefaultValue"] = ++ defValue != nullptr ? *defValue : 0; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR ++ << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::vector<OptionsItemType>& optionsVector = ++ std::get<biosBaseOptions>(item.second); ++ for (const OptionsItemType& optItem : optionsVector) ++ { ++ nlohmann::json optItemJson; ++ const std::string& strOptItemType = ++ std::get<optItemType>(optItem); ++ std::string optItemTypeRedfish = ++ mapBoundTypeToRedfish(strOptItemType); ++ if (optItemTypeRedfish == "UNKNOWN") ++ { ++ BMCWEB_LOG_ERROR ++ << "optItemTypeRedfish == UNKNOWN"; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ if (optItemTypeRedfish == "OneOf") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<optItemValue>(optItem)); ++ optItemJson[optItemTypeRedfish] = ++ currValue != nullptr ? *currValue : ""; ++ } ++ else ++ { ++ const int64_t* currValue = ++ std::get_if<int64_t>( ++ &std::get<optItemValue>(optItem)); ++ optItemJson[optItemTypeRedfish] = ++ currValue != nullptr ? *currValue : 0; ++ } ++ ++ optionsArray.push_back(optItemJson); ++ } ++ ++ attributeItem["Value"] = optionsArray; ++ attributeArray.push_back(attributeItem); ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); + } + }; + /** +diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp +index 77fc10e..0caf01c 100644 +--- a/redfish-core/lib/message_registries.hpp ++++ b/redfish-core/lib/message_registries.hpp +@@ -18,6 +18,7 @@ + #include "node.hpp" + #include "registries.hpp" + #include "registries/base_message_registry.hpp" ++#include "registries/bios_registry.hpp" + #include "registries/openbmc_message_registry.hpp" + #include "registries/resource_event_message_registry.hpp" + #include "registries/task_event_message_registry.hpp" +@@ -56,11 +57,12 @@ class MessageRegistryFileCollection : public Node + {"@odata.id", "/redfish/v1/Registries"}, + {"Name", "MessageRegistryFile Collection"}, + {"Description", "Collection of MessageRegistryFiles"}, +- {"Members@odata.count", 4}, ++ {"Members@odata.count", 5}, + {"Members", + {{{"@odata.id", "/redfish/v1/Registries/Base"}}, + {{"@odata.id", "/redfish/v1/Registries/TaskEvent"}}, + {{"@odata.id", "/redfish/v1/Registries/ResourceEvent"}}, ++ {{"@odata.id", "/redfish/v1/Registries/BiosAttributeRegistry"}}, + {{"@odata.id", "/redfish/v1/Registries/OpenBMC"}}}}}; + + res.end(); +@@ -118,6 +120,11 @@ class MessageRegistryFile : public Node + header = &message_registries::resource_event::header; + url = message_registries::resource_event::url; + } ++ else if (registry == "BiosAttributeRegistry") ++ { ++ header = &message_registries::bios::header; ++ dmtf.clear(); ++ } + else + { + messages::resourceNotFound( +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch new file mode 100644 index 000000000..6f3794478 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch @@ -0,0 +1,153 @@ +From ad2b1c83bd9cb1bb6eb86bebd1867b0172e5a7a8 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Wed, 23 Dec 2020 16:50:45 +0800 +Subject: [PATCH] BaseBiosTable: Add support for PATCH operation + +This commit brings in support for PATCH operation of the +bios variables that updates the BaseBiosTable. + +Tested-By: +* Passed Redfish validator + +* Single Attribute: +PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d +'{"data":[{"AttributeName": <attribute name>, "AttributeType": +<attribute type>, "AttributeValue": <attribute value>}]}' + +* Multiple Attributes: +PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d +'{"data":[{"AttributeName": <attribute name>, "AttributeType": +<attribute type>, "AttributeValue": <attribute value>}, +{"AttributeName": <attribute name>, "AttributeType": +<attribute type>, "AttributeValue": <attribute value>}]}' + +This makes use of the "Set" of "PendingAttributes" in the +backend and that updates the BaseBiosTable. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + redfish-core/lib/bios.hpp | 94 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 93 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index 5f8c91b..cf76fe0 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -96,6 +96,29 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus) + + return ret; + } ++static std::string mapRedfishToAttrType(const std::string_view type) ++{ ++ std::string ret; ++ if (type == "string") ++ { ++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String"; ++ } ++ else if (type == "int") ++ { ++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer"; ++ } ++ else if (type == "enum") ++ { ++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType." ++ "Enumeration"; ++ } ++ else ++ { ++ ret = "UNKNOWN"; ++ } ++ ++ return ret; ++} + static std::string mapBoundTypeToRedfish(const std::string_view typeDbus) + { + std::string ret; +@@ -262,7 +285,9 @@ class BiosSettings : public Node + BiosSettings(App& app) : + Node(app, "/redfish/v1/Systems/system/Bios/Settings") + { +- entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}}; ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; + } + + private: +@@ -359,6 +384,73 @@ class BiosSettings : public Node + "/xyz/openbmc_project/bios_config/manager", + std::array<const char*, 0>()); + } ++ ++ void doPatch(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>&) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ ++ nlohmann::json inpJson; ++ ++ if (!redfish::json_util::readJson(req, asyncResp->res, "data", inpJson)) ++ { ++ return; ++ } ++ ++ for (auto& attrInfo : inpJson) ++ { ++ std::optional<std::string> attrName; ++ std::optional<std::string> attrType; ++ std::optional<std::string> attrValue; ++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeName", ++ attrName)) ++ { ++ messages::propertyMissing(asyncResp->res, "AttributeName"); ++ return; ++ } ++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeType", ++ attrType)) ++ { ++ messages::propertyMissing(asyncResp->res, "AttributeType"); ++ return; ++ } ++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeValue", ++ attrValue)) ++ { ++ messages::propertyMissing(asyncResp->res, "AttributeValue"); ++ return; ++ } ++ std::string biosAttrType = mapRedfishToAttrType(*attrType); ++ ++ if (biosAttrType == "UNKNOWN") ++ { ++ BMCWEB_LOG_ERROR << "Invalid attribute type"; ++ messages::propertyValueNotInList(asyncResp->res, ++ "AttributeType", *attrType); ++ return; ++ } ++ ++ PendingAttributesType pendingAttributes; ++ pendingAttributes.emplace_back(std::make_pair( ++ *attrName, std::make_tuple(biosAttrType, *attrValue))); ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "doPatch resp_handler got error " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ }, ++ "xyz.openbmc_project.BIOSConfigManager", ++ "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes", ++ std::variant<PendingAttributesType>(pendingAttributes)); ++ } ++ } + }; + /** + * BiosAttributeRegistry class supports handle get method for BIOS attribute +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch new file mode 100644 index 000000000..7e4e2e8d8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch @@ -0,0 +1,62 @@ +From a78eecb032eefeb84da3ec042700a40f55ae8f10 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Wed, 23 Dec 2020 22:47:56 +0800 +Subject: [PATCH] Add support to ResetBios action + +Tested: + +Bios reset flag can be modified throw redfish +POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios + +Change-Id: I5e5fbdd70d4a3ce3b976cc2eb0a7d9a2a3adb124 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> + +--- + redfish-core/lib/bios.hpp | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index cf76fe0..7b6fc3d 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -643,7 +643,7 @@ class BiosReset : public Node + Node(app, "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios/") + { + entityPrivileges = { +- {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; + } + + private: +@@ -655,19 +655,23 @@ class BiosReset : public Node + const std::vector<std::string>&) override + { + auto asyncResp = std::make_shared<AsyncResp>(res); +- ++ std::string resetFlag = ++ "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.FactoryDefaults"; + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "Failed to reset bios: " << ec; ++ BMCWEB_LOG_ERROR << "doPost bios reset got error " << ec; + messages::internalError(asyncResp->res); + return; + } ++ BMCWEB_LOG_DEBUG << "bios reset action is done"; + }, +- "org.open_power.Software.Host.Updater", +- "/xyz/openbmc_project/software", +- "xyz.openbmc_project.Common.FactoryReset", "Reset"); ++ "xyz.openbmc_project.BIOSConfigManager", ++ "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.BIOSConfig.Manager", "ResetBIOSSettings", ++ std::variant<std::string>(resetFlag)); + } + }; + } // namespace redfish +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch new file mode 100644 index 000000000..976292197 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch @@ -0,0 +1,139 @@ +From ede8454491b554c2494a61f42993fa2e39b4d865 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Wed, 23 Dec 2020 14:41:23 +0800 +Subject: [PATCH] Add support to ChangePassword action + +Tested: + +Passed Redfish validator. +Bios change password: +root@intel-obmc:~# cat /var/lib/bios-settings-manager/seedData +{ +"UserPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D", +"AdminPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D", +"Seed": "123456", +"HashAlgo": "SHA384" +} +POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword +{ + "NewPassword": "12345678", + "OldPassword": "1234567890", + "PasswordName": "Administrator" +} +root@intel-obmc:~# cat /var/lib/bios-settings-manager/passwordData +{ + "CurrentPassword": "1234567890", + "IsAdminPwdChanged": 1, + "IsUserPwdChanged": 0, + "NewPassword": "2DD65D57EB60B1D92C5F3D2DC84724FCEE7BC02E57AA75E834712266ED94CAC704047B2FF7CEC1C36BED280B36BB5AC6", + "UserName": "Administrator" +} + +Change-Id: I90319a68da0b0a7f9c5cd65a8cb8cf52269a5f52 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + redfish-core/include/redfish.hpp | 1 + + redfish-core/lib/bios.hpp | 70 ++++++++++++++++++++++++++++++++ + 2 files changed, 71 insertions(+) + +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index a8e5cf2..dabf78e 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -160,6 +160,7 @@ class RedfishService + nodes.emplace_back(std::make_unique<BiosSettings>(app)); + nodes.emplace_back(std::make_unique<BiosAttributeRegistry>(app)); + nodes.emplace_back(std::make_unique<BiosReset>(app)); ++ nodes.emplace_back(std::make_unique<BiosChangePassword>(app)); + #ifdef BMCWEB_ENABLE_VM_NBDPROXY + nodes.emplace_back(std::make_unique<VirtualMedia>(app)); + nodes.emplace_back(std::make_unique<VirtualMediaCollection>(app)); +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index 7b6fc3d..61b396b 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -186,6 +186,9 @@ class BiosService : public Node + asyncResp->res.jsonValue["Actions"]["#Bios.ResetBios"] = { + {"target", + "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"}}; ++ asyncResp->res.jsonValue["Actions"]["#Bios.ChangePassword"] = { ++ {"target", ++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"}}; + + // Get the ActiveSoftwareImage and SoftwareImages + fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose, +@@ -674,4 +677,71 @@ class BiosReset : public Node + std::variant<std::string>(resetFlag)); + } + }; ++ ++/** ++ * BiosChangePassword class supports handle POST method for change bios ++ * password. The class retrieves and sends data directly to D-Bus. ++ */ ++class BiosChangePassword : public Node ++{ ++ public: ++ BiosChangePassword(App& app) : ++ Node(app, ++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword/") ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; ++ } ++ ++ private: ++ /** ++ * Function handles POST method request. ++ * Analyzes POST body message before sends Reset request data to D-Bus. ++ */ ++ void doPost(crow::Response& res, const crow::Request& req, ++ const std::vector<std::string>&) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ std::string currentPassword, newPassword, userName; ++ if (!json_util::readJson(req, res, "NewPassword", newPassword, ++ "OldPassword", currentPassword, "PasswordName", ++ userName)) ++ { ++ return; ++ } ++ if (currentPassword.empty()) ++ { ++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword", ++ "OldPassword"); ++ return; ++ } ++ if (newPassword.empty()) ++ { ++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword", ++ "NewPassword"); ++ return; ++ } ++ if (userName.empty()) ++ { ++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword", ++ "PasswordName"); ++ return; ++ } ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_CRITICAL << "Failed in doPost(BiosChangePassword) " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ }, ++ "xyz.openbmc_project.BIOSConfigPassword", ++ "/xyz/openbmc_project/bios_config/password", ++ "xyz.openbmc_project.BIOSConfig.Password", "ChangePassword", ++ userName, currentPassword, newPassword); ++ } ++}; ++ + } // namespace redfish +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch new file mode 100644 index 000000000..a9c46f487 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch @@ -0,0 +1,57 @@ +From a76314cd29f5cbcf19142b7120c5bf83358910fd Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Date: Mon, 28 Dec 2020 18:55:57 +0000 +Subject: [PATCH] managers: add attributes for Manager.CommandShell + +Issue: ConnectTypesSupported, ServiceEnabled and + MaxConcurrentSessions Attributes are missing for + Manager.CommandShell, though Requirement mandates it. + +Fix: Added missing attributes to Manager.CommandShell + +Tested: +1. Verified redfish validator passed +2. Get bmc details from Redfish +Redfish URI: https://<BMC IP>/redfish/v1/Managers/bmc +Response: +{ + "@odata.id": "/redfish/v1/Managers/bmc", + "@odata.type": "#Manager.v1_9_0.Manager", +.... +.... + "CommandShell": { + "ConnectTypesSupported": [ + "SSH", + "IPMI" + ], + "MaxConcurrentSessions": 4, + "ServiceEnabled": true + }, +.... +.... + +Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +--- + redfish-core/lib/managers.hpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp +index 6347caf..c401ca9 100644 +--- a/redfish-core/lib/managers.hpp ++++ b/redfish-core/lib/managers.hpp +@@ -1767,6 +1767,12 @@ class Manager : public Node + res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; + res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = {"IPMI", + "SSH"}; ++ // Fill in CommandShell info ++ res.jsonValue["CommandShell"]["ServiceEnabled"] = true; ++ res.jsonValue["CommandShell"]["MaxConcurrentSessions"] = 4; ++ res.jsonValue["CommandShell"]["ConnectTypesSupported"] = {"SSH", ++ "IPMI"}; ++ + #ifdef BMCWEB_ENABLE_KVM + // Fill in GraphicalConsole info + res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch new file mode 100644 index 000000000..e52dff3f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch @@ -0,0 +1,135 @@ +From b9747ecfce682f15dce0bb6e41e0c894f29419f3 Mon Sep 17 00:00:00 2001 +From: Snehalatha Venkatesh <snehalathax.v@intel.com> +Date: Thu, 8 Apr 2021 14:42:07 +0000 +Subject: [PATCH] bmcweb: Add PhysicalContext to Thermal resources + +Adding PhysicalContext to make redfish data compliance with OCP +Server Mgmt Interface v0.2.1.pdf and specific to Thermal resources. +https://github.com/opencomputeproject/OCP-Profiles/blob/master/ +OCPServerHardwareManagement.v0_2_4.json + +Tested: +1. Redfish validator - passed for this new change +2. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Thermal +Response: +{ + "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/0", + "@odata.type": "#Thermal.v1_3_0.Temperature", + "LowerThresholdCritical": 0.0, + "LowerThresholdNonCritical": 5.0, + "MaxReadingRangeTemp": 127.0, + "MemberId": "BMC_Temp", + "MinReadingRangeTemp": -128.0, + "Name": "BMC Temp", + "PhysicalContext": "SystemBoard", + "ReadingCelsius": 25.75, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "UpperThresholdCritical": 115.0, + "UpperThresholdNonCritical": 110.0 +}, +{ + "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/1", + "@odata.type": "#Thermal.v1_3_0.Temperature", + "LowerThresholdCritical": 0.0, + "LowerThresholdNonCritical": 5.0, + "MaxReadingRangeTemp": 255.0, + "MemberId": "CPU1_P12V_PVCCIN_VR_Temp", + "MinReadingRangeTemp": 0.0, + "Name": "CPU1 P12V PVCCIN VR Temp", + "PhysicalContext": "CPU", + "ReadingCelsius": 41.0, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "UpperThresholdCritical": 115.0, + "UpperThresholdNonCritical": 110.0 +}, +{ + "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/28", + "@odata.type": "#Thermal.v1_3_0.Temperature", + "LowerThresholdCritical": 0.0, + "LowerThresholdNonCritical": 5.0, + "MaxReadingRangeTemp": 127.0, + "MemberId": "Inlet_BRD_Temp", + "MinReadingRangeTemp": -128.0, + "Name": "Inlet BRD Temp", + "PhysicalContext": "Intake", + "ReadingCelsius": 23.187, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "UpperThresholdCritical": 115.0, + "UpperThresholdNonCritical": 110.0 +} +3. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Power +Response: +{ + "@odata.id": "/redfish/v1/Chassis/<Board>/Power#/Voltages/3", + "@odata.type": "#Power.v1_0_0.Voltage", + "LowerThresholdCritical": 1.648, + "LowerThresholdNonCritical": 1.699, + "MaxReadingRange": 2.3984009912875566, + "MemberId": "P1V8_PCH", + "MinReadingRange": 0.0, + "Name": "P1V8 PCH", + "ReadingVolts": 1.8055, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "UpperThresholdCritical": 1.961, + "UpperThresholdNonCritical": 1.904 +} +4. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Sensors/PSU1_Input_Current +Response: +{ + "@odata.id": "/redfish/v1/Chassis/<Board>/Sensors/PSU1_Input_Current", + "@odata.type": "#Sensor.v1_0_0.Sensor", + "Id": "PSU1_Input_Current", + "Name": "PSU1 Input Current", + "Reading": 0.947, + "ReadingRangeMax": 12.0, + "ReadingRangeMin": 0.0, + "ReadingType": "Current", + "ReadingUnits": "A", + "Status": { + "Health": "OK", + "State": "Enabled" + } +} +Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com> +--- + redfish-core/lib/sensors.hpp | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp +index 9f06d2f..40fcdf8 100644 +--- a/redfish-core/lib/sensors.hpp ++++ b/redfish-core/lib/sensors.hpp +@@ -964,6 +964,18 @@ inline void objectInterfacesToJson( + { + unit = "/ReadingCelsius"_json_pointer; + sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature"; ++ if (sensorName.find("CPU") != std::string::npos) ++ { ++ sensorJson["PhysicalContext"] = "CPU"; ++ } ++ else if (sensorName.find("Inlet") != std::string::npos) ++ { ++ sensorJson["PhysicalContext"] = "Intake"; ++ } ++ else ++ { ++ sensorJson["PhysicalContext"] = "SystemBoard"; ++ } + // TODO(ed) Documentation says that path should be type fan_tach, + // implementation seems to implement fan + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch new file mode 100644 index 000000000..3ef4ee2de --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch @@ -0,0 +1,67 @@ +From 1f572a1991fc8d9b08689aa6e3470080467977a7 Mon Sep 17 00:00:00 2001 +From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Date: Thu, 15 Apr 2021 10:59:42 +0000 +Subject: [PATCH] Log RedFish event for Invalid login attempt + +This commit adds support for logging RedFish event log while user tries +to attempt login with invalid credentials. +When user trying to login with invalid credentials on HTTPS interface +like WebUI and RedFish, event should be logged in RedFish event log. +This event log is useful for further analysis to debug the root-cause +for failure. + +Tested: +1. Verified RedFish validator passed +2. Login with wrong credentials on HTTPS interface. +3. Verified for RedFish/WebUI events. RedFish event logged successfully. +GET: https://BMC-IP/redfish/v1/Systems/system/LogServices/ + EventLog/Entries +Response: +"Members": [ +{ + "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/ + Entries/1618466128", + "@odata.type": "#LogEntry.v1_4_0.LogEntry", + "Created": "2021-04-15T05:55:28+00:00", + "EntryType": "Event", + "Id": "1618466128", + "Message": "Invalid username or password attempted on HTTPS.", + "MessageArgs": [ + "HTTPS" + ], + "MessageId": "OpenBMC.0.1.InvalidLoginAttempted", + "Name": "System Event Log Entry", + "Severity": "Warning" +} + +Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +--- + include/pam_authenticate.hpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp +index 12f19c0..01bf301 100644 +--- a/include/pam_authenticate.hpp ++++ b/include/pam_authenticate.hpp +@@ -1,6 +1,7 @@ + #pragma once + + #include <security/pam_appl.h> ++#include <systemd/sd-journal.h> + + #include <boost/utility/string_view.hpp> + +@@ -75,6 +76,10 @@ inline int pamAuthenticateUser(const std::string_view username, + PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); + if (retval != PAM_SUCCESS) + { ++ sd_journal_send("MESSAGE= %s", "Invalid login attempted on HTTPS", ++ "PRIORITY=%i", LOG_WARNING, "REDFISH_MESSAGE_ID=%s", ++ "OpenBMC.0.1.InvalidLoginAttempted", ++ "REDFISH_MESSAGE_ARGS=%s", "HTTPS", NULL); + pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval + return retval; + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch new file mode 100644 index 000000000..8b0d90fe0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch @@ -0,0 +1,59 @@ +From 6c10adb53d3247f65e5d9399290e6b8e7962cdef Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 28 Apr 2021 17:19:50 -0700 +Subject: [PATCH] Add UART routing logic into host console connection flow + +Switching UART routing when starting obmc-service introduces garbled +character printing out on physical host serial output and it's +inevitable so this commit moves the routing logic into host console +connection flow in bmcweb to avoid the issue until SOL is actually +activated. + +Tested: The garbled character printing out was not observed during +BMC booting. SOL worked well. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + include/obmc_console.hpp | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/include/obmc_console.hpp b/include/obmc_console.hpp +index cdb19901e82d..9c4ae8821074 100644 +--- a/include/obmc_console.hpp ++++ b/include/obmc_console.hpp +@@ -22,6 +22,9 @@ static boost::container::flat_set<crow::websocket::Connection*> sessions; + + static bool doingWrite = false; + ++constexpr char const* uartMuxCtrlPath = "/sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/raw"; ++constexpr char const* uartMuxCtrlVal = "0x03450003"; ++ + inline void doWrite() + { + if (doingWrite) +@@ -110,6 +113,22 @@ inline void connectHandler(const boost::system::error_code& ec) + return; + } + ++ FILE* file = fopen(uartMuxCtrlPath, "w"); ++ if (file != nullptr) ++ { ++ int rc = fputs(uartMuxCtrlVal, file); ++ fclose(file); ++ if (rc < 0) ++ { ++ BMCWEB_LOG_ERROR << "Couldn't change UART routing: " << rc; ++ for (crow::websocket::Connection* session : sessions) ++ { ++ session->close("Error in connecting to host port"); ++ } ++ return; ++ } ++ } ++ + doWrite(); + doRead(); + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch new file mode 100644 index 000000000..5ffc259c0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch @@ -0,0 +1,75 @@ +From aaaa117817687a05284f8bfff07e2404e0d616b7 Mon Sep 17 00:00:00 2001 +From: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Date: Thu, 10 Dec 2020 13:42:20 -0800 +Subject: [PATCH] recommended fixes by crypto review team + +some curves/cyphers are forbiden to be used by +Intel crypto team. +Only enable approved ones. +the patch was created by aleksandr.v.tereschenko@intel.com + +Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +--- + include/ssl_key_handler.hpp | 39 ++++++++++++++++++++----------------- + 1 file changed, 21 insertions(+), 18 deletions(-) + +diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp +index 39e83d7..8de7349 100644 +--- a/include/ssl_key_handler.hpp ++++ b/include/ssl_key_handler.hpp +@@ -381,31 +381,34 @@ inline std::shared_ptr<boost::asio::ssl::context> + mSslContext->use_private_key_file(sslPemFile, + boost::asio::ssl::context::pem); + +- // Set up EC curves to auto (boost asio doesn't have a method for this) +- // There is a pull request to add this. Once this is included in an asio +- // drop, use the right way +- // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue +- if (SSL_CTX_set_ecdh_auto(mSslContext->native_handle(), 1) != 1) ++ std::string handshakeCurves = "P-384:P-521:X448"; ++ if (SSL_CTX_set1_groups_list(mSslContext->native_handle(), handshakeCurves.c_str()) != 1) + { +- BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n"; ++ BMCWEB_LOG_ERROR << "Error setting ECDHE group list\n"; + } + +- std::string mozillaModern = "ECDHE-ECDSA-AES256-GCM-SHA384:" +- "ECDHE-RSA-AES256-GCM-SHA384:" +- "ECDHE-ECDSA-CHACHA20-POLY1305:" +- "ECDHE-RSA-CHACHA20-POLY1305:" +- "ECDHE-ECDSA-AES128-GCM-SHA256:" +- "ECDHE-RSA-AES128-GCM-SHA256:" +- "ECDHE-ECDSA-AES256-SHA384:" +- "ECDHE-RSA-AES256-SHA384:" +- "ECDHE-ECDSA-AES128-SHA256:" +- "ECDHE-RSA-AES128-SHA256"; ++ std::string tls12Ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:" ++ "ECDHE-RSA-AES256-GCM-SHA384"; ++ std::string tls13Ciphers = "TLS_AES_256_GCM_SHA384"; + + if (SSL_CTX_set_cipher_list(mSslContext->native_handle(), +- mozillaModern.c_str()) != 1) ++ tls12Ciphers.c_str()) != 1) + { +- BMCWEB_LOG_ERROR << "Error setting cipher list\n"; ++ BMCWEB_LOG_ERROR << "Error setting TLS 1.2 cipher list\n"; + } ++ ++ if (SSL_CTX_set_ciphersuites(mSslContext->native_handle(), ++ tls13Ciphers.c_str()) != 1) ++ { ++ BMCWEB_LOG_ERROR << "Error setting TLS 1.3 cipher list\n"; ++ } ++ ++ if ((SSL_CTX_set_options(mSslContext->native_handle(), ++ SSL_OP_CIPHER_SERVER_PREFERENCE) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0) ++ { ++ BMCWEB_LOG_ERROR << "Error setting TLS server preference option\n"; ++ } ++ + return mSslContext; + } + } // namespace ensuressl +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0037-Add-state-sensor-messages-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0037-Add-state-sensor-messages-to-the-registry.patch new file mode 100644 index 000000000..b171a8b2c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0037-Add-state-sensor-messages-to-the-registry.patch @@ -0,0 +1,98 @@ +From df571ddf0596f73c0318da3a90b9813e6df19dd9 Mon Sep 17 00:00:00 2001 +From: "Arun P. Mohanan" <arun.p.m@linux.intel.com> +Date: Wed, 27 Jan 2021 18:22:58 +0530 +Subject: [PATCH] Add state sensor messages to the registry + +Add messages to registry to indicate state sensor state change. + +Tested: +Build and redfish validator passes. +Logged these events and confirmed that they appear as expected on +Redfish. +GET: https://<BMC IP>/redfish/v1/Systems/system/LogServices/EventLog/Entries/1612528180 +{ + "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1612528180", + "@odata.type": "#LogEntry.v1_4_0.LogEntry", + "Created": "2021-02-05T12:29:40+00:00", + "EntryType": "Event", + "Id": "1612528180", + "Message": "Operational Fault Status of Card_health_1 state sensor changed from Error to Normal.", + "MessageArgs": [ + "Operational Fault Status", + "Card_health_1", + "Error", + "Normal" + ], + "MessageId": "OpenBMC.0.1.StateSensorNormal", + "Name": "System Event Log Entry", + "Severity": "OK" +} + +Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com> +--- + .../registries/openbmc_message_registry.hpp | 36 +++++++++++++++++-- + 1 file changed, 34 insertions(+), 2 deletions(-) + +diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp +index 5eb9380..dbea97c 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<MessageEntry, 187> registry = { ++constexpr std::array<MessageEntry, 190> registry = { + MessageEntry{ + "ADDDCCorrectable", + { +@@ -2318,6 +2318,39 @@ constexpr std::array<MessageEntry, 187> registry = { + {}, + "None.", + }}, ++ MessageEntry{ ++ "StateSensorNormal", ++ { ++ "Indicates that a state sensor has changed state to normal.", ++ "%1 of %2 state sensor changed from %3 to %4.", ++ "OK", ++ "OK", ++ 4, ++ {"string", "string", "string", "string"}, ++ "None.", ++ }}, ++ MessageEntry{ ++ "StateSensorWarning", ++ { ++ "Indicates that a state sensor has changed state to warning.", ++ "%1 of %2 state sensor changed from %3 to %4.", ++ "Warning", ++ "Warning", ++ 4, ++ {"string", "string", "string", "string"}, ++ "Check sensor subsystem for errors.", ++ }}, ++ MessageEntry{ ++ "StateSensorCritical", ++ { ++ "Indicates that a state sensor has changed state to critical.", ++ "%1 of %2 state sensor changed from %3 to %4.", ++ "Critical", ++ "Critical", ++ 4, ++ {"string", "string", "string", "string"}, ++ "Check sensor subsystem for errors.", ++ }}, + MessageEntry{"SystemInterfaceDisabledProvisioned", + { + "Indicates that the system interface is in the disabled " +@@ -2410,6 +2443,5 @@ constexpr std::array<MessageEntry, 187> registry = { + {"string"}, + "None.", + }}, +- + }; + } // namespace redfish::message_registries::openbmc +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0038-Revert-Disable-nbd-proxy-from-the-build.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0038-Revert-Disable-nbd-proxy-from-the-build.patch new file mode 100644 index 000000000..3e3f69d1c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0038-Revert-Disable-nbd-proxy-from-the-build.patch @@ -0,0 +1,50 @@ +From 95f002dc969d7d6d64dbf2ee0db7dc1c1c6a9173 Mon Sep 17 00:00:00 2001 +From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +Date: Thu, 18 Mar 2021 11:30:28 +0100 +Subject: [PATCH] Revert "Disable nbd proxy from the build" + +NBD Proxy has been disabled upstream. Reenable as we use it for Virtual +Media + +This reverts commit efb8062c306474942bc94f15d748b2eb0b58fbb6. +--- + meson.build | 2 +- + meson_options.txt | 9 +-------- + 2 files changed, 2 insertions(+), 9 deletions(-) + +diff --git a/meson.build b/meson.build +index 66a066b..cef0a49 100644 +--- a/meson.build ++++ b/meson.build +@@ -81,7 +81,7 @@ feature_map = { + 'static-hosting' : '-DBMCWEB_ENABLE_STATIC_HOSTING', + 'insecure-tftp-update' : '-DBMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE', + 'validate-unsecure-feature' : '-DBMCWEB_ENABLE_VALIDATION_UNSECURE_FEATURE', +-#'vm-nbdproxy' : '-DBMCWEB_ENABLE_VM_NBDPROXY', ++'vm-nbdproxy' : '-DBMCWEB_ENABLE_VM_NBDPROXY', + 'vm-websocket' : '-DBMCWEB_ENABLE_VM_WEBSOCKET', + } + +diff --git a/meson_options.txt b/meson_options.txt +index 9611631..7ee3ebb 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -3,14 +3,7 @@ option('yocto-deps', type: 'feature', value: 'disabled', description : 'Use YOCT + option('kvm', type : 'feature',value : 'enabled', description : 'Enable the KVM host video WebSocket. Path is \'/kvm/0\'. Video is from the BMC\'s \'/dev/video\' device.') + option ('tests', type : 'feature', value : 'enabled', description : 'Enable Unit tests for bmcweb') + option('vm-websocket', type : 'feature', value : 'enabled', description : '''Enable the Virtual Media WebSocket. Path is \'/vm/0/0\'to open the websocket. See https://github.com/openbmc/jsnbd/blob/master/README.''') +- +-# if you use this option and are seeing this comment, please comment here: +-# https://github.com/openbmc/bmcweb/issues/188 and put forward your intentions +-# for this code. At this point, no daemon has been upstreamed that implements +-# this interface, so for the moment this appears to be dead code; In leiu of +-# removing it, it has been disabled to try to give those that use it the +-# opportunity to upstream their backend implementation +-#option('vm-nbdproxy', type: 'feature', value : 'disabled', description : 'Enable the Virtual Media WebSocket.') ++option('vm-nbdproxy', type: 'feature', value : 'disabled', description : 'Enable the Virtual Media WebSocket.') + option('rest', type : 'feature', value : 'enabled', description : '''Enable Phosphor REST (D-Bus) APIs. Paths directly map Phosphor D-Bus object paths, for example, \'/xyz/openbmc_project/logging/entry/enumerate\'. See https://github.com/openbmc/docs/blob/master/rest-api.md.''') + option('redfish', type : 'feature',value : 'enabled', description: 'Enable Redfish APIs. Paths are under \'/redfish/v1/\'. See https://github.com/openbmc/bmcweb/blob/master/DEVELOPING.md#redfish.') + option('host-serial-socket', type : 'feature', value : 'enabled', description : 'Enable host serial console WebSocket. Path is \'/console0\'. See https://github.com/openbmc/docs/blob/master/console.md.') +-- +2.26.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0039-Fix-bmcweb-crashes-if-socket-directory-not-present.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0039-Fix-bmcweb-crashes-if-socket-directory-not-present.patch new file mode 100644 index 000000000..bc023839f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0039-Fix-bmcweb-crashes-if-socket-directory-not-present.patch @@ -0,0 +1,44 @@ +From 48fe2a68d634970795f9ff13903afbedca801088 Mon Sep 17 00:00:00 2001 +From: Nidhin MS <nidhin.ms@intel.com> +Date: Wed, 14 Apr 2021 11:28:44 +0530 +Subject: [PATCH] Fix: bmcweb crashes if socket directory not present + +When trying to mount virtual media image bmcweb tries to create unix +socket and if the parent directory does not exist +stream_protocol::acceptor throws error and bmcweb crashes. Fix the same + +Tested: +Removed directory and mounted the vm image. bmcweb crash was not +observed + +Change-Id: I3aea1d8e197c06238f425a97435c01d3c80552a9 +Signed-off-by: Nidhin MS <nidhin.ms@intel.com> +--- + include/nbd_proxy.hpp | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp +index 7b90e90..3b28823 100644 +--- a/include/nbd_proxy.hpp ++++ b/include/nbd_proxy.hpp +@@ -397,6 +397,17 @@ inline void requestRoutes(App& app) + // If the socket file exists (i.e. after bmcweb crash), + // we cannot reuse it. + std::remove((*socketValue).c_str()); ++ std::filesystem::path socketPath(*socketValue); ++ std::error_code fsErr; ++ if (!std::filesystem::exists(socketPath.parent_path(), ++ fsErr)) ++ { ++ BMCWEB_LOG_ERROR ++ << "VirtualMedia socket directory not present. " ++ << socketPath.parent_path(); ++ conn.close("Unable to create unix socket"); ++ return; ++ } + + sessions[&conn] = std::make_shared<NbdProxyServer>( + conn, *socketValue, *endpointValue, +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0039-Fix-comparison-for-proxy-legacy-mode.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0039-Fix-comparison-for-proxy-legacy-mode.patch new file mode 100644 index 000000000..f02e5e1a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0039-Fix-comparison-for-proxy-legacy-mode.patch @@ -0,0 +1,51 @@ +From 7cde56820505a4f750cc67caa0dc9300688f3fd9 Mon Sep 17 00:00:00 2001 +From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +Date: Tue, 13 Apr 2021 15:16:43 +0200 +Subject: [PATCH] Fix comparison for proxy/legacy mode + +After sdbusplus made available string path wrapper VM code has been +updated to use it. This makes legacy mode unusable as appropriate +change introduced a problem with comparison of DBus object path, which +is now fixed. + +Tested: +After applying this fix, legacy mode has InsertMedia action enabled +again. + +Change-Id: I062994f23b77cb7ab9c4421f296a65a80b9ce896 +Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> +--- + redfish-core/lib/virtual_media.hpp | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp +index 365290b..dda73d8 100644 +--- a/redfish-core/lib/virtual_media.hpp ++++ b/redfish-core/lib/virtual_media.hpp +@@ -274,10 +274,22 @@ static void getVmData(const std::shared_ptr<AsyncResp>& aResp, + continue; + } + ++ auto mode = item.first.parent_path(); ++ auto type = mode.parent_path(); ++ if (mode.filename().empty() || type.filename().empty()) ++ { ++ continue; ++ } ++ ++ if (type.filename() != "VirtualMedia") ++ { ++ continue; ++ } ++ + aResp->res.jsonValue = vmItemTemplate(name, resName); + + // Check if dbus path is Legacy type +- if (thispath.find("VirtualMedia/Legacy") != std::string::npos) ++ if (mode.filename() == "Legacy") + { + aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"] + ["target"] = +-- +2.26.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket new file mode 100644 index 000000000..8782e4dd3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket @@ -0,0 +1,9 @@ +[Unit] +Description=BMC Webserver socket + +[Socket] +ListenStream=443 +ReusePort=true + +[Install] +WantedBy=sockets.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch new file mode 100644 index 000000000..b46d30149 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch @@ -0,0 +1,543 @@ +From ae55e89c14ea5abef0895409c956f5f4c38f330f Mon Sep 17 00:00:00 2001 +From: Sunitha Harish <sunithaharish04@gmail.com> +Date: Fri, 19 Feb 2021 13:38:31 +0530 +Subject: [PATCH 1/2] EventService : Fix retry handling for http-client + +When the event send/receive is failed, the bmcweb does not handle +the failure to tear-down the complete connection and start a fresh + +The keep-alive header from the event listener is read to update +the connection states, so that the connection will be kept alive +or closed as per the subscriber's specifications + +Updated the connection state machine to handle retry logic properly. +Avoided multiple simultaneous async calls which crashes the bmcweb. So +added connBusy flag which protects simultaneous async calls. + +Used boost http response parser as parser for producing the response +message. Set the parser skip option to handle the empty response message +from listening server. + +Tested by: + - Subscribe for the events at BMC using DMTF event listener + - Generate an event and see the same is received at the listener's console + - Update the listner to change the keep-alive to true/false and + observe the http-client connection states at bmcweb + +Change-Id: Ibb45691f139916ba2954da37beda9d4f91c7cef3 +Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + http/http_client.hpp | 289 ++++++++++-------- + .../include/event_service_manager.hpp | 2 +- + 2 files changed, 163 insertions(+), 128 deletions(-) + +diff --git a/http/http_client.hpp b/http/http_client.hpp +index 992ac2b..d116f6d 100644 +--- a/http/http_client.hpp ++++ b/http/http_client.hpp +@@ -34,22 +34,28 @@ namespace crow + { + + static constexpr uint8_t maxRequestQueueSize = 50; ++static constexpr unsigned int httpReadBodyLimit = 8192; + + enum class ConnState + { + initialized, + resolveInProgress, + resolveFailed, ++ resolved, + connectInProgress, + connectFailed, + connected, + sendInProgress, + sendFailed, ++ recvInProgress, + recvFailed, + idle, +- suspended, ++ closeInProgress, + closed, +- terminated ++ suspended, ++ terminated, ++ abortConnection, ++ retry + }; + + class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -58,11 +64,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + crow::async_resolve::Resolver resolver; + boost::beast::tcp_stream conn; + boost::asio::steady_timer timer; +- boost::beast::flat_buffer buffer; ++ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; + boost::beast::http::request<boost::beast::http::string_body> req; +- boost::beast::http::response<boost::beast::http::string_body> res; +- std::vector<std::pair<std::string, std::string>> headers; +- std::queue<std::string> requestDataQueue; ++ std::optional< ++ boost::beast::http::response_parser<boost::beast::http::string_body>> ++ parser; ++ boost::asio::ip::tcp::endpoint endpoint; ++ boost::circular_buffer_space_optimized<std::string> requestDataQueue{}; ++ std::vector<boost::asio::ip::tcp::endpoint> endPoints; + ConnState state; + std::string subId; + std::string host; +@@ -76,12 +85,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + + void doResolve() + { +- if (state == ConnState::resolveInProgress) +- { +- return; +- } + state = ConnState::resolveInProgress; +- + BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port; + + auto respHandler = +@@ -89,78 +93,56 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + const boost::beast::error_code ec, + const std::vector<boost::asio::ip::tcp::endpoint>& + endpointList) { +- if (ec) ++ if (ec || (endpointList.size() == 0)) + { + BMCWEB_LOG_ERROR << "Resolve failed: " << ec.message(); + self->state = ConnState::resolveFailed; +- self->checkQueue(); ++ self->handleConnState(); + return; + } + BMCWEB_LOG_DEBUG << "Resolved"; +- self->doConnect(endpointList); ++ self->endPoints.assign(endpointList.begin(), ++ endpointList.end()); ++ self->state = ConnState::resolved; ++ self->handleConnState(); + }; + resolver.asyncResolve(host, port, std::move(respHandler)); + } + +- void doConnect( +- const std::vector<boost::asio::ip::tcp::endpoint>& endpointList) ++ void doConnect() + { +- if (state == ConnState::connectInProgress) +- { +- return; +- } + state = ConnState::connectInProgress; + + BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; + + conn.expires_after(std::chrono::seconds(30)); + conn.async_connect( +- endpointList, [self(shared_from_this())]( +- const boost::beast::error_code ec, +- const boost::asio::ip::tcp::endpoint& endpoint) { ++ endPoints, [self(shared_from_this())]( ++ const boost::beast::error_code ec, ++ const boost::asio::ip::tcp::endpoint& endpoint) { + if (ec) + { + BMCWEB_LOG_ERROR << "Connect " << endpoint + << " failed: " << ec.message(); + self->state = ConnState::connectFailed; +- self->checkQueue(); ++ self->handleConnState(); + return; + } +- self->state = ConnState::connected; + BMCWEB_LOG_DEBUG << "Connected to: " << endpoint; +- +- self->checkQueue(); ++ self->state = ConnState::connected; ++ self->handleConnState(); + }); + } + + void sendMessage(const std::string& data) + { +- if (state == ConnState::sendInProgress) +- { +- return; +- } + state = ConnState::sendInProgress; + + BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; + +- req.version(static_cast<int>(11)); // HTTP 1.1 +- req.target(uri); +- req.method(boost::beast::http::verb::post); +- +- // Set headers +- for (const auto& [key, value] : headers) +- { +- req.set(key, value); +- } +- req.set(boost::beast::http::field::host, host); +- req.keep_alive(true); +- + req.body() = data; + req.prepare_payload(); + +- // Set a timeout on the operation +- conn.expires_after(std::chrono::seconds(30)); +- + // Send the HTTP request to the remote host + boost::beast::http::async_write( + conn, req, +@@ -171,7 +153,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + BMCWEB_LOG_ERROR << "sendMessage() failed: " + << ec.message(); + self->state = ConnState::sendFailed; +- self->checkQueue(); ++ self->handleConnState(); + return; + } + BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " +@@ -184,9 +166,18 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + + void recvMessage() + { ++ state = ConnState::recvInProgress; ++ ++ parser.emplace(std::piecewise_construct, std::make_tuple()); ++ parser->body_limit(httpReadBodyLimit); ++ // Since these are all push style eventing, we are not ++ // bothered about response body parsing. ++ // Check only for the response header ++ parser->skip(true); ++ + // Receive the HTTP response + boost::beast::http::async_read( +- conn, buffer, res, ++ conn, buffer, *parser, + [self(shared_from_this())](const boost::beast::error_code& ec, + const std::size_t& bytesTransferred) { + if (ec) +@@ -194,30 +185,46 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + BMCWEB_LOG_ERROR << "recvMessage() failed: " + << ec.message(); + self->state = ConnState::recvFailed; +- self->checkQueue(); ++ self->handleConnState(); + 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; ++ BMCWEB_LOG_DEBUG << "recvMessage() data: " ++ << self->parser->get(); + + // Send is successful, Lets remove data from queue + // check for next request data in queue. +- self->requestDataQueue.pop(); ++ if (!self->requestDataQueue.empty()) ++ { ++ self->requestDataQueue.pop_front(); ++ } + self->state = ConnState::idle; +- self->checkQueue(); ++ ++ // Keep the connection alive if server supports it ++ // Else close the connection ++ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : " ++ << self->parser->keep_alive(); ++ if (!self->parser->keep_alive()) ++ { ++ // Abort the connection since server is not keep-alive ++ // enabled ++ self->state = ConnState::abortConnection; ++ } ++ // Transfer ownership of the response ++ self->parser->release(); ++ ++ self->handleConnState(); + }); + } + + void doClose() + { ++ state = ConnState::closeInProgress; + boost::beast::error_code ec; + conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); ++ conn.close(); + +- state = ConnState::closed; + // not_connected happens sometimes so don't bother reporting it. + if (ec && ec != boost::beast::errc::not_connected) + { +@@ -225,112 +232,139 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + return; + } + BMCWEB_LOG_DEBUG << "Connection closed gracefully"; +- } +- +- void checkQueue(const bool newRecord = false) +- { +- if (requestDataQueue.empty()) ++ if ((state != ConnState::suspended) && (state != ConnState::terminated)) + { +- // TODO: Having issue in keeping connection alive. So lets close if +- // nothing to be transferred. +- doClose(); +- +- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; +- return; ++ state = ConnState::closed; ++ handleConnState(); + } ++ } + ++ void waitAndRetry() ++ { + if (retryCount >= maxRetryAttempts) + { +- BMCWEB_LOG_ERROR << "Maximum number of retries is reached."; ++ BMCWEB_LOG_ERROR << "Maximum number of retries reached."; + + // Clear queue. + while (!requestDataQueue.empty()) + { +- requestDataQueue.pop(); ++ requestDataQueue.pop_front(); + } + +- BMCWEB_LOG_DEBUG << "Retry policy is set to " << retryPolicyAction; ++ BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction; + if (retryPolicyAction == "TerminateAfterRetries") + { + // TODO: delete subscription + state = ConnState::terminated; +- return; + } + if (retryPolicyAction == "SuspendRetries") + { + state = ConnState::suspended; +- return; + } +- // keep retrying, reset count and continue. ++ // Reset the retrycount to zero so that client can try connecting ++ // again if needed + retryCount = 0; ++ handleConnState(); ++ return; + } + +- if ((state == ConnState::connectFailed) || +- (state == ConnState::sendFailed) || +- (state == ConnState::recvFailed)) ++ if (runningTimer) + { +- if (newRecord) +- { +- // We are already running async wait and retry. +- // Since record is added to queue, it gets the +- // turn in FIFO. +- return; +- } +- +- if (runningTimer) +- { +- BMCWEB_LOG_DEBUG << "Retry timer is already running."; +- return; +- } +- runningTimer = true; +- +- retryCount++; +- +- BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs +- << " seconds. RetryCount = " << retryCount; +- timer.expires_after(std::chrono::seconds(retryIntervalSecs)); +- timer.async_wait( +- [self = shared_from_this()](const boost::system::error_code&) { +- self->runningTimer = false; +- self->connStateCheck(); +- }); ++ BMCWEB_LOG_DEBUG << "Retry timer is already running."; + return; + } +- // reset retry count. +- retryCount = 0; +- connStateCheck(); ++ runningTimer = true; + ++ retryCount++; ++ ++ BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs ++ << " seconds. RetryCount = " << retryCount; ++ timer.expires_after(std::chrono::seconds(retryIntervalSecs)); ++ timer.async_wait( ++ [self = shared_from_this()](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "async_wait failed: " << ec.message(); ++ // Ignore the error and continue the retry loop to attempt ++ // sending the event as per the retry policy ++ } ++ self->runningTimer = false; ++ ++ // Lets close connection and start from resolve. ++ self->doClose(); ++ }); + return; + } + +- void connStateCheck() ++ void handleConnState() + { + switch (state) + { + case ConnState::resolveInProgress: + case ConnState::connectInProgress: + case ConnState::sendInProgress: +- case ConnState::suspended: +- case ConnState::terminated: +- // do nothing ++ case ConnState::recvInProgress: ++ case ConnState::closeInProgress: ++ { ++ BMCWEB_LOG_DEBUG << "Async operation is already in progress"; + break; ++ } + case ConnState::initialized: + case ConnState::closed: ++ { ++ if (requestDataQueue.empty()) ++ { ++ BMCWEB_LOG_DEBUG << "requestDataQueue is empty"; ++ return; ++ } ++ doResolve(); ++ break; ++ } ++ case ConnState::resolved: ++ { ++ doConnect(); ++ break; ++ } ++ case ConnState::suspended: ++ case ConnState::terminated: ++ { ++ doClose(); ++ break; ++ } ++ case ConnState::resolveFailed: + case ConnState::connectFailed: + case ConnState::sendFailed: + case ConnState::recvFailed: +- case ConnState::resolveFailed: ++ case ConnState::retry: + { +- doResolve(); ++ // In case of failures during connect and handshake ++ // the retry policy will be applied ++ waitAndRetry(); + break; + } + case ConnState::connected: + case ConnState::idle: + { ++ // State idle means, previous attempt is successful ++ // State connected means, client connection is established ++ // successfully ++ if (requestDataQueue.empty()) ++ { ++ BMCWEB_LOG_DEBUG << "requestDataQueue is empty"; ++ return; ++ } + std::string data = requestDataQueue.front(); + sendMessage(data); + break; + } ++ case ConnState::abortConnection: ++ { ++ // Server did not want to keep alive the session ++ doClose(); ++ break; ++ } ++ default: ++ break; + } + } + +@@ -339,37 +373,38 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + const std::string& destIP, const std::string& destPort, + const std::string& destUri) : + conn(ioc), +- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), +- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), ++ timer(ioc), req(boost::beast::http::verb::post, destUri, 11), ++ state(ConnState::initialized), subId(id), host(destIP), port(destPort), ++ uri(destUri), retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), + retryPolicyAction("TerminateAfterRetries"), runningTimer(false) + { +- state = ConnState::initialized; ++ // Set the request header ++ req.set(boost::beast::http::field::host, host); ++ req.set(boost::beast::http::field::content_type, "application/json"); ++ req.keep_alive(true); ++ ++ requestDataQueue.set_capacity(maxRequestQueueSize); + } + + void sendData(const std::string& data) + { +- if (state == ConnState::suspended) ++ if ((state == ConnState::suspended) || (state == ConnState::terminated)) + { + return; + } +- +- if (requestDataQueue.size() <= maxRequestQueueSize) +- { +- requestDataQueue.push(data); +- checkQueue(true); +- } +- else +- { +- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data."; +- } +- ++ requestDataQueue.push_back(data); ++ handleConnState(); + return; + } + +- void setHeaders( ++ void addHeaders( + const std::vector<std::pair<std::string, std::string>>& httpHeaders) + { +- headers = httpHeaders; ++ // Set custom headers ++ for (const auto& [key, value] : httpHeaders) ++ { ++ req.set(key, value); ++ } + } + + void setRetryConfig(const uint32_t retryAttempts, +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 148c703..bffa68f 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -412,7 +412,7 @@ class Subscription + reqHeaders.emplace_back(std::pair(key, val)); + } + } +- conn->setHeaders(reqHeaders); ++ conn->addHeaders(reqHeaders); + conn->sendData(msg); + this->eventSeqNum++; + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch new file mode 100644 index 000000000..b1f61c6fd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch @@ -0,0 +1,401 @@ +From 579fda953ec991b4e7f9d7194b08f6aa103fa0ec Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 22 Feb 2021 17:07:47 +0000 +Subject: [PATCH 2/2] EventService: https client support + +Add https client support for push style +eventing. Using this BMC can push the event +logs/telemetry data to event listener over +secure http channel. + +Tested: + - Created subscription with https destination + url. Using SubmitTestEvent action set the + event and can see event on event listener. + - Validator passed. + +Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + http/http_client.hpp | 255 ++++++++++++------ + .../include/event_service_manager.hpp | 2 +- + 2 files changed, 175 insertions(+), 82 deletions(-) + +diff --git a/http/http_client.hpp b/http/http_client.hpp +index d116f6d..cebc857 100644 +--- a/http/http_client.hpp ++++ b/http/http_client.hpp +@@ -20,6 +20,7 @@ + #include <boost/beast/core/flat_buffer.hpp> + #include <boost/beast/core/tcp_stream.hpp> + #include <boost/beast/http/message.hpp> ++#include <boost/beast/ssl/ssl_stream.hpp> + #include <boost/beast/version.hpp> + #include <include/async_resolve.hpp> + +@@ -44,6 +45,8 @@ enum class ConnState + resolved, + connectInProgress, + connectFailed, ++ handshakeInProgress, ++ handshakeFailed, + connected, + sendInProgress, + sendFailed, +@@ -62,7 +65,9 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + { + private: + crow::async_resolve::Resolver resolver; ++ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; + boost::beast::tcp_stream conn; ++ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn; + boost::asio::steady_timer timer; + boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; + boost::beast::http::request<boost::beast::http::string_body> req; +@@ -112,23 +117,52 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + void doConnect() + { + state = ConnState::connectInProgress; ++ sslConn.emplace(conn, ctx); + + BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code ec, ++ const boost::asio::ip::tcp::endpoint& endpoint) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Connect " << endpoint ++ << " failed: " << ec.message(); ++ self->state = ConnState::connectFailed; ++ self->handleConnState(); ++ return; ++ } + ++ BMCWEB_LOG_DEBUG << "Connected to: " << endpoint; ++ if (self->sslConn) ++ { ++ self->performHandshake(); ++ } ++ else ++ { ++ self->handleConnState(); ++ } ++ }; + conn.expires_after(std::chrono::seconds(30)); +- conn.async_connect( +- endPoints, [self(shared_from_this())]( +- const boost::beast::error_code ec, +- const boost::asio::ip::tcp::endpoint& endpoint) { ++ conn.async_connect(endPoints, std::move(respHandler)); ++ } ++ ++ void performHandshake() ++ { ++ state = ConnState::handshakeInProgress; ++ ++ sslConn->async_handshake( ++ boost::asio::ssl::stream_base::client, ++ [self(shared_from_this())](const boost::beast::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "Connect " << endpoint +- << " failed: " << ec.message(); +- self->state = ConnState::connectFailed; ++ BMCWEB_LOG_ERROR << "SSL handshake failed: " ++ << ec.message(); ++ self->state = ConnState::handshakeFailed; + self->handleConnState(); + return; + } +- BMCWEB_LOG_DEBUG << "Connected to: " << endpoint; ++ ++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull"; + self->state = ConnState::connected; + self->handleConnState(); + }); +@@ -136,106 +170,159 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + + void sendMessage(const std::string& data) + { +- state = ConnState::sendInProgress; +- + BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; ++ state = ConnState::sendInProgress; + + req.body() = data; + req.prepare_payload(); + +- // Send the HTTP request to the remote host +- boost::beast::http::async_write( +- conn, req, +- [self(shared_from_this())](const boost::beast::error_code& ec, +- const std::size_t& bytesTransferred) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "sendMessage() failed: " +- << ec.message(); +- self->state = ConnState::sendFailed; +- self->handleConnState(); +- return; +- } +- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code ec, ++ const std::size_t& bytesTransferred) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); ++ self->state = ConnState::sendFailed; ++ self->handleConnState(); ++ return; ++ } + +- self->recvMessage(); +- }); +- } ++ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " ++ << bytesTransferred; ++ boost::ignore_unused(bytesTransferred); ++ self->recvMessage(); ++ }; + ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) ++ { ++ boost::beast::http::async_write(*sslConn, req, ++ std::move(respHandler)); ++ } ++ else ++ { ++ boost::beast::http::async_write(conn, req, std::move(respHandler)); ++ } ++ } + void recvMessage() + { + state = ConnState::recvInProgress; + ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code ec, ++ const std::size_t& bytesTransferred) { ++ if (ec && ec != boost::asio::ssl::error::stream_truncated) ++ { ++ BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message(); ++ ++ self->state = ConnState::recvFailed; ++ self->handleConnState(); ++ return; ++ } ++ ++ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " ++ << bytesTransferred; ++ boost::ignore_unused(bytesTransferred); ++ // Send is successful, Lets remove data from queue ++ // check for next request data in queue. ++ if (!self->requestDataQueue.empty()) ++ { ++ self->requestDataQueue.pop_front(); ++ } ++ self->state = ConnState::idle; ++ // Keep the connection alive if server supports it ++ // Else close the connection ++ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : " ++ << self->parser->keep_alive(); ++ if (!self->parser->keep_alive()) ++ { ++ // Abort the connection since server is not keep-alive enabled ++ self->state = ConnState::abortConnection; ++ } ++ // Transfer ownership of the response ++ self->parser->release(); ++ ++ self->handleConnState(); ++ }; + parser.emplace(std::piecewise_construct, std::make_tuple()); + parser->body_limit(httpReadBodyLimit); + // Since these are all push style eventing, we are not + // bothered about response body parsing. + // Check only for the response header + parser->skip(true); ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) ++ { ++ boost::beast::http::async_read(*sslConn, buffer, *parser, ++ std::move(respHandler)); ++ } ++ else ++ { ++ boost::beast::http::async_read(conn, buffer, *parser, ++ std::move(respHandler)); ++ } ++ } ++ void doClose() ++ { ++ state = ConnState::closeInProgress; + +- // Receive the HTTP response +- boost::beast::http::async_read( +- conn, buffer, *parser, +- [self(shared_from_this())](const boost::beast::error_code& ec, +- const std::size_t& bytesTransferred) { ++ // Set the timeout on the tcp stream socket for the async operation ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) ++ { ++ sslConn->async_shutdown([self = shared_from_this()]( ++ const boost::system::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "recvMessage() failed: " +- << ec.message(); +- self->state = ConnState::recvFailed; +- self->handleConnState(); +- return; ++ // Many https server closes connection abruptly ++ // i.e witnout close_notify. More details are at ++ // https://github.com/boostorg/beast/issues/824 ++ if (ec == boost::asio::ssl::error::stream_truncated) ++ { ++ BMCWEB_LOG_INFO << "doClose(): Connection " ++ "closed by server. "; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "doClose() failed: " ++ << ec.message(); ++ } + } +- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " +- << bytesTransferred; +- BMCWEB_LOG_DEBUG << "recvMessage() data: " +- << self->parser->get(); +- +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- if (!self->requestDataQueue.empty()) ++ else + { +- self->requestDataQueue.pop_front(); ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; + } +- self->state = ConnState::idle; ++ self->conn.close(); + +- // Keep the connection alive if server supports it +- // Else close the connection +- BMCWEB_LOG_DEBUG << "recvMessage() keepalive : " +- << self->parser->keep_alive(); +- if (!self->parser->keep_alive()) ++ if ((self->state != ConnState::suspended) && ++ (self->state != ConnState::terminated)) + { +- // Abort the connection since server is not keep-alive +- // enabled +- self->state = ConnState::abortConnection; ++ self->state = ConnState::closed; ++ self->handleConnState(); + } +- // Transfer ownership of the response +- self->parser->release(); +- +- self->handleConnState(); + }); +- } +- +- void doClose() +- { +- state = ConnState::closeInProgress; +- boost::beast::error_code ec; +- conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); +- conn.close(); +- +- // not_connected happens sometimes so don't bother reporting it. +- if (ec && ec != boost::beast::errc::not_connected) +- { +- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); +- return; + } +- BMCWEB_LOG_DEBUG << "Connection closed gracefully"; +- if ((state != ConnState::suspended) && (state != ConnState::terminated)) ++ else + { +- state = ConnState::closed; +- handleConnState(); ++ boost::beast::error_code ec; ++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ++ ec); ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "doClose() failed: " << ec.message(); ++ } ++ else ++ { ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; ++ } ++ conn.close(); ++ ++ if ((state != ConnState::suspended) && ++ (state != ConnState::terminated)) ++ { ++ state = ConnState::closed; ++ handleConnState(); ++ } + } + } + +@@ -302,6 +389,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + { + case ConnState::resolveInProgress: + case ConnState::connectInProgress: ++ case ConnState::handshakeInProgress: + case ConnState::sendInProgress: + case ConnState::recvInProgress: + case ConnState::closeInProgress: +@@ -333,6 +421,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } + case ConnState::resolveFailed: + case ConnState::connectFailed: ++ case ConnState::handshakeFailed: + case ConnState::sendFailed: + case ConnState::recvFailed: + case ConnState::retry: +@@ -371,7 +460,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + public: + explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, + const std::string& destIP, const std::string& destPort, +- const std::string& destUri) : ++ const std::string& destUri, ++ const std::string& uriProto) : + conn(ioc), + timer(ioc), req(boost::beast::http::verb::post, destUri, 11), + state(ConnState::initialized), subId(id), host(destIP), port(destPort), +@@ -384,8 +474,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + req.keep_alive(true); + + requestDataQueue.set_capacity(maxRequestQueueSize); ++ if (uriProto == "https") ++ { ++ sslConn.emplace(conn, ctx); ++ } + } +- + void sendData(const std::string& data) + { + if ((state == ConnState::suspended) || (state == ConnState::terminated)) +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index bffa68f..1e6f496 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -387,7 +387,7 @@ class Subscription + { + conn = std::make_shared<crow::HttpClient>( + crow::connections::systemBus->get_io_context(), id, host, port, +- path); ++ path, uriProto); + } + + Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) : +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch new file mode 100644 index 000000000..0d31fbc72 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch @@ -0,0 +1,477 @@ +From e93a6a02b0fba3371144d474422fadacc3f25fde Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Fri, 12 Mar 2021 18:53:25 +0000 +Subject: [PATCH 4/6] Add Server-Sent-Events support + +Server-Sent Events is a standard describing how servers can +initiate data transmission towards clients once an initial +client connection has been established. Unlike websockets +(which are bidirectional), Server-Sent Events are +unidirectional and commonly used to send message updates or +continuous data streams to a browser client. + +This is base patch for adding Server-Sent events support to +bmcweb. Redfish eventservice SSE style subscription uses +this and will be loaded on top of this commit. + +Tested: + - Tested using follow-up patch on top which adds + support for Redfish EventService SSE style subscription + and observed events are getting sent periodically. + +Change-Id: I36956565cbba30c2007852c9471f477f6d1736e9 +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + http/http_connection.hpp | 14 +- + http/http_response.hpp | 7 +- + http/routing.hpp | 70 ++++++++++ + http/server_sent_event.hpp | 279 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 364 insertions(+), 6 deletions(-) + create mode 100644 http/server_sent_event.hpp + +diff --git a/http/http_connection.hpp b/http/http_connection.hpp +index 4482f8d..2c8bf40 100644 +--- a/http/http_connection.hpp ++++ b/http/http_connection.hpp +@@ -326,7 +326,7 @@ class Connection : + BMCWEB_LOG_INFO << "Request: " + << " " << this << " HTTP/" << req->version() / 10 << "." + << req->version() % 10 << ' ' << req->methodString() +- << " " << req->target() << " " << req->ipAddress; ++ << " " << req->url << " " << req->ipAddress; + + needToCallAfterHandlers = false; + +@@ -345,11 +345,15 @@ class Connection : + boost::asio::post(self->adaptor.get_executor(), + [self] { self->completeRequest(); }); + }; +- if (req->isUpgrade() && +- boost::iequals( +- req->getHeaderValue(boost::beast::http::field::upgrade), +- "websocket")) ++ ++ if ((req->isUpgrade() && ++ boost::iequals(req->getHeaderValue( ++ boost::beast::http::field::upgrade), ++ "websocket")) || ++ (req->url == "/sse")) + { ++ BMCWEB_LOG_DEBUG << "Request: " << this ++ << " is getting upgraded"; + handler->handleUpgrade(*req, res, std::move(adaptor)); + // delete lambda with self shared_ptr + // to enable connection destruction +diff --git a/http/http_response.hpp b/http/http_response.hpp +index cd00ec8..ffd6dda 100644 +--- a/http/http_response.hpp ++++ b/http/http_response.hpp +@@ -13,10 +13,15 @@ namespace crow + template <typename Adaptor, typename Handler> + class Connection; + ++template <typename Adaptor> ++class SseConnectionImpl; ++ + struct Response + { + template <typename Adaptor, typename Handler> + friend class crow::Connection; ++ template <typename Adaptor> ++ friend class crow::SseConnectionImpl; + using response_type = + boost::beast::http::response<boost::beast::http::string_body>; + +@@ -136,8 +141,8 @@ struct Response + + private: + bool completed{}; +- std::function<void()> completeRequestHandler; + std::function<bool()> isAliveHelper; ++ std::function<void()> completeRequestHandler; + + // In case of a JSON object, set the Content-Type header + void jsonMode() +diff --git a/http/routing.hpp b/http/routing.hpp +index 65c7b70..0824939 100644 +--- a/http/routing.hpp ++++ b/http/routing.hpp +@@ -6,6 +6,7 @@ + #include "http_response.hpp" + #include "logging.hpp" + #include "privileges.hpp" ++#include "server_sent_event.hpp" + #include "sessions.hpp" + #include "utility.hpp" + #include "websocket.hpp" +@@ -390,6 +391,67 @@ class WebSocketRule : public BaseRule + std::function<void(crow::websocket::Connection&)> errorHandler; + }; + ++class SseSocketRule : public BaseRule ++{ ++ using self_t = SseSocketRule; ++ ++ public: ++ SseSocketRule(const std::string& ruleIn) : BaseRule(ruleIn) ++ {} ++ ++ void validate() override ++ {} ++ ++ void handle(const Request&, Response& res, const RoutingParams&) override ++ { ++ res.result(boost::beast::http::status::not_found); ++ res.end(); ++ } ++ ++ void handleUpgrade(const Request& req, Response&, ++ boost::asio::ip::tcp::socket&& adaptor) override ++ { ++ std::shared_ptr<crow::SseConnectionImpl<boost::asio::ip::tcp::socket>> ++ myConnection = std::make_shared< ++ crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>( ++ req, std::move(adaptor), openHandler, closeHandler); ++ myConnection->start(); ++ } ++#ifdef BMCWEB_ENABLE_SSL ++ void handleUpgrade(const Request& req, Response&, ++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& ++ adaptor) override ++ { ++ std::shared_ptr<crow::SseConnectionImpl< ++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>> ++ myConnection = std::make_shared<crow::SseConnectionImpl< ++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>( ++ req, std::move(adaptor), openHandler, closeHandler); ++ myConnection->start(); ++ } ++#endif ++ ++ template <typename Func> ++ self_t& onopen(Func f) ++ { ++ openHandler = f; ++ return *this; ++ } ++ ++ template <typename Func> ++ self_t& onclose(Func f) ++ { ++ closeHandler = f; ++ return *this; ++ } ++ ++ private: ++ std::function<void(std::shared_ptr<crow::SseConnection>&, ++ const crow::Request&, crow::Response&)> ++ openHandler; ++ std::function<void(std::shared_ptr<crow::SseConnection>&)> closeHandler; ++}; ++ + template <typename T> + struct RuleParameterTraits + { +@@ -402,6 +464,14 @@ struct RuleParameterTraits + return *p; + } + ++ SseSocketRule& serverSentEvent() ++ { ++ self_t* self = static_cast<self_t*>(this); ++ SseSocketRule* p = new SseSocketRule(self->rule); ++ self->ruleToUpgrade.reset(p); ++ return *p; ++ } ++ + self_t& name(const std::string_view name) noexcept + { + self_t* self = static_cast<self_t*>(this); +diff --git a/http/server_sent_event.hpp b/http/server_sent_event.hpp +new file mode 100644 +index 0000000..41d18ed +--- /dev/null ++++ b/http/server_sent_event.hpp +@@ -0,0 +1,279 @@ ++#pragma once ++#include "http_request.hpp" ++ ++#include <boost/algorithm/string/predicate.hpp> ++#include <boost/asio/buffer.hpp> ++#include <boost/beast/http/buffer_body.hpp> ++#include <boost/beast/websocket.hpp> ++ ++#include <array> ++#include <functional> ++ ++#ifdef BMCWEB_ENABLE_SSL ++#include <boost/beast/websocket/ssl.hpp> ++#endif ++ ++namespace crow ++{ ++ ++struct SseConnection : std::enable_shared_from_this<SseConnection> ++{ ++ public: ++ SseConnection(const crow::Request& reqIn) : req(reqIn) ++ {} ++ virtual ~SseConnection() = default; ++ ++ virtual boost::asio::io_context& getIoContext() = 0; ++ virtual void sendSSEHeader() = 0; ++ virtual void completeRequest() = 0; ++ virtual void close(const std::string_view msg = "quit") = 0; ++ virtual void sendEvent(const std::string_view id, ++ const std::string_view msg) = 0; ++ ++ crow::Request req; ++ crow::Response res; ++}; ++ ++template <typename Adaptor> ++class SseConnectionImpl : public SseConnection ++{ ++ public: ++ SseConnectionImpl( ++ const crow::Request& reqIn, Adaptor adaptorIn, ++ std::function<void(std::shared_ptr<SseConnection>&, ++ const crow::Request&, crow::Response&)> ++ openHandler, ++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler) : ++ SseConnection(reqIn), ++ adaptor(std::move(adaptorIn)), openHandler(std::move(openHandler)), ++ closeHandler(std::move(closeHandler)) ++ { ++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE constructor " << this; ++ } ++ ++ ~SseConnectionImpl() override ++ { ++ res.completeRequestHandler = nullptr; ++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE destructor " << this; ++ } ++ ++ boost::asio::io_context& getIoContext() override ++ { ++ return static_cast<boost::asio::io_context&>( ++ adaptor.get_executor().context()); ++ } ++ ++ void start() ++ { ++ // Register for completion callback. ++ res.completeRequestHandler = [this, self(shared_from_this())] { ++ boost::asio::post(this->adaptor.get_executor(), ++ [self] { self->completeRequest(); }); ++ }; ++ ++ if (openHandler) ++ { ++ std::shared_ptr<SseConnection> self = this->shared_from_this(); ++ openHandler(self, req, res); ++ } ++ } ++ ++ void close(const std::string_view msg) override ++ { ++ BMCWEB_LOG_DEBUG << "Closing SSE connection " << this << " - " << msg; ++ boost::beast::get_lowest_layer(adaptor).close(); ++ ++ // send notification to handler for cleanup ++ if (closeHandler) ++ { ++ std::shared_ptr<SseConnection> self = this->shared_from_this(); ++ closeHandler(self); ++ } ++ } ++ ++ void sendSSEHeader() override ++ { ++ BMCWEB_LOG_DEBUG << "Starting SSE connection"; ++ using BodyType = boost::beast::http::buffer_body; ++ auto response = ++ std::make_shared<boost::beast::http::response<BodyType>>( ++ boost::beast::http::status::ok, 11); ++ auto serializer = ++ std::make_shared<boost::beast::http::response_serializer<BodyType>>( ++ *response); ++ ++ response->set(boost::beast::http::field::server, "bmcweb"); ++ response->set(boost::beast::http::field::content_type, ++ "text/event-stream"); ++ response->body().data = nullptr; ++ response->body().size = 0; ++ response->body().more = true; ++ ++ boost::beast::http::async_write_header( ++ adaptor, *serializer, ++ [this, self(shared_from_this()), response, serializer]( ++ const boost::beast::error_code& ec, const std::size_t&) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Error sending header" << ec; ++ close("async_write_header failed"); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "SSE header sent - Connection established"; ++ ++ // SSE stream header sent, So lets setup monitor. ++ // Any read data on this stream will be error in case of SSE. ++ setupRead(); ++ }); ++ } ++ ++ void setupRead() ++ { ++ adaptor.async_read_some( ++ outputBuffer.prepare(outputBuffer.capacity() - outputBuffer.size()), ++ [this](const boost::system::error_code& ec, std::size_t bytesRead) { ++ BMCWEB_LOG_DEBUG << "async_read_some: Read " << bytesRead ++ << " bytes"; ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "Read error: " << ec; ++ } ++ outputBuffer.commit(bytesRead); ++ outputBuffer.consume(bytesRead); ++ ++ // After establishing SSE stream, Reading data on this ++ // stream means client is disobeys the SSE protocol. ++ // Read the data to avoid buffer attacks and close connection. ++ close("Close SSE connection"); ++ return; ++ }); ++ } ++ ++ void doWrite() ++ { ++ if (doingWrite) ++ { ++ return; ++ } ++ if (inputBuffer.size() == 0) ++ { ++ BMCWEB_LOG_DEBUG << "inputBuffer is empty... Bailing out"; ++ return; ++ } ++ doingWrite = true; ++ ++ adaptor.async_write_some( ++ inputBuffer.data(), [this, self(shared_from_this())]( ++ boost::beast::error_code ec, ++ const std::size_t& bytesTransferred) { ++ doingWrite = false; ++ inputBuffer.consume(bytesTransferred); ++ ++ if (ec == boost::asio::error::eof) ++ { ++ BMCWEB_LOG_ERROR << "async_write_some() SSE stream closed"; ++ close("SSE stream closed"); ++ return; ++ } ++ ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "async_write_some() failed: " ++ << ec.message(); ++ close("async_write_some failed"); ++ return; ++ } ++ BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: " ++ << bytesTransferred; ++ ++ doWrite(); ++ }); ++ } ++ ++ void completeRequest() override ++ { ++ BMCWEB_LOG_DEBUG << "SSE completeRequest() handler"; ++ if (res.body().empty() && !res.jsonValue.empty()) ++ { ++ res.addHeader("Content-Type", "application/json"); ++ res.body() = res.jsonValue.dump( ++ 2, ' ', true, nlohmann::json::error_handler_t::replace); ++ } ++ ++ res.preparePayload(); ++ auto serializer = ++ std::make_shared<boost::beast::http::response_serializer< ++ boost::beast::http::string_body>>(*res.stringResponse); ++ ++ boost::beast::http::async_write( ++ adaptor, *serializer, ++ [this, self(shared_from_this()), ++ serializer](const boost::system::error_code& ec, ++ std::size_t bytesTransferred) { ++ BMCWEB_LOG_DEBUG << this << " async_write " << bytesTransferred ++ << " bytes"; ++ if (ec) ++ { ++ BMCWEB_LOG_DEBUG << this << " from async_write failed"; ++ return; ++ } ++ res.clear(); ++ ++ BMCWEB_LOG_DEBUG << this ++ << " Closing SSE connection - Request invalid"; ++ close("Request invalid"); ++ }); ++ ++ // delete lambda with self shared_ptr ++ // to enable connection destruction ++ res.completeRequestHandler = nullptr; ++ } ++ ++ void sendEvent(const std::string_view id, ++ const std::string_view msg) override ++ { ++ if (msg.empty()) ++ { ++ BMCWEB_LOG_DEBUG << "Empty data, bailing out."; ++ return; ++ } ++ ++ std::string rawData; ++ if (!id.empty()) ++ { ++ rawData += "id: "; ++ rawData.append(id.begin(), id.end()); ++ rawData += "\n"; ++ } ++ ++ rawData += "data: "; ++ for (char character : msg) ++ { ++ rawData += character; ++ if (character == '\n') ++ { ++ rawData += "data: "; ++ } ++ } ++ rawData += "\n\n"; ++ ++ boost::asio::buffer_copy(inputBuffer.prepare(rawData.size()), ++ boost::asio::buffer(rawData)); ++ inputBuffer.commit(rawData.size()); ++ ++ doWrite(); ++ } ++ ++ private: ++ Adaptor adaptor; ++ ++ boost::beast::flat_static_buffer<1024U * 8U> outputBuffer; ++ boost::beast::flat_static_buffer<1024U * 64U> inputBuffer; ++ bool doingWrite = false; ++ ++ std::function<void(std::shared_ptr<SseConnection>&, const crow::Request&, ++ crow::Response&)> ++ openHandler; ++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler; ++}; ++} // namespace crow +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch new file mode 100644 index 000000000..02d28833f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch @@ -0,0 +1,627 @@ +From 698d2615c5bc30ab7f89f11ed5659df8bf248ea0 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 16 Mar 2021 15:37:24 +0000 +Subject: [PATCH 5/6] Add SSE style subscription support to eventservice + +This commit adds the SSE style eventservice subscription +style event. Using this, end user can subscribe for +Redfish event logs using GET on SSE usri from +browser. +URI: /redfish/v1/EventService/Subscriptions/SSE + +Tested: + - From Browser did GET on above SSE URI and + generated some Redfish event logs(power cycle) + and saw redfish event logs streaming on browser. + - After SSE registration, Check Subscription collections + and GET on individual subscription and saw desired + response. + - Ran RedfishValidation and its passed. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Change-Id: I7f4b7a34974080739c4ba968ed570489af0474de +--- + http/http_connection.hpp | 2 +- + include/eventservice_sse.hpp | 75 +++++ + .../include/event_service_manager.hpp | 77 ++++- + redfish-core/include/server_sent_events.hpp | 291 ------------------ + redfish-core/lib/event_service.hpp | 4 +- + src/webserver_main.cpp | 2 + + 6 files changed, 149 insertions(+), 302 deletions(-) + create mode 100644 include/eventservice_sse.hpp + delete mode 100644 redfish-core/include/server_sent_events.hpp + +diff --git a/http/http_connection.hpp b/http/http_connection.hpp +index 2c8bf40..1ab776c 100644 +--- a/http/http_connection.hpp ++++ b/http/http_connection.hpp +@@ -350,7 +350,7 @@ class Connection : + boost::iequals(req->getHeaderValue( + boost::beast::http::field::upgrade), + "websocket")) || +- (req->url == "/sse")) ++ (req->url == "/redfish/v1/EventService/Subscriptions/SSE")) + { + BMCWEB_LOG_DEBUG << "Request: " << this + << " is getting upgraded"; +diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp +new file mode 100644 +index 0000000..6c98e6e +--- /dev/null ++++ b/include/eventservice_sse.hpp +@@ -0,0 +1,75 @@ ++#pragma once ++ ++#include <app.hpp> ++#include <event_service_manager.hpp> ++ ++namespace redfish ++{ ++namespace eventservice_sse ++{ ++ ++static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn, ++ const crow::Request& req, crow::Response& res) ++{ ++ if ((EventServiceManager::getInstance().getNumberOfSubscriptions() >= ++ maxNoOfSubscriptions) || ++ EventServiceManager::getInstance().getNumberOfSSESubscriptions() >= ++ maxNoOfSSESubscriptions) ++ { ++ BMCWEB_LOG_ERROR << "Max SSE subscriptions reached"; ++ messages::eventSubscriptionLimitExceeded(res); ++ res.end(); ++ return false; ++ } ++ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size(); ++ ++ std::shared_ptr<redfish::Subscription> subValue = ++ std::make_shared<redfish::Subscription>(std::move(conn)); ++ ++ // GET on this URI means, Its SSE subscriptionType. ++ subValue->subscriptionType = redfish::subscriptionTypeSSE; ++ ++ // TODO: parse $filter query params and fill config. ++ subValue->protocol = "Redfish"; ++ subValue->retryPolicy = "TerminateAfterRetries"; ++ subValue->eventFormatType = "Event"; ++ ++ std::string id = ++ redfish::EventServiceManager::getInstance().addSubscription(subValue, ++ false); ++ if (id.empty()) ++ { ++ messages::internalError(res); ++ res.end(); ++ return false; ++ } ++ ++ return true; ++} ++ ++static void deleteSubscription(std::shared_ptr<crow::SseConnection>& conn) ++{ ++ redfish::EventServiceManager::getInstance().deleteSubscription(conn); ++} ++ ++inline void requestRoutes(App& app) ++{ ++ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/SSE") ++ .privileges({"ConfigureComponents", "ConfigureManager"}) ++ .serverSentEvent() ++ .onopen([](std::shared_ptr<crow::SseConnection>& conn, ++ const crow::Request& req, crow::Response& res) { ++ BMCWEB_LOG_DEBUG << "Connection " << conn << " opened."; ++ if (createSubscription(conn, req, res)) ++ { ++ // All success, lets send SSE haader ++ conn->sendSSEHeader(); ++ } ++ }) ++ .onclose([](std::shared_ptr<crow::SseConnection>& conn) { ++ BMCWEB_LOG_DEBUG << "Connection " << conn << " closed"; ++ deleteSubscription(conn); ++ }); ++} ++} // namespace eventservice_sse ++} // namespace redfish +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 5821e2e..f4d57c2 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -23,13 +23,15 @@ + #include <sys/inotify.h> + + #include <boost/asio/io_context.hpp> ++#include <boost/beast/core/span.hpp> + #include <boost/container/flat_map.hpp> + #include <error_messages.hpp> + #include <http_client.hpp> + #include <random.hpp> +-#include <server_sent_events.hpp> ++#include <server_sent_event.hpp> + #include <utils/json_utils.hpp> + ++#include <algorithm> + #include <cstdlib> + #include <ctime> + #include <fstream> +@@ -46,9 +48,13 @@ using EventServiceConfig = std::tuple<bool, uint32_t, uint32_t>; + static constexpr const char* eventFormatType = "Event"; + static constexpr const char* metricReportFormatType = "MetricReport"; + ++static constexpr const char* subscriptionTypeSSE = "SSE"; + static constexpr const char* eventServiceFile = + "/var/lib/bmcweb/eventservice_config.json"; + ++static constexpr const uint8_t maxNoOfSubscriptions = 20; ++static constexpr const uint8_t maxNoOfSSESubscriptions = 10; ++ + #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES + static std::optional<boost::asio::posix::stream_descriptor> inotifyConn; + static constexpr const char* redfishEventLogDir = "/var/log"; +@@ -391,11 +397,9 @@ class Subscription + path, uriProto); + } + +- Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) : +- eventSeqNum(1) +- { +- sseConn = std::make_shared<crow::ServerSentEvents>(adaptor); +- } ++ Subscription(const std::shared_ptr<crow::SseConnection>& adaptor) : ++ sseConn(adaptor), eventSeqNum(1) ++ {} + + ~Subscription() = default; + +@@ -420,7 +424,7 @@ class Subscription + + if (sseConn != nullptr) + { +- sseConn->sendData(eventSeqNum, msg); ++ sseConn->sendEvent(std::to_string(eventSeqNum), msg); + } + } + +@@ -510,6 +514,7 @@ class Subscription + + this->sendEvent( + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace)); ++ this->eventSeqNum++; + } + #endif + +@@ -565,14 +570,39 @@ class Subscription + return eventSeqNum; + } + ++ void setSubscriptionId(const std::string& id) ++ { ++ BMCWEB_LOG_DEBUG << "Subscription ID: " << id; ++ subId = id; ++ } ++ ++ std::string getSubscriptionId() ++ { ++ return subId; ++ } ++ ++ std::optional<std::string> ++ getSubscriptionId(const std::shared_ptr<crow::SseConnection>& connPtr) ++ { ++ if (sseConn != nullptr && connPtr == sseConn) ++ { ++ BMCWEB_LOG_DEBUG << __FUNCTION__ ++ << " conn matched, subId: " << subId; ++ return subId; ++ } ++ ++ return std::nullopt; ++ } ++ + private: ++ std::shared_ptr<crow::SseConnection> sseConn = nullptr; + uint64_t eventSeqNum; + std::string host; + std::string port; + std::string path; + std::string uriProto; + std::shared_ptr<crow::HttpClient> conn = nullptr; +- std::shared_ptr<crow::ServerSentEvents> sseConn = nullptr; ++ std::string subId; + }; + + static constexpr const bool defaultEnabledState = true; +@@ -963,6 +993,8 @@ class EventServiceManager + subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); + subValue->updateRetryPolicy(); + ++ // Set Subscription ID for back trace ++ subValue->setSubscriptionId(id); + return id; + } + +@@ -987,11 +1019,40 @@ class EventServiceManager + } + } + ++ void deleteSubscription(const std::shared_ptr<crow::SseConnection>& connPtr) ++ { ++ for (const auto& it : this->subscriptionsMap) ++ { ++ std::shared_ptr<Subscription> entry = it.second; ++ if (entry->subscriptionType == subscriptionTypeSSE) ++ { ++ std::optional<std::string> id = ++ entry->getSubscriptionId(connPtr); ++ if (id) ++ { ++ deleteSubscription(*id); ++ return; ++ } ++ } ++ } ++ } ++ + size_t getNumberOfSubscriptions() + { + return subscriptionsMap.size(); + } + ++ size_t getNumberOfSSESubscriptions() const ++ { ++ auto count = std::count_if( ++ subscriptionsMap.begin(), subscriptionsMap.end(), ++ [this](const std::pair<std::string, std::shared_ptr<Subscription>>& ++ entry) { ++ return (entry.second->subscriptionType == subscriptionTypeSSE); ++ }); ++ return static_cast<size_t>(count); ++ } ++ + std::vector<std::string> getAllIDs() + { + std::vector<std::string> idList; +diff --git a/redfish-core/include/server_sent_events.hpp b/redfish-core/include/server_sent_events.hpp +deleted file mode 100644 +index 578fa19..0000000 +--- a/redfish-core/include/server_sent_events.hpp ++++ /dev/null +@@ -1,291 +0,0 @@ +- +-/* +-// Copyright (c) 2020 Intel Corporation +-// +-// Licensed under the Apache License, Version 2.0 (the "License"); +-// you may not use this file except in compliance with the License. +-// You may obtain a copy of the License at +-// +-// http://www.apache.org/licenses/LICENSE-2.0 +-// +-// Unless required by applicable law or agreed to in writing, software +-// distributed under the License is distributed on an "AS IS" BASIS, +-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-// See the License for the specific language governing permissions and +-// limitations under the License. +-*/ +-#pragma once +-#include "node.hpp" +- +-#include <boost/asio/strand.hpp> +-#include <boost/beast/core/span.hpp> +-#include <boost/beast/http/buffer_body.hpp> +-#include <boost/beast/http/message.hpp> +-#include <boost/beast/version.hpp> +- +-#include <cstdlib> +-#include <functional> +-#include <iostream> +-#include <memory> +-#include <queue> +-#include <string> +- +-namespace crow +-{ +- +-static constexpr uint8_t maxReqQueueSize = 50; +- +-enum class SseConnState +-{ +- startInit, +- initInProgress, +- initialized, +- initFailed, +- sendInProgress, +- sendFailed, +- idle, +- suspended, +- closed +-}; +- +-class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents> +-{ +- private: +- std::shared_ptr<boost::beast::tcp_stream> sseConn; +- std::queue<std::pair<uint64_t, std::string>> requestDataQueue; +- std::string outBuffer; +- SseConnState state; +- int retryCount; +- int maxRetryAttempts; +- +- void sendEvent(const std::string& id, const std::string& msg) +- { +- if (msg.empty()) +- { +- BMCWEB_LOG_DEBUG << "Empty data, bailing out."; +- return; +- } +- +- if (state == SseConnState::sendInProgress) +- { +- return; +- } +- state = SseConnState::sendInProgress; +- +- if (!id.empty()) +- { +- outBuffer += "id: "; +- outBuffer.append(id.begin(), id.end()); +- outBuffer += "\n"; +- } +- +- outBuffer += "data: "; +- for (char character : msg) +- { +- outBuffer += character; +- if (character == '\n') +- { +- outBuffer += "data: "; +- } +- } +- outBuffer += "\n\n"; +- +- doWrite(); +- } +- +- void doWrite() +- { +- if (outBuffer.empty()) +- { +- BMCWEB_LOG_DEBUG << "All data sent successfully."; +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- requestDataQueue.pop(); +- state = SseConnState::idle; +- checkQueue(); +- return; +- } +- +- sseConn->async_write_some( +- boost::asio::buffer(outBuffer.data(), outBuffer.size()), +- [self(shared_from_this())]( +- boost::beast::error_code ec, +- [[maybe_unused]] const std::size_t& bytesTransferred) { +- self->outBuffer.erase(0, bytesTransferred); +- +- if (ec == boost::asio::error::eof) +- { +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- self->requestDataQueue.pop(); +- self->state = SseConnState::idle; +- self->checkQueue(); +- return; +- } +- +- if (ec) +- { +- BMCWEB_LOG_ERROR << "async_write_some() failed: " +- << ec.message(); +- self->state = SseConnState::sendFailed; +- self->checkQueue(); +- return; +- } +- BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: " +- << bytesTransferred; +- +- self->doWrite(); +- }); +- } +- +- void startSSE() +- { +- if (state == SseConnState::initInProgress) +- { +- return; +- } +- state = SseConnState::initInProgress; +- +- BMCWEB_LOG_DEBUG << "starting SSE connection "; +- using BodyType = boost::beast::http::buffer_body; +- auto response = +- std::make_shared<boost::beast::http::response<BodyType>>( +- boost::beast::http::status::ok, 11); +- auto serializer = +- std::make_shared<boost::beast::http::response_serializer<BodyType>>( +- *response); +- +- // TODO: Add hostname in http header. +- response->set(boost::beast::http::field::server, "iBMC"); +- response->set(boost::beast::http::field::content_type, +- "text/event-stream"); +- response->body().data = nullptr; +- response->body().size = 0; +- response->body().more = true; +- +- boost::beast::http::async_write_header( +- *sseConn, *serializer, +- [this, response, +- serializer](const boost::beast::error_code& ec, +- [[maybe_unused]] const std::size_t& bytesTransferred) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Error sending header" << ec; +- state = SseConnState::initFailed; +- checkQueue(); +- return; +- } +- +- BMCWEB_LOG_DEBUG << "startSSE Header sent."; +- state = SseConnState::initialized; +- checkQueue(); +- }); +- } +- +- void checkQueue(const bool newRecord = false) +- { +- if (requestDataQueue.empty()) +- { +- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; +- return; +- } +- +- if (retryCount >= maxRetryAttempts) +- { +- BMCWEB_LOG_ERROR << "Maximum number of retries is reached."; +- +- // Clear queue. +- while (!requestDataQueue.empty()) +- { +- requestDataQueue.pop(); +- } +- +- // TODO: Take 'DeliveryRetryPolicy' action. +- // For now, doing 'SuspendRetries' action. +- state = SseConnState::suspended; +- return; +- } +- +- if ((state == SseConnState::initFailed) || +- (state == SseConnState::sendFailed)) +- { +- if (newRecord) +- { +- // We are already running async wait and retry. +- // Since record is added to queue, it gets the +- // turn in FIFO. +- return; +- } +- +- retryCount++; +- // TODO: Perform async wait for retryTimeoutInterval before proceed. +- } +- else +- { +- // reset retry count. +- retryCount = 0; +- } +- +- switch (state) +- { +- case SseConnState::initInProgress: +- case SseConnState::sendInProgress: +- case SseConnState::suspended: +- case SseConnState::startInit: +- case SseConnState::closed: +- // do nothing +- break; +- case SseConnState::initFailed: +- { +- startSSE(); +- break; +- } +- case SseConnState::initialized: +- case SseConnState::idle: +- case SseConnState::sendFailed: +- { +- std::pair<uint64_t, std::string> reqData = +- requestDataQueue.front(); +- sendEvent(std::to_string(reqData.first), reqData.second); +- break; +- } +- } +- +- return; +- } +- +- public: +- ServerSentEvents(const ServerSentEvents&) = delete; +- ServerSentEvents& operator=(const ServerSentEvents&) = delete; +- ServerSentEvents(ServerSentEvents&&) = delete; +- ServerSentEvents& operator=(ServerSentEvents&&) = delete; +- +- ServerSentEvents(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) : +- sseConn(adaptor), state(SseConnState::startInit), retryCount(0), +- maxRetryAttempts(5) +- { +- startSSE(); +- } +- +- ~ServerSentEvents() = default; +- +- void sendData(const uint64_t& id, const std::string& data) +- { +- if (state == SseConnState::suspended) +- { +- return; +- } +- +- if (requestDataQueue.size() <= maxReqQueueSize) +- { +- requestDataQueue.push(std::pair(id, data)); +- checkQueue(true); +- } +- else +- { +- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data."; +- } +- } +-}; +- +-} // namespace crow +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index be6f04d..1875ec9 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -34,8 +34,6 @@ static constexpr const std::array<const char*, 1> supportedResourceTypes = { + "Task"}; + #endif + +-static constexpr const uint8_t maxNoOfSubscriptions = 20; +- + class EventService : public Node + { + public: +@@ -59,6 +57,8 @@ class EventService : public Node + {"@odata.type", "#EventService.v1_5_0.EventService"}, + {"Id", "EventService"}, + {"Name", "Event Service"}, ++ {"ServerSentEventUri", ++ "/redfish/v1/EventService/Subscriptions/SSE"}, + {"Subscriptions", + {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, + {"Actions", +diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp +index 902c32b..c871faa 100644 +--- a/src/webserver_main.cpp ++++ b/src/webserver_main.cpp +@@ -5,6 +5,7 @@ + #include <cors_preflight.hpp> + #include <dbus_monitor.hpp> + #include <dbus_singleton.hpp> ++#include <eventservice_sse.hpp> + #include <hostname_monitor.hpp> + #include <ibm/management_console_rest.hpp> + #include <image_upload.hpp> +@@ -83,6 +84,7 @@ int main(int /*argc*/, char** /*argv*/) + #ifdef BMCWEB_ENABLE_REDFISH + redfish::requestRoutes(app); + redfish::RedfishService redfish(app); ++ redfish::eventservice_sse::requestRoutes(app); + + // Create EventServiceManager instance and initialize Config + redfish::EventServiceManager::getInstance(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch new file mode 100644 index 000000000..4d99b2754 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch @@ -0,0 +1,243 @@ +From 82185c52ae6e27cc1e086654a3b7d10e63ecc783 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 17 Mar 2021 01:16:50 +0000 +Subject: [PATCH 6/6] Add EventService SSE filter support + +This commit implements the Event Service SSE stream +filters support. As per redfish specification: +The SSE streams have these formats: + - Metric report SSE stream + - Event message SSE stream + +To reduce the amount of data, service supports $filter +query parameter in SSE URI. +Below properties support as filter criteria: + - EventFormatType( Event & MetricReport) + - MessageId + - RegistryPrefix + - MetricReportDefinition + +For more details, refer Redfish specification section 13.5.2 + +Tested: + Created SSE stream with different filters and observed + desired events on SSE stream client(browser), some examples + - To get all Redfish events, + URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event) + - To get Redfish events with RegistryPrefix "OpenBMC" + URi: /redfish/v1/EventService/Subscriptions/SSE?$filter=(RegistryPrefix%20eq%20OpenBMC) + - To get only DC power of Events, + URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)%20and%20(MessageId%20eq%20DCPowerOff) + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Change-Id: I55c6f53bb5e57aa1f2d1601f1a16525a33b13bd2 +--- + include/eventservice_sse.hpp | 94 ++++++++++++++++++- + redfish-core/include/error_messages.hpp | 9 ++ + .../include/event_service_manager.hpp | 5 + + redfish-core/lib/event_service.hpp | 4 - + redfish-core/src/error_messages.cpp | 26 +++++ + 5 files changed, 130 insertions(+), 8 deletions(-) + +diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp +index 6c98e6e..ff72c4d 100644 +--- a/include/eventservice_sse.hpp ++++ b/include/eventservice_sse.hpp +@@ -23,16 +23,102 @@ static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn, + } + BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size(); + ++ // EventService SSE supports only "$filter" query param. ++ if (req.urlParams.size() > 1) ++ { ++ messages::invalidQueryFilter(res); ++ res.end(); ++ return false; ++ } ++ std::string eventFormatType; ++ std::string queryFilters; ++ if (req.urlParams.size()) ++ { ++ boost::urls::url_view::params_type::iterator it = ++ req.urlParams.find("$filter"); ++ if (it == req.urlParams.end()) ++ { ++ messages::invalidQueryFilter(res); ++ res.end(); ++ return false; ++ } ++ queryFilters = it->value(); ++ } ++ else ++ { ++ eventFormatType = "Event"; ++ } ++ ++ std::vector<std::string> msgIds; ++ std::vector<std::string> regPrefixes; ++ std::vector<std::string> mrdsArray; ++ if (!queryFilters.empty()) ++ { ++ // Reading from query params. ++ bool status = readSSEQueryParams(queryFilters, eventFormatType, msgIds, ++ regPrefixes, mrdsArray); ++ if (!status) ++ { ++ messages::invalidObject(res, queryFilters); ++ res.end(); ++ return false; ++ } ++ ++ // RegsitryPrefix and messageIds are mutuly exclusive as per redfish ++ // specification. ++ if (regPrefixes.size() && msgIds.size()) ++ { ++ messages::mutualExclusiveProperties(res, "RegistryPrefix", ++ "MessageId"); ++ res.end(); ++ return false; ++ } ++ ++ if (!eventFormatType.empty()) ++ { ++ if (std::find(supportedEvtFormatTypes.begin(), ++ supportedEvtFormatTypes.end(), ++ eventFormatType) == supportedEvtFormatTypes.end()) ++ { ++ messages::propertyValueNotInList(res, eventFormatType, ++ "EventFormatType"); ++ res.end(); ++ return false; ++ } ++ } ++ else ++ { ++ // If nothing specified, using default "Event" ++ eventFormatType = "Event"; ++ } ++ ++ if (!regPrefixes.empty()) ++ { ++ for (const std::string& it : regPrefixes) ++ { ++ if (std::find(supportedRegPrefixes.begin(), ++ supportedRegPrefixes.end(), ++ it) == supportedRegPrefixes.end()) ++ { ++ messages::propertyValueNotInList(res, it, "RegistryPrefix"); ++ res.end(); ++ return false; ++ } ++ } ++ } ++ } ++ + std::shared_ptr<redfish::Subscription> subValue = + std::make_shared<redfish::Subscription>(std::move(conn)); + + // GET on this URI means, Its SSE subscriptionType. +- subValue->subscriptionType = redfish::subscriptionTypeSSE; +- +- // TODO: parse $filter query params and fill config. ++ subValue->subscriptionType = subscriptionTypeSSE; + subValue->protocol = "Redfish"; + subValue->retryPolicy = "TerminateAfterRetries"; +- subValue->eventFormatType = "Event"; ++ subValue->eventFormatType = eventFormatType; ++ subValue->registryMsgIds = msgIds; ++ subValue->registryPrefixes = regPrefixes; ++ subValue->metricReportDefinitions = mrdsArray; + + std::string id = + redfish::EventServiceManager::getInstance().addSubscription(subValue, +diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp +index 7dfdc80..922dae9 100644 +--- a/redfish-core/include/error_messages.hpp ++++ b/redfish-core/include/error_messages.hpp +@@ -959,6 +959,15 @@ nlohmann::json mutualExclusiveProperties(const std::string& arg1, + void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, + const std::string& arg2); + ++/** ++ * @brief Formats InvalidQueryFilter message into JSON ++ * Message body: "The requested URL contains the invalid query filters" ++ * ++ * @returns Message InvalidQueryFilter formatted to JSON */ ++nlohmann::json invalidQueryFilter(); ++ ++void invalidQueryFilter(crow::Response& res); ++ + } // namespace messages + + } // namespace redfish +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index f4d57c2..567fb9c 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -55,6 +55,11 @@ static constexpr const char* eventServiceFile = + static constexpr const uint8_t maxNoOfSubscriptions = 20; + static constexpr const uint8_t maxNoOfSSESubscriptions = 10; + ++static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { ++ eventFormatType, metricReportFormatType}; ++static constexpr const std::array<const char*, 3> supportedRegPrefixes = { ++ "Base", "OpenBMC", "Task"}; ++ + #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES + static std::optional<boost::asio::posix::stream_descriptor> inotifyConn; + static constexpr const char* redfishEventLogDir = "/var/log"; +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index 1875ec9..4d1ac9f 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -19,10 +19,6 @@ + namespace redfish + { + +-static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { +- eventFormatType, metricReportFormatType}; +-static constexpr const std::array<const char*, 3> supportedRegPrefixes = { +- "Base", "OpenBMC", "Task"}; + static constexpr const std::array<const char*, 3> supportedRetryPolicies = { + "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; + +diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp +index 7059a38..1e3ef2f 100644 +--- a/redfish-core/src/error_messages.cpp ++++ b/redfish-core/src/error_messages.cpp +@@ -2147,6 +2147,32 @@ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, + addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2)); + } + ++/** ++ * @internal ++ * @brief Formats InvalidQueryFilter into JSON ++ * ++ * See header file for more information ++ * @endinternal ++ */ ++nlohmann::json invalidQueryFilter() ++{ ++ return nlohmann::json{ ++ {"@odata.type", "#Message.v1_0_0.Message"}, ++ {"MessageId", "Base.1.5.0.InvalidQueryFilter"}, ++ {"Message", "The requested url contains the invalid query filter."}, ++ {"MessageArgs", nlohmann::json::array()}, ++ {"Severity", "Warning"}, ++ {"Resolution", ++ "Ensure the correct query filter is specified in requested url " ++ "and resubmit the request."}}; ++} ++ ++void invalidQueryFilter(crow::Response& res) ++{ ++ res.result(boost::beast::http::status::bad_request); ++ addMessageToErrorJson(res.jsonValue, invalidQueryFilter()); ++} ++ + } // namespace messages + + } // namespace redfish +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README new file mode 100644 index 000000000..3954e89c1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README @@ -0,0 +1,19 @@ +Eventservice specific patches: Temporary pulling down +the upstream patches. These will be remove as soon as +thee gets merged upstream. + +Upstream revision information: + - EventService : Fix retry handling for http-client + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/40731/18 + + - EventService: https client support + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31735/38 + + - Add Server-Sent-Events support + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41258/5 + + - Add SSE style subscription support to eventservice + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41319/5 + + - Add EventService SSE filter support + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41349/2 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch new file mode 100644 index 000000000..03feec633 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch @@ -0,0 +1,369 @@ +From b6ccf463b4cfb8df4a904f06c5f4852029a96c50 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Tue, 15 Dec 2020 12:28:17 +0100 +Subject: [PATCH 3/4] Add support for MetricDefinition scheme + +Added MetricDefinition node to Redfish code. Now user is able +to list all available metrics in OpenBMC that are supported +by Telemetry service. Metrics are grouped by following +categories: temperature, power, voltage, current, fan_tach, +fan_pwm, utilization. + +Tested: + - MetricDefinitions response is filled with existing sensors, + it works with and without Telemetry service + - Validated a presence of MetricDefinition members and it + attributes + - Succesfully passed RedfishServiceValidator.py using + witherspoon image on QEMU + +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00 +--- + redfish-core/include/redfish.hpp | 3 + + .../include/utils/telemetry_utils.hpp | 2 + + redfish-core/lib/metric_definition.hpp | 283 ++++++++++++++++++ + redfish-core/lib/telemetry_service.hpp | 2 + + 4 files changed, 290 insertions(+) + create mode 100644 redfish-core/lib/metric_definition.hpp + +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index aad28ac..dfcb8cd 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -25,6 +25,7 @@ + #include "../lib/managers.hpp" + #include "../lib/memory.hpp" + #include "../lib/message_registries.hpp" ++#include "../lib/metric_definition.hpp" + #include "../lib/metric_report.hpp" + #include "../lib/metric_report_definition.hpp" + #include "../lib/network_protocol.hpp" +@@ -215,6 +216,8 @@ class RedfishService + nodes.emplace_back(std::make_unique<HypervisorResetActionInfo>(app)); + + nodes.emplace_back(std::make_unique<TelemetryService>(app)); ++ nodes.emplace_back(std::make_unique<MetricDefinitionCollection>(app)); ++ nodes.emplace_back(std::make_unique<MetricDefinition>(app)); + nodes.emplace_back( + std::make_unique<MetricReportDefinitionCollection>(app)); + nodes.emplace_back(std::make_unique<MetricReportDefinition>(app)); +diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp +index 0a3af5f..54b5133 100644 +--- a/redfish-core/include/utils/telemetry_utils.hpp ++++ b/redfish-core/include/utils/telemetry_utils.hpp +@@ -10,6 +10,8 @@ namespace telemetry + + constexpr const char* service = "xyz.openbmc_project.Telemetry"; + constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report"; ++constexpr const char* metricDefinitionUri = ++ "/redfish/v1/TelemetryService/MetricDefinitions/"; + constexpr const char* metricReportDefinitionUri = + "/redfish/v1/TelemetryService/MetricReportDefinitions/"; + constexpr const char* metricReportUri = +diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp +new file mode 100644 +index 0000000..f9c7779 +--- /dev/null ++++ b/redfish-core/lib/metric_definition.hpp +@@ -0,0 +1,283 @@ ++#pragma once ++ ++#include "node.hpp" ++#include "sensors.hpp" ++#include "utils/telemetry_utils.hpp" ++ ++namespace redfish ++{ ++ ++namespace utils ++{ ++ ++template <typename F> ++inline void getChassisNames(F&& cb, const std::shared_ptr<AsyncResp>& asyncResp) ++{ ++ const std::array<const char*, 2> interfaces = { ++ "xyz.openbmc_project.Inventory.Item.Board", ++ "xyz.openbmc_project.Inventory.Item.Chassis"}; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp, ++ callback = std::move(cb)](const boost::system::error_code ec, ++ std::vector<std::string>& chassis) { ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_DEBUG << "DBus call error: " << ec.value(); ++ return; ++ } ++ ++ std::vector<std::string> chassisNames; ++ chassisNames.reserve(chassis.size()); ++ for (const auto& path : chassis) ++ { ++ sdbusplus::message::object_path dbusPath = path; ++ std::string name = dbusPath.filename(); ++ if (name.empty()) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "Invalid chassis: " << dbusPath.str; ++ return; ++ } ++ chassisNames.emplace_back(std::move(name)); ++ } ++ ++ callback(chassisNames); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", ++ "/xyz/openbmc_project/inventory", 0, interfaces); ++} ++} // namespace utils ++ ++namespace telemetry ++{ ++ ++class MetricDefinitionCollectionReduce ++{ ++ public: ++ MetricDefinitionCollectionReduce( ++ const std::shared_ptr<AsyncResp>& asyncResp) : ++ asyncResp{asyncResp} ++ {} ++ ++ ~MetricDefinitionCollectionReduce() ++ { ++ if (asyncResp->res.result() != boost::beast::http::status::ok) ++ { ++ return; ++ } ++ ++ nlohmann::json& members = asyncResp->res.jsonValue["Members"]; ++ members = nlohmann::json::array(); ++ ++ for (const std::string& type : dbusTypes) ++ { ++ members.push_back( ++ {{"@odata.id", telemetry::metricDefinitionUri + type}}); ++ } ++ asyncResp->res.jsonValue["Members@odata.count"] = members.size(); ++ } ++ ++ void insert(const boost::container::flat_map<std::string, std::string>& el) ++ { ++ for (const auto& [_, dbusSensor] : el) ++ { ++ sdbusplus::message::object_path path(dbusSensor); ++ sdbusplus::message::object_path parentPath = path.parent_path(); ++ std::string type = parentPath.filename(); ++ if (type.empty()) ++ { ++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = " ++ << dbusSensor; ++ continue; ++ } ++ ++ dbusTypes.insert(std::move(type)); ++ } ++ } ++ ++ private: ++ const std::shared_ptr<AsyncResp> asyncResp; ++ boost::container::flat_set<std::string> dbusTypes; ++}; ++ ++class MetricDefinitionReduce ++{ ++ public: ++ MetricDefinitionReduce(const std::shared_ptr<AsyncResp>& asyncResp, ++ const std::string& id) : ++ id(id), ++ pattern{'/' + id + '/'}, asyncResp{asyncResp} ++ {} ++ ~MetricDefinitionReduce() ++ { ++ if (asyncResp->res.result() != boost::beast::http::status::ok) ++ { ++ return; ++ } ++ if (redfishSensors.empty()) ++ { ++ messages::resourceNotFound(asyncResp->res, "MetricDefinition", id); ++ return; ++ } ++ ++ asyncResp->res.jsonValue["MetricProperties"] = redfishSensors; ++ asyncResp->res.jsonValue["Id"] = id; ++ asyncResp->res.jsonValue["Name"] = id; ++ asyncResp->res.jsonValue["@odata.id"] = ++ telemetry::metricDefinitionUri + id; ++ asyncResp->res.jsonValue["@odata.type"] = ++ "#MetricDefinition.v1_0_3.MetricDefinition"; ++ asyncResp->res.jsonValue["MetricDataType"] = "Decimal"; ++ asyncResp->res.jsonValue["MetricType"] = "Numeric"; ++ asyncResp->res.jsonValue["IsLinear"] = true; ++ asyncResp->res.jsonValue["Units"] = sensors::toReadingUnits(id); ++ } ++ ++ void insert(const boost::container::flat_map<std::string, std::string>& el) ++ { ++ for (const auto& [redfishSensor, dbusSensor] : el) ++ { ++ if (dbusSensor.find(pattern) != std::string::npos) ++ { ++ redfishSensors.push_back(redfishSensor); ++ } ++ } ++ } ++ ++ private: ++ const std::string id; ++ const std::string pattern; ++ const std::shared_ptr<AsyncResp> asyncResp; ++ std::vector<std::string> redfishSensors; ++}; ++} // namespace telemetry ++ ++class MetricDefinitionCollection : public Node ++{ ++ public: ++ MetricDefinitionCollection(App& app) : ++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions/") ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) override ++ { ++ res.jsonValue["@odata.type"] = "#MetricDefinitionCollection." ++ "MetricDefinitionCollection"; ++ res.jsonValue["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricDefinitions"; ++ res.jsonValue["Name"] = "Metric Definition Collection"; ++ res.jsonValue["Members"] = nlohmann::json::array(); ++ res.jsonValue["Members@odata.count"] = 0; ++ ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ utils::getChassisNames( ++ [asyncResp](const std::vector<std::string>& chassisNames) { ++ auto collectionReduce = std::make_shared< ++ telemetry::MetricDefinitionCollectionReduce>(asyncResp); ++ for (const std::string& chassisName : chassisNames) ++ { ++ for (const auto& [sensorNode, _] : sensors::dbus::paths) ++ { ++ BMCWEB_LOG_INFO << "Chassis: " << chassisName ++ << " sensor: " << sensorNode; ++ retrieveUriToDbusMap( ++ chassisName, sensorNode.data(), ++ [asyncResp, collectionReduce]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map< ++ std::string, std::string>& uriToDbus) { ++ if (status != boost::beast::http::status::ok) ++ { ++ BMCWEB_LOG_ERROR ++ << "Failed to retrieve URI to dbus " ++ "sensors map with err " ++ << static_cast<unsigned>(status); ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ collectionReduce->insert(uriToDbus); ++ }); ++ } ++ } ++ }, ++ asyncResp); ++ } ++}; ++ ++class MetricDefinition : public Node ++{ ++ public: ++ MetricDefinition(App& app) : ++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions/<str>/", ++ std::string()) ++ { ++ entityPrivileges = { ++ {boost::beast::http::verb::get, {{"Login"}}}, ++ {boost::beast::http::verb::head, {{"Login"}}}, ++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::put, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, ++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; ++ } ++ ++ private: ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>& params) override ++ { ++ auto asyncResp = std::make_shared<AsyncResp>(res); ++ if (params.size() != 1) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::string& id = params[0]; ++ utils::getChassisNames( ++ [asyncResp, id](const std::vector<std::string>& chassisNames) { ++ auto definitionGather = ++ std::make_shared<telemetry::MetricDefinitionReduce>( ++ asyncResp, id); ++ for (const std::string& chassisName : chassisNames) ++ { ++ for (const auto& [sensorNode, dbusPaths] : ++ sensors::dbus::paths) ++ { ++ retrieveUriToDbusMap( ++ chassisName, sensorNode.data(), ++ [asyncResp, definitionGather]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map< ++ std::string, std::string>& uriToDbus) { ++ if (status != boost::beast::http::status::ok) ++ { ++ BMCWEB_LOG_ERROR ++ << "Failed to retrieve URI to dbus " ++ "sensors map with err " ++ << static_cast<unsigned>(status); ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ definitionGather->insert(uriToDbus); ++ }); ++ } ++ } ++ }, ++ asyncResp); ++ } ++}; ++ ++} // namespace redfish +diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp +index 61ca891..a8c8b03 100644 +--- a/redfish-core/lib/telemetry_service.hpp ++++ b/redfish-core/lib/telemetry_service.hpp +@@ -32,6 +32,8 @@ class TelemetryService : public Node + res.jsonValue["Id"] = "TelemetryService"; + res.jsonValue["Name"] = "Telemetry Service"; + ++ res.jsonValue["MetricDefinitions"]["@odata.id"] = ++ "/redfish/v1/TelemetryService/MetricDefinitions"; + res.jsonValue["MetricReportDefinitions"]["@odata.id"] = + "/redfish/v1/TelemetryService/MetricReportDefinitions"; + res.jsonValue["MetricReports"]["@odata.id"] = +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch new file mode 100644 index 000000000..f2ebce6e3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch @@ -0,0 +1,295 @@ +From efcd128a3d66fce33200fd4211ba5abf13a81375 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +Date: Tue, 15 Dec 2020 12:30:31 +0100 +Subject: [PATCH 4/4] Sync Telmetry service with EventService + +Synced the latest changes in Telemetry service with Event Service +code. Now assembling MetricReport is covered in single place in +code. Updated method of fetching Readings from Telemetry by +Event Service. Using ReportUpdate signal is no longer +supported. Now Event Service monitors for PropertiesChanged signal +from /xyz/openbmc_project/Telemetry/Reports path. + +Tested: + - Verified that EventListener received MetricReport response from + Event Service in insecure http push style eventing mode + +Change-Id: I2fc1841a6c9259a8bff30b34bddc0d4aabd41912 +Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +--- + .../include/event_service_manager.hpp | 156 ++++++------------ + redfish-core/lib/metric_report.hpp | 28 ++-- + 2 files changed, 69 insertions(+), 115 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 148c703..27e41e3 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -14,6 +14,7 @@ + // limitations under the License. + */ + #pragma once ++#include "metric_report.hpp" + #include "node.hpp" + #include "registries.hpp" + #include "registries/base_message_registry.hpp" +@@ -512,47 +513,32 @@ class Subscription + } + #endif + +- void filterAndSendReports(const std::string& id2, +- const std::string& readingsTs, +- const ReadingsObjType& readings) ++ void filterAndSendReports( ++ const std::string& id, ++ const std::variant<telemetry::TimestampReadings>& var) + { +- std::string metricReportDef = +- "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id2; ++ std::string mrdUri = telemetry::metricReportDefinitionUri + id; + + // Empty list means no filter. Send everything. + if (metricReportDefinitions.size()) + { + if (std::find(metricReportDefinitions.begin(), + metricReportDefinitions.end(), +- metricReportDef) == metricReportDefinitions.end()) ++ mrdUri) == metricReportDefinitions.end()) + { + return; + } + } + +- nlohmann::json metricValuesArray = nlohmann::json::array(); +- for (const auto& it : readings) ++ nlohmann::json msg; ++ if (!telemetry::fillReport(msg, id, var)) + { +- metricValuesArray.push_back({}); +- nlohmann::json& entry = metricValuesArray.back(); +- +- auto& [id, property, value, timestamp] = it; +- +- entry = {{"MetricId", id}, +- {"MetricProperty", property}, +- {"MetricValue", std::to_string(value)}, +- {"Timestamp", crow::utility::getDateTime(timestamp)}}; ++ BMCWEB_LOG_ERROR << "Failed to fill the MetricReport for DBus " ++ "Report with id " ++ << id; ++ return; + } + +- nlohmann::json msg = { +- {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id}, +- {"@odata.type", "#MetricReport.v1_3_0.MetricReport"}, +- {"Id", id2}, +- {"Name", id2}, +- {"Timestamp", readingsTs}, +- {"MetricReportDefinition", {{"@odata.id", metricReportDef}}}, +- {"MetricValues", metricValuesArray}}; +- + this->sendEvent( + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace)); + } +@@ -1348,75 +1334,6 @@ class EventServiceManager + } + + #endif +- +- void getMetricReading(const std::string& service, +- const std::string& objPath, const std::string& intf) +- { +- std::size_t found = objPath.find_last_of('/'); +- if (found == std::string::npos) +- { +- BMCWEB_LOG_DEBUG << "Invalid objPath received"; +- return; +- } +- +- std::string idStr = objPath.substr(found + 1); +- if (idStr.empty()) +- { +- BMCWEB_LOG_DEBUG << "Invalid ID in objPath"; +- return; +- } +- +- crow::connections::systemBus->async_method_call( +- [idStr{std::move(idStr)}]( +- const boost::system::error_code ec, +- boost::container::flat_map< +- std::string, std::variant<int32_t, ReadingsObjType>>& +- resp) { +- if (ec) +- { +- BMCWEB_LOG_DEBUG +- << "D-Bus call failed to GetAll metric readings."; +- return; +- } +- +- const int32_t* timestampPtr = +- std::get_if<int32_t>(&resp["Timestamp"]); +- if (!timestampPtr) +- { +- BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; +- return; +- } +- +- ReadingsObjType* readingsPtr = +- std::get_if<ReadingsObjType>(&resp["Readings"]); +- if (!readingsPtr) +- { +- BMCWEB_LOG_DEBUG << "Failed to Get Readings property."; +- return; +- } +- +- if (!readingsPtr->size()) +- { +- BMCWEB_LOG_DEBUG << "No metrics report to be transferred"; +- return; +- } +- +- for (const auto& it : +- EventServiceManager::getInstance().subscriptionsMap) +- { +- std::shared_ptr<Subscription> entry = it.second; +- if (entry->eventFormatType == metricReportFormatType) +- { +- entry->filterAndSendReports( +- idStr, crow::utility::getDateTime(*timestampPtr), +- *readingsPtr); +- } +- } +- }, +- service, objPath, "org.freedesktop.DBus.Properties", "GetAll", +- intf); +- } +- + void unregisterMetricReportSignal() + { + if (matchTelemetryMonitor) +@@ -1436,9 +1353,11 @@ class EventServiceManager + } + + BMCWEB_LOG_DEBUG << "Metrics report signal - Register"; +- std::string matchStr( +- "type='signal',member='ReportUpdate', " +- "interface='xyz.openbmc_project.MonitoringService.Report'"); ++ std::string matchStr = "type='signal',member='PropertiesChanged'," ++ "interface='org.freedesktop.DBus.Properties'," ++ "path_namespace=/xyz/openbmc_project/Telemetry/" ++ "Reports/TelemetryService," ++ "arg0=xyz.openbmc_project.Telemetry.Report"; + + matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>( + *crow::connections::systemBus, matchStr, +@@ -1449,10 +1368,43 @@ class EventServiceManager + return; + } + +- std::string service = msg.get_sender(); +- std::string objPath = msg.get_path(); +- std::string intf = msg.get_interface(); +- getMetricReading(service, objPath, intf); ++ sdbusplus::message::object_path path(msg.get_path()); ++ std::string id = path.filename(); ++ if (id.empty()) ++ { ++ BMCWEB_LOG_ERROR << "Failed to get Id from path"; ++ return; ++ } ++ ++ std::string intf; ++ std::vector<std::pair< ++ std::string, std::variant<telemetry::TimestampReadings>>> ++ props; ++ std::vector<std::string> invalidProps; ++ msg.read(intf, props, invalidProps); ++ ++ auto found = ++ std::find_if(props.begin(), props.end(), [](const auto& x) { ++ return x.first == "Readings"; ++ }); ++ if (found == props.end()) ++ { ++ BMCWEB_LOG_ERROR ++ << "Failed to get Readings from Report properties"; ++ return; ++ } ++ ++ std::variant<telemetry::TimestampReadings>& readings = ++ found->second; ++ for (const auto& it : ++ EventServiceManager::getInstance().subscriptionsMap) ++ { ++ Subscription& entry = *it.second.get(); ++ if (entry.eventFormatType == metricReportFormatType) ++ { ++ entry.filterAndSendReports(id, readings); ++ } ++ } + }); + } + +diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp +index 9caf4a3..e79a41c 100644 +--- a/redfish-core/lib/metric_report.hpp ++++ b/redfish-core/lib/metric_report.hpp +@@ -31,16 +31,14 @@ inline nlohmann::json toMetricValues(const Readings& readings) + return metricValues; + } + +-inline void fillReport(const std::shared_ptr<AsyncResp>& asyncResp, +- const std::string& id, ++inline bool fillReport(nlohmann::json& json, const std::string& id, + const std::variant<TimestampReadings>& var) + { +- asyncResp->res.jsonValue["@odata.type"] = +- "#MetricReport.v1_3_0.MetricReport"; +- asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id; +- asyncResp->res.jsonValue["Id"] = id; +- asyncResp->res.jsonValue["Name"] = id; +- asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] = ++ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport"; ++ json["@odata.id"] = telemetry::metricReportUri + id; ++ json["Id"] = id; ++ json["Name"] = id; ++ json["MetricReportDefinition"]["@odata.id"] = + telemetry::metricReportDefinitionUri + id; + + const TimestampReadings* timestampReadings = +@@ -48,14 +46,14 @@ inline void fillReport(const std::shared_ptr<AsyncResp>& asyncResp, + if (!timestampReadings) + { + BMCWEB_LOG_ERROR << "Property type mismatch or property is missing"; +- messages::internalError(asyncResp->res); +- return; ++ return false; + } + + const auto& [timestamp, readings] = *timestampReadings; +- asyncResp->res.jsonValue["Timestamp"] = ++ json["Timestamp"] = + crow::utility::getDateTime(static_cast<time_t>(timestamp)); +- asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings); ++ json["MetricValues"] = toMetricValues(readings); ++ return true; + } + } // namespace telemetry + +@@ -146,7 +144,11 @@ class MetricReport : public Node + return; + } + +- telemetry::fillReport(asyncResp, id, ret); ++ if (!telemetry::fillReport(asyncResp->res.jsonValue, id, ++ ret)) ++ { ++ messages::internalError(asyncResp->res); ++ } + }, + telemetry::service, reportPath, + "org.freedesktop.DBus.Properties", "Get", +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README new file mode 100644 index 000000000..46128f7ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README @@ -0,0 +1,10 @@ +These patches are mirror of upstream TelemetryService implementation. +Until change is integrated they will be manually merged here to enable feature in Intel builds. + +Current revisions: +- Add support for MetricDefinition scheme + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/60 + +- Sync Telmetry service with EventService + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/38798/26 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend new file mode 100644 index 000000000..d9b32f5ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -0,0 +1,79 @@ +SRC_URI = "git://github.com/openbmc/bmcweb.git" +SRCREV = "dab0604af234bdd5010407031a01343d6c242edf" + +DEPENDS += "boost-url" +RDEPENDS_${PN} += "phosphor-nslcd-authority-cert-config" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# add a user called bmcweb for the server to assume +# bmcweb is part of group shadow for non-root pam authentication +USERADD_PARAM_${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb" + +GROUPADD_PARAM_${PN} = "web; redfish " + +SRC_URI += "file://0001-Firmware-update-configuration-changes.patch \ + file://0002-Use-chip-id-based-UUID-for-Service-Root.patch \ + file://0004-bmcweb-handle-device-or-resource-busy-exception.patch \ + file://0006-Define-Redfish-interface-Registries-Bios.patch \ + file://0007-BIOS-config-Add-support-for-PATCH-operation.patch \ + file://0008-Add-support-to-ResetBios-action.patch \ + file://0009-Add-support-to-ChangePassword-action.patch \ + file://0010-managers-add-attributes-for-Manager.CommandShell.patch \ + file://0034-recommended-fixes-by-crypto-review-team.patch \ + file://0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch \ + file://0012-Log-RedFish-event-for-Invalid-login-attempt.patch \ + file://0013-Add-UART-routing-logic-into-host-console-connection-.patch \ +" + +# Temporary downstream mirror of upstream patch to enable feature in Intel builds. +SRC_URI += "file://0037-Add-state-sensor-messages-to-the-registry.patch \ +" + +# EventService: Temporary pulled to downstream. See eventservice\README for details +SRC_URI += "file://eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch \ + file://eventservice/0002-EventService-https-client-support.patch \ + file://eventservice/0004-Add-Server-Sent-Events-support.patch \ + file://eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch \ + file://eventservice/0006-Add-EventService-SSE-filter-support.patch \ +" + +# Temporary downstream mirror of upstream patches, see telemetry\README for details +SRC_URI += "file://telemetry/0003-Add-support-for-MetricDefinition-scheme.patch \ + file://telemetry/0004-Sync-Telmetry-service-with-EventService.patch \ +" + +SRC_URI += "file://0001-Add-ConnectedVia-property-to-virtual-media-item-temp.patch \ + file://0002-Invalid-status-code-from-InsertMedia-REST-methods.patch \ + file://0003-Set-Inserted-redfish-property-for-not-inserted-resou.patch \ + file://0004-Bmcweb-handle-permission-denied-exception.patch \ + file://0005-Fix-unmounting-image-in-proxy-mode.patch \ +" + +SRC_URI += "file://0038-Revert-Disable-nbd-proxy-from-the-build.patch \ + file://0039-Fix-comparison-for-proxy-legacy-mode.patch \ +" + +# Fix to avoid bmcweb crash on VM mount +SRC_URI += "file://0039-Fix-bmcweb-crashes-if-socket-directory-not-present.patch \ +" + +# Temporary fix: Move it to service file +do_install_append() { + install -d ${D}/var/lib/bmcweb + install -d ${D}/etc/ssl/certs/authority +} + +# Enable PFR support +EXTRA_OEMESON += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-Dredfish-provisioning-feature=enabled', '', d)}" + +# Enable NBD proxy embedded in bmcweb +EXTRA_OEMESON += " -Dvm-nbdproxy=enabled" + +# Disable dependency on external nbd-proxy application +EXTRA_OEMESON += " -Dvm-websocket=disabled" +RDEPENDS_${PN}_remove += "jsnbd" + +# Enable Validation unsecure based on IMAGE_FEATURES +EXTRA_OEMESON += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-Dvalidate-unsecure-feature=enabled', '', d)}" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend new file mode 100644 index 000000000..616fb9a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://dev_id.json \ + file://channel_access.json \ + file://channel_config.json \ + file://master_write_read_white_list.json \ + " + +FILES_${PN} += " \ + ${datadir}/ipmi-providers/channel_access.json \ + ${datadir}/ipmi-providers/channel_config.json \ + ${datadir}/ipmi-providers/master_write_read_white_list.json \ + " + +do_install_append() { + install -m 0644 -D ${WORKDIR}/channel_access.json \ + ${D}${datadir}/ipmi-providers/channel_access.json + install -m 0644 -D ${WORKDIR}/channel_config.json \ + ${D}${datadir}/ipmi-providers/channel_config.json + install -m 0644 -D ${WORKDIR}/master_write_read_white_list.json \ + ${D}${datadir}/ipmi-providers/master_write_read_white_list.json +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json new file mode 100644 index 000000000..299483121 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json @@ -0,0 +1,23 @@ +{ + "1" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "2" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "3" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json new file mode 100644 index 000000000..656207de6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json @@ -0,0 +1,178 @@ +{ + "0" : { + "name" : "Ipmb", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "1" : { + "name" : "eth1", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "lan-802.3", + "protocol_type" : "ipmb-1.0", + "session_supported" : "multi-session", + "is_ipmi" : true + } + }, + "2" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "3" : { + "name" : "eth0", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "lan-802.3", + "protocol_type" : "ipmb-1.0", + "session_supported" : "multi-session", + "is_ipmi" : true + } + }, + "4" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "5" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "6" : { + "name" : "SMLINK", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "7" : { + "name" : "ipmi_kcs4", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "system-interface", + "protocol_type" : "kcs", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "8" : { + "name" : "INTRABMC", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "oem", + "protocol_type" : "oem", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "9" : { + "name" : "SIPMB", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "10" : { + "name" : "PCIE", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "11" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "12" : { + "name" : "INTERNAL", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "13" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "14" : { + "name" : "SELF", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "unknown", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "15" : { + "name" : "ipmi_kcs3", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "system-interface", + "protocol_type" : "kcs", + "session_supported" : "session-less", + "is_ipmi" : true + } + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json new file mode 100644 index 000000000..e561569d9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json @@ -0,0 +1,2 @@ +{"id": 35, "revision": 0, "addn_dev_support": 191, + "manuf_id": 343, "prod_id": 123, "aux": 0} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json new file mode 100644 index 000000000..6fc46f452 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json @@ -0,0 +1,76 @@ +{ + "filters": [ + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x01", + "slaveAddr": "0x4d", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x01", + "slaveAddr": "0x57", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x40", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x49", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x51", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x03", + "slaveAddr": "0x44", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x03", + "slaveAddr": "0x68", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x06", + "slaveAddr": "0x40", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x07", + "slaveAddr": "0x51", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + } + ] +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend new file mode 100644 index 000000000..2d892ad1a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://config.yaml" + +#override source file before it is used for final FRU file (merged from multiple sources) +do_install() { + cp ${WORKDIR}/config.yaml ${config_datadir}/ +} + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml new file mode 100644 index 000000000..e9b7a621e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml @@ -0,0 +1,31 @@ +# A YAML similar to this example would have to be generated, for eg with MRW +# inputs and system configuration, to depict IPMI Fru information. +# +# This file maps IPMI properties to phosphor dbus inventory properties +# +# This YAML could help generate C++ code. +# Format of the YAML: +# Fruid: +# Associated Fru paths +# d-bus Interfaces +# d-bus Properties +# IPMI Fru mapping +0: + /system/board/WFP_Baseboard: + entityID: 23 + entityInstance: 1 + interfaces: + xyz.openbmc_project.Inventory.Item: + name: + IPMIFruProperty: Product Name + IPMIFruSection: Product + xyz.openbmc_project.Inventory.Decorator.Asset: + Manufacturer: + IPMIFruProperty: Manufacturer + IPMIFruSection: Product + PartNumber: + IPMIFruProperty: Part Number + IPMIFruSection: Product + SerialNumber: + IPMIFruProperty: Serial Number + IPMIFruSection: Product diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format new file mode 100644 index 000000000..ea71ad6e1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format @@ -0,0 +1,99 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch new file mode 100644 index 000000000..a7d09f61e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch @@ -0,0 +1,41 @@ +From f18efe239cb4bbfd6996f753ae694f81041d8d43 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 14 Feb 2020 13:13:06 -0800 +Subject: [PATCH] Fix 'Get System GUID' to use settings UUID + +The upstream Get System GUID command looks first for a BMC interface +and then assumes that the UUID interface is next to that. But that is +not the case on Intel systems where the system GUID is found in the +settings daemon. + +Change-Id: I924bd05e0a546f2b30288c1faf72157296ab6579 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + apphandler.cpp | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 90818a9..dcf2c86 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -788,8 +788,6 @@ auto ipmiAppGetBtCapabilities() + + auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> + { +- static constexpr auto bmcInterface = +- "xyz.openbmc_project.Inventory.Item.Bmc"; + static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID"; + static constexpr auto uuidProperty = "UUID"; + +@@ -798,7 +796,7 @@ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> + { + // Get the Inventory object implementing BMC interface + auto busPtr = getSdBus(); +- auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface); ++ auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface); + + // Read UUID property value from bmcObject + // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch new file mode 100644 index 000000000..941e356ed --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch @@ -0,0 +1,89 @@ +From 58771a22dfcaa1e67bcf4fc0bd2ce0aa28c67e3f Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@linux.intel.com> +Date: Wed, 23 Jan 2019 17:02:40 +0800 +Subject: [PATCH] Fix keep looping issue when entering OS + +Sometimes when entering OS, OS will keep continuously sending ipmi command +"READ EVENT MESSAGE BUFFER" to BMC. This issue is caused by incorrect KCS +status. If restart the host immediately while OS is still running, SMS_ATN +will be set, after that KCS come into an incorrect status, and then KCS +communction between BMC and OS crash. To make KCS go back to correct status +and fix the issue, clear SMS_ATN after every time power cycle happen. + +Unit Test: + After entered OS, force reset system, after enter OS again, OS can start +normally without keep sending READ EVENT MESSAGE BUFFER command. + After power on system, enter EFI SHELL, check cmdtool.efi can work +correctly through KCS channel. +--- + host-cmd-manager.cpp | 33 ++++++++++++++++++++++++--------- + 1 file changed, 24 insertions(+), 9 deletions(-) + +diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp +index e52c9bb..b3a5d71 100644 +--- a/host-cmd-manager.cpp ++++ b/host-cmd-manager.cpp +@@ -23,6 +23,8 @@ namespace command + constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0"; + constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host"; + constexpr auto HOST_TRANS_PROP = "RequestedHostTransition"; ++constexpr const char* IPMI_PATH = "/xyz/openbmc_project/Ipmi/Channel/ipmi_kcs3"; ++constexpr const char* IPMI_INTERFACE = "xyz.openbmc_project.Ipmi.Channel.SMS"; + + // For throwing exceptions + using namespace phosphor::logging; +@@ -103,6 +105,20 @@ void Manager::clearQueue() + // `false` indicating Failure + std::get<CallBack>(command)(ipmiCmdData, false); + } ++ ++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "clearAttention"); ++ ++ try ++ { ++ auto reply = this->bus.call(method); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ log<level::ERR>("Error in clearing SMS attention"); ++ elog<InternalFailure>(); ++ } + } + + // Called for alerting the host +@@ -112,9 +128,7 @@ void Manager::checkQueueAndAlertHost() + { + log<level::DEBUG>("Asserting SMS Attention"); + +- std::string HOST_IPMI_SVC("org.openbmc.HostIpmi"); +- std::string IPMI_PATH("/org/openbmc/HostIpmi/1"); +- std::string IPMI_INTERFACE("org.openbmc.HostIpmi"); ++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); + + // Start the timer for this transaction + auto time = std::chrono::duration_cast<std::chrono::microseconds>( +@@ -127,12 +141,13 @@ void Manager::checkQueueAndAlertHost() + return; + } + +- auto method = +- this->bus.new_method_call(HOST_IPMI_SVC.c_str(), IPMI_PATH.c_str(), +- IPMI_INTERFACE.c_str(), "setAttention"); +- auto reply = this->bus.call(method); +- +- if (reply.is_method_error()) ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "setAttention"); ++ try ++ { ++ auto reply = this->bus.call(method); ++ } ++ catch (const std::exception&) + { + log<level::ERR>("Error in setting SMS attention"); + elog<InternalFailure>(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..ba8896195 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,356 @@ +From 9f4fb8a6aa076261b19c187aeef840d818158ec7 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 16 Oct 2019 14:24:20 +0800 +Subject: [PATCH] Move Set SOL config parameter to host-ipmid + +Move Set SOL config parameter command from net-ipmid to host-ipmid, +so that BIOS in Intel platform can enable or disable SOL through KCS. +Get SOL config parameter command will be moved later. + +Tested by: +With the related change in phospher-ipmi-net and phospher-dbus-interface, +Run commands: +ipmitool raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +All these commands have correct response and all dbus interface for +sol command change to same value in above commands. +After reboot BMC, "Progress" property in dbus interface change back +to 0 and other properties will not reset to default value. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 294 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 295 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 5397115..c93f3b1 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,6 +41,7 @@ + 0x0A:0x48 //<Storage>:<Get SEL Time> + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> ++0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 0012746..0de76c4 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -2030,8 +2030,298 @@ RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits, + } // namespace transport + } // namespace ipmi + ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; ++ + void register_netfn_transport_functions() __attribute__((constructor)); + ++static std::string ++ getSOLService(std::shared_ptr<sdbusplus::asio::connection> dbus, ++ const std::string& solPathWitheEthName) ++{ ++ static std::string solService{}; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = ++ ipmi::getService(*dbus, solInterface, solPathWitheEthName); ++ } ++ catch (const sdbusplus::exception::SdBusError& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return solService; ++ } ++ } ++ return solService; ++} ++ ++static int setSOLParameter(const std::string& property, ++ const ipmi::Value& value, const uint8_t& channelNum) ++{ ++ auto dbus = getSdBus(); ++ ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ ++ std::string solPathWitheEthName = std::string(solPath) + ethdevice; ++ ++ std::string service = getSOLService(dbus, solPathWitheEthName); ++ if (service.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get SOL service failed"); ++ return -1; ++ } ++ try ++ { ++ ipmi::setDbusProperty(*dbus, service, solPathWitheEthName, solInterface, ++ property, value); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int getSOLParameter(const std::string& property, ipmi::Value& value, ++ const uint8_t& channelNum) ++{ ++ auto dbus = getSdBus(); ++ ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ ++ std::string solPathWitheEthName = std::string(solPath) + ethdevice; ++ ++ std::string service = getSOLService(dbus, solPathWitheEthName); ++ if (service.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get SOL service failed"); ++ return -1; ++ } ++ try ++ { ++ value = ipmi::getDbusProperty(*dbus, service, solPathWitheEthName, ++ solInterface, property); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static const constexpr uint8_t encryptMask = 0x80; ++static const constexpr uint8_t encryptShift = 7; ++static const constexpr uint8_t authMask = 0x40; ++static const constexpr uint8_t authShift = 6; ++static const constexpr uint8_t privilegeMask = 0xf; ++ ++namespace ipmi ++{ ++constexpr Cc ccParmNotSupported = 0x80; ++constexpr Cc ccSetInProgressActive = 0x81; ++constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82; ++ ++static inline auto responseParmNotSupported() ++{ ++ return response(ccParmNotSupported); ++} ++static inline auto responseSetInProgressActive() ++{ ++ return response(ccSetInProgressActive); ++} ++static inline auto responseSystemInfoParameterSetReadOnly() ++{ ++ return response(ccSystemInfoParameterSetReadOnly); ++} ++ ++} // namespace ipmi ++ ++namespace sol ++{ ++enum class Parameter ++{ ++ progress, //!< Set In Progress. ++ enable, //!< SOL Enable. ++ authentication, //!< SOL Authentication. ++ accumulate, //!< Character Accumulate Interval & Send Threshold. ++ retry, //!< SOL Retry. ++ nvbitrate, //!< SOL non-volatile bit rate. ++ vbitrate, //!< SOL volatile bit rate. ++ channel, //!< SOL payload channel. ++ port, //!< SOL payload port. ++}; ++ ++enum class Privilege : uint8_t ++{ ++ highestPriv, ++ callbackPriv, ++ userPriv, ++ operatorPriv, ++ adminPriv, ++ oemPriv, ++}; ++ ++} // namespace sol ++ ++constexpr uint8_t progressMask = 0x03; ++constexpr uint8_t enableMask = 0x01; ++constexpr uint8_t retryMask = 0x07; ++ ++ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, ++ uint4_t reserved, uint8_t paramSelector, ++ uint8_t configParamData1, ++ std::optional<uint8_t> configParamData2) ++{ ++ ipmi::ChannelInfo chInfo; ++ uint8_t channelNum = ipmi::convertCurrentChannelNum( ++ static_cast<uint8_t>(chNum), ctx->channel); ++ if (reserved != 0 || ++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum)))) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ switch (static_cast<sol::Parameter>(paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ uint8_t progress = configParamData1 & progressMask; ++ ipmi::Value currentProgress = 0; ++ if (getSOLParameter("Progress", currentProgress, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ if ((std::get<uint8_t>(currentProgress) == 1) && (progress == 1)) ++ { ++ return ipmi::responseSetInProgressActive(); ++ } ++ ++ if (setSOLParameter("Progress", progress, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::enable: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ bool enable = configParamData1 & enableMask; ++ if (setSOLParameter("Enable", enable, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::authentication: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ uint8_t encrypt = (configParamData1 & encryptMask) >> encryptShift; ++ uint8_t auth = (configParamData1 & authMask) >> authShift; ++ uint8_t privilege = configParamData1 & privilegeMask; ++ // For security considering encryption and authentication must be ++ // true. ++ if (!encrypt || !auth) ++ { ++ return ipmi::responseSystemInfoParameterSetReadOnly(); ++ } ++ else if (privilege < ++ static_cast<uint8_t>(sol::Privilege::userPriv) || ++ privilege > static_cast<uint8_t>(sol::Privilege::oemPriv)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ if (setSOLParameter("Privilege", privilege, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ break; ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (!configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if (*configParamData2 == 0) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ if (setSOLParameter("AccumulateIntervalMS", configParamData1, ++ channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ if (setSOLParameter("Threshold", *configParamData2, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::retry: ++ { ++ if (!configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if ((setSOLParameter( ++ "RetryCount", ++ static_cast<uint8_t>(configParamData1 & retryMask), ++ channelNum) < 0) || ++ (setSOLParameter("RetryIntervalMS", *configParamData2, ++ channelNum) < 0)) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ break; ++ } ++ case sol::Parameter::port: ++ { ++ return ipmi::responseSystemInfoParameterSetReadOnly(); ++ } ++ case sol::Parameter::nvbitrate: ++ case sol::Parameter::vbitrate: ++ case sol::Parameter::channel: ++ default: ++ return ipmi::responseParmNotSupported(); ++ } ++ ++ return ipmi::responseSuccess(); ++} ++ + void register_netfn_transport_functions() + { + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, +@@ -2040,4 +2330,8 @@ void register_netfn_transport_functions() + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, + ipmi::transport::cmdGetLanConfigParameters, + ipmi::Privilege::Operator, ipmi::transport::getLan); ++ ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdSetSolConfigParameters, ++ ipmi::Privilege::Admin, setSOLConfParams); + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..d6ba70562 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,259 @@ +From ff1d4198e8ad8f824f34fb9d261ea0e25179f070 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Thu, 11 Jul 2019 00:32:58 +0800 +Subject: [PATCH] Move Get SOL config parameter to host-ipmid + +Move Get SOL config parameter command from net-ipmid to host-ipmid. + +Tested: +Run command ipmitool sol info 1 +Set in progress : set-complete +Enabled : true +Force Encryption : false +Force Authentication : false +Privilege Level : ADMINISTRATOR +Character Accumulate Level (ms) : 60 +Character Send Threshold : 96 +Retry Count : 6 +Retry Interval (ms) : 200 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : 115.2 +Payload Channel : 1 (0x01) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 191 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 192 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index c93f3b1..730437d 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -42,6 +42,7 @@ + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> + 0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> ++0x0C:0x22 //<Transport>:<Get SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 0de76c4..b81e0d5 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -2120,6 +2120,28 @@ static int getSOLParameter(const std::string& property, ipmi::Value& value, + return 0; + } + ++constexpr const char* consoleInterface = "xyz.openbmc_project.console"; ++constexpr const char* consolePath = "/xyz/openbmc_project/console"; ++static int getSOLBaudRate(ipmi::Value& value) ++{ ++ auto dbus = getSdBus(); ++ ++ try ++ { ++ value = ++ ipmi::getDbusProperty(*dbus, "xyz.openbmc_project.console", ++ consolePath, consoleInterface, "baudrate"); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol baud rate"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static const constexpr uint8_t encryptMask = 0x80; + static const constexpr uint8_t encryptShift = 7; + static const constexpr uint8_t authMask = 0x40; +@@ -2322,6 +2344,171 @@ ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, + return ipmi::responseSuccess(); + } + ++static const constexpr uint8_t retryCountMask = 0x07; ++static constexpr uint16_t ipmiStdPort = 623; ++static constexpr uint8_t solParameterRevision = 0x11; ++ipmi::RspType<uint8_t, std::optional<uint8_t>, std::optional<uint8_t>> ++ getSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, uint3_t reserved, ++ bool getParamRev, uint8_t paramSelector, ++ uint8_t setSelector, uint8_t blockSelector) ++{ ++ ipmi::ChannelInfo chInfo; ++ uint8_t channelNum = ipmi::convertCurrentChannelNum( ++ static_cast<uint8_t>(chNum), ctx->channel); ++ if (reserved != 0 || ++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))) || ++ (ipmi::EChannelSessSupported::none == ++ ipmi::getChannelSessionSupport(static_cast<uint8_t>(channelNum)))) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ if (getParamRev) ++ { ++ return ipmi::responseSuccess(solParameterRevision, std::nullopt, ++ std::nullopt); ++ } ++ ++ ipmi::Value value; ++ switch (static_cast<sol::Parameter>(paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (getSOLParameter("Progress", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, std::get<uint8_t>(value), std::nullopt); ++ } ++ case sol::Parameter::enable: ++ { ++ if (getSOLParameter("Enable", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, ++ static_cast<uint8_t>(std::get<bool>(value)), std::nullopt); ++ } ++ case sol::Parameter::authentication: ++ { ++ uint8_t authentication = 0; ++ if (getSOLParameter("Privilege", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication = (std::get<uint8_t>(value) & 0x0f); ++ ++ if (getSOLParameter("ForceAuthentication", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 6); ++ ++ if (getSOLParameter("ForceEncryption", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 7); ++ return ipmi::responseSuccess(solParameterRevision, authentication, ++ std::nullopt); ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (getSOLParameter("AccumulateIntervalMS", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ ipmi::Value value1; ++ if (getSOLParameter("Threshold", value1, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess(solParameterRevision, ++ std::get<uint8_t>(value), ++ std::get<uint8_t>(value1)); ++ } ++ case sol::Parameter::retry: ++ { ++ if (getSOLParameter("RetryCount", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ ipmi::Value value1; ++ if (getSOLParameter("RetryIntervalMS", value1, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, std::get<uint8_t>(value) & retryCountMask, ++ std::get<uint8_t>(value1)); ++ } ++ case sol::Parameter::channel: ++ { ++ return ipmi::responseSuccess(solParameterRevision, channelNum, ++ std::nullopt); ++ } ++ case sol::Parameter::port: ++ { ++ uint16_t port = htole16(ipmiStdPort); ++ auto buffer = reinterpret_cast<const uint8_t*>(&port); ++ return ipmi::responseSuccess(solParameterRevision, buffer[0], ++ buffer[1]); ++ } ++ case sol::Parameter::nvbitrate: ++ { ++ if (getSOLBaudRate(value) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ uint8_t bitRate = 0; ++ uint32_t* pBaudRate = std::get_if<uint32_t>(&value); ++ if (!pBaudRate) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Failed to get valid baud rate from D-Bus interface"); ++ } ++ switch (*pBaudRate) ++ { ++ case 9600: ++ bitRate = 0x06; ++ break; ++ case 19200: ++ bitRate = 0x07; ++ break; ++ case 38400: ++ bitRate = 0x08; ++ break; ++ case 57600: ++ bitRate = 0x09; ++ break; ++ case 115200: ++ bitRate = 0x0a; ++ break; ++ default: ++ break; ++ } ++ return ipmi::responseSuccess(solParameterRevision, bitRate, ++ std::nullopt); ++ } ++ default: ++ return ipmi::responseParmNotSupported(); ++ } ++} ++ + void register_netfn_transport_functions() + { + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, +@@ -2334,4 +2521,8 @@ void register_netfn_transport_functions() + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, + ipmi::transport::cmdSetSolConfigParameters, + ipmi::Privilege::Admin, setSOLConfParams); ++ ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdGetSolConfigParameters, ++ ipmi::Privilege::User, getSOLConfParams); + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch new file mode 100644 index 000000000..bf1928825 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch @@ -0,0 +1,291 @@ +From 16eb5d80893406739518e7a56eb5191aa7e68257 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 3 Jun 2019 17:01:47 -0700 +Subject: [PATCH] Update IPMI Chassis Control command + +This change updates the IPMI Chassis Control command to use the new +host state transitions. This allows each chassis control action +to more closely follow the behavior defined in the IPMI spec. + +ref: https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/22358 + +Tested: +Ran each IPMI chassis control command to confirm the expected +behavior: +ipmitool power on: system is powered-on +ipmitool power off: system is forced off +ipmitool power cycle: system is forced off then powered-on +ipmitool power reset: system is hard reset +ipmitool power soft: soft power-off requested from system software + +Change-Id: Ic9fba3ca4abd9a758eb88f1e6ee09f7ca64ff80a +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + chassishandler.cpp | 206 +++++++++++---------------------------------- + 1 file changed, 50 insertions(+), 156 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 4ca981d..cd0a13d 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -31,6 +31,7 @@ + #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> + #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> + #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp> ++#include <xyz/openbmc_project/State/Chassis/server.hpp> + #include <xyz/openbmc_project/State/Host/server.hpp> + #include <xyz/openbmc_project/State/PowerOnHours/server.hpp> + +@@ -813,59 +814,63 @@ ipmi::RspType<> ipmiSetChassisCap(bool intrusion, bool fpLockout, + //------------------------------------------ + // Calls into Host State Manager Dbus object + //------------------------------------------ +-int initiate_state_transition(State::Host::Transition transition) ++int initiateHostStateTransition(State::Host::Transition transition) + { + // OpenBMC Host State Manager dbus framework +- constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0"; +- constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host"; +- constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties"; +- constexpr auto PROPERTY = "RequestedHostTransition"; ++ constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0"; ++ constexpr auto hostStateIntf = "xyz.openbmc_project.State.Host"; + +- // sd_bus error +- int rc = 0; +- char* busname = NULL; ++ auto service = ipmi::getService(*getSdBus(), hostStateIntf, hostStatePath); + +- // SD Bus error report mechanism. +- sd_bus_error bus_error = SD_BUS_ERROR_NULL; ++ // Convert to string equivalent of the passed in transition enum. ++ auto request = State::convertForMessage(transition); + +- // Gets a hook onto either a SYSTEM or SESSION bus +- sd_bus* bus_type = ipmid_get_sd_bus_connection(); +- rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname); +- if (rc < 0) ++ try ++ { ++ ipmi::setDbusProperty(*getSdBus(), service, hostStatePath, ++ hostStateIntf, "RequestedHostTransition", ++ request); ++ } ++ catch (std::exception& e) + { + log<level::ERR>( +- "Failed to get bus name", +- entry("ERRNO=0x%X, OBJPATH=%s", -rc, HOST_STATE_MANAGER_ROOT)); +- return rc; ++ "Failed to initiate transition", ++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str())); ++ return -1; + } ++ return 0; ++} ++ ++//------------------------------------------ ++// Calls into Chassis State Manager Dbus object ++//------------------------------------------ ++int initiateChassisStateTransition(State::Chassis::Transition transition) ++{ ++ // OpenBMC Chassis State Manager dbus framework ++ constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0"; ++ constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis"; ++ ++ auto service = ++ ipmi::getService(*getSdBus(), chassisStateIntf, chassisStatePath); + + // Convert to string equivalent of the passed in transition enum. + auto request = State::convertForMessage(transition); + +- rc = sd_bus_call_method(bus_type, // On the system bus +- busname, // Service to contact +- HOST_STATE_MANAGER_ROOT, // Object path +- DBUS_PROPERTY_IFACE, // Interface name +- "Set", // Method to be called +- &bus_error, // object to return error +- nullptr, // Response buffer if any +- "ssv", // Takes 3 arguments +- HOST_STATE_MANAGER_IFACE, PROPERTY, "s", +- request.c_str()); +- if (rc < 0) +- { +- log<level::ERR>("Failed to initiate transition", +- entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str())); ++ try ++ { ++ ipmi::setDbusProperty(*getSdBus(), service, chassisStatePath, ++ chassisStateIntf, "RequestedPowerTransition", ++ request); + } +- else ++ catch (std::exception& e) + { +- log<level::INFO>("Transition request initiated successfully"); ++ log<level::ERR>( ++ "Failed to initiate transition", ++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str())); ++ return -1; + } + +- sd_bus_error_free(&bus_error); +- free(busname); +- +- return rc; ++ return 0; + } + + //------------------------------------------ +@@ -1298,76 +1303,6 @@ ipmi::RspType<uint4_t, // Restart Cause + CHANNEL_NOT_SUPPORTED); + } + +-//------------------------------------------------------------- +-// Send a command to SoftPowerOff application to stop any timer +-//------------------------------------------------------------- +-int stop_soft_off_timer() +-{ +- constexpr auto iface = "org.freedesktop.DBus.Properties"; +- constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal." +- "SoftPowerOff"; +- +- constexpr auto property = "ResponseReceived"; +- constexpr auto value = "xyz.openbmc_project.Ipmi.Internal." +- "SoftPowerOff.HostResponse.HostShutdown"; +- +- // Get the system bus where most system services are provided. +- auto bus = ipmid_get_sd_bus_connection(); +- +- // Get the service name +- // TODO openbmc/openbmc#1661 - Mapper refactor +- // +- // See openbmc/openbmc#1743 for some details but high level summary is that +- // for now the code will directly call the soft off interface due to a +- // race condition with mapper usage +- // +- // char *busname = nullptr; +- // auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname); +- // if (r < 0) +- //{ +- // fprintf(stderr, "Failed to get %s bus name: %s\n", +- // SOFTOFF_OBJPATH, -r); +- // return r; +- //} +- +- // No error object or reply expected. +- int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface, +- "Set", nullptr, nullptr, "ssv", soft_off_iface, +- property, "s", value); +- if (rc < 0) +- { +- log<level::ERR>("Failed to set property in SoftPowerOff object", +- entry("ERRNO=0x%X", -rc)); +- } +- +- // TODO openbmc/openbmc#1661 - Mapper refactor +- // free(busname); +- return rc; +-} +- +-//---------------------------------------------------------------------- +-// Create file to indicate there is no need for softoff notification to host +-//---------------------------------------------------------------------- +-void indicate_no_softoff_needed() +-{ +- fs::path path{HOST_INBAND_REQUEST_DIR}; +- if (!fs::is_directory(path)) +- { +- fs::create_directory(path); +- } +- +- // Add the host instance (default 0 for now) to the file name +- std::string file{HOST_INBAND_REQUEST_FILE}; +- auto size = std::snprintf(nullptr, 0, file.c_str(), 0); +- size++; // null +- std::unique_ptr<char[]> buf(new char[size]); +- std::snprintf(buf.get(), size, file.c_str(), 0); +- +- // Append file name to directory and create it +- path /= buf.get(); +- std::ofstream(path.c_str()); +-} +- + /** @brief Implementation of chassis control command + * + * @param - chassisControl command byte +@@ -1380,63 +1315,22 @@ ipmi::RspType<> ipmiChassisControl(uint8_t chassisControl) + switch (chassisControl) + { + case CMD_POWER_ON: +- rc = initiate_state_transition(State::Host::Transition::On); ++ rc = initiateHostStateTransition(State::Host::Transition::On); + break; + case CMD_POWER_OFF: +- // This path would be hit in 2 conditions. +- // 1: When user asks for power off using ipmi chassis command 0x04 +- // 2: Host asking for power off post shutting down. +- +- // If it's a host requested power off, then need to nudge Softoff +- // application that it needs to stop the watchdog timer if running. +- // If it is a user requested power off, then this is not really +- // needed. But then we need to differentiate between user and host +- // calling this same command +- +- // For now, we are going ahead with trying to nudge the soft off and +- // interpret the failure to do so as a non softoff case +- rc = stop_soft_off_timer(); +- +- // Only request the Off transition if the soft power off +- // application is not running +- if (rc < 0) +- { +- // First create a file to indicate to the soft off application +- // that it should not run. Not doing this will result in State +- // manager doing a default soft power off when asked for power +- // off. +- indicate_no_softoff_needed(); +- +- // Now request the shutdown +- rc = initiate_state_transition(State::Host::Transition::Off); +- } +- else +- { +- log<level::INFO>("Soft off is running, so let shutdown target " +- "stop the host"); +- } ++ rc = ++ initiateChassisStateTransition(State::Chassis::Transition::Off); + break; +- + case CMD_HARD_RESET: ++ rc = initiateHostStateTransition( ++ State::Host::Transition::ForceWarmReboot); ++ break; + case CMD_POWER_CYCLE: +- // SPEC has a section that says certain implementations can trigger +- // PowerOn if power is Off when a command to power cycle is +- // requested +- +- // First create a file to indicate to the soft off application +- // that it should not run since this is a direct user initiated +- // power reboot request (i.e. a reboot request that is not +- // originating via a soft power off SMS request) +- indicate_no_softoff_needed(); +- +- rc = initiate_state_transition(State::Host::Transition::Reboot); ++ rc = initiateHostStateTransition(State::Host::Transition::Reboot); + break; +- + case CMD_SOFT_OFF_VIA_OVER_TEMP: +- // Request Host State Manager to do a soft power off +- rc = initiate_state_transition(State::Host::Transition::Off); ++ rc = initiateHostStateTransition(State::Host::Transition::Off); + break; +- + case CMD_PULSE_DIAGNOSTIC_INTR: + rc = setNmiProperty(true); + break; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch new file mode 100644 index 000000000..d0f9331d2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch @@ -0,0 +1,140 @@ +From cfb5e13388531e1317eeb3ccf0f8eef0c6eeca60 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Tue, 28 May 2019 17:11:17 +0800 +Subject: [PATCH] Save the pre-timeout interrupt in dbus property + +Get the watchdog pre-timeout interrupt value from ipmi watchdog set command, +and store it into dbus property. + +Tested: +Config IPMI watchdog: BIOS FRB2 Power Cycle after 1 seconds: +ipmitool raw 0x06 0x24 0x01 0x13 0x0 0x2 0xa 0x00 +Start watchdog: +Ipmitool mc watchdog reset +Check the watchdog pre-timeout interrupt in below: +https://BMCIP/redfish/v1/Systems/system/LogServices/EventLog/Entries + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + app/watchdog.cpp | 47 ++++++++++++++++++++++++++++++++++++++++ + app/watchdog_service.cpp | 6 +++++ + app/watchdog_service.hpp | 9 ++++++++ + 3 files changed, 62 insertions(+) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 03c373e..cb0b1fd 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -80,6 +80,7 @@ ipmi::RspType<> ipmiAppResetWatchdogTimer() + + static constexpr uint8_t wd_dont_stop = 0x1 << 6; + static constexpr uint8_t wd_timeout_action_mask = 0x3; ++static constexpr uint8_t wdPreTimeoutInterruptMask = 0x3; + + static constexpr uint8_t wdTimerUseResTimer1 = 0x0; + static constexpr uint8_t wdTimerUseResTimer2 = 0x6; +@@ -127,6 +128,45 @@ WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action) + } + } + ++enum class IpmiPreTimeoutInterrupt : uint8_t ++{ ++ None = 0x0, ++ SMI = 0x1, ++ NMI = 0x2, ++ MI = 0x3, ++}; ++/** @brief Converts an IPMI Watchdog PreTimeoutInterrupt to DBUS defined action ++ * @param[in] ipmi_action The IPMI Watchdog PreTimeoutInterrupt ++ * @return The Watchdog PreTimeoutInterrupt that the ipmi_action maps to ++ */ ++WatchdogService::PreTimeoutInterruptAction ipmiPreTimeoutInterruptToWdAction( ++ IpmiPreTimeoutInterrupt ipmiPreTimeOutInterrupt) ++{ ++ switch (ipmiPreTimeOutInterrupt) ++ { ++ case IpmiPreTimeoutInterrupt::None: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::None; ++ } ++ case IpmiPreTimeoutInterrupt::SMI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::SMI; ++ } ++ case IpmiPreTimeoutInterrupt::NMI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::NMI; ++ } ++ case IpmiPreTimeoutInterrupt::MI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::MI; ++ } ++ default: ++ { ++ throw std::domain_error("IPMI PreTimeoutInterrupt is invalid"); ++ } ++ } ++} ++ + enum class IpmiTimerUse : uint8_t + { + Reserved = 0x0, +@@ -250,6 +290,13 @@ ipmi::RspType<> + // Mark as initialized so that future resets behave correctly + wd_service.setInitialized(true); + ++ // pretimeOutAction ++ const auto ipmiPreTimeoutInterrupt = ++ static_cast<IpmiPreTimeoutInterrupt>(wdPreTimeoutInterruptMask & ++ (static_cast<uint8_t>(preTimeoutInterrupt))); ++ wd_service.setPreTimeoutInterrupt( ++ ipmiPreTimeoutInterruptToWdAction(ipmiPreTimeoutInterrupt)); ++ + lastCallSuccessful = true; + return ipmi::responseSuccess(); + } +diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp +index 3534e89..4df1ab6 100644 +--- a/app/watchdog_service.cpp ++++ b/app/watchdog_service.cpp +@@ -198,3 +198,9 @@ void WatchdogService::setInterval(uint64_t interval) + { + setProperty("Interval", interval); + } ++ ++void WatchdogService::setPreTimeoutInterrupt( ++ PreTimeoutInterruptAction preTimeoutInterrupt) ++{ ++ setProperty("PreTimeoutInterrupt", convertForMessage(preTimeoutInterrupt)); ++} +\ No newline at end of file +diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp +index 141bdb7..32b7461 100644 +--- a/app/watchdog_service.hpp ++++ b/app/watchdog_service.hpp +@@ -15,6 +15,8 @@ class WatchdogService + + using Action = + sdbusplus::xyz::openbmc_project::State::server::Watchdog::Action; ++ using PreTimeoutInterruptAction = sdbusplus::xyz::openbmc_project::State:: ++ server::Watchdog::PreTimeoutInterruptAction; + using TimerUse = + sdbusplus::xyz::openbmc_project::State::server::Watchdog::TimerUse; + +@@ -92,6 +94,13 @@ class WatchdogService + */ + void setInterval(uint64_t interval); + ++ /** @brief Sets the value of the PreTimeoutInterrupt property on the host ++ * watchdog ++ * ++ * @param[in] PreTimeoutInterrupt - The new PreTimeoutInterrupt value ++ */ ++ void setPreTimeoutInterrupt(PreTimeoutInterruptAction preTimeoutInterrupt); ++ + private: + /** @brief sdbusplus handle */ + sdbusplus::bus::bus bus; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service new file mode 100644 index 000000000..1e45ee6c9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service @@ -0,0 +1,15 @@ +[Unit] +Description=Phosphor Inband IPMI + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env ipmid +SyslogIdentifier=ipmid +RuntimeDirectory = ipmi +RuntimeDirectoryPreserve = yes +StateDirectory = ipmi + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp new file mode 100644 index 000000000..856a80fbc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp @@ -0,0 +1,147 @@ +/* Copyright 2019 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dcmihandler.hpp" + +#include <cstdint> +#include <ipmid/api-types.hpp> +#include <ipmid/api.hpp> +#include <ipmid/message.hpp> +#include <ipmid/message/types.hpp> +#include <ipmid/utils.hpp> +#include <vector> + +enum class oemLanParam : uint8_t +{ + intelHostnameConfig = 0xc7, +}; + +constexpr size_t IpmiHostnameLen = 16; +constexpr uint8_t CurrentRevision = 0x11; // Current rev per IPMI Spec 2.0 + +constexpr ipmi::Cc ccParamNotSupported = 0x80; +constexpr ipmi::Cc ccUnprintable = 0x90; + +namespace ipmi::transport +{ + +constexpr auto validHostnameChars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX" + "YZ0123456789-"; +constexpr int lanOemHostnameLength = 64; + +RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req) +{ + std::vector<uint8_t> dataBytes; + switch (static_cast<oemLanParam>(parameter)) + { + case oemLanParam::intelHostnameConfig: + { + static std::array<uint8_t, lanOemHostnameLength> blockData; + uint8_t block = 0; + uint8_t complete = 0; + if ((req.unpack(block, complete, dataBytes) != 0) || + (!req.fullyUnpacked())) + { + return responseReqDataLenInvalid(); + } + + size_t numDataBytes = req.size() - 4; + if ((numDataBytes > IpmiHostnameLen) || + (!complete && (numDataBytes < IpmiHostnameLen))) + { + return responseReqDataLenInvalid(); + } + + if (!((block > 0) && (block < 5)) || + ((complete != 0) && (complete != 1))) + { + return responseInvalidFieldRequest(); + } + + if (block == 1) + { + blockData.fill(0); + } + + std::copy(dataBytes.begin(), dataBytes.end(), + blockData.data() + ((block - 1) * IpmiHostnameLen)); + if (complete) + { + blockData[lanOemHostnameLength - 1] = 0; + // check hostname, and write it + std::string newHostname( + reinterpret_cast<char*>(blockData.data()), + lanOemHostnameLength); + size_t firstNull = newHostname.find_first_of('\0'); + if (newHostname.find_first_not_of(validHostnameChars) != + firstNull) + { + return response(ccUnprintable); + } + std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); + ipmi::setDbusProperty(*busp, ::dcmi::networkServiceName, + ::dcmi::networkConfigObj, + ::dcmi::networkConfigIntf, + ::dcmi::hostNameProp, newHostname); + } + return responseSuccess(); + } + default: + return response(ccParamNotSupported); + } + return response(ccParamNotSupported); +} + +RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter, + uint8_t set, uint8_t block) +{ + message::Payload message; + message.pack(CurrentRevision); + oemLanParam param = static_cast<oemLanParam>(parameter); + switch (param) + { + case oemLanParam::intelHostnameConfig: + { + if (set != 0) + { + return responseInvalidFieldRequest(); + } + if ((block < 1) || (block > 4)) + { + return responseInvalidFieldRequest(); + } + std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); + auto service = ipmi::getService(*busp, ::dcmi::networkConfigIntf, + ::dcmi::networkConfigObj); + auto value = ipmi::getDbusProperty( + *busp, service, ::dcmi::networkConfigObj, + ::dcmi::networkConfigIntf, ::dcmi::hostNameProp); + std::string hostname = std::get<std::string>(value); + std::array<char, IpmiHostnameLen> buf = {0}; + size_t head = (block - 1) * IpmiHostnameLen; + if (head < hostname.size()) + { + size_t numToCopy = hostname.size() - head; + numToCopy = std::min(IpmiHostnameLen, numToCopy); + hostname.copy(buf.data(), numToCopy, head); + } + message.pack(buf); + return responseSuccess(std::move(message)); + } + } + return response(ccParamNotSupported); +} +} // namespace ipmi::transport diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend new file mode 100644 index 000000000..677641faf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -0,0 +1,39 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +PROJECT_SRC_DIR := "${THISDIR}/${PN}" + +SRC_URI += "file://phosphor-ipmi-host.service \ + file://0010-fix-get-system-GUID-ipmi-command.patch \ + file://0053-Fix-keep-looping-issue-when-entering-OS.patch \ + file://0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch \ + file://0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch \ + file://0062-Update-IPMI-Chassis-Control-command.patch \ + file://0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch \ + " + +EXTRA_OECONF_append = " --disable-i2c-whitelist-check" +EXTRA_OECONF_append = " --enable-transport-oem=yes" +EXTRA_OECONF_append = " --disable-boot-flag-safe-mode-support" +EXTRA_OECONF_append = " --disable-ipmi-whitelist" + +RDEPENDS_${PN}_remove = "clear-once" + +# remove the softpoweroff service since we do not need it +SYSTEMD_SERVICE_${PN}_remove += " \ + xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service" + +SYSTEMD_LINK_${PN}_remove += " \ + ../xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service:obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \ + " +FILES_${PN}_remove = " \ + ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/ \ + ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \ + " + +do_compile_prepend(){ + cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S} +} + +do_install_append(){ + rm -f ${D}/${bindir}/phosphor-softpoweroff + rm -f ${S}/transporthandler_oem.cpp +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch new file mode 100644 index 000000000..d071ebd67 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/0001-Add-dbus-method-SlotIpmbRequest.patch @@ -0,0 +1,535 @@ +From 42231615d6a1effbfaa581ca41c0d406174feee8 Mon Sep 17 00:00:00 2001 +From: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@linux.intel.com> +Date: Mon, 23 Mar 2020 22:19:07 +0530 +Subject: [PATCH] Add dbus method SlotIpmbRequest + +Added dbus method SlotIpmbRequest which enables the applications to +communicate with add-in cards. + +This is submitted in down stream because SlotIpmbRequest uses hold and +unhold mux kernel patches which are downstream only patches. + +Tested: + +busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb +/xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb SlotIpmbRequest +"yyyyyay" <valid_addressType> <valid_slot> <valid_slaveAddr> <valid_netFun> <valid_cmd> <data> // method call +(iyyyyay) 0 7 0 1 0 15 0 0 0 0 2 12 87 1 0 0 0 0 0 0 0 // success + +busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb +/xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb SlotIpmbRequest +"yyyyyay" <valid_addressType> <invalid_slot> <valid_slaveAddr> <valid_netFun> <valid_cmd> <data> // method call +(iyyyyay) 4 0 0 0 0 0 // failure + +busctl call xyz.openbmc_project.Ipmi.Channel.Ipmb +/xyz/openbmc_project/Ipmi/Channel/Ipmb org.openbmc.Ipmb SlotIpmbRequest +"yyyyyay" <valid_addressType> <valid_slot> <invalid_slaveAddr> <valid_netFun> <valid_cmd> <data> // method call +(iyyyyay) 4 0 0 0 0 0 // failure + +//This ipmi command internally calls the dbus method SlotIpmbRequest. +ipmitool raw 0x3e 0x51 0 0x01 0xb0 0x6 1 +00 00 00 00 00 02 0c 57 01 00 00 00 00 00 00 00 //success + +Note: Tested for all possible negative test cases and it works fine. + +Signed-off-by: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@intel.com> +--- + CMakeLists.txt | 2 +- + include/linux/i2c.h | 159 +++++++++++++++++++++++++++++++ + ipmb-channels.json | 6 ++ + ipmbbridged.cpp | 221 +++++++++++++++++++++++++++++++++++++++++++- + ipmbbridged.hpp | 8 +- + 5 files changed, 392 insertions(+), 4 deletions(-) + create mode 100644 include/linux/i2c.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 4acdccf..3484a58 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -8,7 +8,7 @@ set (CMAKE_CXX_STANDARD_REQUIRED ON) + #set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +-include_directories (${CMAKE_CURRENT_SOURCE_DIR}) ++include_directories (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) + find_package (Boost REQUIRED) + include_directories (${Boost_INCLUDE_DIRS}) + add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +new file mode 100644 +index 0000000..a1db9b1 +--- /dev/null ++++ b/include/linux/i2c.h +@@ -0,0 +1,159 @@ ++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ ++/* ------------------------------------------------------------------------- */ ++/* */ ++/* i2c.h - definitions for the i2c-bus interface */ ++/* */ ++/* ------------------------------------------------------------------------- */ ++/* Copyright (C) 1995-2000 Simon G. Vogl ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ++ MA 02110-1301 USA. */ ++/* ------------------------------------------------------------------------- */ ++ ++/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and ++ Frodo Looijaard <frodol@dds.nl> */ ++ ++#ifndef _UAPI_LINUX_I2C_H ++#define _UAPI_LINUX_I2C_H ++ ++#include <linux/types.h> ++ ++/** ++ * struct i2c_msg - an I2C transaction segment beginning with START ++ * @addr: Slave address, either seven or ten bits. When this is a ten ++ * bit address, I2C_M_TEN must be set in @flags and the adapter ++ * must support I2C_FUNC_10BIT_ADDR. ++ * @flags: I2C_M_RD is handled by all adapters. No other flags may be ++ * provided unless the adapter exported the relevant I2C_FUNC_* ++ * flags through i2c_check_functionality(). ++ * @len: Number of data bytes in @buf being read from or written to the ++ * I2C slave address. For read transactions where I2C_M_RECV_LEN ++ * is set, the caller guarantees that this buffer can hold up to ++ * 32 bytes in addition to the initial length byte sent by the ++ * slave (plus, if used, the SMBus PEC); and this value will be ++ * incremented by the number of block data bytes received. ++ * @buf: The buffer into which data is read, or from which it's written. ++ * ++ * An i2c_msg is the low level representation of one segment of an I2C ++ * transaction. It is visible to drivers in the @i2c_transfer() procedure, ++ * to userspace from i2c-dev, and to I2C adapter drivers through the ++ * @i2c_adapter.@master_xfer() method. ++ * ++ * Except when I2C "protocol mangling" is used, all I2C adapters implement ++ * the standard rules for I2C transactions. Each transaction begins with a ++ * START. That is followed by the slave address, and a bit encoding read ++ * versus write. Then follow all the data bytes, possibly including a byte ++ * with SMBus PEC. The transfer terminates with a NAK, or when all those ++ * bytes have been transferred and ACKed. If this is the last message in a ++ * group, it is followed by a STOP. Otherwise it is followed by the next ++ * @i2c_msg transaction segment, beginning with a (repeated) START. ++ * ++ * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then ++ * passing certain @flags may have changed those standard protocol behaviors. ++ * Those flags are only for use with broken/nonconforming slaves, and with ++ * adapters which are known to support the specific mangling options they ++ * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR). ++ */ ++struct i2c_msg { ++ __u16 addr; /* slave address */ ++ __u16 flags; ++#define I2C_M_RD 0x0001 /* read data, from slave to master */ ++ /* I2C_M_RD is guaranteed to be 0x0001! */ ++#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ ++#define I2C_M_HOLD 0x0100 /* for holding a mux path */ ++#define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */ ++ /* makes only sense in kernelspace */ ++ /* userspace buffers are copied anyway */ ++#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ ++#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ ++#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ ++#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ ++#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ ++#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ ++ __u16 len; /* msg length */ ++ __u8 *buf; /* pointer to msg data */ ++}; ++ ++/* To determine what functionality is present */ ++ ++#define I2C_FUNC_I2C 0x00000001 ++#define I2C_FUNC_10BIT_ADDR 0x00000002 ++#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */ ++#define I2C_FUNC_SMBUS_PEC 0x00000008 ++#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */ ++#define I2C_FUNC_SLAVE 0x00000020 ++#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ ++#define I2C_FUNC_SMBUS_QUICK 0x00010000 ++#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 ++#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 ++#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 ++#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 ++#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 ++#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 ++#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 ++#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 ++#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 ++#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ ++#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ ++#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000 ++ ++#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ ++ I2C_FUNC_SMBUS_WRITE_BYTE) ++#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_BYTE_DATA) ++#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_WORD_DATA) ++#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) ++#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) ++ ++#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ ++ I2C_FUNC_SMBUS_BYTE | \ ++ I2C_FUNC_SMBUS_BYTE_DATA | \ ++ I2C_FUNC_SMBUS_WORD_DATA | \ ++ I2C_FUNC_SMBUS_PROC_CALL | \ ++ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ ++ I2C_FUNC_SMBUS_I2C_BLOCK | \ ++ I2C_FUNC_SMBUS_PEC) ++ ++/* ++ * Data for SMBus Messages ++ */ ++#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ ++union i2c_smbus_data { ++ __u8 byte; ++ __u16 word; ++ __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ ++ /* and one more for user-space compatibility */ ++}; ++ ++/* i2c_smbus_xfer read or write markers */ ++#define I2C_SMBUS_READ 1 ++#define I2C_SMBUS_WRITE 0 ++ ++/* SMBus transaction types (size parameter in the above functions) ++ Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ ++#define I2C_SMBUS_QUICK 0 ++#define I2C_SMBUS_BYTE 1 ++#define I2C_SMBUS_BYTE_DATA 2 ++#define I2C_SMBUS_WORD_DATA 3 ++#define I2C_SMBUS_PROC_CALL 4 ++#define I2C_SMBUS_BLOCK_DATA 5 ++#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 ++#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ ++#define I2C_SMBUS_I2C_BLOCK_DATA 8 ++ ++#endif /* _UAPI_LINUX_I2C_H */ +diff --git a/ipmb-channels.json b/ipmb-channels.json +index 0876db7..ff570c6 100644 +--- a/ipmb-channels.json ++++ b/ipmb-channels.json +@@ -11,6 +11,12 @@ + "slave-path": "/dev/ipmb-0", + "bmc-addr": 32, + "remote-addr": 88 ++ }, ++ { ++ "type": "slot-ipmb", ++ "slave-path": "/dev/ipmb-6", ++ "bmc-addr": 18, ++ "remote-addr": 176 + } + ] + } +diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp +index 3bf8469..6d1be04 100644 +--- a/ipmbbridged.cpp ++++ b/ipmbbridged.cpp +@@ -18,6 +18,11 @@ + #include "ipmbdefines.hpp" + #include "ipmbutils.hpp" + ++#include <i2c/smbus.h> ++#include <linux/i2c-dev.h> ++#include <linux/i2c.h> ++#include <sys/ioctl.h> ++ + #include <boost/algorithm/string/replace.hpp> + #include <boost/asio/write.hpp> + #include <filesystem> +@@ -40,7 +45,8 @@ auto conn = std::make_shared<sdbusplus::asio::connection>(io); + static std::list<IpmbChannel> ipmbChannels; + static const std::unordered_map<std::string, ipmbChannelType> + ipmbChannelTypeMap = {{"me", ipmbChannelType::me}, +- {"ipmb", ipmbChannelType::ipmb}}; ++ {"ipmb", ipmbChannelType::ipmb}, ++ {"slot-ipmb", ipmbChannelType::slot_ipmb}}; + + /** + * @brief Ipmb request class methods +@@ -555,7 +561,10 @@ int IpmbChannel::ipmbChannelInit(const char *ipmbI2cSlave) + { + std::string deviceFileName = + "/sys/bus/i2c/devices/i2c-" + busStr + "/new_device"; +- std::string para = "ipmb-dev 0x1010"; // init with BMC addr 0x20 ++ std::ostringstream param; ++ param << "ipmb-dev 0x" << std::hex ++ << static_cast<uint16_t>(0x1000 | (ipmbBmcSlaveAddress >> 1)); ++ std::string para(param.str()); + std::fstream deviceFile; + deviceFile.open(deviceFileName, std::ios::out); + if (!deviceFile.good()) +@@ -711,6 +720,171 @@ void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd) + } + } + ++class Mux ++{ ++ public: ++ Mux(const std::string &path) : heldMux(false) ++ { ++ fd = open(path.c_str(), O_RDWR | O_NONBLOCK); ++ } ++ ~Mux() ++ { ++ if (heldMux) ++ { ++ if (unholdMux() < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error while unholding the bus"); ++ } ++ } ++ if (!(fd < 0)) ++ { ++ close(fd); ++ } ++ } ++ ++ int transferAndHoldMux(const uint8_t slaveAddr, uint8_t *buffer, ++ const uint8_t len, uint16_t timeout) ++ { ++ if (!isMuxFdOpen()) ++ { ++ return -1; ++ } ++ struct i2c_msg holdmsg[2] = { ++ {slaveAddr, 0, len, buffer}, ++ {0, I2C_M_HOLD, sizeof(timeout), (uint8_t *)&timeout}}; ++ ++ struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg[0], 2}; ++ ++ int retVal = ioctl(fd, I2C_RDWR, &msgrdwr); ++ if (retVal >= 0) ++ { ++ heldMux = true; ++ } ++ return retVal; ++ } ++ ++ bool isMuxFdOpen() ++ { ++ if (fd < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error while opening the mux device file"); ++ return false; ++ } ++ return true; ++ } ++ ++ private: ++ int unholdMux() ++ { ++ if (!isMuxFdOpen()) ++ { ++ return -1; ++ } ++ uint16_t holdtimeout = 0; // unhold the bus ++ ++ struct i2c_msg holdmsg = {0, I2C_M_HOLD, sizeof(holdtimeout), ++ (uint8_t *)&holdtimeout}; ++ ++ struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg, 1}; ++ ++ return ioctl(fd, I2C_RDWR, &msgrdwr); ++ } ++ ++ int fd; ++ bool heldMux; ++}; ++ ++std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> ++ IpmbChannel::slotRequestAdd(boost::asio::yield_context &yield, ++ std::shared_ptr<IpmbRequest> request, ++ const uint8_t pcieSlot) ++{ ++ makeRequestValid(request); ++ std::filesystem::path p = ++ "/dev/i2c-mux/PCIE_Mux/Pcie_Slot_" + std::to_string(pcieSlot); ++ ++ if (!std::filesystem::exists(p) || !std::filesystem::is_symlink(p)) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "does not exist or not a symlink ", ++ phosphor::logging::entry("File:%s", p.c_str())); ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ ++ Mux mux(p); ++ if (!mux.isMuxFdOpen()) ++ { ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ ++ std::vector<uint8_t> buffer(0); ++ if (request->ipmbToi2cConstruct(buffer) != 0) ++ { ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ ++ uint8_t size = buffer.size(); ++ ++ const uint8_t slaveAddrIndex = 1; ++ const uint8_t slotIpmbHeader = 2; ++ ++ for (int i = 0; i < ipmbNumberOfTries; i++) ++ { ++ boost::system::error_code ec; ++ int i2cRetryCnt = 0; ++ do ++ { ++ if (mux.transferAndHoldMux( ++ buffer[slaveAddrIndex] >> 1, buffer.data() + slotIpmbHeader, ++ size - slotIpmbHeader, ipmbRequestRetryTimeout) >= 0) ++ { ++ break; ++ } ++ ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error sending slot IPMB command"); ++ i2cRetryCnt++; ++ } while (i2cRetryCnt < ipmbI2cNumberOfRetries); ++ ++ if (i2cRetryCnt == ipmbI2cNumberOfRetries) ++ { ++ std::string msgToLog = ++ "slotRequestAdd: Sent to I2C failed after retries." ++ " busId=" + ++ std::to_string(ipmbBusId) + ", error=" + ec.message(); ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ msgToLog.c_str()); ++ makeRequestInvalid(*request); ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ ++ request->timer->expires_after( ++ std::chrono::milliseconds(ipmbRequestRetryTimeout)); ++ request->timer->async_wait(yield[ec]); ++ ++ if (ec && ec != boost::asio::error::operation_aborted) ++ { ++ // unexpected error - invalidate request and return generic error ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "requestAdd: async_wait error"); ++ makeRequestInvalid(*request); ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ ++ if (request->state == ipmbRequestState::matched) ++ { ++ // matched response, send it to client application ++ makeRequestInvalid(*request); ++ return request->returnMatchedResponse(); ++ } ++ } ++ ++ makeRequestInvalid(*request); ++ return returnStatus(ipmbResponseStatus::timeout); ++} ++ + std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> + IpmbChannel::requestAdd(boost::asio::yield_context &yield, + std::shared_ptr<IpmbRequest> request) +@@ -848,6 +1022,47 @@ static int initializeChannels() + return 0; + } + ++auto slotIpmbHandleRequest = ++ [](boost::asio::yield_context yield, uint8_t addressType, ++ uint8_t slotNumber, uint8_t targetSlaveAddr, uint8_t netfn, uint8_t cmd, ++ std::vector<uint8_t> dataReceived) { ++ uint8_t lun = 0; // No support for lun in slot IPMB ++ IpmbChannel *channel = ++ getChannel(static_cast<uint8_t>(ipmbChannelType::slot_ipmb)); ++ if (channel == nullptr) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "slotIpmbHandleRequest: Slot IPMB channel does not exist"); ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ ++ // check outstanding request list for valid sequence number ++ uint8_t seqNum = 0; ++ bool seqValid = channel->seqNumGet(seqNum); ++ if (!seqValid) ++ { ++ phosphor::logging::log<phosphor::logging::level::WARNING>( ++ "slotIpmbHandleRequest: cannot add more requests to the list"); ++ return returnStatus(ipmbResponseStatus::busy); ++ } ++ ++ uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress(); ++ uint8_t rqSlaveAddress = targetSlaveAddr; ++ ++ // construct the request to add it to outstanding request list ++ std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>( ++ rqSlaveAddress, netfn, ipmbRsLun, bmcSlaveAddress, seqNum, lun, cmd, ++ dataReceived); ++ ++ if (!request->timer) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "slotIpmbHandleRequest: timer object does not exist"); ++ return returnStatus(ipmbResponseStatus::error); ++ } ++ return channel->slotRequestAdd(yield, request, slotNumber); ++ }; ++ + auto ipmbHandleRequest = [](boost::asio::yield_context yield, + uint8_t reqChannel, uint8_t netfn, uint8_t lun, + uint8_t cmd, std::vector<uint8_t> dataReceived) { +@@ -994,6 +1209,8 @@ int main(int argc, char *argv[]) + server.add_interface(ipmbObj, ipmbDbusIntf); + + ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest)); ++ ipmbIface->register_method("SlotIpmbRequest", ++ std::move(slotIpmbHandleRequest)); + ipmbIface->initialize(); + + if (initializeChannels() < 0) +diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp +index 052c193..c79ac63 100644 +--- a/ipmbbridged.hpp ++++ b/ipmbbridged.hpp +@@ -155,7 +155,8 @@ enum class ipmbRequestState + enum class ipmbChannelType + { + ipmb = 0, +- me = 1 ++ me = 1, ++ slot_ipmb = 2 + }; + + /** +@@ -293,6 +294,11 @@ class IpmbChannel + void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer, + size_t retriesAttempted); + ++ std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> ++ slotRequestAdd(boost::asio::yield_context &yield, ++ std::shared_ptr<IpmbRequest> requestToSend, ++ const uint8_t pcieSlot); ++ + std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> + requestAdd(boost::asio::yield_context &yield, + std::shared_ptr<IpmbRequest> requestToSend); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json new file mode 100644 index 000000000..2d77aa6e7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb/ipmb-channels.json @@ -0,0 +1,22 @@ +{ + "channels": [ + { + "type": "me", + "slave-path": "/dev/ipmb-5", + "bmc-addr": 32, + "remote-addr": 44 + }, + { + "type": "ipmb", + "slave-path": "/dev/ipmb-13", + "bmc-addr": 32, + "remote-addr": 32 + }, + { + "type": "slot-ipmb", + "slave-path": "/dev/ipmb-6", + "bmc-addr": 18, + "remote-addr": 176 + } + ] +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend new file mode 100644 index 000000000..33392f3c1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend @@ -0,0 +1,11 @@ +SRC_URI = "git://github.com/openbmc/ipmbbridge.git" +SRCREV = "8fe0abe6d9f69f735e93d7055687fce4b56e80bf" +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += "file://0001-Add-dbus-method-SlotIpmbRequest.patch \ + file://ipmb-channels.json \ + " + +do_install_append() { + install -D ${WORKDIR}/ipmb-channels.json \ + ${D}/usr/share/ipmbbridge +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules new file mode 100644 index 000000000..0a64b58db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules @@ -0,0 +1,2 @@ +KERNEL=="ipmi-kcs3", SYMLINK+="ipmi_kcs3" +KERNEL=="ipmi-kcs4", SYMLINK+="ipmi_kcs4" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend new file mode 100644 index 000000000..cc9f2d025 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}" + +# Default kcs device is ipmi-kcs3; this is SMS. +# Add SMM kcs device instance + +# Replace the '-' to '_', since Dbus object/interface names do not allow '-'. +KCS_DEVICE = "ipmi_kcs3" +SMM_DEVICE = "ipmi_kcs4" +SYSTEMD_SERVICE_${PN}_append = " ${PN}@${SMM_DEVICE}.service " + +SRC_URI = "git://github.com/openbmc/kcsbridge.git" +SRCREV = "3b170152ddc967f270939f4c351be987c451f0ca" + +SRC_URI += "file://99-ipmi-kcs.rules" + +do_install_append() { + install -d ${D}${base_libdir}/udev/rules.d + install -m 0644 ${WORKDIR}/99-ipmi-kcs.rules ${D}${base_libdir}/udev/rules.d/ +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch new file mode 100644 index 000000000..867b3aba6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch @@ -0,0 +1,40 @@ +From 0fd38eb0a155cb11ff5a5452087f68c46d12111b Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Thu, 28 Mar 2019 18:10:40 +0800 +Subject: [PATCH] Change Authentication Parameter + +Seprate D-bus interface Authentication to forceAuthentication, +forceEncryption, Privilege according to the related change in +sol-dbus-interface. + +Tested By: +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0xc2 +The parameters has been changed to the request data in above command. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + sol/sol_manager.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp +index de36723..0bd837e 100644 +--- a/sol/sol_manager.cpp ++++ b/sol/sol_manager.cpp +@@ -195,8 +195,12 @@ void Manager::updateSOLParameter() + + enable = std::get<bool>(properties["Enable"]); + ++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]); ++ ++ forceAuth = std::get<bool>(properties["ForceAuthentication"]); ++ + solMinPrivilege = static_cast<session::Privilege>( +- std::get<uint8_t>(properties["Authentication"])); ++ std::get<uint8_t>(properties["Privilege"])); + + accumulateInterval = + std::get<uint8_t>((properties["AccumulateIntervalMS"])) * +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch new file mode 100644 index 000000000..0ad625a1f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch @@ -0,0 +1,39 @@ +From 6fc55bb689272d34ff6616cdd4b24367ea39c749 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Mon, 2 Jul 2018 15:51:52 +0800 +Subject: [PATCH] Modify dbus namespace of chassis control for guid.cpp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Switch chassis control service namespace for guid.cpp from “org” to “xyz”, +to compatible with new intel-chassis services + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + command/guid.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: phosphor-net-ipmid.clean/command/guid.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/command/guid.cpp ++++ phosphor-net-ipmid.clean/command/guid.cpp +@@ -21,7 +21,8 @@ namespace command + + std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr); + +-static constexpr auto guidObjPath = "/org/openbmc/control/chassis0"; ++static constexpr auto guidObjPath = ++ "/xyz/openbmc_project/Chassis/Control/Chassis0"; + static constexpr auto propInterface = "org.freedesktop.DBus.Properties"; + + Guid getSystemGUID() +@@ -31,7 +32,7 @@ Guid getSystemGUID() + Guid guid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; + +- constexpr auto chassisIntf = "org.openbmc.control.Chassis"; ++ constexpr auto chassisIntf = "xyz.openbmc_project.Chassis.Control.Chassis"; + + sd_bus_message* reply = nullptr; + sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch new file mode 100644 index 000000000..da173704b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch @@ -0,0 +1,336 @@ +From a36f181163974b2da0a954fc97a89fb2cdbd7287 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Tue, 30 Apr 2019 05:35:31 +0800 +Subject: [PATCH] Remove Get SOL Config Command from Netipmid + +Since Get SOL Config Parameter command already exists in host-ipmid, and +can be shared to net channel, remove this command from net-ipmid. + +Tested: +Run ipmitool -I lanplus -H xxx -U root -P 0penBmc sol info, the command +returns the same result as ipmitool sol info as below. +Info: SOL parameter 'Nonvolatile Bitrate (5)' not supported +Info: SOL parameter 'Volatile Bitrate (6)' not supported +Info: SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e +Set in progress : set-complete +Enabled : true +Force Encryption : true +Force Authentication : true +Privilege Level : USER +Character Accumulate Level (ms) : 100 +Character Send Threshold : 1 +Retry Count : 3 +Retry Interval (ms) : 100 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Payload Channel : 14 (0x0e) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + command/sol_cmds.cpp | 91 ---------------------------- + command/sol_cmds.hpp | 168 --------------------------------------------------- + sol_module.cpp | 6 -- + 3 files changed, 265 deletions(-) + +diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp +index 804b5ea..8b2d041 100644 +--- a/command/sol_cmds.cpp ++++ b/command/sol_cmds.cpp +@@ -65,97 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) + outPayload); + } + +-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler) +-{ +- std::vector<uint8_t> outPayload(sizeof(GetConfParamsResponse)); +- auto request = +- reinterpret_cast<const GetConfParamsRequest*>(inPayload.data()); +- auto response = reinterpret_cast<GetConfParamsResponse*>(outPayload.data()); +- response->completionCode = IPMI_CC_OK; +- response->paramRev = parameterRevision; +- +- if (request->getParamRev) +- { +- return outPayload; +- } +- +- switch (static_cast<Parameter>(request->paramSelector)) +- { +- case Parameter::PROGRESS: +- { +- outPayload.push_back( +- std::get<sol::Manager&>(singletonPool).progress); +- break; +- } +- case Parameter::ENABLE: +- { +- outPayload.push_back(std::get<sol::Manager&>(singletonPool).enable); +- break; +- } +- case Parameter::AUTHENTICATION: +- { +- Auth value{0}; +- +- value.encrypt = std::get<sol::Manager&>(singletonPool).forceEncrypt; +- value.auth = std::get<sol::Manager&>(singletonPool).forceAuth; +- value.privilege = static_cast<uint8_t>( +- std::get<sol::Manager&>(singletonPool).solMinPrivilege); +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::ACCUMULATE: +- { +- Accumulate value{0}; +- +- value.interval = std::get<sol::Manager&>(singletonPool) +- .accumulateInterval.count() / +- sol::accIntervalFactor; +- value.threshold = +- std::get<sol::Manager&>(singletonPool).sendThreshold; +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::RETRY: +- { +- Retry value{0}; +- +- value.count = std::get<sol::Manager&>(singletonPool).retryCount; +- value.interval = +- std::get<sol::Manager&>(singletonPool).retryInterval.count() / +- sol::retryIntervalFactor; +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::PORT: +- { +- auto port = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); +- auto buffer = reinterpret_cast<const uint8_t*>(&port); +- +- std::copy_n(buffer, sizeof(port), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::CHANNEL: +- { +- outPayload.push_back( +- std::get<sol::Manager&>(singletonPool).channel); +- break; +- } +- case Parameter::NVBITRATE: +- case Parameter::VBITRATE: +- default: +- response->completionCode = ipmiCCParamNotSupported; +- } +- +- return outPayload; +-} +- + } // namespace command + + } // namespace sol +diff --git a/command/sol_cmds.hpp b/command/sol_cmds.hpp +index 182b73e..10cbf25 100644 +--- a/command/sol_cmds.hpp ++++ b/command/sol_cmds.hpp +@@ -62,174 +62,6 @@ struct ActivatingRequest + */ + void activating(uint8_t payloadInstance, uint32_t sessionID); + +-/** @enum Parameter +- * +- * SOL parameters are volatile, they are initialized by the SOL manager. +- * They can be read using Get SOL configuration parameters command and updated +- * using Set SOL configuration parameters command. +- */ +-enum class Parameter +-{ +- PROGRESS, //!< Set In Progress. +- ENABLE, //!< SOL Enable. +- AUTHENTICATION, //!< SOL Authentication. +- ACCUMULATE, //!< Character Accumulate Interval & Send Threshold. +- RETRY, //!< SOL Retry. +- NVBITRATE, //!< SOL non-volatile bit rate. +- VBITRATE, //!< SOL volatile bit rate. +- CHANNEL, //!< SOL payload channel. +- PORT, //!< SOL payload port. +-}; +- +-constexpr uint8_t progressMask = 0x03; +-constexpr uint8_t enableMask = 0x01; +- +-/** @struct Auth +- * +- * SOL authentication parameter. +- */ +-struct Auth +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t privilege : 4; //!< SOL privilege level. +- uint8_t reserved : 2; //!< Reserved. +- uint8_t auth : 1; //!< Force SOL payload Authentication. +- uint8_t encrypt : 1; //!< Force SOL payload encryption. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t encrypt : 1; //!< Force SOL payload encryption. +- uint8_t auth : 1; //!< Force SOL payload Authentication. +- uint8_t reserved : 2; //!< Reserved. +- uint8_t privilege : 4; //!< SOL privilege level. +-#endif +-} __attribute__((packed)); +- +-/** @struct Accumulate +- * +- * Character accumulate interval & Character send threshold. +- */ +-struct Accumulate +-{ +- uint8_t interval; //!< Character accumulate interval. +- uint8_t threshold; //!< Character send threshold. +-} __attribute__((packed)); +- +-constexpr uint8_t retryCountMask = 0x07; +- +-/** @struct Retry +- * +- * SOL retry count and interval. +- */ +-struct Retry +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t count : 3; //!< SOL retry count. +- uint8_t reserved : 5; //!< Reserved. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t reserved : 5; //!< Reserved. +- uint8_t count : 3; //!< SOL retry count. +-#endif +- +- uint8_t interval; //!< SOL retry interval. +-} __attribute__((packed)); +- +-constexpr uint8_t ipmiCCParamNotSupported = 0x80; +-constexpr uint8_t ipmiCCInvalidSetInProgress = 0x81; +-constexpr uint8_t ipmiCCWriteReadParameter = 0x82; +-constexpr uint8_t ipmiCCReadWriteParameter = 0x83; +-constexpr uint8_t parameterRevision = 0x11; +- +-/** @struct SetConfParamsRequest +- * +- * IPMI payload for Set SOL configuration parameters command request. +- */ +-struct SetConfParamsRequest +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t channelNumber : 4; //!< Channel number. +- uint8_t reserved : 4; //!< Reserved. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t reserved : 4; //!< Reserved. +- uint8_t channelNumber : 4; //!< Channel number. +-#endif +- +- uint8_t paramSelector; //!< Parameter selector. +- union +- { +- uint8_t value; //!< Represents one byte SOL parameters. +- struct Accumulate acc; //!< Character accumulate values. +- struct Retry retry; //!< Retry values. +- struct Auth auth; //!< Authentication parameters. +- }; +-} __attribute__((packed)); +- +-/** @struct SetConfParamsResponse +- * +- * IPMI payload for Set SOL configuration parameters command response. +- */ +-struct SetConfParamsResponse +-{ +- uint8_t completionCode; //!< Completion code. +-} __attribute__((packed)); +- +-/** @brief Set SOL configuration parameters command. +- * +- * @param[in] inPayload - Request data for the command. +- * @param[in] handler - Reference to the message handler. +- * +- * @return Response data for the command. +- */ +-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler); +- +-/** @struct GetConfParamsRequest +- * +- * IPMI payload for Get SOL configuration parameters command request. +- */ +-struct GetConfParamsRequest +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t channelNum : 4; //!< Channel number. +- uint8_t reserved : 3; //!< Reserved. +- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision +- uint8_t reserved : 3; //!< Reserved. +- uint8_t channelNum : 4; //!< Channel number. +-#endif +- +- uint8_t paramSelector; //!< Parameter selector. +- uint8_t setSelector; //!< Set selector. +- uint8_t blockSelector; //!< Block selector. +-} __attribute__((packed)); +- +-/** @struct GetConfParamsResponse +- * +- * IPMI payload for Get SOL configuration parameters command response. +- */ +-struct GetConfParamsResponse +-{ +- uint8_t completionCode; //!< Completion code. +- uint8_t paramRev; //!< Parameter revision. +-} __attribute__((packed)); +- +-/** @brief Get SOL configuration parameters command. +- * +- * @param[in] inPayload - Request data for the command. +- * @param[in] handler - Reference to the message handler. +- * +- * @return Response data for the command. +- */ +-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler); +- + } // namespace command + + } // namespace sol +diff --git a/sol_module.cpp b/sol_module.cpp +index 2b1fb46..6da82c0 100644 +--- a/sol_module.cpp ++++ b/sol_module.cpp +@@ -42,12 +42,6 @@ void registerCommands() + &getPayloadInfo, + session::Privilege::USER, + false}, +- // Get SOL Configuration Parameters +- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22}, +- &getConfParams, +- session::Privilege::USER, +- false}, + }; + + for (const auto& iter : commands) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf new file mode 100644 index 000000000..d2fb5ba04 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/10-nice-rules.conf @@ -0,0 +1,2 @@ +[Service] +Nice=-18 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend new file mode 100644 index 000000000..7fe91fd1f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend @@ -0,0 +1,30 @@ +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 = "d4a4bed525f79c39705fa526b20ab663bb2c2069" + +USERADD_PACKAGES = "${PN}" +# add a group called ipmi +GROUPADD_PARAM_${PN} = "ipmi " + +# Default rmcpp iface is eth0; channel 1 +# Add channel 2 instance (eth1) +RMCPP_EXTRA = "eth1" +SYSTEMD_SERVICE_${PN} += " \ + ${PN}@${RMCPP_EXTRA}.service \ + ${PN}@${RMCPP_EXTRA}.socket \ + " + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " file://10-nice-rules.conf \ + file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \ + file://0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch \ + " + +do_install_append() { + mkdir -p ${D}${sysconfdir}/systemd/system/phosphor-ipmi-net@.service.d/ + install -m 0644 ${WORKDIR}/10-nice-rules.conf ${D}${sysconfdir}/systemd/system/phosphor-ipmi-net@.service.d/ +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend new file mode 100644 index 000000000..72d991c7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb new file mode 100644 index 000000000..8a6911345 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb @@ -0,0 +1,19 @@ +SUMMARY = "Node Manager Proxy" +DESCRIPTION = "The Node Manager Proxy provides a simple interface for communicating \ +with Management Engine via IPMB" + +SRC_URI = "git://github.com/Intel-BMC/node-manager;protocol=ssh" +SRCREV = "1b243b3bfa5a3523a6ca9805626c8cf045146697" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} = "node-manager-proxy.service" + +DEPENDS = "sdbusplus \ + phosphor-logging \ + boost" + +S = "${WORKDIR}/git" +inherit cmake systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service new file mode 100644 index 000000000..51e59c614 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service @@ -0,0 +1,11 @@ +[Unit] +Description=turn off the ID LED when BMC is ready +Wants=multi-user.target +After=multi-user.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/id-led-off.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh new file mode 100755 index 000000000..b609fc0ea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh @@ -0,0 +1,12 @@ +#!/bin/sh +busctl set-property "xyz.openbmc_project.LED.GroupManager" \ +"/xyz/openbmc_project/led/groups/enclosure_identify" \ +"xyz.openbmc_project.Led.Group" "Asserted" b false + +busctl set-property "xyz.openbmc_project.LED.GroupManager" \ +"/xyz/openbmc_project/led/groups/enclosure_identify_blink" \ +"xyz.openbmc_project.Led.Group" "Asserted" b false + +busctl set-property "xyz.openbmc_project.LED.Controller.identify" \ +"/xyz/openbmc_project/led/physical/identify" \ +"xyz.openbmc_project.Led.Physical" "State" s "xyz.openbmc_project.Led.Physical.Action.Off" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb new file mode 100644 index 000000000..a1d20c2bc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb @@ -0,0 +1,24 @@ +SUMMARY = "Turn off the ID LED" +DESCRIPTION = "Script to turn off the ID LED after BMC is ready" + +S = "${WORKDIR}" +SRC_URI = "file://id-led-off.sh \ + file://id-led-off.service \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/id-led-off.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/id-led-off.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/id-led-off.sh ${D}/${bindir}/id-led-off.sh +} + +SYSTEMD_SERVICE_${PN} += " id-led-off.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb new file mode 100644 index 000000000..47c66ccb8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb @@ -0,0 +1,21 @@ +SUMMARY = "Phosphor LED Group Management for Intel" +PR = "r1" + +inherit obmc-phosphor-utils +inherit native + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES += "virtual/phosphor-led-manager-config-native" + +SRC_URI += "file://led.yaml" +S = "${WORKDIR}" + +# Overwrite the example led layout yaml file prior +# to building the phosphor-led-manager package +do_install() { + SRC=${S} + DEST=${D}${datadir}/phosphor-led-manager + install -D ${SRC}/led.yaml ${DEST}/led.yaml +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml new file mode 100644 index 000000000..1605b8e6b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml @@ -0,0 +1,80 @@ +bmc_booted: + +power_on: + +status_ok: + status_green: + Action: 'On' + status_amber: + Action: 'Off' + +status_degraded: + status_green: + Action: 'Blink' + DutyOn: 50 + Period: 1000 + status_amber: + Action: 'Off' + +status_non_critical: + status_green: + Action: 'Off' + status_amber: + Action: 'Blink' + DutyOn: 50 + Period: 1000 + +status_critical: + status_green: + Action: 'Off' + status_amber: + Action: 'On' + +enclosure_identify: + identify: + Action: 'On' + +enclosure_identify_blink: + identify: + Action: 'Blink' + +cpu0_fault: + cpu0fault: + Action: 'On' + +cpu1_fault: + cpu1fault: + Action: 'On' + +fan1_fault: + fan1_fault: + Action: 'On' + +fan2_fault: + fan2_fault: + Action: 'On' + +fan3_fault: + fan3_fault: + Action: 'On' + +fan4_fault: + fan4_fault: + Action: 'On' + +fan5_fault: + fan5_fault: + Action: 'On' + +fan6_fault: + fan6_fault: + Action: 'On' + +fan7_fault: + fan7_fault: + Action: 'On' + +fan8_fault: + fan8_fault: + Action: 'On' + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb new file mode 100644 index 000000000..c47a581f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb @@ -0,0 +1,27 @@ +SUMMARY = "Multi-node Non-legacy" +DESCRIPTION = "New systemd target for non-legacy nodes on multi-node platform" + +inherit systemd + +SYSTEMD_SERVICE_${PN} = "multi-node-nl.target" +SYSTEMD_SERVICE_${PN} += "nonLegacyNode.service" + +S = "${WORKDIR}" +SRC_URI = "file://multi-node-nl.target \ + file://nonLegacyNode.service \ + file://nonLegacyNode.sh \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +RDEPENDS_${PN} = "bash" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${S}/nonLegacyNode.sh ${D}/${bindir}/nonLegacyNode.sh + + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/multi-node-nl.target ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/nonLegacyNode.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target new file mode 100644 index 000000000..32b50532f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target @@ -0,0 +1,4 @@ +[Unit] +Description=Target for non-legacy node in multi-node system +Documentation=man:systemd.special(7) + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service new file mode 100644 index 000000000..8e3d07ba4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service @@ -0,0 +1,9 @@ +[Unit] +Description=Non Legacy node + +[Service] +ExecStart=/usr/bin/nonLegacyNode.sh +Type=exec + +[Install] +WantedBy=multi-node-nl.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh new file mode 100755 index 000000000..28a6bbe2a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +PWM_FILE="/sys/class/hwmon/hwmon0/pwm" +FAN_SPEED=$((255 * 80 / 100)) + +set_fan_speed() { + local idx=0 + for ((idx=1; idx<=8; idx++)) + do + if [ -f $PWM_FILE$idx ]; then + echo $FAN_SPEED > $PWM_FILE$idx + fi + done +} + +$(set_fan_speed) + +#Stop power control service in NL mode +systemctl stop xyz.openbmc_project.Chassis.Control.Power.service + +export TERM=xterm +# Autologin root user to serial console (ttyS4) on boot +exec /sbin/agetty -a root -J -8 -L ttyS4 115200 $TERM diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend new file mode 100644 index 000000000..48f72ab36 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/peci/peci-pcie_%.bbappend @@ -0,0 +1,3 @@ +SRC_URI = "git://github.com/openbmc/peci-pcie" + +SRCREV = "d570dfd4f3a7c38b029f74a8194eeb3911b5f6a5" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb new file mode 100644 index 000000000..f1327dbbd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb @@ -0,0 +1,18 @@ +SUMMARY = "Phosphor U-Boot environment manager" +DESCRIPTION = "Daemon to read or write U-Boot environment variables" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +SRC_URI = "git://github.com/openbmc/phosphor-u-boot-env-mgr.git;protocol=ssh" + +SRCREV = "6707fc81f48634599df3fce764578d6d9661881f" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.U_Boot.Environment.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb new file mode 100644 index 000000000..6c930876f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb @@ -0,0 +1,16 @@ +SUMMARY = "libmctp_intel" +DESCRIPTION = "Implementation of MCTP(DMTF DSP0236)" + +SRC_URI = "git://github.com/Intel-BMC/libmctp.git;protocol=ssh" +SRCREV = "37ea118aa8653cc6220c4fd6da0224f0797f4bdc" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0 | GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=0d30807bb7a4f16d36e96b78f9ed8fae" + +inherit cmake + +DEPENDS += "i2c-tools" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb new file mode 100644 index 000000000..ee6fd12ee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libpldm-intel_git.bb @@ -0,0 +1,18 @@ +SUMMARY = "libpldm_intel" +DESCRIPTION = "Provides encode/decode APIs for PLDM specifications" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git/libpldm_intel" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +inherit cmake + +DEPENDS += " \ + gtest \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb new file mode 100644 index 000000000..b9d3c0ca4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-emulator.bb @@ -0,0 +1,30 @@ +SUMMARY = "MCTP Daemon" +DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=bcd9ada3a943f58551867d72893cc9ab" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git/mctp_emulator" + +PV = "1.0+git${SRCPV}" + +inherit cmake systemd + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += " \ + libmctp-intel \ + systemd \ + sdbusplus \ + phosphor-logging \ + boost \ + i2c-tools \ + cli11 \ + nlohmann-json \ + gtest \ + " + +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.mctp-emulator.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb new file mode 100644 index 000000000..afe199192 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctp-wrapper.bb @@ -0,0 +1,28 @@ +SUMMARY = "MCTP Wrapper Library" +DESCRIPTION = "Implementation of MCTP Wrapper Library" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=bcd9ada3a943f58551867d72893cc9ab" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git/mctp_wrapper" + +PV = "1.0+git${SRCPV}" + +inherit cmake systemd + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += " \ + libmctp-intel \ + systemd \ + sdbusplus \ + phosphor-logging \ + gtest \ + boost \ + phosphor-dbus-interfaces \ + " + +EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb new file mode 100644 index 000000000..96582c76e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb @@ -0,0 +1,34 @@ +SUMMARY = "MCTP Daemon" +DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${PN}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +OECMAKE_SOURCEPATH = "${S}/${PN}" + +inherit cmake systemd + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += " \ + libmctp-intel \ + systemd \ + sdbusplus \ + phosphor-logging \ + boost \ + i2c-tools \ + cli11 \ + nlohmann-json \ + gtest \ + phosphor-dbus-interfaces \ + udev \ + " +FILES_${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.mctpd@.service" +FILES_${PN} += "/usr/share/mctp/mctp_config.json" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb new file mode 100644 index 000000000..c36c0d926 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpwplus.bb @@ -0,0 +1,24 @@ +SUMMARY = "MCTP Wrapper Library Plus" +DESCRIPTION = "Implementation of MCTP Wrapper Library Plus" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=615045c30a05cde5c0e924854d43c327" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git/mctpwplus" + +PV = "1.0+git${SRCPV}" + +inherit cmake + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += " \ + systemd \ + sdbusplus \ + phosphor-logging \ + cli11 \ + " +EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb new file mode 100644 index 000000000..8a73394e5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/nvmemi-daemon.bb @@ -0,0 +1,17 @@ +SUMMARY = "NVMe MI Daemon" +DESCRIPTION = "Implementation of NVMe MI daemon" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +SRC_URI = "git://github.com/Intel-BMC/nvme-mi.git;protocol=ssh" +SRCREV = "832c63d3db86788859f4afb911840f5ba100d230" +S = "${WORKDIR}/git" +PV = "1.0+git${SRCPV}" + +inherit meson systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.nvme-mi.service" +DEPENDS = "boost sdbusplus systemd phosphor-logging mctpwplus googletest nlohmann-json" + +EXTRA_OEMESON = "-Dyocto_dep='enabled' -Dtests='enabled'" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb new file mode 100644 index 000000000..4a2a33878 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pldmd.bb @@ -0,0 +1,31 @@ +SUMMARY = "PLDM Requester Stack" +DESCRIPTION = "Implementation of PLDM specifications" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +SRC_URI += "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git/pldmd" + +PV = "1.0+git${SRCPV}" + +inherit cmake systemd + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += " \ + libpldm-intel \ + mctp-wrapper \ + systemd \ + sdbusplus \ + phosphor-logging \ + gtest \ + boost \ + phosphor-dbus-interfaces \ + mctpwplus \ + " + +FILES_${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.pldmd.service" +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.pldmd.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb new file mode 100644 index 000000000..134cd9fdd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/pmci-launcher.bb @@ -0,0 +1,23 @@ +SUMMARY = "PMCI Launcher" +DESCRIPTION = "Support to launch pmci services on-demand" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "196f057fe8efea8080ec71ad4159df0675dd6a4c" + +S = "${WORKDIR}/git/pmci_launcher" + +PV = "1.0+git${SRCPV}" + +inherit cmake systemd + +DEPENDS += " \ + systemd \ + sdbusplus \ + phosphor-logging \ + boost \ + " +FILES_${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.pmci-launcher.service" +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.pmci-launcher.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend new file mode 100644 index 000000000..410775ee3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI = "file://init" + +RDEPENDS_${PN} += "bash" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init new file mode 100755 index 000000000..2065f94ee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init @@ -0,0 +1,268 @@ +#!/bin/bash + +# Copyright 2017-2019 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# provide a couple of places in the RO root filesystem +# that can be made RW with an overlayfs + +log() { + [ -c /dev/kmsg ] && echo "init: $*" > /dev/kmsg + echo "init: $*" +} + +# start with /proc and /tmp mounted +[ -e /proc/mounts ] || mount -t proc proc /proc +# FIXME: add size limits to /tmp +grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp +grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys + +# fix up /srv to be RW +mkdir -p /tmp/srv +mount --bind /tmp/srv /srv + +if grep -q debug-init /proc/cmdline; then + exec > /tmp/init.log 2>&1 + set -x + env +else + # Suppress any stray output but we want to see any errors + exec >/dev/null 2>/dev/kmsg +fi + +# list of things that need to be rw at boot +NV_OVERLAYS="/etc /var /home" + +# place to mount the overlay backing store +OVERLAY_MNT=/tmp/.overlay +# OVERLAY_SIZE=16384 +# place to mount NV +RWFS_MNT=/tmp/.rwfs +# NV overlay storage +OVERLAY_SYNC=${RWFS_MNT}/.overlay + +if grep -q "$RWFS_MNT" /proc/mounts; then + # quit - we have already run + exit 0 +fi +mkdir -p "$OVERLAY_MNT" +# TODO: remount the overlay with a size limit? +# mount -t tmpfs -o rw,size=${OVERLAY_SIZE} oltmp ${OVERLAY_MNT} + +mtd_by_name() { + local name="$1" + echo "/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)" +} + +mtdnum_by_name() { + local name="$1" + grep "$name" /proc/mtd | cut -c 4 +} + +NV_MTD=rwfs + +nvrw() { + local p="$1" + # Clear the work dir doing overlay mount + rm -rf "${OVERLAY_MNT}${p}.work" + mkdir -p "${OVERLAY_MNT}${p}" "${OVERLAY_MNT}${p}.work" + local mname + mname=$(echo "ol${p}" | sed 's,/,,g') + local opts="lowerdir=${p},upperdir=${OVERLAY_MNT}${p},workdir=${OVERLAY_MNT}${p}.work,sync" + mount -t overlay -o "$opts" "$mname" "$p" +} + +targeted_clean() { + log "restore-defaults: targeted_clean" + # Do not delete FRU info, ssh/ssl certs, or machine-id + ( + cd "${OVERLAY_SYNC}/etc" || exit + find . ! -regex '.*/\(ssl\|dropbear\|machine-id\|fru\).*' -a ! -path '.' \ + -exec rm -rf {} + + ) + # nothing should be in the workdir, but clear it just in case + rm -rf "${OVERLAY_SYNC}/etc.work" + + # clean everything out of /home + rm -rf "${OVERLAY_SYNC}/home" "${OVERLAY_SYNC}/home.work" + + # clean everything out of /var + rm -rf "${OVERLAY_SYNC}/var" "${OVERLAY_SYNC}/var.work" + + echo "Files remaining: $(find $OVERLAY_SYNC/)" + sync +} + +full_clean() { + log "restore-defaults: full_clean" + local OVL='' + for OVL in $NV_OVERLAYS; do + rm -rf "${OVERLAY_SYNC}${OVL}" "${OVERLAY_SYNC}${OVL}.work" + done + sync +} + +jffs2_mount() { + mtd_name=$1 + mnt=$2 + mount -t jffs2 -o sync,ro mtd:"$mtd_name" "$mnt" +} + +reformat_jffs2_partition() { + local mtd_name="$1" + local mnt="$2" + # unmount the partition to reformat it + umount -f "$mnt" + flash_erase "$(mtd_by_name "$mtd_name")" 0 0 + # remount the JFFS2 + if ! jffs2_mount "$mtd_name" "$mnt"; then + log "Failed to mount reformatted NV volume; system unstable" + fi +} + +clear_ubenv() { + log "Clearing U-Boot environment" + flash_erase "$(mtd_by_name u-boot-env)" 0 0 +} + +# mount NV filesystem +mkdir -p "$RWFS_MNT" +if ! jffs2_mount "$NV_MTD" "$RWFS_MNT"; then + log "Failed to mount NV volume; attempting recovery" + reformat_jffs2_partition $NV_MTD $RWFS_MNT +fi + +# check for full factory reset: if so, format $NV_MTD_DEV +RESTORE_FLAG=$RWFS_MNT/.restore_op +if [ -f "$RESTORE_FLAG" ]; then + mount -o remount,rw "$RWFS_MNT" + restore_op=$(cat $RESTORE_FLAG) # read from NV + modified_on=$(stat -c %y $RESTORE_FLAG) # get last modified time + log "restore_op: $restore_op modified on: $modified_on" + # To rule out stale file mounted, Write unique, unused value 0x10 + # (last 2-bits are b00) before removing the file. + echo 16 > $RESTORE_FLAG + # set default value 0 if RESTORE_FLAG file was empty + restore_op=${restore_op:-0} + restore_op=$((restore_op & 3)) # mask off 2 bits + if [ $restore_op -eq 1 ]; then + targeted_clean + elif [ $restore_op -eq 2 ]; then + full_clean + clear_ubenv + elif [ $restore_op -eq 3 ]; then + log "restore-defaults: reformat" + reformat_jffs2_partition $NV_MTD $RWFS_MNT + clear_ubenv + fi + rm -f $RESTORE_FLAG + mount -o remount,ro "$RWFS_MNT" +fi + +# Restore the overlay saved in the sync +rsync -a --delete "${OVERLAY_SYNC}/" "${OVERLAY_MNT}" +log "Restored overlay from sync location" + +for FS in $NV_OVERLAYS; do + nvrw "$FS" +done + +# work around bug where /etc/machine-id will be mounted with a temporary file +# if rootfs is read-only and the file is empty +MACHINE_ID=/etc/machine-id +generate_machine_id() { + systemd-machine-id-setup + cp -pf "$MACHINE_ID" "${MACHINE_ID}_bkup" +} + +if [ ! -s "$MACHINE_ID" ]; then + # work around - Bug: Overlay fs fails for machine-id due to + # origin mismatch. Clean it up, from overlay fs before re-creating + # the same. + if [ -e "$OVERLAY_MNT$MACHINE_ID" ]; then + umount "/etc" + rm -f "$OVERLAY_MNT$MACHINE_ID" + nvrw "/etc" + # Restore the machine-id from backup, else generate it. + if [ -s "${MACHINE_ID}_bkup" ]; then + cp -pf "${MACHINE_ID}_bkup" "${MACHINE_ID}" + else + generate_machine_id + fi + log "Remounted /etc for machine-id origin mismatch" + else + generate_machine_id + fi +fi + +# mount persistent NV filesystem, where immortal settings live +SOFS_MNT=/var/sofs +if ! grep -q sofs /proc/mounts; then + mkdir -p $SOFS_MNT + SOFS_MTD=sofs + + # mount a JFFS2 on the partition + if ! jffs2_mount "$SOFS_MTD" "$SOFS_MNT"; then + log "Failed to mount SOFS volume; attempting recovery" + reformat_jffs2_partition $SOFS_MTD $SOFS_MNT + fi +fi + +log "Finished mounting nv and overlays" + + +# Detect the non-legacy node in cooper city and boot in to special mode. + +readonly COOPER_CITY=40 # Board id of cooper city + +is_nl_node() { + typeset -i nid1=$(gpioget $(gpiofind "FM_NODE_ID_1")) + typeset -i nid2=$(gpioget $(gpiofind "FM_NODE_ID_2")) + echo $((nid1|nid2)) +} + +read_board_id() { + local idx=0 + local result=0 + local value=0 + for ((idx=0; idx<6; idx++)) + do + typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N")) + value=$((value << idx)) + result=$((result | value)) + done + echo $result +} + +pfr_write() { + [ $# -ne 2 ] && return 1 + local PFR_BUS=4 + local PFR_ADDR=0x38 + local reg=$1 + local val=$2 + i2cset -y $PFR_BUS $PFR_ADDR "$reg" "$val" >&/dev/null +} + +board_id=$(read_board_id) +if [ "$board_id" -eq $COOPER_CITY ]; then + if [ "$(is_nl_node)" -ne 0 ]; then + systemctl set-default multi-node-nl.target + PFR_BMC_CHECKPOINT_REG=0xf + PFR_BMC_CHECKPOINT_COMPLETE=0x9 + pfr_write $PFR_BMC_CHECKPOINT_REG $PFR_BMC_CHECKPOINT_COMPLETE + fi +fi + +exec /lib/systemd/systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb new file mode 100644 index 000000000..7138e8628 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb @@ -0,0 +1,18 @@ +SUMMARY = "Provision mode daemon - RestrictionMode" +DESCRIPTION = "Daemon allows to configure RestrictionMode property" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/provisioning-mode-manager.git;protocol=ssh" + +SRCREV = "ea03e4e87f5d5f0d873624b46ebc3deabb8d6ebe" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.RestrictionMode.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb new file mode 100644 index 000000000..3fab0ae54 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb @@ -0,0 +1,23 @@ +SUMMARY = "Security Manager daemon to detect the security violation- ASD/ user management" +DESCRIPTION = "Daemon check for Remote debug enable and user account violation" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/security-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +inherit cmake systemd + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.SecurityManager.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + libgpiod \ + phosphor-logging \ + boost \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend new file mode 100644 index 000000000..e5c229ac7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend @@ -0,0 +1,4 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git" +SRCREV = "486e42e9db215070d631b7ac1f8f32537cb3bfe7" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service new file mode 100644 index 000000000..b8c3554ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service @@ -0,0 +1,10 @@ +[Unit] +Description= BMC Self-Test + +[Service] +Restart=always +ExecStart=/usr/bin/env selftest +SyslogIdentifier=selftest + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch new file mode 100644 index 000000000..33d35ec5e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-check-for-min-max-received-from-hwmon-files.patch @@ -0,0 +1,108 @@ +From 2516d67f8bb5ecd241b8dcdec3f8c58d0e3c4744 Mon Sep 17 00:00:00 2001 +From: Wojciech Dembinski <wojciech.dembinski@intel.com> +Date: Mon, 7 Dec 2020 19:23:10 +0100 +Subject: [PATCH] Add check for min/max received from hwmon files + +When hwmon reports incorrect min/max values or CPU Sensor cannot access +readings, it shall keep the last known good readings and not update +DBus with incorrect values. +This patch adds min < max verification check for the values received +from hwmon and removes check for power on/off in the case of a read +failure. + +Tested manually on a physical platform, test cases cover incorrect +max/min values and failing access to hwmon files. +SDR over IPMI can be fully received in the case of error. + +Signed-off-by: Wojciech Dembinski <wojciech.dembinski@intel.com> +Change-Id: Ia061f849b0f434812f822ed1902c8964d4c64b45 +--- + src/CPUSensor.cpp | 50 ++++++++++++++++++++++++----------------------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp +index 2356821..01f5eb6 100644 +--- a/src/CPUSensor.cpp ++++ b/src/CPUSensor.cpp +@@ -1,5 +1,5 @@ + /* +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2021 Intel Corporation + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -146,19 +146,22 @@ void CPUSensor::setupRead(void) + + void CPUSensor::updateMinMaxValues(void) + { ++ double newMin = std::numeric_limits<double>::quiet_NaN(); ++ double newMax = std::numeric_limits<double>::quiet_NaN(); ++ + const boost::container::flat_map< + std::string, + std::vector<std::tuple<const char*, std::reference_wrapper<double>, +- const char*>>> +- map = { ++ const char*, std::reference_wrapper<double>>>> ++ map = { ++ { ++ "cap", + { +- "cap", +- { +- std::make_tuple("cap_max", std::ref(maxValue), "MaxValue"), +- std::make_tuple("cap_min", std::ref(minValue), "MinValue"), +- }, ++ std::make_tuple("cap_max", std::ref(maxValue), "MaxValue", std::ref(newMax)), ++ std::make_tuple("cap_min", std::ref(minValue), "MinValue", std::ref(newMin)), + }, +- }; ++ }, ++ }; + + if (auto fileParts = splitFileName(path)) + { +@@ -168,26 +171,25 @@ void CPUSensor::updateMinMaxValues(void) + { + for (const auto& vectorItem : mapIt->second) + { +- auto& [suffix, oldValue, dbusName] = vectorItem; ++ auto& [suffix, oldValue, dbusName, newValue] = vectorItem; + auto attrPath = boost::replace_all_copy(path, fileItem, suffix); +- if (auto newVal = +- readFile(attrPath, CPUSensor::sensorScaleFactor)) ++ ++ if(auto tmp = readFile(attrPath, CPUSensor::sensorScaleFactor)) + { +- updateProperty(sensorInterface, oldValue, *newVal, +- dbusName); ++ newValue.get() = *tmp; + } + else + { +- if (isPowerOn()) +- { +- updateProperty(sensorInterface, oldValue, 0, dbusName); +- } +- else +- { +- updateProperty(sensorInterface, oldValue, +- std::numeric_limits<double>::quiet_NaN(), +- dbusName); +- } ++ newValue.get() = std::numeric_limits<double>::quiet_NaN(); ++ } ++ } ++ ++ if(std::isfinite(newMin) && std::isfinite(newMax) && (newMin < newMax)) ++ { ++ for (const auto& vectorItem : mapIt->second) ++ { ++ auto& [suffix, oldValue, dbusName, newValue] = vectorItem; ++ updateProperty(sensorInterface, oldValue, newValue, dbusName); + } + } + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch new file mode 100644 index 000000000..cfdc99d66 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0002-Fix-PECI-client-creation-flow.patch @@ -0,0 +1,159 @@ +From 0a1b2a13f6dbc64b5851ac2b1ca99d57afa78d60 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 27 Jan 2021 15:52:16 -0800 +Subject: [PATCH] Fix PECI client creation flow + +This commit fixes the PECI client creation flow to make it retry +the creation when the client is not exposed correctly. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + src/CPUSensorMain.cpp | 66 +++++++++++++++++++++++++++++++++++-------- + 1 file changed, 54 insertions(+), 12 deletions(-) + +diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp +index f304e3f..92c1716 100644 +--- a/src/CPUSensorMain.cpp ++++ b/src/CPUSensorMain.cpp +@@ -82,6 +82,7 @@ struct CPUConfig + }; + + static constexpr const char* peciDev = "/dev/peci-"; ++static constexpr const char* peciDevPath = "/sys/bus/peci/devices/"; + static constexpr const unsigned int rankNumMax = 8; + + namespace fs = std::filesystem; +@@ -167,7 +168,7 @@ bool createSensors(boost::asio::io_service& io, + } + + std::vector<fs::path> hwmonNamePaths; +- if (!findFiles(fs::path(R"(/sys/bus/peci/devices)"), ++ if (!findFiles(fs::path(peciDevPath), + R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/name$)", + hwmonNamePaths, 6)) + { +@@ -403,7 +404,7 @@ bool createSensors(boost::asio::io_service& io, + return true; + } + +-void exportDevice(const CPUConfig& config) ++int exportDevice(const CPUConfig& config) + { + std::ostringstream hex; + hex << std::hex << config.addr; +@@ -411,9 +412,12 @@ void exportDevice(const CPUConfig& config) + std::string busStr = std::to_string(config.bus); + + std::string parameters = "peci-client 0x" + addrHexStr; +- std::string device = "/sys/bus/peci/devices/peci-" + busStr + "/new_device"; ++ std::string devPath = peciDevPath; ++ std::string delDevice = devPath + "peci-" + busStr + "/delete_device"; ++ std::string newDevice = devPath + "peci-" + busStr + "/new_device"; ++ std::string newClient = devPath + busStr + "-" + addrHexStr + "/driver"; + +- std::filesystem::path devicePath(device); ++ std::filesystem::path devicePath(newDevice); + const std::string& dir = devicePath.parent_path().string(); + for (const auto& path : std::filesystem::directory_iterator(dir)) + { +@@ -431,20 +435,38 @@ void exportDevice(const CPUConfig& config) + std::cout << parameters << " on bus " << busStr + << " is already exported\n"; + } +- return; ++ ++ std::ofstream delDeviceFile(delDevice); ++ if (!delDeviceFile.good()) ++ { ++ std::cerr << "Error opening " << delDevice << "\n"; ++ return -1; ++ } ++ delDeviceFile << parameters; ++ delDeviceFile.close(); ++ ++ break; + } + } + +- std::ofstream deviceFile(device); ++ std::ofstream deviceFile(newDevice); + if (!deviceFile.good()) + { +- std::cerr << "Error writing " << device << "\n"; +- return; ++ std::cerr << "Error opening " << newDevice << "\n"; ++ return -1; + } + deviceFile << parameters; + deviceFile.close(); + ++ if (!std::filesystem::exists(newClient)) ++ { ++ std::cerr << "Error creating " << newClient << "\n"; ++ return -1; ++ } ++ + std::cout << parameters << " on bus " << busStr << " is exported\n"; ++ ++ return 0; + } + + void detectCpu(boost::asio::deadline_timer& pingTimer, +@@ -460,6 +482,11 @@ void detectCpu(boost::asio::deadline_timer& pingTimer, + + for (CPUConfig& config : cpuConfigs) + { ++ if (config.state == State::READY) ++ { ++ continue; ++ } ++ + std::string peciDevPath = peciDev + std::to_string(config.bus); + auto file = open(peciDevPath.c_str(), O_RDWR | O_CLOEXEC); + if (file < 0) +@@ -510,16 +537,29 @@ void detectCpu(boost::asio::deadline_timer& pingTimer, + newState = State::OFF; + } + +- close(file); +- + if (config.state != newState) + { + if (newState != State::OFF) + { + if (config.state == State::OFF) + { +- std::cout << config.name << " is detected\n"; +- exportDevice(config); ++ struct peci_rd_pkg_cfg_msg msg; ++ msg.addr = config.addr; ++ msg.index = PECI_MBX_INDEX_CPU_ID; ++ msg.param = 0; ++ msg.rx_len = 4; ++ if (!ioctl(file, PECI_IOC_RD_PKG_CFG, &msg)) ++ { ++ std::cout << config.name << " is detected\n"; ++ if (exportDevice(config)) ++ { ++ newState = State::OFF; ++ } ++ } ++ else ++ { ++ newState = State::OFF; ++ } + } + + if (newState == State::ON) +@@ -542,6 +582,8 @@ void detectCpu(boost::asio::deadline_timer& pingTimer, + keepPinging = true; + } + ++ close(file); ++ + if (debug) + { + std::cout << config.name << ", state: " << config.state << "\n"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch new file mode 100644 index 000000000..c9175fd64 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0003-Fix-missing-threshold-de-assert-event-when-threshold.patch @@ -0,0 +1,139 @@ +From 17e3ed85f2ff919ff52b4a3fe7a1eb0026f28898 Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Thu, 24 Sep 2020 14:27:32 -0700 +Subject: [PATCH] Fix missing threshold de-assert event when threshold changes. + +Sensor can be re-constructed when sensor configuration changes +like a new threshold value. Threshold deassert can be missed +if the new threshold value fixes the alarm because the +default state for new threshold interface is de-asserted. +Send threshold de-assert message after interfaces are initialized to +ensure de-assert event is logged if there is an active assert +event. + +Tested: +step1: +busctl set-property xyz.openbmc_project.ADCSensor /xyz/openbmc_project/sensors/voltage/P3VBAT xyz.openbmc_project.Sensor.Threshold.Warning WarningLow d 2.457 +ipmitool sel list +SEL has no entries +step2: +busctl set-property xyz.openbmc_project.ADCSensor /xyz/openbmc_project/sensors/voltage/P3VBAT xyz.openbmc_project.Sensor.Threshold.Warning WarningLow d 3.1 +ipmitool sel list + 1 | 09/24/20 | 21:30:15 UTC | Voltage #0x2d | Lower Non-critical going low | Asserted +step3: +busctl set-property xyz.openbmc_project.ADCSensor /xyz/openbmc_project/sensors/voltage/P3VBAT xyz.openbmc_project.Sensor.Threshold.Warning WarningLow d 2.457 +ipmitool sel list + 1 | 09/24/20 | 21:30:15 UTC | Voltage #0x2d | Lower Non-critical going low | Asserted + 2 | 09/24/20 | 21:30:33 UTC | Voltage #0x2d | Lower Non-critical going low | Deasserted + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +Change-Id: If28870ac1e0d09be4a631a3145408ec70390dfc5 +--- + include/Thresholds.hpp | 5 ++++- + include/sensor.hpp | 13 +++++++++++++ + src/ADCSensor.cpp | 1 + + src/Thresholds.cpp | 15 +++++++++++++-- + 4 files changed, 31 insertions(+), 3 deletions(-) + +diff --git a/include/Thresholds.hpp b/include/Thresholds.hpp +index ca2b0a0..c1d0baf 100644 +--- a/include/Thresholds.hpp ++++ b/include/Thresholds.hpp +@@ -45,7 +45,10 @@ struct Threshold + + void assertThresholds(Sensor* sensor, double assertValue, + thresholds::Level level, thresholds::Direction direction, +- bool assert); ++ bool assert, bool force = false); ++ ++void forceDeassertThresholds(Sensor* sensor, thresholds::Level level, ++ thresholds::Direction direction); + + struct TimerUsed + { +diff --git a/include/sensor.hpp b/include/sensor.hpp +index 0ef87d5..d50b2ff 100644 +--- a/include/sensor.hpp ++++ b/include/sensor.hpp +@@ -312,6 +312,19 @@ struct Sensor + operationalInterface->register_property("Functional", true); + operationalInterface->initialize(); + } ++ ++ // Sensor can be reconstructed when sensor configuration changes ++ // like a new threshold value. Threshold deassert can be missed ++ // if the new threshold value fixes the alarm because ++ // default state for new threshold interface is de-asserted. ++ // Send threshold de-assert message during initialization to ++ // ensure de-assert events are logged if there is an active assert ++ // event. ++ for (auto& threshold : thresholds) ++ { ++ thresholds::forceDeassertThresholds(this, threshold.level, ++ threshold.direction); ++ } + } + + bool readingStateGood() +diff --git a/src/ADCSensor.cpp b/src/ADCSensor.cpp +index fe600d7..632fc8c 100644 +--- a/src/ADCSensor.cpp ++++ b/src/ADCSensor.cpp +@@ -88,6 +88,7 @@ ADCSensor::~ADCSensor() + // close the input dev to cancel async operations + inputDev.close(); + waitTimer.cancel(); ++ + objServer.remove_interface(thresholdInterfaceWarning); + objServer.remove_interface(thresholdInterfaceCritical); + objServer.remove_interface(sensorInterface); +diff --git a/src/Thresholds.cpp b/src/Thresholds.cpp +index f4d4ed0..3c791c9 100644 +--- a/src/Thresholds.cpp ++++ b/src/Thresholds.cpp +@@ -344,6 +344,7 @@ bool checkThresholds(Sensor* sensor) + { + bool status = true; + std::vector<ChangeParam> changes = checkThresholds(sensor, sensor->value); ++ + for (const auto& change : changes) + { + assertThresholds(sensor, change.assertValue, change.threshold.level, +@@ -392,7 +393,7 @@ void checkThresholdsPowerDelay(Sensor* sensor, ThresholdTimer& thresholdTimer) + + void assertThresholds(Sensor* sensor, double assertValue, + thresholds::Level level, thresholds::Direction direction, +- bool assert) ++ bool assert, bool force) + { + std::string property; + std::shared_ptr<sdbusplus::asio::dbus_interface> interface; +@@ -432,7 +433,9 @@ void assertThresholds(Sensor* sensor, double assertValue, + return; + } + +- if (interface->set_property<bool, true>(property, assert)) ++ bool propertyChanged = ++ interface->set_property<bool, true>(property, assert); ++ if (force || propertyChanged) + { + try + { +@@ -452,6 +455,14 @@ void assertThresholds(Sensor* sensor, double assertValue, + } + } + ++// Explicitely de-assert a threshold with existing sensor value ++// Should only be called on sensor desctruction ++void forceDeassertThresholds(Sensor* sensor, thresholds::Level level, ++ thresholds::Direction direction) ++{ ++ assertThresholds(sensor, sensor->value, level, direction, false, true); ++} ++ + bool parseThresholdsFromAttr( + std::vector<thresholds::Threshold>& thresholdVector, + const std::string& inputPath, const double& scaleFactor, +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch new file mode 100644 index 000000000..65558aba5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch @@ -0,0 +1,58 @@ +From 8f850ea8745aa7aafcb504aa50686ba00fdfcfee Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Fri, 19 Feb 2021 12:14:05 -0800 +Subject: [PATCH] Fan Tach Sensor Threshold Ignore Zero + +Currently there are systems that have system fans plugged +into different fan connectors. Fan present detection is +not supported in most of these systems. Critical low +threshold is asserted for the non-utilized fans +resulting in FSC boost all fans. + +Skip threshold checking for fan tach reading less or equal +to zero. This is a temporary WA until a more robust solution +is available. + +Note: with this workaround a completely non-working fan +will not be detected. FSC will still boost fans due to other +constraints if the system can't be cooled with the working fans. + +Tested: +No cr event for the missing fans. + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +--- + src/TachSensor.cpp | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/src/TachSensor.cpp b/src/TachSensor.cpp +index 1ec979f..b17be98 100644 +--- a/src/TachSensor.cpp ++++ b/src/TachSensor.cpp +@@ -185,12 +185,18 @@ void TachSensor::handleResponse(const boost::system::error_code& err) + + void TachSensor::checkThresholds(void) + { +- bool status = thresholds::checkThresholds(this); +- +- if (redundancy && *redundancy) ++ // WA - treat value <= 0 as not present ++ bool status = false; ++ if (value > 0) + { +- (*redundancy) +- ->update("/xyz/openbmc_project/sensors/fan_tach/" + name, !status); ++ status = thresholds::checkThresholds(this); ++ ++ if (redundancy && *redundancy) ++ { ++ (*redundancy) ++ ->update("/xyz/openbmc_project/sensors/fan_tach/" + name, ++ !status); ++ } + } + + bool curLed = !status; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch new file mode 100644 index 000000000..8119f7542 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0005-Fix-PECI-ioctl-number.patch @@ -0,0 +1,29 @@ +From f85dd776301371892ff5197c1995bf2224dd87ab Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 22 Feb 2021 15:57:20 -0800 +Subject: [PATCH] Fix PECI ioctl number + +This commit fixes PECI ioctl number to 0xb8 to avoid conflicts in +kernel v5.10. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + include/linux/peci-ioctl.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/peci-ioctl.h b/include/linux/peci-ioctl.h +index e5b4b8bd3275..1f44edf4fc04 100644 +--- a/include/linux/peci-ioctl.h ++++ b/include/linux/peci-ioctl.h +@@ -601,7 +601,7 @@ struct peci_crashdump_get_frame_msg { + __u8 data[16]; + } __attribute__((__packed__)); + +-#define PECI_IOC_BASE 0xb7 ++#define PECI_IOC_BASE 0xb8 + + #define PECI_IOC_XFER \ + _IOWR(PECI_IOC_BASE, PECI_CMD_XFER, struct peci_xfer_msg) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf new file mode 100644 index 000000000..6f0fd3ffc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/intrusionsensor-depend-on-networkd.conf @@ -0,0 +1,3 @@ +[Unit] +After=systemd-networkd.service +Requires=systemd-networkd.service diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend new file mode 100644 index 000000000..c00b5d4cf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -0,0 +1,42 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +PROJECT_SRC_DIR := "${THISDIR}/${PN}" + +SRCREV = "6b6891c52e550c42507d4b413cbc4c6a09235535" +#SRC_URI = "git://github.com/openbmc/dbus-sensors.git" + +SRC_URI += "\ + file://intrusionsensor-depend-on-networkd.conf \ + file://0001-Add-check-for-min-max-received-from-hwmon-files.patch \ + file://0002-Fix-PECI-client-creation-flow.patch \ + file://0003-Fix-missing-threshold-de-assert-event-when-threshold.patch \ + file://0004-Fan-Tach-Sensor-Threshold-Ignore-Zero.patch \ + file://0005-Fix-PECI-ioctl-number.patch \ + " + +DEPENDS_append = " libgpiod libmctp" + +PACKAGECONFIG += " \ + adcsensor \ + cpusensor \ + exitairtempsensor \ + fansensor \ + hwmontempsensor \ + intrusionsensor \ + ipmbsensor \ + mcutempsensor \ + psusensor \ +" + +PACKAGECONFIG[nvmesensor] = "-Dnvme=enabled, -Dnvme=disabled" + +SYSTEMD_SERVICE_${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'nvmesensor', \ + 'xyz.openbmc_project.nvmesensor.service', \ + '', d)}" + +do_install_append() { + svc="xyz.openbmc_project.intrusionsensor.service" + srcf="${WORKDIR}/intrusionsensor-depend-on-networkd.conf" + dstf="${D}/etc/systemd/system/${svc}.d/10-depend-on-networkd.conf" + mkdir -p "${D}/etc/systemd/system/${svc}.d" + install "${srcf}" "${dstf}" +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb new file mode 100644 index 000000000..6acbfff37 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb @@ -0,0 +1,20 @@ +SUMMARY = "Settings" + +SRC_URI = "git://github.com/Intel-BMC/settings.git;protocol=ssh" +SRCREV = "1bdbb05873b5790bd56b683ce8ddf1a02a6795e7" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Settings.service" + +DEPENDS = "boost \ + nlohmann-json \ + sdbusplus" + +S = "${WORKDIR}/git" +inherit cmake systemd + +EXTRA_OECMAKE = "-DYOCTO=1" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb new file mode 100644 index 000000000..c77e5ace6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb @@ -0,0 +1,30 @@ +SUMMARY = "Special mode manager daemon to handle manufacturing modes" +DESCRIPTION = "Daemon exposes the manufacturing mode property" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/special-mode-manager.git;protocol=ssh" +SRCREV = "32ea1e19df9e5179054d87617468664367dfab80" + +EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "specialmodemgr.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + phosphor-logging \ + boost \ + libpam \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend new file mode 100644 index 000000000..ebb498866 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-post-code-manager_git.bbappend @@ -0,0 +1,2 @@ +#SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git" +SRCREV = "0171dd6bce9004e187c957f160809b729322f37d" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend new file mode 100644 index 000000000..d23480a05 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += "gtest" + +SYSTEMD_SERVICE_${PN}-bmc += "obmc-mapper.target" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb new file mode 100644 index 000000000..0dae2be3c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb @@ -0,0 +1,19 @@ +SUMMARY = "Callback Manager" +DESCRIPTION = "D-Bus daemon that registers matches that trigger method calls" + +SRC_URI = "git://github.com/openbmc/s2600wf-misc.git;protocol=ssh" + +inherit cmake systemd +DEPENDS = "boost sdbusplus" + +PV = "0.1+git${SRCPV}" +SRCREV = "291d6388e0b770e89091935bc4edc7f371874666" + +S = "${WORKDIR}/git/callback-manager" + +SYSTEMD_SERVICE_${PN} += "callback-manager.service" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENCE;md5=7becf906c8f8d03c237bad13bc3dac53" + +EXTRA_OECMAKE = "-DYOCTO=1" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend new file mode 100644 index 000000000..42f23dd9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/telemetry/telemetry_%.bbappend @@ -0,0 +1,6 @@ +SRC_URI = "git://github.com/openbmc/telemetry.git" +SRCREV = "f763c9e3bbe0f86a4a41e7bb0dc70bffde0af9b2" + +EXTRA_OEMESON += " -Dmax-reports=5" +EXTRA_OEMESON += " -Dmax-reading-parameters=200" +EXTRA_OEMESON += " -Dmin-interval=5000" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch new file mode 100644 index 000000000..dfd980a2b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch @@ -0,0 +1,1665 @@ +From 6fd1c797ec7440551052e8fc638d06313c9d6836 Mon Sep 17 00:00:00 2001 +From: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Date: Mon, 2 Jul 2018 19:23:25 -0700 +Subject: [PATCH 1/2] Added suport for multiple user manager services + +Support added for SSSD service implementation + +Signed-off-by: Alberto Salazar Perez <alberto.salazar.perez@intel.com> +Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 5 +- + mainapp.cpp | 90 +++++- + user_mgr.cpp | 297 ++---------------- + user_mgr.hpp | 9 +- + user_service.cpp | 789 +++++++++++++++++++++++++++++++++++++++++++++++ + user_service.hpp | 233 ++++++++++++++ + 6 files changed, 1149 insertions(+), 274 deletions(-) + create mode 100644 user_service.cpp + create mode 100644 user_service.hpp + +diff --git a/Makefile.am b/Makefile.am +index 7c7271e..58916b0 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1,11 +1,12 @@ + bin_PROGRAMS = phosphor-user-manager + +-noinst_HEADERS = user_mgr.hpp users.hpp ++noinst_HEADERS = user_mgr.hpp users.hpp user_service.hpp + + phosphor_user_manager_SOURCES = \ + mainapp.cpp \ + user_mgr.cpp \ +- users.cpp ++ users.cpp \ ++ user_service.cpp + + phosphor_user_manager_LDFLAGS = $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ +diff --git a/mainapp.cpp b/mainapp.cpp +index e08da61..f4b7f8c 100644 +--- a/mainapp.cpp ++++ b/mainapp.cpp +@@ -16,18 +16,106 @@ + #include "config.h" + + #include "user_mgr.hpp" ++#include "user_service.hpp" + ++#include <getopt.h> ++ ++#include <iostream> + #include <string> + + // D-Bus root for user manager + constexpr auto USER_MANAGER_ROOT = "/xyz/openbmc_project/user"; + ++void printUsage() ++{ ++ std::string usage = ++ R"(Usage: ++ phosphor-user-manager [OPTIONS] ++ ++Backend DBUS service for OpenBMC User Management. ++If no OPTIONS are specified, shadow file will be used. ++ ++Options: ++ -s, --service={shadow|sssd} ++ Specify the authentication service to use: ++ 'shadow' will use the /etc/shadow file. ++ 'sssd' will use the sssd service domains. ++ -h, --help Displays this help message. ++)"; ++ std::cerr << usage; ++} ++ ++void parseArgs(int argc, char** argv, ++ phosphor::user::UserService::ServiceType& srvc) ++{ ++ const std::string shortOpts{"s:h"}; ++ const struct option longOpts[] = {{"service", 1, nullptr, 's'}, ++ {"help", 0, nullptr, 'h'}, ++ {nullptr, 0, nullptr, 0}}; ++ ++ while (true) ++ { ++ const auto opt = ++ getopt_long(argc, argv, shortOpts.c_str(), longOpts, nullptr); ++ ++ if (opt == -1) ++ { ++ if (srvc == phosphor::user::UserService::ServiceType::none) ++ { ++ srvc = phosphor::user::UserService::ServiceType::shadow; ++ } ++ break; ++ } ++ ++ switch (opt) ++ { ++ case 's': ++ { ++ std::string srvcStr{optarg}; ++ if (!srvcStr.compare("shadow")) ++ { ++ srvc = phosphor::user::UserService::ServiceType::shadow; ++ } ++ else if (!srvcStr.compare("sssd")) ++ { ++ srvc = phosphor::user::UserService::ServiceType::sssd; ++ } ++ else ++ { ++ std::cerr << "Error. '" << srvcStr << "' is not a valid" ++ << " authentication service." << std::endl; ++ printUsage(); ++ exit(1); ++ } ++ } ++ break; ++ ++ case 'h': ++ { ++ printUsage(); ++ exit(0); ++ } ++ ++ default: ++ { ++ printUsage(); ++ exit(1); ++ } ++ } ++ } ++} ++ + int main(int argc, char** argv) + { ++ // Check command line options. Exit if error. ++ phosphor::user::UserService::ServiceType srvc = ++ phosphor::user::UserService::ServiceType::none; ++ parseArgs(argc, argv, srvc); ++ + auto bus = sdbusplus::bus::new_default(); + sdbusplus::server::manager::manager objManager(bus, USER_MANAGER_ROOT); + +- phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT); ++ phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT, srvc); + + // Claim the bus now + bus.request_name(USER_MANAGER_BUSNAME); +diff --git a/user_mgr.cpp b/user_mgr.cpp +index c65a822..eed81aa 100644 +--- a/user_mgr.cpp ++++ b/user_mgr.cpp +@@ -18,43 +18,34 @@ + + #include "user_mgr.hpp" + +-#include "file.hpp" + #include "shadowlock.hpp" + #include "users.hpp" + + #include <grp.h> + #include <pwd.h> +-#include <shadow.h> +-#include <sys/types.h> +-#include <sys/wait.h> + #include <time.h> +-#include <unistd.h> + + #include <boost/algorithm/string/split.hpp> +-#include <boost/process/child.hpp> +-#include <boost/process/io.hpp> + #include <phosphor-logging/elog-errors.hpp> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/log.hpp> + #include <xyz/openbmc_project/Common/error.hpp> + #include <xyz/openbmc_project/User/Common/error.hpp> + +-#include <algorithm> ++#include <cstdio> + #include <fstream> +-#include <numeric> + #include <regex> ++#include <stdexcept> + + namespace phosphor + { + namespace user + { + +-static constexpr const char* passwdFileName = "/etc/passwd"; + static constexpr size_t ipmiMaxUsers = 15; + static constexpr size_t ipmiMaxUserNameLen = 16; + static constexpr size_t systemMaxUserNameLen = 30; + static constexpr size_t maxSystemUsers = 30; +-static constexpr const char* grpSsh = "ssh"; + static constexpr uint8_t minPasswdLength = 8; + static constexpr int success = 0; + static constexpr int failure = -1; +@@ -100,79 +91,6 @@ using NoResource = + + using Argument = xyz::openbmc_project::Common::InvalidArgument; + +-template <typename... ArgTypes> +-static std::vector<std::string> executeCmd(const char* path, +- ArgTypes&&... tArgs) +-{ +- std::vector<std::string> stdOutput; +- boost::process::ipstream stdOutStream; +- boost::process::child execProg(path, const_cast<char*>(tArgs)..., +- boost::process::std_out > stdOutStream); +- std::string stdOutLine; +- +- while (stdOutStream && std::getline(stdOutStream, stdOutLine) && +- !stdOutLine.empty()) +- { +- stdOutput.emplace_back(stdOutLine); +- } +- +- execProg.wait(); +- +- int retCode = execProg.exit_code(); +- if (retCode) +- { +- log<level::ERR>("Command execution failed", entry("PATH=%d", path), +- entry("RETURN_CODE:%d", retCode)); +- elog<InternalFailure>(); +- } +- +- return stdOutput; +-} +- +-static std::string getCSVFromVector(std::vector<std::string> vec) +-{ +- switch (vec.size()) +- { +- case 0: +- { +- return ""; +- } +- break; +- +- case 1: +- { +- return std::string{vec[0]}; +- } +- break; +- +- default: +- { +- return std::accumulate( +- std::next(vec.begin()), vec.end(), vec[0], +- [](std::string a, std::string b) { return a + ',' + b; }); +- } +- } +-} +- +-static bool removeStringFromCSV(std::string& csvStr, const std::string& delStr) +-{ +- std::string::size_type delStrPos = csvStr.find(delStr); +- if (delStrPos != std::string::npos) +- { +- // need to also delete the comma char +- if (delStrPos == 0) +- { +- csvStr.erase(delStrPos, delStr.size() + 1); +- } +- else +- { +- csvStr.erase(delStrPos - 1, delStr.size() + 1); +- } +- return true; +- } +- return false; +-} +- + bool UserMgr::isUserExist(const std::string& userName) + { + if (userName.empty()) +@@ -299,39 +217,14 @@ void UserMgr::createUser(std::string userName, + { + throwForInvalidPrivilege(priv); + throwForInvalidGroups(groupNames); +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserExists(userName); + throwForUserNameConstraints(userName, groupNames); + throwForMaxGrpUserCount(groupNames); + +- std::string groups = getCSVFromVector(groupNames); +- bool sshRequested = removeStringFromCSV(groups, grpSsh); +- +- // treat privilege as a group - This is to avoid using different file to +- // store the same. +- if (!priv.empty()) +- { +- if (groups.size() != 0) +- { +- groups += ","; +- } +- groups += priv; +- } +- try +- { +- executeCmd("/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), +- "-m", "-N", "-s", +- (sshRequested ? "/bin/sh" : "/bin/nologin"), "-e", +- (enabled ? "" : "1970-01-02")); +- } +- catch (const InternalFailure& e) +- { +- log<level::ERR>("Unable to create new user"); +- elog<InternalFailure>(); +- } ++ // Tell the User Service to create a new user with the info provided. ++ userSrvc->createUser(userName, groupNames, priv, enabled); + +- // Add the users object before sending out the signal ++ // Add the users to the local list before sending out the signal + std::string userObj = std::string(usersObjPath) + "/" + userName; + std::sort(groupNames.begin(), groupNames.end()); + usersList.emplace( +@@ -345,19 +238,11 @@ void UserMgr::createUser(std::string userName, + + void UserMgr::deleteUser(std::string userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); +- try +- { +- executeCmd("/usr/sbin/userdel", userName.c_str(), "-r"); +- } +- catch (const InternalFailure& e) +- { +- log<level::ERR>("User delete failed", +- entry("USER_NAME=%s", userName.c_str())); +- elog<InternalFailure>(); +- } ++ ++ // Tell the User Service to delete user ++ userSrvc->deleteUser(userName); ++ // Then delete user from local list + + usersList.erase(userName); + +@@ -368,24 +253,13 @@ void UserMgr::deleteUser(std::string userName) + + void UserMgr::renameUser(std::string userName, std::string newUserName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); + throwForUserExists(newUserName); + throwForUserNameConstraints(newUserName, + usersList[userName].get()->userGroups()); +- try +- { +- std::string newHomeDir = "/home/" + newUserName; +- executeCmd("/usr/sbin/usermod", "-l", newUserName.c_str(), +- userName.c_str(), "-d", newHomeDir.c_str(), "-m"); +- } +- catch (const InternalFailure& e) +- { +- log<level::ERR>("User rename failed", +- entry("USER_NAME=%s", userName.c_str())); +- elog<InternalFailure>(); +- } ++ // Call The User Service to rename user on the system ++ userSrvc->renameUser(userName, newUserName); ++ // Update local list to reflect the name change + const auto& user = usersList[userName]; + std::string priv = user.get()->userPrivilege(); + std::vector<std::string> groupNames = user.get()->userGroups(); +@@ -409,8 +283,6 @@ void UserMgr::updateGroupsAndPriv(const std::string& userName, + { + throwForInvalidPrivilege(priv); + throwForInvalidGroups(groupNames); +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); + const std::vector<std::string>& oldGroupNames = + usersList[userName].get()->userGroups(); +@@ -426,29 +298,8 @@ void UserMgr::updateGroupsAndPriv(const std::string& userName, + throwForMaxGrpUserCount(groupNames); + } + +- std::string groups = getCSVFromVector(groupNames); +- bool sshRequested = removeStringFromCSV(groups, grpSsh); +- +- // treat privilege as a group - This is to avoid using different file to +- // store the same. +- if (!priv.empty()) +- { +- if (groups.size() != 0) +- { +- groups += ","; +- } +- groups += priv; +- } +- try +- { +- executeCmd("/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), +- "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); +- } +- catch (const InternalFailure& e) +- { +- log<level::ERR>("Unable to modify user privilege / groups"); +- elog<InternalFailure>(); +- } ++ // Call The User Service to update user groups and priv on the system ++ userSrvc->updateGroupsAndPriv(userName, groupNames, priv); + + log<level::INFO>("User groups / privilege updated successfully", + entry("USER_NAME=%s", userName.c_str())); +@@ -644,19 +495,9 @@ int UserMgr::setPamModuleArgValue(const std::string& moduleName, + + void UserMgr::userEnable(const std::string& userName, bool enabled) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); +- try +- { +- executeCmd("/usr/sbin/usermod", userName.c_str(), "-e", +- (enabled ? "" : "1970-01-02")); +- } +- catch (const InternalFailure& e) +- { +- log<level::ERR>("Unable to modify user enabled state"); +- elog<InternalFailure>(); +- } ++ // Call The User Service to update user groups and priv on the system ++ userSrvc->updateUserStatus(userName, enabled); + + log<level::INFO>("User enabled/disabled state updated successfully", + entry("USER_NAME=%s", userName.c_str()), +@@ -779,54 +620,8 @@ bool UserMgr::userPasswordExpired(const std::string& userName) + + UserSSHLists UserMgr::getUserAndSshGrpList() + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- +- std::vector<std::string> userList; +- std::vector<std::string> sshUsersList; +- struct passwd pw, *pwp = nullptr; +- std::array<char, 1024> buffer{}; +- +- phosphor::user::File passwd(passwdFileName, "r"); +- if ((passwd)() == NULL) +- { +- log<level::ERR>("Error opening the passwd file"); +- elog<InternalFailure>(); +- } +- +- while (true) +- { +- auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(), +- &pwp); +- if ((r != 0) || (pwp == NULL)) +- { +- // Any error, break the loop. +- break; +- } +-#ifdef ENABLE_ROOT_USER_MGMT +- // Add all users whose UID >= 1000 and < 65534 +- // and special UID 0. +- if ((pwp->pw_uid == 0) || +- ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) +-#else +- // Add all users whose UID >=1000 and < 65534 +- if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)) +-#endif +- { +- std::string userName(pwp->pw_name); +- userList.emplace_back(userName); +- +- // ssh doesn't have separate group. Check login shell entry to +- // get all users list which are member of ssh group. +- std::string loginShell(pwp->pw_shell); +- if (loginShell == "/bin/sh") +- { +- sshUsersList.emplace_back(userName); +- } +- } +- } +- endpwent(); +- return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ // Call The User Service to get the User and SSUsers lists ++ return std::move(userSrvc->getUserAndSshGrpList()); + } + + size_t UserMgr::getIpmiUsersCount() +@@ -837,49 +632,14 @@ size_t UserMgr::getIpmiUsersCount() + + bool UserMgr::isUserEnabled(const std::string& userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- std::array<char, 4096> buffer{}; +- struct spwd spwd; +- struct spwd* resultPtr = nullptr; +- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), +- buffer.max_size(), &resultPtr); +- if (!status && (&spwd == resultPtr)) +- { +- if (resultPtr->sp_expire >= 0) +- { +- return false; // user locked out +- } +- return true; +- } +- return false; // assume user is disabled for any error. ++ // Call The User Service to verify if user is enabled ++ return userSrvc->isUserEnabled(userName); + } + + std::vector<std::string> UserMgr::getUsersInGroup(const std::string& groupName) + { +- std::vector<std::string> usersInGroup; +- // Should be more than enough to get the pwd structure. +- std::array<char, 4096> buffer{}; +- struct group grp; +- struct group* resultPtr = nullptr; +- +- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(), +- buffer.max_size(), &resultPtr); +- +- if (!status && (&grp == resultPtr)) +- { +- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) +- { +- usersInGroup.emplace_back(*(grp.gr_mem)); +- } +- } +- else +- { +- log<level::ERR>("Group not found", +- entry("GROUP=%s", groupName.c_str())); +- // Don't throw error, just return empty userList - fallback +- } +- return usersInGroup; ++ // Call The User Service to get the users that belong to a group ++ return std::move(userSrvc->getUsersInGroup(groupName)); + } + + DbusUserObj UserMgr::getPrivilegeMapperObject(void) +@@ -1106,11 +866,9 @@ void UserMgr::initUserObjects(void) + { + // All user management lock has to be based on /etc/shadow + phosphor::user::shadow::Lock lock(); +- std::vector<std::string> userNameList; +- std::vector<std::string> sshGrpUsersList; + UserSSHLists userSSHLists = getUserAndSshGrpList(); +- userNameList = std::move(userSSHLists.first); +- sshGrpUsersList = std::move(userSSHLists.second); ++ std::vector<std::string> userNameList = std::move(userSSHLists.first); ++ std::vector<std::string> sshGrpUsersList = std::move(userSSHLists.second); + + if (!userNameList.empty()) + { +@@ -1165,8 +923,10 @@ void UserMgr::initUserObjects(void) + } + } + +-UserMgr::UserMgr(sdbusplus::bus::bus& bus, const char* path) : +- Ifaces(bus, path, true), bus(bus), path(path) ++UserMgr::UserMgr(sdbusplus::bus::bus& bus, const char* path, ++ UserService::ServiceType srvc) : ++ Ifaces(bus, path, true), ++ bus(bus), path(path) + { + UserMgrIface::allPrivileges(privMgr); + std::sort(groupsMgr.begin(), groupsMgr.end()); +@@ -1274,6 +1034,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus& bus, const char* path) : + } + AccountPolicyIface::accountUnlockTimeout(value32); + } ++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr); + initUserObjects(); + + // emit the signal +diff --git a/user_mgr.hpp b/user_mgr.hpp +index f5aac22..5d5ca99 100644 +--- a/user_mgr.hpp ++++ b/user_mgr.hpp +@@ -14,6 +14,7 @@ + // limitations under the License. + */ + #pragma once ++#include "user_service.hpp" + #include "users.hpp" + + #include <sdbusplus/bus.hpp> +@@ -30,8 +31,6 @@ namespace user + { + + using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager; +-using UserSSHLists = +- std::pair<std::vector<std::string>, std::vector<std::string>>; + using AccountPolicyIface = + sdbusplus::xyz::openbmc_project::User::server::AccountPolicy; + +@@ -77,8 +76,10 @@ class UserMgr : public Ifaces + * + * @param[in] bus - sdbusplus handler + * @param[in] path - D-Bus path ++ * @param[in] srvc - User service to be used + */ +- UserMgr(sdbusplus::bus::bus& bus, const char* path); ++ UserMgr(sdbusplus::bus::bus& bus, const char* path, ++ UserService::ServiceType srvc); + + /** @brief create user method. + * This method creates a new user as requested +@@ -194,6 +195,8 @@ class UserMgr : public Ifaces + /** @brief object path */ + const std::string path; + ++ /** @brief user service to be used */ ++ std::unique_ptr<UserService> userSrvc; + /** @brief privilege manager container */ + std::vector<std::string> privMgr = {"priv-admin", "priv-operator", + "priv-user", "priv-noaccess"}; +diff --git a/user_service.cpp b/user_service.cpp +new file mode 100644 +index 0000000..ad4e510 +--- /dev/null ++++ b/user_service.cpp +@@ -0,0 +1,789 @@ ++/* ++// Copyright (c) 2018 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#include "user_service.hpp" ++ ++#include "file.hpp" ++#include "shadowlock.hpp" ++ ++#include <grp.h> ++#include <pwd.h> ++ ++#include <boost/algorithm/string/split.hpp> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++ ++#include <numeric> ++ ++/* anonymous namespace for User Service interface implementations. ++// Each class inside this namespace implements a special service ++// to be used for the User Manager class. This can be extended to use ++// other user management services and it should be as simple as ++// adding a new class which inherits from phosphor::user::UserServiceInterface ++*/ ++ ++namespace ++{ ++ ++std::string getCSVFromVector(std::vector<std::string> vec) ++{ ++ switch (vec.size()) ++ { ++ case 0: ++ { ++ return ""; ++ } ++ break; ++ ++ case 1: ++ { ++ return std::string{vec[0]}; ++ } ++ break; ++ ++ default: ++ { ++ return std::accumulate( ++ std::next(vec.begin()), vec.end(), vec[0], ++ [](std::string a, std::string b) { return a + ',' + b; }); ++ } ++ } ++} ++ ++bool removeStringFromCSV(std::string& csvStr, const std::string& delStr) ++{ ++ std::string::size_type delStrPos = csvStr.find(delStr); ++ if (delStrPos != std::string::npos) ++ { ++ // need to also delete the comma char ++ if (delStrPos == 0) ++ { ++ csvStr.erase(delStrPos, delStr.size() + 1); ++ } ++ else ++ { ++ csvStr.erase(delStrPos - 1, delStr.size() + 1); ++ } ++ return true; ++ } ++ return false; ++} ++ ++class ShadowService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ ShadowService() = default; ++ ++ ~ShadowService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::vector<std::string> userList; ++ std::vector<std::string> sshUsersList; ++ ++ struct passwd pw, *pwp = nullptr; ++ std::array<char, 1024> buffer{}; ++ ++ phosphor::user::File passwd(passwdFileName, "r"); ++ if ((passwd)() == NULL) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error opening the passwd file"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ while (true) ++ { ++ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), ++ buffer.max_size(), &pwp); ++ if ((r != 0) || (pwp == NULL)) ++ { ++ // Any error, break the loop. ++ break; ++ } ++#ifdef ENABLE_ROOT_USER_MGMT ++ // Add all users whose UID >= 1000 and < 65534 ++ // and special UID 0. ++ if ((pwp->pw_uid == 0) || ++ ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) ++#else ++ // Add all users whose UID >=1000 and < 65534 ++ if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)) ++#endif ++ { ++ std::string userName(pwp->pw_name); ++ userList.emplace_back(userName); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ std::string loginShell(pwp->pw_shell); ++ if (loginShell == "/bin/sh") ++ { ++ sshUsersList.emplace_back(userName); ++ } ++ } ++ } ++ endpwent(); ++ return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string& groupName) const override ++ { ++ std::vector<std::string> usersInGroup; ++ // Should be more than enough to get the pwd structure. ++ std::array<char, 4096> buffer{}; ++ struct group grp; ++ struct group* grpPtr = &grp; ++ struct group* resultPtr; ++ ++ int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ ++ if (!status && (grpPtr == resultPtr)) ++ { ++ for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) ++ { ++ usersInGroup.emplace_back(*(grp.gr_mem)); ++ } ++ } ++ else ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Group not found", ++ phosphor::logging::entry("GROUP=%s", groupName.c_str())); ++ // Don't throw error, just return empty usersInGroup - fallback ++ } ++ return usersInGroup; ++ } ++ ++ void createUser(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv, const bool& enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups.append(","); ++ } ++ groups.append(priv); ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), ++ "-m", "-N", "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void renameUser(const std::string& userName, ++ const std::string& newUserName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ std::string newHomeDir = "/home/" + newUserName; ++ phosphor::user::executeCmd("/usr/sbin/usermod", "-l", ++ newUserName.c_str(), userName.c_str(), ++ "-d", newHomeDir.c_str(), "-m"); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User rename failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void deleteUser(const std::string& userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/userdel", userName.c_str(), ++ "-r"); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User delete failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same. ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), ++ "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user privilege / groups"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string& userName, ++ const bool& enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/usermod", userName.c_str(), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user enabled state"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string& userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ std::array<char, 4096> buffer{}; ++ struct spwd spwd; ++ struct spwd* resultPtr = nullptr; ++ int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ if (!status && (&spwd == resultPtr)) ++ { ++ if (resultPtr->sp_expire >= 0) ++ { ++ return false; // user locked out ++ } ++ return true; ++ } ++ return false; // assume user is disabled for any error. ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string& userName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::getUserGroups not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ return std::vector<std::string>(); ++ } ++ ++ void createGroup(const std::string& groupName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::createGroup not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ private: ++ static constexpr const char* passwdFileName = "/etc/passwd"; ++}; ++ ++class SSSDService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ SSSDService(const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs) ++ { ++ ++ createGroup(lockedGrp); ++ for (const auto& g : groups) ++ { ++ createGroup(g); ++ } ++ for (const auto& p : privs) ++ { ++ createGroup(p); ++ } ++ } ++ ++ ~SSSDService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ std::vector<std::string> users; ++ std::vector<std::string> sshGroup; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/bin/getent", "-s", ++ "sss", "passwd"); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get users information " ++ "from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ for (const auto& userLine : exeOutput) ++ { ++ std::vector<std::string> userInfo; ++ boost::algorithm::split(userInfo, userLine, ++ boost::algorithm::is_any_of(":")); ++ // At this point userInfo is a vector containing the passwd ++ // info for the user, so we know the correct positions: ++ // 0: User name. ++ // 1: Encrypted password. ++ // 2: User ID number (UID) ++ // 3: User's group ID number (GID) ++ // 4: Full name of the user (GECOS) ++ // 5: User home directory. ++ // 6: Login shell. ++ users.emplace_back(userInfo[0]); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ if (userInfo[6] == "/bin/sh") ++ { ++ sshGroup.emplace_back(userInfo[0]); ++ } ++ } ++ ++ return std::make_pair(std::move(users), std::move(sshGroup)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string& groupName) const override ++ { ++ std::vector<std::string> userList; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get group users from sssd service"); ++ // Don't throw error, just return empty usersInGroup - return ++ return userList; ++ } ++ // exeOutput should have 5 entries ++ // 0: Group ++ // 1: GID number ++ // 2: Member users ++ // 3: Is a member of ++ // 4: Member groups ++ exeOutput[2].erase( ++ exeOutput[2].begin(), ++ std::find(exeOutput[2].begin(), exeOutput[2].end(), ':')); ++ boost::algorithm::trim_left(exeOutput[2]); ++ boost::algorithm::split(userList, exeOutput[2], ++ boost::algorithm::is_any_of(",")); ++ return userList; ++ } ++ ++ void createUser(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv, const bool& enabled) const override ++ { ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_useradd", "-m", "-G", groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user in sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ // Sometimes the SSSD service needs some time to actually ++ // reflect the changes to the local DB to the NSS service, ++ // that is why we have this sleep here ... ++ std::this_thread::sleep_for(std::chrono::seconds(1)); ++ // update user status (locked/unlocked) ++ updateUserStatus(userName, enabled); ++ } ++ ++ void renameUser(const std::string& userName, ++ const std::string& newUserName) const override ++ { ++ std::vector<std::string> exeOutput; ++ // Local Domain for sssd doesn't have a rename feature ++ // so we need to first create a new user and then delete ++ // the old one. ++ // The only issue with this is that the password for the ++ // user will have to be reseted since it is a new user being created. ++ ++ // Get original user groups ++ std::vector<std::string> groups = getUserGroups(userName); ++ // Check if it has a "ssh" group by looking for the shell login ++ try ++ { ++ exeOutput = phosphor::user::executeCmd( ++ "/usr/bin/getent", "-s", "sss", "passwd", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get information for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ if (exeOutput[0].find("/bin/sh")) ++ { ++ groups.emplace_back(phosphor::user::grpSsh); ++ } ++ // Call create user with the new user names and previous groups ++ // Priv is already part of the groups so that can be empty. ++ createUser(newUserName, groups, "", isUserEnabled(userName)); ++ ++ // Now delete original user ++ deleteUser(userName); ++ } ++ ++ void deleteUser(const std::string& userName) const override ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_userdel", "-r", ++ userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to delete user from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv) const override ++ { ++ // local domain sssd do not allow to update all list of groups, ++ // so we will remove all groups first (except for the user one) ++ // and then all all the ones that were passed ++ std::string oldGroups = getCSVFromVector(getUserGroups(userName)); ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_usermod", "-r", oldGroups.c_str(), "-a", ++ groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user groups and " ++ "priv from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string& userName, ++ const bool& enabled) const override ++ { ++ std::string enabledStr; ++ std::string lockedStr; ++ if (isUserEnabled(userName) == enabled) ++ { ++ return; ++ } ++ if (enabled) ++ { ++ enabledStr = "-r"; ++ lockedStr = "-U"; ++ } ++ else ++ { ++ enabledStr = "-a"; ++ lockedStr = "-L"; ++ } ++ try ++ { ++ // We will add a special locked group to identify the users ++ // that have been locked out of the system. ++ // TODO: sss_usermod is not locking user accounts for the ++ // LOCAL domain, need to find the correct PAM configuration ++ // to actually lockout users for SSSD. ++ // As a workaround we are using the pam module pam_listfile.so ++ // to lockout all users that belong to the locked group. ++ phosphor::user::executeCmd("/usr/sbin/sss_usermod", ++ enabledStr.c_str(), lockedGrp.c_str(), ++ lockedStr.c_str(), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user status from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string& userName) const override ++ { ++ std::vector<std::string> userGrps = getUserGroups(userName); ++ return std::find(userGrps.begin(), userGrps.end(), lockedGrp) == ++ userGrps.end(); ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string& userName) const override ++ { ++ std::vector<std::string> exeOutput; ++ try ++ { ++ exeOutput = ++ phosphor::user::executeCmd("/usr/bin/groups", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get groups for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ std::vector<std::string> groups; ++ boost::algorithm::split(groups, exeOutput[0], ++ boost::algorithm::is_any_of(" ")); ++ // Delete group that equals user name if it exists ++ auto userNameGroup = std::find(groups.begin(), groups.end(), userName); ++ if (userNameGroup != groups.end()) ++ { ++ groups.erase(userNameGroup); ++ } ++ return groups; ++ } ++ ++ void createGroup(const std::string& groupName) const override ++ { ++ try ++ { ++ if (!groupExists(groupName)) ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupadd", ++ groupName.c_str()); ++ } ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create group"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ private: ++ static const std::string lockedGrp; ++ ++ bool groupExists(const std::string& groupName) const ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure& e) ++ { ++ return false; ++ } ++ return true; ++ } ++}; ++ ++const std::string SSSDService::lockedGrp = "sssd_locked"; ++} // anonymous namespace ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++UserService::UserService(const ServiceType& srvcType, ++ const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs) ++{ ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::updateServiceType(const ServiceType& srvcType, ++ const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs) ++{ ++ usrSrvcImpl.reset(); ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::setServiceImpl(const ServiceType& srvcType, ++ const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs) ++{ ++ switch (srvcType) ++ { ++ case ServiceType::shadow: ++ { ++ usrSrvcImpl = std::make_unique<ShadowService>(); ++ } ++ break; ++ ++ case ServiceType::sssd: ++ { ++ usrSrvcImpl = std::make_unique<SSSDService>(groups, privs); ++ } ++ break; ++ ++ case ServiceType::none: ++ default: ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Invalid service type initialization!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ break; ++ } ++} ++ ++UserService::~UserService() ++{} ++ ++phosphor::user::UserSSHLists UserService::getUserAndSshGrpList() const ++{ ++ return usrSrvcImpl->getUserAndSshGrpList(); ++} ++ ++std::vector<std::string> ++ UserService::getUsersInGroup(const std::string& groupName) const ++{ ++ return usrSrvcImpl->getUsersInGroup(groupName); ++} ++ ++void UserService::createUser(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv, const bool& enabled) const ++{ ++ usrSrvcImpl->createUser(userName, groupNames, priv, enabled); ++} ++ ++void UserService::renameUser(const std::string& userName, ++ const std::string& newUserName) const ++{ ++ usrSrvcImpl->renameUser(userName, newUserName); ++} ++ ++void UserService::deleteUser(const std::string& userName) const ++{ ++ usrSrvcImpl->deleteUser(userName); ++} ++ ++void UserService::updateGroupsAndPriv( ++ const std::string& userName, const std::vector<std::string>& groupNames, ++ const std::string& priv) const ++{ ++ usrSrvcImpl->updateGroupsAndPriv(userName, groupNames, priv); ++} ++ ++void UserService::updateUserStatus(const std::string& userName, ++ const bool& enabled) const ++{ ++ usrSrvcImpl->updateUserStatus(userName, enabled); ++} ++ ++bool UserService::isUserEnabled(const std::string& userName) const ++{ ++ return usrSrvcImpl->isUserEnabled(userName); ++} ++ ++std::vector<std::string> ++ UserService::getUserGroups(const std::string& userName) const ++{ ++ return usrSrvcImpl->getUserGroups(userName); ++} ++ ++} // namespace user ++} // namespace phosphor +diff --git a/user_service.hpp b/user_service.hpp +new file mode 100644 +index 0000000..50ee4db +--- /dev/null ++++ b/user_service.hpp +@@ -0,0 +1,233 @@ ++/* ++// Copyright (c) 2018 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++#include <phosphor-logging/elog.hpp> ++#include <phosphor-logging/log.hpp> ++#include <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/User/Common/error.hpp> ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++using UserSSHLists = ++ std::pair<std::vector<std::string>, std::vector<std::string>>; ++using InternalFailure = ++ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; ++using InsufficientPermission = ++ sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission; ++ ++const std::string grpSsh = "ssh"; ++ ++template <typename... ArgTypes> ++std::vector<std::string> executeCmd(const char* path, ArgTypes&&... tArgs) ++{ ++ std::vector<std::string> stdOutput; ++ boost::process::ipstream stdOutStream; ++ boost::process::child execProg(path, const_cast<char*>(tArgs)..., ++ boost::process::std_out > stdOutStream); ++ std::string stdOutLine; ++ ++ while (stdOutStream && std::getline(stdOutStream, stdOutLine) && ++ !stdOutLine.empty()) ++ { ++ stdOutput.emplace_back(stdOutLine); ++ } ++ ++ execProg.wait(); ++ ++ int retCode = execProg.exit_code(); ++ if (retCode) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Command execution failed", ++ phosphor::logging::entry("PATH=%d", path), ++ phosphor::logging::entry("RETURN_CODE:%d", retCode)); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ return stdOutput; ++} ++ ++/** @class UserServiceInterface ++ * @brief Interface class for methods provided by the implemmentations ++ * of the user service. Provides the same methods as the UserService ++ * class. ++ */ ++class UserServiceInterface ++{ ++ public: ++ UserServiceInterface() = default; ++ virtual ~UserServiceInterface() = default; ++ virtual UserSSHLists getUserAndSshGrpList() const = 0; ++ virtual std::vector<std::string> ++ getUsersInGroup(const std::string& groupName) const = 0; ++ virtual void createUser(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv, ++ const bool& enabled) const = 0; ++ virtual void renameUser(const std::string& userName, ++ const std::string& newUserName) const = 0; ++ virtual void deleteUser(const std::string& userName) const = 0; ++ virtual void updateGroupsAndPriv(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv) const = 0; ++ virtual void updateUserStatus(const std::string& userName, ++ const bool& enabled) const = 0; ++ virtual bool isUserEnabled(const std::string& userName) const = 0; ++ virtual std::vector<std::string> ++ getUserGroups(const std::string& userName) const = 0; ++ virtual void createGroup(const std::string& groupName) const = 0; ++}; ++ ++/** @class UserService ++ * @brief Responsible for managing the user service for the user manager. ++ * This service is the one responsible to actually change the user information ++ * of the application. It can support sevaral services, currently the ones ++ * supported are: ++ * ++ * 1) Shadow: Which uses the /etc/shadow file for updating the users ++ * 2) SSSD: Which uses the sssd service for a LOCAL domain only right now. ++ */ ++class UserService ++{ ++ public: ++ UserService() = delete; ++ UserService(const UserService&) = delete; ++ UserService& operator=(const UserService&) = delete; ++ UserService(UserService&&) = delete; ++ UserService& operator=(UserService&&) = delete; ++ ++ // Service Types implemented. None is used to validate. ++ enum class ServiceType ++ { ++ none, ++ shadow, ++ sssd ++ }; ++ ++ UserService(const ServiceType& srvcType, ++ const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs); ++ ~UserService(); ++ ++ /** @brief update the current Service type of the instance. ++ * This function is used to update in real time the service ++ * being used for the user management without restarting the ++ * whole service. ++ * ++ * @param[in] srvcType ++ * @param[in] groups ++ * @param[in] privs ++ */ ++ void updateServiceType(const ServiceType& srvcType, ++ const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs); ++ ++ /** @brief get user list and SSH group members list ++ * This method gets the list of users from the service. ++ * If the userlist reference is empty, all the users will be added ++ * and DBus notified about them. If the list is not empty, the function ++ * will only update list adding the missing ones to it. It will not remove ++ * any extra users on the list that are not part of the service! ++ * ++ */ ++ UserSSHLists getUserAndSshGrpList() const; ++ ++ /** @brief Get users in group. ++ * This method creates a new user as requested ++ * ++ * @param[in] groupName - Name of the group which has to be queried ++ */ ++ std::vector<std::string> ++ getUsersInGroup(const std::string& groupName) const; ++ ++ /** @brief create user method. ++ * This method creates a new user as requested ++ * ++ * @param[in] userName - Name of the user which has to be created ++ * @param[in] groupNames - Group names list, to which user has to be added. ++ * @param[in] priv - Privilege of the user. ++ * @param[in] enabled - State of the user enabled / disabled. ++ */ ++ void createUser(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv, const bool& enabled) const; ++ ++ /** @brief rename user method. ++ * This method renames the user as requested ++ * ++ * @param[in] userName - current name of the user ++ * @param[in] userName - user name to which it has to be renamed. ++ */ ++ void renameUser(const std::string& userName, ++ const std::string& newUserName) const; ++ ++ /** @brief delete user method. ++ * This method deletes the user as requested ++ * ++ * @param[in] userName - Name of the user which has to be deleted ++ */ ++ void deleteUser(const std::string& userName) const; ++ ++ /** @brief Updates user Groups and Privilege. ++ * ++ * @param[in] userName - Name of the user which has to be modified ++ * @param[in] groupNames - Group names list for user. ++ * @param[in] priv - Privilege of the user. ++ */ ++ void updateGroupsAndPriv(const std::string& userName, ++ const std::vector<std::string>& groupNames, ++ const std::string& priv) const; ++ ++ /** @brief Updates user status ++ * If enabled = false: User will be disabled ++ * If enabled = true : User will be enabled ++ * ++ * @param[in] userName - Name of the user ++ * @param[in] enabled - Status of the user: enabled / disabled? ++ */ ++ void updateUserStatus(const std::string& userName, ++ const bool& enabled) const; ++ ++ /** @brief Verify if user is enabled or not ++ * If enabled returns true ++ * If not enabled returns false ++ * ++ * @param[in] userName - Name of the user ++ */ ++ bool isUserEnabled(const std::string& userName) const; ++ ++ /** @brief Get the list of groups a user belongs to ++ * ++ * @param[in] userName - Name of the user ++ */ ++ std::vector<std::string> getUserGroups(const std::string& userName) const; ++ ++ private: ++ // User service implementation. ++ void setServiceImpl(const ServiceType& srvcType, ++ const std::vector<std::string>& groups, ++ const std::vector<std::string>& privs); ++ std::unique_ptr<UserServiceInterface> usrSrvcImpl; ++}; ++ ++} // namespace user ++} // namespace phosphor +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch new file mode 100644 index 000000000..7a0eff80e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch @@ -0,0 +1,76 @@ +From 06064b3d6e56f4e13e6b85552f8525b74d9f1931 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Mon, 24 Feb 2020 13:37:12 +0530 +Subject: [PATCH 2/2] Use groupmems instead of getgrnam_r due to overlay + +With JFFS2 overlay, getgrnam_r during initial time returns the +old group details as per the lower dir, instead of the overlay one +but at the same time groupmems where returning proper values, which +reads the file everytime. Hence replacing getgrnam_r with groupmems + +Tested: +1. Verified that when added multiple user and then doing +BMC reset using ipmitool raw 6 2 doesn't reproduce the issue of +user with only ssh group. (on 38 version source + this fix) +2. Updated using redfish to version 39 + this fix, and made sure +issue doesn't happen. + +Note: For testing purpose added debug statements to dump ouput of +both getgrnam_r & groupmems and able to see proper list only +in groupmems when the issue is reproduced + +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +--- + user_service.cpp | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/user_service.cpp b/user_service.cpp +index ad4e510..89b27ed 100644 +--- a/user_service.cpp ++++ b/user_service.cpp +@@ -147,28 +147,26 @@ class ShadowService : public phosphor::user::UserServiceInterface + getUsersInGroup(const std::string& groupName) const override + { + std::vector<std::string> usersInGroup; +- // Should be more than enough to get the pwd structure. +- std::array<char, 4096> buffer{}; +- struct group grp; +- struct group* grpPtr = &grp; +- struct group* resultPtr; +- +- int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(), +- buffer.max_size(), &resultPtr); +- +- if (!status && (grpPtr == resultPtr)) ++ std::vector<std::string> output; ++ try + { +- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) +- { +- usersInGroup.emplace_back(*(grp.gr_mem)); +- } ++ output = phosphor::user::executeCmd("/usr/sbin/groupmems", "-l", ++ "-g", groupName.c_str()); + } +- else ++ catch (const phosphor::user::InternalFailure& e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Group not found", + phosphor::logging::entry("GROUP=%s", groupName.c_str())); + // Don't throw error, just return empty usersInGroup - fallback ++ return usersInGroup; ++ } ++ if (!output.empty()) ++ { ++ boost::algorithm::trim_right(output[0]); ++ boost::algorithm::split(usersInGroup, output[0], ++ boost::algorithm::is_any_of("\t "), ++ boost::token_compress_on); + } + return usersInGroup; + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend new file mode 100644 index 000000000..c9f14f54c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI = "git://github.com/openbmc/phosphor-user-manager" +SRCREV = "18c1b42c1612e0e8d8f5cd9973bba09b447c7185" + +EXTRA_OECONF += "${@bb.utils.contains_any("IMAGE_FEATURES", [ 'debug-tweaks', 'allow-root-login' ], '', '--disable-root_user_mgmt', d)}" + +SRC_URI += " \ + file://0005-Added-suport-for-multiple-user-manager-services.patch \ + file://0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb new file mode 100644 index 000000000..e568ea5d2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb @@ -0,0 +1,24 @@ +SUMMARY = "Virtual Media Service" +DESCRIPTION = "Virtual Media Service" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +S = "${WORKDIR}/git/virtual-media" +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.VirtualMedia.service" + +DEPENDS = "udev boost nlohmann-json systemd sdbusplus" + +RDEPENDS_${PN} = "nbd-client nbdkit" + +inherit cmake systemd + +EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON" +EXTRA_OECMAKE += "-DLEGACY_MODE_ENABLED=ON" + +FULL_OPTIMIZATION = "-Os -pipe -flto -fno-rtti" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb new file mode 100644 index 000000000..d6ff9f7a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb @@ -0,0 +1,33 @@ + +SUMMARY = "FRB2 timer service" +DESCRIPTION = "The FRB2 timer service will monitor the mailbox register 0\ +and start a watchdog for FRB2 if the data is 1(BIOS will write this value)" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://frb2-watchdog.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +inherit cmake +inherit pkgconfig + +DEPENDS += " \ + systemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + boost \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt new file mode 100644 index 000000000..bd5567d31 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (frb2-watchdog CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import libsystemd +find_package (PkgConfig REQUIRED) +pkg_check_modules (SYSTEMD libsystemd REQUIRED) +include_directories (${SYSTEMD_INCLUDE_DIRS}) +link_directories (${SYSTEMD_LIBRARY_DIRS}) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +# import phosphor-dbus-interfaces +find_package (PkgConfig REQUIRED) +pkg_check_modules (DBUSINTERFACE phosphor-dbus-interfaces REQUIRED) +include_directories (${DBUSINTERFACE_INCLUDE_DIRS}) +link_directories (${DBUSINTERFACE_LIBRARY_DIRS}) + +add_executable (frb2-watchdog frb2-watchdog.cpp) + +target_link_libraries (${PROJECT_NAME} systemd) +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} + phosphor_logging) +install (TARGETS frb2-watchdog DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp new file mode 100644 index 000000000..bae54f335 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp @@ -0,0 +1,264 @@ +/* Copyright 2018 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <boost/asio/buffers_iterator.hpp> +#include <boost/asio/deadline_timer.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/posix/stream_descriptor.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/streambuf.hpp> +#include <boost/container/flat_set.hpp> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <optional> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> +#include <sdbusplus/bus.hpp> +#include <sdbusplus/bus/match.hpp> +#include <sdbusplus/message.hpp> +#include <sdbusplus/timer.hpp> +#include <vector> +#include <xyz/openbmc_project/State/Watchdog/server.hpp> + +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred); + +static int mailboxDevFd = -1; + +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); +boost::asio::ip::tcp::socket mailBoxDevSocket(io); +boost::asio::deadline_timer pollTimer(io); +boost::asio::posix::stream_descriptor inputDevice(io); + +// mailbox registre data[0:0] for FRB2 enable bit +boost::asio::streambuf readBuf(1); +std::string dataRead; + +// FRB2 watchdog timeout is 6 minutes +static constexpr unsigned int frb2TimerIntervalMs = 360 * 1000; + +// mailbox device polling time interval is 2 seconds +static constexpr unsigned int pollMs = 2000; + +static constexpr unsigned int frb2Started = 1; +static constexpr unsigned int frb2Stopped = 0; + +// FRB2 status +static uint8_t frb2Status = frb2Stopped; + +static constexpr const char *mailboxDevName = "/dev/aspeed-mbox"; + +static constexpr const char frb2Bus[] = "xyz.openbmc_project.FRB2"; +static constexpr const char frb2Obj[] = "/xyz/openbmc_project/FRB2"; +static constexpr const char frb2Intf[] = "xyz.openbmc_project.FRB2"; + +static constexpr char powerBus[] = "xyz.openbmc_project.Chassis.Control.Power"; +static constexpr char powerPath[] = + "/xyz/openbmc_project/Chassis/Control/Power0"; +static constexpr char powerIntf[] = "xyz.openbmc_project.Chassis.Control.Power"; + +static constexpr char wdBus[] = "xyz.openbmc_project.Watchdog"; +static constexpr char wdPath[] = "/xyz/openbmc_project/watchdog/host0"; +static constexpr char wdIntf[] = "xyz.openbmc_project.State.Watchdog"; +static constexpr char propIntf[] = "org.freedesktop.DBus.Properties"; + +typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator; + +// check if FRB2 bit is 0x1 +std::pair<iterator, bool> matchFRB2(iterator begin, iterator end) +{ + unsigned char ch = 0; + iterator i = begin; + + while (i != end) + { + ch = static_cast<unsigned char>(*i); + if (ch & 0x1) + { + return std::make_pair(i, true); + } + i++; + } + + return std::make_pair(i, false); +} + +static void startRead() +{ + boost::asio::async_read_until(inputDevice, readBuf, matchFRB2, + [&](const boost::system::error_code &ec, + std::size_t bytes_transferred) { + handleResponse(ec, bytes_transferred); + }); +} + +template <typename T> void setProperty(const std::string &key, const T &val) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "setProperty", phosphor::logging::entry("KEY=%s", key.c_str())); + + try + { + conn->async_method_call( + [](const boost::system::error_code &err) { + if (err) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "async_method_call error!", + phosphor::logging::entry( + "ERROR=%s", + boost::system::system_error(err).what())); + } + }, + wdBus, wdPath, propIntf, "Set", wdIntf, key, std::variant<T>(val)); + } + catch (sdbusplus::exception::SdBusError &e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Dbus error!", phosphor::logging::entry("ERROR=%s", e.what())); + } +} +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred) +{ + std::istream responseStream(&readBuf); + std::string response; + int n = 0; + uint64_t interval = frb2TimerIntervalMs; + + std::getline(responseStream, response); + responseStream.clear(); + + if (err == boost::system::errc::bad_file_descriptor) + { + + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "bad file descriptor"); + return; // we're being destroyed + } + + if (!err) + { + // FRB2 is set by BIOS + if (frb2Stopped == frb2Status) + { + // start FRB2 watchdog + frb2Status = frb2Started; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 enable, start FRB2 watchdog"); + setProperty( + "ExpireAction", + std::string( + "xyz.openbmc_project.State.Watchdog.Action.HardReset")); + setProperty("Interval", interval); + setProperty("TimeRemaining", interval); + setProperty("Initialized", true); + setProperty("Enabled", true); + } + } + else if (err == boost::asio::error::misc_errors::not_found) + { + // FRB2 is clear, stop FRB2 watchdog if it is started + if (frb2Started == frb2Status) + { + frb2Status = frb2Stopped; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 is unset, stop FRB2 watchdog"); + setProperty("Enabled", false); + } + } + else + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "handleResponse error!", + phosphor::logging::entry("ERROR=%s", + boost::system::system_error(err).what())); + } + + pollTimer.expires_from_now(boost::posix_time::milliseconds(pollMs)); + pollTimer.async_wait( + [](const boost::system::error_code &ec) { startRead(); }); +} + +int main(int argc, char **argv) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "Monitor FRB2 signal"); + + sdbusplus::bus::match_t biosPostSignal( + static_cast<sdbusplus::bus::bus &>(*conn), + sdbusplus::bus::match::rules::type::signal() + + sdbusplus::bus::match::rules::member("PostCompleted") + + sdbusplus::bus::match::rules::path(powerPath) + + sdbusplus::bus::match::rules::interface(powerIntf), + [](sdbusplus::message::message &msg) { + uint8_t value = 0; + ssize_t rc = 0; + phosphor::logging::log<phosphor::logging::level::INFO>( + "BIOS post completed signal"); + // stop FRB2 and clean mailbox + value = 0; + rc = ::pwrite(mailboxDevFd, &value, 1, 0); + if (rc != 1) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox write error!"); + } + setProperty("Enabled", false); + frb2Status = frb2Stopped; + return; + }); + + conn->request_name(frb2Bus); + + auto server = sdbusplus::asio::object_server(conn); + + std::shared_ptr<sdbusplus::asio::dbus_interface> frb2Iface = + server.add_interface(frb2Obj, frb2Intf); + + frb2Iface->register_property("frb2Status", frb2Status); + + frb2Iface->initialize(); + + mailboxDevFd = ::open(mailboxDevName, O_RDWR | O_CLOEXEC); + if (mailboxDevFd < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox device open fail!"); + return -1; + } + + inputDevice.assign(mailboxDevFd); + + startRead(); + + io.run(); + + ::close(mailboxDevFd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch new file mode 100644 index 000000000..a634b1588 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch @@ -0,0 +1,353 @@ +From 67797d726b6eb6fa8e1dad063c7d2021cec47ab3 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Mon, 17 Jun 2019 12:00:58 -0700 +Subject: [PATCH] Customize phosphor-watchdog for Intel platforms + +This patch adds various changes to phosphor-watchdog that are +required for compatibility with Intel platforms. + + 1. Add Redfish messages for watchdog timeout and pre-interrupt + 2. Use dbus properties for power control insted of service files + 3. Use host status to enable/disable watchdog + 4. Set preTimeoutInterruptOccurFlag + 5. Assign watchdog cause for correct reset cause reporting + 6. Add NMI Pre-Interrupt support for IPMI watchdog timer. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Ren Yu <yux.ren@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +Signed-off-by: Sunita Kumari <sunitax.kumari@intel.com> + +%% original patch: 0001-Customize-phosphor-watchdog-for-Intel-platforms.patch +--- + watchdog.cpp | 230 ++++++++++++++++++++++++++++++++++++++++++++++++--- + watchdog.hpp | 23 +++++- + 2 files changed, 242 insertions(+), 11 deletions(-) + +diff --git a/watchdog.cpp b/watchdog.cpp +index 57e9050..1204db4 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -1,11 +1,14 @@ + #include "watchdog.hpp" + ++#include <systemd/sd-journal.h> ++ + #include <algorithm> + #include <chrono> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/log.hpp> + #include <sdbusplus/exception.hpp> + #include <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/State/Host/server.hpp> + + namespace phosphor + { +@@ -18,10 +21,86 @@ using namespace phosphor::logging; + using sdbusplus::exception::SdBusError; + using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; + +-// systemd service to kick start a target. +-constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; +-constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1"; +-constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; ++const static constexpr char* currentHostState = "CurrentHostState"; ++const static constexpr char* hostStatusOff = ++ "xyz.openbmc_project.State.Host.HostState.Off"; ++ ++const static constexpr char* actionDescription = " due to Watchdog timeout"; ++const static constexpr char* hardResetDescription = "Hard Reset - System reset"; ++const static constexpr char* powerOffDescription = ++ "Power Down - System power down"; ++const static constexpr char* powerCycleDescription = ++ "Power Cycle - System power cycle"; ++const static constexpr char* timerExpiredDescription = "Timer expired"; ++ ++const static constexpr char* preInterruptActionNone = ++ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None"; ++ ++const static constexpr char* preInterruptDescriptionSMI = "SMI"; ++const static constexpr char* preInterruptDescriptionNMI = "NMI"; ++const static constexpr char* preInterruptDescriptionMI = "Messaging Interrupt"; ++ ++const static constexpr char* reservedDescription = "Reserved"; ++ ++const static constexpr char* timerUseDescriptionBIOSFRB2 = "BIOS FRB2"; ++const static constexpr char* timerUseDescriptionBIOSPOST = "BIOS/POST"; ++const static constexpr char* timerUseDescriptionOSLoad = "OSLoad"; ++const static constexpr char* timerUseDescriptionSMSOS = "SMS/OS"; ++const static constexpr char* timerUseDescriptionOEM = "OEM"; ++ ++namespace restart ++{ ++static constexpr const char* busName = ++ "xyz.openbmc_project.Control.Host.RestartCause"; ++static constexpr const char* path = ++ "/xyz/openbmc_project/control/host0/restart_cause"; ++static constexpr const char* interface = ++ "xyz.openbmc_project.Control.Host.RestartCause"; ++static constexpr const char* property = "RequestedRestartCause"; ++} // namespace restart ++ ++// chassis state manager service ++namespace chassis ++{ ++static constexpr const char* busName = "xyz.openbmc_project.State.Chassis"; ++static constexpr const char* path = "/xyz/openbmc_project/state/chassis0"; ++static constexpr const char* interface = "xyz.openbmc_project.State.Chassis"; ++static constexpr const char* request = "RequestedPowerTransition"; ++} // namespace chassis ++ ++namespace host ++{ ++static constexpr const char* busName = "xyz.openbmc_project.State.Host"; ++static constexpr const char* path = "/xyz/openbmc_project/state/host0"; ++static constexpr const char* interface = "xyz.openbmc_project.State.Host"; ++static constexpr const char* request = "RequestedHostTransition"; ++} // namespace host ++ ++namespace nmi ++{ ++static constexpr const char* busName = "xyz.openbmc_project.Control.Host.NMI"; ++static constexpr const char* path = "/xyz/openbmc_project/control/host0/nmi"; ++static constexpr const char* interface = "xyz.openbmc_project.Control.Host.NMI"; ++static constexpr const char* request = "NMI"; ++ ++} // namespace nmi ++ ++void Watchdog::powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props) ++{ ++ const auto iter = props.find(currentHostState); ++ if (iter != props.end()) ++ { ++ const std::string* powerState = std::get_if<std::string>(&iter->second); ++ if (powerState && (*powerState == hostStatusOff)) ++ { ++ if (timerEnabled()) ++ { ++ enabled(false); ++ } ++ } ++ } ++} + + void Watchdog::resetTimeRemaining(bool enableWatchdog) + { +@@ -107,13 +186,111 @@ uint64_t Watchdog::interval(uint64_t value) + // Optional callback function on timer expiration + void Watchdog::timeOutHandler() + { ++ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt(); ++ std::string preInterruptActionMessageArgs{}; ++ + Action action = expireAction(); ++ std::string actionMessageArgs{}; ++ ++ expiredTimerUse(currentTimerUse()); ++ ++ TimerUse timeUser = expiredTimerUse(); ++ std::string timeUserMessage{}; ++ + if (!this->enabled()) + { + action = fallback->action; + } + +- expiredTimerUse(currentTimerUse()); ++ switch (timeUser) ++ { ++ case Watchdog::TimerUse::BIOSFRB2: ++ timeUserMessage = timerUseDescriptionBIOSFRB2; ++ break; ++ case Watchdog::TimerUse::BIOSPOST: ++ timeUserMessage = timerUseDescriptionBIOSPOST; ++ break; ++ case Watchdog::TimerUse::OSLoad: ++ timeUserMessage = timerUseDescriptionOSLoad; ++ break; ++ case Watchdog::TimerUse::SMSOS: ++ timeUserMessage = timerUseDescriptionSMSOS; ++ break; ++ case Watchdog::TimerUse::OEM: ++ timeUserMessage = timerUseDescriptionOEM; ++ break; ++ default: ++ timeUserMessage = reservedDescription; ++ break; ++ } ++ ++ switch (action) ++ { ++ case Watchdog::Action::HardReset: ++ actionMessageArgs = std::string(hardResetDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::PowerOff: ++ actionMessageArgs = std::string(powerOffDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::PowerCycle: ++ actionMessageArgs = std::string(powerCycleDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::None: ++ actionMessageArgs = timerExpiredDescription; ++ break; ++ default: ++ actionMessageArgs = reservedDescription; ++ break; ++ } ++ ++ // Log into redfish event log ++ sd_journal_send("MESSAGE=IPMIWatchdog: Timed out ACTION=%s", ++ convertForMessage(action).c_str(), "PRIORITY=%i", LOG_INFO, ++ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=%s. timer use: %s", ++ actionMessageArgs.c_str(), timeUserMessage.c_str(), NULL); ++ ++ switch (preTimeoutInterruptAction) ++ { ++ case Watchdog::PreTimeoutInterruptAction::SMI: ++ preInterruptActionMessageArgs = preInterruptDescriptionSMI; ++ break; ++ case Watchdog::PreTimeoutInterruptAction::NMI: ++ preInterruptActionMessageArgs = preInterruptDescriptionNMI; ++ break; ++ case Watchdog::PreTimeoutInterruptAction::MI: ++ preInterruptActionMessageArgs = preInterruptDescriptionMI; ++ break; ++ default: ++ preInterruptActionMessageArgs = reservedDescription; ++ break; ++ } ++ ++ if (preInterruptActionNone != convertForMessage(preTimeoutInterruptAction)) ++ { ++ preTimeoutInterruptOccurFlag(true); ++ ++ sd_journal_send("MESSAGE=IPMIWatchdog: Pre Timed out Interrupt=%s", ++ convertForMessage(preTimeoutInterruptAction).c_str(), ++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", ++ "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to " ++ "Watchdog timeout. timer use: %s", ++ preInterruptActionMessageArgs.c_str(), ++ timeUserMessage.c_str(), NULL); ++ ++ if (preTimeoutInterruptAction == ++ Watchdog::PreTimeoutInterruptAction::NMI) ++ { ++ sdbusplus::message::message preTimeoutInterruptHandler; ++ preTimeoutInterruptHandler = bus.new_method_call( ++ nmi::busName, nmi::path, nmi::interface, nmi::request); ++ bus.call_noreply(preTimeoutInterruptHandler); ++ } ++ } + + auto target = actionTargetMap.find(action); + if (target == actionTargetMap.end()) +@@ -133,12 +310,45 @@ void Watchdog::timeOutHandler() + + try + { +- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, +- SYSTEMD_INTERFACE, "StartUnit"); +- method.append(target->second); +- method.append("replace"); ++ sdbusplus::message::message method; ++ if (action == Watchdog::Action::HardReset) ++ { ++ auto method = bus.new_method_call( ++ restart::busName, restart::path, ++ "org.freedesktop.DBus.Properties", "Set"); ++ method.append( ++ restart::interface, restart::property, ++ std::variant<std::string>("xyz.openbmc_project.State.Host." ++ "RestartCause.WatchdogTimer")); ++ bus.call_noreply(method); + +- bus.call_noreply(method); ++ method = bus.new_method_call(host::busName, host::path, ++ "org.freedesktop.DBus.Properties", ++ "Set"); ++ method.append(host::interface, host::request, ++ std::variant<std::string>(target->second)); ++ bus.call_noreply(method); ++ } ++ else ++ { ++ if (action == Watchdog::Action::PowerCycle) ++ { ++ auto method = bus.new_method_call( ++ restart::busName, restart::path, ++ "org.freedesktop.DBus.Properties", "Set"); ++ method.append(restart::interface, restart::property, ++ std::variant<std::string>( ++ "xyz.openbmc_project.State.Host." ++ "RestartCause.WatchdogTimer")); ++ bus.call_noreply(method); ++ } ++ method = bus.new_method_call(chassis::busName, chassis::path, ++ "org.freedesktop.DBus.Properties", ++ "Set"); ++ method.append(chassis::interface, chassis::request, ++ std::variant<std::string>(target->second)); ++ bus.call_noreply(method); ++ } + } + catch (const SdBusError& e) + { +diff --git a/watchdog.hpp b/watchdog.hpp +index 7de9bb3..b004b7a 100644 +--- a/watchdog.hpp ++++ b/watchdog.hpp +@@ -68,7 +68,18 @@ class Watchdog : public WatchdogInherits + WatchdogInherits(bus, objPath), + bus(bus), actionTargetMap(std::move(actionTargetMap)), + fallback(std::move(fallback)), minInterval(minInterval), +- timer(event, std::bind(&Watchdog::timeOutHandler, this)) ++ timer(event, std::bind(&Watchdog::timeOutHandler, this)), ++ powerStateChangedSignal( ++ bus, ++ sdbusplus::bus::match::rules::propertiesChanged( ++ "/xyz/openbmc_project/state/host0", ++ "xyz.openbmc_project.State.Host"), ++ [this](sdbusplus::message::message& msg) { ++ std::string objectName; ++ std::map<std::string, std::variant<std::string>> props; ++ msg.read(objectName, props); ++ powerStateChangedHandler(props); ++ }) + { + // We set the watchdog interval with the default value. + interval(interval()); +@@ -77,6 +88,12 @@ class Watchdog : public WatchdogInherits + tryFallbackOrDisable(); + } + ++ /** @brief Disable watchdog when power status change meet ++ * the specific requirement ++ */ ++ void powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props); ++ + /** @brief Resets the TimeRemaining to the configured Interval + * Optionally enables the watchdog. + * +@@ -165,6 +182,10 @@ class Watchdog : public WatchdogInherits + /** @brief Contained timer object */ + sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer; + ++ /** @brief Optional Callback handler when power status change meet ++ * the specific requirement */ ++ sdbusplus::bus::match_t powerStateChangedSignal; ++ + /** @brief Optional Callback handler on timer expirartion */ + void timeOutHandler(); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service new file mode 100644 index 000000000..007e39d8a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service @@ -0,0 +1,16 @@ +[Unit] +Description=Phosphor Watchdog + +[Service] +ExecStart=/usr/bin/env phosphor-watchdog --continue --service=xyz.openbmc_project.Watchdog \ + --path=/xyz/openbmc_project/watchdog/host0 \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=xyz.openbmc_project.State.Host.Transition.ForceWarmReboot \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=xyz.openbmc_project.State.Chassis.Transition.Off \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=xyz.openbmc_project.State.Chassis.Transition.PowerCycle + +SyslogIdentifier=phosphor-watchdog +BusName =xyz.openbmc_project.Watchdog +Type=dbus + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend new file mode 100644 index 000000000..75f04e2ab --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +SRC_URI += "file://0001-Customize-phosphor-watchdog-for-Intel-platforms.patch \ + " + +# Remove the override to keep service running after DC cycle +SYSTEMD_OVERRIDE_${PN}_remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf" +SYSTEMD_SERVICE_${PN} = "phosphor-watchdog.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb new file mode 100644 index 000000000..addd1ccb2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb @@ -0,0 +1,12 @@ +SUMMARY = "System watchdog" +DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \ + when unrecoverable events occurs" + +inherit allarch +inherit obmc-phosphor-systemd + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} += "system-watchdog.service" +SYSTEMD_ENVIRONMENT_FILE_${PN} += "obmc/system-watchdog/system-watchdog.conf" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf new file mode 100644 index 000000000..defe830a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf @@ -0,0 +1,3 @@ +TIMEOUT=60 +INTERVAL=10 +DEVICE=/dev/watchdog1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service new file mode 100644 index 000000000..1564fda20 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service @@ -0,0 +1,11 @@ +[Unit] +Description=BMC Hardware Watchdog Daemon + +[Service] +EnvironmentFile=/etc/default/obmc/system-watchdog/system-watchdog.conf +ExecStart=/sbin/watchdog -T ${{TIMEOUT}} -t ${{INTERVAL}} -F ${{DEVICE}} +KillSignal=SIGKILL + +[Install] +WantedBy=basic.target + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json new file mode 100644 index 000000000..348a7792d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json @@ -0,0 +1,9 @@ +{ + "customKeyEnable": true, + "keyType" : "VT100+", + "customConsoleDisplaySize": { + "width": 100, + "height": 32 + }, + "VirtualMediaEnabled" : true +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend new file mode 100644 index 000000000..244af18dc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend @@ -0,0 +1,4 @@ +SRC_URI = "git://github.com/Intel-BMC/phosphor-webui;protocol=ssh;branch=intel2" +FILESEXTRAPATHS_prepend_intel := "${THISDIR}/${PN}:" + +SRCREV = "40dd78bd5fe1dfcadd22bba9eee8e402b634b40d" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend new file mode 100644 index 000000000..7ebf1d4d6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/webui-vue_%.bbappend @@ -0,0 +1,7 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/webui-vue.git" +SRCREV = "5ed21f2d1e8b82be699a623bfdef550dfd598dbb" + +do_compile_prepend() { + cp -vf ${S}/.env.intel ${S}/.env +} diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh new file mode 100644 index 000000000..176bfd7ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh @@ -0,0 +1 @@ +export LDB_MODULES_PATH=/usr/lib/ldb diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups new file mode 100644 index 000000000..7c189e231 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups @@ -0,0 +1 @@ +sssd_locked diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf new file mode 100644 index 000000000..d2ffe5ddc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf @@ -0,0 +1,2 @@ +enable-cache passwd no +enable-cache group no
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf new file mode 100644 index 000000000..7a2786bee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf @@ -0,0 +1,16 @@ +[sssd] +domains = LOCAL +services = nss, pam +config_file_version = 2 + +[nss] +enum_cache_timeout = 1 +filter_groups = root +filter_users = root + +[pam] + +[domain/LOCAL] +enumerate = true +id_provider = local +auth_provider = local diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service new file mode 100644 index 000000000..fe2bcf8b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service @@ -0,0 +1,15 @@ +[Unit] +Description=System Security Services Daemon +# SSSD must be running before we permit user sessions +Before=systemd-user-sessions.service nss-user-lookup.target +Wants=nss-user-lookup.target + +[Service] +Environment=LDB_MODULES_PATH=/usr/lib/ldb DEBUG_LOGGER=-f +ExecStart=/usr/sbin/sssd $DEBUG_LOGGER +Type=simple +Restart=always +PIDFile=/var/run/sssd.pid + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend new file mode 100644 index 000000000..03965ce72 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend @@ -0,0 +1,26 @@ +inherit obmc-phosphor-systemd + +FILESEXTRAPATHS_append := "${THISDIR}/files:" +SRC_URI += "file://sssd.conf \ + file://nscd.conf \ + file://locked_groups \ + file://ldb.sh \ + " + +PACKAGECONFIG += " systemd " +SYSTEMD_AUTO_ENABLE = "enable" + +EXTRA_OECONF += " --enable-pammoddir=${base_libdir}/security" + +do_install_append() { + # sssd creates also the /var/run link. Need to remove it to avoid conflicts + # with the one created by base-files recipe. + rm -rf ${D}/var/run + install -m 600 ${WORKDIR}/locked_groups ${D}/${sysconfdir}/${BPN} + install -m 600 ${WORKDIR}/nscd.conf ${D}/${sysconfdir} + install -d ${D}${sysconfdir}/profile.d + install -m 0644 ${WORKDIR}/ldb.sh ${D}${sysconfdir}/profile.d +} + +FILES_${PN} += " /lib/security/pam_sss.so " + diff --git a/meta-openbmc-mods/meta-common/recipes-support/avro/avro-c++/0001-enable-cross-compilation-and-pkgconfig.patch b/meta-openbmc-mods/meta-common/recipes-support/avro/avro-c++/0001-enable-cross-compilation-and-pkgconfig.patch new file mode 100644 index 000000000..7355ad5f1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/avro/avro-c++/0001-enable-cross-compilation-and-pkgconfig.patch @@ -0,0 +1,71 @@ +diff --git a/lang/c++/CMakeLists.txt b/lang/c++/CMakeLists.txt +index 28a272b15..06ec38382 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -25,6 +25,7 @@ if (NOT DEFINED CMAKE_CXX_STANDARD) + endif() + + set(CMAKE_CXX_STANDARD_REQUIRED ON) ++set(PKGCONFIG_SUPPORT ON) + + cmake_policy (SET CMP0042 NEW) + +@@ -107,6 +108,12 @@ set (AVRO_SOURCE_FILES + impl/Resolver.cc impl/Validator.cc + ) + ++if (PKGCONFIG_SUPPORT) ++ install(FILES "avrocpp.pc" ++ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") ++ message("${CMAKE_INSTALL_LIBDIR}/pkgconfig") ++endif() ++ + add_library (avrocpp SHARED ${AVRO_SOURCE_FILES}) + + set_property (TARGET avrocpp +@@ -141,6 +148,7 @@ macro (gen file ns) + add_custom_target (${file}_hh DEPENDS ${file}.hh) + endmacro (gen) + ++if (NOT DEFINED YOCTO_BUILD) + gen (empty_record empty) + gen (bigrecord testgen) + gen (bigrecord_r testgen_r) +@@ -196,13 +204,16 @@ include (InstallRequiredSystemLibraries) + set (CPACK_PACKAGE_FILE_NAME "avrocpp-${AVRO_VERSION_MAJOR}") + + include (CPack) ++endif () + + install (TARGETS avrocpp avrocpp_s + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION lib) + ++if (NOT DEFINED YOCTO_BUILD) + install (TARGETS avrogencpp RUNTIME DESTINATION bin) ++endif () + + install (DIRECTORY api/ DESTINATION include/avro + FILES_MATCHING PATTERN *.hh) +@@ -212,3 +223,4 @@ if (NOT CMAKE_BUILD_TYPE) + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + FORCE) + endif (NOT CMAKE_BUILD_TYPE) ++ +diff --git a/lang/c++/avrocpp.pc b/lang/c++/avrocpp.pc +new file mode 100644 +index 000000000..471f1863c +--- /dev/null ++++ b/avrocpp.pc +@@ -0,0 +1,10 @@ ++prefix=/usr ++libdir=${prefix}/lib ++includedir=${prefix}/include/avro ++ ++Name: avrocpp ++Description: C++ bindings for Apache avro ++Version: 1.0.0 ++Libs: -L${libdir} -lavrocpp ++Cflags: -I${includedir} ++ diff --git a/meta-openbmc-mods/meta-common/recipes-support/avro/avro-c++_git.bb b/meta-openbmc-mods/meta-common/recipes-support/avro/avro-c++_git.bb new file mode 100644 index 000000000..af8aad522 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/avro/avro-c++_git.bb @@ -0,0 +1,22 @@ +SUMMARY = "Apache Avro data serialization system (C++ bindings)" +HOMEPAGE = "http://apr.apache.org/" +SECTION = "libs" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=43abf34d8b9908494f83c55d213a7f89" + +DEPENDS = "boost" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +BRANCH = "master" +SRCREV = "f4e2ebaadaf6e6d99b59882233f8024243adb55d" +SRC_URI = "git://github.com/apache/avro;branch=${BRANCH} \ + file://0001-enable-cross-compilation-and-pkgconfig.patch \ + " + +S = "${WORKDIR}/git/lang/c++" + +EXTRA_OECMAKE = "-DSNAPPY_INCLUDE_DIR='' -DYOCTO_BUILD=ON -DCMAKE_BUILD_TYPE=MinSizeRel" +inherit cmake + diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost-url/boost-url_git.bb b/meta-openbmc-mods/meta-common/recipes-support/boost-url/boost-url_git.bb new file mode 100644 index 000000000..6d4635b66 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/boost-url/boost-url_git.bb @@ -0,0 +1,17 @@ +DESCRIPTION = "Boost.URL is a library for manipulating Uniform Resource Identifiers (URI) and Locators (URL)" +HOMEPAGE = "https://github.com/CPPAlliance/url" +SECTION = "libs" +LICENSE = "BSL-1.0" +LIC_FILES_CHKSUM = "file://LICENSE_1_0.txt;md5=e4224ccaecb14d942c71d31bef20d78c" + +SRC_URI = "git://github.com/CPPAlliance/url.git" + +SRCREV = "a56ae0df6d3078319755fbaa67822b4fa7fd352b" + +S = "${WORKDIR}/git" + +inherit cmake + +DEPENDS = "boost" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend new file mode 100644 index 000000000..c24249bcf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend @@ -0,0 +1,7 @@ +FILES_${PN} += "/usr/lib/libboost_chrono.so* \ + /usr/lib/libboost_context.so* \ + /usr/lib/libboost_thread.so*" + +BOOST_LIBS_intel += "iostreams coroutine filesystem program_options regex system" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-support/curl/curl/0001-replace-krb5-config-with-pkg-config.patch b/meta-openbmc-mods/meta-common/recipes-support/curl/curl/0001-replace-krb5-config-with-pkg-config.patch new file mode 100644 index 000000000..a7db1b3c9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/curl/curl/0001-replace-krb5-config-with-pkg-config.patch @@ -0,0 +1,44 @@ +From ed70f0623708b8a6c1f58a5d243d87c5ff45b24d Mon Sep 17 00:00:00 2001 +From: Roy Li <rongqing.li@windriver.com> +Date: Tue, 26 Apr 2016 13:13:01 +0800 +Subject: [PATCH] replace krb5-config with pkg-config + +Upstream-Status: Pending + +Signed-off-by: Roy Li <rongqing.li@windriver.com> + +--- + configure.ac | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 5569a26..56b0380 100755 +--- a/configure.ac ++++ b/configure.ac +@@ -1290,7 +1290,7 @@ AC_ARG_WITH(gssapi, + fi + ]) + +-: ${KRB5CONFIG:="$GSSAPI_ROOT/bin/krb5-config"} ++KRB5CONFIG=`which pkg-config` + + save_CPPFLAGS="$CPPFLAGS" + AC_MSG_CHECKING([if GSS-API support is requested]) +@@ -1301,7 +1301,7 @@ if test x"$want_gss" = xyes; then + if test -n "$host_alias" -a -f "$GSSAPI_ROOT/bin/$host_alias-krb5-config"; then + GSSAPI_INCS=`$GSSAPI_ROOT/bin/$host_alias-krb5-config --cflags gssapi` + elif test -f "$KRB5CONFIG"; then +- GSSAPI_INCS=`$KRB5CONFIG --cflags gssapi` ++ GSSAPI_INCS=`$KRB5CONFIG --cflags mit-krb5-gssapi` + elif test "$GSSAPI_ROOT" != "yes"; then + GSSAPI_INCS="-I$GSSAPI_ROOT/include" + fi +@@ -1394,7 +1394,7 @@ if test x"$want_gss" = xyes; then + elif test -f "$KRB5CONFIG"; then + dnl krb5-config doesn't have --libs-only-L or similar, put everything + dnl into LIBS +- gss_libs=`$KRB5CONFIG --libs gssapi` ++ gss_libs=`$KRB5CONFIG --libs mit-krb5-gssapi` + LIBS="$gss_libs $LIBS" + else + case $host in diff --git a/meta-openbmc-mods/meta-common/recipes-support/curl/curl_7.76.0.bb b/meta-openbmc-mods/meta-common/recipes-support/curl/curl_7.76.0.bb new file mode 100644 index 000000000..83e1a81e4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/curl/curl_7.76.0.bb @@ -0,0 +1,85 @@ +SUMMARY = "Command line tool and library for client-side URL transfers" +HOMEPAGE = "http://curl.haxx.se/" +BUGTRACKER = "http://curl.haxx.se/mail/list.cgi?list=curl-tracker" +SECTION = "console/network" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://COPYING;md5=425f6fdc767cc067518eef9bbdf4ab7b" + +SRC_URI = "https://curl.haxx.se/download/curl-${PV}.tar.bz2 \ + file://0001-replace-krb5-config-with-pkg-config.patch \ +" + +SRC_URI[sha256sum] = "e29bfe3633701590d75b0071bbb649ee5ca4ca73f00649268bd389639531c49a" + +# Curl has used many names over the years... +CVE_PRODUCT = "haxx:curl haxx:libcurl curl:curl curl:libcurl libcurl:libcurl daniel_stenberg:curl" + +inherit autotools pkgconfig binconfig multilib_header + +PACKAGECONFIG ??= "${@bb.utils.filter('DISTRO_FEATURES', 'ipv6', d)} gnutls libidn proxy threaded-resolver verbose zlib" +PACKAGECONFIG_class-native = "ipv6 proxy ssl threaded-resolver verbose zlib" +PACKAGECONFIG_class-nativesdk = "ipv6 proxy ssl threaded-resolver verbose zlib" + +# 'ares' and 'threaded-resolver' are mutually exclusive +PACKAGECONFIG[ares] = "--enable-ares,--disable-ares,c-ares,,,threaded-resolver" +PACKAGECONFIG[brotli] = "--with-brotli,--without-brotli,brotli" +PACKAGECONFIG[builtinmanual] = "--enable-manual,--disable-manual" +PACKAGECONFIG[dict] = "--enable-dict,--disable-dict," +PACKAGECONFIG[gnutls] = "--with-gnutls,--without-gnutls,gnutls" +PACKAGECONFIG[gopher] = "--enable-gopher,--disable-gopher," +PACKAGECONFIG[imap] = "--enable-imap,--disable-imap," +PACKAGECONFIG[ipv6] = "--enable-ipv6,--disable-ipv6," +PACKAGECONFIG[krb5] = "--with-gssapi,--without-gssapi,krb5" +PACKAGECONFIG[ldap] = "--enable-ldap,--disable-ldap," +PACKAGECONFIG[ldaps] = "--enable-ldaps,--disable-ldaps," +PACKAGECONFIG[libidn] = "--with-libidn2,--without-libidn2,libidn2" +PACKAGECONFIG[libssh2] = "--with-libssh2,--without-libssh2,libssh2" +PACKAGECONFIG[mbedtls] = "--with-mbedtls=${STAGING_DIR_TARGET},--without-mbedtls,mbedtls" +PACKAGECONFIG[mqtt] = "--enable-mqtt,--disable-mqtt," +PACKAGECONFIG[nghttp2] = "--with-nghttp2,--without-nghttp2,nghttp2" +PACKAGECONFIG[pop3] = "--enable-pop3,--disable-pop3," +PACKAGECONFIG[proxy] = "--enable-proxy,--disable-proxy," +PACKAGECONFIG[rtmpdump] = "--with-librtmp,--without-librtmp,rtmpdump" +PACKAGECONFIG[rtsp] = "--enable-rtsp,--disable-rtsp," +PACKAGECONFIG[smb] = "--enable-smb,--disable-smb," +PACKAGECONFIG[smtp] = "--enable-smtp,--disable-smtp," +PACKAGECONFIG[ssl] = "--with-ssl --with-random=/dev/urandom,--without-ssl,openssl" +PACKAGECONFIG[nss] = "--with-nss,--without-nss,nss" +PACKAGECONFIG[telnet] = "--enable-telnet,--disable-telnet," +PACKAGECONFIG[tftp] = "--enable-tftp,--disable-tftp," +PACKAGECONFIG[threaded-resolver] = "--enable-threaded-resolver,--disable-threaded-resolver,,,,ares" +PACKAGECONFIG[verbose] = "--enable-verbose,--disable-verbose" +PACKAGECONFIG[zlib] = "--with-zlib=${STAGING_LIBDIR}/../,--without-zlib,zlib" + +EXTRA_OECONF = " \ + --disable-libcurl-option \ + --disable-ntlm-wb \ + --enable-crypto-auth \ + --with-ca-bundle=${sysconfdir}/ssl/certs/ca-certificates.crt \ + --without-libmetalink \ + --without-libpsl \ + --enable-debug \ + --enable-optimize \ + --disable-curldebug \ +" + +do_install_append_class-target() { + # cleanup buildpaths from curl-config + sed -i \ + -e 's,--sysroot=${STAGING_DIR_TARGET},,g' \ + -e 's,--with-libtool-sysroot=${STAGING_DIR_TARGET},,g' \ + -e 's|${DEBUG_PREFIX_MAP}||g' \ + ${D}${bindir}/curl-config +} + +PACKAGES =+ "lib${BPN}" + +FILES_lib${BPN} = "${libdir}/lib*.so.*" +RRECOMMENDS_lib${BPN} += "ca-certificates" + +FILES_${PN} += "${datadir}/zsh" + +inherit multilib_script +MULTILIB_SCRIPTS = "${PN}-dev:${bindir}/curl-config" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta-openbmc-mods/meta-common/recipes-support/gnutls/gnutls_%.bbappend b/meta-openbmc-mods/meta-common/recipes-support/gnutls/gnutls_%.bbappend new file mode 100644 index 000000000..4377bf0e3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/gnutls/gnutls_%.bbappend @@ -0,0 +1,12 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PV = "3.6.15" + +SHRT_VER = "${@d.getVar('PV').split('.')[0]}.${@d.getVar('PV').split('.')[1]}" +SRC_URI = "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar.xz \ + " +SRC_URI[md5sum] = "e80e0d20a8bb337a15fa63caa7f67006" +#SRC_URI[sha256sum] = "3847a3354dd908c5e603f490865ae10577d7ee3b5edf35e82d1ed8cfa1cf0191" +SRC_URI[sha256sum] = "0ea8c3283de8d8335d7ae338ef27c53a916f15f382753b174c18b45ffd481558" + + diff --git a/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/Add-target-to-only-build-tests-not-run-them.patch b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/Add-target-to-only-build-tests-not-run-them.patch new file mode 100644 index 000000000..e3f5c6de7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/Add-target-to-only-build-tests-not-run-them.patch @@ -0,0 +1,45 @@ +Add target to only build tests (not run them) + +Not sending upstream as this is only a start of a solution to +installable tests: It's useful for us already as is. + +Upstream-Status: Inappropriate [not a complete solution] + +Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com> +Refactored for 3.4 +Signed-off-by: Armin Kuster <akuster@mvista.com> +--- + Makefile.in | 3 +++ + testsuite/Makefile.in | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/Makefile.in b/Makefile.in +index e5ccfc7..15c9275 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -52,6 +52,9 @@ clean distclean mostlyclean maintainer-clean tags: + echo "Making $@ in $$d" ; (cd $$d && $(MAKE) $@); done + $(MAKE) $@-here + ++buildtest: ++ echo "Making $@ in testsuite" ; (cd testsuite && $(MAKE) $@) ++ + check-here: + true + +diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in +index 3f5e5f6..8fd68a3 100644 +--- a/testsuite/Makefile.in ++++ b/testsuite/Makefile.in +@@ -122,6 +122,8 @@ $(TARGETS) $(EXTRA_TARGETS): testutils.$(OBJEXT) ../nettle-internal.$(OBJEXT) \ + # data. + VALGRIND = valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes @IF_ASM@ --partial-loads-ok=yes + ++buildtest: $(TS_ALL) ++ + check: $(TS_ALL) + TEST_SHLIB_DIR="$(TEST_SHLIB_DIR)" \ + srcdir="$(srcdir)" \ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/check-header-files-of-openssl-only-if-enable_.patch b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/check-header-files-of-openssl-only-if-enable_.patch new file mode 100644 index 000000000..d5f266681 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/check-header-files-of-openssl-only-if-enable_.patch @@ -0,0 +1,36 @@ +From ffee6b5f6204a0210f717968ec6ce514d70acca1 Mon Sep 17 00:00:00 2001 +From: Haiqing Bai <Haiqing.Bai@windriver.com> +Date: Fri, 9 Dec 2016 15:23:17 +0800 +Subject: [PATCH] nettle: check header files of openssl only if + 'enable_openssl=yes'. + +The original configure script checks openssl header files to generate +config.h even if 'enable_openssl' is not set to yes, this made inconsistent +building for nettle. + +Upstream-Status: Pending +Signed-off-by: Haiqing Bai <Haiqing.Bai@windriver.com> + +refactored for 3.4. pending not in as of 3.4 + +Signed-off-by: Armin Kuster <akuster@mvista.com> + +Index: nettle-3.4/configure.ac +=================================================================== +--- nettle-3.4.orig/configure.ac ++++ nettle-3.4/configure.ac +@@ -185,9 +185,11 @@ AC_HEADER_TIME + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(size_t) + +-AC_CHECK_HEADERS([openssl/evp.h openssl/ecdsa.h],, +-[enable_openssl=no +- break]) ++if test "x$enable_openssl" = "xyes"; then ++ AC_CHECK_HEADERS([openssl/evp.h openssl/ecdsa.h],, ++ [enable_openssl=no ++ break]) ++fi + + # For use by the testsuite + AC_CHECK_HEADERS([valgrind/memcheck.h]) diff --git a/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/dlopen-test.patch b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/dlopen-test.patch new file mode 100644 index 000000000..ab9b91f88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/dlopen-test.patch @@ -0,0 +1,29 @@ +Remove the relative path for libnettle.so so the test +program can find it. +Relative paths are not suitable, as the folder strucure for ptest +is different from the one expected by the nettle testsuite. + +Upstream-Status: Inappropriate [embedded specific] + +Signed-off-by: Juro Bystricky <juro.bystricky@intel.com> +Signed-off-by: Mingli Yu <mingli.yu@windriver.com> +--- + testsuite/dlopen-test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/testsuite/dlopen-test.c b/testsuite/dlopen-test.c +index 4265bf7..1a25d17 100644 +--- a/testsuite/dlopen-test.c ++++ b/testsuite/dlopen-test.c +@@ -15,7 +15,7 @@ int + main (int argc UNUSED, char **argv UNUSED) + { + #if HAVE_LIBDL +- void *handle = dlopen ("../libnettle." SO_EXT, RTLD_NOW); ++ void *handle = dlopen ("libnettle.so", RTLD_NOW); + int (*get_version)(void); + if (!handle) + { +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/run-ptest b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/run-ptest new file mode 100644 index 000000000..b90bed66d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle/run-ptest @@ -0,0 +1,36 @@ +#! /bin/sh + +cd testsuite + +failed=0 +all=0 + +for f in *-test; do + if [ "$f" = "sha1-huge-test" ] ; then + echo "SKIP: $f (skipped for ludicrous run time)" + continue + fi + + "./$f" + case "$?" in + 0) + echo "PASS: $f" + all=$((all + 1)) + ;; + 77) + echo "SKIP: $f" + ;; + *) + echo "FAIL: $f" + failed=$((failed + 1)) + all=$((all + 1)) + ;; + esac +done + +if [ "$failed" -eq 0 ] ; then + echo "All $all tests passed" +else + echo "$failed of $all tests failed" +fi + diff --git a/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle_3.7.2.bb b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle_3.7.2.bb new file mode 100644 index 000000000..f8f336008 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/nettle/nettle_3.7.2.bb @@ -0,0 +1,57 @@ +SUMMARY = "A low level cryptographic library" +DESCRIPTION = "Nettle is a cryptographic library that is designed to fit easily in more or less any context: In crypto toolkits for object-oriented languages (C++, Python, Pike, ...), in applications like LSH or GNUPG, or even in kernel space." +HOMEPAGE = "http://www.lysator.liu.se/~nisse/nettle/" +DESCRIPTION = "It tries to solve a problem of providing a common set of \ +cryptographic algorithms for higher-level applications by implementing a \ +context-independent set of cryptographic algorithms" +SECTION = "libs" +LICENSE = "LGPLv3+ | GPLv2+" + +LIC_FILES_CHKSUM = "file://COPYING.LESSERv3;md5=6a6a8e020838b23406c81b19c1d46df6 \ + file://COPYINGv2;md5=b234ee4d69f5fce4486a80fdaf4a4263 \ + file://serpent-decrypt.c;beginline=14;endline=36;md5=ca0d220bc413e1842ecc507690ce416e \ + file://serpent-set-key.c;beginline=14;endline=36;md5=ca0d220bc413e1842ecc507690ce416e" + +DEPENDS += "gmp" + +SRC_URI = "${GNU_MIRROR}/${BPN}/${BP}.tar.gz \ + file://Add-target-to-only-build-tests-not-run-them.patch \ + file://run-ptest \ + file://check-header-files-of-openssl-only-if-enable_.patch \ + " + +SRC_URI_append_class-target = "\ + file://dlopen-test.patch \ + " + +SRC_URI[sha256sum] = "8d2a604ef1cde4cd5fb77e422531ea25ad064679ff0adf956e78b3352e0ef162" + +UPSTREAM_CHECK_REGEX = "nettle-(?P<pver>\d+(\.\d+)+)\.tar" + +inherit autotools ptest multilib_header + +EXTRA_AUTORECONF += "--exclude=aclocal" + +EXTRA_OECONF = "--disable-openssl" + +do_compile_ptest() { + oe_runmake buildtest +} + +do_install_append() { + oe_multilib_header nettle/version.h +} + +do_install_ptest() { + install -d ${D}${PTEST_PATH}/testsuite/ + install ${S}/testsuite/gold-bug.txt ${D}${PTEST_PATH}/testsuite/ + install ${S}/testsuite/*-test ${D}${PTEST_PATH}/testsuite/ + # tools can be found in PATH, not in ../tools/ + sed -i -e 's|../tools/||' ${D}${PTEST_PATH}/testsuite/*-test + install ${B}/testsuite/*-test ${D}${PTEST_PATH}/testsuite/ +} + +RDEPENDS_${PN}-ptest += "${PN}-dev" +INSANE_SKIP_${PN}-ptest += "dev-deps" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default new file mode 100644 index 000000000..b9f8e0363 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default @@ -0,0 +1 @@ +EXTRA_ARGS="-r /dev/hwrng" diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init new file mode 100644 index 000000000..13f0ecd37 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init @@ -0,0 +1,42 @@ +#!/bin/sh +# +# This is an init script for openembedded +# Copy it to @SYSCONFDIR@/init.d/rng-tools and type +# > update-rc.d rng-tools defaults 60 +# + +rngd=@SBINDIR@/rngd +test -x "$rngd" || exit 1 + +[ -r @SYSCONFDIR@/default/rng-tools ] && . "@SYSCONFDIR@/default/rng-tools" + +case "$1" in + start) + echo -n "Starting random number generator daemon" + start-stop-daemon -S -q -x $rngd -- $EXTRA_ARGS + echo "." + ;; + stop) + echo -n "Stopping random number generator daemon" + start-stop-daemon -K -q -n rngd + echo "." + ;; + reload|force-reload) + echo -n "Signalling rng daemon restart" + start-stop-daemon -K -q -s 1 -x $rngd + start-stop-daemon -K -q -s 1 -x $rngd + ;; + restart) + echo -n "Stopping random number generator daemon" + start-stop-daemon -K -q -n rngd + echo "." + echo -n "Starting random number generator daemon" + start-stop-daemon -S -q -x $rngd -- $EXTRA_ARGS + echo "." + ;; + *) + echo "Usage: @SYSCONFDIR@/init.d/rng-tools {start|stop|reload|restart|force-reload}" + exit 1 +esac + +exit 0 diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service new file mode 100644 index 000000000..d76e9a0c4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service @@ -0,0 +1,10 @@ +[Unit] +Description=Hardware RNG Entropy Gatherer Daemon + +[Service] +EnvironmentFile=-@SYSCONFDIR@/default/rng-tools +ExecStart=@SBINDIR@/rngd -f $EXTRA_ARGS +Nice=15 + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb new file mode 100644 index 000000000..b4e453f67 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb @@ -0,0 +1,52 @@ +SUMMARY = "Random number generator daemon" +DESCRIPTION = "Check and feed random data from hardware device to kernel" +AUTHOR = "Philipp Rumpf, Jeff Garzik <jgarzik@pobox.com>, \ + Henrique de Moraes Holschuh <hmh@debian.org>" +HOMEPAGE = "https://github.com/nhorman/rng-tools" +BUGTRACKER = "https://github.com/nhorman/rng-tools/issues" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263" +DEPENDS = "sysfsutils" + +SRC_URI = "\ + git://github.com/nhorman/rng-tools.git \ + file://init \ + file://default \ + file://rngd.service \ +" +SRCREV = "9fc873c5af0e392632e6b736938b811f7ca97251" + +S = "${WORKDIR}/git" + +inherit autotools update-rc.d systemd pkgconfig + +PACKAGECONFIG ??= "libgcrypt libjitterentropy" +PACKAGECONFIG_libc-musl = "libargp libjitterentropy" + +PACKAGECONFIG[libargp] = "--with-libargp,--without-libargp,argp-standalone," +PACKAGECONFIG[libgcrypt] = "--with-libgcrypt,--without-libgcrypt,libgcrypt," +PACKAGECONFIG[libjitterentropy] = "--enable-jitterentropy,--disable-jitterentropy,libjitterentropy" +PACKAGECONFIG[libp11] = "--with-pkcs11,--without-pkcs11,libp11 openssl" +PACKAGECONFIG[nistbeacon] = "--with-nistbeacon,--without-nistbeacon,curl libxml2 openssl" + +INITSCRIPT_NAME = "rng-tools" +INITSCRIPT_PARAMS = "start 03 2 3 4 5 . stop 30 0 6 1 ." + +SYSTEMD_SERVICE_${PN} = "rngd.service" + +# Refer autogen.sh in rng-tools +do_configure_prepend() { + cp ${S}/README.md ${S}/README +} + +do_install_append() { + install -Dm 0644 ${WORKDIR}/default ${D}${sysconfdir}/default/rng-tools + install -Dm 0755 ${WORKDIR}/init ${D}${sysconfdir}/init.d/rng-tools + install -Dm 0644 ${WORKDIR}/rngd.service \ + ${D}${systemd_system_unitdir}/rngd.service + sed -i \ + -e 's,@SYSCONFDIR@,${sysconfdir},g' \ + -e 's,@SBINDIR@,${sbindir},g' \ + ${D}${sysconfdir}/init.d/rng-tools \ + ${D}${systemd_system_unitdir}/rngd.service +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb new file mode 100644 index 000000000..51cda82e9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb @@ -0,0 +1,17 @@ +SUMMARY = "Beeper Test App" +DESCRIPTION = "Beeper Test Application for pwm-beeper" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM += "\ + file://beeper-test.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \ + " + +SRC_URI = "\ + file://CMakeLists.txt \ + file://beeper-test.cpp \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format new file mode 100644 index 000000000..ea71ad6e1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format @@ -0,0 +1,99 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt new file mode 100644 index 000000000..81a0c7e81 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(beeper-test CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(beeper-test beeper-test.cpp) +install(TARGETS beeper-test DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp new file mode 100644 index 000000000..31dafdd88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp @@ -0,0 +1,81 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: pwm-beeper test application +// +*/ + +#include <fcntl.h> +#include <linux/input.h> +#include <stdio.h> +#include <unistd.h> + +#include <cstring> +#include <iostream> + +int main(int argc, char** argv) +{ + if (argc < 3) + { + std::cout << "usage: <input device> <sequence of 'tone in " + "Hz','duration in ms' pair>\n"; + std::cout << "example: beeper-test /dev/input/event0 " + "2100,100,0,150,2500,50,0,50,2200,100\n"; + return 1; + } + + int fd; + if ((fd = open(argv[1], O_RDWR | O_CLOEXEC)) < 0) + { + perror("Failed to open input device"); + return -1; + } + + struct input_event event; + event.type = EV_SND; + event.code = SND_TONE; + + char* pch = strtok(argv[2], ","); + while (pch != NULL) + { + event.value = atoi(pch); + + pch = strtok(NULL, ","); + if (!pch) + { + std::cerr << "Invalid tone,duration pair\n"; + close(fd); + return -1; + } + + int durationMs = atoi(pch); + + if (write(fd, &event, sizeof(struct input_event)) != + sizeof(struct input_event)) + { + perror("Failed to write a tone sound event"); + close(fd); + return -1; + } + + usleep(durationMs * 1000); + + pch = strtok(NULL, ","); + } + + close(fd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb new file mode 100644 index 000000000..78240c0f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb @@ -0,0 +1,17 @@ +SUMMARY = "Dimm Sensor" +DESCRIPTION = "Dimm Sensor Executable" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://DimmSensor.cpp \ + " + +LICENSE = "CLOSED" + +S = "${WORKDIR}" + +inherit cmake + +# linux-libc-headers guides this way to include custom uapi headers +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +do_configure[depends] += "virtual/kernel:do_shared_workdir" diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt new file mode 100644 index 000000000..6262f8dee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(dimmsensor CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(dimmsensor DimmSensor.cpp) +install (TARGETS dimmsensor DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp new file mode 100644 index 000000000..9cc13c2a5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp @@ -0,0 +1,143 @@ +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <vector> +#include <linux/aspeed_peci_ioctl.h> + +#define PECI_DIMM_TEMP_REG 0x150 +#define DIMM_DEFAULT_VALUE 0x55 + +class DimmConfig { + public: + uint8_t chanId, bus, device, function, dimmnum; +}; + +#define MAX_BUFFER_SIZE 32 + +// TODO get this from config +auto GetDimmConfig(uint8_t dimm) { + uint8_t chan = dimm / 2; + assert(chan < 6); + + auto ret = std::make_unique<DimmConfig>(); + + ret->chanId = chan; + ret->dimmnum = 2; + ret->bus = 2; + switch (chan) { + case 0: + ret->device = 10; + ret->function = 2; + break; + case 1: + ret->device = 10; + ret->function = 6; + break; + case 2: + ret->device = 11; + ret->function = 2; + break; + case 3: + ret->device = 12; + ret->function = 2; + break; + case 4: + ret->device = 12; + ret->function = 6; + break; + case 5: + ret->device = 13; + ret->function = 2; + break; + default: + assert(0); + break; + } + + return ret; +} + +// returns read vector on success, empty vector on failure +auto peci_config_local(uint8_t u8target, uint8_t u8bus, uint8_t u8device, + uint8_t u8fcn, uint16_t u16reg, uint8_t u8readlen) { + auto msg = std::make_unique<peci_xfer_msg>(); + uint32_t u32Address; + int fd; + std::vector<uint8_t> ret; + + u32Address = u16reg; + u32Address |= u8fcn << 12; + u32Address |= u8device << 15; + u32Address |= u8bus << 20; + + msg->client_addr = u8target; + msg->tx_len = RDPCICFGLOCAL_WRITE_LEN; + msg->rx_len = RDPCICFGLOCAL_READ_LEN_BASE + u8readlen; + + msg->tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; + msg->tx_buf[2] = u32Address & 0xFF; + msg->tx_buf[3] = (u32Address >> 8) & 0xFF; + msg->tx_buf[4] = (u32Address >> 16) & 0xFF; + + fd = open("/dev/peci", O_RDWR | O_CLOEXEC); + if (fd >= 0) { + int success = ioctl(fd, PECI_IOC_XFER, msg.get()); + if (success == 0) { + if (DEV_PECI_CC_SUCCESS == msg->rx_buf[0]) { + ret.resize(RDPCICFGLOCAL_READ_LEN_BASE + u8readlen - 1); + memcpy(ret.data(), &(msg->rx_buf[1]), ret.size()); + } + } + close(fd); + } + return ret; +} + +int main(int argc, char** argv) { + if (argc != 3) { + std::cout << argv[0] << " requires 2 arguments: CPUNum, DimmNum.\n"; + return -1; + } + uint8_t cpunum = atoi(argv[1]); + if (cpunum > 3) { + std::cout << cpunum << " greater than cpu max of 3.\n"; + return -1; + } + uint8_t dimmnum = atoi(argv[2]); + if (dimmnum > 11) { + std::cout << dimmnum << " greater than dimm max of 11.\n"; + return -1; + } + + auto dimm_config = GetDimmConfig(dimmnum); + + uint8_t dimmSelect = dimmnum % 2; // dimm 0 or 1 for each config + + auto val = peci_config_local(PECI_BASE_ADDR + cpunum, dimm_config->bus, + dimm_config->device, dimm_config->function, + PECI_DIMM_TEMP_REG + dimmSelect * 4, 4); + + if (!val.size()) { + std::cout << "Peci Error\n"; + return -1; + } + + // TODO dimm offsets needed? + + if (val[0] == 0) + std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum) + << " not populated.\n"; + else if(val[0] == DIMM_DEFAULT_VALUE) + std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum) + << " in illegal state.\n"; + else + std::cout << unsigned(val[0]) << " degrees C.\n"; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/i3c-tools/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/i3c-tools/files/CMakeLists.txt new file mode 100644 index 000000000..5a049e9ff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/i3c-tools/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(i3c-tools C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +include_directories(include) +add_executable(i3ctransfer i3ctransfer.c) +install(TARGETS i3ctransfer DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/i3c-tools/i3c-tools.bb b/meta-openbmc-mods/meta-common/recipes-utilities/i3c-tools/i3c-tools.bb new file mode 100644 index 000000000..89dbf1d68 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/i3c-tools/i3c-tools.bb @@ -0,0 +1,25 @@ +SUMMARY = "i3c-tools" +DESCRIPTION = "Set of tools to interact with i3c devices from user space" + +SRC_URI = "git://github.com/vitor-soares-snps/i3c-tools.git" +SRCREV = "5d752038c72af8e011a2cf988b1476872206e706" + +S = "${WORKDIR}/git" + +PV = "0.1+git${SRCPV}" + +LICENSE = "GPL-2.0" +LIC_FILES_CHKSUM = "\ + file://i3ctransfer.c;beginline=1;endline=6;md5=8a1ae5c1aaf128e640de497ceaa9935e \ + " + +inherit cmake + +SRC_URI += "\ + file://CMakeLists.txt \ + " + +do_configure_prepend() { + cp -f ${WORKDIR}/CMakeLists.txt ${S} +} + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini new file mode 100644 index 000000000..38609ad5d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini @@ -0,0 +1,277 @@ +; +; Copyright 2015 Intel Corporation. +; +; The source code, information and material ("Material") contained herein is +; owned by Intel Corporation or its suppliers or licensors, and title to such +; Material remains with Intel Corporation or its suppliers or licensors. The +; Material contains proprietary information of Intel or its suppliers and +; licensors. The Material is protected by worldwide copyright laws and treaty +; provisions. No part of the Material may be used, copied, reproduced, +; modified, published, uploaded, posted, transmitted, distributed or disclosed +; in any way without Intel's prior express written permission. No license under +; any patent, copyright or other intellectual property rights in the Material +; is granted to or conferred upon you, either expressly, by implication, +; inducement, estoppel or otherwise. Any license under such intellectual +; property rights must be express and approved by Intel in writing. + +; +; This file is similar to the config.genimage2 file of previous BMC +; generations but it is not generated. It contains all of the information +; to generate the signed-image variant of the signtool config file. +; + +[GLOBAL] +Major = 0 +Minor = 72 +Output = update.bin +Alloc = 33792K ; 0x2100000 +BlockSize = 64K +Type = 0xffffffff ; generate top level composite image +Locate = 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Factory ROM file generation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +RomOutput = rom-a-only.ima +RomAlloc = 33M +KeyRegion = Certificate +NewKeyRegion = ReplacementCertificate +SecVersion = 0 + + + +; RecoveryOnly items should be place first in the image + +[FRISBEE_ROM] +Major = 1 +Minor = 5 +Type = ROBL +File = frisbee.bin +Locate = 0x00000000 +Alloc = 240K +Compress = 0 +SecVersion = 1 +Unsigned = 1 + +[Certificate] +Locate = 0x3c000 +Type = CERT +Alloc = 8K +Fill = 0xff +Unsigned = 1 +ROMOnly = 1 +SecVersion = 0 + +;[FWPRODUCTID] +;Major = 1 +;Minor = 0 +;Type = FWID +;File = fwproductid.bin +;Locate = 0x0003f000 +;ROMOnly = 1 +;SecVersion = 0 + +[FRISBEE_UPD] +Major = 1 +Minor = 5 +Type = RWBL +File = frisbee.bin +Locate = 0x040000 +Alloc = 256K +Compress = 0 +SecVersion = 1 +IndivSign = 1 +SigOffset = 0x03e000 + +[U-Boot] +Major = 1 +Minor = 5 +Type = UBT\x00 +File = u-boot.bin +Alloc = 256K +Compress = 0 +SecVersion = 1 +IndivSign = 1 +SigOffset = 0x03e000 + +; Linux OS Image +[OSIMAGE] +Major = 1 +Minor = 1 +Type = LKNL +File = uImage +SecVersion = 1 + +[DTB] +Major = 1 +Minor = 1 +Type = DTB\x00 +File = uImage-aspeed-bmc-intel-ast2500.dtb +SecVersion = 0 + +; Root File System +[ROOT] +Major = 1 +Minor = 1 +Type = RtFS +File = image-rofs.squashfs-xz.u-boot +Load = 0x83000000 +SecVersion = 1 +; +; WWW File System in CRAMFS. +;[WWW] +;Major = 1 +;Minor = 1 +;Type = WWW\x00 +;File = webfs.bin +;BlockDev = 1 +;SecVersion = 1 + +; Replacement certificate for re-keying the BMC +; Will only be added to image if -rk is specified +[ReplacementCertificate] +Major = 1 +Minor = 1 +Type = CRT0 +Alloc = 4K +SecVersion = 0 +Compress = 0 +IndivSign = 1 +Unbound = 1 +Fill = 0xff +SigOffset = 0x800 + +; Manifest goes here +; This gets some special treatment (this needs to match the location +; that Frisbee thinks the manifest is at or it won't boot) +[Manifest] +Major = 0 +Minor = 0 +Type = MFST +Alloc = 4K +Locate = 0x1bff000 +Fill = 0xff +SecVersion = 0 + +; +; NV File System in JFFS2, but it is blank in the ROM version +; and filled in with defaults from the rootfs +[PARAMS] +Major = 1 +Minor = 1 +Type = CONF +Alloc = 4096K +Locate = 0x1c00000 +ROMOnly = 1 +BlockDev = 1 +SecVersion = 1 +Unsigned = 1 + +; notice that these sections have no file +; and are marked as ROMOnly. This forces them +; into the allocation so we don't get overlapping +; sections, but does not actually put anything into +; the rom at build time. + +[UBootEnv] +Major = 1 +Minor = 0 +Type = UENV +; File = ; no file makes this a placeholder +Locate = 0x2000000 +Alloc = 64K +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[FRUData] +Major = 1 +Minor = 0 +Type = FRU\x00 +Alloc = 64K +Locate = 0x2010000 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[SEL] +Major = 1 +Minor = 0 +Type = SEL\x00 +Alloc = 512K +Locate = 0x2020000 +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +; NV filesystem that survives reset mfg defaults. +; OEM Web customization goes here. +[PersistentNV] +Major = 1 +Minor = 0 +Type = PNV\x00 +Alloc = 2048K +Locate = 0x20a0000 +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[RubixLog] +Major = 1 +Minor = 0 +Type = BTLG +Alloc = 4K +Locate = 0x23fe000 +BlockDev = 0 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[BootPointer] +Major = 1 +Minor = 0 +Type = BPTR +Alloc = 4K +Locate = 0x23ff000 +BlockDev = 0 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +; +; Example Section with all possible fields with their default +; values, unless the field is specified mandatory +; +;[EXAMPLE] +;Major = 0 ; Major number of module +;Minor = 0 ; Minor number of module +;Type = TYPE ; four bytes hopefully human readable, +; ; use c-style escapes if non-ascii, \x23\x10\x00\xf3 +; ; or use a number 0xf3001023 +;Alloc = X ; Maximum memory allocated; X = roundup +;File = name ; File containing the module +; ; If Alloc is specified, but no File, a blank +; ; header will be created (only useful for ROMOnly) +;Locate = addr ; Location in Flash; MANDATORY +;ROMOnly = 1 ; if ROMOnly is set and non-zero, this section +; ; will only be present in the ROM image, not the updater image +;RecoveryOnly = 1 ; if RecoveryOnly is set and non-zero, this section +; ; will only be present in the recovery image, not the active image +;BlockDev = 1 ; this will make the signed image code export this +; ; image as a mtd block device at runtime +;Unsigned = 1 ; Do not include this section in signatures (NV data) +;Compress = 1 ; compress image contents (useful for non-compressed items) +;SecVersion = X ; a 16-bit security revision to enforce no downgrades +;IndivSign = 1 ; section is individually signed; do not include in full signature +;Unbound = 1 ; by default, individually signed sections are part of the +; ; full signature too. This makes them independent +;SigOffset = X ; offset within individually-signed section to place signature +;Fill = xx ; fill with pattern xx instead of a file's contents +; +; Note: Numeric values can be represented either by decimal or a +; hexadecimal (Prefixed by 0x) +; Numeric values can either end with K or M to specify in +; KiloBytes or MegaBytes +; diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt new file mode 100644 index 000000000..0c98160b9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(io-app C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +add_executable(io io-app.c) +install (TARGETS io DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c new file mode 100644 index 000000000..955674fa6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c @@ -0,0 +1,696 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: map io region to read or write to HW registers +// +*/ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> + +static int quiet = 0; + +static int dump(unsigned long phys, void *addr, size_t len) +{ + const uint32_t *ubuf = addr; + unsigned int wd = 0, l, iv; + unsigned char *h, *a; + char line[256]; + static const char itoh[] = "0123456789abcdef"; + + /* 0 1 2 3 4 5 6 + * 0123456789012345678901234567890123456789012345678901234567890123456789 + * 00000000: 00000000 00000000 00000000 00000000 ................ + */ + while (wd < len) + { + memset(line, ' ', sizeof(line)); + sprintf(line, "%08lx: ", phys + (wd*sizeof(uint32_t))); + a = (unsigned char*)&line[47]; + h = (unsigned char*)&line[10]; + for (l=0; l<4 && (l+wd)<len; l++) + { + uint32_t v = *ubuf++; + for (iv=0; iv<sizeof(v); iv++) + { + uint8_t b = v >> (8*((sizeof(v)-1)-iv)); + *h++ = itoh[b>>4]; + *h++ = itoh[b&0xf]; + if (isprint(b)) + *a++ = (char)b; + else + *a++ = '.'; + } + *h++ = ' '; + } + *a++ = '\n'; + *a = 0; + wd += l; + fputs(line, stdout); + } + return wd; +} + + +struct mapping +{ + unsigned long phys; + void *virt; + size_t len; +}; + +static struct mapping *maps = NULL; +static int nr_maps = 0; + +static void unmap_all(void) +{ + int i; + for (i=0; i<nr_maps; i++) + { + if (maps[i].virt) + munmap(maps[i].virt, maps[i].len); + maps[i].virt = NULL; + } +} + +int add_a_map(unsigned long phys, void *virt, size_t len) +{ + void *new_maps; + new_maps = realloc(maps, (nr_maps + 1) * sizeof(struct mapping)); + if (!new_maps) + { + unmap_all(); + munmap(virt, len); + } + else + { + maps = new_maps; + maps[nr_maps].phys = phys; + maps[nr_maps].virt = virt; + maps[nr_maps].len = len; + nr_maps++; + return 0; + } + return -1; +} + +static void *map_fd(int fd, off_t offset, size_t len, int mode, int flags) +{ + void *mapped_at; + unsigned long phys = -1; + + if (offset != -1) + phys = offset; + else + offset = 0; + + mapped_at = mmap(NULL, len, mode, flags, fd, offset); + if (mapped_at != MAP_FAILED) + { + if (add_a_map(phys, mapped_at, len) != 0) + { + mapped_at = MAP_FAILED; + } + } + + return mapped_at; +} + +static void *map_file(const char *fname, size_t *len, int mode, int flags) +{ + int fd; + struct stat sb; + void *ptr; + int fmode; + + if (mode & PROT_WRITE) + fmode = O_RDWR; + else + fmode = O_RDONLY; + + fd = open(fname, fmode); + if (fd < 0) + return MAP_FAILED; + + if (*len == 0) + { + fstat(fd, &sb); + *len = sb.st_size; + } + ptr = map_fd(fd, -1, *len, mode, flags); + close(fd); + return ptr; +} + +static int load_maps(const char *cmap_str, size_t mlen) +{ + char *tmp_sa = NULL, *tmp_sl = NULL, *endptr = NULL; + const void *mapped = NULL; + int ret = 0; + const char *delim = "\r\n\t ,"; + unsigned long addr; + size_t len; + char *map_str = NULL, *paddr = NULL, *plen = NULL; + int fd; + + fd = open("/dev/mem", O_RDWR); + if (fd < 0) + { + return -1; + } + + len = strlen(cmap_str); + map_str = (char *)malloc(len + 1); + if (!map_str) + { + close(fd); + return -1; + } + strncpy(map_str, cmap_str, len); + map_str[len] = '\0'; + paddr = strtok_r(map_str, delim, &tmp_sa); + while (paddr) + { + /* find the next comma or newline */ + if (!strtok_r(paddr, ":", &tmp_sl)) + { + fprintf(stderr, "malformed map string '%s'\n", paddr); + goto _loop; + } + plen = strtok_r(NULL, ":", &tmp_sl); + if (!plen) + { + goto _loop; + } + addr = strtoul(paddr, &endptr, 16); + if (*endptr) + { + fprintf(stderr, "Failed to parse address from '%s'\n", paddr); + ret = -1; + break; + } + len = strtoul(plen, &endptr, 16); + if (*endptr) + { + fprintf(stderr, "Failed to parse len from '%s'\n", plen); + ret = -1; + break; + } + if (MAP_FAILED == (mapped = map_fd(fd, addr, len, PROT_READ|PROT_WRITE, MAP_SHARED))) + { + fprintf(stderr, "Failed to map %lx +%x\n", addr, len); + ret = -1; + break; + } + if (!quiet) + printf("added map: %p (%lx..%lx)\n", mapped, addr, addr+len); +_loop: + paddr = strtok_r(NULL, delim, &tmp_sa); + } + free(map_str); + close(fd); + return ret; +} + +int md(unsigned long addr, uint32_t unused, size_t len) +{ + int i, j; + + (void)unused; + for (i=0; i<nr_maps; i++) + { + if (-1 == maps[i].phys) + continue; + if (maps[i].phys <= addr && + (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len)) + { + uint32_t *buf, *pv; + + buf = (uint32_t *)malloc(len*sizeof(uint32_t)); + if (!buf) + return 1; + pv = (uint32_t *)(maps[i].virt + (addr - maps[i].phys)); + for (j=0; j<len; j++) + buf[j] = *pv++; + + dump(addr, buf, len); + free(buf); + return 0; + } + } + fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len); + return 1; +} + +int mw(unsigned long addr, uint32_t val, size_t len) +{ + int i, j; + + for (i=0; i<nr_maps; i++) + { + if (-1 == maps[i].phys) + continue; + if (maps[i].phys <= addr && + (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len)) + { + for (j=0; j<len; j++) + { + *((uint32_t*)(maps[i].virt + (addr - maps[i].phys))) = val; + } + return 0; + } + } + fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len); + return 1; +} + +char *readline(char *buf, size_t len, FILE *f) +{ + int raw = 0; + size_t br = 0; + struct termios tios, orig_tios; + + if (!quiet) + { + /* put terminal in raw mode to get unbuffered io */ + if (tcgetattr(fileno(f), &orig_tios) == 0) + { + tios = orig_tios; + tios.c_iflag |= IGNPAR; + tios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); + tios.c_oflag &= ~OPOST; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + tcsetattr(fileno(f), TCSADRAIN, &tios); + raw = 1; + } + } + if (!raw) + { + return fgets(buf, len, f); + } + /* read in bytes one at a time and echo them */ + while (br < (len-1)) + { + int c = fgetc(f); + switch (c) + { + case 3: /* ^C */ + br = 0; + c = '\n'; + break; + case 4: + br = 0; + c = -1; + break; + case '\b': + if (br > 0) + { + fputs("\b \b", stdout); + br--; + } + break; + case '\r': + case '\n': + fputs("\r\n", stdout); + buf[br++] = '\n'; + break; + case ' '...'~': + fputc(c, stdout); + buf[br++] = c; + break; + break; + default: + break; + } + if (c == -1) + { + if (br == 0) + buf = NULL; + break; + } + if (c == '\r' || c == '\n') + break; + } + if (buf) + buf[br] = 0; + + tcsetattr(fileno(f), TCSADRAIN, &orig_tios); + return buf; +} + +#define MAX_LINE_LEN 4096 +int io(void) +{ + const char delim1[] = "\r\n;"; + const char delim2[] = "\t "; + char line[MAX_LINE_LEN]; + char *command, *cmd, *paddr, *pval, *plen, *endptr; + char *tmp_s1, *tmp_s2; + unsigned long addr; + uint32_t val; + size_t len; + int (*fn)(unsigned long, uint32_t, size_t); + + if (!quiet) + fputs("> ", stdout); + while (readline(line, MAX_LINE_LEN, stdin) != NULL && *line) + { + /* read next line or next command (up to newline or ';') */ + command = strtok_r(line, delim1, &tmp_s1); + if (!command || strlen(command) == 0) + goto _command_loop; + while (NULL != command && strlen(command) > 0) + { + cmd = strtok_r(command, delim2, &tmp_s2); + if (!cmd) + goto _cmd_err; + if (cmd[0] == 'q' || cmd[0] == 'Q') + return 0; + paddr = strtok_r(NULL, delim2, &tmp_s2); + if (!paddr) + goto _cmd_err; + addr = strtoul(paddr, &endptr, 16); + if (*endptr) + goto _cmd_err; + fn = NULL; + if (strncmp(cmd, "mw", 3) == 0) + { + fn = mw; + pval = strtok_r(NULL, delim2, &tmp_s2); + if (!pval) + goto _cmd_err; + val = strtoul(pval, &endptr, 16); + if (*endptr) + goto _cmd_err; + len = 1; + } + else if (strncmp(cmd, "md", 3) == 0) + { + fn = md; + len = 0x40; + val = 0; + } + else + { + goto _cmd_err; + } + plen = strtok_r(NULL, delim2, &tmp_s2); + if (plen) + { + len = strtoul(plen, &endptr, 16); + if (*endptr) + goto _cmd_err; + } + + if (fn) + fn(addr, val, len); + + command = strtok_r(NULL, delim1, &tmp_s1); + } +_command_loop: + if (!quiet) + fputs("> ", stderr); + continue; +_cmd_err: + fprintf(stderr, "md addr [len]\nmw addr val [len]\n" + "q[uit] | ctrl-d | ctrl-c to exit\n"); + if (!quiet) + fputs("> ", stderr); + } + return 0; +} + +typedef enum +{ + CPU_NONE = 0, + CPU_PILOT3, + CPU_PILOT4, + CPU_AST2500, + CPU_AST2600, + CPU_MAX, +} CPU_TYPE; + +static CPU_TYPE probe_cpu(void) +{ + FILE *f; + char cpuinfo[128]; + static CPU_TYPE this_cpu = CPU_NONE; + + if (CPU_NONE == this_cpu) + { + f = fopen("/sys/firmware/devicetree/base/compatible", "r"); + if (f) { + int br = fread(cpuinfo, 1, sizeof(cpuinfo)-1, f); + if (br > 0) { + cpuinfo[br] = 0; + char *v = cpuinfo; + while (v < (cpuinfo + sizeof(cpuinfo)) && *v) { + if (strncmp("aspeed,ast2500", v, 15) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + } + v += 1 + strnlen(v, sizeof(cpuinfo) - (v - cpuinfo)); + } + } + fclose(f); + } + } + if (CPU_NONE == this_cpu) + { + const char delim[] = "\r\n\t :"; + char *tmp_s; + f = fopen("/proc/cpuinfo", "r"); + if (f != NULL) { + while (fgets(cpuinfo, sizeof(cpuinfo), f)) + { + strtok_r(cpuinfo, delim, &tmp_s); + if (strncmp("Hardware", cpuinfo, 9) == 0) + { + char *v = strtok_r(NULL, delim, &tmp_s); + if (v) + { + if (strncmp("AST2500", v, 8) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + break; + } + else if (strncmp("ASpeed SoC", v, 11) == 0) + { + if (!quiet) + fprintf(stderr, "Found ASpeed SoC\n"); + this_cpu = CPU_AST2500; + break; + } + else if (strncmp("ServerEngines PILOT3", v, 21) == 0) + { + if (!quiet) + fprintf(stderr, "Found PILOT3\n"); + this_cpu = CPU_PILOT3; + break; + } + } + } + else if (strncmp("CPU", cpuinfo, 4) == 0) + { + char *v = strtok_r(NULL, delim, &tmp_s); + if (!v || strncmp("part", v, 5) != 0) + { + continue; + } + v = strtok_r(NULL, delim, &tmp_s); + if (v) + { + if (strncmp("0xb76", v, 6) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + break; + } + else if (strncmp("0xc07", v, 6) == 0) + { + if (!quiet) + fprintf(stderr, "AST2600\n"); + this_cpu = CPU_AST2600; + break; + } + } + } + } + fclose(f); + } + } + return this_cpu; +} + +static const char *probe_cpu_for_map(void) +{ + switch (probe_cpu()) + { + case CPU_PILOT3: + return "0:2000000,10000000:8000,40000000:43b000"; + case CPU_AST2500: + return "0:4000000,1e600000:1a0000,20000000:4000000"; + case CPU_AST2600: + return "0:20000000,38000000:8000000,60000000:20000000"; + default: + return ""; + } +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: io [-c config] [-m map]\n" + " md [-c config] [-m map] <addr> [len]\n" + " mw [-c config] [-m map] <addr> <val> [len]\n\n" + "With: -c config load mappings from file config\n" + " -m map load mappings from string map\n" + " addr, val, len are all hex numbers\n\n" + "When invoked as io, this will start a shell that will\n" + "allow the user to type in md and mw commands much like\n" + "the U-Boot environment. By default, it will map in all\n" + "the addresses for the known processor type.\n\n" + "map string is of the format addr:len[,addr2:len2...]\n" + "config file is of the same format as map string\n" + "but with each mapping on separate lines instead of\n" + "comma separated values\n" + ); + exit(1); +} + +#define shift if (++i >= argc) usage() + +int main(int argc, const char *argv[]) +{ + char *exe_full; + char *exe; + char *endptr; + int i, first_arg = 1; + const char *cfg_file = NULL; + const char *map_str = NULL; + size_t flen = 0; + size_t len = 0; + unsigned long addr; + uint32_t val; + int ret = 0; + + i = 1; + while (i < argc) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'm': + shift; + map_str = argv[i]; + break; + case 'c': + shift; + cfg_file = argv[i]; + break; + default: + usage(); + } + } + else + { + first_arg = i; + break; + } + } + + exe_full = strdup(argv[0]); + if (exe_full != NULL ) + exe = basename(exe_full); + else + return ret; + + if (strncmp(exe, "io", 3) != 0 || !isatty(fileno(stdin))) + quiet = 1; + + if (!map_str) + { + if (!cfg_file) + map_str = probe_cpu_for_map(); + else + map_str = map_file(cfg_file, &flen, PROT_READ, MAP_PRIVATE); + } + else + { + flen = strlen(map_str); + } + if (load_maps(map_str, flen) < 0) + { + fprintf(stderr, "failed to map regions: check map string or config file\n"); + goto _cleanup; + } + + if (strncmp(exe, "md", 3) == 0) + { + len = 0x40; + addr = strtoul(argv[first_arg], &endptr, 16); + if ((first_arg + 1) < argc) + { + len = strtoul(argv[first_arg + 1], &endptr, 16); + } + ret = md(addr, 0, len); + goto _cleanup; + } + + if (strncmp(exe, "mw", 3) == 0) + { + len = 1; + addr = strtoul(argv[first_arg], &endptr, 16); + if ((first_arg + 1) < argc) + { + val = strtoul(argv[first_arg + 1], &endptr, 16); + } + else + { + usage(); + } + if ((first_arg + 2) < argc) + { + len = strtoul(argv[first_arg + 2], &endptr, 16); + } + ret = mw(addr, val, len); + goto _cleanup; + } + + io(); + +_cleanup: + unmap_all(); + free(exe_full); + return ret; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb new file mode 100644 index 000000000..5ac0f0a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb @@ -0,0 +1,17 @@ +SUMMARY = "IO App" +DESCRIPTION = "IO application for accessing memory-mapped IO regions on the BMC" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM += "\ + file://io-app.c;beginline=2;endline=14;md5=639666a0bf40bb717b46b378297eeceb \ + " + +SRC_URI = "\ + file://CMakeLists.txt \ + file://io-app.c \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt new file mode 100644 index 000000000..1cde22b49 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(lpc-cmds C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +add_executable(lpc_cmds lpc_cmds.c) +install (TARGETS lpc_cmds DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c new file mode 100644 index 000000000..bc215f60b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c @@ -0,0 +1,528 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +*/ + +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include "lpc_drv.h" + +#define SIO_DEVICE_NAME "/dev/lpc-sio" +#define KCS_DEVICE_NAME "/dev/ipmi-kcs" +#define MAILBOX_DEVICE_NAME "/dev/aspeed-mbox" +#define SNOOP_DEVICE_NAME "/dev/aspeed-lpc-snoop" + +#define SNOOP_BUF_SIZE 4096 + +#define SUPPORT_KCS_ADDR_CMD 0 +#define SUPPORT_MAILBOX 1 +#define SUPPORT_SNOOP 1 + +/*********************************************************************************/ +static void ProcessKCSReq(int fd, unsigned char *pReq, int ReqLen, int NoPrint) +{ + int i; + unsigned char SendPkt[16]; + + if (!NoPrint) { + printf("\nKCS Request >>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + for (i = 0; i < ReqLen; i++) + printf("%02X ", pReq[i]); + printf("\n======================================\n"); + } + + SendPkt[0] = pReq[0] | 0x04; + SendPkt[1] = pReq[1]; + SendPkt[2] = 0xC1; /* Always Invalid Command */ + + if (!NoPrint) { + printf("\nKCS Response <<<<<<<<<<<<<<<<<<<<<<<<<\n"); + for (i = 0; i < 3; i++) + printf("%02X ", SendPkt[i]); + printf("\n======================================\n"); + } + + write(fd, SendPkt, 3); +} + +static void KCSIfcTask(int KCSIfcIdx, int NoPrint) +{ + int fd; + int RecvPktLen; + char KCSDev[16]; + struct kcs_ioctl_data IOData; + unsigned char RecvPkt[512]; + + snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx); + fd = open(KCSDev, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open KCS device: %s\n", KCSDev); + exit(1); + } + + IOData.cmd = KCS_FORCE_ABORT; + IOData.data = 0; + ioctl(fd, KCS_IOC_COMMAND, &IOData); + + while (1) { + RecvPktLen = read(fd, RecvPkt, sizeof(RecvPkt)); + if (RecvPktLen < 2) + continue; + + ProcessKCSReq(fd, RecvPkt, RecvPktLen, NoPrint); + } +} + +#if SUPPORT_KCS_ADDR_CMD +static void KCSIfcSetAddr(int KCSIfcIdx, unsigned int addr) +{ + int fd; + struct kcs_ioctl_data kcs_data; + char KCSDev[16]; + + snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx); + fd = open(KCSDev, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open KCS device: %s\n", KCSDev); + exit(1); + } + + kcs_data.cmd = KCS_SET_ADDR; + kcs_data.data = addr; + if (ioctl(fd, KCS_IOC_COMMAND, &kcs_data) == 0) + printf("Set KCS%d addr to 0x%X successfully!\n", KCSIfcIdx + 1, addr); + + close(fd); +} + +static void KCSIfcGetAddr(int KCSIfcIdx) +{ + int fd; + struct kcs_ioctl_data kcs_data; + char KCSDev[16]; + + snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx); + fd = open(KCSDev, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open KCS device: %s\n", KCSDev); + exit(1); + } + + kcs_data.cmd = KCS_GET_ADDR; + if (ioctl(fd, KCS_IOC_COMMAND, &kcs_data) == 0) + printf("KCS%d addr is : 0x%X!\n", KCSIfcIdx + 1, kcs_data.data); + + close(fd); +} +#endif + +/*********************************************************************************/ + +#if SUPPORT_SNOOP +static void ReadBiosPOSTCodes(unsigned int if_idx) +{ + char snoop_dev[32]; + int fd; + int i; + unsigned char buf[SNOOP_BUF_SIZE]; + int len; + + snprintf(snoop_dev, sizeof(snoop_dev), SNOOP_DEVICE_NAME"%d", if_idx); + fd = open(snoop_dev, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s !\n", snoop_dev); + return; + } + + len = read(fd, &buf, sizeof(buf)); + + if (len == 0 || errno == EAGAIN) { + printf("No BIOS POST Codes Found!\n"); + goto out; + } else if (len < 0) { + printf("Failed to read the POST Codes! (%s)\n", + strerror(errno)); + goto out; + } + + printf("BIOS POST Codes in Hex (%d entries):\n", len); + + for (i = 0; i < len; i++) + printf(" %d: %02X\n", i, buf[i]); + + printf("\n"); + +out: + close(fd); +} +#endif + +/*********************************************************************************/ + +static void SIOGetACPIState(unsigned short changed) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_ACPI_STATE; + sio_data.param = changed; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) { + if (changed) + printf("ACPI SLP state is %s!\n", + sio_data.param != 0 ? "Changed" : "Same"); + + if (sio_data.data == ACPI_STATE_S12) + printf("ACPI SLP state --> SLP_12\n"); + else if (sio_data.data == ACPI_STATE_S3I) + printf("ACPI SLP state --> SLP_3I\n"); + else if (sio_data.data == ACPI_STATE_S45) + printf("ACPI SLP state --> SLP_45\n"); + } + + close(fd); +} + +static void SIOGetPWRGDStatus(unsigned short changed) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_PWRGD_STATUS; + sio_data.param = changed; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) { + if (changed) + printf("PWRGD status : %s\n", + sio_data.param != 0 ? "Changed" : "Same"); + + printf("PWRGD status value :%u\n", sio_data.data); + } + + close(fd); +} + +static void SIOGetONCTLStatus(void) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_ONCTL_STATUS; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("ONCTL status value :%u\n", sio_data.data); + + close(fd); +} + +static void SIOSetONCTLGPIO(unsigned short enable, unsigned int value) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_SET_ONCTL_GPIO; + sio_data.param = enable; + sio_data.data = value; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("ONCTL GPIO mode setting is Done!\n"); + + close(fd); +} + +static void SIOGetPWRBTNOverride(unsigned short clear) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_PWRBTN_OVERRIDE; + sio_data.param = clear; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("PWRBTN Override status : %u\n", sio_data.data); + + close(fd); +} + +static void SIOGetPFailStatus() +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_PFAIL_STATUS; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("PFail status : %u\n", sio_data.data); + + close(fd); +} + +static void SIOSetBMCSCIEvent(unsigned short set) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_SET_BMC_SCI_EVENT; + sio_data.param = set; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("BMC SCI event is %s\n", + sio_data.data ? "set" : "cleared"); + + close(fd); +} + +/*********************************************************************************/ + +#if SUPPORT_MAILBOX +static void MailBoxRead(int num) +{ + int fd; + int len; + uint8_t data; + + fd = open(MAILBOX_DEVICE_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + printf("Error open mailbox\n"); + exit(1); + } + + len = pread(fd, &data, 1, num); + if (len == 0 || errno == EAGAIN) { + printf("No mailbox message found!\n"); + goto out; + } else if (len < 0) { + printf("Error reading from mailbox%d! (%s)\n", num, + strerror(errno)); + goto out; + } + + printf("MailBox%d read value : 0x%02X\n", num, data); + +out: + close(fd); +} + +static void MailBoxWrite(int num, uint8_t value) +{ + int fd; + ssize_t rc; + + fd = open(MAILBOX_DEVICE_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + printf("Error open mailbox\n"); + exit(1); + } + + rc = pwrite(fd, &value, 1, num); + + if (rc == 1) + printf("MailBox%d write value : 0x%02X done!\n", num, value); + else + printf("Error writing to mailbox%d, rc: %d\n", num, rc); + + close(fd); +} +#endif + +/*********************************************************************************/ + +static void usage(void) +{ + printf("Usage:\n" + "\tlpc_cmds sio get_acpi_state\n" + "\tlpc_cmds sio get_acpi_changed\n" + "\tlpc_cmds sio get_pwrgd_status\n" + "\tlpc_cmds sio get_pwrgd_changed\n" + "\tlpc_cmds sio get_onctl_status\n" + "\tlpc_cmds sio set_onctl_gpio_disable\n" + "\tlpc_cmds sio set_onctl_gpio_high\n" + "\tlpc_cmds sio set_onctl_gpio_low\n" + "\tlpc_cmds sio get_pwrbtn_override_status\n" + "\tlpc_cmds sio get_pwrbtn_override_status_clear\n" + "\tlpc_cmds sio get_pfail_status\n" + "\tlpc_cmds sio set_bmc_sci_event\n" + "\tlpc_cmds sio clear_bmc_sci_event\n" + "\n" +#if SUPPORT_KCS_ADDR_CMD + "\tlpc_cmds kcs [1 ~ 4] (getaddr / setaddr / quiet)\n" +#else + "\tlpc_cmds kcs [1 ~ 4] (quiet)\n" +#endif +#if SUPPORT_MAILBOX + "\n" + "\tlpc_cmds mailbox read (0 ~ 15)\n" + "\tlpc_cmds mailbox write (0 ~ 15) (0x00 ~ 0xFF)\n" +#endif +#if SUPPORT_SNOOP + "\n" + "\tlpc_cmds snoop [0 ~ 1] read\n" +#endif + ); + + exit(-1); +} + +int main(int argc, char** argv) +{ + char *cmd; + + if (argc < 2) + usage(); + + cmd = argv[1]; + + if (strcmp(cmd, "sio") == 0) { + if (argc < 3) + usage(); + + if (strcmp(argv[2], "get_acpi_state") == 0) + SIOGetACPIState(0); + else if (strcmp(argv[2], "get_acpi_changed") == 0) + SIOGetACPIState(1); + else if (strcmp(argv[2], "get_pwrgd_status") == 0) + SIOGetPWRGDStatus(0); + else if (strcmp(argv[2], "get_pwrgd_changed") == 0) + SIOGetPWRGDStatus(1); + else if (strcmp(argv[2], "get_onctl_status") == 0) + SIOGetONCTLStatus(); + else if (strcmp(argv[2], "set_onctl_gpio_disable") == 0) + SIOSetONCTLGPIO(0, 0); + else if (strcmp(argv[2], "set_onctl_gpio_high") == 0) + SIOSetONCTLGPIO(1, 1); + else if (strcmp(argv[2], "set_onctl_gpio_low") == 0) + SIOSetONCTLGPIO(1, 0); + else if (strcmp(argv[2], "get_pwrbtn_override_status") == 0) + SIOGetPWRBTNOverride(0); + else if (strcmp(argv[2], "get_pwrbtn_override_status_clear") == 0) + SIOGetPWRBTNOverride(1); + else if (strcmp(argv[2], "get_pfail_status") == 0) + SIOGetPFailStatus(); + else if (strcmp(argv[2], "set_bmc_sci_event") == 0) + SIOSetBMCSCIEvent(1); + else if (strcmp(argv[2], "clear_bmc_sci_event") == 0) + SIOSetBMCSCIEvent(0); + } else if (strcmp(cmd, "kcs") == 0) { + int ifc; + + if (argc < 3) + usage(); + + ifc = atoi(argv[2]); + if (ifc < 1 || ifc > 4) /* ipmi-kcs1 ~ ipmi-kcs4 */ + usage(); + + if (argc == 3) + KCSIfcTask(ifc, 0); + else if (argc == 4 && strcmp(argv[3], "quiet") == 0) + KCSIfcTask(ifc, 1); +#if SUPPORT_KCS_ADDR_CMD + else if (argc == 4 && strcmp(argv[3], "getaddr") == 0) + KCSIfcGetAddr(ifc); + else if (argc == 5 && strcmp(argv[3], "setaddr") == 0) + KCSIfcSetAddr(ifc, strtoul(argv[4], NULL, 16)); +#endif +#if SUPPORT_MAILBOX + } else if (strcmp(cmd, "mailbox") == 0) { + if (argc < 4) + usage(); + + if (strcmp(argv[2], "read") == 0) { + MailBoxRead(atoi(argv[3])); + } else { + if (argc < 5) + usage(); + MailBoxWrite(atoi(argv[3]), strtoul(argv[4], NULL, 16)); + } +#endif +#if SUPPORT_SNOOP + } else if (strcmp(cmd, "snoop") == 0) { + int ifc; + + if (argc < 3) + usage(); + + ifc = atoi(argv[2]); + if (ifc < 0 || ifc > 1) /* snoop0 ~ snoop1 */ + usage(); + + if (strcmp(argv[3], "read") == 0) + ReadBiosPOSTCodes(ifc); + else + usage(); +#endif + } + + return 0; +} + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h new file mode 100644 index 000000000..793e8b49c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h @@ -0,0 +1,79 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +*/ + +#ifndef __LPC_DRV_H__ +#define __LPC_DRV_H__ + +#define LPC_DEV_MAJOR 250 +#define LPC_DEV_MINOR 0 + +/***********************************************************************************/ + +enum KCS_CMD { + KCS_SET_ADDR = 0, + KCS_GET_ADDR, + KCS_SMS_ATN, + KCS_FORCE_ABORT, +}; + +struct kcs_ioctl_data { + unsigned int cmd; + unsigned int data; +}; + +#define KCS_IOC_BASE 'K' +#define KCS_IOC_COMMAND _IOWR(KCS_IOC_BASE, 1, struct kcs_ioctl_data) + +/***********************************************************************************/ + +enum ACPI_SLP_STATE { + ACPI_STATE_S12 = 1, + ACPI_STATE_S3I, + ACPI_STATE_S45 +}; + +/* SWC & ACPI for SuperIO IOCTL */ +enum SIO_CMD { + SIO_GET_ACPI_STATE = 0, + SIO_GET_PWRGD_STATUS, + SIO_GET_ONCTL_STATUS, + SIO_SET_ONCTL_GPIO, + SIO_GET_PWRBTN_OVERRIDE, + SIO_GET_PFAIL_STATUS, /* Start from AC Loss */ + SIO_SET_BMC_SCI_EVENT, + + SIO_MAX_CMD +}; + +struct sio_ioctl_data { + unsigned short sio_cmd; + unsigned short param; + unsigned int data; +}; + +#define SIO_IOC_BASE 'P' +#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data) + +/***********************************************************************************/ + +#define MAX_MAILBOX_NUM 16 + +/***********************************************************************************/ + +#endif + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb new file mode 100644 index 000000000..38489263b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb @@ -0,0 +1,16 @@ +SUMMARY = "LPC tools" +DESCRIPTION = "command tool for LPC interface test on the BMC" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://lpc_drv.h \ + file://lpc_cmds.c \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch new file mode 100644 index 000000000..83f015a76 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch @@ -0,0 +1,71 @@ +From ad236d3f04cb2547fea33d72aeeb695ce3035bba Mon Sep 17 00:00:00 2001 +From: Iwona Winiarska <iwona.winiarska@intel.com> +Date: Mon, 9 Dec 2019 01:58:15 +0100 +Subject: [PATCH] Force nbdkit to send PATCH as upload method + +This modifies pwrite to send PATCH rather than default upload method +used by curl. + +FIXME: This patch only works around lack of PATCH method support in curl. +It's just a hack and it should be removed if/when proper PATCH support +is implemented in curl. + +We've added it to nbdkit rather than curl, because currently PATCH +support is unlikely to be accepted in upstream curl and it is easier to +maintain this patch in nbdkit. + +Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com> +--- + plugins/curl/curl.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c +index 0ed3984..804ad78 100644 +--- a/plugins/curl/curl.c ++++ b/plugins/curl/curl.c +@@ -525,6 +525,7 @@ static int + curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset) + { + struct curl_handle *h = handle; ++ struct curl_slist *list = NULL; + CURLcode r; + char range[128]; + +@@ -535,15 +536,21 @@ curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset) + h->read_count = count; + + curl_easy_setopt (h->c, CURLOPT_UPLOAD, 1); ++ curl_easy_setopt (h->c, CURLOPT_CUSTOMREQUEST, "PATCH"); + + /* Make an HTTP range request. */ +- snprintf (range, sizeof range, "%" PRIu64 "-%" PRIu64, ++ snprintf (range, sizeof range, "Range: bytes=%" PRIu64 "-%" PRIu64, + offset, offset + count); +- curl_easy_setopt (h->c, CURLOPT_RANGE, range); ++ list = curl_slist_append(list, range); ++ curl_easy_setopt(h->c, CURLOPT_HTTPHEADER, list); + + /* The assumption here is that curl will look after timeouts. */ + r = curl_easy_perform (h->c); + if (r != CURLE_OK) { ++ curl_easy_setopt (h->c, CURLOPT_RANGE, NULL); ++ curl_easy_setopt(h->c, CURLOPT_HTTPHEADER, NULL); ++ curl_slist_free_all(list); ++ curl_easy_setopt (h->c, CURLOPT_CUSTOMREQUEST, NULL); + display_curl_error (h, r, "pwrite: curl_easy_perform"); + return -1; + } +@@ -554,6 +561,10 @@ curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset) + + /* As far as I understand the cURL API, this should never happen. */ + assert (h->read_count == 0); ++ curl_easy_setopt (h->c, CURLOPT_RANGE, NULL); ++ curl_easy_setopt(h->c, CURLOPT_HTTPHEADER, NULL); ++ curl_slist_free_all(list); ++ curl_easy_setopt (h->c, CURLOPT_CUSTOMREQUEST, NULL); + + return 0; + } +-- +2.21.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0002-Add-support-for-ssl-config.patch b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0002-Add-support-for-ssl-config.patch new file mode 100644 index 000000000..c597cb3a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0002-Add-support-for-ssl-config.patch @@ -0,0 +1,66 @@ +diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c +index 610511f7..92be4656 100644 +--- a/plugins/curl/curl.c ++++ b/plugins/curl/curl.c +@@ -69,6 +69,8 @@ static const char *proxy = NULL; + static char *proxy_password = NULL; + static const char *proxy_user = NULL; + static bool sslverify = true; ++static const char *ssl_version = NULL; ++static const char *ssl_cipher_list = NULL; + static bool tcp_keepalive = false; + static bool tcp_nodelay = true; + static uint32_t timeout = 0; +@@ -232,6 +234,12 @@ curl_config (const char *key, const char *value) + sslverify = r; + } + ++ else if (strcmp (key, "ssl-version") == 0) ++ ssl_version = value; ++ ++ else if (strcmp (key, "ssl-cipher-list") == 0) ++ ssl_cipher_list = value; ++ + else if (strcmp (key, "tcp-keepalive") == 0) { + r = nbdkit_parse_bool (value); + if (r == -1) +@@ -302,6 +310,8 @@ curl_config_complete (void) + "proxy-user=<USER> The proxy user.\n" \ + "timeout=<TIMEOUT> Set the timeout for requests (seconds).\n" \ + "sslverify=false Do not verify SSL certificate of remote host.\n" \ ++ "ssl-version=<VERSION> Specify preferred TLS/SSL version.\n " \ ++ "ssl-cipher-list=C1:C2:.. Specify TLS/SSL cipher suites to be used.\n" \ + "tcp-keepalive=true Enable TCP keepalives.\n" \ + "tcp-nodelay=false Disable Nagle’s algorithm.\n" \ + "unix-socket-path=<PATH> Open Unix domain socket instead of TCP/IP.\n" \ +@@ -418,6 +428,30 @@ curl_open (int readonly) + curl_easy_setopt (h->c, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt (h->c, CURLOPT_SSL_VERIFYHOST, 0L); + } ++ if (ssl_version) { ++ if (strcmp (ssl_version, "tlsv1") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); ++ else if (strcmp (ssl_version, "sslv2") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv2); ++ else if (strcmp (ssl_version, "sslv3") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); ++ else if (strcmp (ssl_version, "tlsv1.0") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); ++ else if (strcmp (ssl_version, "tlsv1.1") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); ++ else if (strcmp (ssl_version, "tlsv1.2") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); ++ else if (strcmp (ssl_version, "tlsv1.3") == 0) ++ curl_easy_setopt (h->c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_3); ++ else { ++ display_curl_error (h, r, "curl_easy_setopt: CURLOPT_SSLVERSION [%s]", ++ ssl_version); ++ goto err; ++ } ++ ++ } ++ if (ssl_cipher_list) ++ curl_easy_setopt (h->c, CURLOPT_SSL_CIPHER_LIST, ssl_cipher_list); + if (tcp_keepalive) + curl_easy_setopt (h->c, CURLOPT_TCP_KEEPALIVE, 1L); + if (!tcp_nodelay) diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb new file mode 100644 index 000000000..01b3fc27e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb @@ -0,0 +1,36 @@ +SUMMARY = "nbdkit is a toolkit for creating NBD servers." +DESCRIPTION = "NBD — Network Block Device — is a protocol \ +for accessing Block Devices (hard disks and disk-like things) \ +over a Network. \ +\ +nbdkit is a toolkit for creating NBD servers." + +HOMEPAGE = "https://github.com/libguestfs/nbdkit" +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://LICENSE;md5=4332a97808994cf2133a65b6c6f33eaf" + +SRC_URI = "git://github.com/libguestfs/nbdkit.git;protocol=https" +SRC_URI += "file://0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch" +SRC_URI += "file://0002-Add-support-for-ssl-config.patch" + +PV = "1.17.5+git${SRCPV}" +SRCREV = "c8406880c6603bb617dae131dd0a8826c05869ca" + +S = "${WORKDIR}/git" + +DEPENDS = "curl xz e2fsprogs zlib" + +inherit pkgconfig python3native perlnative autotools +inherit autotools-brokensep + +# Specify any options you want to pass to the configure script using EXTRA_OECONF: +EXTRA_OECONF = "--disable-python --disable-perl --disable-ocaml \ + --disable-rust --disable-ruby --disable-tcl \ + --disable-lua --disable-vddk --without-libvirt \ + --without-libguestfs" + +do_install_append() { + rm -f ${D}/usr/share/bash-completion/completions/nbdkit + rmdir ${D}/usr/share/bash-completion/completions + rmdir ${D}/usr/share/bash-completion +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py new file mode 100755 index 000000000..977fcd3a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py @@ -0,0 +1,144 @@ +#!/usr/bin/python + +import glob +import os +import sys +import time + +if len(sys.argv) == 1: + cpuno = 0 +else: + cpuno = int(sys.argv[1]) + +hwmon_path = '/sys/class/hwmon' +cputemp_name_match = '{}{}'.format('peci_cputemp.cpu', cpuno) +dimmtemp_name_match = '{}{}'.format('peci_dimmtemp.cpu', cpuno) + +dimmtemp_path = '' + +os.chdir(hwmon_path) + +for dirpath, dirnames, files in os.walk(hwmon_path): + for d in dirnames: + try: + with open('{}/{}'.format(d, 'name')) as f: + hwmon_name = f.read().strip() + if hwmon_name == cputemp_name_match: + cputemp_path = os.path.abspath(d) + cputemp_name = hwmon_name + elif hwmon_name == dimmtemp_name_match: + dimmtemp_path = os.path.abspath(d) + dimmtemp_name = hwmon_name + except: + continue + +if not cputemp_path: + print "Can't find the " + cputemp_name_match + quit() + +try: + while True: + os.system('clear') + os.chdir(cputemp_path) + + print '{}/{}: {}'.format(hwmon_path, cputemp_path, cputemp_name) + if dimmtemp_path: + print '{}/{}: {}'.format(hwmon_path, dimmtemp_path, dimmtemp_name) + + print + print 'Package temperature' + for input in glob.glob('temp[1-5]_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print '{:11s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000)) + + print + print 'Core temperature' + count = 0 + for input in glob.glob('temp[!1-5]_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + for input in glob.glob('temp??_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + print + + if dimmtemp_path: + os.chdir(dimmtemp_path) + print + print 'DIMM temperature' + count = 0 + for input in glob.glob('temp*_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + print + else: + os.chdir(hwmon_path) + for dirpath, dirnames, files in os.walk(hwmon_path): + for d in dirnames: + try: + with open('{}/{}'.format(d, 'name')) as f: + hwmon_name = f.read().strip() + if hwmon_name == dimmtemp_name_match: + dimmtemp_path = os.path.abspath(d) + dimmtemp_name = hwmon_name + except: + continue + + time.sleep(1) +except KeyboardInterrupt: + print " exiting..." diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb new file mode 100644 index 000000000..b3b4096a6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb @@ -0,0 +1,20 @@ +SUMMARY = "PECI hwmon test tool" +DESCRIPTION = "command line python tool for testing PECI hwmon" + +SRC_URI = "\ + file://peci-hwmon-test.py \ + " +LICENSE = "CLOSED" + +RDEPENDS_${PN} += "python" + +S = "${WORKDIR}" + +do_compile () { +} + +do_install () { + install -d ${D}/${bindir} + install -m 0755 ${WORKDIR}/peci-hwmon-test.py ${D}/${bindir} +} + diff --git a/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control/0001-Extend-VR-Watchdog-timeout.patch b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control/0001-Extend-VR-Watchdog-timeout.patch new file mode 100644 index 000000000..15de955c0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control/0001-Extend-VR-Watchdog-timeout.patch @@ -0,0 +1,32 @@ +From 540836801f4ab5e8be9703d2c1350e988b2ccc1f Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Thu, 11 Jun 2020 13:00:15 -0700 +Subject: [PATCH] Extend VR Watchdog timeout + +The VR watchdog reset is causing issues on platforms such as +Cooper City that take longer to assert CPU Power Good. This +extends the timeout to 12s to hold off the reset for Cooper +City. + +Change-Id: I9658b4ead6d9bf8eaa30e4aeb9f1d56c2f2187d3 +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + power-control-x86/config/power-config-host0.json | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/power-control-x86/config/power-config-host0.json b/power-control-x86/config/power-config-host0.json +index ca9a86a..f579c2b 100644 +--- a/power-control-x86/config/power-config-host0.json ++++ b/power-control-x86/config/power-config-host0.json +@@ -18,7 +18,7 @@ + "ForceOffPulseMs": 15000, + "ResetPulseMs": 500, + "PowerCycleMs": 5000, +- "SioPowerGoodWatchdogMs": 1000, ++ "SioPowerGoodWatchdogMs": 12000, + "PsPowerOKWatchdogMs": 8000, + "GracefulPowerOffS": 300, + "WarmResetCheckMs": 500, +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend new file mode 100755 index 000000000..93a32164d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend @@ -0,0 +1,9 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/x86-power-control.git;protocol=ssh" +SRCREV = "afd04f0283bfc4854c0100c56ccf8bc1c10c799a" + +FILESEXTRAPATHS_append := "${THISDIR}/${PN}:" + +SRC_URI += " \ + file://0001-Extend-VR-Watchdog-timeout.patch \ + " |