Writeprotection handler in CoreController #87

Merged
meierj merged 13 commits from mueller/writeprotect-handler into develop 2021-08-20 11:08:25 +02:00
2 changed files with 300 additions and 38 deletions
Showing only changes of commit 7fc3285272 - Show all commits

View File

@ -21,12 +21,11 @@
#include <filesystem>
CoreController::Chip CoreController::currentChip = Chip::NO_CHIP;
CoreController::Copy CoreController::currentCopy = Copy::NO_COPY;
CoreController::Chip CoreController::CURRENT_CHIP = Chip::NO_CHIP;
CoreController::Copy CoreController::CURRENT_COPY = Copy::NO_COPY;
CoreController::CoreController(object_id_t objectId):
ExtendedControllerBase(objectId, objects::NO_OBJECT, 5),
opDivider(5) {
ExtendedControllerBase(objectId, objects::NO_OBJECT, 5), opDivider(5) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
try {
result = initWatchdogFifo();
@ -552,6 +551,12 @@ ReturnValue_t CoreController::initializeAfterTaskCreation() {
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "CoreController::initialize: Version initialization failed" << std::endl;
}
// Add script folder to path
char* currentEnvPath = getenv("PATH");
sif::info << currentEnvPath << std::endl;
std::string updatedEnvPath = std::string(currentEnvPath) + ":/home/root/scripts";
setenv("PATH", updatedEnvPath.c_str(), true);
updateProtInfo();
initPrint();
return result;
}
@ -614,7 +619,7 @@ ReturnValue_t CoreController::initVersionFile() {
std::to_string(FSFW_SUBVERSION) + "." + std::to_string(FSFW_REVISION);
std::string systemString = "System: " + unameLine;
std::string mountPrefix = SdCardManager::instance()->getCurrentMountPrefix();
std::string versionFilePath = mountPrefix + "/conf/version.txt";
std::string versionFilePath = mountPrefix + VERSION_FILE;
std::fstream versionFile;
if(not std::filesystem::exists(versionFilePath)) {
@ -731,32 +736,31 @@ ReturnValue_t CoreController::actionListDirectoryIntoFile(ActionId_t actionId,
}
ReturnValue_t CoreController::initBootCopy() {
std::string fileName = "/tmp/curr_copy.txt";
if(not std::filesystem::exists(fileName)) {
if(not std::filesystem::exists(CURR_COPY_FILE)) {
// Thils file is created by the systemd service eive-early-config so this should
// not happen normally
std::string cmd = "xsc_boot_copy > " + fileName;
std::string cmd = "xsc_boot_copy > " + std::string(CURR_COPY_FILE);
int result = std::system(cmd.c_str());
if(result != 0) {
utility::handleSystemError(result, "CoreController::initBootCopy");
}
}
std::ifstream file(fileName);
std::ifstream file(CURR_COPY_FILE);
std::string line;
std::getline(file, line);
std::istringstream iss(line);
int value = 0;
iss >> value;
currentChip = static_cast<Chip>(value);
CURRENT_CHIP = static_cast<Chip>(value);
iss >> value;
currentCopy = static_cast<Copy>(value);
CURRENT_COPY = static_cast<Copy>(value);
return HasReturnvaluesIF::RETURN_OK;
}
void CoreController::getCurrentBootCopy(Chip &chip, Copy &copy) {
// Not really thread-safe but it does not need to be
chip = currentChip;
copy = currentCopy;
chip = CURRENT_CHIP;
copy = CURRENT_COPY;
}
ReturnValue_t CoreController::initWatchdogFifo() {
@ -795,6 +799,7 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
return HasActionsIF::INVALID_PARAMETERS;
}
bool rebootSameBootCopy = data[0];
bool protOpPerformed;
if(rebootSameBootCopy) {
#if OBSW_VERBOSE_LEVEL >= 1
sif::info << "CoreController::actionPerformReboot: Rebooting on current image" << std::endl;
@ -802,6 +807,12 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
// Attempt graceful shutdown by unmounting and switching off SD cards
SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_0);
SdCardManager::instance()->switchOffSdCard(sd::SdCard::SLOT_1);
// If any boot copies are unprotected
ReturnValue_t retval = checkAndSetBootCopyProtection(Chip::SELF_CHIP, Copy::SELF_COPY,
true, protOpPerformed, false);
if(retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) {
sif::info << "Running slot was writeprotected before reboot" << std::endl;
}
int result = std::system("xsc_boot_copy -r");
if(result != 0) {
utility::handleSystemError(result, "CoreController::executeAction");
@ -816,6 +827,16 @@ ReturnValue_t CoreController::actionPerformReboot(const uint8_t *data, size_t si
sif::info << "CoreController::actionPerformReboot: Rebooting on " <<
static_cast<int>(data[1]) << " " << static_cast<int>(data[2]) << std::endl;
#endif
// Check that the target chip and copy is writeprotected first
generateChipStateFile();
// If any boot copies are unprotected, protect them here
ReturnValue_t retval = checkAndSetBootCopyProtection(static_cast<Chip>(data[1]),
static_cast<Copy>(data[2]), true, protOpPerformed, false);
if(retval == HasReturnvaluesIF::RETURN_OK and protOpPerformed) {
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
std::string cmdString = "xsc_boot_copy " + std::to_string(data[1]) + " " +
std::to_string(data[2]);
@ -873,6 +894,209 @@ bool CoreController::sdInitFinished() const {
return sdInfo.initFinished;
}
ReturnValue_t CoreController::generateChipStateFile() {
int result = std::system(CHIP_PROT_SCRIPT);
if(result != 0) {
utility::handleSystemError(result, "CoreController::generateChipStateFile");
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CoreController::checkAndSetBootCopyProtection(Chip targetChip, Copy targetCopy,
bool protect, bool& protOperationPerformed, bool updateProtFile) {
bool allChips = false;
bool allCopies = false;
bool selfChip = false;
bool selfCopy = false;
switch(targetChip) {
case(Chip::ALL_CHIP): {
allChips = true;
break;
}
case(Chip::NO_CHIP): {
return HasReturnvaluesIF::RETURN_OK;
}
case(Chip::SELF_CHIP): {
selfChip = true;
break;
}
default: {
break;
}
}
switch(targetCopy) {
case(Copy::ALL_COPY): {
allCopies = true;
break;
}
case(Copy::NO_COPY): {
return HasReturnvaluesIF::RETURN_OK;
}
case(Copy::SELF_COPY): {
selfCopy = true;
break;
}
default: {
break;
}
}
for(uint8_t arrIdx = 0; arrIdx < 4; arrIdx++) {
bool currentProt = protArray[arrIdx];
std::ostringstream oss;
if(protect == currentProt) {
continue;
}
Chip currentChip;
Copy currentCopy;
oss << "writeprotect ";
if(arrIdx == 0 or arrIdx == 1) {
oss << "0 ";
currentChip = Chip::CHIP_0;
}
else {
oss << "1 ";
currentChip = Chip::CHIP_1;
}
if(arrIdx == 0 or arrIdx == 2) {
oss << "0 ";
currentCopy = Copy::COPY_0;
}
else {
oss << "1 ";
currentCopy = Copy::COPY_1;
}
if(protect) {
oss << "1";
}
else {
oss << "0";
}
int result = 0;
if(allChips and allCopies) {
protOperationPerformed = true;
result = std::system(oss.str().c_str());
}
else if(allChips) {
if((selfCopy and CURRENT_COPY == targetCopy) or
(currentCopy == targetCopy)) {
protOperationPerformed = true;
result = std::system(oss.str().c_str());
}
}
else if(allCopies) {
if((selfChip and CURRENT_COPY == targetCopy) or
(currentChip == targetChip)) {
protOperationPerformed = true;
result = std::system(oss.str().c_str());
}
}
else if(selfChip and (CURRENT_CHIP == targetChip)) {
protOperationPerformed = true;
result = std::system(oss.str().c_str());
}
else if(selfCopy and (CURRENT_COPY == targetCopy)) {
protOperationPerformed = true;
result = std::system(oss.str().c_str());
}
if(result != 0) {
utility::handleSystemError(result, "CoreController::checkAndSetBootCopyProtection");
}
}
if(protOperationPerformed and updateProtFile) {
updateProtInfo();
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CoreController::updateProtInfo(bool regenerateChipStateFile) {
using namespace std;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(regenerateChipStateFile) {
result = generateChipStateFile();
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "CoreController::updateProtInfo: Generating chip state file failed" <<
std::endl;
return result;
}
}
if(not filesystem::exists(CHIP_STATE_FILE)) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ifstream chipStateFile(CHIP_STATE_FILE);
if(not chipStateFile.good()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
string nextLine;
uint8_t lineCounter = 0;
string word;
while(getline(chipStateFile, nextLine)) {
ReturnValue_t result = handleProtInfoUpdateLine(nextLine);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "CoreController::updateProtInfo: Protection info update failed!" <<
std::endl;
return result;
}
++lineCounter;
if(lineCounter > 4) {
sif::warning << "CoreController::checkAndProtectBootCopy: "
"Line counter larger than 4" << std::endl;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CoreController::handleProtInfoUpdateLine(std::string nextLine) {
using namespace std;
string word;
uint8_t wordIdx = 0;
istringstream iss(nextLine);
Chip currentChip;
Copy currentCopy;
while(iss >> word) {
if(wordIdx == 1) {
currentChip = static_cast<Chip>(stoi(word));
}
if(wordIdx == 3) {
currentCopy = static_cast<Copy>(stoi(word));
}
uint8_t arrayIdx = 0;
if(currentChip == Chip::CHIP_0) {
if(currentCopy == Copy::COPY_1) {
arrayIdx = 1;
}
else if(currentCopy != Copy::COPY_0) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
else if(currentChip == Chip::CHIP_1) {
if(currentCopy == Copy::COPY_0) {
arrayIdx = 2;
}
else if(currentCopy == Copy::COPY_1) {
arrayIdx = 3;
}
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
if(wordIdx == 5) {
if(word == "unlocked.") {
protArray[arrayIdx] = false;
}
else {
protArray[arrayIdx] = true;
}
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void CoreController::performWatchdogControlOperation() {
// Only perform each fifth iteration
if(watchdogFifoFd != 0 and opDivider.checkAndIncrement()) {

View File

@ -16,17 +16,28 @@ public:
enum Chip: uint8_t {
CHIP_0,
CHIP_1,
NO_CHIP
NO_CHIP,
SELF_CHIP,
ALL_CHIP
};
enum Copy: uint8_t {
COPY_0,
COPY_1,
NO_COPY
NO_COPY,
SELF_COPY,
ALL_COPY
};
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 CURR_COPY_FILE[] = "/tmp/curr_copy.txt";
static constexpr char VERSION_FILE[] = "/conf/sd_status";
static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0;
static constexpr ActionId_t REBOOT_OBC = 32;
static constexpr ActionId_t MOUNT_OTHER_COPY = 33;
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE;
@ -46,19 +57,39 @@ public:
ReturnValue_t handleCommandMessage(CommandMessage *message) override;
void performControlOperation() override;
/**
* Generate a file containing the chip lock/unlock states inside /tmp/chip_status.txt
* @return
*/
static ReturnValue_t generateChipStateFile();
static ReturnValue_t incrementAllocationFailureCount();
static void getCurrentBootCopy(Chip& chip, Copy& copy);
ReturnValue_t updateProtInfo(bool regenerateChipStateFile = true);
/**
* Checks whether the target chip and copy are writeprotected and protect them if they are
* not
* @param targetChip
* @param targetCopy
* @param protect
* @param protOperationPerformed [out] Can be used to determine whether any operation
* was performed
* @param updateProtFile Specify whether the protection info file is updated
* @return
*/
ReturnValue_t checkAndSetBootCopyProtection(Chip targetChip, Copy targetCopy,
bool protect, bool& protOperationPerformed, bool updateProtFile = true);
bool sdInitFinished() const;
private:
static Chip currentChip;
static Copy currentCopy;
static Chip CURRENT_CHIP;
static Copy CURRENT_COPY;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode);
// Designated value for rechecking FIFO open
static constexpr int RETRY_FIFO_OPEN = -2;
int watchdogFifoFd = 0;
// States for SD state machine, which is used in non-blocking mode
enum class SdStates {
@ -85,9 +116,6 @@ private:
SdCardManager* sdcMan = nullptr;
ReturnValue_t initSdCardBlocking();
ReturnValue_t sdStateMachine();
struct SdInfo {
sd::SdCard pref = sd::SdCard::NONE;
sd::SdState prefState = sd::SdState::OFF;
@ -108,9 +136,29 @@ private:
sd::SdCard commandedCard = sd::SdCard::NONE;
sd::SdState commandedState = sd::SdState::OFF;
};
SdInfo sdInfo;
/**
* Index 0: Chip 0 Copy 0
* Index 1: Chip 0 Copy 1
* Index 2: Chip 1 Copy 0
* Index 3: Chip 1 Copy 1
*/
std::array<bool, 4> protArray;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode);
ReturnValue_t initVersionFile();
ReturnValue_t initBootCopy();
ReturnValue_t initWatchdogFifo();
ReturnValue_t initSdCardBlocking();
void initPrint();
ReturnValue_t sdStateMachine();
void updateSdInfoOther();
ReturnValue_t sdCardSetup(sd::SdCard sdCard, sd::SdState targetState, std::string sdChar,
bool printOutput = true);
@ -120,24 +168,14 @@ private:
void executeNextExternalSdCommand();
void checkExternalSdCommandStatus();
ReturnValue_t initVersionFile();
ReturnValue_t initBootCopy();
ReturnValue_t initWatchdogFifo();
ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t *data, size_t size);
ReturnValue_t actionPerformReboot(const uint8_t *data, size_t size);
void initPrint();
// Designated value for rechecking FIFO open
static constexpr int RETRY_FIFO_OPEN = -2;
int watchdogFifoFd = 0;
PeriodicOperationDivider opDivider;
void performWatchdogControlOperation();
ReturnValue_t handleProtInfoUpdateLine(std::string nextLine);
};
#endif /* BSP_Q7S_CORE_CORECONTROLLER_H_ */