From f78c67a2c007121d3e590a86bdf507016b6d398e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Kr=C3=B3lik?= <66667989+Damian-Nordic@users.noreply.github.com> Date: Tue, 16 Aug 2022 03:43:51 +0200 Subject: [PATCH] [nrfconnect] Improve SoftwareUpdateCompleted boot reason detection (#21851) The existing code relies on a specific bootloader mode to detect that the last reboot was due to software update. This method will not work correctly if a user chooses a different bootloader mode, or clears the "tentative" flag in the current firmware image before the diagnostic data provider is initialized. Store the software reboot reason explicitly in one of the retention registers on nRF SOCs. Signed-off-by: Damian Krolik Signed-off-by: Damian Krolik --- .../Zephyr/DiagnosticDataProviderImpl.cpp | 11 ++- src/platform/nrfconnect/BUILD.gn | 2 + .../nrfconnect/OTAImageProcessorImpl.cpp | 5 +- src/platform/nrfconnect/Reboot.cpp | 85 +++++++++++++++++++ src/platform/nrfconnect/Reboot.h | 35 ++++++++ 5 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 src/platform/nrfconnect/Reboot.cpp create mode 100644 src/platform/nrfconnect/Reboot.h diff --git a/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp b/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp index 6aebf3d2c8a583..6fac30482f6251 100644 --- a/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp +++ b/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp @@ -31,7 +31,9 @@ #include #include -#ifdef CONFIG_MCUBOOT_IMG_MANAGER +#if CHIP_DEVICE_LAYER_TARGET_NRFCONNECT +#include +#elif defined(CONFIG_MCUBOOT_IMG_MANAGER) #include #endif @@ -88,7 +90,12 @@ BootReasonType DetermineBootReason() if (reason & RESET_SOFTWARE) { -#ifdef CONFIG_MCUBOOT_IMG_MANAGER +#if CHIP_DEVICE_LAYER_TARGET_NRFCONNECT + if (GetSoftwareRebootReason() == SoftwareRebootReason::kSoftwareUpdate) + { + return BootReasonType::kSoftwareUpdateCompleted; + } +#elif defined(CONFIG_MCUBOOT_IMG_MANAGER) if (mcuboot_swap_type() == BOOT_SWAP_TYPE_REVERT) { return BootReasonType::kSoftwareUpdateCompleted; diff --git a/src/platform/nrfconnect/BUILD.gn b/src/platform/nrfconnect/BUILD.gn index 928c3c045b4725..3af24f2a72d0b5 100644 --- a/src/platform/nrfconnect/BUILD.gn +++ b/src/platform/nrfconnect/BUILD.gn @@ -46,6 +46,8 @@ static_library("nrfconnect") { "InetPlatformConfig.h", "KeyValueStoreManagerImpl.h", "PlatformManagerImpl.h", + "Reboot.cpp", + "Reboot.h", "SystemPlatformConfig.h", ] diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index b558906258e994..bb8f846d8d900c 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -17,6 +17,8 @@ #include "OTAImageProcessorImpl.h" +#include "Reboot.h" + #include #include #include @@ -35,7 +37,6 @@ #include #include #include -#include #if CONFIG_CHIP_CERTIFICATION_DECLARATION_STORAGE // Cd globals are needed to be accessed from dfu image writer lambdas @@ -123,7 +124,7 @@ CHIP_ERROR OTAImageProcessorImpl::Apply() [](System::Layer *, void * /* context */) { PlatformMgr().HandleServerShuttingDown(); k_msleep(CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS); - sys_reboot(SYS_REBOOT_WARM); + Reboot(SoftwareRebootReason::kSoftwareUpdate); }, nullptr /* context */); } diff --git a/src/platform/nrfconnect/Reboot.cpp b/src/platform/nrfconnect/Reboot.cpp new file mode 100644 index 00000000000000..5b1b6abdde68ad --- /dev/null +++ b/src/platform/nrfconnect/Reboot.cpp @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * 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 "Reboot.h" + +#include + +#include + +#ifndef CONFIG_ARCH_POSIX +#include +#endif + +namespace chip { +namespace DeviceLayer { + +#ifdef CONFIG_ARCH_POSIX + +void Reboot(SoftwareRebootReason reason) +{ + sys_reboot(SYS_REBOOT_WARM); +} + +SoftwareRebootReason GetSoftwareRebootReason() +{ + return SoftwareRebootReason::kOther; +} + +#else + +using RetainedReason = decltype(nrf_power_gpregret_get(NRF_POWER)); + +constexpr RetainedReason EncodeReason(SoftwareRebootReason reason) +{ + // Set MSB to avoid collission with Zephyr's pre-defined reboot reasons. + constexpr RetainedReason kCustomReasonFlag = 0x80; + + return static_cast(reason) | kCustomReasonFlag; +} + +void Reboot(SoftwareRebootReason reason) +{ + const RetainedReason retainedReason = EncodeReason(reason); + + // The parameter passed to sys_reboot() is retained in GPREGRET (general-purpose + // retention register) on nRF52 SOC family, but nRF53 ignores the parameter, so + // set it manually. + +#ifdef CONFIG_SOC_SERIES_NRF53X + nrf_power_gpregret_set(NRF_POWER, retainedReason); +#endif + + sys_reboot(retainedReason); +} + +SoftwareRebootReason GetSoftwareRebootReason() +{ + switch (nrf_power_gpregret_get(NRF_POWER)) + { + case EncodeReason(SoftwareRebootReason::kSoftwareUpdate): + nrf_power_gpregret_set(NRF_POWER, 0); + return SoftwareRebootReason::kSoftwareUpdate; + default: + return SoftwareRebootReason::kOther; + } +} + +#endif + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nrfconnect/Reboot.h b/src/platform/nrfconnect/Reboot.h new file mode 100644 index 00000000000000..09f5493ebf17ad --- /dev/null +++ b/src/platform/nrfconnect/Reboot.h @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * 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 + +namespace chip { +namespace DeviceLayer { + +enum class SoftwareRebootReason : uint8_t +{ + kSoftwareUpdate, + kOther +}; + +[[noreturn]] void Reboot(SoftwareRebootReason reason); +SoftwareRebootReason GetSoftwareRebootReason(); + +} // namespace DeviceLayer +} // namespace chip