diff --git a/README.md b/README.md index 0f3a6dd..62199ad 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,15 @@ GUARD Tool Usage: guard [OPTIONS] Options: - -h,--help Use the below listed functions. - Warning: Don't try guard on non guardable units - (sys, perv) - -c,--create TEXT Create GUARD record, expects physical path as input. - -d,--delete TEXT Delete GUARD record, expects physical path as input. - -l,--list Listing of GUARDed resources. - -r,--clearall Clears GUARD states for all resources. - -v,--version Version of GUARD tool. + -h,--help Guard CLI tool options + -c,--create TEXT Create Guard record, expects physical path as input + -i,--invalidate TEXT Invalidate a single Guard record, expects physical + path as input + -I,--invalidate-all Invalidates all the Guard records + -l,--list List all the GUARD'ed resources + -r,--reset Erase all the Guard records + -v,--version Version of GUARD tool + ``` **Note:** Physical path can be fetched from device tree, using ATTR_PHYS_DEV_PATH attribute of the corresponding target. @@ -64,11 +65,15 @@ guard -l ID | ERROR | Type | Path 00000001 | 00000000 | manual | physical:sys-0/node-0/proc-0/mc-0/mi-0/mcc-0 ``` -* To clear all the guard records +* To erase all the guard records ``` guard -r ``` -* To clear a particular guard record +* To invalidate a single guard record +``` +guard -i sys-0/node-0/proc-0/mc-0/mi-0/mcc-0 +``` +* To invalidate all the guard records ``` -guard -d sys-0/node-0/proc-0/mc-0/mi-0/mcc-0 +guard -I ``` diff --git a/guard.cpp b/guard.cpp index efa5418..73bc451 100644 --- a/guard.cpp +++ b/guard.cpp @@ -2,12 +2,14 @@ #include "libguard/guard_interface.hpp" #include "libguard/include/guard_record.hpp" +#include + #include using namespace std; using namespace openpower::guard; -void guardList() +void guardList(bool displayResolved) { auto records = getAll(); if (!records.size()) @@ -15,34 +17,68 @@ void guardList() std::cout << "No Records to display" << std::endl; return; } - std::cout << "ID | ERROR | Type | Path " << std::endl; + + bool isHeaderPrinted = false; for (const auto& elem : records) { - if (elem.errType != GARD_Reconfig) + // Not to print guard records with errorlog type set as GARD_Reconfig + // As guard below type records are for internal usage only. + if (elem.errType == GARD_Reconfig) + { + continue; + } + // To list resolved records as user wants to list resolved records + else if (displayResolved && (elem.recordId != GUARD_RESOLVED)) + { + continue; + } + // To list unresolved records as user wants to list unresolved records + else if (!displayResolved && (elem.recordId == GUARD_RESOLVED)) + { + continue; + } + + // Don't print the header if already printed header since + // records mixed of resolved and unresolved records so if have + // only either one in retrieved records and user tried to see opposite + // one then we should not print header else user will get confused. + if (!isHeaderPrinted) + { + std::cout << "ID | ERROR | Type | Path " << std::endl; + isHeaderPrinted = true; + } + + std::cout << std::hex << std::setw(8) << std::setfill('0') + << elem.recordId; + + std::cout << " | "; + std::cout << std::hex << std::setw(8) << std::setfill('0') + << elem.elogId; + + std::cout << " | "; + std::optional gReasonToStr = + guardReasonToStr(elem.errType); + std::cout << *gReasonToStr; + + std::cout << " | "; + std::optional physicalPath = + getPhysicalPath(elem.targetId); + if (!physicalPath) + { + std::cout << "Unknown "; + } + else { - std::cout << std::hex << std::setw(8) << std::setfill('0') - << elem.recordId; - std::cout << " | "; - std::cout << std::hex << std::setw(8) << std::setfill('0') - << elem.elogId; - - std::cout << " | "; - std::optional gReasonToStr = - guardReasonToStr(elem.errType); - std::cout << *gReasonToStr; - std::cout << " | "; - std::optional physicalPath = - getPhysicalPath(elem.targetId); - if (!physicalPath) - { - std::cout << "Unknown "; - } - else - { - std::cout << *physicalPath; - } - std::cout << std::endl; + std::cout << *physicalPath; } + std::cout << std::endl; + } + + if (!isHeaderPrinted) + { + std::cout << "No " + << (displayResolved == true ? "resolved" : "unresolved") + << " records to display" << std::endl; } } @@ -62,6 +98,11 @@ void guardClear() clearAll(); } +void guardInvalidateAll() +{ + invalidateAll(); +} + void guardCreate(const std::string& physicalPath) { std::optional entityPath = getEntityPath(physicalPath); @@ -84,25 +125,29 @@ int main(int argc, char** argv) { try { - CLI::App app{"GUARD Tool"}; + CLI::App app{"Guard Tool"}; std::optional createGuardStr; std::optional deleteGuardStr; bool listGuardRecords = false; bool clearAll = false; + bool listResolvedGuardRecords = false; + bool invalidateAll = false; bool gversion = false; - app.set_help_flag("-h, --help", - "Use the below listed functions.\n" - "Warning: Don't try guard on non guardable units " - "(sys, perv)"); + app.set_help_flag("-h, --help", "Guard CLI tool options"); app.add_option("-c, --create", createGuardStr, - "Create GUARD record, expects physical path as input"); - app.add_option("-d, --delete", deleteGuardStr, - "Delete GUARD record, expects physical path as input"); + "Create Guard record, expects physical path as input"); + app.add_option( + "-i, --invalidate", deleteGuardStr, + "Invalidate a single Guard record, expects physical path as input"); + app.add_flag("-I, --invalidate-all", invalidateAll, + "Invalidates all the Guard records"); app.add_flag("-l, --list", listGuardRecords, - "Listing of GUARDed resources."); - app.add_flag("-r, --clearall", clearAll, - "Clears GUARD states for all resources"); + "List all the Guard'ed resources"); + app.add_flag("-r, --reset", clearAll, "Erase all the Guard records"); + app.add_flag("-a, --listresolvedrecords", listResolvedGuardRecords, + "List all the resolved Guard'ed resources") + ->group(""); app.add_flag("-v, --version", gversion, "Version of GUARD tool"); CLI11_PARSE(app, argc, argv); @@ -123,11 +168,19 @@ int main(int argc, char** argv) } else if (listGuardRecords) { - guardList(); + guardList(false); + } + else if (listResolvedGuardRecords) + { + guardList(true); + } + else if (invalidateAll) + { + guardInvalidateAll(); } else if (gversion) { - std::cout << "GUARD Tool version is " << GUARD_VERSION << std::endl; + std::cout << "Guard tool " << GUARD_VERSION << std::endl; } else { diff --git a/libguard/guard_common.hpp b/libguard/guard_common.hpp index ac69e71..4ed6511 100644 --- a/libguard/guard_common.hpp +++ b/libguard/guard_common.hpp @@ -1,17 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once +#include "guard_exception.hpp" #include "guard_log.hpp" #include #include -#include #include namespace openpower { namespace guard { + +using namespace openpower::guard::exception; + /* From hostboot: src/include/usr/targeting/common/entitypath.H */ struct EntityPath { @@ -75,7 +78,7 @@ struct EntityPath GUARD_ERROR, "Size mismatch. Given buf size[%d] EntityPath sizeof[%d]", rawData.size(), sizeof(EntityPath)); - throw std::runtime_error( + throw InvalidEntityPath( "EntityPath initializer_list constructor failed"); } @@ -83,7 +86,7 @@ struct EntityPath { openpower::guard::log::guard_log(GUARD_ERROR, "Given raw data is empty"); - throw std::runtime_error( + throw InvalidEntityPath( "EntityPath initializer_list constructor failed"); } @@ -93,7 +96,7 @@ struct EntityPath { openpower::guard::log::guard_log( GUARD_ERROR, "PathElement size mismatch in given raw data"); - throw std::runtime_error( + throw InvalidEntityPath( "EntityPath initializer_list constructor failed"); } @@ -107,7 +110,7 @@ struct EntityPath openpower::guard::log::guard_log( GUARD_ERROR, "Insufficient data for PathElement in given raw data"); - throw std::runtime_error( + throw InvalidEntityPath( "EntityPath initializer_list constructor failed"); } @@ -122,8 +125,7 @@ struct EntityPath { openpower::guard::log::guard_log(GUARD_ERROR, "Given raw data is empty"); - throw std::runtime_error( - "EntityPath conversion constructor failed"); + throw InvalidEntityPath("EntityPath conversion constructor failed"); } type_size = rawData[0]; @@ -135,8 +137,7 @@ struct EntityPath GUARD_ERROR, "Size mismatch. Given path elements size[%d] max[%d]", pathElementsSize, maxPathElements); - throw std::runtime_error( - "EntityPath conversion constructor failed"); + throw InvalidEntityPath("EntityPath conversion constructor failed"); } for (int i = 0, j = 1; i < pathElementsSize; @@ -147,7 +148,7 @@ struct EntityPath openpower::guard::log::guard_log( GUARD_ERROR, "Insufficient data for PathElement in given raw data"); - throw std::runtime_error( + throw InvalidEntityPath( "EntityPath conversion constructor failed"); } diff --git a/libguard/guard_exception.hpp b/libguard/guard_exception.hpp new file mode 100644 index 0000000..c920936 --- /dev/null +++ b/libguard/guard_exception.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include + +namespace openpower +{ +namespace guard +{ +namespace exception +{ +// TODO:Issue #3, to avoid multiple exception classes +class GuardException : public std::exception +{ + public: + explicit GuardException(const std::string& message) : message(message){}; + + const char* what() const noexcept override + { + return message.c_str(); + } + + private: + std::string message; +}; + +class GuardFileOpenFailed : public GuardException +{ + public: + explicit GuardFileOpenFailed(const std::string& msg) : + GuardException(msg){}; +}; + +class GuardFileReadFailed : public GuardException +{ + public: + explicit GuardFileReadFailed(const std::string& msg) : + GuardException(msg){}; +}; + +class GuardFileWriteFailed : public GuardException +{ + public: + explicit GuardFileWriteFailed(const std::string& msg) : + GuardException(msg){}; +}; + +class GuardFileSeekFailed : public GuardException +{ + public: + explicit GuardFileSeekFailed(const std::string& msg) : + GuardException(msg){}; +}; + +class InvalidEntry : public GuardException +{ + public: + explicit InvalidEntry(const std::string& msg) : GuardException(msg){}; +}; + +class AlreadyGuarded : public GuardException +{ + public: + explicit AlreadyGuarded(const std::string& msg) : GuardException(msg){}; +}; + +class InvalidEntityPath : public GuardException +{ + public: + explicit InvalidEntityPath(const std::string& msg) : GuardException(msg){}; +}; + +class GuardFileOverFlowed : public GuardException +{ + public: + explicit GuardFileOverFlowed(const std::string& msg) : + GuardException(msg){}; +}; + +} // namespace exception +} // namespace guard +} // namespace openpower diff --git a/libguard/guard_file.cpp b/libguard/guard_file.cpp index 5ae6999..feeae31 100644 --- a/libguard/guard_file.cpp +++ b/libguard/guard_file.cpp @@ -2,6 +2,7 @@ #include "guard_file.hpp" +#include "guard_exception.hpp" #include "guard_log.hpp" #include @@ -12,6 +13,7 @@ namespace openpower namespace guard { using namespace openpower::guard::log; +using namespace openpower::guard::exception; GuardFile::GuardFile(const fs::path& file) : guardFile(file) { @@ -22,22 +24,27 @@ GuardFile::GuardFile(const fs::path& file) : guardFile(file) { guard_log(GUARD_ERROR, "Failed to open the GUARD file during initailization"); - throw std::runtime_error("Failed to get the GUARD file."); + throw GuardFileOpenFailed( + "Exception thrown as failed to open the guard file"); } file.seekg(0, file.end); if (file.fail()) { - throw std::runtime_error( - "Failed to move to the last position in the file"); + guard_log(GUARD_ERROR, + "Failed to move to last position in guard file"); + throw GuardFileSeekFailed( + "Exception thrown as failed to move to the " + "last position in the file"); } fileSize = file.tellg(); } - catch (const std::exception& ex) + catch (openpower::guard::exception::GuardFileOpenFailed& ex) { - guard_log(GUARD_ERROR, - "Error caught during initializing the GUARD file %s", ex.what()); - throw std::runtime_error( - "Exception thrown during initialize GUARD file."); + throw GuardFileOpenFailed(ex.what()); + } + catch (openpower::guard::exception::GuardFileSeekFailed& ex) + { + throw GuardFileSeekFailed(ex.what()); } } @@ -48,7 +55,8 @@ void GuardFile::read(const uint64_t pos, void* dst, const uint64_t len) { guard_log(GUARD_ERROR, "Unable to open the guard file during read operation."); - throw std::runtime_error("Failed to open guard file in read function."); + throw GuardFileOpenFailed( + "Failed to open guard file in read function."); } file.seekg(pos, file.beg); if (file.fail()) @@ -57,14 +65,16 @@ void GuardFile::read(const uint64_t pos, void* dst, const uint64_t len) "Unable to move to the position in the guard file at" " position= 0x%016llx", pos); - throw std::runtime_error("Failed to move to the position in the file"); + throw GuardFileSeekFailed( + "Failed to move" + "to the position during read operation in the guard file"); } file.read(reinterpret_cast(dst), len); if (file.fail()) { guard_log(GUARD_ERROR, "Unable to read from guard file at position= 0x%016llx", pos); - throw std::runtime_error("Failed to read from guard file."); + throw GuardFileReadFailed("Failed to read from guard file."); } return; } @@ -78,7 +88,7 @@ void GuardFile::write(const uint64_t pos, const void* src, const uint64_t len) guard_log( GUARD_ERROR, "Unable to open guard file while perfoming the write operation"); - throw std::runtime_error("Failed to open guard file to write"); + throw GuardFileOpenFailed("Failed to open guard file to write"); } file.seekp(pos, file.beg); @@ -88,15 +98,15 @@ void GuardFile::write(const uint64_t pos, const void* src, const uint64_t len) "Unable to move to the position in the guard file." " Position= 0x%016llx", pos); - throw std::runtime_error("Failed to move to the position in the guard file."); + throw GuardFileSeekFailed("Failed to move to the position during write " + "operation in the guard file."); } file.write(reinterpret_cast(src), len); if (file.fail()) { - guard_log(GUARD_ERROR, - "Unable to write the record to GUARD file."); - throw std::runtime_error("Failed to write to the guard file."); + guard_log(GUARD_ERROR, "Unable to write the record to GUARD file."); + throw GuardFileWriteFailed("Failed to write to the guard file."); } return; } @@ -109,7 +119,7 @@ void GuardFile::erase(const uint64_t pos, const uint64_t len) if (len <= 0) { guard_log(GUARD_ERROR, "Length passed is %d which is not valid", len); - throw std::runtime_error("Not a valid length value"); + throw InvalidEntry("Not a valid length value"); } while (len - rlen > 0) diff --git a/libguard/guard_file.hpp b/libguard/guard_file.hpp index f84c677..8c0b5ff 100644 --- a/libguard/guard_file.hpp +++ b/libguard/guard_file.hpp @@ -45,7 +45,11 @@ class GuardFile * @param[in] dst data to read * @param[in] len length of the data to read * magic number and other details. - * @return NULL + * @return NULL on success + * Throw below exceptions on failure: + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileReadFailed */ void read(const uint64_t pos, void* dst, const uint64_t len); @@ -55,7 +59,11 @@ class GuardFile * @param[in] pos position in the file to write guard data * @param[in] dst data to write * @param[in] len length of the data to write - * @return NULL + * @return NULL on success + * Throw below exceptions on failure: + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileWriteFailed */ void write(const uint64_t pos, const void* src, const uint64_t len); @@ -64,7 +72,8 @@ class GuardFile * * @param[in] pos position in the file to erase guard data * @param[in] len length of the data to erase from position - * @return NULL + * @return NULL on success + * Throw InvalidEntry exception on failure. */ void erase(const uint64_t pos, const uint64_t len); diff --git a/libguard/guard_interface.cpp b/libguard/guard_interface.cpp index aad56cd..b68c31f 100644 --- a/libguard/guard_interface.cpp +++ b/libguard/guard_interface.cpp @@ -5,6 +5,7 @@ #include "guard_common.hpp" #include "guard_entity.hpp" +#include "guard_exception.hpp" #include "guard_file.hpp" #include "guard_log.hpp" #include "include/guard_record.hpp" @@ -14,6 +15,7 @@ #endif /* DEV_TREE */ #include +#include namespace openpower { @@ -21,6 +23,8 @@ namespace guard { using namespace openpower::guard::log; +using guardRecordParam = std::variant; +using namespace openpower::guard::exception; static fs::path guardFilePath = ""; @@ -75,7 +79,8 @@ const fs::path& getGuardFilePath() { if (guardFilePath.empty()) { - throw std::runtime_error( + guard_log(GUARD_ERROR, "Guard file is not initialised."); + throw GuardFileOpenFailed( "Guard file is not initialised. " "Please make sure libguard_init() is called already"); } @@ -134,76 +139,94 @@ GuardRecord create(const EntityPath& entityPath, uint32_t eId, uint8_t eType) //! check if guard record already exists int pos = 0; int lastPos = 0; - uint32_t maxId = 0; uint32_t offset = 0; + uint32_t avalSize = 0; + uint32_t maxId = 0; + uint32_t id = 0; + int empPos = -1; GuardRecord existGuard; - memset(&existGuard, 0xff, sizeof(existGuard)); + GuardRecord guard; + size_t sizeOfGuard = sizeof(guard); + memset(&guard, 0xff, sizeOfGuard); + memset(&existGuard, 0xff, sizeOfGuard); GuardFile file(guardFilePath); for_each_guard(file, pos, existGuard) { + // Storing the oldest resolved guard record position. + if ((existGuard.recordId == GUARD_RESOLVED) && (empPos < 0)) + { + empPos = pos; + } + if (existGuard.targetId == entityPath) { if (existGuard.errType == GARD_Reconfig) { - offset = lastPos * sizeof(existGuard); + offset = lastPos * sizeOfGuard; existGuard.errType = eType; existGuard.recordId = htobe32(lastPos + 1); - file.write(offset + headerSize, &existGuard, - sizeof(existGuard)); + file.write(offset + headerSize, &existGuard, sizeOfGuard); + } + else if (existGuard.recordId == GUARD_RESOLVED) + { + lastPos++; + continue; } else { guard_log( GUARD_ERROR, "Already guard record is available in the GUARD partition"); - throw std::runtime_error("Guard record is already exist"); + throw AlreadyGuarded("Guard record is already exist"); } return getHostEndiannessRecord(existGuard); } + + id = be32toh(existGuard.recordId); //! find the largest record ID - if (be32toh(existGuard.recordId) > maxId) + if ((id > maxId) && (existGuard.recordId != GUARD_RESOLVED)) { maxId = be32toh(existGuard.recordId); } lastPos++; } - GuardRecord guard; - //! if blank record exist - if (isBlankRecord(existGuard)) + // Space left in GUARD file before writing a new record + avalSize = file.size() - ((lastPos + 1) * sizeOfGuard + headerSize); + if (avalSize < sizeOfGuard) { - offset = lastPos * sizeof(guard); - memset(&guard, 0xff, sizeof(guard)); - guard.recordId = htobe32(maxId + 1); - guard.errType = eType; - guard.targetId = entityPath; - guard.elogId = htobe32(eId); - //! TODO:- Need to fetch details from device tree APIs i.e. serial - //! number and part number. - // For now initializing serial number and part number with 0. -#ifndef PGUARD - memset(guard.u.s1.serialNum, 0, sizeof(guard.u.s1.serialNum)); - memset(guard.u.s1.partNum, 0, sizeof(guard.u.s1.partNum)); -#endif - uint32_t guardFileSize = file.size(); - if (offset > (guardFileSize - sizeof(guard))) + if (empPos < 0) { - guard_log( - GUARD_ERROR, - "GUARD file has no space to write the new record in the file."); - throw std::runtime_error("No space in GUARD for a new record"); + guard_log(GUARD_ERROR, + "Guard file size is %d and space remaining in GUARD file " + "is %d\n", + file.size(), avalSize); + throw GuardFileOverFlowed( + "Enough size is not available in GUARD file"); } - file.write(offset + headerSize, &guard, sizeof(guard)); + // No space is left and have invalid record present. Hence using that + // slot to write new guard record. + offset = empPos * sizeOfGuard; } else { - guard_log( - GUARD_ERROR, - "GUARD file has no space to write the new record in the file."); - std::runtime_error("No space in GUARD for a new record"); + offset = lastPos * sizeOfGuard; } + guard.recordId = htobe32(maxId + 1); + guard.errType = eType; + guard.targetId = entityPath; + guard.elogId = htobe32(eId); + //! TODO:- Need to fetch details from device tree APIs i.e. serial + //! number and part number. + // For now initializing serial number and part number with 0. +#ifndef PGUARD + memset(guard.u.s1.serialNum, 0, sizeof(guard.u.s1.serialNum)); + memset(guard.u.s1.partNum, 0, sizeof(guard.u.s1.partNum)); +#endif + file.write(offset + headerSize, &guard, sizeOfGuard); + return getHostEndiannessRecord(guard); } @@ -223,126 +246,100 @@ GuardRecords getAll() } /** - * @brief Helper function to delete guard record + * @brief To find the guard record based on recordId or entityPath * - * @param[in] record to delete - * @param[in] recordPos position for deleting record - * @param[in] posOfLastRecord position of last record in guard file + * @param[in] value (std::variant) * - * @return NULL on success - * Throw exception on failure + * @return NULL on success. + * Throw following exceptions: + * -InvalidEntry + * -InvalidEntityPath * */ -static void deleteRecord(GuardRecord record, int recordPos, int posOfLastRecord) -{ - GuardRecord nullGuard; - size_t sizeOfGuardRecord = sizeof(nullGuard); - - memset(&nullGuard, 0xFF, sizeOfGuardRecord); - - uint32_t offset = recordPos * sizeOfGuardRecord; - - GuardFile file(guardFilePath); - file.erase(offset + headerSize, sizeOfGuardRecord); - - int i = recordPos + 1; - while (posOfLastRecord != i) - { - uint32_t offset1 = i * sizeOfGuardRecord; - file.read(offset1 + headerSize, &record, sizeOfGuardRecord); - uint32_t offset2 = (i - 1) * sizeOfGuardRecord; - file.write(offset2 + headerSize, &record, sizeOfGuardRecord); - file.write(offset1 + headerSize, &nullGuard, sizeOfGuardRecord); - i++; - } -} - -void clear(const EntityPath& entityPath) +static void invalidateRecord(const guardRecordParam& value) { int pos = 0; - int delpos = 0; - int lastPos = 0; GuardRecord existGuard; bool found = false; + uint32_t offset = 0; + EntityPath entityPath = {}; + uint32_t recordPos = 0; - GuardFile file(guardFilePath); - for_each_guard(file, pos, existGuard) + if (std::holds_alternative(value)) { - if (existGuard.targetId == entityPath) - { - delpos = pos; - found = true; - } - lastPos++; + recordPos = std::get(value); } - - if (!found) + else if (std::holds_alternative(value)) { - guard_log(GUARD_ERROR, "Guard record not found"); - throw std::runtime_error("Guard record not found"); + entityPath = std::get(value); + } + else + { + throw InvalidEntry( + "Invalid parameter passed to invalidate guard record"); } - deleteRecord(existGuard, delpos, lastPos); -} - -void clear(const uint32_t recordId) -{ - int pos = 0; - int delpos = 0; - int lastPos = 0; - GuardRecord existGuard; - bool found = false; GuardFile file(guardFilePath); for_each_guard(file, pos, existGuard) { - if (be32toh(existGuard.recordId) == recordId) + if (((be32toh(existGuard.recordId) == recordPos) || + (existGuard.targetId == entityPath)) && + (existGuard.recordId != GUARD_RESOLVED)) { - delpos = pos; + offset = pos * sizeof(existGuard); + existGuard.recordId = GUARD_RESOLVED; + file.write(offset + headerSize, &existGuard, sizeof(existGuard)); found = true; + break; } - lastPos++; } if (!found) { guard_log(GUARD_ERROR, "Guard record not found"); - throw std::runtime_error("Guard record not found"); + throw InvalidEntityPath("Guard record not found"); } +} - deleteRecord(existGuard, delpos, lastPos); +void clear(const EntityPath& entityPath) +{ + auto path = entityPath; + invalidateRecord(path); +} + +void clear(const uint32_t recordId) +{ + auto id = recordId; + invalidateRecord(id); } void clearAll() { - GuardRecords guardRecords; - GuardRecord guard; + GuardFile file(guardFilePath); - memset(&guard, 0, sizeof(guard)); + file.erase(0, file.size()); +} + +void invalidateAll() +{ + int pos = 0; + GuardRecord existGuard; + uint32_t offset = 0; + + memset(&existGuard, 0, sizeof(existGuard)); GuardFile file(guardFilePath); - file.read(0 + headerSize, &guard, sizeof(guard)); - if (isBlankRecord(guard)) + file.read(0 + headerSize, &existGuard, sizeof(existGuard)); + if (isBlankRecord(existGuard)) { guard_log(GUARD_INFO, "No GUARD records to clear"); } else { - int pos = 0; - for_each_guard(file, pos, guard) - { - if (guard.errType == GARD_Reconfig) - { - guardRecords.push_back(guard); - } - } - - file.erase(pos + headerSize, file.size()); - pos = 0; - for (auto& elem : guardRecords) + for_each_guard(file, pos, existGuard) { - uint32_t offset = pos * sizeof(guard); - elem.recordId = htobe32(pos + 1); - file.write(offset + headerSize, &elem, sizeof(guard)); - pos++; + offset = pos * sizeof(existGuard); + existGuard.recordId = GUARD_RESOLVED; + file.write(offset + headerSize, &existGuard, sizeof(existGuard)); } } } diff --git a/libguard/guard_interface.hpp b/libguard/guard_interface.hpp index efb4172..10d248a 100644 --- a/libguard/guard_interface.hpp +++ b/libguard/guard_interface.hpp @@ -18,7 +18,13 @@ namespace fs = std::filesystem; * @param[in] eId errorlog ID * @param[in] eType errorlog type * @return created guard record in host endianess format on success - * Throw exception on failure + * Throw following exceptions on failure: + * -GuardFileOverFlowed + * -AlreadyGuarded + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileReadFailed + * -GuardFileWriteFailed * * @note EntityPath provided conversion constructor so, same api can use to pass * array of uint8_t buffer and conversion constructor automatically will take @@ -31,6 +37,10 @@ GuardRecord create(const EntityPath& entityPath, uint32_t eId = 0, * @brief Get all the guard records * * @return GuardRecords List of Guard Records. + * On failure will throw below exceptions: + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileReadFailed */ GuardRecords getAll(); @@ -39,7 +49,13 @@ GuardRecords getAll(); * * @param[in] entityPath entity path * @return NULL on success - * Throw exception on failure + * Throw following exceptions on failure: + * -InvalidEntry + * -InvalidEntityPath + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileReadFailed + * -GuardFileWriteFailed * * @note EntityPath provided conversion constructor so, same api can use to pass * array of uint8_t buffer and conversion constructor automatically will take @@ -51,7 +67,13 @@ void clear(const EntityPath& entityPath); * @brief Clear the guard record based on given record id * * @return NULL on success. - * Throw exception on failure. + * Throw following exceptions on failure: + * -InvalidEntry + * -InvalidEntityPath + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileWriteFailed + * -GuardFileReadFailed * */ void clear(const uint32_t recordId); @@ -59,10 +81,27 @@ void clear(const uint32_t recordId); /** * @brief Clear all the guard records * - * @return NULL + * @return NULL on success + * Throw below exceptions on failure: + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileWriteFailed */ void clearAll(); +/** + * @brief Invalidates all the guard records + * i.e. mark recordId as 0xFFFFFFFF. + * + * @return NULL on success + * Throw throw below exceptions on failure: + * -GuardFileOpenFailed + * -GuardFileSeekFailed + * -GuardFileWriteFailed + * -GuardFileReadFailed + */ +void invalidateAll(); + /** * @brief To initialize libguard * @@ -82,7 +121,8 @@ void libguard_init(bool enableDevtree = true); * @brief Used to get guard file path which is using by libguard. * * @return guard file path on success - * Throw exception if guard file is not initialised. + * Throws GuardFileOpenFailed exception if guard file is not + * initialised. * * @note This function should call after libguard_init() */ diff --git a/libguard/include/guard_record.hpp b/libguard/include/guard_record.hpp index fa5e52a..b56a707 100644 --- a/libguard/include/guard_record.hpp +++ b/libguard/include/guard_record.hpp @@ -12,6 +12,7 @@ namespace guard #define GUARD_MAGIC "GUARDREC" //! "GUARDREC" /* From hostboot: src/include/usr/hwas/hwasPlatDeconfigGard.H */ const uint8_t CURRENT_GARD_VERSION_LAYOUT = 0x1; +#define GUARD_RESOLVED 0xFFFFFFFF #ifdef PGUARD /* From hostboot: src/include/usr/hwas/common/deconfigGard.H:GuardRecord */ diff --git a/libguard/meson.build b/libguard/meson.build index 42d5d13..c8f7673 100644 --- a/libguard/meson.build +++ b/libguard/meson.build @@ -9,6 +9,7 @@ headers_libguard = [ 'guard_entity.hpp', 'guard_log.hpp', 'guard_common.hpp', + 'guard_exception.hpp', ] headers = [ diff --git a/meson.build b/meson.build index 63d71b7..55bed5c 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,10 @@ conf_data.set_quoted('GUARD_PRSV_PATH', get_option('GUARD_PRSV_PATH'), description : 'GUARD file in pnor prsv partition' ) +conf_data.set_quoted('GUARD_VERSION', 'v1.0', + description : 'Setting guard tool version' + ) + conf_data.set('DEV_TREE', get_option('devtree').enabled(), description : 'Use device tree to get physical path value' ) @@ -40,8 +44,6 @@ configure_file(output: 'config.h', ) #add_project_arguments('-DPGUARD', language : 'cpp') -add_project_arguments('-DGUARD_VERSION', language : 'cpp') -set_variable('GUARD_VERSION', '1.0') subdir('libguard') diff --git a/test/guard_intf_test.cpp b/test/guard_intf_test.cpp index a708701..0baaaa7 100644 --- a/test/guard_intf_test.cpp +++ b/test/guard_intf_test.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "libguard/guard_common.hpp" #include "libguard/guard_entity.hpp" +#include "libguard/guard_exception.hpp" #include "libguard/guard_file.hpp" #include "libguard/guard_interface.hpp" #include "libguard/include/guard_record.hpp" @@ -100,13 +101,14 @@ TEST_F(TestGuardRecord, DeleteGuardGoodPathTest) entityPath = openpower::guard::getEntityPath(phyPath); openpower::guard::clear(*entityPath); openpower::guard::GuardRecords records = openpower::guard::getAll(); - bool isRecordDeleted = true; + bool isRecordDeleted = false; for (int i = 0; i < (int)records.size(); i++) { openpower::guard::GuardRecord record = records.at(i); if (record.targetId == entityPath) { - isRecordDeleted = false; + EXPECT_EQ(record.recordId, 0xFFFFFFFF); + isRecordDeleted = true; break; } } @@ -125,9 +127,8 @@ TEST_F(TestGuardRecord, NegTestCaseEP) TEST_F(TestGuardRecord, NegTestCaseFullGuardFile) { openpower::guard::libguard_init(); - std::string phyPath = "/sys-0"; - std::optional entityPath = - openpower::guard::getEntityPath(phyPath); + std::string phyPath = " "; + std::optional entityPath; phyPath = "/sys-0/node-0/proc-1/eq-0/fc-0/core-1"; entityPath = openpower::guard::getEntityPath(phyPath); openpower::guard::create(*entityPath); @@ -140,13 +141,10 @@ TEST_F(TestGuardRecord, NegTestCaseFullGuardFile) phyPath = "/sys-0/node-0/proc-1/eq-0/fc-0/core-0"; entityPath = openpower::guard::getEntityPath(phyPath); openpower::guard::create(*entityPath); - phyPath = "/sys-0/node-0/proc-1/eq-0/fc-0"; - entityPath = openpower::guard::getEntityPath(phyPath); - openpower::guard::create(*entityPath); - phyPath = "/sys-0/node-0/proc-1/eq-0"; + phyPath = "/sys-0/node-0/dimm-1"; entityPath = openpower::guard::getEntityPath(phyPath); EXPECT_THROW({ openpower::guard::create(*entityPath); }, - std::runtime_error); + openpower::guard::exception::GuardFileOverFlowed); } TEST_F(TestGuardRecord, AlreadyGuardedTC) @@ -159,7 +157,7 @@ TEST_F(TestGuardRecord, AlreadyGuardedTC) // Trying to guard again with same entity EXPECT_THROW({ openpower::guard::create(*entityPath); }, - std::runtime_error); + openpower::guard::exception::AlreadyGuarded); } TEST_F(TestGuardRecord, GetCreatedGuardRecordTC) @@ -197,7 +195,7 @@ TEST_F(TestGuardRecord, DeleteByEntityPath) // Make sure is deleted openpower::guard::GuardRecords records = openpower::guard::getAll(); - EXPECT_EQ(records.size(), 0); + EXPECT_EQ(records.size(), 1); } TEST_F(TestGuardRecord, DeleteWithNotExistentEntity) @@ -208,7 +206,8 @@ TEST_F(TestGuardRecord, DeleteWithNotExistentEntity) openpower::guard::getEntityPath(physPath); // Trying to delete entity which is not present - EXPECT_THROW({ openpower::guard::clear(*entityPath); }, std::runtime_error); + EXPECT_THROW({ openpower::guard::clear(*entityPath); }, + openpower::guard::exception::InvalidEntityPath); } TEST_F(TestGuardRecord, DeleteByRecordId) @@ -226,7 +225,9 @@ TEST_F(TestGuardRecord, DeleteByRecordId) // Make sure is deleted openpower::guard::GuardRecords records = openpower::guard::getAll(); - EXPECT_EQ(records.size(), 0); + EXPECT_EQ(records.size(), 1); + openpower::guard::GuardRecord record = records.at(0); + EXPECT_EQ(record.recordId, 0xFFFFFFFF); } TEST_F(TestGuardRecord, DeleteWithNotExistentRecordId) @@ -241,7 +242,7 @@ TEST_F(TestGuardRecord, DeleteWithNotExistentRecordId) // Trying to delete a record by using returned record id with increment EXPECT_THROW({ openpower::guard::clear(retGuardRecord.recordId + 1); }, - std::runtime_error); + openpower::guard::exception::InvalidEntityPath); } TEST_F(TestGuardRecord, GetGuardFilePathTC) @@ -260,7 +261,8 @@ TEST_F(TestGuardRecord, GetGuardFilePathWhenLibguradDidNotInitTC) openpower::guard::utest::setGuardFile(""); // Checking without libguard_init() call. - EXPECT_THROW({ openpower::guard::getGuardFilePath(); }, std::runtime_error); + EXPECT_THROW({ openpower::guard::getGuardFilePath(); }, + openpower::guard::exception::GuardFileOpenFailed); // Set the guard file since UT reached the end openpower::guard::utest::setGuardFile(guardFile); @@ -271,3 +273,47 @@ TEST_F(TestGuardRecord, GetGuardFilePathWhenLibguradDidNotInitTC) std::string retGuardFilePath = openpower::guard::getGuardFilePath(); EXPECT_EQ(retGuardFilePath, guardFile); } + +TEST_F(TestGuardRecord, ClearGuardInvalidateAllPathTest) +{ + openpower::guard::libguard_init(); + std::string phyPath = "/sys-0/node-0/proc-1/eq-0/fc-0/core-0"; + std::optional entityPath = + openpower::guard::getEntityPath(phyPath); + EXPECT_NE(entityPath, std::nullopt); + openpower::guard::create(*entityPath); + phyPath = "/sys-0/node-0/proc-1/eq-0/fc-0/core-1"; + entityPath = openpower::guard::getEntityPath(phyPath); + openpower::guard::create(*entityPath); + openpower::guard::invalidateAll(); + openpower::guard::GuardRecords records = openpower::guard::getAll(); + EXPECT_EQ(records.size(), 2); + openpower::guard::GuardRecord record = records.at(0); + EXPECT_EQ(record.recordId, 0xFFFFFFFF); + record = records.at(1); + EXPECT_EQ(record.recordId, 0xFFFFFFFF); +} + +TEST_F(TestGuardRecord, ClearResolvedGuardRecord) +{ + openpower::guard::libguard_init(); + std::string phyPath = "/sys-0/node-0/dimm-0"; + std::optional entityPath = + openpower::guard::getEntityPath(phyPath); + openpower::guard::create(*entityPath); + phyPath = "/sys-0/node-0/dimm-1"; + entityPath = openpower::guard::getEntityPath(phyPath); + openpower::guard::create(*entityPath); + phyPath = "/sys-0/node-0/dimm-2"; + entityPath = openpower::guard::getEntityPath(phyPath); + openpower::guard::create(*entityPath); + phyPath = "/sys-0/node-0/dimm-3"; + entityPath = openpower::guard::getEntityPath(phyPath); + openpower::guard::create(*entityPath); + openpower::guard::clear(*entityPath); + phyPath = "/sys-0/node-0/dimm-4"; + entityPath = openpower::guard::getEntityPath(phyPath); + openpower::guard::create(*entityPath); + openpower::guard::GuardRecords records = openpower::guard::getAll(); + EXPECT_EQ(records.size(), 4); +}