Reboot File Handling #154

Merged
meierj merged 27 commits from mueller/reboot-file-handling into develop 2022-03-01 17:24:27 +01:00
10 changed files with 607 additions and 96 deletions
Showing only changes of commit 3a6c7e3183 - Show all commits

View File

@ -170,15 +170,15 @@ void Q7STestTask::testProtHandler() {
bool opPerformed = false; bool opPerformed = false;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
// If any chips are unlocked, lock them here // If any chips are unlocked, lock them here
result = coreController->setBootCopyProtection( result = coreController->setBootCopyProtection(xsc::Chip::ALL_CHIP, xsc::Copy::ALL_COPY, true,
CoreController::Chip::ALL_CHIP, CoreController::Copy::ALL_COPY, true, opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
// unlock own copy // unlock own copy
result = coreController->setBootCopyProtection( result = coreController->setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, false,
CoreController::Chip::SELF_CHIP, CoreController::Copy::SELF_COPY, false, opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -191,8 +191,8 @@ void Q7STestTask::testProtHandler() {
} }
// lock own copy // lock own copy
result = coreController->setBootCopyProtection( result = coreController->setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, true,
CoreController::Chip::SELF_CHIP, CoreController::Copy::SELF_COPY, true, opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -205,8 +205,8 @@ void Q7STestTask::testProtHandler() {
} }
// unlock specific copy // unlock specific copy
result = coreController->setBootCopyProtection( result = coreController->setBootCopyProtection(xsc::Chip::CHIP_1, xsc::Copy::COPY_1, false,
CoreController::Chip::CHIP_1, CoreController::Copy::COPY_1, false, opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -219,8 +219,8 @@ void Q7STestTask::testProtHandler() {
} }
// lock specific copy // lock specific copy
result = coreController->setBootCopyProtection( result = coreController->setBootCopyProtection(xsc::Chip::CHIP_1, xsc::Copy::COPY_1, true,
CoreController::Chip::CHIP_1, CoreController::Copy::COPY_1, true, opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }

View File

@ -1,5 +1,7 @@
#include "CoreController.h" #include "CoreController.h"
#include <fsfw/events/EventManager.h>
#include "OBSWConfig.h" #include "OBSWConfig.h"
#include "OBSWVersion.h" #include "OBSWVersion.h"
#include "fsfw/FSFWVersion.h" #include "fsfw/FSFWVersion.h"
@ -20,8 +22,8 @@
#include "bsp_q7s/memory/SdCardManager.h" #include "bsp_q7s/memory/SdCardManager.h"
#include "bsp_q7s/memory/scratchApi.h" #include "bsp_q7s/memory/scratchApi.h"
CoreController::Chip CoreController::CURRENT_CHIP = Chip::NO_CHIP; xsc::Chip CoreController::CURRENT_CHIP = xsc::Chip::NO_CHIP;
CoreController::Copy CoreController::CURRENT_COPY = Copy::NO_COPY; xsc::Copy CoreController::CURRENT_COPY = xsc::Copy::NO_COPY;
CoreController::CoreController(object_id_t objectId) CoreController::CoreController(object_id_t objectId)
: ExtendedControllerBase(objectId, objects::NO_OBJECT, 5), opDivider(5) { : ExtendedControllerBase(objectId, objects::NO_OBJECT, 5), opDivider(5) {
@ -57,6 +59,7 @@ ReturnValue_t CoreController::handleCommandMessage(CommandMessage *message) {
void CoreController::performControlOperation() { void CoreController::performControlOperation() {
performWatchdogControlOperation(); performWatchdogControlOperation();
sdStateMachine(); sdStateMachine();
performRebootFileHandling(false);
} }
ReturnValue_t CoreController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, ReturnValue_t CoreController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
@ -77,6 +80,8 @@ ReturnValue_t CoreController::initialize() {
} }
sdStateMachine(); sdStateMachine();
triggerEvent(REBOOT_SW, CURRENT_CHIP, CURRENT_COPY);
return ExtendedControllerBase::initialize(); return ExtendedControllerBase::initialize();
} }
@ -102,6 +107,59 @@ ReturnValue_t CoreController::initializeAfterTaskCreation() {
return result; return result;
} }
ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) {
switch (actionId) {
case (LIST_DIRECTORY_INTO_FILE): {
return actionListDirectoryIntoFile(actionId, commandedBy, data, size);
}
case (SWITCH_REBOOT_FILE_HANDLING): {
if (size < 1) {
return HasActionsIF::INVALID_PARAMETERS;
}
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
// Disable the reboot file mechanism
parseRebootFile(path, rebootFile);
if (data[0] == 0) {
rebootFile.enabled = false;
rewriteRebootFile(rebootFile);
} else if (data[0] == 1) {
rebootFile.enabled = true;
rewriteRebootFile(rebootFile);
} else {
return HasActionsIF::INVALID_PARAMETERS;
}
return HasActionsIF::EXECUTION_FINISHED;
}
case (RESET_ALL_REBOOT_COUNTERS): {
resetRebootCount(xsc::ALL_CHIP, xsc::ALL_COPY);
return HasActionsIF::EXECUTION_FINISHED;
}
case (RESET_REBOOT_COUNTER_00): {
resetRebootCount(xsc::CHIP_0, xsc::COPY_0);
return HasActionsIF::EXECUTION_FINISHED;
}
case (RESET_REBOOT_COUNTER_01): {
resetRebootCount(xsc::CHIP_0, xsc::COPY_1);
return HasActionsIF::EXECUTION_FINISHED;
}
case (RESET_REBOOT_COUNTER_10): {
resetRebootCount(xsc::CHIP_1, xsc::COPY_0);
return HasActionsIF::EXECUTION_FINISHED;
}
case (RESET_REBOOT_COUNTER_11): {
resetRebootCount(xsc::CHIP_1, xsc::COPY_1);
return HasActionsIF::EXECUTION_FINISHED;
}
case (REBOOT_OBC): {
return actionPerformReboot(data, size);
}
default: {
return HasActionsIF::INVALID_ACTION_ID;
}
}
}
ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode, ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) { uint32_t *msToReachTheMode) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -500,21 +558,6 @@ ReturnValue_t CoreController::sdCardSetup(sd::SdCard sdCard, sd::SdState targetS
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) {
switch (actionId) {
case (LIST_DIRECTORY_INTO_FILE): {
return actionListDirectoryIntoFile(actionId, commandedBy, data, size);
}
case (REBOOT_OBC): {
return actionPerformReboot(data, size);
}
default: {
return HasActionsIF::INVALID_ACTION_ID;
}
}
}
ReturnValue_t CoreController::sdColdRedundantBlockingInit() { ReturnValue_t CoreController::sdColdRedundantBlockingInit() {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
@ -689,7 +732,7 @@ ReturnValue_t CoreController::actionListDirectoryIntoFile(ActionId_t actionId,
ReturnValue_t CoreController::initBootCopy() { ReturnValue_t CoreController::initBootCopy() {
if (not std::filesystem::exists(CURR_COPY_FILE)) { if (not std::filesystem::exists(CURR_COPY_FILE)) {
// Thils file is created by the systemd service eive-early-config so this should // This file is created by the systemd service eive-early-config so this should
// not happen normally // not happen normally
std::string cmd = "xsc_boot_copy > " + std::string(CURR_COPY_FILE); std::string cmd = "xsc_boot_copy > " + std::string(CURR_COPY_FILE);
int result = std::system(cmd.c_str()); int result = std::system(cmd.c_str());
@ -697,22 +740,18 @@ ReturnValue_t CoreController::initBootCopy() {
utility::handleSystemError(result, "CoreController::initBootCopy"); utility::handleSystemError(result, "CoreController::initBootCopy");
} }
} }
std::ifstream file(CURR_COPY_FILE);
std::string line; getCurrentBootCopy(CURRENT_CHIP, CURRENT_COPY);
std::getline(file, line);
std::istringstream iss(line);
int value = 0;
iss >> value;
CURRENT_CHIP = static_cast<Chip>(value);
iss >> value;
CURRENT_COPY = static_cast<Copy>(value);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void CoreController::getCurrentBootCopy(Chip &chip, Copy &copy) { void CoreController::getCurrentBootCopy(xsc::Chip &chip, xsc::Copy &copy) {
xsc_libnor_chip_t xscChip;
xsc_libnor_copy_t xscCopy;
xsc_boot_get_chip_copy(&xscChip, &xscCopy);
// Not really thread-safe but it does not need to be // Not really thread-safe but it does not need to be
chip = CURRENT_CHIP; chip = static_cast<xsc::Chip>(xscChip);
copy = CURRENT_COPY; copy = static_cast<xsc::Copy>(xscCopy);
} }
ReturnValue_t CoreController::initWatchdogFifo() { ReturnValue_t CoreController::initWatchdogFifo() {
@ -759,8 +798,8 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_0); SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_0);
SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_1); SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_1);
// If any boot copies are unprotected // If any boot copies are unprotected
ReturnValue_t retval = ReturnValue_t retval = setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, true,
setBootCopyProtection(Chip::SELF_CHIP, Copy::SELF_COPY, true, protOpPerformed, false); protOpPerformed, false);
if (retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) { if (retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) {
sif::info << "Running slot was writeprotected before reboot" << std::endl; sif::info << "Running slot was writeprotected before reboot" << std::endl;
} }
@ -771,7 +810,7 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
} }
return HasActionsIF::EXECUTION_FINISHED; return HasActionsIF::EXECUTION_FINISHED;
} }
if (size < 3) { if (size < 3 or (data[1] > 1 or data[2] > 1)) {
return HasActionsIF::INVALID_PARAMETERS; return HasActionsIF::INVALID_PARAMETERS;
} }
#if OBSW_VERBOSE_LEVEL >= 1 #if OBSW_VERBOSE_LEVEL >= 1
@ -782,21 +821,53 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
// Check that the target chip and copy is writeprotected first // Check that the target chip and copy is writeprotected first
generateChipStateFile(); generateChipStateFile();
// If any boot copies are unprotected, protect them here // If any boot copies are unprotected, protect them here
ReturnValue_t retval = setBootCopyProtection( auto tgtChip = static_cast<xsc::Chip>(data[1]);
static_cast<Chip>(data[1]), static_cast<Copy>(data[2]), true, protOpPerformed, false); auto tgtCopy = static_cast<xsc::Copy>(data[2]);
ReturnValue_t retval =
setBootCopyProtection(static_cast<xsc::Chip>(data[1]), static_cast<xsc::Copy>(data[2]), true,
protOpPerformed, false);
if (retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) { if (retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) {
sif::info << "Target slot was writeprotected before reboot" << std::endl; sif::info << "Target slot was writeprotected before reboot" << std::endl;
} }
// The second byte in data is the target chip, the third byte is the target copy switch (tgtChip) {
std::string cmdString = case (xsc::Chip::CHIP_0): {
"xsc_boot_copy " + std::to_string(data[1]) + " " + std::to_string(data[2]); switch (tgtCopy) {
int result = std::system(cmdString.c_str()); case (xsc::Copy::COPY_0): {
if (result != 0) { xsc_boot_copy(XSC_LIBNOR_CHIP_0, XSC_LIBNOR_COPY_NOMINAL);
utility::handleSystemError(result, "CoreController::executeAction"); break;
return HasReturnvaluesIF::RETURN_FAILED; }
case (xsc::Copy::COPY_1): {
xsc_boot_copy(XSC_LIBNOR_CHIP_0, XSC_LIBNOR_COPY_GOLD);
break;
}
default: {
break;
}
}
break;
}
case (xsc::Chip::CHIP_1): {
switch (tgtCopy) {
case (xsc::Copy::COPY_0): {
xsc_boot_copy(XSC_LIBNOR_CHIP_1, XSC_LIBNOR_COPY_NOMINAL);
break;
}
case (xsc::Copy::COPY_1): {
xsc_boot_copy(XSC_LIBNOR_CHIP_1, XSC_LIBNOR_COPY_GOLD);
break;
}
default: {
break;
}
}
break;
}
default:
break;
} }
return HasActionsIF::EXECUTION_FINISHED; return HasReturnvaluesIF::RETURN_FAILED;
} }
CoreController::~CoreController() {} CoreController::~CoreController() {}
@ -850,8 +921,8 @@ ReturnValue_t CoreController::generateChipStateFile() {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t CoreController::setBootCopyProtection(Chip targetChip, Copy targetCopy, bool protect, ReturnValue_t CoreController::setBootCopyProtection(xsc::Chip targetChip, xsc::Copy targetCopy,
bool &protOperationPerformed, bool protect, bool &protOperationPerformed,
bool updateProtFile) { bool updateProtFile) {
bool allChips = false; bool allChips = false;
bool allCopies = false; bool allCopies = false;
@ -860,14 +931,14 @@ ReturnValue_t CoreController::setBootCopyProtection(Chip targetChip, Copy target
protOperationPerformed = false; protOperationPerformed = false;
switch (targetChip) { switch (targetChip) {
case (Chip::ALL_CHIP): { case (xsc::Chip::ALL_CHIP): {
allChips = true; allChips = true;
break; break;
} }
case (Chip::NO_CHIP): { case (xsc::Chip::NO_CHIP): {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
case (Chip::SELF_CHIP): { case (xsc::Chip::SELF_CHIP): {
selfChip = true; selfChip = true;
targetChip = CURRENT_CHIP; targetChip = CURRENT_CHIP;
break; break;
@ -877,14 +948,14 @@ ReturnValue_t CoreController::setBootCopyProtection(Chip targetChip, Copy target
} }
} }
switch (targetCopy) { switch (targetCopy) {
case (Copy::ALL_COPY): { case (xsc::Copy::ALL_COPY): {
allCopies = true; allCopies = true;
break; break;
} }
case (Copy::NO_COPY): { case (xsc::Copy::NO_COPY): {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
case (Copy::SELF_COPY): { case (xsc::Copy::SELF_COPY): {
selfCopy = true; selfCopy = true;
targetCopy = CURRENT_COPY; targetCopy = CURRENT_COPY;
break; break;
@ -907,10 +978,10 @@ ReturnValue_t CoreController::setBootCopyProtection(Chip targetChip, Copy target
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
int CoreController::handleBootCopyProtAtIndex(Chip targetChip, Copy targetCopy, bool protect, int CoreController::handleBootCopyProtAtIndex(xsc::Chip targetChip, xsc::Copy targetCopy,
bool &protOperationPerformed, bool selfChip, bool protect, bool &protOperationPerformed,
bool selfCopy, bool allChips, bool allCopies, bool selfChip, bool selfCopy, bool allChips,
uint8_t arrIdx) { bool allCopies, uint8_t arrIdx) {
bool currentProt = protArray[arrIdx]; bool currentProt = protArray[arrIdx];
std::ostringstream oss; std::ostringstream oss;
bool performOp = false; bool performOp = false;
@ -923,22 +994,22 @@ int CoreController::handleBootCopyProtAtIndex(Chip targetChip, Copy targetCopy,
return 1; return 1;
} }
} }
Chip currentChip; xsc::Chip currentChip;
Copy currentCopy; xsc::Copy currentCopy;
oss << "writeprotect "; oss << "writeprotect ";
if (arrIdx == 0 or arrIdx == 1) { if (arrIdx == 0 or arrIdx == 1) {
oss << "0 "; oss << "0 ";
currentChip = Chip::CHIP_0; currentChip = xsc::Chip::CHIP_0;
} else { } else {
oss << "1 "; oss << "1 ";
currentChip = Chip::CHIP_1; currentChip = xsc::Chip::CHIP_1;
} }
if (arrIdx == 0 or arrIdx == 2) { if (arrIdx == 0 or arrIdx == 2) {
oss << "0 "; oss << "0 ";
currentCopy = Copy::COPY_0; currentCopy = xsc::Copy::COPY_0;
} else { } else {
oss << "1 "; oss << "1 ";
currentCopy = Copy::COPY_1; currentCopy = xsc::Copy::COPY_1;
} }
if (protect) { if (protect) {
oss << "1"; oss << "1";
@ -1033,29 +1104,29 @@ ReturnValue_t CoreController::handleProtInfoUpdateLine(std::string nextLine) {
uint8_t wordIdx = 0; uint8_t wordIdx = 0;
uint8_t arrayIdx = 0; uint8_t arrayIdx = 0;
istringstream iss(nextLine); istringstream iss(nextLine);
Chip currentChip = Chip::CHIP_0; xsc::Chip currentChip = xsc::Chip::CHIP_0;
Copy currentCopy = Copy::COPY_0; xsc::Copy currentCopy = xsc::Copy::COPY_0;
while (iss >> word) { while (iss >> word) {
if (wordIdx == 1) { if (wordIdx == 1) {
currentChip = static_cast<Chip>(stoi(word)); currentChip = static_cast<xsc::Chip>(stoi(word));
} }
if (wordIdx == 3) { if (wordIdx == 3) {
currentCopy = static_cast<Copy>(stoi(word)); currentCopy = static_cast<xsc::Copy>(stoi(word));
} }
if (wordIdx == 3) { if (wordIdx == 3) {
if (currentChip == Chip::CHIP_0) { if (currentChip == xsc::Chip::CHIP_0) {
if (currentCopy == Copy::COPY_0) { if (currentCopy == xsc::Copy::COPY_0) {
arrayIdx = 0; arrayIdx = 0;
} else if (currentCopy == Copy::COPY_1) { } else if (currentCopy == xsc::Copy::COPY_1) {
arrayIdx = 1; arrayIdx = 1;
} }
} }
else if (currentChip == Chip::CHIP_1) { else if (currentChip == xsc::Chip::CHIP_1) {
if (currentCopy == Copy::COPY_0) { if (currentCopy == xsc::Copy::COPY_0) {
arrayIdx = 2; arrayIdx = 2;
} else if (currentCopy == Copy::COPY_1) { } else if (currentCopy == xsc::Copy::COPY_1) {
arrayIdx = 3; arrayIdx = 3;
} }
} }
@ -1101,3 +1172,363 @@ void CoreController::performWatchdogControlOperation() {
} }
} }
} }
void CoreController::performRebootFileHandling(bool recreateFile) {
bool sdCardMounted = false;
if (not recreateFile and doPerformRebootFileHandling) {
sdCardMounted = sdcMan->isSdCardMounted(sdInfo.pref);
}
if ((doPerformRebootFileHandling and sdCardMounted) or recreateFile) {
using namespace std;
if (recreateFile) {
#if OBSW_VERBOSE_LEVEL >= 1
sif::info << "CoreController::performRebootFileHandling: Recreating reboot file" << std::endl;
#endif
}
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
if (not std::filesystem::exists(path) or recreateFile) {
rebootFile.enabled = true;
rebootFile.img00Cnt = 0;
rebootFile.img01Cnt = 0;
rebootFile.img10Cnt = 0;
rebootFile.img11Cnt = 0;
rebootFile.lastChip = xsc::Chip::CHIP_0;
rebootFile.lastCopy = xsc::Copy::COPY_0;
rebootFile.bootFlag = false;
rewriteRebootFile(rebootFile);
} else {
if (not parseRebootFile(path, rebootFile)) {
performRebootFileHandling(true);
}
}
if (rebootFile.bootFlag) {
// Trigger event to inform ground that a reboot was triggered
uint32_t p1 = rebootFile.lastChip << 16 | rebootFile.lastCopy;
uint32_t p2 = rebootFile.img00Cnt << 24 | rebootFile.img01Cnt << 16 |
rebootFile.img10Cnt << 8 | rebootFile.img11Cnt;
triggerEvent(REBOOT_MECHANISM_TRIGGERED, p1, p2);
// Clear the boot flag
rebootFile.bootFlag = false;
}
switch (CURRENT_CHIP) {
case (xsc::CHIP_0): {
switch (CURRENT_COPY) {
case (xsc::COPY_0): {
rebootFile.img00Cnt++;
break;
}
case (xsc::COPY_1): {
rebootFile.img01Cnt++;
break;
}
default: {
break;
}
}
break;
}
case (xsc::CHIP_1): {
switch (CURRENT_COPY) {
case (xsc::COPY_0): {
rebootFile.img10Cnt++;
break;
}
case (xsc::COPY_1): {
rebootFile.img11Cnt++;
break;
}
default: {
break;
}
}
break;
}
default: {
break;
}
}
if (CURRENT_CHIP == xsc::CHIP_0 and CURRENT_COPY == xsc::COPY_0) {
}
if (rebootFile.relevantBootCnt > rebootFile.maxCount) {
// Reboot to other image
bool doReboot = false;
determineAndExecuteReboot(rebootFile, doReboot, rebootFile.lastChip, rebootFile.lastCopy);
if (doReboot) {
rebootFile.bootFlag = true;
#if OBSW_VERBOSE_LEVEL >= 1
sif::info << "Boot counter for image " << CURRENT_CHIP << " " << CURRENT_COPY
<< "too high. Rebooting to " << rebootFile.lastChip << " " << rebootFile.lastCopy
<< std::endl;
#endif
rewriteRebootFile(rebootFile);
xsc_boot_copy(static_cast<xsc_libnor_chip_t>(rebootFile.lastChip),
static_cast<xsc_libnor_copy_t>(rebootFile.lastCopy));
}
} else {
rewriteRebootFile(rebootFile);
}
doPerformRebootFileHandling = false;
}
}
void CoreController::determineAndExecuteReboot(RebootFile &rf, bool &needsReboot,
xsc::Chip &tgtChip, xsc::Copy &tgtCopy) {
tgtChip = xsc::CHIP_0;
tgtCopy = xsc::COPY_0;
needsReboot = false;
if ((CURRENT_COPY == xsc::COPY_0) and (CURRENT_CHIP == xsc::CHIP_0) and
(rf.img00Cnt >= rf.maxCount)) {
needsReboot = true;

There might be the unlikely but nevertheless possible case that one of the firmware images is corrupted and all reboot counters except for the counter of the partition containing the corrupted firmware reached the maximum reboot count. I think this could lead in the current configuration to a scenario where the OBSW tries to boot from the partition with the corrupted firmware (because the reboot counter for this image is the only one not set to max reboot counts) but always ends in another image because the Xiphos bootloader prevents booting the corrupted image (according to datasheet performs integrity check by means of a CRC and md5sum).
Just my thoughts on this. Maybe you already considered this scenario.

There might be the unlikely but nevertheless possible case that one of the firmware images is corrupted and all reboot counters except for the counter of the partition containing the corrupted firmware reached the maximum reboot count. I think this could lead in the current configuration to a scenario where the OBSW tries to boot from the partition with the corrupted firmware (because the reboot counter for this image is the only one not set to max reboot counts) but always ends in another image because the Xiphos bootloader prevents booting the corrupted image (according to datasheet performs integrity check by means of a CRC and md5sum). Just my thoughts on this. Maybe you already considered this scenario.
if (rf.img01Cnt >= rf.maxCount) {
if (rf.img10Cnt >= rf.maxCount) {
if (rf.img11Cnt >= rf.maxCount) {
// Can't really do much here. Stay on image
sif::warning << "All reboot counts too high, but already on fallback image" << std::endl;
return;
} else {
tgtChip = xsc::CHIP_1;
tgtCopy = xsc::COPY_1;
}
} else {
tgtChip = xsc::CHIP_0;
tgtCopy = xsc::COPY_1;
}
} else {
tgtCopy = xsc::COPY_1;
}
}
if ((CURRENT_COPY == xsc::COPY_0) and (CURRENT_CHIP == xsc::CHIP_1) and
(rf.img01Cnt >= rf.maxCount)) {
needsReboot = true;
if (rf.img00Cnt >= rf.maxCount) {
if (rf.img10Cnt >= rf.maxCount) {
if (rf.img11Cnt >= rf.maxCount) {
// Reboot to fallback image
} else {
tgtChip = xsc::CHIP_1;
tgtCopy = xsc::COPY_1;
}
} else {
tgtChip = xsc::CHIP_1;
tgtCopy = xsc::COPY_0;
}
} else {
// Reboot on fallback image
}
}
if ((CURRENT_COPY == xsc::COPY_1) and (CURRENT_CHIP == xsc::CHIP_0) and
(rf.img10Cnt >= rf.maxCount)) {
needsReboot = true;
if (rf.img11Cnt >= rf.maxCount) {
if (rf.img00Cnt >= rf.maxCount) {
if (rf.img01Cnt >= rf.maxCount) {
// Reboot to fallback image
} else {
tgtChip = xsc::CHIP_0;
tgtCopy = xsc::COPY_1;
}
} else {
tgtChip = xsc::CHIP_0;
tgtCopy = xsc::COPY_0;
}
} else {
tgtChip = xsc::CHIP_1;
tgtCopy = xsc::COPY_1;
}
}
if ((CURRENT_COPY == xsc::COPY_1) and (CURRENT_CHIP == xsc::CHIP_1) and
(rf.img11Cnt >= rf.maxCount)) {
needsReboot = true;
if (rf.img10Cnt >= rf.maxCount) {
if (rf.img00Cnt >= rf.maxCount) {
if (rf.img01Cnt >= rf.maxCount) {
// Reboot to fallback image
} else {
tgtChip = xsc::CHIP_0;
tgtCopy = xsc::COPY_1;
}
} else {
tgtChip = xsc::CHIP_0;
tgtCopy = xsc::COPY_0;
}
} else {
tgtChip = xsc::CHIP_1;
tgtCopy = xsc::COPY_0;
}
}
}
bool CoreController::parseRebootFile(std::string path, RebootFile &rf) {
using namespace std;
std::string selfMatch;
if (CURRENT_CHIP == xsc::CHIP_0) {
if (CURRENT_COPY == xsc::COPY_0) {
selfMatch = "00";
} else {
selfMatch = "01";
}
} else {
if (CURRENT_COPY == xsc::COPY_0) {
selfMatch = "10";
} else {
selfMatch = "11";
}
}
ifstream file(path);
string word;
string line;
uint8_t lineIdx = 0;
while (std::getline(file, line)) {
istringstream iss(line);
switch (lineIdx) {
case 0: {
iss >> word;
if (word.find("on:") == string::npos) {
// invalid file
return false;
}
iss >> rf.enabled;
break;
}
case 1: {
iss >> word;
if (word.find("maxcnt:") == string::npos) {
return false;
}
iss >> rf.maxCount;
break;
}
case 2: {
iss >> word;
if (word.find("img00:") == string::npos) {
return false;
}
iss >> rf.img00Cnt;
if (word.find(selfMatch) != string::npos) {
rf.relevantBootCnt = rf.img00Cnt;
}
break;
}
case 3: {
iss >> word;
if (word.find("img01:") == string::npos) {
return false;
}
iss >> rf.img01Cnt;
if (word.find(selfMatch) != string::npos) {
rf.relevantBootCnt = rf.img01Cnt;
}
break;
}
case 4: {
iss >> word;
if (word.find("img10:") == string::npos) {
return false;
}
iss >> rf.img10Cnt;
if (word.find(selfMatch) != string::npos) {
rf.relevantBootCnt = rf.img10Cnt;
}
break;
}
case 5: {
iss >> word;
if (word.find("img11:") == string::npos) {
return false;
}
iss >> rf.img11Cnt;
if (word.find(selfMatch) != string::npos) {
rf.relevantBootCnt = rf.img11Cnt;
}
break;
}
case 6: {
iss >> word;
if (word.find("bootflag:") == string::npos) {
return false;
}
iss >> rf.bootFlag;
break;
}
case 7: {
iss >> word;
if (word.find("bootflag:") == string::npos) {
return false;
}
break;
}
case 8: {
iss >> word;
uint8_t copyRaw = 0;
uint8_t chipRaw = 0;
if (word.find("last:") == string::npos) {
return false;
}
iss >> chipRaw;
if (iss.fail()) {
return false;
}
iss >> copyRaw;
if (iss.fail()) {
return false;
}
if (chipRaw > 1 or copyRaw > 1) {
return false;
}
rf.lastChip = static_cast<xsc::Chip>(chipRaw);
rf.lastCopy = static_cast<xsc::Copy>(copyRaw);
}
}
if (iss.fail()) {
return false;
}
lineIdx++;
}
if (lineIdx < 8) {
return false;
}
return true;
}
void CoreController::resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy) {
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
// Disable the reboot file mechanism
parseRebootFile(path, rebootFile);
if (tgtChip == xsc::ALL_CHIP and tgtCopy == xsc::ALL_COPY) {
rebootFile.img00Cnt = 0;
rebootFile.img01Cnt = 0;
rebootFile.img10Cnt = 0;
rebootFile.img11Cnt = 0;
} else {
if (tgtChip == xsc::CHIP_0) {
if (tgtCopy == xsc::COPY_0) {
rebootFile.img00Cnt = 0;
} else {
rebootFile.img01Cnt = 0;
}
} else {
if (tgtCopy == xsc::COPY_0) {
rebootFile.img10Cnt = 0;
} else {
rebootFile.img11Cnt = 0;
}
}
}
rewriteRebootFile(rebootFile);
}
void CoreController::rewriteRebootFile(RebootFile file) {
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
std::ofstream rebootFile(path);
if (rebootFile.is_open()) {
// Initiate reboot file first. Reboot handling will be on on initialization
rebootFile << "on: " << file.enabled << "\nmaxcnt: " << file.maxCount
<< "\nimg00: " << file.img00Cnt << "\nimg01: " << file.img01Cnt
<< "\nimg10: " << file.img10Cnt << "\nimg11: " << file.img11Cnt
<< "\nbootflag: " << file.bootFlag << "\nlast: " << file.lastChip << " "
<< file.lastCopy << "\n";
}
}

View File

@ -2,6 +2,9 @@
#define BSP_Q7S_CORE_CORECONTROLLER_H_ #define BSP_Q7S_CORE_CORECONTROLLER_H_
#include <fsfw/globalfunctions/PeriodicOperationDivider.h> #include <fsfw/globalfunctions/PeriodicOperationDivider.h>
#include <libxiphos.h>
#include <cstddef>
#include "bsp_q7s/memory/SdCardManager.h" #include "bsp_q7s/memory/SdCardManager.h"
#include "events/subsystemIdRanges.h" #include "events/subsystemIdRanges.h"
@ -10,24 +13,64 @@
class Timer; class Timer;
class SdCardManager; class SdCardManager;
namespace xsc {
enum Chip : uint8_t { CHIP_0, CHIP_1, NO_CHIP, SELF_CHIP, ALL_CHIP };
enum Copy : uint8_t { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY };
} // namespace xsc
struct RebootFile {
static constexpr uint8_t DEFAULT_MAX_BOOT_CNT = 10;
bool enabled = false;
size_t maxCount = DEFAULT_MAX_BOOT_CNT;
uint8_t img00Cnt = 0;
uint8_t img01Cnt = 0;
uint8_t img10Cnt = 0;
uint8_t img11Cnt = 0;
uint8_t relevantBootCnt = 0;
bool bootFlag = false;
xsc::Chip lastChip = xsc::Chip::CHIP_0;
xsc::Copy lastCopy = xsc::Copy::COPY_0;
};
class CoreController : public ExtendedControllerBase { class CoreController : public ExtendedControllerBase {
public: public:
enum Chip : uint8_t { CHIP_0, CHIP_1, NO_CHIP, SELF_CHIP, ALL_CHIP }; static xsc::Chip CURRENT_CHIP;
static xsc::Copy CURRENT_COPY;
enum Copy : uint8_t { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY };
static constexpr char CHIP_PROT_SCRIPT[] = "/home/root/scripts/get-chip-prot-status.sh"; static constexpr char CHIP_PROT_SCRIPT[] = "/home/root/scripts/get-chip-prot-status.sh";
static constexpr char CHIP_STATE_FILE[] = "/tmp/chip_prot_status.txt"; static constexpr char CHIP_STATE_FILE[] = "/tmp/chip_prot_status.txt";
static constexpr char CURR_COPY_FILE[] = "/tmp/curr_copy.txt"; static constexpr char CURR_COPY_FILE[] = "/tmp/curr_copy.txt";
static constexpr char VERSION_FILE[] = "/conf/sd_status"; static constexpr char VERSION_FILE[] = "/conf/version.txt";
static constexpr char REBOOT_FILE[] = "/conf/reboot.txt";
static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0; static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0;
static constexpr ActionId_t SWITCH_REBOOT_FILE_HANDLING = 5;
static constexpr ActionId_t RESET_ALL_REBOOT_COUNTERS = 6;
static constexpr ActionId_t RESET_REBOOT_COUNTER_00 = 7;
static constexpr ActionId_t RESET_REBOOT_COUNTER_01 = 8;
static constexpr ActionId_t RESET_REBOOT_COUNTER_10 = 9;
static constexpr ActionId_t RESET_REBOOT_COUNTER_11 = 10;
static constexpr ActionId_t SET_MAX_REBOOT_CNT = 11;
static constexpr ActionId_t REBOOT_OBC = 32; static constexpr ActionId_t REBOOT_OBC = 32;
static constexpr ActionId_t MOUNT_OTHER_COPY = 33; static constexpr ActionId_t MOUNT_OTHER_COPY = 33;
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE;
static constexpr Event ALLOC_FAILURE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM); static constexpr Event ALLOC_FAILURE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
//! [EXPORT] : [COMMENT] Software reboot occured. Can also be a systemd reboot.
//! P1: Current Chip, P2: Current Copy
static constexpr Event REBOOT_SW = event::makeEvent(SUBSYSTEM_ID, 1, severity::MEDIUM);
//! [EXPORT] : [COMMENT] The reboot mechanism was triggered.
//! P1: First 16 bits: Last Chip, Last 16 bits: Last Copy,
//! P2: Each byte is the respective reboot count for the slots
static constexpr Event REBOOT_MECHANISM_TRIGGERED =
event::makeEvent(SUBSYSTEM_ID, 2, severity::MEDIUM);
//! Trying to find a way how to determine that the reboot came from ProASIC3 or PCDU..
static constexpr Event REBOOT_HW = event::makeEvent(SUBSYSTEM_ID, 3, severity::MEDIUM);
CoreController(object_id_t objectId); CoreController(object_id_t objectId);
virtual ~CoreController(); virtual ~CoreController();
@ -48,7 +91,7 @@ class CoreController : public ExtendedControllerBase {
*/ */
static ReturnValue_t generateChipStateFile(); static ReturnValue_t generateChipStateFile();
static ReturnValue_t incrementAllocationFailureCount(); static ReturnValue_t incrementAllocationFailureCount();
static void getCurrentBootCopy(Chip& chip, Copy& copy); static void getCurrentBootCopy(xsc::Chip& chip, xsc::Copy& copy);
ReturnValue_t updateProtInfo(bool regenerateChipStateFile = true); ReturnValue_t updateProtInfo(bool regenerateChipStateFile = true);
@ -63,15 +106,12 @@ class CoreController : public ExtendedControllerBase {
* @param updateProtFile Specify whether the protection info file is updated * @param updateProtFile Specify whether the protection info file is updated
* @return * @return
*/ */
ReturnValue_t setBootCopyProtection(Chip targetChip, Copy targetCopy, bool protect, ReturnValue_t setBootCopyProtection(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect,
bool& protOperationPerformed, bool updateProtFile = true); bool& protOperationPerformed, bool updateProtFile = true);
bool sdInitFinished() const; bool sdInitFinished() const;
private: private:
static Chip CURRENT_CHIP;
static Copy CURRENT_COPY;
// Designated value for rechecking FIFO open // Designated value for rechecking FIFO open
static constexpr int RETRY_FIFO_OPEN = -2; static constexpr int RETRY_FIFO_OPEN = -2;
int watchdogFifoFd = 0; int watchdogFifoFd = 0;
@ -122,6 +162,8 @@ class CoreController : public ExtendedControllerBase {
sd::SdState commandedState = sd::SdState::OFF; sd::SdState commandedState = sd::SdState::OFF;
}; };
SdInfo sdInfo; SdInfo sdInfo;
RebootFile rebootFile = {};
bool doPerformRebootFileHandling = true;
/** /**
* Index 0: Chip 0 Copy 0 * Index 0: Chip 0 Copy 0
@ -152,6 +194,7 @@ class CoreController : public ExtendedControllerBase {
void determinePreferredSdCard(); void determinePreferredSdCard();
void executeNextExternalSdCommand(); void executeNextExternalSdCommand();
void checkExternalSdCommandStatus(); void checkExternalSdCommandStatus();
void performRebootFileHandling(bool recreateFile);
ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy, ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size); const uint8_t* data, size_t size);
@ -160,9 +203,14 @@ class CoreController : public ExtendedControllerBase {
void performWatchdogControlOperation(); void performWatchdogControlOperation();
ReturnValue_t handleProtInfoUpdateLine(std::string nextLine); ReturnValue_t handleProtInfoUpdateLine(std::string nextLine);
int handleBootCopyProtAtIndex(Chip targetChip, Copy targetCopy, bool protect, int handleBootCopyProtAtIndex(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect,
bool& protOperationPerformed, bool selfChip, bool selfCopy, bool& protOperationPerformed, bool selfChip, bool selfCopy,
bool allChips, bool allCopies, uint8_t arrIdx); bool allChips, bool allCopies, uint8_t arrIdx);
void determineAndExecuteReboot(RebootFile& rf, bool& needsReboot, xsc::Chip& tgtChip,
xsc::Copy& tgtCopy);
void resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy);
bool parseRebootFile(std::string path, RebootFile& file);
void rewriteRebootFile(RebootFile file);
}; };
#endif /* BSP_Q7S_CORE_CORECONTROLLER_H_ */ #endif /* BSP_Q7S_CORE_CORECONTROLLER_H_ */

View File

@ -7,6 +7,7 @@
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include "common/config/commonObjects.h"
#include "fsfw/ipc/MutexFactory.h" #include "fsfw/ipc/MutexFactory.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include "linux/utility/utility.h" #include "linux/utility/utility.h"
@ -14,7 +15,7 @@
SdCardManager* SdCardManager::factoryInstance = nullptr; SdCardManager* SdCardManager::factoryInstance = nullptr;
SdCardManager::SdCardManager() : cmdExecutor(256) {} SdCardManager::SdCardManager() : SystemObject(objects::SDC_MANAGER), cmdExecutor(256) {}
SdCardManager::~SdCardManager() {} SdCardManager::~SdCardManager() {}

View File

@ -1,6 +1,7 @@
#ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ #ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_
#define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ #define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_
#include <fsfw/objectmanager/SystemObject.h>
#include <poll.h> #include <poll.h>
#include <array> #include <array>
@ -22,7 +23,7 @@ class MutexIF;
* @brief Manages handling of SD cards like switching them on or off or getting the current * @brief Manages handling of SD cards like switching them on or off or getting the current
* state * state
*/ */
class SdCardManager { class SdCardManager : public SystemObject {
friend class SdCardAccess; friend class SdCardAccess;
public: public:
@ -54,6 +55,7 @@ class SdCardManager {
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FILE_SYSTEM; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FILE_SYSTEM;
static constexpr Event SANITIZATION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW); static constexpr Event SANITIZATION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW);
static constexpr Event MOUNTED_SD_CARD = event::makeEvent(SUBSYSTEM_ID, 1, severity::INFO);
// C++17 does not support constexpr std::string yet // C++17 does not support constexpr std::string yet
static constexpr char SD_0_DEV_NAME[] = "/dev/mmcblk0p1"; static constexpr char SD_0_DEV_NAME[] = "/dev/mmcblk0p1";
@ -183,7 +185,7 @@ class SdCardManager {
/** /**
* @brief Checks if an SD card is mounted * @brief Checks if an SD card is mounted
* *
* @param sdCard The SD crad to check * @param sdCard The SD card to check
* *
* @return true if mounted, otherwise false * @return true if mounted, otherwise false
*/ */

View File

@ -81,8 +81,19 @@ set(CMAKE_PREFIX_PATH
# "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}" # "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}"
) )
set(C_FLAGS
-mcpu=cortex-a9
-mfpu=neon-vfpv3
-mfloat-abi=hard
${COMMON_FLAGS}
-lgpiod
-lxiphos
)
string (REPLACE ";" " " C_FLAGS "${C_FLAGS}")
set(CMAKE_C_FLAGS set(CMAKE_C_FLAGS
"-mcpu=cortex-a9 -mfpu=neon-vfpv3 -mfloat-abi=hard ${COMMON_FLAGS} -lgpiod" ${C_FLAGS}
CACHE STRING "C flags for Q7S" CACHE STRING "C flags for Q7S"
) )
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS

View File

@ -19,6 +19,7 @@ enum: uint8_t {
PLOC_MEMORY_DUMPER = 118, PLOC_MEMORY_DUMPER = 118,
PDEC_HANDLER = 119, PDEC_HANDLER = 119,
STR_HELPER = 120, STR_HELPER = 120,
PL_PCDU_HANDLER = 121,
COMMON_SUBSYSTEM_ID_END COMMON_SUBSYSTEM_ID_END
}; };
} }

1
unittest/rebootLogic/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.0.0)
project(reboot-logic VERSION 0.1.0)
include(CTest)
enable_testing()
add_executable(reboot-logic main.cpp)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

View File

@ -0,0 +1,5 @@
#include <iostream>
int main(int, char**) {
std::cout << "Hello, world!\n";
}