diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor')
111 files changed, 9814 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service new file mode 100644 index 000000000..bc05fa1a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service @@ -0,0 +1,10 @@ +[Unit] +Description=Close Muxes +ConditionFileNotEmpty=/usr/bin/CloseMuxes.py + +[Service] +ExecStart=/usr/bin/env CloseMuxes.py +Type=oneshot + +[Install] +WantedBy=basic.target 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..b059a35d7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend @@ -0,0 +1,18 @@ +# this is here just to bump faster than upstream +SRC_URI = "git://github.com/openbmc/entity-manager.git" +SRCREV = "4133426a04bf46e275416362205bc29c1b3c0935" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +RDEPENDS_${PN} += "python" +SRC_URI += " file://xyz.openbmc_project.CloseMuxes.service" +SYSTEMD_SERVICE_${PN} += " xyz.openbmc_project.CloseMuxes.service" + +EXTRA_OECMAKE = "-DYOCTO=1 -DUSE_OVERLAYS=0" + +do_install_prepend() { + install -d ${D}${bindir} + install -m 0755 ${S}/scripts/CloseMuxes.py ${D}${bindir} + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${WORKDIR}/xyz.openbmc_project.CloseMuxes.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch new file mode 100644 index 000000000..5b86d3154 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch @@ -0,0 +1,55 @@ +From 066ecddebc29a87b05f8c66491eec19bb27d1d33 Mon Sep 17 00:00:00 2001 +From: David Cobbley <david.j.cobbley@linux.intel.com> +Date: Wed, 6 Jun 2018 10:11:58 -0700 +Subject: [PATCH 3/3] Modify Dbus for IPv6. + +Add additional interfaces for IPv6 use. +--- + .../Network/EthernetInterface.interface.yaml | 18 ++++++++++++++++++ + xyz/openbmc_project/Network/IP.interface.yaml | 4 ++++ + 2 files changed, 22 insertions(+) + +diff --git a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml +index fc744fc..fd19e27 100644 +--- a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml ++++ b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml +@@ -37,3 +37,21 @@ properties: + Implementation of this Dbus-interface is required to implement this property. + This property supports read/write operation. + Configure the NTP servers on the system during write operation. ++ - name: IPv6AcceptRA ++ type: boolean ++ description: > ++ Boolean for accepting router advertisements in IPv6 ++ - name: IPAddressEnables ++ type: enum[self.IPAllowed] ++ description: > ++ The type of IP connection is allowed on this channel ++ ++enumerations: ++ - name: IPAllowed ++ description: > ++ Determines whether the system allows both IPv6 & IPv4, or disables on ++ or the other ++ values: ++ - name: IPv4AndIPv6 ++ - name: IPv4Only ++ - name: IPv6Only +diff --git a/xyz/openbmc_project/Network/IP.interface.yaml b/xyz/openbmc_project/Network/IP.interface.yaml +index 565dcd6..2ffb016 100644 +--- a/xyz/openbmc_project/Network/IP.interface.yaml ++++ b/xyz/openbmc_project/Network/IP.interface.yaml +@@ -22,6 +22,10 @@ properties: + type: string + description: > + This is the IP gateway for this address. ++ - name: BackupGateway ++ type: string ++ description: > ++ This is the IP address of the backup gateway. + - name: Type + type: enum[self.Protocol] + description: > +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch new file mode 100644 index 000000000..79d02ca9b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch @@ -0,0 +1,257 @@ +From 35271230690c5d85dc7a6502031b38d93ddd683f Mon Sep 17 00:00:00 2001 +From: Ed Tanous <ed.tanous@intel.com> +Date: Thu, 24 Jan 2019 09:29:01 -0800 +Subject: [PATCH] Chassis Power Control are implemented. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Feature level: +Power on server is ready +Power off server is ready +Power cycle server is ready +Power reset server is ready + +Framework level: +WebUI is enabled. +IPMI Commands is enabled. +Restful API is enabled. +Physical buttons (Power/Reset/ID) are enabled. +Chassis state manager is enabled. +Host state manager is enabled. + +Enabled IPMI commands: +ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis status +ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis power status +ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis power on +ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis power off +ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis power cycle +ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis power reset + +Enabled Restful APIs: +Login: curl --noproxy <ip_addr> -c cjar -b cjar -k -H "Content-Type: application/json" -X POST https://<ip_addr>/login -d "{\"data\": [ \"root\", \"0penBmc\" ] }“ +Host State: curl --noproxy <ip_addr> -b cjar -k https://<ip_addr>/xyz/openbmc_project/state/host0 +Chassis State: curl --noproxy <ip_addr> -b cjar -k https://<ip_addr>/xyz/openbmc_project/state/chassis0 +Power state: curl --noproxy <ip_addr> -b cjar -k https://<ip_addr>/xyz/openbmc_project/Chassis/Control/Power0 +Power on/off: curl --noproxy <ip_addr> -q1c cjar -b cjar -k -H "Content-Type: application/json" -d '{"data": "xyz.openbmc_project.State.Host.Transition.Off"}' -X PUT https://<ip_addr>/xyz/openbmc_project/state/host0/attr/RequestedHostTransition + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + .../Chassis/Control/Chassis.interface.yaml | 94 +++++++++++++++++++ + .../Chassis/Control/Power.interface.yaml | 85 ++++++++++++++--- + 2 files changed, 166 insertions(+), 13 deletions(-) + create mode 100644 xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml + +diff --git a/xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml b/xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml +new file mode 100644 +index 0000000..c28492a +--- /dev/null ++++ b/xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml +@@ -0,0 +1,94 @@ ++description: > ++ chassis control service ++methods: ++ - name: powerOn ++ description: > ++ Power on system. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: powerOff ++ description: > ++ Power Off system. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: softPowerOff ++ description: > ++ Soft Power off system. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: reboot ++ description: > ++ reboot system. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: softReboot ++ description: > ++ Soft Reboot system. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: quiesce ++ description: > ++ Quiesce system. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: getPowerState ++ description: > ++ Get system power state. ++ returns: ++ - name: state ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ +diff --git a/xyz/openbmc_project/Chassis/Control/Power.interface.yaml b/xyz/openbmc_project/Chassis/Control/Power.interface.yaml +index 082586f..e77598b 100644 +--- a/xyz/openbmc_project/Chassis/Control/Power.interface.yaml ++++ b/xyz/openbmc_project/Chassis/Control/Power.interface.yaml +@@ -1,31 +1,90 @@ + description: > +- Power control service ++ Chassis control service + methods: ++ - name: setPowerState ++ description: > ++ set host power state. ++ parameters: ++ - name: state ++ type: int32 ++ description: > ++ 0 for force power off host ++ 1 for power on host ++ returns: ++ - name: status ++ type: int32 ++ description: > ++ The result of command. ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ ++ - name: getPowerState ++ description: > ++ Get current host power status. ++ returns: ++ - name: status ++ type: int32 ++ description: > ++ Current host status, ++ 0 for host power off ++ 1 for host power on ++ errors: ++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ ++ - xyz.openbmc_project.Chassis.Common.Error.IOError ++ + - name: forcePowerOff + description: > + Force power off the host. + returns: + - name: status +- type: boolean ++ type: int32 + description: > + The result of power off command. + errors: + - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand ++ + - xyz.openbmc_project.Chassis.Common.Error.IOError + + properties: +- - name: PGood +- type: boolean +- default: false ++ - name: vrd_good ++ type: int32 ++ default: 0 + description: > +- PSU Power good property +- It is a read-only property. +- - name: State ++ ACPI status ++ - name: s4s5_state + type: int32 + default: 0 + description: > +- System power status +- 0: power is off +- 1: power is on +- Setting its value to change the system state +- Read its value to get the system state. +\ No newline at end of file ++ ACPI status ++ - name: pgood ++ type: int32 ++ default: 0 ++ description: > ++ pgood property ++ - name: state ++ type: int32 ++ default: 0 ++ description: > ++ state property ++ - name: pgood_timeout ++ type: int32 ++ default: 0 ++ description: > ++ pgoodtimeout property ++ - name: post_complete ++ type: boolean ++ default: false ++ description: > ++ The current BIOS POST state, ++ false means not completed or system reset, ++ true means BIOS POST completed. ++signals: ++ - name: PowerGood ++ description: > ++ Signal for powergood ++ - name: PowerLost ++ description: > ++ Signal for powerlost +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch new file mode 100644 index 000000000..7568f8ce9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch @@ -0,0 +1,120 @@ +From a30a09f58b9ebfb267c0b9cce9ae25994ea025ca Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Tue, 17 Jul 2018 16:04:58 +0800 +Subject: [PATCH] Add DBUS interface of CPU and Memory's properties Feature + Support: SMBIOS service interface. CPU DIMM information redfish + interface. Base on smbios spec DSP0134_3.0.0 + +Signed-off-by: cyang29 <cheng.c.yang@intel.com> +--- + .../Inventory/Item/Cpu.interface.yaml | 41 +++++++++++++++++++ + .../Inventory/Item/Dimm.interface.yaml | 46 +++++++++++++++++++++- + 2 files changed, 86 insertions(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +index ab29cf3..313eada 100644 +--- a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +@@ -1,4 +1,45 @@ + description: > + Implement to provide CPU attributes. ++properties: ++ - name: ProcessorSocket ++ type: string ++ description: > ++ Processor Socket on MotherBoard ++ - name: ProcessorType ++ type: string ++ description: > ++ Processor Type of CPU ++ - name: ProcessorFamily ++ type: string ++ description: > ++ Processor Family of CPU ++ - name: ProcessorManufacturer ++ type: string ++ description: > ++ Processor Manufacturer of CPU ++ - name: ProcessorId ++ type: uint32 ++ description: > ++ Processor ID of CPU ++ - name: ProcessorVersion ++ type: string ++ description: > ++ Processor Version of CPU ++ - name: ProcessorMaxSpeed ++ type: uint16 ++ description: > ++ Max Speed CPU Can Support ++ - name: ProcessorCharacteristics ++ type: string ++ description: > ++ The Characteristics CPU Has ++ - name: ProcessorCoreCount ++ type: uint16 ++ description: > ++ The Count of Core in CPU ++ - name: ProcessorThreadCount ++ type: uint16 ++ description: > ++ The Count of Thread CPU Can Support + + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +diff --git a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml +index d85326d..b750320 100644 +--- a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml +@@ -1,4 +1,48 @@ + description: > + Implement to provide DIMM attributes. +- ++properties: ++ - name: MemoryDataWidth ++ type: uint16 ++ description: > ++ Data width of Memory. ++ - name: MemorySizeInKB ++ type: uint32 ++ description: > ++ Memory size of DIMM in Kilobyte. ++ - name: MemoryDeviceLocator ++ type: string ++ description: > ++ Socket on base board where Memory located. ++ - name: MemoryType ++ type: string ++ description: > ++ Type of memory. ++ - name: MemoryTypeDetail ++ type: string ++ description: > ++ Additional detail on Memory. ++ - name: MemorySpeed ++ type: uint16 ++ description: > ++ The maximun capable speed of Memory. ++ - name: MemoryManufacturer ++ type: string ++ description: > ++ Manufacturer of memory. ++ - name: MemorySerialNum ++ type: string ++ description: > ++ Memory Serial Number. ++ - name: MemoryPartNum ++ type: string ++ description: > ++ Memory Part Number. ++ - name: MemoryAttributes ++ type: byte ++ description: > ++ Rank attributes of Memory. ++ - name: MemoryConfClockSpeed ++ type: uint16 ++ description: > ++ Configured clock speed to Memory. + # 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/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch new file mode 100644 index 000000000..f0d7b03f8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch @@ -0,0 +1,77 @@ +From 643772fc7f6021fbfba3b14de0c86501ae3e7f3a Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Fri, 13 Jul 2018 15:22:05 +0800 +Subject: [PATCH] [dbus interface]add boot option support for floppy and USB + +Current implementations use ExternalMedia type to specify both CD/DVD/USB +/Floppy. But in IPMI spec, they are different. CD/DVD type is 0x5 and +USB/Floppy type is 0xF. + +This causes a bug that we can not force BIOS boots into USB/Floppy. + +Test: +$ ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus raw + 0x0 0x8 0x5 0x80 0x14 0x00 0x00 0x00 +$ ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus chassis bootparam get 5 +Boot parameter version: 1 +Boot parameter 5 is valid/unlocked +Boot parameter data: 8014000000 + Boot Flags : + - Boot Flag Valid + - Options apply to only next boot + - BIOS PC Compatible (legacy) boot + - Boot Device Selector : Force Boot from CD/DVD + - Console Redirection control : System Default + - BIOS verbosity : Console redirection occurs per BIOS + configuration setting (default) + - BIOS Mux Control Override : + BIOS uses recommended setting of the mux at the end of POST + +$ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus raw + 0x0 0x8 0x5 0x80 0x3c 0x00 0x00 0x00 +$ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus chassis bootparam get 5 +Boot parameter version: 1 +Boot parameter 5 is valid/unlocked +Boot parameter data: 803c000000 + Boot Flags : + - Boot Flag Valid + - Options apply to only next boot + - BIOS PC Compatible (legacy) boot + - Boot Device Selector : Force Boot from Floppy/primary removable media + - Console Redirection control : System Default + - BIOS verbosity : + Console redirection occurs per BIOS configuration setting (default) + + - BIOS Mux Control Override : + BIOS uses recommended setting of the mux at the end of POST + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + xyz/openbmc_project/Control/Boot/Source.interface.yaml | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/xyz/openbmc_project/Control/Boot/Source.interface.yaml b/xyz/openbmc_project/Control/Boot/Source.interface.yaml +index ea811bd..8e5916f 100644 +--- a/xyz/openbmc_project/Control/Boot/Source.interface.yaml ++++ b/xyz/openbmc_project/Control/Boot/Source.interface.yaml +@@ -15,12 +15,15 @@ enumerations: + - name: Disk + description: > + Boot from the local hard disk. +- - name: ExternalMedia ++ - name: DVD + description: > +- Boot from CD/DVD/USB, etc. ++ Boot from CD/DVD. + - name: Network + description: > + Boot from a remote source over a network. + - name: Default + description: > + Boot from an implementation defined source. ++ - name: Removable ++ description: > ++ Boot from floppy/primary removable media(USB). +-- +2.16.2 + 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/0009-Add-host-restart-cause-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0009-Add-host-restart-cause-property.patch new file mode 100644 index 000000000..1221a0ab4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0009-Add-host-restart-cause-property.patch @@ -0,0 +1,98 @@ +From 72b7b30a5dda56c170ee2ce82c1082c26f4663e3 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 31 Jul 2018 16:55:21 +0800 +Subject: [PATCH] Add host restart cause property. + +Add host restart cause property to track the information about what +action last caused the system to restart. +According to IPMI Spec, it includes 12 types as following: +1. Unknown 0x0 +2. IpmiCommand 0x1 +3. ResetButton 0x2 +4. PowerButton 0x3 +5. WatchdogTimer 0x4 +6. OEM 0x5 +7. PowerPolicyAlwaysOn 0x6 +8. PowerPolicyPreviousState 0x7 +9. PEF-Reset 0x8 +10. PEF-PowerCycle 0x9 +11. SoftReset 0xA +12. RTC-Wakeup 0xB + +Change-Id: Id2cc6a18b98e485a978940e5ffc085bf5c4fbed8 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + xyz/openbmc_project/State/Host.interface.yaml | 52 +++++++++++++++++++ + 1 file changed, 52 insertions(+) + +diff --git a/xyz/openbmc_project/State/Host.interface.yaml b/xyz/openbmc_project/State/Host.interface.yaml +index 8f481b8..a4d88d0 100644 +--- a/xyz/openbmc_project/State/Host.interface.yaml ++++ b/xyz/openbmc_project/State/Host.interface.yaml +@@ -17,6 +17,12 @@ properties: + comparing the CurrentHostState and the RequestedHostTransition + properties. + ++ - name: HostRestartCause ++ type: enum[self.RestartCause] ++ default: Unknown ++ description: > ++ The information about what action last caused the system to restart. ++ + enumerations: + - name: Transition + description: > +@@ -45,3 +51,49 @@ enumerations: + - name: 'Quiesced' + description: > + Host firmware is quiesced ++ ++ - name: RestartCause ++ description: > ++ The information about what action last caused the system to restart. ++ values: ++ - name: Unknown ++ description: > ++ System start/restart detected but the reason is unknown. ++ - name: IpmiCommand ++ description: > ++ System start/restart detected and caused by ipmi command. ++ - name: ResetButton ++ description: > ++ System start/restart detected and caused by reset button. ++ - name: PowerButton ++ description: > ++ System start/restart detected and caused by power button. ++ - name: WatchdogTimer ++ description: > ++ System start/restart detected and casued by watchdog expiration. ++ - name: OEM ++ description: > ++ System start/restart detected and caused by OEM command. ++ - name: PowerPolicyAlwaysOn ++ description: > ++ System start/restart detected and caused by power restore policy ++ "chassis always powers up after AC/mains is applied or returns". ++ - name: PowerPolicyPreviousState ++ description: > ++ System start/restart detected and caused by power restore policy ++ "after AC/mains is applied or returns, power is restored to the ++ state was in effect when AC/mains removed or lost". ++ - name: PEFReset ++ description: > ++ System start/restart detected and caused by PEF(reset). ++ - name: PEFPowerCycle ++ description: > ++ System start/restart detected and caused by PEF(power-cycle). ++ - name: SoftReset ++ description: > ++ System start/restart detected and caused by soft reset like ++ "CTRL-ALT-DEL". ++ - name: RTCWakeup ++ description: > ++ System start/restart detected and caused by system real time ++ clock(RTC) wakeup. +\ No newline at end of file +-- +2.17.0 + 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/0014-Add-multiple-state-signal-for-host-start-and-stop.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0014-Add-multiple-state-signal-for-host-start-and-stop.patch new file mode 100644 index 000000000..a8d732dab --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0014-Add-multiple-state-signal-for-host-start-and-stop.patch @@ -0,0 +1,63 @@ +From 6d0069f4a2b4637c58fd321c9db3034ac9dd17c7 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Wed, 12 Sep 2018 15:03:26 +0800 +Subject: [PATCH] Add multiple state signal for host start and stop + +Add six host state signals like following: + - name: PreHostStart + description: > + This is the signal to indicate host is at pre start stage. + - name: PostHostStart + description: > + This is the signal to indicate host is at start complete stage. + - name: HostStarting + description: > + This is the signal to indicate host is at starting stage. + - name: HostStoping + description: > + This is the signal to indicate host is at stoping stage. + - name: PreHostStop + description: > + This is the signal to indicate host is at pre stop stage. + - name: PostHostStop + description: > + This is the signal to indicate host is at stop complete stage. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + xyz/openbmc_project/State/Host.interface.yaml | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/State/Host.interface.yaml b/xyz/openbmc_project/State/Host.interface.yaml +index 8531a27..1ceba13 100644 +--- a/xyz/openbmc_project/State/Host.interface.yaml ++++ b/xyz/openbmc_project/State/Host.interface.yaml +@@ -96,4 +96,23 @@ enumerations: + - name: RTCWakeup + description: > + System start/restart detected and caused by system real time +- clock(RTC) wakeup. +\ No newline at end of file ++ clock(RTC) wakeup. ++signals: ++ - name: PreHostStart ++ description: > ++ This is the signal to indicate host is at pre start stage. ++ - name: PostHostStart ++ description: > ++ This is the signal to indicate host is at start complete stage. ++ - name: HostStarting ++ description: > ++ This is the signal to indicate host is at starting stage. ++ - name: HostStoping ++ description: > ++ This is the signal to indicate host is at stoping stage. ++ - name: PreHostStop ++ description: > ++ This is the signal to indicate host is at pre stop stage. ++ - name: PostHostStop ++ description: > ++ This is the signal to indicate host is at stop complete stage. +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch new file mode 100644 index 000000000..576bae81a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch @@ -0,0 +1,227 @@ +From 9490574667485cd407193ff9f0d6a96f8c2c87d3 Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Wed, 12 Sep 2018 00:27:23 +0800 +Subject: [PATCH] Add DBUS interface of SMBIOS MDR V2 + +Support: + SMBIOS MDR V2 service interface. + SMBIOS MDR V2 IPMI Command + SMBIOS MDR V2 Redfish interface. +Base on SMBIOS spec DSP0134_3.0.0 and Managed Data Region +Specification Revision 4 +--- + xyz/openbmc_project/Smbios/MDR_V2.errors.yaml | 9 + + xyz/openbmc_project/Smbios/MDR_V2.interface.yaml | 158 +++++++++++++++++++++++ + xyz/openbmc_project/Smbios/README.md | 21 +++ + 3 files changed, 188 insertions(+) + create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.errors.yaml + create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.interface.yaml + create mode 100644 xyz/openbmc_project/Smbios/README.md + +diff --git a/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml +new file mode 100644 +index 0000000..88bd6db +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml +@@ -0,0 +1,9 @@ ++- name: InvalidParameter ++ description: > ++ An invalid parameter is attempted. ++- name: UpdateInProgress ++ description: > ++ Update is in progress. ++- name: InvalidId ++ description: > ++ An invalid Id is attempted. +diff --git a/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml +new file mode 100644 +index 0000000..f97700a +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml +@@ -0,0 +1,158 @@ ++description: > ++ SMBIOS MDR V2 service ++methods: ++ - name: GetDirectoryInformation ++ description: > ++ Get the directory with directory index. ++ parameters: ++ - name: dirIndex ++ type: byte ++ description: > ++ Directory index of SMBIOS. ++ returns: ++ - name: dir ++ type: array[byte] ++ description: > ++ Directory of agent. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: GetDataInformation ++ description: > ++ Get the data info with id index and data set ID. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ returns: ++ - name: dataInfo ++ type: array[byte] ++ description: > ++ Data information of SMBIOS. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: SendDirectoryInformation ++ description: > ++ Send directory information to SMBIOS directory. ++ parameters: ++ - name: dirVersion ++ type: byte ++ description: > ++ A counter which increments each time directory updated. ++ - name: dirIndex ++ type: byte ++ description: > ++ Directory index of SMBIOS. ++ - name: returnedEntries ++ type: byte ++ description: > ++ Indicates number of directory entries. ++ - name: remainingEntries ++ type: byte ++ description: > ++ Remaining entries which are higher than index in this transfer. ++ - name: dirEntry ++ type: array[byte] ++ description: > ++ Data set ID of SMBIOS table. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Need to continue directory transmisson or not. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: GetDataOffer ++ description: > ++ Get data set ID. ++ returns: ++ - name: offer ++ type: array[byte] ++ description: > ++ Data set ID. ++ errors: ++ - self.Error.UpdateInProgress ++ ++ - name: SendDataInformation ++ description: > ++ Send data information with directory index. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ - name: flag ++ type: byte ++ description: > ++ Valid flag to set dir entry status. ++ - name: dataLen ++ type: uint32 ++ description: > ++ The length of the data in bytes. ++ - name: dataVer ++ type: uint32 ++ description: > ++ The version number of this data. ++ - name: timeStamp ++ type: uint32 ++ description: > ++ Timestamp determinded by the agent. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Whether data changes. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: FindIdIndex ++ description: > ++ Find id index by data info. ++ parameters: ++ - name: dataInfo ++ type: array[byte] ++ description: > ++ Data info of data entry. ++ returns: ++ - name: idIndex ++ type: int32 ++ description: > ++ Id index of data entry. ++ errors: ++ - self.Error.InvalidId ++ ++ - name: AgentSynchronizeData ++ description: > ++ Synchronize SMBIOS data from file. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Whether synchronization succeed or not. ++ ++ - name: SynchronizeDirectoryCommonData ++ description: > ++ Synchronize directory common data. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ - name: size ++ type: uint32 ++ description: > ++ Size of data that BIOS prepare to transfer. ++ returns: ++ - name: commonData ++ type: array[uint32] ++ description: > ++ Directory common data includes data size, version and timestamp. ++ ++properties: ++ - name: DirectoryEntries ++ type: byte ++ description: > ++ Numbers of directory entries. +diff --git a/xyz/openbmc_project/Smbios/README.md b/xyz/openbmc_project/Smbios/README.md +new file mode 100644 +index 0000000..415ac52 +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/README.md +@@ -0,0 +1,22 @@ ++# SMBIOS MDR V2 ++ ++## Overview ++SMBIOS MDR V2 service exposes D-Bus methods for SMBIOS Version 2 operations. ++ ++### SMBIOS MDR V2 Interface ++SMBIOS MDR V2 interface `xyz.openbmc_project.Smbios.MDR_V2` provides following ++methods. ++#### methods ++* GetDirectoryInformation - Get the directory with directory index. ++* GetDataInformation - Get the data information with id index and data set ID. ++* SendDirectoryInformation - Send directory information to SMBIOS directory. ++* GetDataOffer - Get data set ID. ++* SendDataInformation - Send data information with directory index. ++* FindIdIndex - Find id index by data info. ++* SynchronizeDirectoryCommonData - Synchronize directory common data before ++SMBIOS data start to transfer. ++* AgentSynchronizeData - Synchronize SMBIOS data from file after data transfer ++complete. ++ ++#### properties ++* DirEntries - Numbers of directory entries. Default: 0 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch new file mode 100644 index 000000000..587bcebf1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch @@ -0,0 +1,42 @@ +From 7ebb72a93922a0163a5b35c277f3bbd241bdf78c Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 22 Oct 2018 16:20:36 +0800 +Subject: [PATCH] Add shutdown policy interface for get/set shutdown policy OEM + IPMI commands + +The policy property is used to store the shutdown policy. + +Tested by: +busctl get-property "xyz.openbmc_project.Settings" \ +"/xyz/openbmc_project/control/shutdown_policy_config" \ +"xyz.openbmc_project.Control.ShutdownPolicy" "Policy" + +busctl set-property "xyz.openbmc_project.Settings" \ +"/xyz/openbmc_project/control/shutdown_policy_config" \ +"xyz.openbmc_project.Control.ShutdownPolicy" "Policy" y 1 + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml | 10 ++++++++++ + 1 file changed, 10 insertions(+) + create mode 100644 xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml + +diff --git a/xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml b/xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml +new file mode 100644 +index 0000000..e562ea8 +--- /dev/null ++++ b/xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml +@@ -0,0 +1,10 @@ ++description: > ++ An interface for node shutdown policy on multi-node products. ++properties: ++ - name: Policy ++ type: byte ++ description: > ++ 0: Do not shutdown node on a power supply over current(OC) ++ or a power supply over temperature(OT) event. ++ 1: Shutdown node on an OC/OT event. ++ Only available on multi-node products. +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch new file mode 100644 index 000000000..ce23c222b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch @@ -0,0 +1,64 @@ +From f88cac8364d5312e29208018909827d2da4a0f87 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 19 Feb 2019 16:52:51 +0800 +Subject: [PATCH] Define post code interfaces for post code manager + +It includes one method and 2 properties. +properties: + - name: CurrentBootCycleIndex + description: > + It is used to indicate current boot cycle index. + - name: MaxBootCycleNum + description: > + The max cached boot cycles for post code. +methods: + - name: GetPostCodes + description: > + Method to get the cached post code for each boot cycle. +TestBy: bitbake build + +Signeoff-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../State/Boot/PostCode.interface.yaml | 30 ++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + create mode 100644 xyz/openbmc_project/State/Boot/PostCode.interface.yaml + +diff --git a/xyz/openbmc_project/State/Boot/PostCode.interface.yaml b/xyz/openbmc_project/State/Boot/PostCode.interface.yaml +new file mode 100644 +index 0000000..711749d +--- /dev/null ++++ b/xyz/openbmc_project/State/Boot/PostCode.interface.yaml +@@ -0,0 +1,30 @@ ++description: > ++ Monitor Post code coming and buffer all of them based on boot cycle ++ into file system. ++ ++properties: ++ - name: CurrentBootCycleIndex ++ type: uint16 ++ description: > ++ It is used to indicate current boot cycle index. ++ - name: MaxBootCycleNum ++ type: uint16 ++ description: > ++ The max cached boot cycles for post code. ++methods: ++ - name: GetPostCodes ++ description: > ++ Method to get the cached post code for each boot cycle. ++ parameters: ++ - name: Index ++ type: uint16 ++ description: > ++ Index indicates which boot cycle of post codes is requested. ++ returns: ++ - name: codes ++ type: array[uint64] ++ description: > ++ An array of post codes of one boot cycle. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - xyz.openbmc_project.Common.Error.InvalidArgument +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch new file mode 100644 index 000000000..e1208cf5b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch @@ -0,0 +1,126 @@ +From f805522921d69eb4ea70248fe7e54557363aacea Mon Sep 17 00:00:00 2001 +From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +Date: Sat, 2 Mar 2019 03:31:09 +0530 +Subject: [PATCH] Creating the Session interface- for Host and LAN + +Defined all needed session properites to manage the session in +host and also in LAN + +Change-Id: Ic7cccfc3333a602ee07fcd60077ec58fd8f06304 +Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +--- + xyz/openbmc_project/Session/Info.interface.yaml | 56 +++++++++++++++++++++++++ + xyz/openbmc_project/Session/README.md | 38 +++++++++++++++++ + 2 files changed, 94 insertions(+) + create mode 100644 xyz/openbmc_project/Session/Info.interface.yaml + create mode 100644 xyz/openbmc_project/Session/README.md + +diff --git a/xyz/openbmc_project/Session/Info.interface.yaml b/xyz/openbmc_project/Session/Info.interface.yaml +new file mode 100644 +index 0000000..fbb5a45 +--- /dev/null ++++ b/xyz/openbmc_project/Session/Info.interface.yaml +@@ -0,0 +1,56 @@ ++description: > ++ Provides properties for session objects. ++ As communication to this service is done through authenticated ++ & authorized session, there won't be any validation for the both. ++ ++properties: ++ - name: SessionHandle ++ type: byte ++ description: > ++ Session Handle,unique number to locate the session. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: ChannelNum ++ type: byte ++ description: > ++ channelnumber which session is created. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: CurrentPrivilege ++ type: byte ++ description: > ++ Privilege of the session. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: RemoteIPAddr ++ type: uint32 ++ description: > ++ Remote IP address. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: RemotePort ++ type: uint16 ++ description: > ++ Remote IP Port. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: RemoteMACAddress ++ type: array[byte] ++ description: > ++ Remote MAC address. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: UserID ++ type: byte ++ description: > ++ Session created by given user ID. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - name: State ++ type: byte ++ description: > ++ Session state. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ ++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +diff --git a/xyz/openbmc_project/Session/README.md b/xyz/openbmc_project/Session/README.md +new file mode 100644 +index 0000000..f220885 +--- /dev/null ++++ b/xyz/openbmc_project/Session/README.md +@@ -0,0 +1,38 @@ ++# Session Management ++ ++## Overview ++Session Manager service exposes D-Bus methods for session management operations. ++ ++### Session Manager Interface ++Session manager interface `xyz.openbmc_project.Session.Manager` provides following ++methods, properties and signals. ++ ++#### xyz.openbmc_project.Session.Manager interface ++##### methods ++* CreateSession - To create new session object to the system. ++ ++##### properties ++* MaxSessionSupported - To list all the groups supported in the system. ++* ActiveSessionCount - To hold the no of active sessions. ++ ++Session manager service will create session objects for every session ++in the system under object path `/xyz/openbmc_project/session/<SessionIndex>`. ++Each session object can be handled through 'org.freedesktop.DBus.ObjectManager'. ++session object will expose following properties and methods. ++ ++#### xyz.openbmc_project.Session.Info interface ++##### properties ++* SessionID - Session ID,random unique number to locate the session. ++* Channel - Session created Channel. ++* SessionPrivilege - Privilege of the session. ++* RemoteIPAddr – Remote IP address. ++* RemotePort - Remote Port address. ++* RemoteMACAddress -Remote MAC Address. ++* UserID - Session created by given user id. ++ ++ ++ ++#### xyz.openbmc_project.Object.Delete ++#### methods ++* Delete - To delete the session object in the system. ++ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch new file mode 100644 index 000000000..68d2c92b7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch @@ -0,0 +1,76 @@ +From 2820ca36ab21c52341cdbde477756f960eaeb68b Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 13 Mar 2019 11:19:07 +0800 +Subject: [PATCH] Create dbus interface for SOL commands + +Create dbus properties for Set/Get SOL config parameter command. +Some platforms need to call Set/Get SOL config parameter command +through KCS, and since sol manager in net-ipmid cannot be accessed +by commands in host-ipmid, need to create a dbus interface in +phospher-settings to transfer properties from host-ipmid to +net-ipmid. + +TestedBy: +With the related code change in net-ipmid, busctl introspect +xyz.openbmc_project.Ipmi.SOL /xyz/openbmc_project/SOL +can show all the properties needed. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + xyz/openbmc_project/Ipmi/SOL.interface.yaml | 44 ++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + create mode 100644 xyz/openbmc_project/Ipmi/SOL.interface.yaml + +diff --git a/xyz/openbmc_project/Ipmi/SOL.interface.yaml b/xyz/openbmc_project/Ipmi/SOL.interface.yaml +new file mode 100644 +index 0000000..94db59f +--- /dev/null ++++ b/xyz/openbmc_project/Ipmi/SOL.interface.yaml +@@ -0,0 +1,44 @@ ++description: > ++ SOL properties use for Get/Set SOL config parameter command in host-ipmid ++ sending config to SOL process in net-ipmid. ++ Since some platforms need to access Get/Set SOL config parameter command ++ through KCS, and current sol manager is implemented in net-ipmid and ++ cannot be accessed by host-ipmid, add a dbus interface for host-ipmid ++ command to transfer properties to net-ipmid. ++ This interface will be implemented in phosphor-settings. ++properties: ++ - name: Progress ++ type: byte ++ description: > ++ Set In Progress property, indicate when any parameters are being ++ updated. ++ - name: Enable ++ type: boolean ++ description: > ++ SOL Enable property, this controls whether the SOL payload type ++ can be activated. ++ - name: Authentication ++ type: byte ++ description: > ++ If SOL enable Force Payload Encryption and Authenticaton. ++ And the minimun operating privilege level SOL required. ++ - name: AccumulateIntervalMS ++ type: byte ++ description: > ++ Character Accumulate Interval in 5ms increments. ++ BMC will wait this time before transmitting a packet. ++ - name: Threshold ++ type: byte ++ description: > ++ BMC will automatically send an SOL character data packet containing ++ this number of characters as soon as this number of characters ++ (or greater) has been accepted from the baseboard serial controller. ++ - name: RetryCount ++ type: byte ++ description: > ++ Packet will be dropped if no ACK/NACK received by time retries ++ expire. ++ - name: RetryIntervalMS ++ type: byte ++ description: > ++ Retry Interval in 10ms increments. +-- +2.16.2 + 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..a2eb6649c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend @@ -0,0 +1,20 @@ +SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git" +SRCREV = "5515c34fded4c217e3cc07f551d59d34cd3329c5" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0002-Modify-Dbus-for-IPv6.patch \ + file://0003-Chassis-Power-Control-are-implemented.patch \ + file://0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch \ + file://0006-dbus-interface-add-boot-option-support-for-floppy-an.patch \ + file://0007-ipmi-set-BIOS-id.patch \ + file://0009-Add-host-restart-cause-property.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://0014-Add-multiple-state-signal-for-host-start-and-stop.patch \ + file://0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch \ + file://0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch \ + file://0018-Define-post-code-interfaces-for-post-code-manager.patch \ + file://0019-Creating-the-Session-interface-for-Host-and-LAN.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..f4ffa17a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service @@ -0,0 +1,12 @@ +[Unit] +Description=Phosphor-Pid-Control Margin-based Fan Control Daemon + +[Service] +Restart=always +ExecStart={sbindir}/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..0c56a8fe5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend @@ -0,0 +1,8 @@ +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 = "90e9dbcae6c1df3127dd3de41f9d1e1b5a438828" 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..d51fee312 --- /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=/usr/bin/fwupd.sh file:////tmp/images/%i/image-runtime
+SyslogIdentifier=fwupd
\ No newline at end of file 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..80c5ea9d3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +EXTRA_OECONF += "--enable-fwupd_script" + +SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service" + +SRC_URI_remove = "git://github.com/openbmc/phosphor-bmc-code-mgmt" +SRC_URI += "git://git@github.com/Intel-BMC/phosphor-bmc-code-mgmt;protocol=ssh" +SRCREV = "f8f76c29dbe2806a6eacd15847563cdf7f7567f4" + +#Currently enforcing image signature validation only for PFR images +PACKAGECONFIG_append = "${@bb.utils.contains('IMAGE_TYPE', 'pfr', ' verify_signature', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb new file mode 100644 index 000000000..c04069fb9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb @@ -0,0 +1,18 @@ +SUMMARY = "Gpio daemon service for handling gpio operations" +DESCRIPTION = "Daemon allows to block gpio access under certain conditions" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/gpiodaemon" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "gpiodaemon.service" + +DEPENDS = "boost systemd sdbusplus phosphor-logging" 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/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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend new file mode 100644 index 000000000..fe09e6da2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -0,0 +1,17 @@ +SRC_URI = "git://github.com/openbmc/bmcweb.git" +SRCREV = "b01bf2991955ef267ce2be8e7a18eac984990de8" + +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 " + +# Enable CPU Log and Raw PECI support +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_CPU_LOG=ON" +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_RAW_PECI=ON" + +# Enable Redfish BMC Journal support +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_BMC_JOURNAL=ON" 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..13b945fd0 --- /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" : "eth2", + "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 + } + }, + "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" : "EMP", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "5" : { + "name" : "ICMB", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "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" : "SMM", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "8" : { + "name" : "INTRABMC", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "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" : "ipmb", + "protocol_type" : "ipmb-1.0", + "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" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "14" : { + "name" : "SELF", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "15" : { + "name" : "SMS", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "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..9fdb3c916 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json @@ -0,0 +1,49 @@ +{ + "filters": [ + { + "busId": "0x01", + "slaveAddr": "0x4d", + "command": "0x00" + }, + { + "busId": "0x01", + "slaveAddr": "0x57", + "command": "0x00" + }, + { + "busId": "0x02", + "slaveAddr": "0x40", + "command": "0x00" + }, + { + "busId": "0x02", + "slaveAddr": "0x49", + "command": "0x00" + }, + { + "busId": "0x02", + "slaveAddr": "0x51", + "command": "0x00" + }, + { + "busId": "0x03", + "slaveAddr": "0x44", + "command": "0x00" + }, + { + "busId": "0x03", + "slaveAddr": "0x68", + "command": "0x00" + }, + { + "busId": "0x06", + "slaveAddr": "0x40", + "command": "0x00" + }, + { + "busId": "0x07", + "slaveAddr": "0x51", + "command": "0x00" + } + ] +} 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/0002-Modify-dbus-interface-for-power-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch new file mode 100644 index 000000000..236bd18f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch @@ -0,0 +1,31 @@ +From 39df500f277eca01d6a0538d4db8ec34894d9441 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 12:59:12 +0800 +Subject: [PATCH] Modify dbus interface for power control + +Switch power control service namespace from "org" to "xyz", +to compatible with new intel-chassis services + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 6002e7a..0e83bba 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -786,8 +786,8 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_data_len_t data_len, + ipmi_context_t context) + { +- const char* objname = "/org/openbmc/control/power0"; +- const char* intf = "org.openbmc.control.Power"; ++ const char* objname = "/xyz/openbmc_project/Chassis/Control/Power0"; ++ const char* intf = "xyz.openbmc_project.Chassis.Control.Power"; + + sd_bus* bus = NULL; + sd_bus_message* reply = NULL; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch new file mode 100644 index 000000000..9061481ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch @@ -0,0 +1,33 @@ +From 48ac37551cd51415deafe8b1dcb23ebeef1e8ade Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 13:04:42 +0800 +Subject: [PATCH] Modify-dbus-interface-for-chassis-control + +Switch chassis control service namespace from "org" to "xyz", +to compatible with new intel-chassis services + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index b089331..f2889c5 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -393,9 +393,9 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_data_len_t data_len, + ipmi_context_t context) + { +- const char* objname = "/org/openbmc/control/chassis0"; ++ const char* objname = "/xyz/openbmc_project/Chassis/Control/Chassis"; + const char* iface = "org.freedesktop.DBus.Properties"; +- const char* chassis_iface = "org.openbmc.control.Chassis"; ++ const char* chassis_iface = "xyz.openbmc_project.Chassis.Control.Chassis"; + sd_bus_message* reply = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + int r = 0; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch new file mode 100644 index 000000000..3d9179ce5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch @@ -0,0 +1,909 @@ +From cd4bc9e4291771f638f66efa205bf8fbec518546 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Mon, 4 Feb 2019 10:30:12 -0800 +Subject: [PATCH] IPv6 Network changes + +Allow IPv6 IPMI set/get commands + +Signed-off-by: David Cobbley <david.j.cobbley@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +Change-Id: If5528d3b7294c5f8c17db5919439235d0fad0446 +--- + transporthandler.cpp | 667 ++++++++++++++++++++++++++++++++++++++++++- + transporthandler.hpp | 68 +++++ + types.hpp | 9 + + utils.hpp | 1 + + 4 files changed, 744 insertions(+), 1 deletion(-) + +Index: phosphor-host-ipmid.clean/transporthandler.cpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/transporthandler.cpp ++++ phosphor-host-ipmid.clean/transporthandler.cpp +@@ -41,6 +41,12 @@ extern std::unique_ptr<phosphor::Timer> + + const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx + constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; ++constexpr auto ipv6Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; ++ ++static const std::array<std::string, 3> ipAddressEnablesType = { ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"}; + + std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; + +@@ -400,7 +406,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + ipmi_context_t context) + { + ipmi_ret_t rc = IPMI_CC_OK; +- *data_len = 0; + + using namespace std::chrono_literals; + +@@ -414,6 +419,9 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + auto reqptr = reinterpret_cast<const set_lan_t*>(request); + sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); + ++ size_t reqLen = *data_len; ++ *data_len = 0; ++ + // channel number is the lower nibble + int channel = reqptr->channel & CHANNEL_MASK; + auto ethdevice = ipmi::network::ChanneltoEthernet(channel); +@@ -437,6 +445,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::IPSRC: + { ++ if (reqLen != LAN_PARAM_IPSRC_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint8_t ipsrc{}; + std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); + channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); +@@ -445,6 +458,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::MAC: + { ++ if (reqLen != LAN_PARAM_MAC_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + char mac[SIZE_MAC]; + + std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, +@@ -465,6 +483,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::SUBNET: + { ++ if (reqLen != LAN_PARAM_SUBNET_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(netmask, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -474,6 +497,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::GATEWAY: + { ++ if (reqLen != LAN_PARAM_GATEWAY_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(gateway, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -483,6 +511,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::VLAN: + { ++ if (reqLen != LAN_PARAM_VLAN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint16_t vlan{}; + std::memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); + // We are not storing the enable bit +@@ -495,6 +528,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::INPROGRESS: + { ++ if (reqLen != LAN_PARAM_INPROGRESS_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + if (reqptr->data[0] == SET_COMPLETE) + { + channelConf->lan_set_in_progress = SET_COMPLETE; +@@ -523,6 +561,122 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + } + break; + ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ if (reqLen != LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressingEnables = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressSource = ++ reqptr->data[1] & 0x81; // Looking at bit 0 and bit 7 ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, &reqptr->data[2], tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6Addr.assign(tmpIPV6); ++ channelConf->ipv6Prefix = reqptr->data[19]; ++ break; ++ } ++ ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6RouterAddressConfigControl = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6GatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6BackupGatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ + default: + { + rc = IPMI_CC_PARM_NOT_SUPPORTED; +@@ -549,6 +703,7 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_n + ipmi_ret_t rc = IPMI_CC_OK; + *data_len = 0; + const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 ++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; + + get_lan_t* reqptr = (get_lan_t*)request; + // channel number is the lower nibble +@@ -687,6 +842,489 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_n + static_cast<uint8_t>(cipherList.size()); + break; + } ++ case LanParam::IPV6_AND_IPV4_SUPPORTED: ++ { ++ uint8_t addressSupport = ++ 0x1; // Allow both IPv4 & IPv6 simultaneously ++ std::array<uint8_t, 2> buf = {current_revision, addressSupport}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ // If DHCP, check if you have an ipv6 and ipv4 address. If static ++ // return not supported ++ ++ // 00h check if conf DHCP == ipv4 or off ++ // 01h check if conf DHCP == ipv6 ++ // 02h check if DHCP == true ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t ipVAddressEnables = 0; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system has an ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ std::string ipEnables = ++ sdbusplus::message::variant_ns::get<std::string>( ++ ipmi::getDbusProperty(bus, ipmi::network::SERVICE, ++ networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, ++ "IPAddressEnables")); ++ ++ // check if on off ipv4 ipv6, etc. ++ bool found = false; ++ for (uint8_t ii = 0; ii < ipAddressEnablesType.size(); ii++) ++ { ++ if (ipEnables == ipAddressEnablesType[ii]) ++ { ++ ipVAddressEnables = ii; ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ { ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ } ++ else ++ { ++ ipVAddressEnables = channelConf->ipv6AddressingEnables; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, ipVAddressEnables}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATUS: ++ { ++ // Number of IPV6 addresses that are supported ++ constexpr std::array<uint8_t, 3> statusData = {1, 1, 3}; ++ ++ std::array<uint8_t, 4> buf = {current_revision, statusData[0], ++ statusData[1], statusData[2]}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ // Only return set selector 0 ++ uint8_t ipv6SetSelector = 0; ++ std::string ipaddress; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ std::string origin = ++ sdbusplus::message::variant_ns::get<std::string>( ++ properties["Origin"]); ++ if (sdbusplus::message::variant_ns::get<std::string>( ++ properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ++ { ++ ipaddress = ++ sdbusplus::message::variant_ns::get<std::string>( ++ properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ sdbusplus::message::variant_ns::get<uint8_t>( ++ properties["PrefixLength"]); ++ status = 0; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ ipaddress = channelConf->ipv6Addr.c_str(); ++ prefixLength = channelConf->ipv6Prefix; ++ status = 1; ++ } ++ ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_STATUS_SIZE> buf = { ++ current_revision, ipv6SetSelector, ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUID_STORAGE_LENGTH: ++ { ++ // DHCP unique identified ++ // Only 1 read-only 16-byte Block needed ++ uint8_t duidLength = 1; ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = ++ sdbusplus::message::variant_ns::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DYNAMIC_ADDRESSES: ++ { ++ std::string ipaddress; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (sdbusplus::message::variant_ns::get<std::string>( ++ properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") ++ { ++ ipaddress = ++ sdbusplus::message::variant_ns::get<std::string>( ++ properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ sdbusplus::message::variant_ns::get<uint8_t>( ++ properties["PrefixLength"]); ++ status = 0; ++ } ++ else ++ { ++ status = 1; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipaddress = channelConf->ipv6Addr; ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ prefixLength = channelConf->ipv6Prefix; ++ status = channelConf->ipv6AddressStatus; ++ } ++ ++ uint8_t ipv6SetSelector = 0; ++ std::array<uint8_t, 22> buf = {current_revision, ipv6SetSelector, ++ ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUID_STOR_LEN: ++ { ++ uint8_t duidLength = 0; ++ // Only 1 read-only 16-byte Block needed ++ duidLength = 1; ++ ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = ++ sdbusplus::message::variant_ns::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ // Determine if automated router discovery occurs when static ++ // addresses are used for the bmc ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t dynamicRA; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system is having ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA"); ++ dynamicRA = sdbusplus::message::variant_ns::get<bool>(variant); ++ } ++ else ++ { ++ dynamicRA = channelConf->ipv6RouterAddressConfigControl; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, dynamicRA}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6GatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = {current_revision, ++ channelConf->ipv6GatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ ++ inet_pton(AF_INET6, channelConf->ipv6GatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6BackupGatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = { ++ current_revision, channelConf->ipv6BackupGatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ inet_pton(AF_INET6, ++ channelConf->ipv6BackupGatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } + default: + log<level::ERR>("Unsupported parameter", + entry("PARAMETER=0x%x", reqptr->parameter)); +@@ -932,6 +1570,16 @@ void applyChanges(int channel) + ipaddress, prefix); + } + ++ if (!channelConf->ipv6Addr.empty() && ++ channelConf->ipv6AddressSource == ++ 0x80) // Check if IPv6 static addresses are enabled ++ { ++ ipmi::network::createIP(bus, ipmi::network::SERVICE, ++ networkInterfacePath, ipv6Protocol, ++ channelConf->ipv6Addr, ++ channelConf->ipv6Prefix); ++ } ++ + if (!gateway.empty()) + { + ipmi::setDbusProperty(bus, systemObject.second, +@@ -939,7 +1587,24 @@ void applyChanges(int channel) + ipmi::network::SYSTEMCONFIG_INTERFACE, + "DefaultGateway", std::string(gateway)); + } ++ else if (!channelConf->ipv6GatewayAddr.empty()) ++ { ++ ipmi::setDbusProperty( ++ bus, systemObject.second, systemObject.first, ++ ipmi::network::SYSTEMCONFIG_INTERFACE, "DefaultGateway", ++ std::string(channelConf->ipv6GatewayAddr)); ++ } + } ++ // set IPAddress Enables ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables", ++ ipAddressEnablesType[channelConf->ipv6AddressingEnables]); ++ ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA", ++ (bool)channelConf->ipv6RouterAddressConfigControl); + } + catch (InternalFailure& e) + { +Index: phosphor-host-ipmid.clean/transporthandler.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/transporthandler.hpp ++++ phosphor-host-ipmid.clean/transporthandler.hpp +@@ -80,6 +80,28 @@ enum class LanParam : uint8_t + IPV6_NEIGHBOR_TIMING_CONFIGURATION = 80, + }; + ++// Data length of parameters ++constexpr size_t LAN_PARAM_INPROGRESS_SIZE = 3; ++constexpr size_t LAN_PARAM_IP_SIZE = 6; ++constexpr size_t LAN_PARAM_IPSRC_SIZE = 3; ++constexpr size_t LAN_PARAM_MAC_SIZE = 8; ++constexpr size_t LAN_PARAM_SUBNET_SIZE = 6; ++constexpr size_t LAN_PARAM_GATEWAY_SIZE = 6; ++constexpr size_t LAN_PARAM_VLAN_SIZE = 4; ++constexpr size_t LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE = 23; ++constexpr size_t LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE = 18; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE = 19; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE = 18; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE = 19; ++ ++constexpr uint8_t DUID_LEN = 10; ++constexpr uint8_t DUID_LL_TYPE = 3; ++constexpr uint8_t DUIC_ETH_HW_TYPE = 1; ++ + constexpr uint8_t SET_COMPLETE = 0; + constexpr uint8_t SET_IN_PROGRESS = 1; + constexpr uint8_t SET_COMMIT_WRITE = 2; // Optional +@@ -102,6 +124,20 @@ struct ChannelConfig_t + uint8_t lan_set_in_progress = SET_COMPLETE; + bool flush = false; + ++ // IPV6 parameters ++ uint8_t ipv6AddressSource = 0x0; ++ uint8_t ipv6AddressingEnables = 0x2; ++ std::string ipv6Addr; ++ uint8_t ipv6Prefix = 32; ++ uint8_t ipv6AddressStatus = 0x0; ++ uint8_t ipv6RouterAddressConfigControl = 0x0; ++ std::string ipv6GatewayAddr; ++ std::string ipv6BackupGatewayAddr; ++ uint8_t ipv6GatewayPrefixLength; ++ std::string ipv6GatewayPrefixValue; ++ uint8_t ipv6BackupGatewayPrefixLength = 0x0; ++ std::string ipv6BackupGatewayPrefixValue; ++ + void clear() + { + ipaddr.clear(); +@@ -112,6 +148,20 @@ struct ChannelConfig_t + ipsrc = ipmi::network::IPOrigin::UNSPECIFIED; + lan_set_in_progress = SET_COMPLETE; + flush = false; ++ ++ // IPv6 ++ ipv6Addr.clear(); ++ ipv6GatewayAddr.clear(); ++ ipv6BackupGatewayAddr.clear(); ++ ipv6AddressingEnables = 0x2; ++ ipv6AddressSource = 0x0; ++ ipv6Prefix = 32; ++ ipv6AddressStatus = 0x0; ++ ipv6RouterAddressConfigControl = 0x0; ++ ipv6GatewayPrefixLength = 0x0; ++ ipv6GatewayPrefixValue.clear(); ++ ipv6BackupGatewayPrefixLength = 0x0; ++ ipv6BackupGatewayPrefixValue.clear(); + } + }; + +Index: phosphor-host-ipmid.clean/types.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/types.hpp ++++ phosphor-host-ipmid.clean/types.hpp +@@ -209,6 +209,7 @@ constexpr auto ADDR_TYPE_FORMAT = "%hhx" + + constexpr auto IPV4_ADDRESS_SIZE_BYTE = 4; + constexpr auto IPV6_ADDRESS_SIZE_BYTE = 16; ++constexpr auto IPV6_ADDRESS_STATUS_SIZE = 22; + + constexpr auto DEFAULT_MAC_ADDRESS = "00:00:00:00:00:00"; + constexpr auto DEFAULT_ADDRESS = "0.0.0.0"; +@@ -220,6 +221,7 @@ constexpr auto BITS_32 = 32; + constexpr auto MASK_32_BIT = 0xFFFFFFFF; + constexpr auto VLAN_ID_MASK = 0x00000FFF; + constexpr auto VLAN_ENABLE_MASK = 0x8000; ++constexpr auto IPV6_DUID_SIZE = 18; + + enum class IPOrigin : uint8_t + { +@@ -228,5 +230,12 @@ enum class IPOrigin : uint8_t + DHCP = 2, + }; + ++enum class AddressingEnables : uint8_t ++{ ++ IPv4Only = 0, ++ IPv6Only = 1, ++ IPv4AndIPv6 = 2, ++}; ++ + } // namespace network + } // namespace ipmi +Index: phosphor-host-ipmid.clean/utils.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/utils.hpp ++++ phosphor-host-ipmid.clean/utils.hpp +@@ -246,6 +246,7 @@ namespace network + constexpr auto ROOT = "/xyz/openbmc_project/network"; + constexpr auto SERVICE = "xyz.openbmc_project.Network"; + constexpr auto IP_TYPE = "ipv4"; ++constexpr auto IPV6_TYPE = "ipv6"; + constexpr auto IPV4_PREFIX = "169.254"; + constexpr auto IPV6_PREFIX = "fe80"; + constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; 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..c1ec6ac6e --- /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,56 @@ +From 4953a9f2233fd24a28da84443cea6aebecd14fbc Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 13:20:54 +0800 +Subject: [PATCH] fix "get system GUID" ipmi command + +Change-Id: I15c71607c24ad8b3e2c9065a5470002ecb1761bb +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 7 ++----- + host-ipmid-whitelist.conf | 1 + + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index f2889c5..9149373 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -48,7 +48,7 @@ extern sd_bus* bus; + + constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC"; + constexpr auto bmc_state_property = "CurrentBMCState"; +-constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc"; ++// phosphor-setting-manager is the unique service that holds this interface + constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID"; + constexpr auto bmc_guid_property = "UUID"; + constexpr auto bmc_guid_len = 16; +@@ -546,8 +545,7 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + { + // Get the Inventory object implementing BMC interface + ipmi::DbusObjectInfo bmcObject = +- ipmi::getDbusObject(bus, bmc_interface); +- ++ ipmi::getDbusObject(bus, bmc_guid_interface); + // Read UUID property value from bmcObject + // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 + auto variant = +@@ -591,7 +589,6 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + catch (const InternalFailure& e) + { + log<level::ERR>("Failed in reading BMC UUID property", +- entry("INTERFACE=%s", bmc_interface), + entry("PROPERTY_INTERFACE=%s", bmc_guid_interface), + entry("PROPERTY=%s", bmc_guid_property)); + return IPMI_CC_UNSPECIFIED_ERROR; +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 2c37ac9..164edbe 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -40,3 +40,4 @@ + 0x2C:0x06 //<Group Extension>:<Get Asset Tag> + 0x2C:0x07 //<Group Extension>:<Get Sensor Info> + 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> ++0x30:0x41 //<OEM>:<Set System GUID> +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch new file mode 100644 index 000000000..243015c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch @@ -0,0 +1,64 @@ +From 7b5c6a54c049a447b1fd3a42f9d63322dcee4dc7 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Sun, 16 Sep 2018 19:45:10 +0800 +Subject: [PATCH] [ipmi] set/get boot options + +1. fix issue for handling unsupported paramter +2. add support for floppy/USB boot + +Change-Id: I2b888c1ad67fec7924dd5825f78622cd216a55f4 +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 666addb..77af2dc 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1244,7 +1244,8 @@ constexpr auto ipmiDefault = 0; + std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = { + {0x01, Source::Sources::Network}, + {0x02, Source::Sources::Disk}, +- {0x05, Source::Sources::ExternalMedia}, ++ {0x05, Source::Sources::DVD}, ++ {0x0f, Source::Sources::Removable}, + {ipmiDefault, Source::Sources::Default}}; + + std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { +@@ -1255,7 +1256,8 @@ std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { + std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = { + {Source::Sources::Network, 0x01}, + {Source::Sources::Disk, 0x02}, +- {Source::Sources::ExternalMedia, 0x05}, ++ {Source::Sources::DVD, 0x05}, ++ {Source::Sources::Removable, 0x0f}, + {Source::Sources::Default, ipmiDefault}}; + + std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = { +@@ -1533,7 +1535,7 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + setBootMode(Mode::Modes::Regular); + } + } +- if (modeIpmiToDbus.end() != modeItr) ++ else if (modeIpmiToDbus.end() != modeItr) + { + rc = setBootMode(modeItr->second); + if (rc != IPMI_CC_OK) +@@ -1550,6 +1552,12 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + setBootSource(Source::Sources::Default); + } + } ++ else ++ { ++ // if boot option is not in support list, return error ++ *data_len = 0; ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } + } + catch (InternalFailure& e) + { +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch new file mode 100644 index 000000000..ae10ab60a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch @@ -0,0 +1,25 @@ +From ad7276f3aedb6f5aed315db57406c98f2bf71a09 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 13:21:52 +0800 +Subject: [PATCH] [ipmi] add set bios id to whitelist + +Add "SetBIOSId" and "GetDeviceInfo" 2 OEM commands into whitelist + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 164edbe..db54a49 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,3 +41,5 @@ + 0x2C:0x07 //<Group Extension>:<Get Sensor Info> + 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> + 0x30:0x41 //<OEM>:<Set System GUID> ++0x30:0x26 //<OEM>:<Set BIOS ID> ++0x30:0x27 //<OEM>:<Get Device Info> +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch new file mode 100644 index 000000000..46dd99466 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch @@ -0,0 +1,45 @@ +From 482a6cc52d0ec514d6da5f4bcb04b4991f3cc36e Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 13:41:25 +0800 +Subject: [PATCH] Enable get device guid ipmi command + +The UUID interface is changed, modify the API to get the correct UUID +for device guid + +Change-Id: I0c0c7bd350992ac03f928707986a7180407d8f3f +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 937be71..89d797a 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -392,9 +392,10 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_data_len_t data_len, + ipmi_context_t context) + { +- const char* objname = "/xyz/openbmc_project/Chassis/Control/Chassis"; ++ const char* objname = ++ "/xyz/openbmc_project/inventory/system/chassis/motherboard/bmc"; + const char* iface = "org.freedesktop.DBus.Properties"; +- const char* chassis_iface = "xyz.openbmc_project.Chassis.Control.Chassis"; ++ const char* uuid_iface = "xyz.openbmc_project.Common.UUID"; + sd_bus_message* reply = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + int r = 0; +@@ -426,8 +427,9 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + entry("ERRNO=0x%X", -r)); + goto finish; + } ++ + r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply, +- "ss", chassis_iface, "uuid"); ++ "ss", uuid_iface, "UUID"); + if (r < 0) + { + log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r)); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch new file mode 100644 index 000000000..873eb6b16 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch @@ -0,0 +1,153 @@ +From a445f287d4aebca68dc0321e292933311caf59ba Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Sun, 16 Sep 2018 20:14:55 +0800 +Subject: [PATCH] add better sdbusplus exception handling + +Now that sdbusplus throws, we need to catch more stuff. To compound the +problem, even though sdbusplus::exception::exception inherits from +std::exception, there is a problem that prevents the code from simply +catching std::exception. + +Change-Id: I2a330e542f5d87722a4c04e6d47de2cfb2f7d7c9 +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> + +--- + apphandler.cpp | 14 +++++++-- + ipmid.cpp | 77 +++++++++++++++++++++++++++++++++++--------------- + 2 files changed, 66 insertions(+), 25 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 126de33..3cae6d5 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -312,9 +312,19 @@ ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + auto version = getActiveSoftwareVersionInfo(); + r = convert_version(version.c_str(), &rev); + } +- catch (const std::exception& e) ++ catch (sdbusplus::exception::exception& e) + { +- log<level::ERR>(e.what()); ++ log<level::ERR>("sdbusplus::exception", ++ entry("ERROR=%s", e.what())); ++ } ++ catch (std::exception& e) ++ { ++ log<level::ERR>("unexpected exception", ++ entry("ERROR=%s", e.what())); ++ } ++ catch (...) ++ { ++ log<level::ERR>("unknown exception"); + } + + if (r >= 0) +diff --git a/ipmid.cpp b/ipmid.cpp +index 2d48bfe..8d2fb37 100644 +--- a/ipmid.cpp ++++ b/ipmid.cpp +@@ -273,6 +273,10 @@ ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + } + // IPMI command handlers can throw unhandled exceptions, catch those + // and return sane error code. ++ catch (sdbusplus::exception::exception& e) ++ { ++ log<level::ERR>("sdbusplus exception", entry("EXCEPTION=%s", e.what())); ++ } + catch (const std::exception& e) + { + log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn), +@@ -281,6 +285,23 @@ ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + *data_len = 0; + // fall through + } ++ catch (...) ++ { ++ std::exception_ptr eptr = std::current_exception(); ++ try ++ { ++ std::rethrow_exception(eptr); ++ } ++ catch (std::exception& e) ++ { ++ log<level::ERR>("unexpected uncaught exception", ++ entry("EXCEPTION=%s", e.what()), ++ entry("NET_FUN=0x%X", netfn), ++ entry("CMD=0x%X", cmd)); ++ rc = IPMI_CC_UNSPECIFIED_ERROR; ++ *data_len = 0; ++ } ++ } + // Now copy the return code that we got from handler and pack it in first + // byte. + std::memcpy(response, &rc, IPMI_CC_LEN); +@@ -361,32 +382,42 @@ final: + void cache_restricted_mode() + { + restricted_mode = false; +- using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; +- using namespace internal; +- using namespace internal::cache; +- sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); +- const auto& restrictionModeSetting = +- objects->map.at(restrictionModeIntf).front(); +- auto method = dbus.new_method_call( +- objects->service(restrictionModeSetting, restrictionModeIntf).c_str(), +- restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties", +- "Get"); +- method.append(restrictionModeIntf, "RestrictionMode"); +- auto resp = dbus.call(method); +- if (resp.is_method_error()) ++ try + { +- log<level::ERR>("Error in RestrictionMode Get"); +- // Fail-safe to true. +- restricted_mode = true; +- return; ++ using namespace sdbusplus::xyz::openbmc_project::Control::Security:: ++ server; ++ using namespace internal; ++ using namespace internal::cache; ++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); ++ const auto& restrictionModeSetting = ++ objects->map.at(restrictionModeIntf).front(); ++ auto method = dbus.new_method_call( ++ objects->service(restrictionModeSetting, restrictionModeIntf) ++ .c_str(), ++ restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties", ++ "Get"); ++ method.append(restrictionModeIntf, "RestrictionMode"); ++ auto resp = dbus.call(method); ++ if (resp.is_method_error()) ++ { ++ log<level::ERR>("Error in RestrictionMode Get"); ++ // Fail-safe to true. ++ restricted_mode = true; ++ return; ++ } ++ sdbusplus::message::variant<std::string> result; ++ resp.read(result); ++ auto restrictionMode = RestrictionMode::convertModesFromString( ++ sdbusplus::message::variant_ns::get<std::string>(result)); ++ if (RestrictionMode::Modes::Whitelist == restrictionMode) ++ { ++ restricted_mode = true; ++ } + } +- sdbusplus::message::variant<std::string> result; +- resp.read(result); +- auto restrictionMode = RestrictionMode::convertModesFromString( +- variant_ns::get<std::string>(result)); +- if (RestrictionMode::Modes::Whitelist == restrictionMode) ++ catch (sdbusplus::exception::exception& e) + { +- restricted_mode = true; ++ // restrictionModeIntf does not exist; default to not enforcing ++ log<level::ERR>("sdbusplus exception", entry("EXCEPTION=%s", e.what())); + } + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch new file mode 100644 index 000000000..6fa69b602 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch @@ -0,0 +1,49 @@ +From 4490ee7a9fd054640af7a9da3400f76195dc2880 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Sun, 16 Sep 2018 21:03:58 +0800 +Subject: [PATCH] Catch sdbusplus exceptions in IPMI net + +Missing the correct exception was causing issues with setting the IPV4 +address + +Change-Id: Ieaaacfcbaec82a0c3b110889817a7ceb9cda8d3c +Signed-off-by: Dave Cobbley <david.j.cobbley@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + transporthandler.cpp | 2 +- + utils.cpp | 5 +++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 6f4ec3f..6cb3feb 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1559,7 +1559,7 @@ void applyChanges(int channel) + ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA", + (bool)channelConf->ipv6RouterAddressConfigControl); + } +- catch (InternalFailure& e) ++ catch (sdbusplus::exception::exception& e) + { + log<level::ERR>( + "Failed to set network data", entry("PREFIX=%d", prefix), +diff --git a/utils.cpp b/utils.cpp +index 225b1cc..d10b5de 100644 +--- a/utils.cpp ++++ b/utils.cpp +@@ -358,9 +358,10 @@ void deleteAllDbusObjects(sdbusplus::bus::bus& bus, + "Delete"); + } + } +- catch (InternalFailure& e) ++ catch (sdbusplus::exception::exception& e) + { +- log<level::INFO>("Unable to delete the objects having", ++ log<level::INFO>("sdbusplus exception - Unable to delete the objects", ++ entry("ERROR=%s", e.what()), + entry("INTERFACE=%s", interface.c_str()), + entry("SERVICE=%s", serviceRoot.c_str())); + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch new file mode 100644 index 000000000..af526c177 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch @@ -0,0 +1,143 @@ +From c14e31ebc35e0bb7b843d84683f9f2698c9c08d7 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Sun, 16 Sep 2018 21:32:38 +0800 +Subject: [PATCH] Implement IPMI Commmand - Get Host Restart Cause. + +It supports to track the information about what +action last caused the system to restart. +Return value includes: restart_cause and channel_number. + +According to IPMI Spec, it includes 12 types as following: +1. Unknown 0x0 +2. IpmiCommand 0x1 +3. ResetButton 0x2 +4. PowerButton 0x3 +5. WatchdogTimer 0x4 +6. OEM 0x5 +7. PowerPolicyAlwaysOn 0x6 +8. PowerPolicyPreviousState 0x7 +9. PEF-Reset 0x8 +10. PEF-PowerCycle 0x9 +11. SoftReset 0xA +12. RTC-Wakeup 0xB + +Change-Id: Id3b32e271b85b5fc4c69d5ca40227f8f9c08ce48 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++ + chassishandler.hpp | 1 + + host-ipmid-whitelist.conf | 1 + + 3 files changed, 56 insertions(+) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 77af2dc..2a29755 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -107,6 +107,11 @@ static constexpr auto chassisPOHStateIntf = + "xyz.openbmc_project.State.PowerOnHours"; + static constexpr auto pOHCounterProperty = "POHCounter"; + static constexpr auto match = "chassis0"; ++const static constexpr char* stateHostInterface = ++ "xyz.openbmc_project.State.Host"; ++const static constexpr char* hostRestartCauseInterface = ++ "xyz.openbmc_project.State.Host.HostRestartCause"; ++const static constexpr char* hostRestartCause = "HostRestartCause"; + const static constexpr char chassisCapIntf[] = + "xyz.openbmc_project.Control.ChassisCapabilities"; + const static constexpr char chassisCapFlagsProp[] = "CapabilitiesFlags"; +@@ -324,6 +329,13 @@ struct set_sys_boot_options_t + uint8_t data[SIZE_BOOT_OPTION]; + } __attribute__((packed)); + ++struct GetSysRestartCauseResponse ++{ ++ uint8_t restartCause; ++ uint8_t channelNum; ++ ++} __attribute__((packed)); ++ + int getHostNetworkData(get_sys_boot_options_response_t* respptr) + { + ipmi::PropertyMap properties; +@@ -1598,6 +1610,44 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return rc; + } + ++ipmi_ret_t ipmi_chassis_get_sys_restart_cause( ++ ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, ++ ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) ++{ ++ ipmi_ret_t rc = IPMI_CC_OK; ++ ++ GetSysRestartCauseResponse* resp = (GetSysRestartCauseResponse*)response; ++ std::fill(reinterpret_cast<uint8_t*>(resp), ++ reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0); ++ if (*data_len != 0) ++ { ++ rc = IPMI_CC_REQ_DATA_LEN_INVALID; ++ return rc; ++ } ++ ++ try ++ { ++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; ++ ipmi::DbusObjectInfo hostObject = ++ ipmi::getDbusObject(bus, stateHostInterface); ++ ipmi::Value variant = ++ ipmi::getDbusProperty(bus, hostObject.second, hostObject.first, ++ hostRestartCauseInterface, hostRestartCause); ++ resp->restartCause = variant.get<uint8_t>(); ++ } ++ ++ catch (std::exception& e) ++ { ++ log<level::ERR>(e.what()); ++ rc = IPMI_CC_UNSPECIFIED_ERROR; ++ return rc; ++ } ++ resp->channelNum = 0; // Fix to primary channel. ++ *data_len = sizeof(GetSysRestartCauseResponse); ++ ++ return rc; ++} ++ + ipmi_ret_t ipmiGetPOHCounter(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, ipmi_response_t response, + ipmi_data_len_t data_len, ipmi_context_t context) +@@ -1739,4 +1789,8 @@ void register_netfn_chassis_functions() + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_RESTORE_POLICY, NULL, + ipmi_chassis_set_power_restore_policy, + PRIVILEGE_OPERATOR); ++ ++ // <get Host Restart Cause> ++ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_RESTART_CAUSE, NULL, ++ ipmi_chassis_get_sys_restart_cause, PRIVILEGE_USER); + } +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 0c6d5a2..e37c4f1 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -17,6 +17,7 @@ enum ipmi_netfn_chassis_cmds + // Set Power Restore Policy + IPMI_CMD_SET_RESTORE_POLICY = 0x06, + // Get capability bits ++ IPMI_CMD_GET_SYS_RESTART_CAUSE = 0x07, + IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08, + IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09, + IPMI_CMD_GET_POH_COUNTER = 0x0F, +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index db54a49..827e2dc 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -3,6 +3,7 @@ + 0x00:0x02 //<Chassis>:<Chassis Control> + 0x00:0x05 //<Chassis>:<Set Chassis Capabilities> + 0x00:0x06 //<Chassis>:<Set Power Restore Policy> ++0x00:0x07 //<Chassis>:<Get System Restart Cause> + 0x00:0x08 //<Chassis>:<Set System Boot Options> + 0x00:0x09 //<Chassis>:<Get System Boot Options> + 0x00:0x0F //<Chassis>:<Get POH Counter Command> +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch new file mode 100644 index 000000000..fdaa91085 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch @@ -0,0 +1,25 @@ +From cf466ba2c66a95825ae0014d7c378ad63b050d2f Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Wed, 15 Aug 2018 14:50:04 +0800 +Subject: [PATCH] [ipmi] add oem command "get AIC FRU" to whitelist + +Intel BIOS requires this oem command to get addon card FRU info. +Add to whitelist to unblock. + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index db54a49..49746a2 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -43,3 +43,4 @@ + 0x30:0x41 //<OEM>:<Set System GUID> + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> ++0x30:0x31 //<OEM>:<Get AIC card FRU> +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch new file mode 100644 index 000000000..4018dbffe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch @@ -0,0 +1,322 @@ +From cd25f43461b41b74d19cd1f93ce301df9c3bd4f2 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 21 Sep 2018 09:21:14 +0800 +Subject: [PATCH] Implement IPMI Master Write-Read command + +This command can be used for low-level I2C/SMBus write, read, or write-read +accesses to the IPMB or private busses behind a management controller. + +The command can also be used for providing low-level access to devices +that provide an SMBus slave interface. + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++++++ + apphandler.hpp | 1 + + host-ipmid-whitelist.conf | 1 + + 3 files changed, 238 insertions(+) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 17aff2a..2fe79f6 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -8,6 +8,14 @@ + #include "types.hpp" + #include "utils.hpp" + ++#include <fcntl.h> ++#include <linux/i2c-dev.h> ++#include <linux/i2c.h> ++#include <sys/ioctl.h> ++#include <sys/stat.h> ++#include <sys/types.h> ++#include <unistd.h> ++ + #include <arpa/inet.h> + #include <host-ipmid/ipmid-api.h> + #include <limits.h> +@@ -55,6 +63,8 @@ constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID"; + constexpr auto bmc_guid_property = "UUID"; + constexpr auto bmc_guid_len = 16; + ++static constexpr uint8_t maxIPMIWriteReadSize = 144; ++ + static constexpr auto redundancyIntf = + "xyz.openbmc_project.Software.RedundancyPriority"; + static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version"; +@@ -86,6 +96,34 @@ typedef struct + uint8_t aux[4]; + } __attribute__((packed)) ipmi_device_id_t; + ++typedef struct ++{ ++ uint8_t busId; ++ uint8_t slaveAddr; ++ uint8_t readCount; ++} __attribute__((packed)) ipmiI2cRwReq; ++ ++typedef struct ++{ ++ uint8_t busId; ++ uint8_t slaveAddr; ++ std::vector<uint8_t> data; ++} ipmiMasterRwWhitelist; ++ ++static std::vector<ipmiMasterRwWhitelist>& getWhiteList() ++{ ++ static std::vector<ipmiMasterRwWhitelist> rwWhiteList; ++ return rwWhiteList; ++} ++ ++static constexpr const char* whiteListFilename = ++ "/usr/share/ipmi-providers/master_write_read_white_list.json"; ++ ++static constexpr const char* filtersStr = "filters"; ++static constexpr const char* busIdStr = "busId"; ++static constexpr const char* slaveAddrStr = "slaveAddr"; ++static constexpr const char* cmdStr = "command"; ++ + /** + * @brief Returns the Version info from primary s/w object + * +@@ -1089,8 +1127,195 @@ writeResponse: + return IPMI_CC_OK; + } + ++static int loadI2CWhiteList() ++{ ++ nlohmann::json data = nullptr; ++ std::ifstream jsonFile(whiteListFilename); ++ ++ if (!jsonFile.good()) ++ { ++ log<level::WARNING>("whitelist file not found!"); ++ return -1; ++ } ++ ++ try ++ { ++ data = nlohmann::json::parse(jsonFile, nullptr, false); ++ } ++ catch (nlohmann::json::parse_error& e) ++ { ++ log<level::ERR>("Corrupted whitelist config file", ++ entry("MSG: %s", e.what())); ++ return -1; ++ } ++ ++ try ++ { ++ unsigned int i = 0; ++ nlohmann::json filters = data[filtersStr].get<nlohmann::json>(); ++ getWhiteList().resize(filters.size()); ++ ++ for (const auto& it : filters.items()) ++ { ++ nlohmann::json filter = it.value(); ++ if (filter.is_null()) ++ { ++ log<level::ERR>("Incorrect filter"); ++ return -1; ++ } ++ ++ getWhiteList()[i].busId = ++ std::stoul(filter[busIdStr].get<std::string>(), nullptr, 16); ++ ++ getWhiteList()[i].slaveAddr = std::stoul( ++ filter[slaveAddrStr].get<std::string>(), nullptr, 16); ++ ++ std::string command = filter[cmdStr].get<std::string>(); ++ ++ log<level::DEBUG>("IPMI I2C whitelist ", entry("INDEX=%d", i), ++ entry("BUS=%d", getWhiteList()[i].busId), ++ entry("ADDR=0x%x", getWhiteList()[i].slaveAddr), ++ entry("LEN=0x%x", command.length()), ++ entry("COMMAND=[%s]", command.c_str())); ++ ++ // convert data string ++ std::istringstream iss(command); ++ std::string token; ++ while (std::getline(iss, token, ' ')) ++ { ++ log<level::DEBUG>("IPMI I2C command\n", ++ entry("TOKEN=%s", token.c_str())); ++ getWhiteList()[i].data.emplace_back( ++ std::stoul(token, nullptr, 16)); ++ } ++ i++; ++ } ++ } ++ catch (std::exception& e) ++ { ++ log<level::ERR>("unexpected exception", entry("ERROR=%s", e.what())); ++ return -1; ++ } ++ return 0; ++} ++ ++ipmi_ret_t ipmiMasterWriteRead(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ipmi_response_t response, ++ ipmi_data_len_t data_len, ipmi_context_t context) ++{ ++ bool foundInList = false; ++ int ret = 0; ++ i2c_rdwr_ioctl_data msgRdwr = {0}; ++ i2c_msg i2cmsg[2] = {0}; ++ ipmiI2cRwReq* reqi2c = reinterpret_cast<ipmiI2cRwReq*>(request); ++ ++ if (*data_len <= sizeof(ipmiI2cRwReq)) ++ { ++ log<level::ERR>("Failed in request", entry("LEN=%d", *data_len)); ++ *data_len = 0; ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ if (reqi2c->readCount > maxIPMIWriteReadSize) ++ { ++ log<level::ERR>("Failed in request", entry("R=%d", reqi2c->readCount)); ++ *data_len = 0; ++ return IPMI_CC_PARM_OUT_OF_RANGE; ++ } ++ ++ uint8_t* resptr = reinterpret_cast<uint8_t*>(response); ++ uint8_t busId = (reqi2c->busId & 0xFF) >> 1; ++ // Convert the I2C address from 7-bit format ++ uint8_t i2cAddr = reqi2c->slaveAddr >> 1; ++ size_t writeCount = *data_len - sizeof(ipmiI2cRwReq); ++ ++ log<level::DEBUG>( ++ "INPUT: ", entry("LEN=%d", *data_len), entry("ID=0x%x", busId), ++ entry("ADDR=0x%x", reqi2c->slaveAddr), entry("R=%d", reqi2c->readCount), ++ entry("W=%d", writeCount)); ++ ++ *data_len = 0; ++ ++ std::vector<uint8_t> inBuf(reqi2c->readCount); ++ std::vector<uint8_t> outBuf(writeCount); ++ uint8_t* reqptr = reinterpret_cast<uint8_t*>(request); ++ ++ reqptr += sizeof(ipmiI2cRwReq); ++ std::copy(reqptr, reqptr + writeCount, outBuf.begin()); ++ ++ log<level::DEBUG>("checking list ", entry("SIZE=%d", getWhiteList().size())); ++ // command whitelist checking ++ for (unsigned int i = 0; i < getWhiteList().size(); i++) ++ { ++ // TODO add wildchard/regex support ++ if ((busId == getWhiteList()[i].busId) && ++ (i2cAddr == getWhiteList()[i].slaveAddr) && ++ (outBuf == getWhiteList()[i].data)) ++ { ++ log<level::DEBUG>("In whitelist"); ++ foundInList = true; ++ break; ++ } ++ } ++ ++ if (!foundInList) ++ { ++ log<level::ERR>("Request blocked!", entry("BUS=%d", busId), ++ entry("ADDR=0x%x", reqi2c->slaveAddr)); ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ log<level::DEBUG>("IPMI Master WriteRead ", entry("BUS=%d", busId), ++ entry("ADDR=0x%x", reqi2c->slaveAddr), ++ entry("R=%d", reqi2c->readCount), ++ entry("W=%d", writeCount)); ++ ++ std::string i2cBus = "/dev/i2c-" + std::to_string(busId); ++ ++ int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC); ++ if (i2cDev < 0) ++ { ++ log<level::ERR>("Failed in opening i2c device", ++ entry("BUS=%s", i2cBus.c_str())); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ // write message ++ i2cmsg[0].addr = i2cAddr; ++ i2cmsg[0].flags = 0x00; ++ i2cmsg[0].len = writeCount; ++ i2cmsg[0].buf = outBuf.data(); ++ ++ // read message ++ i2cmsg[1].addr = i2cAddr; ++ i2cmsg[1].flags = I2C_M_RD; ++ i2cmsg[1].len = reqi2c->readCount; ++ i2cmsg[1].buf = inBuf.data(); ++ ++ msgRdwr.msgs = i2cmsg; ++ msgRdwr.nmsgs = 2; ++ ++ ret = ::ioctl(i2cDev, I2C_RDWR, &msgRdwr); ++ ::close(i2cDev); ++ ++ // TODO add completion code support ++ if (ret < 0) ++ { ++ log<level::ERR>("RDWR ioctl error", entry("RET=%d", ret)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ *data_len = msgRdwr.msgs[1].len; ++ std::copy(msgRdwr.msgs[1].buf, msgRdwr.msgs[1].buf + msgRdwr.msgs[1].len, ++ resptr); ++ ++ return IPMI_CC_OK; ++} ++ + void register_netfn_app_functions() + { ++ int ret = -1; ++ + // <Get BT Interface Capabilities> + ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL, + ipmi_app_get_bt_capabilities, PRIVILEGE_USER); +@@ -1145,6 +1370,17 @@ void register_netfn_app_functions() + ipmi_app_channel_info, PRIVILEGE_USER); + #endif + ++ ret = loadI2CWhiteList(); ++ log<level::DEBUG>("i2c white list is loaded", entry("RET=%d", ret), ++ entry("SIZE=%d", getWhiteList().size())); ++ if (ret == 0) ++ { ++ log<level::DEBUG>("Register Master RW command"); ++ // <Master Write Read Command> ++ ipmi_register_callback(NETFUN_APP, IPMI_CMD_MASTER_WRITE_READ, NULL, ++ ipmiMasterWriteRead, PRIVILEGE_OPERATOR); ++ } ++ + // <Get System GUID Command> + ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL, + ipmi_app_get_sys_guid, PRIVILEGE_USER); +diff --git a/apphandler.hpp b/apphandler.hpp +index d4dd8e8..f9e5c59 100644 +--- a/apphandler.hpp ++++ b/apphandler.hpp +@@ -19,6 +19,7 @@ enum ipmi_netfn_app_cmds + IPMI_CMD_SET_CHAN_ACCESS = 0x40, + IPMI_CMD_GET_CHANNEL_ACCESS = 0x41, + IPMI_CMD_GET_CHAN_INFO = 0x42, ++ IPMI_CMD_MASTER_WRITE_READ = 0x52, + IPMI_CMD_GET_CHAN_CIPHER_SUITES = 0x54, + IPMI_CMD_SET_SYSTEM_INFO = 0x58, + IPMI_CMD_GET_SYSTEM_INFO = 0x59, +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index c7eb2d8..22a2a3c 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -25,6 +25,7 @@ + 0x06:0x36 //<App>:<Get BT Interface Capabilities> + 0x06:0x37 //<App>:<Get System GUID> + 0x06:0x42 //<App>:<Get Channel Info Command> ++0x06:0x52 //<App>:<Master Write Read Command> + 0x06:0x54 //<App>:<Get Channel Cipher Suites> + 0x0A:0x10 //<Storage>:<Get FRU Inventory Area Info> + 0x0A:0x11 //<Storage>:<Read FRU Data> +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch new file mode 100644 index 000000000..aba5eb095 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch @@ -0,0 +1,71 @@ +From 59287a8869b5253a1b4203e0cc8a92f063dcc7e6 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 25 Sep 2018 16:08:22 +0800 +Subject: [PATCH] Fix "Unspecified error" on ipmi restart cause command + +Needs to convert the dbus value(enum) into ipmi value(uint8) + +Tested by: +ipmitool chassis restart_cause + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 40eb4f5..c3d4931 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -106,7 +106,7 @@ static constexpr auto match = "chassis0"; + const static constexpr char* stateHostInterface = + "xyz.openbmc_project.State.Host"; + const static constexpr char* hostRestartCauseInterface = +- "xyz.openbmc_project.State.Host.HostRestartCause"; ++ "xyz.openbmc_project.State.Host"; + const static constexpr char* hostRestartCause = "HostRestartCause"; + const static constexpr char chassisCapIntf[] = + "xyz.openbmc_project.Control.ChassisCapabilities"; +@@ -1764,6 +1764,26 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return rc; + } + ++namespace restart_cause ++{ ++ ++using namespace sdbusplus::xyz::openbmc_project::State::server; ++ ++std::map<Host::RestartCause, uint8_t> dbusToIpmi = { ++ {Host::RestartCause::Unknown, 0x0}, ++ {Host::RestartCause::IpmiCommand, 0x1}, ++ {Host::RestartCause::ResetButton, 0x2}, ++ {Host::RestartCause::PowerButton, 0x3}, ++ {Host::RestartCause::WatchdogTimer, 0x4}, ++ {Host::RestartCause::OEM, 0x5}, ++ {Host::RestartCause::PowerPolicyAlwaysOn, 0x6}, ++ {Host::RestartCause::PowerPolicyPreviousState, 0x7}, ++ {Host::RestartCause::PEFReset, 0x8}, ++ {Host::RestartCause::PEFPowerCycle, 0x9}, ++ {Host::RestartCause::SoftReset, 0xa}, ++ {Host::RestartCause::RTCWakeup, 0xb}}; ++} // namespace restart_cause ++ + ipmi_ret_t ipmi_chassis_get_sys_restart_cause( + ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, + ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) +@@ -1787,7 +1807,11 @@ ipmi_ret_t ipmi_chassis_get_sys_restart_cause( + ipmi::Value variant = + ipmi::getDbusProperty(bus, hostObject.second, hostObject.first, + hostRestartCauseInterface, hostRestartCause); +- resp->restartCause = variant.get<uint8_t>(); ++ ++ std::string restartCause = ++ sdbusplus::message::variant_ns::get<std::string>(variant); ++ resp->restartCause = restart_cause::dbusToIpmi.at( ++ restart_cause::Host::convertRestartCauseFromString(restartCause)); + } + + catch (std::exception& e) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch new file mode 100644 index 000000000..b800632cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch @@ -0,0 +1,15 @@ +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 22a2a3c..5d71698 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -49,3 +49,10 @@ + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> + 0x30:0x31 //<OEM>:<Get AIC card FRU> ++0x30:0x54 //<OEM>:<Set Power Restore Delay> ++0x30:0x55 //<OEM>:<Get Power Restore Delay> ++0x30:0x9A //<OEM>:<Get Processor Error Config> ++0x30:0x9B //<OEM>:<Set Processor Error Config> ++0x30:0xB0 //<OEM>:<Get LED Status> ++0x30:0xE9 //<OEM>:<Get BIOS Post Codes> ++ diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch new file mode 100644 index 000000000..3990c6b5c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch @@ -0,0 +1,142 @@ +From cae9e21f88e6f12c80c89402473a17a10258c843 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Thu, 17 Jan 2019 21:22:30 +0530 +Subject: [PATCH] Fix: Set LAN Config to work without SetInProgress + +Set LAN Configuration parameters in up-stream code works +with SetInProgress (parameter selector 0), to be marked +as SET_IN_PROGRESS before fields update, and SET_COMPLETE to +make the changes effective. This is not mandatory as per +IPMI Spec, and we must support individual fields update. +Fix: +1. After SET_COMPLETE for parameter selector, changes has +to be applied immediately, and doesn't require to rely on +network timer, as purpose of this logic itself is to stage +and commit. +2. Allow individual parameter changes to take effect based +on timer. For the time being reduced the timer to 5 sec +to have quicker turn-around and group things together. + +TODO: +Still need to introduce lock between ChannelConfig variable +between Timer & Get / Set LAN Configuration command to avoid +race condition + +Unit-Test: +1. Verified the BIOS Setup page, able to set the IPV4 to static +IP, afte disabling IPV6, and configuring IPV4 to static, after +save and reset, the changes of IPV4 static is preserved. + +Change-Id: I7c2edad2861b5dba5ad1ca97cc5e39ac02871746 +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + transporthandler.cpp | 54 ++++++++++++++++++++++++++++++++++++---------------- + transporthandler.hpp | 2 ++ + 2 files changed, 40 insertions(+), 16 deletions(-) + +Index: phosphor-host-ipmid.clean/transporthandler.cpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/transporthandler.cpp ++++ phosphor-host-ipmid.clean/transporthandler.cpp +@@ -399,6 +399,41 @@ struct set_lan_t + uint8_t data[8]; // Per IPMI spec, not expecting more than this size + } __attribute__((packed)); + ++ipmi_ret_t checkAndUpdateNetwork(int channel) ++{ ++ auto channelConf = getChannelConfig(channel); ++ using namespace std::chrono_literals; ++ // time to wait before applying the network changes. ++ constexpr auto networkTimeout = 5000000us; // 5 sec ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE && ++ ((channelConf->flush == false) || ++ (channelConf->updateInProgress == true))) ++ { ++ channelConf->flush = true; ++ // used to indicate that network timer update is in progress. ++ channelConf->updateInProgress = true; ++ if (!networkTimer) ++ { ++ log<level::ERR>("Network timer is not instantiated"); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // start/restart the timer ++ // TODO: Need to implement locking mechansim between networkTimer & ++ // get/set to avoid race condition. ++ networkTimer->start(networkTimeout); ++ } ++ else if (channelConf->lan_set_in_progress == SET_COMPLETE && ++ channelConf->flush == true && ++ channelConf->updateInProgress == false) ++ { ++ // Apply the network changes immediately, if proper SET_IN_PROGRESS, ++ // followed by SET_COMPLETE is issued. ++ applyChanges(channel); ++ } ++ return IPMI_CC_OK; ++} ++ + ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -406,12 +441,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + ipmi_context_t context) + { + ipmi_ret_t rc = IPMI_CC_OK; +- +- using namespace std::chrono_literals; +- +- // time to wait before applying the network changes. +- constexpr auto networkTimeout = 10000000us; // 10 sec +- + char ipaddr[INET_ADDRSTRLEN]; + char netmask[INET_ADDRSTRLEN]; + char gateway[INET_ADDRSTRLEN]; +@@ -543,15 +572,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + entry("ADDRESS=%s", channelConf->ipaddr.c_str()), + entry("GATEWAY=%s", channelConf->gateway.c_str()), + entry("VLAN=%d", channelConf->vlanID)); +- +- if (!networkTimer) +- { +- log<level::ERR>("Network timer is not instantiated"); +- return IPMI_CC_UNSPECIFIED_ERROR; +- } +- +- // start/restart the timer +- networkTimer->start(networkTimeout); + } + else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress + { +@@ -680,8 +700,10 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + default: + { + rc = IPMI_CC_PARM_NOT_SUPPORTED; ++ return rc; + } + } ++ rc = checkAndUpdateNetwork(channel); + + return rc; + } +Index: phosphor-host-ipmid.clean/transporthandler.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/transporthandler.hpp ++++ phosphor-host-ipmid.clean/transporthandler.hpp +@@ -140,6 +140,7 @@ struct ChannelConfig_t + // vlan id is in 12 bits and the 16th bit is for enable mask. + uint32_t vlanID = ipmi::network::VLAN_ID_MASK; + uint8_t lan_set_in_progress = SET_COMPLETE; ++ uint8_t updateInProgress = false; + bool flush = false; + + // IPV6 parameters +@@ -165,6 +166,7 @@ struct ChannelConfig_t + vlanID = ipmi::network::VLAN_ID_MASK; + ipsrc = ipmi::network::IPOrigin::UNSPECIFIED; + lan_set_in_progress = SET_COMPLETE; ++ updateInProgress = false; + flush = false; + + // IPv6 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..2a4cc9bb1 --- /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,80 @@ +From 9ed3fd11047f8c360b7d808946939ef280813811 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 | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp +index 0a61e63..6e50684 100644 +--- a/host-cmd-manager.cpp ++++ b/host-cmd-manager.cpp +@@ -26,6 +26,8 @@ constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; + 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 = "/org/openbmc/HostIpmi/1"; ++constexpr const char* IPMI_INTERFACE = "org.openbmc.HostIpmi"; + + // For throwing exceptions + using namespace phosphor::logging; +@@ -107,6 +109,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 +@@ -116,9 +132,6 @@ void Manager::checkQueueAndAlertHost() + { + log<level::DEBUG>("Asserting SMS Attention"); + +- 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 +@@ -132,9 +145,8 @@ void Manager::checkQueueAndAlertHost() + return; + } + +- auto method = +- this->bus.new_method_call(host.c_str(), IPMI_PATH.c_str(), +- IPMI_INTERFACE.c_str(), "setAttention"); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "setAttention"); + auto reply = this->bus.call(method); + + if (reply.is_method_error()) +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch new file mode 100644 index 000000000..bf6f672cf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch @@ -0,0 +1,37 @@ +From 5d0c9d2217dbe369daffb8a92d7b5e7d7d34d566 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Sat, 2 Mar 2019 20:08:32 +0530 +Subject: [PATCH] Fix: User commands require channel layer lib + +As channel layer is separated out from user layer lib, it +has to be manually included in libusercommands, as user +command handlers use channel layer API's + +Tested-by: +1. Made sure that libusercommands are loaded on it's own +without any undefined symbol error. +2. ipmitool user list 1 works on host interface + +Change-Id: I6652ad248e01afc1349e3a9612754dbdb84b96ad +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index bb7bdbf..4e9101e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -120,7 +120,8 @@ libipmi20_la_CXXFLAGS = $(COMMON_CXX) + providers_LTLIBRARIES += libusercmds.la + libusercmds_la_LIBADD = \ + libipmid/libipmid.la \ +- user_channel/libuserlayer.la ++ user_channel/libuserlayer.la \ ++ user_channel/libchannellayer.la + libusercmds_la_SOURCES = \ + user_channel/usercommands.cpp + libusercmds_la_LDFLAGS = \ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch new file mode 100644 index 000000000..170e530f9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch @@ -0,0 +1,185 @@ +From b8b88a5c0f9e9cb6023cb8d5453e5cfadaa1a375 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 4 Jan 2019 10:50:21 +0800 +Subject: [PATCH] Implement set front panel button enables command + +Through modify buttons' property "Enabled" to disable/enable +corresponding button. +Currently support power and reset button. + +Test-By: ipmitool raw 0x0 0xa 0x2 //disable reset button + ipmitool raw 0x0 0xa 0x1 //disable power button + ipmitool raw 0x0 0xa 0x0 //enable all buttons + +Change-Id: Ice6f58edb898689f7a7fa08ad078d25fccaab27e +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + chassishandler.cpp | 98 +++++++++++++++++++++++++++++++++++++++ + chassishandler.hpp | 1 + + host-ipmid-whitelist.conf | 1 + + 3 files changed, 100 insertions(+) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 4b42b3c..1a5b805 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -112,6 +112,8 @@ const static constexpr char chassisSMDevAddrProp[] = "SMDeviceAddress"; + const static constexpr char chassisBridgeDevAddrProp[] = "BridgeDeviceAddress"; + static constexpr uint8_t chassisCapFlagMask = 0x0f; + static constexpr uint8_t chassisCapAddrMask = 0xfe; ++static constexpr uint8_t disableResetButton = 0x2; ++static constexpr uint8_t disablePowerButton = 0x1; + + typedef struct + { +@@ -140,6 +142,19 @@ struct GetPOHCountResponse + uint8_t counterReading[4]; ///< Counter reading + } __attribute__((packed)); + ++typedef struct ++{ ++ uint8_t disables; // Front Panel Button Enables ++ //[7:4] - reserved ++ //[3] - 1b = disable Standby (sleep) button for entering standby (sleep) ++ //(control can still be used to wake the system) ++ //[2] - 1b = disable Diagnostic Interrupt button ++ //[1] - 1b = disable Reset button ++ //[0] - 1b = disable Power off button for power off only (in the case there ++ // is a single combined power/standby (sleep) button, then this also ++ // disables sleep requests via that button) ++} __attribute__((packed)) IPMISetFrontPanelButtonEnablesReq; ++ + // Phosphor Host State manager + namespace State = sdbusplus::xyz::openbmc_project::State::server; + +@@ -948,6 +963,8 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // Front Panel Button Capabilities and disable/enable status(Optional) + // set to 0, for we don't support them. ++ // TODO, it is tracked by an issue: ++ // https://github.com/openbmc/phosphor-host-ipmid/issues/122 + chassis_status.front_panel_button_cap_status = 0; + + // Pack the actual response +@@ -1721,6 +1738,82 @@ ipmi_ret_t ipmi_chassis_set_power_restore_policy( + return IPMI_CC_OK; + } + ++ipmi_ret_t ipmiSetFrontPanelButtonEnables(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ++ ipmi_response_t response, ++ ipmi_data_len_t data_len, ++ ipmi_context_t context) ++{ ++ bool enable = false; ++ constexpr const char* powerButtonIntf = ++ "xyz.openbmc_project.Chassis.Buttons.Power"; ++ constexpr const char* powerButtonPath = ++ "/xyz/openbmc_project/Chassis/Buttons/Power0"; ++ constexpr const char* resetButtonIntf = ++ "xyz.openbmc_project.Chassis.Buttons.Reset"; ++ constexpr const char* resetButtonPath = ++ "/xyz/openbmc_project/Chassis/Buttons/Reset0"; ++ using namespace chassis::internal; ++ ++ IPMISetFrontPanelButtonEnablesReq* req = ++ static_cast<IPMISetFrontPanelButtonEnablesReq*>(request); ++ if (*data_len != 1) ++ { ++ *data_len = 0; ++ log<level::ERR>("IPMI request len is invalid"); ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ *data_len = 0; ++ if (req->disables & disablePowerButton) ++ { ++ // Disable power button ++ enable = false; ++ } ++ else ++ { ++ // Enable power button ++ enable = true; ++ } ++ // set power button Enabled property ++ try ++ { ++ auto service = ipmi::getService(dbus, powerButtonIntf, powerButtonPath); ++ ipmi::setDbusProperty(dbus, service, powerButtonPath, powerButtonIntf, ++ "Enabled", enable); ++ } ++ catch (sdbusplus::exception::SdBusError& e) ++ { ++ log<level::ERR>(e.what()); ++ log<level::ERR>("Fail to set power button Enabled property"); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ if (req->disables & disableResetButton) ++ { ++ // disable reset button ++ enable = false; ++ } ++ else ++ { ++ // enable reset button ++ enable = true; ++ } ++ // set reset button Enabled property ++ try ++ { ++ auto service = ipmi::getService(dbus, resetButtonIntf, resetButtonPath); ++ ipmi::setDbusProperty(dbus, service, resetButtonPath, resetButtonIntf, ++ "Enabled", enable); ++ } ++ catch (sdbusplus::exception::SdBusError& e) ++ { ++ log<level::ERR>(e.what()); ++ log<level::ERR>("Fail to set reset button Enabled property"); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ return IPMI_CC_OK; ++} ++ + void register_netfn_chassis_functions() + { + createIdentifyTimer(); +@@ -1733,6 +1826,11 @@ void register_netfn_chassis_functions() + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL, + ipmi_get_chassis_cap, PRIVILEGE_USER); + ++ // Set Front Panel Button Enables ++ ipmi_register_callback(NETFUN_CHASSIS, ++ IPMI_CMD_SET_FRONT_PANEL_BUTTON_ENABLES, NULL, ++ ipmiSetFrontPanelButtonEnables, PRIVILEGE_ADMIN); ++ + // Set Chassis Capabilities + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_CHASSIS_CAP, NULL, + ipmi_set_chassis_cap, PRIVILEGE_USER); +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 49b5ef8..f4a6bff 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -19,6 +19,7 @@ enum ipmi_netfn_chassis_cmds + // Get capability bits + IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08, + IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09, ++ IPMI_CMD_SET_FRONT_PANEL_BUTTON_ENABLES = 0x0A, + IPMI_CMD_GET_POH_COUNTER = 0x0F, + }; + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index e5cd0b5..d96d9ed 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -6,6 +6,7 @@ + 0x00:0x06 //<Chassis>:<Set Power Restore Policy> + 0x00:0x08 //<Chassis>:<Set System Boot Options> + 0x00:0x09 //<Chassis>:<Get System Boot Options> ++0x00:0x0A //<Chassis>:<Set Front Panel Button Enables> + 0x00:0x0F //<Chassis>:<Get POH Counter Command> + 0x04:0x2D //<Sensor/Event>:<Get Sensor Reading> + 0x04:0x2F //<Sensor/Event>:<Get Sensor Type> +-- +2.19.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch new file mode 100644 index 000000000..3a77887a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch @@ -0,0 +1,102 @@ +From 949db3a985719335d3df77db368eb2b296756749 Mon Sep 17 00:00:00 2001 +From: "Jia, chunhui" <chunhui.jia@linux.intel.com> +Date: Tue, 19 Mar 2019 16:09:06 +0800 +Subject: [PATCH] add SetInProgress to get/set boot option cmd + +It is required by BIOS. BIOS will check setinprogress first. +If this flag is not supported, BIOS will bypass all boot +option flow. + +Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f +Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com> +--- + chassishandler.cpp | 26 +++++++++++++++++++++++++- + chassishandler.hpp | 3 +++ + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 6d14d1b..553afa8 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1351,6 +1351,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + return IPMI_CC_OK; + } + ++static constexpr uint8_t setComplete = 0x0; ++static constexpr uint8_t setInProgress = 0x1; ++static uint8_t transferStatus = setComplete; ++ + ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -1365,11 +1369,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; + IpmiValue bootOption = ipmiDefault; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ *data_len = ++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS); ++ resp->version = SET_PARM_VERSION; ++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS); ++ resp->data[0] = transferStatus; ++ return IPMI_CC_OK; ++ } ++ + std::memset(resp, 0, sizeof(*resp)); + resp->version = SET_PARM_VERSION; + resp->parm = 5; + resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; +- + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +@@ -1505,6 +1519,16 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // This IPMI command does not have any resposne data + *data_len = 0; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ if (transferStatus == setInProgress) { ++ return IPMI_CC_FAIL_SET_IN_PROGRESS; ++ } ++ transferStatus = reqptr->data[0]; ++ return IPMI_CC_OK; ++ } ++ + /* 000101 + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 2c42b11..6a24507 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -28,6 +28,7 @@ enum ipmi_chassis_return_codes + { + IPMI_OK = 0x0, + IPMI_CC_PARM_NOT_SUPPORTED = 0x80, ++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81, + }; + + // Generic completion codes, +@@ -49,6 +50,7 @@ enum ipmi_chassis_control_cmds : uint8_t + }; + enum class BootOptionParameter : size_t + { ++ SET_IN_PROGRESS = 0x0, + BOOT_INFO = 0x4, + BOOT_FLAGS = 0x5, + OPAL_NETWORK_SETTINGS = 0x61 +@@ -56,6 +58,7 @@ enum class BootOptionParameter : size_t + + enum class BootOptionResponseSize : size_t + { ++ SET_IN_PROGRESS = 3, + BOOT_FLAGS = 5, + OPAL_NETWORK_SETTINGS = 50 + }; +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch new file mode 100644 index 000000000..5813cceae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch @@ -0,0 +1,195 @@ +From 6e37e02a4f200507627a82f6dba00a9c9d877cb2 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 18 Mar 2019 23:05:16 +0800 +Subject: [PATCH] Add timer use/actions support + +Based on IPMI spec, add timer use/actions support, +and add input data checking + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + app/watchdog.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++----- + app/watchdog_service.cpp | 8 +++++++ + app/watchdog_service.hpp | 8 +++++++ + 3 files changed, 72 insertions(+), 6 deletions(-) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 1a5d19c..3b61055 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -89,6 +89,13 @@ static constexpr uint8_t wd_dont_stop = 0x1 << 6; + static constexpr uint8_t wd_timeout_action_mask = 0x3; + + static constexpr uint8_t wdTimerUseMask = 0x7; ++static constexpr uint8_t wdTimerUseResTimer1 = 0x0; ++static constexpr uint8_t wdTimerUseResTimer2 = 0x6; ++static constexpr uint8_t wdTimerUseResTimer3 = 0x7; ++static constexpr uint8_t wdTimerUseRes = 0x38; ++ ++static constexpr uint8_t wdTimerActionMask = 0xcc; ++static constexpr uint8_t wdTimerUseExpMask = 0xc1; + + enum class IpmiAction : uint8_t + { +@@ -186,6 +193,11 @@ static_assert(sizeof(wd_set_req) == 6, "wd_set_req has invalid size."); + static_assert(sizeof(wd_set_req) <= MAX_IPMI_BUFFER, + "wd_get_res can't fit in request buffer."); + ++static uint8_t timerLogFlags = 0; ++static uint8_t timerActions = 0; ++ ++static uint8_t timerUseExpirationFlags = 0; ++ + ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -203,6 +215,24 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + req.initial_countdown = le16toh(req.initial_countdown); + *data_len = 0; + ++ if (((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer1) || ++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer2) || ++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer3) || ++ (req.timer_use & wdTimerUseRes) || ++ (req.timer_action & wdTimerActionMask) || ++ (req.expire_flags & wdTimerUseExpMask)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ if (req.pretimeout > (req.initial_countdown / 10)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ timerLogFlags = req.timer_use & 0x80; ++ timerActions = req.timer_action; ++ + try + { + WatchdogService wd_service; +@@ -221,6 +251,10 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + static_cast<IpmiTimerUse>(req.timer_use & wdTimerUseMask); + wd_service.setTimerUse(ipmiTimerUseToWdTimerUse(ipmiTimerUse)); + ++ wd_service.setExpiredTimerUse(WatchdogService::TimerUse::Reserved); ++ ++ timerUseExpirationFlags &= ~req.expire_flags; ++ + // Set the new interval and the time remaining deci -> mill seconds + const uint64_t interval = req.initial_countdown * 100; + wd_service.setInterval(interval); +@@ -339,7 +373,6 @@ static_assert(sizeof(wd_get_res) == 8, "wd_get_res has invalid size."); + static_assert(sizeof(wd_get_res) <= MAX_IPMI_BUFFER, + "wd_get_res can't fit in response buffer."); + +-static constexpr uint8_t wd_dont_log = 0x1 << 7; + static constexpr uint8_t wd_running = 0x1 << 6; + + ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, +@@ -358,20 +391,37 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // Build and return the response + wd_get_res res; +- res.timer_use = wd_dont_log; +- res.timer_action = +- static_cast<uint8_t>(wdActionToIpmiAction(wd_prop.expireAction)); ++ res.timer_use |= timerLogFlags; ++ res.timer_action = timerActions; + + // Interval and timeRemaining need converted from milli -> deci seconds + res.initial_countdown = htole16(wd_prop.interval / 100); ++ ++ if (wd_prop.expiredTimerUse != WatchdogService::TimerUse::Reserved) ++ { ++ timerUseExpirationFlags |= ++ 1 << static_cast<uint8_t>( ++ wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)); ++ } ++ + if (wd_prop.enabled) + { + res.timer_use |= wd_running; + res.present_countdown = htole16(wd_prop.timeRemaining / 100); ++ res.expire_flags = 0; + } + else + { +- res.present_countdown = res.initial_countdown; ++ if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved) ++ { ++ res.present_countdown = res.initial_countdown; ++ res.expire_flags = 0; ++ } ++ else ++ { ++ res.present_countdown = 0; ++ res.expire_flags = timerUseExpirationFlags; ++ } + } + + res.timer_use |= +@@ -379,7 +429,7 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // TODO: Do something about having pretimeout support + res.pretimeout = 0; +- res.expire_flags = 0; ++ + memcpy(response, &res, sizeof(res)); + *data_len = sizeof(res); + lastCallSuccessful = true; +diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp +index e65ea63..8b1aa47 100644 +--- a/app/watchdog_service.cpp ++++ b/app/watchdog_service.cpp +@@ -83,6 +83,9 @@ WatchdogService::Properties WatchdogService::getProperties() + wd_prop.timerUse = Watchdog::convertTimerUseFromString( + get<std::string>(properties.at("CurrentTimerUse"))); + ++ wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString( ++ get<std::string>(properties.at("ExpiredTimerUse"))); ++ + wd_prop.interval = get<uint64_t>(properties.at("Interval")); + wd_prop.timeRemaining = get<uint64_t>(properties.at("TimeRemaining")); + return wd_prop; +@@ -187,6 +190,11 @@ void WatchdogService::setTimerUse(TimerUse timerUse) + setProperty("CurrentTimerUse", convertForMessage(timerUse)); + } + ++void WatchdogService::setExpiredTimerUse(TimerUse timerUse) ++{ ++ setProperty("ExpiredTimerUse", convertForMessage(timerUse)); ++} ++ + void WatchdogService::setInterval(uint64_t interval) + { + setProperty("Interval", interval); +diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp +index 75afc1e..d0cc1a8 100644 +--- a/app/watchdog_service.hpp ++++ b/app/watchdog_service.hpp +@@ -36,6 +36,7 @@ class WatchdogService + bool enabled; + Action expireAction; + TimerUse timerUse; ++ TimerUse expiredTimerUse; + uint64_t interval; + uint64_t timeRemaining; + }; +@@ -79,6 +80,13 @@ class WatchdogService + */ + void setTimerUse(TimerUse timerUse); + ++ /** @brief Sets the value of the ExpiredTimerUse property on the host ++ * watchdog ++ * ++ * @param[in] timerUse - The new timerUse value ++ */ ++ void setExpiredTimerUse(TimerUse timerUse); ++ + /** @brief Sets the value of the interval property on the host watchdog + * + * @param[in] interval - The new interval value +-- +2.7.4 + 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..d855eaa5b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service @@ -0,0 +1,26 @@ +[Unit] +Description=Phosphor Inband IPMI +# TODO openbmc/openbmc#2059 - The wants/after below should be based on providers +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +After=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-restriction_mode.service +After=mapper-wait@-xyz-openbmc_project-control-host0-restriction_mode.service +Wants=clear-once.service +After=clear-once.service + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env ipmid +SyslogIdentifier=ipmid +RuntimeDirectory = ipmi +RuntimeDirectoryPreserve = yes +StateDirectory = ipmi + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} 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..2d47fdfff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -0,0 +1,37 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# TODO: This should be removed, once up-stream bump up +# issue is resolved +#SRC_URI = "git://github.com/openbmc/phosphor-host-ipmid" +SRCREV = "55768e3548ef7476d4fdbe7be7a3ddb4d4896f14" + +SRC_URI += "file://phosphor-ipmi-host.service \ + file://0002-Modify-dbus-interface-for-power-control.patch \ + file://0003-Modify-dbus-interface-for-chassis-control.patch \ + file://0009-IPv6-Network-changes.patch \ + file://0010-fix-get-system-GUID-ipmi-command.patch \ + file://0012-ipmi-set-get-boot-options.patch \ + file://0013-ipmi-add-set-bios-id-to-whitelist.patch \ + file://0014-Enable-get-device-guid-ipmi-command.patch \ + file://0016-add-better-sdbusplus-exception-handling.patch \ + file://0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch \ + file://0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch \ + file://0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch \ + file://0048-Implement-IPMI-Master-Write-Read-command.patch \ + file://0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch \ + file://0050-enable-6-oem-commands.patch \ + file://0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch \ + file://0053-Fix-keep-looping-issue-when-entering-OS.patch \ + file://0055-Implement-set-front-panel-button-enables-command.patch \ + file://0056-add-SetInProgress-to-get-set-boot-option-cmd.patch \ + file://0057-Add-timer-use-actions-support.patch \ + " + +do_install_append(){ + install -d ${D}${includedir}/phosphor-ipmi-host + install -d ${D}${libdir}/phosphor-ipmi-host + install -m 0644 -D ${S}/*.h ${D}${includedir}/phosphor-ipmi-host + install -m 0644 -D ${S}/*.hpp ${D}${includedir}/phosphor-ipmi-host + install -m 0644 -D ${S}/utils.cpp ${D}${libdir}/phosphor-ipmi-host + +} 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..d5d38a0ce --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend @@ -0,0 +1,2 @@ +SRC_URI = "git://github.com/openbmc/ipmbbridge.git" +SRCREV = "25e85c79257723b1cb754c20299196685373ce24" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service new file mode 100644 index 000000000..288fa422d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service @@ -0,0 +1,13 @@ +[Unit] +Description=Phosphor IPMI KCS DBus Bridge(SMM) +After=phosphor-ipmi-host.service + +[Service] +Restart=always +ExecStart={sbindir}/kcsbridged --d="/dev/ipmi-kcs4" --i="SMM" +SyslogIdentifier=kcsbridged_SMM +Type=dbus +BusName={BUSNAME} + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service new file mode 100644 index 000000000..177062e27 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service @@ -0,0 +1,13 @@ +[Unit] +Description=Phosphor IPMI KCS DBus Bridge(SMS) +After=phosphor-ipmi-host.service + +[Service] +Restart=always +ExecStart={sbindir}/kcsbridged --d="/dev/ipmi-kcs3" +SyslogIdentifier=kcsbridged +Type=dbus +BusName={BUSNAME} + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} 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..ac7a03108 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DBUS_SERVICE_${PN} += "org.openbmc.HostIpmi.SMM.service" + +SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}" + +SRC_URI = "git://github.com/openbmc/kcsbridge.git" +SRCREV = "17a2ab7f39a78ff0603aa68cf35108ea94eb442f" + 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..7225c7529 --- /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/0007-Adding-support-for-GetSessionInfo-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0007-Adding-support-for-GetSessionInfo-command.patch new file mode 100644 index 000000000..fda7ed2ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0007-Adding-support-for-GetSessionInfo-command.patch @@ -0,0 +1,421 @@ +From f5c7d30be4a097998d9390614c0faa2d77109ca5 Mon Sep 17 00:00:00 2001 +From: ssekar <suryakanth.sekar@linux.intel.com> +Date: Wed, 12 Dec 2018 16:04:15 +0530 +Subject: [PATCH] Adding support for GetSessionInfo command + +Description: user can get all session info (remote ip,port, +session id, priv, etc) using this command. + +Verification :we can get all active and non active session +info by session handle session id. +Updated the Remote IP addr and Port update for sessioninfo. +Unit testing are done. + +Change-Id: I662ef2b9f0c1d6bda331eb6481d7b9f34534541b +Signed-off-by: ssekar <suryakanth.sekar@linux.intel.com> +--- + comm_module.cpp | 8 +++ + command/session_cmds.cpp | 147 +++++++++++++++++++++++++++++++++++++++ + command/session_cmds.hpp | 55 +++++++++++++++ + message_handler.cpp | 1 + + sessions_manager.cpp | 55 +++++++++++++++ + sessions_manager.hpp | 7 ++ + socket_channel.cpp | 27 ++++++- + socket_channel.hpp | 3 +- + 8 files changed, 301 insertions(+), 2 deletions(-) + +Index: phosphor-net-ipmid.clean/comm_module.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/comm_module.cpp ++++ phosphor-net-ipmid.clean/comm_module.cpp +@@ -53,6 +53,14 @@ void sessionSetupCommands() + &closeSession, + session::Privilege::CALLBACK, + false}, ++ // Session Info Command ++ { ++ { ++ (static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | ++ static_cast<uint16_t>(command::NetFns::APP) | 0x3D ++ }, ++ &getSessionInfo, session::Privilege::USER, false ++ }, + }; + + for (auto& iter : commands) +Index: phosphor-net-ipmid.clean/command/session_cmds.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/command/session_cmds.cpp ++++ phosphor-net-ipmid.clean/command/session_cmds.cpp +@@ -5,11 +5,19 @@ + + #include <host-ipmid/ipmid-api.h> + ++#include <iostream> + #include <user_channel/channel_layer.hpp> + #include <user_channel/user_layer.hpp> + + namespace command + { ++// Defined as per IPMI sepcification ++static constexpr uint8_t searchCurrentSession = 0x00; ++static constexpr uint8_t searchSessionByHandle = 0xFE; ++static constexpr uint8_t searchSessionByID = 0xFF; ++ ++static constexpr uint8_t ipmi15VerSession = 0x00; ++static constexpr uint8_t ipmi20VerSession = 0x01; + + std::vector<uint8_t> + setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload, +@@ -110,4 +118,143 @@ std::vector<uint8_t> closeSession(const + return outPayload; + } + ++std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, ++ const message::Handler& handler) ++ ++{ ++ std::vector<uint8_t> outPayload(sizeof(GetSessionInfoResponse)); ++ auto request = ++ reinterpret_cast<const GetSessionInfoRequest*>(inPayload.data()); ++ auto response = ++ reinterpret_cast<GetSessionInfoResponse*>(outPayload.data()); ++ uint32_t reqSessionID = handler.sessionID; ++ response->completionCode = IPMI_CC_OK; ++ if (inPayload.size() == 1 && request->sessionIndex != 0) ++ { ++ if (request->sessionIndex <= session::MAX_SESSION_COUNT) ++ { ++ reqSessionID = std::get<session::Manager&>(singletonPool) ++ .getSessionIDbyHandle(request->sessionIndex); ++ } ++ else ++ { ++ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ } ++ ++ // Here we look for session info according to session index parameter ++ switch (request->sessionIndex) ++ { ++ // Look for current active session which this cmd is received over ++ case searchCurrentSession: ++ // Request data should only contain session index byte ++ if (inPayload.size() != 1) ++ { ++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ // To look for current active session which the command came over, ++ // the session ID cannot be 0. ++ if (0 == reqSessionID) ++ { ++ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ break; ++ case searchSessionByHandle: ++ // Request data should only contain session index byte and Session ++ // handle ++ if (inPayload.size() != 2) ++ { ++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ ++ // Retrieve session id based on session handle ++ if (request->sessionHandle <= session::MAX_SESSION_COUNT) ++ { ++ reqSessionID = ++ std::get<session::Manager&>(singletonPool) ++ .getSessionIDbyHandle(request->sessionHandle); ++ } ++ else ++ { ++ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ break; ++ case searchSessionByID: ++ // Request data should only contain session index byte and Session ++ // handle ++ if (inPayload.size() != sizeof(GetSessionInfoRequest)) ++ { ++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ reqSessionID = endian::from_ipmi(request->sessionID); ++ ++ break; ++ default: ++ if (inPayload.size() != 1) ++ { ++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ } ++ ++ response->totalSessionCount = session::MAX_SESSION_COUNT; ++ response->activeSessioncount = ++ std::get<session::Manager&>(singletonPool).getNoOfActiveSession(); ++ response->sessionHandle = 0; ++ if (reqSessionID != 0) ++ { ++ ++ std::shared_ptr<session::Session> sessionInfo; ++ try ++ { ++ sessionInfo = std::get<session::Manager&>(singletonPool) ++ .getSession(reqSessionID); ++ } ++ catch (std::exception& e) ++ { ++ response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ response->sessionHandle = std::get<session::Manager&>(singletonPool) ++ .getSessionHandle(reqSessionID); ++ uint8_t userId = ipmi::ipmiUserGetUserId(sessionInfo->userName); ++ if (userId == ipmi::invalidUserId) ++ { ++ response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; ++ outPayload.resize(sizeof(response->completionCode)); ++ return std::move(outPayload); ++ } ++ response->userID = userId; // userId; ++ response->privLevel = static_cast<uint8_t>(sessionInfo->curPrivLevel); ++ response->chanNum = sessionInfo->chNum; // byte7 3:0 ++ response->ipmiVer = ipmi20VerSession; // byte7 7:4 ++ response->remoteIpAddr = ++ sessionInfo->channelPtr->getRemoteAddressInbytes(); ++ response->remotePort = ++ sessionInfo->channelPtr->getPort(); // remoteSessionPort; ++ ++ std::cerr << "\nSessionInfo:" << (int)reqSessionID; ++ // TODO: Filling the Remote MACAddress ++ } ++ else ++ { ++ outPayload.resize(4); ++ } ++ return std::move(outPayload); ++} ++ + } // namespace command +Index: phosphor-net-ipmid.clean/command/session_cmds.hpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/command/session_cmds.hpp ++++ phosphor-net-ipmid.clean/command/session_cmds.hpp +@@ -116,4 +116,59 @@ struct CloseSessionResponse + std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload, + const message::Handler& handler); + ++/** ++ * @struct GetSessionInfoRequest ++ * ++ * IPMI Request data for getSession info command ++ */ ++struct GetSessionInfoRequest ++{ ++ uint8_t sessionIndex; ++ union ++ { ++ uint8_t sessionHandle; ++ uint32_t sessionID; ++ }; ++} __attribute__((packed)); ++ ++/** ++ * @struct getSessionInfoResponse ++ * ++ * IPMI Response data for getSession info command ++ */ ++struct GetSessionInfoResponse ++{ ++ uint8_t completionCode; ++ uint8_t sessionHandle; ++ uint8_t totalSessionCount; ++ uint8_t activeSessioncount; ++ uint8_t userID; ++ uint8_t privLevel; ++#if BYTE_ORDER == LITTLE_ENDIAN ++ uint8_t chanNum : 4; ++ uint8_t ipmiVer : 4; ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ uint8_t ipmiVer : 4; ++ uint8_t chanNum : 4; ++#endif ++ uint32_t remoteIpAddr; // for channel private data ++ uint8_t remoteMACAddr[6]; ++ uint16_t remotePort; ++} __attribute__((packed)); ++ ++/** ++ * @brief GetSessionInfo Command ++ * ++ * This command is used to get the session information based on ++ * session handle or session ID. Retreive all session information. ++ ++ * @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> getSessionInfo(const std::vector<uint8_t>& inPayload, ++ const message::Handler& handler); ++ + } // namespace command +Index: phosphor-net-ipmid.clean/message_handler.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/message_handler.cpp ++++ phosphor-net-ipmid.clean/message_handler.cpp +@@ -43,6 +43,7 @@ std::shared_ptr<Message> Handler::receiv + sessionID = message->bmcSessionID; + message->rcSessionID = session->getRCSessionID(); + session->updateLastTransactionTime(); ++ session->channelPtr = channel; + + return message; + } +Index: phosphor-net-ipmid.clean/sessions_manager.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/sessions_manager.cpp ++++ phosphor-net-ipmid.clean/sessions_manager.cpp +@@ -88,6 +88,9 @@ std::shared_ptr<Session> + } + sessionID = session->getBMCSessionID(); + sessionsMap.emplace(sessionID, session); ++ storeSessionHandle(sessionID); ++ ++ + return session; + } + +@@ -149,12 +152,15 @@ std::shared_ptr<Session> Manager::getSes + + void Manager::cleanStaleEntries() + { ++ uint8_t sessionIndex = 0; + for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();) + { + auto session = iter->second; + if ((session->getBMCSessionID() != SESSION_ZERO) && + !(session->isSessionActive())) + { ++ sessionIndex = getSessionHandle(session->getBMCSessionID()); ++ sessionHandleMap[sessionIndex] = 0; + iter = sessionsMap.erase(iter); + } + else +@@ -164,4 +170,53 @@ void Manager::cleanStaleEntries() + } + } + ++uint8_t Manager::storeSessionHandle(SessionID bmcSessionID) ++{ ++ // Zero handler is reserved for invalid session. ++ //index starts with 1, for direct usage. Index 0 reserved ++ for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++) ++ { ++ if (sessionHandleMap[i] == 0) ++ { ++ sessionHandleMap[i] = bmcSessionID; ++ break; ++ } ++ } ++ return 0; ++} ++ ++uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const ++{ ++ if (sessionHandle <= MAX_SESSION_COUNT) ++ { ++ return sessionHandleMap[sessionHandle]; ++ } ++ return 0; ++} ++ ++uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const ++{ ++ ++ for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++) ++ { ++ if (sessionHandleMap[i] == bmcSessionID) ++ { ++ return i; ++ } ++ } ++ return 0; ++} ++uint8_t Manager::getNoOfActiveSession() const ++{ ++ uint8_t count = 0; ++ for (const auto& it : sessionsMap) ++ { ++ const auto& session = it.second; ++ if (session->state == State::ACTIVE) ++ { ++ count++; ++ } ++ } ++ return count; ++} + } // namespace session +Index: phosphor-net-ipmid.clean/sessions_manager.hpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/sessions_manager.hpp ++++ phosphor-net-ipmid.clean/sessions_manager.hpp +@@ -82,8 +82,15 @@ class Manager + std::shared_ptr<Session> + getSession(SessionID sessionID, + RetrieveOption option = RetrieveOption::BMC_SESSION_ID); ++ uint8_t getNoOfActiveSession() const; ++ uint8_t getSessionHandle(SessionID bmcSessionID) const; ++ uint8_t storeSessionHandle(SessionID bmcSessionID); ++ uint32_t getSessionIDbyHandle(uint8_t sessionHandle) const; + + private: ++ //+1 for session, as 0 is reserved for sessionless command ++ std::array<uint32_t, MAX_SESSION_COUNT + 1> sessionHandleMap; ++ + /** + * @brief Session Manager keeps the session objects as a sorted + * associative container with Session ID as the unique key +Index: phosphor-net-ipmid.clean/socket_channel.hpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/socket_channel.hpp ++++ phosphor-net-ipmid.clean/socket_channel.hpp +@@ -65,6 +65,23 @@ class Channel + } + + /** ++ * @brief Return the binary representation of the remote IPv4 address ++ * ++ * getSessionInfo needs to return the remote IPv4 addresses of each session ++ * ++ * @return A uint32_t representation of the remote IPv4 address ++ */ ++ std::uint32_t getRemoteAddressInbytes() ++ { ++ const boost::asio::ip::address& addr = endpoint.address(); ++ if (addr.is_v4()) ++ { ++ return addr.to_v4().to_uint(); ++ } ++ return 0; ++ } ++ ++ /** + * @brief Read the incoming packet + * + * Reads the data available on the socket diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch new file mode 100644 index 000000000..1a109a571 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch @@ -0,0 +1,318 @@ +From 0ecc7c816ad4836f8f54922ba92cb527f5978d5a Mon Sep 17 00:00:00 2001 +From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +Date: Wed, 6 Mar 2019 10:35:56 +0530 +Subject: [PATCH] Sync GetSession Info cmd based on Upstream review + +Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +--- + comm_module.cpp | 12 ++++---- + command/session_cmds.cpp | 72 +++++++++++++++++++++--------------------------- + sessions_manager.cpp | 10 +++---- + sessions_manager.hpp | 2 +- + socket_channel.hpp | 33 +++++++++++----------- + 5 files changed, 59 insertions(+), 70 deletions(-) + +diff --git a/comm_module.cpp b/comm_module.cpp +index 7a1a17d..2546583 100644 +--- a/comm_module.cpp ++++ b/comm_module.cpp +@@ -54,13 +54,11 @@ void sessionSetupCommands() + session::Privilege::CALLBACK, + false}, + // Session Info Command +- { +- { +- (static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(command::NetFns::APP) | 0x3D +- }, +- &getSessionInfo, session::Privilege::USER, false +- }, ++ {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | ++ static_cast<uint16_t>(command::NetFns::APP) | 0x3D}, ++ &getSessionInfo, ++ session::Privilege::USER, ++ false}, + }; + + for (auto& iter : commands) +diff --git a/command/session_cmds.cpp b/command/session_cmds.cpp +index 7563b18..fc996a4 100644 +--- a/command/session_cmds.cpp ++++ b/command/session_cmds.cpp +@@ -5,13 +5,12 @@ + + #include <ipmid/api.h> + +-#include <iostream> + #include <user_channel/channel_layer.hpp> + #include <user_channel/user_layer.hpp> + + namespace command + { +-// Defined as per IPMI sepcification ++// Defined as per IPMI specification + static constexpr uint8_t searchCurrentSession = 0x00; + static constexpr uint8_t searchSessionByHandle = 0xFE; + static constexpr uint8_t searchSessionByID = 0xFF; +@@ -129,20 +128,6 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, + reinterpret_cast<GetSessionInfoResponse*>(outPayload.data()); + uint32_t reqSessionID = handler.sessionID; + response->completionCode = IPMI_CC_OK; +- if (inPayload.size() == 1 && request->sessionIndex != 0) +- { +- if (request->sessionIndex <= session::MAX_SESSION_COUNT) +- { +- reqSessionID = std::get<session::Manager&>(singletonPool) +- .getSessionIDbyHandle(request->sessionIndex); +- } +- else +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); +- } +- } + + // Here we look for session info according to session index parameter + switch (request->sessionIndex) +@@ -150,29 +135,22 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, + // Look for current active session which this cmd is received over + case searchCurrentSession: + // Request data should only contain session index byte +- if (inPayload.size() != 1) ++ if (inPayload.size() != sizeof(request->sessionIndex)) + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); +- } +- // To look for current active session which the command came over, +- // the session ID cannot be 0. +- if (0 == reqSessionID) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + break; + case searchSessionByHandle: + // Request data should only contain session index byte and Session + // handle +- if (inPayload.size() != 2) ++ if (inPayload.size() != (sizeof(request->sessionIndex) + ++ sizeof(request->sessionHandle))) + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + + // Retrieve session id based on session handle +@@ -186,7 +164,7 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, + { + response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + break; + case searchSessionByID: +@@ -196,23 +174,38 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + reqSessionID = endian::from_ipmi(request->sessionID); + + break; + default: +- if (inPayload.size() != 1) ++ if (inPayload.size() == sizeof(request->sessionIndex)) ++ { ++ if (request->sessionIndex <= session::MAX_SESSION_COUNT) ++ { ++ reqSessionID = ++ std::get<session::Manager&>(singletonPool) ++ .getSessionIDbyHandle(request->sessionIndex); ++ } ++ else ++ { ++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; ++ outPayload.resize(sizeof(response->completionCode)); ++ return outPayload; ++ } ++ } ++ else + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + } + + response->totalSessionCount = session::MAX_SESSION_COUNT; + response->activeSessioncount = +- std::get<session::Manager&>(singletonPool).getNoOfActiveSession(); ++ std::get<session::Manager&>(singletonPool).getActiveSessionCount(); + response->sessionHandle = 0; + if (reqSessionID != 0) + { +@@ -225,9 +218,9 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, + } + catch (std::exception& e) + { +- response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; ++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + response->sessionHandle = std::get<session::Manager&>(singletonPool) + .getSessionHandle(reqSessionID); +@@ -236,25 +229,24 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload, + { + response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; + outPayload.resize(sizeof(response->completionCode)); +- return std::move(outPayload); ++ return outPayload; + } + response->userID = userId; // userId; + response->privLevel = static_cast<uint8_t>(sessionInfo->curPrivLevel); + response->chanNum = sessionInfo->chNum; // byte7 3:0 + response->ipmiVer = ipmi20VerSession; // byte7 7:4 +- response->remoteIpAddr = +- sessionInfo->channelPtr->getRemoteAddressInbytes(); + response->remotePort = + sessionInfo->channelPtr->getPort(); // remoteSessionPort; ++ response->remoteIpAddr = ++ sessionInfo->channelPtr->getRemoteAddressInBytes(); + +- std::cerr << "\nSessionInfo:" << (int)reqSessionID; + // TODO: Filling the Remote MACAddress + } + else + { + outPayload.resize(4); + } +- return std::move(outPayload); ++ return outPayload; + } + + } // namespace command +diff --git a/sessions_manager.cpp b/sessions_manager.cpp +index 9f3210b..c6897c6 100644 +--- a/sessions_manager.cpp ++++ b/sessions_manager.cpp +@@ -152,15 +152,13 @@ std::shared_ptr<Session> Manager::getSession(SessionID sessionID, + + void Manager::cleanStaleEntries() + { +- uint8_t sessionIndex = 0; + for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();) + { + auto session = iter->second; + if ((session->getBMCSessionID() != SESSION_ZERO) && + !(session->isSessionActive())) + { +- sessionIndex = getSessionHandle(session->getBMCSessionID()); +- sessionHandleMap[sessionIndex] = 0; ++ sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0; + iter = sessionsMap.erase(iter); + } + else +@@ -172,8 +170,8 @@ void Manager::cleanStaleEntries() + + uint8_t Manager::storeSessionHandle(SessionID bmcSessionID) + { +- // Zero handler is reserved for invalid session. +- //index starts with 1, for direct usage. Index 0 reserved ++ // Handler index 0 is reserved for invalid session. ++ // index starts with 1, for direct usage. Index 0 reserved + for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++) + { + if (sessionHandleMap[i] == 0) +@@ -206,7 +204,7 @@ uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const + } + return 0; + } +-uint8_t Manager::getNoOfActiveSession() const ++uint8_t Manager::getActiveSessionCount() const + { + uint8_t count = 0; + for (const auto& it : sessionsMap) +diff --git a/sessions_manager.hpp b/sessions_manager.hpp +index c4caad4..3a3825d 100644 +--- a/sessions_manager.hpp ++++ b/sessions_manager.hpp +@@ -82,7 +82,7 @@ class Manager + std::shared_ptr<Session> + getSession(SessionID sessionID, + RetrieveOption option = RetrieveOption::BMC_SESSION_ID); +- uint8_t getNoOfActiveSession() const; ++ uint8_t getActiveSessionCount() const; + uint8_t getSessionHandle(SessionID bmcSessionID) const; + uint8_t storeSessionHandle(SessionID bmcSessionID); + uint32_t getSessionIDbyHandle(uint8_t sessionHandle) const; +diff --git a/socket_channel.hpp b/socket_channel.hpp +index 349701e..8b64740 100644 +--- a/socket_channel.hpp ++++ b/socket_channel.hpp +@@ -52,33 +52,34 @@ class Channel + } + + /** +- * @brief Fetch the port number of the remote peer +- * +- * Returns the port number of the remote peer ++ * @brief Fetch the IP address of the remote peer + * +- * @return Port number ++ * Returns the IP address of the remote peer which is connected to this ++ * socket + * ++ * @return IP address of the remote peer + */ +- auto getPort() const ++ std::uint32_t getRemoteAddressInBytes() const + { +- return endpoint.port(); ++ const boost::asio::ip::address& addr = endpoint.address(); ++ if (addr.is_v4()) ++ { ++ return addr.to_v4().to_uint(); ++ } ++ return 0; + } + + /** +- * @brief Return the binary representation of the remote IPv4 address ++ * @brief Fetch the port number of the remote peer + * +- * getSessionInfo needs to return the remote IPv4 addresses of each session ++ * Returns the port number of the remote peer ++ * ++ * @return Port number + * +- * @return A uint32_t representation of the remote IPv4 address + */ +- std::uint32_t getRemoteAddressInbytes() ++ auto getPort() const + { +- const boost::asio::ip::address& addr = endpoint.address(); +- if (addr.is_v4()) +- { +- return addr.to_v4().to_uint(); +- } +- return 0; ++ return endpoint.port(); + } + + /** +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch new file mode 100644 index 000000000..771120120 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch @@ -0,0 +1,311 @@ +From 6b9aaf0304aed06e4b5ac53e7c163089568d4171 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Sat, 23 Mar 2019 04:03:07 +0800 +Subject: [PATCH] Add dbus interface for sol commands + +Add dbus interface for sol config parameters so that after move set/get +sol config parameter command from net-ipmid to host-ipmid, the command +can send config parameters to net-ipmid sol service through the dbus +interface. + +Tested by: +busctl introspect xyz.openbmc_project.Settings /xyz/openbmc_project +/network/host0/sol can show correct dbus properties of sol parameters. +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x83 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +all these commands can change the dbus properties as the value in +above commands. +Before and after run these commands, ipmitool -I lanplus -H x -U x +-P x sol activate can start sol session correctly. +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> +--- + command/payload_cmds.cpp | 1 + + command/sol_cmds.cpp | 84 --------------------------------- + sol/sol_manager.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++ + sol/sol_manager.hpp | 1 + + sol_module.cpp | 6 --- + 5 files changed, 121 insertions(+), 90 deletions(-) + +diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp +index 3b5b4f8..570cdff 100644 +--- a/command/payload_cmds.cpp ++++ b/command/payload_cmds.cpp +@@ -34,6 +34,7 @@ std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload, + return outPayload; + } + ++ std::get<sol::Manager&>(singletonPool).updateSOLParameter(); + if (!std::get<sol::Manager&>(singletonPool).enable) + { + response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; +diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp +index a8fa410..804b5ea 100644 +--- a/command/sol_cmds.cpp ++++ b/command/sol_cmds.cpp +@@ -65,90 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) + outPayload); + } + +-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler) +-{ +- std::vector<uint8_t> outPayload(sizeof(SetConfParamsResponse)); +- auto request = +- reinterpret_cast<const SetConfParamsRequest*>(inPayload.data()); +- auto response = reinterpret_cast<SetConfParamsResponse*>(outPayload.data()); +- response->completionCode = IPMI_CC_OK; +- +- switch (static_cast<Parameter>(request->paramSelector)) +- { +- case Parameter::PROGRESS: +- { +- uint8_t progress = request->value & progressMask; +- std::get<sol::Manager&>(singletonPool).progress = progress; +- break; +- } +- case Parameter::ENABLE: +- { +- bool enable = request->value & enableMask; +- std::get<sol::Manager&>(singletonPool).enable = enable; +- break; +- } +- case Parameter::AUTHENTICATION: +- { +- if (!request->auth.auth || !request->auth.encrypt) +- { +- response->completionCode = ipmiCCWriteReadParameter; +- } +- else if (request->auth.privilege < +- static_cast<uint8_t>(session::Privilege::USER) || +- request->auth.privilege > +- static_cast<uint8_t>(session::Privilege::OEM)) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- } +- else +- { +- std::get<sol::Manager&>(singletonPool).solMinPrivilege = +- static_cast<session::Privilege>(request->auth.privilege); +- } +- break; +- } +- case Parameter::ACCUMULATE: +- { +- using namespace std::chrono_literals; +- +- if (request->acc.threshold == 0) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- break; +- } +- +- std::get<sol::Manager&>(singletonPool).accumulateInterval = +- request->acc.interval * sol::accIntervalFactor * 1ms; +- std::get<sol::Manager&>(singletonPool).sendThreshold = +- request->acc.threshold; +- break; +- } +- case Parameter::RETRY: +- { +- using namespace std::chrono_literals; +- +- std::get<sol::Manager&>(singletonPool).retryCount = +- request->retry.count; +- std::get<sol::Manager&>(singletonPool).retryInterval = +- request->retry.interval * sol::retryIntervalFactor * 1ms; +- break; +- } +- case Parameter::PORT: +- { +- response->completionCode = ipmiCCWriteReadParameter; +- break; +- } +- case Parameter::NVBITRATE: +- case Parameter::VBITRATE: +- case Parameter::CHANNEL: +- default: +- response->completionCode = ipmiCCParamNotSupported; +- } +- +- return outPayload; +-} +- + std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, + const message::Handler& handler) + { +diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp +index 2046fe4..de36723 100644 +--- a/sol/sol_manager.cpp ++++ b/sol/sol_manager.cpp +@@ -12,7 +12,13 @@ + #include <boost/asio/write.hpp> + #include <chrono> + #include <cmath> ++#include <phosphor-ipmi-host/utils.hpp> + #include <phosphor-logging/log.hpp> ++#include <sdbusplus/message/types.hpp> ++ ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol"; ++constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties"; + + namespace sol + { +@@ -93,6 +99,119 @@ void Manager::stopHostConsole() + } + } + ++std::string getService(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})); ++ ++ std::map<std::string, std::vector<std::string>> mapperResponse; ++ ++ try ++ { ++ auto mapperResponseMsg = bus.call(mapperCall); ++ mapperResponseMsg.read(mapperResponse); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ throw std::runtime_error("ERROR in mapper call"); ++ } ++ ++ if (mapperResponse.begin() == mapperResponse.end()) ++ { ++ throw std::runtime_error("ERROR in reading the mapper response"); ++ } ++ ++ return mapperResponse.begin()->first; ++} ++ ++ipmi::PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus, ++ const std::string& service, ++ const std::string& objPath, ++ const std::string& interface) ++{ ++ ipmi::PropertyMap properties; ++ ++ sdbusplus::message::message method = bus.new_method_call( ++ service.c_str(), objPath.c_str(), PROP_INTF, "GetAll"); ++ ++ method.append(interface); ++ ++ try ++ { ++ sdbusplus::message::message reply = bus.call(method); ++ reply.read(properties); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Failed to get all properties", ++ phosphor::logging::entry("PATH=%s", objPath.c_str()), ++ phosphor::logging::entry("INTERFACE=%s", interface.c_str())); ++ throw std::runtime_error("ERROR in reading proerties"); ++ } ++ ++ return properties; ++} ++ ++void Manager::updateSOLParameter() ++{ ++ std::variant<uint8_t, bool> value; ++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); ++ static std::string solService{}; ++ ipmi::PropertyMap properties; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = getService(dbus, solInterface, solPath); ++ } ++ catch (const std::runtime_error& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return; ++ } ++ } ++ try ++ { ++ properties = ++ getAllDbusProperties(dbus, solService, solPath, solInterface); ++ } ++ catch (const std::runtime_error&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return; ++ } ++ ++ progress = std::get<uint8_t>(properties["Progress"]); ++ ++ enable = std::get<bool>(properties["Enable"]); ++ ++ solMinPrivilege = static_cast<session::Privilege>( ++ std::get<uint8_t>(properties["Authentication"])); ++ ++ accumulateInterval = ++ std::get<uint8_t>((properties["AccumulateIntervalMS"])) * ++ sol::accIntervalFactor * 1ms; ++ ++ sendThreshold = std::get<uint8_t>(properties["Threshold"]); ++ ++ retryCount = std::get<uint8_t>(properties["RetryCount"]); ++ ++ retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) * ++ sol::retryIntervalFactor * 1ms; ++ ++ return; ++} ++ + void Manager::startPayloadInstance(uint8_t payloadInstance, + session::SessionID sessionID) + { +diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp +index 5d96890..b7eb89e 100644 +--- a/sol/sol_manager.hpp ++++ b/sol/sol_manager.hpp +@@ -248,6 +248,7 @@ class Manager + * @return 0 on success and errno on failure. + */ + int writeConsoleSocket(const std::vector<uint8_t>& input) const; ++ void updateSOLParameter(void); + + private: + SOLPayloadMap payloadMap; +diff --git a/sol_module.cpp b/sol_module.cpp +index 8200e74..2b1fb46 100644 +--- a/sol_module.cpp ++++ b/sol_module.cpp +@@ -42,12 +42,6 @@ void registerCommands() + &getPayloadInfo, + session::Privilege::USER, + false}, +- // Set SOL Configuration Parameters +- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x21}, +- &setConfParams, +- session::Privilege::ADMIN, +- false}, + // Get SOL Configuration Parameters + {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | + static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22}, +-- +2.16.2 + 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..4b82cc21c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend @@ -0,0 +1,19 @@ +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 = "7e5d38d2fb51fc746624ff2f2b3701cea245a8fb" + +USERADD_PACKAGES = "${PN}" +# add a group called ipmi +GROUPADD_PARAM_${PN} = "ipmi " + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \ + file://0007-Adding-support-for-GetSessionInfo-command.patch \ + file://0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch \ + file://0009-Add-dbus-interface-for-sol-commands.patch \ + " + 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..09d2f9c41 --- /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://git@github.com/Intel-BMC/node-manager;protocol=ssh" +SRCREV = "81133dd32bd0337aec9e026d1c9c2788028c7bdd" +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/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..dd48df0c6 --- /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 native +inherit obmc-phosphor-utils + +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 100755 index 000000000..7b193f85b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml @@ -0,0 +1,44 @@ +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' + +cpu0_fault: + cpu0fault: + Action: 'On' + +cpu1_fault: + cpu1fault: + Action: 'On' + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend new file mode 100644 index 000000000..b1f4c1ce5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend @@ -0,0 +1,2 @@ +SRCREV = "30047bf9647215951ba5dfe21ceb3e58a1b405a4" + 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..dc22b3c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI = "file://init"
\ No newline at end of file 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..c5b2eb040 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init @@ -0,0 +1,180 @@ +#!/bin/sh + +# 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 + +# start with /proc and /tmp mounted +[ -e /proc/mounts ] || mount -t proc proc /proc +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 + +# list of things that need to be rw at boot +NV_OVERLAYS="/etc /var /home" + +# place to mount the real ubifs backing store +RWFS_MNT=/tmp/.rwfs + +if grep -q "$RWFS_MNT" /proc/mounts; then + # quit - we have already run + exit 0 +fi +mkdir -p "$RWFS_MNT" + +mtd_by_name() { + local name="$1" + local mtd="/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)" + echo "$mtd" +} + +mtdnum_by_name() { + local name="$1" + local mtdnum="$(grep "$name" /proc/mtd | cut -c 4)" + echo "$mtdnum" +} + +NV_MTD=rwfs +NV_MTD_DEV="$(mtd_by_name ${NV_MTD})" +NV_MTD_NUM="$(mtdnum_by_name ${NV_MTD})" + +nvrw() { + local p="$1" + mkdir -p "${RWFS_MNT}${p}" "${RWFS_MNT}${p}.work" + local mname=$(echo "rwnv${p}" | sed 's,/,,g') + local opts="lowerdir=${p},upperdir=${RWFS_MNT}${p},workdir=${RWFS_MNT}${p}.work" + mount -t overlay -o "$opts" "$mname" "$p" +} + +targetted_clean() { + local LOG_TAG="restore-defaults" + # Do not delete server certificates for the web server or ssh + echo "removing targetted contents:" + cd "${RWFS_MNT}/etc" + for file in *; do + case $file in + # The only files that stay are here: + CA|RestoreDefaultConfiguration|dropbear|sdr|server.pem);; + # All else get removed. + *) echo "remove $file" + rm -rf $file;; + esac + done + # nothing should be in the workdir, but clear it just in case + rm -rf "${RWFS_MNT}/etc.work" + + # Log files remaining - but not to stdout. + echo "Files remaining: $(ls)" + + # clean everything out of /var + rm -rf "${RWFS_MNT}/var" "${RWFS_MNT}/var.work" +} + +full_clean() { + local OVL='' + for OVL in $NV_OVERLAYS; do + rm -rf "${RWFS_MNT}${OVL}" "${RWFS_MNT}${OVL}.work" + done +} + +# check for full factory reset: if so, ubiformat $NV_MTD_DEV +bootflags="0x$(sed -n 's/^.*bootflags=\([0-9a-f]*\).*$/\1/p' /proc/cmdline)" +bootflags=$((bootflags + 0)) +let "restore_op = $bootflags & 0x3" +if [ $restore_op -eq 3 ]; then + ubiformat -y "$NV_MTD_DEV" +fi + +# attach a UBI device to the MTD device +NV_UBI_DEV="/dev/ubi${NV_MTD_NUM}" +if [ ! -e $NV_UBI_DEV ]; then + if ! ubiattach -m "$NV_MTD_NUM" -d "$NV_MTD_NUM"; then + # the attach failed, so format the MTD device and try again + echo "Warning! Failed to attach $NV_UBI_DEV to $NV_MTD_DEV." + echo "UBI-formatting $NV_MTD_DEV to attach again. Data on this device will be lost." + ubiformat -y "$NV_MTD_DEV" + ubiattach -m "$NV_MTD_NUM" -d "$NV_MTD_NUM" + fi +fi + +# make a UBI volume on the UBI device +NV_UBI_VOL="${NV_UBI_DEV}_0" +if [ ! -e $NV_UBI_VOL ]; then + ubimkvol "$NV_UBI_DEV" -N "$NV_MTD" -m +fi + +# mount a UBIFS on the UBI volume +mount -t ubifs "$NV_UBI_VOL" "$RWFS_MNT" + +if [ $restore_op -eq 1 ]; then + targetted_clean +elif [ $restore_op -eq 2 ]; then + full_clean +fi + +for FS in $NV_OVERLAYS; do + nvrw "$FS" +done + +# make sure that /etc/fw_env.config mirrors our current uboot environment +UENV_MTD_INFO=$(grep UENV /proc/mtd) +if [ -n "$UENV_MTD_INFO" ]; then + UENV_MTD_INFO=$(echo "$UENV_MTD_INFO" | sed 's,^\([^:]*\): \([0-9a-f]*\) \([0-9a-f]*\) .*,/dev/\1 0 0x\2 0x\3,') + if ! grep -q "^${UENV_MTD_INFO}$" /etc/fw_env.config; then + echo "${UENV_MTD_INFO}" > /etc/fw_env.config + echo "Updated fw_env.config" + fi +fi + +# 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 +if [ ! -s "$MACHINE_ID" ]; then + systemd-machine-id-setup +fi + +# mount persistent NV filesystem, where immortal settings live +if ! grep -q sofs /proc/mounts; then + mkdir -p /var/sofs + SOFS_MTD=sofs + SOFS_MTD_DEV="$(mtd_by_name ${SOFS_MTD})" + SOFS_MTD_NUM="$(mtdnum_by_name ${SOFS_MTD})" + SOFS_UBI_DEV="/dev/ubi${SOFS_MTD_NUM}" + + # attach a UBI device to the MTD device + if [ ! -e $SOFS_UBI_DEV ]; then + if ! ubiattach -m "$SOFS_MTD_NUM" -d "$SOFS_MTD_NUM"; then + # the attach failed, so format the MTD device and try again + echo "Warning! Failed to attach $SOFS_UBI_DEV to $SOFS_MTD_DEV." + echo "UBI-formatting $SOFS_MTD_DEV to attach again. Data on this device will be lost." + ubiformat -y "$SOFS_MTD_DEV" + ubiattach -m "$SOFS_MTD_NUM" -d "$SOFS_MTD_NUM" + fi + fi + + # make a UBI volume on the UBI device + SOFS_UBI_VOL="${SOFS_UBI_DEV}_0" + if [ ! -e $SOFS_UBI_VOL ]; then + ubimkvol "$SOFS_UBI_DEV" -N "$SOFS_MTD" -m + fi + + # mount a UBIFS on the UBI volume + mount -t ubifs "$SOFS_UBI_VOL" /var/sofs +fi + +echo "Finished mounting non-volatile overlays" + +exec /lib/systemd/systemd 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..809d05b94 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend @@ -0,0 +1,6 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git" +SRCREV = "2b9704d7eb666c945c73dd74a426a0af2292b0ea" + +# Enable threshold monitoring +EXTRA_OECMAKE += "-DSEL_LOGGER_MONITOR_THRESHOLD_EVENTS=ON" 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/selftest/intel-self-test_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb new file mode 100644 index 000000000..da1d74207 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb @@ -0,0 +1,38 @@ +SUMMARY = "BMC Self Test service" +DESCRIPTION = "BMC Self Test service for subsystem diagnosis failure info" + +SRC_URI = "git://git@github.com/Intel-BMC/intel-self-test;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "d039998ad2c55aeae4191af30e15bbd3032508c1" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=fa818a259cbed7ce8bc2a22d35a464fc" + +inherit cmake +inherit obmc-phosphor-dbus-service +inherit obmc-phosphor-systemd +inherit pkgconfig pythonnative + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.selftest.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " + +EXTRA_OECMAKE = " -DENABLE_GTEST=OFF -DCMAKE_SKIP_RPATH=ON" 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..dff1647e8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -0,0 +1,4 @@ +SRCREV = "209ec56cca898725213140fd0d1205a4d2f1c6a4" +SRC_URI = "git://github.com/openbmc/dbus-sensors.git" + +DEPENDS_append = " i2c-tools" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend new file mode 100644 index 000000000..436623234 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://defaults.yaml \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml new file mode 100644 index 000000000..24816fb4c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml @@ -0,0 +1,181 @@ +/xyz/openbmc_project/control/minimum_ship_level_required: + - Interface: xyz.openbmc_project.Control.MinimumShipLevel + Properties: + MinimumShipLevelRequired: + Default: 'true' + +/xyz/openbmc_project/control/host0/auto_reboot: + - Interface: xyz.openbmc_project.Control.Boot.RebootPolicy + Properties: + AutoReboot: + Default: 'false' + +/xyz/openbmc_project/control/host0/boot: + - Interface: xyz.openbmc_project.Control.Boot.Source + Properties: + BootSource: + Default: Source::Sources::Default + - Interface: xyz.openbmc_project.Control.Boot.Mode + Properties: + BootMode: + Default: Mode::Modes::Regular + +/xyz/openbmc_project/control/host0/boot/one_time: + - Interface: xyz.openbmc_project.Control.Boot.Source + Properties: + BootSource: + Default: Source::Sources::Default + - Interface: xyz.openbmc_project.Control.Boot.Mode + Properties: + BootMode: + Default: Mode::Modes::Regular + - Interface: xyz.openbmc_project.Object.Enable + Properties: + Enabled: + Default: 'true' + +/xyz/openbmc_project/control/host0/power_cap: + - Interface: xyz.openbmc_project.Control.Power.Cap + Properties: + PowerCap: + Default: 0 + Validation: + Type: "range" + Validator: "0..1000" + Unit: "Watts" + PowerCapEnable: + Default: 'false' + +/xyz/openbmc_project/control/host0/power_restore_policy: + - Interface: xyz.openbmc_project.Control.Power.RestorePolicy + Properties: + PowerRestorePolicy: + Default: RestorePolicy::Policy::AlwaysOff + +/xyz/openbmc_project/control/power_restore_delay: + - Interface: xyz.openbmc_project.Control.Power.RestoreDelay + Properties: + PowerRestoreDelay: + Default: 0 + +/xyz/openbmc_project/control/host0/acpi_power_state: + - Interface: xyz.openbmc_project.Control.Power.ACPIPowerState + Properties: + SysACPIStatus: + Default: ACPIPowerState::ACPI::Unknown + DevACPIStatus: + Default: ACPIPowerState::ACPI::Unknown + +/xyz/openbmc_project/time/owner: + - Interface: xyz.openbmc_project.Time.Owner + Properties: + TimeOwner: + Default: Owner::Owners::BMC + +/xyz/openbmc_project/time/sync_method: + - Interface: xyz.openbmc_project.Time.Synchronization + Properties: + TimeSyncMethod: + Default: Synchronization::Method::NTP + +/xyz/openbmc_project/network/host0/intf: + - Interface: xyz.openbmc_project.Network.MACAddress + Properties: + MACAddress: + Default: '"00:00:00:00:00:00"' + Validation: + Type: "regex" + Validator: '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$' + +#needs to implement address validation TODO openbmc/issues/2046 +/xyz/openbmc_project/network/host0/intf/addr: + - Interface: xyz.openbmc_project.Network.IP + Properties: + Address: + Default: '"0.0.0.0"' + PrefixLength: + Default: 0 + Validation: + Type: "range" + Validator: 0..128 + Unit: "bits" + Origin: + Default: IP::AddressOrigin::Static + Gateway: + Default: '"0.0.0.0"' + Type: + Default: IP::Protocol::IPv4 + +/xyz/openbmc_project/control/host0/restriction_mode: + - Interface: xyz.openbmc_project.Control.Security.RestrictionMode + Properties: + RestrictionMode: + Default: RestrictionMode::Modes::None + +/xyz/openbmc_project/control/host0/TPMEnable: + - Interface: xyz.openbmc_project.Control.TPM.Policy + Properties: + TPMEnable: + Default: 'false' + +/xyz/openbmc_project/control/power_supply_redundancy: + - Interface: xyz.openbmc_project.Control.PowerSupplyRedundancy + Properties: + PowerSupplyRedundancyEnabled: + Default: 'true' + +/xyz/openbmc_project/control/host0/turbo_allowed: + - Interface: xyz.openbmc_project.Control.Host.TurboAllowed + Properties: + TurboAllowed: + Default: 'true' + +/xyz/openbmc_project/control/host0/systemGUID: + - Interface: xyz.openbmc_project.Common.UUID + Properties: + UUID: + Default: '"00000000-0000-0000-0000-000000000000"' + +/xyz/openbmc_project/bios: + - Interface: xyz.openbmc_project.Inventory.Item.Bios + Properties: + BiosId: + Default: '"NA"' + +/xyz/openbmc_project/control/processor_error_config: + - Interface: xyz.openbmc_project.Control.Processor.ErrConfig + Properties: + ResetCfg: + Default: 0 + ResetErrorOccurrenceCounts: + Default: 0 + +/xyz/openbmc_project/control/shutdown_policy_config: + - Interface: xyz.openbmc_project.Control.ShutdownPolicy + Properties: + Policy: + Default: 0 + +/xyz/openbmc_project/control/chassis_capabilities_config: + - Interface: xyz.openbmc_project.Control.ChassisCapabilities + Properties: + CapabilitiesFlags: + Default: 0 + FRUDeviceAddress: + Default: 0x20 + SDRDeviceAddress: + Default: 0x20 + SELDeviceAddress: + Default: 0x20 + SMDeviceAddress: + Default: 0x20 + BridgeDeviceAddress: + Default: 0x20 + +/xyz/openbmc_project/control/thermal_mode: + - Interface: xyz.openbmc_project.Control.ThermalMode + Properties: + Current: + Default: '"Performance"' + Supported: + Default: '{"Acoustic", "Performance"}' diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch new file mode 100644 index 000000000..fcf2415d6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch @@ -0,0 +1,37 @@ +From 9e99aa4f72f4420e03ec2e4a29816eae43c5e748 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 29 May 2018 16:16:06 +0800 +Subject: [PATCH] [settings] initialize data file with default setting + +Current code trys to load settings from file at startup. When file +does not exist, it will just use default setting. However, it will +still load default on next reboot because no one create files. + +This change creates file as well when daemon loads default so next +time daemon could load/save from file. + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + settings_manager.mako.hpp | 3 +++ + 1 file changed, 3 insertions(+) + mode change 100644 => 100755 settings_manager.mako.hpp + +diff --git a/settings_manager.mako.hpp b/settings_manager.mako.hpp +old mode 100644 +new mode 100755 +index 09a5a1f..cd592a0 +--- a/settings_manager.mako.hpp ++++ b/settings_manager.mako.hpp +@@ -323,6 +323,9 @@ class Manager + else + { + initSetting${index}(); ++ std::ofstream ostr(path.c_str(), std::ios::out); ++ cereal::JSONOutputArchive oarchive(ostr); ++ oarchive(*std::get<${index}>(settings)); //create file with default + } + } + catch (cereal::Exception& e) +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend new file mode 100644 index 000000000..bc695abe8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-settings-initialize-data-file-with-default-setting.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb new file mode 100644 index 000000000..01c93490b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "Service configuration manager daemon to control service properties" +DESCRIPTION = "Daemon controls service properies like port, channels, state etc.." + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/srvcfg-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "srvcfg-manager.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + boost \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch new file mode 100644 index 000000000..fac9b52f1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch @@ -0,0 +1,38 @@ +From d34a2a5f6ca0564275ed0e2664624525cad64585 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 13 Jul 2018 09:08:52 +0800 +Subject: [PATCH] Modify dbus interface for power control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Switch power control service namespace from “org” to “xyz”, +to compatible with new intel-chassis services + +Change-Id: I1bf5e218f72eb9fd4fb6f203c35479818d12b1fa +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassis_state_manager.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp +index 03dd176..05e2440 100644 +--- a/chassis_state_manager.cpp ++++ b/chassis_state_manager.cpp +@@ -63,10 +63,11 @@ void Chassis::determineInitialState() + { + sdbusplus::message::variant<int> pgood = -1; + auto method = this->bus.new_method_call( +- "org.openbmc.control.Power", "/org/openbmc/control/power0", ++ "xyz.openbmc_project.Chassis.Control.Power", ++ "/xyz/openbmc_project/Chassis/Control/Power0", + "org.freedesktop.DBus.Properties", "Get"); + +- method.append("org.openbmc.control.Power", "pgood"); ++ method.append("xyz.openbmc_project.Chassis.Control.Power", "pgood"); + try + { + auto reply = this->bus.call(method); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch new file mode 100644 index 000000000..7d70b29fa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch @@ -0,0 +1,234 @@ +From c0f01261572cb527cf9dc62fa732b28c658ff013 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 7 Aug 2018 16:43:00 +0800 +Subject: [PATCH] Capture host restart cause + +Capture host restart cause on power/reset button pressed, +and power restore policy settings. +Save the restart cause into file system. +And restort it when BMC boot up. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + configure.ac | 4 ++-- + discover_system_state.cpp | 14 ++++++++++++ + host_state_manager.cpp | 16 ++++++++++++++ + host_state_manager.hpp | 56 ++++++++++++++++++++++++++++++++++++++++++++--- + 4 files changed, 85 insertions(+), 5 deletions(-) + +diff --git a/configure.ac b/configure.ac +index e985a95..b9e64c8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -56,9 +56,9 @@ AC_ARG_VAR(HOST_RUNNING_FILE, [File to create if host is running]) + AS_IF([test "x$HOST_RUNNING_FILE" == "x"], [HOST_RUNNING_FILE="/run/openbmc/host@%u-on"]) + AC_DEFINE_UNQUOTED([HOST_RUNNING_FILE], ["$HOST_RUNNING_FILE"], [File to create if host is running]) + +-AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing requested host state.]) ++AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing host state.]) + AS_IF([test "x$HOST_STATE_PERSIST_PATH" == "x"], \ +- [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/requestedHostTransition"]) ++ [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/hostState"]) + AC_DEFINE_UNQUOTED([HOST_STATE_PERSIST_PATH], ["$HOST_STATE_PERSIST_PATH"], \ + [Path of file for storing requested host state.]) + +diff --git a/discover_system_state.cpp b/discover_system_state.cpp +index 3a38152..0b5798a 100644 +--- a/discover_system_state.cpp ++++ b/discover_system_state.cpp +@@ -12,6 +12,7 @@ + #include "settings.hpp" + #include "xyz/openbmc_project/Common/error.hpp" + #include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp" ++#include <xyz/openbmc_project/State/Host/server.hpp> + + namespace phosphor + { +@@ -181,6 +182,10 @@ int main(int argc, char** argv) + log<level::INFO>("power_policy=ALWAYS_POWER_ON, powering host on"); + setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", + convertForMessage(server::Host::Transition::On)); ++ ++ setProperty( ++ bus, hostPath, HOST_BUSNAME, "HostRestartCause", ++ convertForMessage(server::Host::RestartCause::PowerPolicyAlwaysOn)); + } + else if (RestorePolicy::Policy::Restore == + RestorePolicy::convertPolicyFromString(powerPolicy)) +@@ -192,6 +197,15 @@ int main(int argc, char** argv) + getProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition"); + setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", + hostReqState); ++ ++ if (server::Host::convertTransitionFromString(hostReqState) == ++ server::Host::Transition::On) ++ { ++ setProperty( ++ bus, hostPath, HOST_BUSNAME, "HostRestartCause", ++ convertForMessage( ++ server::Host::RestartCause::PowerPolicyPreviousState)); ++ } + } + + return 0; +diff --git a/host_state_manager.cpp b/host_state_manager.cpp +index 7d661dd..03d210d 100644 +--- a/host_state_manager.cpp ++++ b/host_state_manager.cpp +@@ -308,6 +308,15 @@ bool Host::deserialize(const fs::path& path) + } + } + ++void Host::restoreHostRestartCause() ++{ ++ if (!deserialize(HOST_STATE_PERSIST_PATH)) ++ { ++ // set to default value ++ server::Host::hostRestartCause(server::Host::RestartCause::Unknown); ++ } ++} ++ + Host::Transition Host::requestedHostTransition(Transition value) + { + log<level::INFO>("Host State transaction request", +@@ -353,6 +362,13 @@ Host::HostState Host::currentHostState(HostState value) + return server::Host::currentHostState(value); + } + ++Host::RestartCause Host::hostRestartCause(RestartCause value) ++{ ++ auto retVal = server::Host::hostRestartCause(value); ++ serialize(); ++ return retVal; ++} ++ + } // namespace manager + } // namespace state + } // namespace phosphor +diff --git a/host_state_manager.hpp b/host_state_manager.hpp +index 2b00777..e74fab7 100644 +--- a/host_state_manager.hpp ++++ b/host_state_manager.hpp +@@ -32,6 +32,15 @@ using namespace phosphor::logging; + namespace sdbusRule = sdbusplus::bus::match::rules; + namespace fs = std::experimental::filesystem; + ++const static constexpr char* powerButtonPath = ++ "/xyz/openbmc_project/Chassis/Buttons/Power0"; ++const static constexpr char* powerButtonIntf = ++ "xyz.openbmc_project.Chassis.Buttons.Power"; ++const static constexpr char* resetButtonPath = ++ "/xyz/openbmc_project/Chassis/Buttons/Reset0"; ++const static constexpr char* resetButtonIntf = ++ "xyz.openbmc_project.Chassis.Buttons.Reset"; ++ + /** @class Host + * @brief OpenBMC host state management implementation. + * @details A concrete implementation for xyz.openbmc_project.State.Host +@@ -59,7 +68,31 @@ class Host : public HostInherit + sdbusRule::interface("org.freedesktop.systemd1.Manager"), + std::bind(std::mem_fn(&Host::sysStateChange), this, + std::placeholders::_1)), +- settings(bus) ++ settings(bus), ++ powerButtonPressedSignal( ++ bus, ++ sdbusRule::type::signal() + sdbusRule::member("Pressed") + ++ sdbusRule::path(powerButtonPath) + ++ sdbusRule::interface(powerButtonIntf), ++ [this](sdbusplus::message::message &msg) { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "powerButtonPressedSignal callback function is called..."); ++ this->hostRestartCause(this->RestartCause::PowerButton); ++ return; ++ } ++ ), ++ resetButtonPressedSignal( ++ bus, ++ sdbusRule::type::signal() + sdbusRule::member("Pressed") + ++ sdbusRule::path(resetButtonPath) + ++ sdbusRule::interface(resetButtonIntf), ++ [this](sdbusplus::message::message &msg) { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "resetButtonPressedSignal callback function is called..."); ++ this->hostRestartCause(this->RestartCause::ResetButton); ++ return; ++ } ++ ) + { + // Enable systemd signals + subscribeToSystemdSignals(); +@@ -69,6 +102,8 @@ class Host : public HostInherit + + attemptsLeft(BOOT_COUNT_MAX_ALLOWED); + ++ restoreHostRestartCause(); // restore host restart cause from persisted file ++ + // We deferred this until we could get our property correct + this->emit_object_added(); + } +@@ -85,6 +120,9 @@ class Host : public HostInherit + /** @brief Set value of CurrentHostState */ + HostState currentHostState(HostState value) override; + ++ /** @brief Set value of HostRestartCause */ ++ RestartCause hostRestartCause(RestartCause value) override; ++ + /** + * @brief Set host reboot count to default + * +@@ -192,7 +230,10 @@ class Host : public HostInherit + server::Progress::bootProgress()), + convertForMessage( + sdbusplus::xyz::openbmc_project::State::OperatingSystem:: +- server::Status::operatingSystemState())); ++ server::Status::operatingSystemState()), ++ convertForMessage(sdbusplus::xyz::openbmc_project::State:: ++ server::Host::hostRestartCause()) ++ ); + } + + /** @brief Function required by Cereal to perform deserialization. +@@ -208,7 +249,8 @@ class Host : public HostInherit + std::string reqTranState; + std::string bootProgress; + std::string osState; +- archive(reqTranState, bootProgress, osState); ++ std::string restartCause; ++ archive(reqTranState, bootProgress, osState, restartCause); + auto reqTran = Host::convertTransitionFromString(reqTranState); + // When restoring, set the requested state with persistent value + // but don't call the override which would execute it +@@ -219,6 +261,8 @@ class Host : public HostInherit + sdbusplus::xyz::openbmc_project::State::OperatingSystem::server:: + Status::operatingSystemState( + Host::convertOSStatusFromString(osState)); ++ sdbusplus::xyz::openbmc_project::State::server::Host:: ++ hostRestartCause(Host::convertRestartCauseFromString(restartCause)); + } + + /** @brief Serialize and persist requested host state +@@ -239,6 +283,9 @@ class Host : public HostInherit + */ + bool deserialize(const fs::path& path); + ++ /** @brief Used to restore HostRestartCause value from persisted file */ ++ void restoreHostRestartCause(); ++ + /** @brief Persistent sdbusplus DBus bus connection. */ + sdbusplus::bus::bus& bus; + +@@ -247,6 +294,9 @@ class Host : public HostInherit + + // Settings objects of interest + settings::Objects settings; ++ ++ sdbusplus::bus::match_t powerButtonPressedSignal; ++ sdbusplus::bus::match_t resetButtonPressedSignal; + }; + + } // namespace manager +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch new file mode 100644 index 000000000..40722c3c9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch @@ -0,0 +1,71 @@ +From 8a7f73a0688524c71023da89e8cb5578dac16f5d Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 8 Mar 2019 17:21:49 +0800 +Subject: [PATCH] Use warm-reboot for the Reboot host state transition + +The same as reset button pressing, the pgood signal will keep on during the reboot + +Tested By: +ipmitool chassis power reset +The pgood(gpio219) will be keep high during the reset process + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + host_state_manager.cpp | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/host_state_manager.cpp b/host_state_manager.cpp +index 03d210d..8fac348 100644 +--- a/host_state_manager.cpp ++++ b/host_state_manager.cpp +@@ -44,8 +44,9 @@ constexpr auto HOST_STATE_SOFT_POWEROFF_TGT = "obmc-host-shutdown@0.target"; + constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-host-stop@0.target"; + constexpr auto HOST_STATE_POWERON_TGT = "obmc-host-start@0.target"; + constexpr auto HOST_STATE_POWERON_MIN_TGT = "obmc-host-startmin@0.target"; +-constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-reboot@0.target"; ++constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-warm-reset@0.target"; + constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target"; ++constexpr auto hostStateRebootService = "intel-power-warm-reset@0.service"; + + constexpr auto ACTIVE_STATE = "active"; + constexpr auto ACTIVATING_STATE = "activating"; +@@ -168,6 +169,7 @@ bool Host::stateActive(const std::string& target) + + const auto& currentStateStr = + sdbusplus::message::variant_ns::get<std::string>(currentState); ++ + return currentStateStr == ACTIVE_STATE || + currentStateStr == ACTIVATING_STATE; + } +@@ -236,18 +238,22 @@ void Host::sysStateChange(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- if ((newStateUnit == HOST_STATE_POWEROFF_TGT) && +- (newStateResult == "done") && +- (!stateActive(HOST_STATE_POWERON_MIN_TGT))) ++ if (((newStateUnit == HOST_STATE_POWEROFF_TGT) && ++ (newStateResult == "done") && ++ (!stateActive(HOST_STATE_POWERON_MIN_TGT))) || ++ ((newStateUnit == hostStateRebootService) && ++ (newStateResult == "done"))) + { + log<level::INFO>("Received signal that host is off"); + this->currentHostState(server::Host::HostState::Off); + this->bootProgress(bootprogress::Progress::ProgressStages::Unspecified); + this->operatingSystemState(osstatus::Status::OSStatus::Inactive); + } +- else if ((newStateUnit == HOST_STATE_POWERON_MIN_TGT) && +- (newStateResult == "done") && +- (stateActive(HOST_STATE_POWERON_MIN_TGT))) ++ else if (((newStateUnit == HOST_STATE_POWERON_MIN_TGT) && ++ (newStateResult == "done") && ++ (stateActive(HOST_STATE_POWERON_MIN_TGT))) || ++ ((newStateUnit == HOST_STATE_REBOOT_TGT) && ++ (newStateResult == "done"))) + { + log<level::INFO>("Received signal that host is running"); + this->currentHostState(server::Host::HostState::Running); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service new file mode 100644 index 000000000..ffde01ca3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service @@ -0,0 +1,18 @@ +[Unit] +Description=Reboot host%i +Wants=obmc-host-stop@%i.target +After=obmc-host-stop@%i.target + +[Service] +#ExecStart={base_bindir}/systemctl start obmc-host-start@%i.target +# This service is starting another target that conflicts with the +# target this service is running in. OpenBMC needs a refactor of +# how it does its host reset path. Until then, this short term +# solution does the job. +# Since this is a part of the reboot target, call the startmin +# target which does the minimum required to start the host. +ExecStart=/bin/sh -c "sleep 10 && systemctl start obmc-host-startmin@%i.target" + + +[Install] +WantedBy=obmc-host-reboot@%i.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service new file mode 100644 index 000000000..13b8f0fca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service @@ -0,0 +1,19 @@ +[Unit] +Description=Check Host%i status on BMC reset +Wants=mapper-wait@-xyz-openbmc_project-control-host%i.service +After=mapper-wait@-xyz-openbmc_project-control-host%i.service +Wants=obmc-host-reset-running@%i.target +Before=obmc-host-reset-running@%i.target +Wants=op-reset-chassis-on@%i.service +After=op-reset-chassis-on@%i.service +Conflicts=obmc-host-stop@%i.target +ConditionPathExists=/run/openbmc/chassis@%i-on + +[Service] +RemainAfterExit=yes +Type=oneshot +ExecStart=/bin/sh -c "if [ $(busctl get-property `mapper get-service /xyz/openbmc_project/Chassis/Control/Power%i` /xyz/openbmc_project/Chassis/Control/Power%i xyz.openbmc_project.Chassis.Control.Power vrd_good | sed 's/i\s*[1]/on/' | grep on | wc -l) != 0 ]; then mkdir -p /run/openbmc/ && touch /run/openbmc/host@%i-on; fi" +SyslogIdentifier=phosphor-host-check + +[Install] +WantedBy=obmc-host-reset@%i.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service new file mode 100644 index 000000000..87c750c57 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service @@ -0,0 +1,14 @@ +[Unit] +Description=Reset host reboot counter +Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service +After=mapper-wait@-xyz-openbmc_project-state-host%i.service +ConditionPathExists=!/run/openbmc/host@%i-on + +[Service] +Restart=no +Type=oneshot +ExecStart=/bin/sh -c "busctl set-property `mapper get-service /xyz/openbmc_project/state/host%i` /xyz/openbmc_project/state/host%i xyz.openbmc_project.Control.Boot.RebootAttempts AttemptsLeft u 3" +StartLimitInterval=0 + +[Install] +WantedBy=obmc-host-start@%i.target 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..4c50ecf5e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Modify-dbus-interface-for-power-control.patch \ + file://phosphor-reboot-host@.service \ + file://phosphor-reset-host-reboot-attempts@.service \ + file://phosphor-reset-host-check@.service \ + file://0002-Capture-host-restart-cause.patch \ + file://0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch new file mode 100644 index 000000000..8915484cd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch @@ -0,0 +1,499 @@ +From 7d78e70735e1bce51ef34cfe128be68758de3447 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 19 Feb 2019 15:00:11 +0800 +Subject: [PATCH] Implement post code manager + +Implement method and properties defined in PostCode.interface.yaml +under phosphor-dbus-interfaces/xyz/openbmc_project/State/Boot +1. Method: std::vector<uint64_t> PostCode::getPostCodes(uint16_t index) +2. Properties: CurrentBootCycleIndex/MaxBootCycleNum + +Test-By: + Every cycle post codes is saved in "/var/lib/phosphor-post-code-manager" + "1" file is saved all post codes for cycle 1 + "2" file is saved all post codes for cycle 2 + "CurrentBootCycleIndex" file is saved the current boot cycle number. + root@wolfpass:/var/lib/phosphor-post-code-manager# ls + 1 2 CurrentBootCycleIndex + +Change-Id: Ia89b9121983261fef5573092d890beb84626ceeb +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + CMakeLists.txt | 45 ++++++ + MAINTAINERS | 45 ++++++ + inc/post_code.hpp | 152 ++++++++++++++++++ + ...penbmc_project.State.Boot.PostCode.service | 11 ++ + src/main.cpp | 61 +++++++ + src/post_code.cpp | 109 +++++++++++++ + 6 files changed, 423 insertions(+) + create mode 100644 CMakeLists.txt + create mode 100644 MAINTAINERS + create mode 100644 inc/post_code.hpp + create mode 100644 service_files/xyz.openbmc_project.State.Boot.PostCode.service + create mode 100644 src/main.cpp + create mode 100644 src/post_code.cpp + +diff --git a/CMakeLists.txt b/CMakeLists.txt +new file mode 100644 +index 0000000..594d839 +--- /dev/null ++++ b/CMakeLists.txt +@@ -0,0 +1,45 @@ ++cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) ++project(post-code-manager CXX) ++set(CMAKE_CXX_STANDARD 17) ++set(CMAKE_CXX_STANDARD_REQUIRED ON) ++ ++set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) ++include(GNUInstallDirs) ++include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) ++include_directories(${CMAKE_CURRENT_BINARY_DIR}) ++ ++set(DBUS_OBJECT_NAME "xyz/openbmc_project/State/Boot/PostCode") ++set(DBUS_INTF_NAME "xyz.openbmc_project.State.Boot.PostCode") ++ ++add_definitions(-DDBUS_OBJECT_NAME="/${DBUS_OBJECT_NAME}") ++add_definitions(-DDBUS_INTF_NAME="${DBUS_INTF_NAME}") ++set(SRC_FILES src/post_code.cpp ++ src/main.cpp ) ++set ( SERVICE_FILES ++ service_files/xyz.openbmc_project.State.Boot.PostCode.service ) ++ ++# import sdbusplus ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(SDBUSPLUSPLUS sdbusplus REQUIRED) ++include_directories(${SDBUSPLUSPLUS_INCLUDE_DIRS}) ++link_directories(${SDBUSPLUSPLUS_LIBRARY_DIRS}) ++find_program(SDBUSPLUSPLUS sdbus++) ++ ++# import phosphor-logging ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(LOGGING phosphor-logging REQUIRED) ++include_directories(${LOGGING_INCLUDE_DIRS}) ++link_directories(${LOGGING_LIBRARY_DIRS}) ++ ++# 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(${PROJECT_NAME} ${SRC_FILES}) ++target_link_libraries(${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} ) ++target_link_libraries(${PROJECT_NAME} "${SDBUSPLUSPLUS_LIBRARIES} -lstdc++fs -lphosphor_dbus") ++ ++install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) ++install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/) +\ No newline at end of file +diff --git a/MAINTAINERS b/MAINTAINERS +new file mode 100644 +index 0000000..de6cc54 +--- /dev/null ++++ b/MAINTAINERS +@@ -0,0 +1,45 @@ ++How to use this list: ++ Find the most specific section entry (described below) that matches where ++ your change lives and add the reviewers (R) and maintainers (M) as ++ reviewers. You can use the same method to track down who knows a particular ++ code base best. ++ ++ Your change/query may span multiple entries; that is okay. ++ ++ If you do not find an entry that describes your request at all, someone ++ forgot to update this list; please at least file an issue or send an email ++ to a maintainer, but preferably you should just update this document. ++ ++Description of section entries: ++ ++ Section entries are structured according to the following scheme: ++ ++ X: NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!> ++ X: ... ++ . ++ . ++ . ++ ++ Where REPO_NAME is the name of the repository within the OpenBMC GitHub ++ organization; FILE_PATH is a file path within the repository, possibly with ++ wildcards; X is a tag of one of the following types: ++ ++ M: Denotes maintainer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; ++ if omitted from an entry, assume one of the maintainers from the ++ MAINTAINERS entry. ++ R: Denotes reviewer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; ++ these people are to be added as reviewers for a change matching the repo ++ path. ++ F: Denotes forked from an external repository; has fields URL. ++ ++ Line comments are to be denoted "# SOME COMMENT" (typical shell style ++ comment); it is important to follow the correct syntax and semantics as we ++ may want to use automated tools with this file in the future. ++ ++ A change cannot be added to an OpenBMC repository without a MAINTAINER's ++ approval; thus, a MAINTAINER should always be listed as a reviewer. ++ ++START OF MAINTAINERS LIST ++------------------------- ++ ++M: Kuiying Wang <kuiying.wang@intel.com> <kuiyingw> +\ No newline at end of file +diff --git a/inc/post_code.hpp b/inc/post_code.hpp +new file mode 100644 +index 0000000..84c8b3e +--- /dev/null ++++ b/inc/post_code.hpp +@@ -0,0 +1,152 @@ ++/* ++// 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. ++*/ ++#pragma once ++#include <fcntl.h> ++#include <unistd.h> ++#include <cereal/cereal.hpp> ++#include <experimental/filesystem> ++#include <cereal/access.hpp> ++#include <cereal/archives/json.hpp> ++#include <iostream> ++#include <fstream> ++#include <cereal/types/vector.hpp> ++ ++#include <xyz/openbmc_project/State/Boot/PostCode/server.hpp> ++#include <xyz/openbmc_project/Common/error.hpp> ++#include <phosphor-logging/elog-errors.hpp> ++#include <xyz/openbmc_project/State/Host/server.hpp> ++ ++#define MaxPostCodeCycles 100 ++ ++const static constexpr char *PostCodePath = ++ "/xyz/openbmc_project/state/boot/raw"; ++const static constexpr char *PropertiesIntf = ++ "org.freedesktop.DBus.Properties"; ++const static constexpr char *PostCodeListPath = ++ "/var/lib/phosphor-post-code-manager/"; ++const static constexpr char *CurrentBootCycleIndexName = ++ "CurrentBootCycleIndex"; ++const static constexpr char *HostStatePath = ++ "/xyz/openbmc_project/state/host0"; ++ ++ ++struct EventDeleter ++{ ++ void operator()(sd_event *event) const ++ { ++ event = sd_event_unref(event); ++ } ++}; ++using EventPtr = std::unique_ptr<sd_event, EventDeleter>; ++namespace fs = std::experimental::filesystem; ++namespace StateServer = sdbusplus::xyz::openbmc_project::State::server; ++ ++using post_code = ++ sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode; ++ ++struct PostCode : sdbusplus::server::object_t<post_code> ++{ ++ PostCode(sdbusplus::bus::bus& bus, const char* path, ++ EventPtr &event) : ++ sdbusplus::server::object_t<post_code>(bus, path), ++ bus(bus), ++ propertiesChangedSignalRaw( ++ bus, ++ sdbusplus::bus::match::rules::type::signal() + ++ sdbusplus::bus::match::rules::member("PropertiesChanged") + ++ sdbusplus::bus::match::rules::path(PostCodePath) + ++ sdbusplus::bus::match::rules::interface(PropertiesIntf), ++ [this](sdbusplus::message::message &msg) { ++ std::string objectName; ++ std::map<std::string, sdbusplus::message::variant<uint64_t>> msgData; ++ msg.read(objectName, msgData); ++ // Check if it was the Value property that changed. ++ auto valPropMap = msgData.find("Value"); ++ { ++ if (valPropMap != msgData.end()) ++ { ++ this->savePostCodes(sdbusplus::message::variant_ns::get<uint64_t>(valPropMap->second)); ++ } ++ } ++ }), ++ propertiesChangedSignalCurrentHostState( ++ bus, ++ sdbusplus::bus::match::rules::type::signal() + ++ sdbusplus::bus::match::rules::member("PropertiesChanged") + ++ sdbusplus::bus::match::rules::path(HostStatePath) + ++ sdbusplus::bus::match::rules::interface(PropertiesIntf), ++ [this](sdbusplus::message::message &msg) { ++ std::string objectName; ++ std::map<std::string, sdbusplus::message::variant<std::string>> msgData; ++ msg.read(objectName, msgData); ++ // Check if it was the Value property that changed. ++ auto valPropMap = msgData.find("CurrentHostState"); ++ { ++ if (valPropMap != msgData.end()) ++ { ++ StateServer::Host::HostState currentHostState = ++ StateServer::Host::convertHostStateFromString( ++ sdbusplus::message::variant_ns::get<std::string>(valPropMap->second)); ++ if (currentHostState == StateServer::Host::HostState::Off) ++ { ++ if (this->currentBootCycleIndex() >= this->maxBootCycleNum()) ++ { ++ this->currentBootCycleIndex(1); ++ } else{ ++ this->currentBootCycleIndex(this->currentBootCycleIndex() + 1); ++ } ++ this->postCodes.clear(); ++ } ++ } ++ } ++ }) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "PostCode is created"); ++ auto dir = fs::path(PostCodeListPath); ++ fs::create_directories(dir); ++ strPostCodeListPath = PostCodeListPath; ++ strCurrentBootCycleIndexName = CurrentBootCycleIndexName; ++ uint16_t index = 0; ++ deserialize(fs::path(strPostCodeListPath + strCurrentBootCycleIndexName), index); ++ currentBootCycleIndex(index); ++ maxBootCycleNum(MaxPostCodeCycles); ++ if (currentBootCycleIndex() >= maxBootCycleNum()) ++ { ++ currentBootCycleIndex(1); ++ } else{ ++ currentBootCycleIndex(currentBootCycleIndex() + 1); ++ } ++ } ++ ~PostCode() ++ { ++ ++ } ++ ++ std::vector<uint64_t> getPostCodes(uint16_t index) override; ++ ++ private: ++ sdbusplus::bus::bus& bus; ++ std::vector<uint64_t> postCodes; ++ std::string strPostCodeListPath; ++ std::string strCurrentBootCycleIndexName; ++ void savePostCodes(uint64_t code); ++ sdbusplus::bus::match_t propertiesChangedSignalRaw; ++ sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState; ++ fs::path serialize(const std::string& path); ++ bool deserialize(const fs::path& path, uint16_t& index); ++ bool deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes); ++}; +diff --git a/service_files/xyz.openbmc_project.State.Boot.PostCode.service b/service_files/xyz.openbmc_project.State.Boot.PostCode.service +new file mode 100644 +index 0000000..67bc43f +--- /dev/null ++++ b/service_files/xyz.openbmc_project.State.Boot.PostCode.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Post code manager ++ ++[Service] ++ExecStart=/usr/bin/env post-code-manager ++SyslogIdentifier=post-code-manager ++Type=dbus ++BusName=xyz.openbmc_project.State.Boot.PostCode ++ ++[Install] ++WantedBy=obmc-standby.target +diff --git a/src/main.cpp b/src/main.cpp +new file mode 100644 +index 0000000..4a74b29 +--- /dev/null ++++ b/src/main.cpp +@@ -0,0 +1,61 @@ ++/* ++// 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. ++*/ ++#include "post_code.hpp" ++ ++int main(int argc, char* argv[]) ++{ ++ int ret = 0; ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Start post code manager service..."); ++ ++ sd_event* event = nullptr; ++ ret = sd_event_default(&event); ++ if (ret < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error creating a default sd_event handler"); ++ return ret; ++ } ++ EventPtr eventP{event}; ++ event = nullptr; ++ ++ sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); ++ sdbusplus::server::manager_t m{bus, DBUS_OBJECT_NAME}; ++ ++ bus.request_name(DBUS_INTF_NAME); ++ ++ PostCode postCode{bus, DBUS_OBJECT_NAME, eventP}; ++ ++ try ++ { ++ bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL); ++ ret = sd_event_loop(eventP.get()); ++ if (ret < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error occurred during the sd_event_loop", ++ phosphor::logging::entry("RET=%d", ret)); ++ } ++ } ++ catch (std::exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return -1; ++ } ++ return 0; ++ ++} +diff --git a/src/post_code.cpp b/src/post_code.cpp +new file mode 100644 +index 0000000..983eeee +--- /dev/null ++++ b/src/post_code.cpp +@@ -0,0 +1,109 @@ ++/* ++// 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. ++*/ ++#include "post_code.hpp" ++std::vector<uint64_t> PostCode::getPostCodes(uint16_t index) ++{ ++ std::vector<uint64_t> codes; ++ ++ if (currentBootCycleIndex() == index) ++ return postCodes; ++ deserializePostCodes(fs::path(strPostCodeListPath + std::to_string(index)), codes); ++ return codes; ++} ++void PostCode::savePostCodes(uint64_t code) ++{ ++ postCodes.push_back(code); ++ serialize(fs::path(PostCodeListPath)); ++ return; ++} ++ ++fs::path PostCode::serialize(const std::string& path) ++{ ++ try ++ { ++ uint16_t index = currentBootCycleIndex(); ++ fs::path fullPath(path + strCurrentBootCycleIndexName); ++ std::ofstream os(fullPath.c_str(), std::ios::binary); ++ cereal::JSONOutputArchive oarchive(os); ++ oarchive(index); ++ ++ std::ofstream osPostCodes((path + std::to_string(currentBootCycleIndex())).c_str(), std::ios::binary); ++ cereal::JSONOutputArchive oarchivePostCodes(osPostCodes); ++ oarchivePostCodes(postCodes); ++ ++ return path; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ } ++} ++ ++bool PostCode::deserialize(const fs::path& path, uint16_t& index) ++{ ++ try ++ { ++ if (fs::exists(path)) ++ { ++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); ++ cereal::JSONInputArchive iarchive(is); ++ iarchive(index); ++ return true; ++ } ++ return false; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return false; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ return false; ++ } ++ ++ return false; ++} ++ ++bool PostCode::deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes) ++{ ++ try ++ { ++ if (fs::exists(path)) ++ { ++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); ++ cereal::JSONInputArchive iarchive(is); ++ iarchive(codes); ++ return true; ++ } ++ return false; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return false; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ return false; ++ } ++ ++ return false; ++} +-- +2.19.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb new file mode 100644 index 000000000..8f2ead18a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb @@ -0,0 +1,34 @@ +SUMMARY = "Phosphor post code manager" +DESCRIPTION = "Post Code Manager" + +SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git" +SRCREV = "7f50dcaa6feb66cf5307b8a0e4742a36a50eed29" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +inherit cmake pkgconfig systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.State.Boot.PostCode.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += "file://0001-Implement-post-code-manager.patch" 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..6d614590d --- /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://git@github.com/Intel-BMC/provingground;protocol=ssh" + +inherit cmake systemd +DEPENDS = "boost sdbusplus" + +PV = "0.1+git${SRCPV}" +SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10" + +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/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..5c2879d8f --- /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,1648 @@ +From 726be648df955f5ae94f34391adc0e88f6956345 Mon Sep 17 00:00:00 2001 +From: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Date: Mon, 2 Jul 2018 19:23:25 -0700 +Subject: [PATCH] Added suport for multiple user manager services + +Support added for SSSD service implementation + +Signed-off-by: Alberto Salazar Perez <alberto.salazar.perez@intel.com> +Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 5 +- + mainapp.cpp | 89 ++++++- + user_mgr.cpp | 293 +++------------------ + user_mgr.hpp | 9 +- + user_service.cpp | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + user_service.hpp | 233 +++++++++++++++++ + 6 files changed, 1141 insertions(+), 269 deletions(-) + create mode 100644 user_service.cpp + create mode 100644 user_service.hpp + +diff --git a/Makefile.am b/Makefile.am +index b138aea..288b780 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1,11 +1,12 @@ + sbin_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 c9da030..03c406a 100644 +--- a/mainapp.cpp ++++ b/mainapp.cpp +@@ -14,18 +14,105 @@ + * limitations under the License. + */ + #include <string> ++#include <iostream> ++#include <getopt.h> + #include "user_mgr.hpp" ++#include "user_service.hpp" + #include "config.h" + + // 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 47edf7d..32f3f4c 100644 +--- a/user_mgr.cpp ++++ b/user_mgr.cpp +@@ -14,26 +14,20 @@ + // limitations under the License. + */ + +-#include <shadow.h> +-#include <unistd.h> +-#include <sys/types.h> +-#include <sys/wait.h> ++#include <cstdio> ++ + #include <fstream> + #include <grp.h> + #include <pwd.h> + #include <regex> +-#include <algorithm> +-#include <numeric> +-#include <boost/process/child.hpp> +-#include <boost/process/io.hpp> + #include <boost/algorithm/string/split.hpp> + #include <xyz/openbmc_project/Common/error.hpp> + #include <xyz/openbmc_project/User/Common/error.hpp> + #include <phosphor-logging/log.hpp> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/elog-errors.hpp> ++#include <stdexcept> + #include "shadowlock.hpp" +-#include "file.hpp" + #include "user_mgr.hpp" + #include "users.hpp" + #include "config.h" +@@ -43,12 +37,10 @@ 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; +@@ -94,79 +86,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()) +@@ -293,39 +212,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( +@@ -339,19 +233,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); + +@@ -362,24 +248,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(); +@@ -403,8 +278,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(); +@@ -420,29 +293,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())); +@@ -638,19 +490,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()), +@@ -728,49 +570,8 @@ bool UserMgr::userLockedForFailedAttempt(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; +- } +- // 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))) +- { +- 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() +@@ -781,49 +582,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) +@@ -1018,11 +784,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()) + { +@@ -1077,8 +841,10 @@ void UserMgr::initUserObjects(void) + } + } + +-UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) : +- UserMgrIface(bus, path), AccountPolicyIface(bus, path), bus(bus), path(path) ++UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path, ++ UserService::ServiceType srvc) : ++ UserMgrIface(bus, path), ++ AccountPolicyIface(bus, path), bus(bus), path(path) + { + UserMgrIface::allPrivileges(privMgr); + std::sort(groupsMgr.begin(), groupsMgr.end()); +@@ -1186,6 +952,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) : + } + AccountPolicyIface::accountUnlockTimeout(value32); + } ++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr); + initUserObjects(); + } + +diff --git a/user_mgr.hpp b/user_mgr.hpp +index c78174d..9d9c842 100644 +--- a/user_mgr.hpp ++++ b/user_mgr.hpp +@@ -21,6 +21,7 @@ + #include <unordered_map> + #include <variant> + #include "users.hpp" ++#include "user_service.hpp" + + namespace phosphor + { +@@ -28,8 +29,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; + +@@ -71,8 +70,10 @@ class UserMgr : public UserMgrIface, AccountPolicyIface + * + * @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 +@@ -181,6 +182,8 @@ class UserMgr : public UserMgrIface, AccountPolicyIface + /** @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-callback"}; +diff --git a/user_service.cpp b/user_service.cpp +new file mode 100644 +index 0000000..9bb602c +--- /dev/null ++++ b/user_service.cpp +@@ -0,0 +1,781 @@ ++/* ++// 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 <grp.h> ++#include <pwd.h> ++#include <numeric> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++#include <boost/algorithm/string/split.hpp> ++#include "shadowlock.hpp" ++#include "file.hpp" ++#include "user_service.hpp" ++ ++/* 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; ++ } ++ // 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))) ++ { ++ 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..97a049b +--- /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 <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/User/Common/error.hpp> ++#include <phosphor-logging/log.hpp> ++#include <phosphor-logging/elog.hpp> ++#include <boost/process/child.hpp> ++#include <boost/process/io.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.7.4 + 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..1939e5ad2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SRC_URI = "git://github.com/openbmc/phosphor-user-manager" +SRCREV = "736648e25eb250d1e200cea961fe75bf791f1355" + + +SRC_URI += " \ + file://0005-Added-suport-for-multiple-user-manager-services.patch \ + " 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..950f4932d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb @@ -0,0 +1,35 @@ + +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://${PHOSPHORBASE}/LICENSE;md5=19407077e42b1ba3d653da313f1f5b4e" + +S = "${WORKDIR}" + +inherit cmake +inherit pkgconfig pythonnative + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + 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..5356e95db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp @@ -0,0 +1,258 @@ +/* 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/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, + sdbusplus::message::variant_ns::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-Add-expiredTimerUse-property-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Add-expiredTimerUse-property-support.patch new file mode 100644 index 000000000..54e459245 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Add-expiredTimerUse-property-support.patch @@ -0,0 +1,28 @@ +From efb3c226fc80243729901f675568b2b41142b1f9 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 18 Mar 2019 22:54:41 +0800 +Subject: [PATCH] Add expiredTimerUse property support + +When the timer expired, set expiredTimerUse property as the timer use + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + watchdog.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/watchdog.cpp b/watchdog.cpp +index aed0443..d529746 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -101,6 +101,8 @@ void Watchdog::timeOutHandler() + action = fallback->action; + } + ++ WatchdogInherits::expiredTimerUse(WatchdogInherits::currentTimerUse()); ++ + auto target = actionTargetMap.find(action); + if (target == actionTargetMap.end()) + { +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service new file mode 100644 index 000000000..87a662f7c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service @@ -0,0 +1,14 @@ +[Unit] +Description=Start FRB2 Watchdog%i +Wants=obmc-host-started@%i.target +After=obmc-host-started@%i.target +Wants=mapper-wait@-xyz-openbmc_project-watchdog-host%i.service +After=mapper-wait@-xyz-openbmc_project-watchdog-host%i.service +Conflicts=obmc-host-stop@%i.target +ConditionPathExists=!/run/openbmc/host@%i-on + +[Service] +Restart=always +ExecStart=/usr/bin/env frb2-watchdog +ExecStopPost=/bin/sh -c "busctl call `mapper get-service /xyz/openbmc_project/watchdog/host%i` /xyz/openbmc_project/watchdog/host%i org.freedesktop.DBus.Properties Set ssv xyz.openbmc_project.State.Watchdog Enabled b false" +SyslogIdentifier=obmc-enable-host-watchdog 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..251c2257b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog@.service @@ -0,0 +1,12 @@ +[Unit] +Description=Phosphor %I watchdog + +[Service] +Restart=no +EnvironmentFile={envfiledir}/obmc/watchdog/%I +ExecStart=/usr/bin/env phosphor-watchdog --continue --service=${{SERVICE}} --path=${{DEVPATH}} \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=obmc-host-warm-reset@0.target \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=obmc-host-shutdown@0.target \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=obmc-host-reboot@0.target + +SyslogIdentifier=phosphor-watchdog 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..5f8d53976 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +SRC_URI += "file://0001-Add-expiredTimerUse-property-support.patch" + +# Remove the override to keep service running after DC cycle +SYSTEMD_OVERRIDE_${PN}_remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf" 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..5da053f1d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb @@ -0,0 +1,13 @@ +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/0001-Implement-KVM-in-webui.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch new file mode 100644 index 000000000..85b0f1009 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch @@ -0,0 +1,238 @@ +From 4c63b4e16fbc3b536a437b2ab5d5df5e846e6b83 Mon Sep 17 00:00:00 2001 +From: Ed tanous <ed@tanous.net> +Date: Sun, 22 Apr 2018 10:53:28 -0700 +Subject: [PATCH] Implement KVM in webui + +This patchset adds the infrastructure to allow KVM sessions +through the webui. A websocket capable VNC/RFB connection +on the BMC is needed for KVM sessions. + +To access, navigate to Server control -> KVM. + +Tested: Ran obmc-ikvm on the BMC, added a KVM Handler to + Phosphor Rest Server, and was able to establish a + KVM session in the webui on a Witherspoon. +Change-Id: I7dda5bec41d270ae8d0913697714d4df4ec3a257 +Signed-off-by: Ed Tanous <ed.tanous@intel.com> +Signed-off-by: Gunnar Mills <gmills@us.ibm.com> +--- + app/common/directives/app-navigation.html | 12 +++-- + app/index.js | 1 + + app/server-control/controllers/kvm-controller.html | 5 ++ + app/server-control/controllers/kvm-controller.js | 55 ++++++++++++++++++++++ + app/server-control/index.js | 5 ++ + app/server-control/styles/index.scss | 1 + + app/server-control/styles/kvm.scss | 11 +++++ + package-lock.json | 5 ++ + package.json | 1 + + webpack.config.js | 6 ++- + 10 files changed, 96 insertions(+), 6 deletions(-) + create mode 100644 app/server-control/controllers/kvm-controller.html + create mode 100644 app/server-control/controllers/kvm-controller.js + create mode 100644 app/server-control/styles/kvm.scss + +diff --git a/app/common/directives/app-navigation.html b/app/common/directives/app-navigation.html +index a45a24bcbaa1..e54b23631b3e 100644 +--- a/app/common/directives/app-navigation.html ++++ b/app/common/directives/app-navigation.html +@@ -87,19 +87,21 @@ + <a href="#/server-control/bmc-reboot" tabindex="13" ng-click="closeSubnav()">Reboot BMC</a></li> + <li ng-class="{'active': (path == '/server-control/remote-console')}"> + <a href="#/server-control/remote-console" tabindex="14" ng-click="closeSubnav()">Serial over LAN console</a></li> ++ <li ng-class="{'active': (path == '/server-control/kvm')}"> ++ <a href="#/server-control/kvm" tabindex="15" ng-click="closeSubnav()">KVM</a></li> + </ul> + <ul class="nav__second-level btn-firmware" ng-style="navStyle" ng-class="{opened: (showSubMenu && firstLevel == 'configuration')}"> + <li ng-class="{'active': (path == '/configuration' || path == '/configuration/network')}"> +- <a href="#/configuration/network" tabindex="15" ng-click="closeSubnav()">Network settings</a></li> ++ <a href="#/configuration/network" tabindex="16" ng-click="closeSubnav()">Network settings</a></li> + <li ng-class="{'active': (path == '/configuration' || path == '/configuration/snmp')}"> +- <a href="#/configuration/snmp" tabindex="16" ng-click="closeSubnav()">SNMP settings</a></li> ++ <a href="#/configuration/snmp" tabindex="17" ng-click="closeSubnav()">SNMP settings</a></li> + <li ng-class="{'active': (path == '/configuration' || path == '/configuration/firmware')}"> +- <a href="#/configuration/firmware" tabindex="17" ng-click="closeSubnav()">Firmware</a></li> ++ <a href="#/configuration/firmware" tabindex="18" ng-click="closeSubnav()">Firmware</a></li> + <li ng-class="{'active': (path == '/configuration' || path == '/configuration/date-time')}"> +- <a href="#/configuration/date-time" tabindex="18" ng-click="closeSubnav()">Date and time settings</a></li> ++ <a href="#/configuration/date-time" tabindex="19" ng-click="closeSubnav()">Date and time settings</a></li> + </ul> + <ul class="nav__second-level btn-users" ng-style="navStyle" ng-class="{opened: (showSubMenu && firstLevel == 'users')}"> + <li ng-class="{'active': (path == '/users' || path == '/users/manage-accounts')}"> +- <a href="#/users/manage-accounts" tabindex="19" ng-click="closeSubnav()">Manage user account</a></li> ++ <a href="#/users/manage-accounts" tabindex="20" ng-click="closeSubnav()">Manage user account</a></li> + </ul> + </nav> +diff --git a/app/index.js b/app/index.js +index 38df0e9896f4..a0dde4df96b7 100644 +--- a/app/index.js ++++ b/app/index.js +@@ -69,6 +69,7 @@ import power_operations_controller from './server-control/controllers/power-oper + import power_usage_controller from './server-control/controllers/power-usage-controller.js'; + import remote_console_window_controller from './server-control/controllers/remote-console-window-controller.js'; + import server_led_controller from './server-control/controllers/server-led-controller.js'; ++import kvm_controller from './server-control/controllers/kvm-controller.js'; + + import server_health_index from './server-health/index.js'; + import inventory_overview_controller from './server-health/controllers/inventory-overview-controller.js'; +diff --git a/app/server-control/controllers/kvm-controller.html b/app/server-control/controllers/kvm-controller.html +new file mode 100644 +index 000000000000..40e4d97454bc +--- /dev/null ++++ b/app/server-control/controllers/kvm-controller.html +@@ -0,0 +1,5 @@ ++<div id="noVNC_container"> ++ <div id="noVNC_status_bar"> ++ <div id="noVNC_left_dummy_elem"></div> ++ </div> ++</div> +diff --git a/app/server-control/controllers/kvm-controller.js b/app/server-control/controllers/kvm-controller.js +new file mode 100644 +index 000000000000..a43f169ddf19 +--- /dev/null ++++ b/app/server-control/controllers/kvm-controller.js +@@ -0,0 +1,55 @@ ++/** ++ * Controller for KVM (Kernel-based Virtual Machine) ++ * ++ * @module app/serverControl ++ * @exports kvmController ++ * @name kvmController ++ */ ++ ++import RFB from '@novnc/novnc/core/rfb.js'; ++ ++window.angular && (function(angular) { ++ 'use strict'; ++ ++ angular.module('app.serverControl').controller('kvmController', [ ++ '$scope', '$location', '$log', ++ function($scope, $location, $log) { ++ var rfb; ++ ++ $scope.$on('$destroy', function() { ++ if (rfb) { ++ rfb.disconnect(); ++ } ++ }); ++ ++ function sendCtrlAltDel() { ++ rfb.sendCtrlAltDel(); ++ return false; ++ }; ++ ++ function connected(e) { ++ $log.debug('RFB Connected'); ++ } ++ function disconnected(e) { ++ $log.debug('RFB disconnected'); ++ } ++ ++ var host = $location.host(); ++ var port = $location.port(); ++ var target = ++ angular.element(document.querySelector('#noVNC_container'))[0]; ++ ++ try { ++ rfb = new RFB(target, 'wss://' + host + ':' + port + '/kvm/0', {}); ++ ++ rfb.addEventListener('connect', connected); ++ rfb.addEventListener('disconnect', disconnected); ++ } catch (exc) { ++ $log.error(exc); ++ updateState( ++ null, 'fatal', null, 'Unable to create RFB client -- ' + exc); ++ return; // don't continue trying to connect ++ }; ++ } ++ ]); ++})(angular); +diff --git a/app/server-control/index.js b/app/server-control/index.js +index 739bd1eb8ad9..1b8aad50b702 100644 +--- a/app/server-control/index.js ++++ b/app/server-control/index.js +@@ -48,6 +48,11 @@ window.angular && (function(angular) { + 'controller': 'remoteConsoleWindowController', + authenticated: true + }) ++ .when('/server-control/kvm', { ++ 'template': require('./controllers/kvm-controller.html'), ++ 'controller': 'kvmController', ++ authenticated: true ++ }) + .when('/server-control', { + 'template': + require('./controllers/power-operations-controller.html'), +diff --git a/app/server-control/styles/index.scss b/app/server-control/styles/index.scss +index f6b15ab6afc9..5e8a99580894 100644 +--- a/app/server-control/styles/index.scss ++++ b/app/server-control/styles/index.scss +@@ -3,3 +3,4 @@ + @import "./remote-console.scss"; + @import "./server-led.scss"; + @import "./power-usage.scss"; ++@import "./kvm.scss"; +diff --git a/app/server-control/styles/kvm.scss b/app/server-control/styles/kvm.scss +new file mode 100644 +index 000000000000..2f9e2c0c9f37 +--- /dev/null ++++ b/app/server-control/styles/kvm.scss +@@ -0,0 +1,11 @@ ++ ++.noNVC_shown { ++ display: inline; ++} ++.noVNC_hidden { ++ display: none; ++} ++ ++#noVNC_left_dummy_elem { ++ flex: 1; ++} +diff --git a/package-lock.json b/package-lock.json +index 2d9d31b21968..103c9b84b933 100644 +--- a/package-lock.json ++++ b/package-lock.json +@@ -807,6 +807,11 @@ + "to-fast-properties": "2.0.0" + } + }, ++ "@novnc/novnc": { ++ "version": "1.0.0", ++ "resolved": "https://registry.npmjs.org/@novnc/novnc/-/novnc-1.0.0.tgz", ++ "integrity": "sha1-drDonm+HOMqBVBlbr1uOaoC8kQU=" ++ }, + "@types/node": { + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", +diff --git a/package.json b/package.json +index 35c6b78e320c..fd253cbb2f02 100644 +--- a/package.json ++++ b/package.json +@@ -30,6 +30,7 @@ + "dependencies": { + "angular": "^1.7.5", + "angular-animate": "^1.7.5", ++ "@novnc/novnc": "^1.0.0", + "angular-clipboard": "^1.6.2", + "angular-cookies": "^1.7.5", + "angular-messages": "^1.7.6", +diff --git a/webpack.config.js b/webpack.config.js +index 91cbea8f2952..6c8667cbbc98 100644 +--- a/webpack.config.js ++++ b/webpack.config.js +@@ -113,7 +113,11 @@ module.exports = (env, options) => { + 'base-uri': '\'self\'', + 'object-src': '\'none\'', + 'script-src': ['\'self\''], +- 'style-src': ['\'self\''] ++ 'style-src': ['\'self\''], ++ // KVM requires image buffers from data: payloads, so allow that in ++ // img-src ++ // https://stackoverflow.com/questions/18447970/content-security-policy-data-not-working-for-base64-images-in-chrome-28 ++ 'img-src': ['\'self\'', 'data:'], + }), + new MiniCssExtractPlugin(), + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch new file mode 100644 index 000000000..31d810cb6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch @@ -0,0 +1,68 @@ +From 5a3750377629725890f949d68e7e0ba7d4752825 Mon Sep 17 00:00:00 2001 +From: Mirage Su <mirage.su@mic.com.tw> +Date: Fri, 8 Mar 2019 17:12:46 +0800 +Subject: [PATCH] Fix some page keeps loading on IE11 + +--- + app/index.js | 1 + + package-lock.json | 19 +++++++++++++++++++ + package.json | 1 + + 3 files changed, 21 insertions(+) + mode change 100644 => 100755 package-lock.json + +diff --git a/app/index.js b/app/index.js +index c9fed83..c51203e 100644 +--- a/app/index.js ++++ b/app/index.js +@@ -8,6 +8,7 @@ + */ + import 'angular/angular-csp.css'; + import 'bootstrap/dist/css/bootstrap.css'; ++import 'babel-polyfill'; + + import angular from 'angular'; + import angular_animate from 'angular-animate'; +diff --git a/package-lock.json b/package-lock.json +old mode 100644 +new mode 100755 +index 2d9d31b..61e9787 +--- a/package-lock.json ++++ b/package-lock.json +@@ -1500,6 +1500,25 @@ + "babel-runtime": "6.26.0" + } + }, ++ "babel-polyfill": { ++ "version": "6.26.0", ++ "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", ++ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", ++ "dev": true, ++ "requires": { ++ "babel-runtime": "^6.26.0", ++ "core-js": "^2.5.0", ++ "regenerator-runtime": "^0.10.5" ++ }, ++ "dependencies": { ++ "regenerator-runtime": { ++ "version": "0.10.5", ++ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", ++ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", ++ "dev": true ++ } ++ } ++ }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", +diff --git a/package.json b/package.json +index 35c6b78..1bdf934 100644 +--- a/package.json ++++ b/package.json +@@ -50,6 +50,7 @@ + "autoprefixer": "9.1.5", + "babel-core": "6.26.3", + "babel-loader": "8.0.2", ++ "babel-polyfill": "^6.26.0", + "compression-webpack-plugin": "2.0.0", + "copy-webpack-plugin": "4.5.2", + "csp-html-webpack-plugin": "^2.5.0", 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..1543a6249 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json @@ -0,0 +1,8 @@ +{ + "customKeyEnable": true, + "keyType" : "VT100+", + "customConsoleDisplaySize": { + "width": 100, + "height": 32 + } +} 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..9caa37767 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend @@ -0,0 +1,13 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +#SRC_URI = "git://github.com/openbmc/phosphor-webui.git" +SRCREV = "a2e36e0f479d1a9fa2b6d26448d5e070aea7259b" + +SRC_URI += "file://0001-Implement-KVM-in-webui.patch \ + file://config.json \ + file://0007-Fix-some-page-keeps-loading-on-IE11.patch \ + " + +do_compile_prepend() { + cp -r ${WORKDIR}/config.json ${S}/ +} |