From 6d50683e760f5e71a24a09bd385ec596ccb93b68 Mon Sep 17 00:00:00 2001 From: Abinaya Dhandapani Date: Wed, 13 Nov 2024 10:10:30 -0600 Subject: [PATCH 1/3] Add README, OWNERS, and LICENSE files - Added README.md with project overview. - Added OWNERS file to define project ownership and contributors. - Added LICENSE file to specify project licensing terms. Signed-off-by: Abinaya Dhandapani --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ OWNERS | 52 ++++++++++++++ README.md | 35 +++++++++- 3 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 100644 OWNERS diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..3f8f1e4 --- /dev/null +++ b/OWNERS @@ -0,0 +1,52 @@ +# OWNERS +# ------ +# +# The OWNERS file maintains the list of individuals responsible for various +# parts of this repository, including code review and approval. We use the +# Gerrit 'owners' plugin, which consumes this file, along with some extra +# keywords for our own purposes and tooling. +# +# For details on the configuration used by 'owners' see: +# https://gerrit.googlesource.com/plugins/owners/+/refs/heads/master/owners/src/main/resources/Documentation/config.md +# +# An OWNERS file must be in the root of a repository but may also be present +# in any subdirectory. The contents of the subdirectory OWNERS file are +# combined with parent directories unless 'inherit: false' is set. +# +# The owners file is YAML and has [up to] 4 top-level keywords. +# * owners: A list of individuals who have approval authority on the +# repository. +# +# * reviewers: A list of individuals who have requested review notification +# on the repository. +# +# * matchers: A list of specific file/path matchers for granular 'owners' and +# 'reviewers'. See 'owners' plugin documentation. +# +# * openbmc: A list of openbmc-specific meta-data about owners and reviewers. +# - name: preferred name of the individual. +# - email: preferred email address of the individual. +# - discord: Discord nickname of the individual. +# +# It is expected that these 4 sections will be listed in the order above and +# data within them will be kept sorted. + +owners: +- abinaya.dhandapani@amd.com +- jayanth.othayoth@amd.com + +reviewers: +- supreeth.venkatesh@amd.com + +matchers: + +openbmc: +- name: Abinaya Dhandapani + email: abinaya.dhandapani@amd.com + discord: abinayadhandapani +- name: Jayanth Othayoth + email: ojayanth@gmail.com + discord: ojayanth +- name: Supreeth Venkatesh + email: supreeth.venkatesh@amd.com + discord: supreeth_psv9810 diff --git a/README.md b/README.md index 4978617..a60236b 100644 --- a/README.md +++ b/README.md @@ -1 +1,34 @@ -# AMD BMC RAS +# AMD RAS MANAGER + +The amd-ras-manager service is intended to discover, configure and exercise Out +Of Band (OOB) Reliability Availability and Serviceability (RAS) capabilities +supported by the processors. The service creates error records from RAS +telemetry extracted from the processor over Advanced Platform Management Link +(APML). + +## Features + +The amd-ras-manager service reads SBRMI registers over the APML upon the APML_L +assertion by the System Management Unit (SMU). If the SBRMI register indicates +if the assertion is due to the fatal error, BMC harvests MCA and MSR dump via +APML and generates the CPER record. On user demand, these CPER files will be +available for download via redfish. The CPER records will be rotated after +reaching maximum limit of 10 CPER records in the BMC. + +Once the CPER record is created, BMC triggers system recovery either by cold +reset or warm reset or no reset depending on user configuration. + +## Configuration + +The amd-ras-manager is configured per the +[meson build files](https://mesonbuild.com/Build-options.html). Available +options are documented in `meson_options.txt` + +## Building + +This project uses Meson (>=1.1.1). To build for native architecture, run: + +```sh +meson setup build +ninja -C build +``` From fb5477f4f16aae76bb5509c68724bfb556b7e74c Mon Sep 17 00:00:00 2001 From: Abinaya Dhandapani Date: Tue, 19 Nov 2024 06:03:28 -0600 Subject: [PATCH 2/3] Add clang-format and prettier Added clang-18 formatter. Signed-off-by: Abinaya Dhandapani --- .clang-format | 136 +++++++++++++++++++++++++++++++++++++++++++++++ .prettierrc.yaml | 7 +++ 2 files changed, 143 insertions(+) create mode 100644 .clang-format create mode 100644 .prettierrc.yaml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..28e3328 --- /dev/null +++ b/.clang-format @@ -0,0 +1,136 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 1 +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: None +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterExternBlock: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakAfterAttributes: Never +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterColon +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 7 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.h"' + Priority: 1 + - Regex: '^".*\.hpp"' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 3 + - Regex: '^<.*\.hpp>' + Priority: 4 + - Regex: '^<.*' + Priority: 5 + - Regex: '.*' + Priority: 6 +IndentCaseLabels: true +IndentExternBlock: NoIndent +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +InsertNewlineAtEOF: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +LineEnding: LF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 25 +PenaltyBreakBeforeFirstCallParameter: 50 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 1 +PointerAlignment: Left +QualifierAlignment: Left +ReferenceAlignment: Left +ReflowComments: true +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: Keyword +SortIncludes: CaseSensitive +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +TabWidth: 4 +UseTab: Never +... + diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..a69b879 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,7 @@ +tabWidth: 4 +printWidth: 80 +proseWrap: "always" +overrides: + - files: "*.md" + options: + tabWidth: 2 From c07119bd41e7a590ea3d981373912b2b33dc10d5 Mon Sep 17 00:00:00 2001 From: Abinaya Dhandapani Date: Fri, 29 Nov 2024 02:52:13 -0600 Subject: [PATCH 3/3] Create D-Bus object path and config interface 1. Added RAS configuration class which creates the RAS configuration interface to set and get the config values. 2. The setAttribute and getAttribute methods are overridden in the class to update the ras_config.json with the latest values. Tested: 1. Service is working well. 2. All the dbus methods and properties are shown correctly. Able to get and update the ras_config.json file using D-Bus methods. 3. Unit test done. root@xxxx:~# busctl tree com.amd.RAS `- /com `- /com/amd `- /com/amd/RAS Signed-off-by: Abinaya Dhandapani --- README.md | 6 + config/ras_config.json | 72 +++++++ include/config_manager.hpp | 115 +++++++++++ meson.build | 64 ++++++ service_files/com.amd.RAS.service | 10 + src/config_manager.cpp | 325 ++++++++++++++++++++++++++++++ src/main.cpp | 40 ++++ 7 files changed, 632 insertions(+) create mode 100644 config/ras_config.json create mode 100644 include/config_manager.hpp create mode 100644 meson.build create mode 100644 service_files/com.amd.RAS.service create mode 100644 src/config_manager.cpp create mode 100644 src/main.cpp diff --git a/README.md b/README.md index a60236b..fdc336f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ APML and generates the CPER record. On user demand, these CPER files will be available for download via redfish. The CPER records will be rotated after reaching maximum limit of 10 CPER records in the BMC. +assertion by the SMU. If the SBRMI register indicates if the assertion is due to +the fatal error, BMC harvests MCA and MSR dump via APML and generates the CPER +record. On user demand, these CPER files will be available for download via +redfish. The CPER records will be rotated after reaching maximum limit of 10 +CPER records in the BMC. + Once the CPER record is created, BMC triggers system recovery either by cold reset or warm reset or no reset depending on user configuration. diff --git a/config/ras_config.json b/config/ras_config.json new file mode 100644 index 0000000..32be86b --- /dev/null +++ b/config/ras_config.json @@ -0,0 +1,72 @@ +{ + "Configuration": [ + { + "ApmlRetries": { + "Description": "Number of APML retry count", + "Value": 10, + "MaxBoundLimit": "50" + } + }, + { + "SystemRecoveryMode": { + "Description": "System recovery mode", + "Value": "NO_RESET", + "ValidOptions": ["COLD_RESET", "WARM_RESET", "NO_RESET"] + } + }, + { + "ResetSignalType": { + "Description": "Reset Signal Type", + "Value": "SYS_RST", + "ValidOptions": ["SYS_RST", "RSMRST"] + } + }, + { + "HarvestMicrocode": { + "Description": "Harvest microcode version", + "Value": true + } + }, + { + "HarvestPPIN": { + "Description": "Harvest Protected Processor Identification Number", + "Value": true + } + }, + { + "SigIdOffset": { + "Description": "List of Signature ID offsets", + "Value": [ + "0x30", + "0x34", + "0x28", + "0x2c", + "0x08", + "0x0c", + "null", + "null" + ] + } + }, + { + "AifsArmed": { + "Description": "If this field is true, AIFS flow is triggered", + "Value": false + } + }, + { + "AifsSignatureIdList": { + "Description": "List of signature Id which has AIFS flow enabled", + "Value": { + "EX-WDT": "0xaea0000000000108000500b020009a00000000004d000000" + } + } + }, + { + "DisableAifsResetOnSyncfloodCounter": { + "Description": "Disable AIFS Reset on syncflood counter", + "Value": true + } + } + ] +} diff --git a/include/config_manager.hpp b/include/config_manager.hpp new file mode 100644 index 0000000..e4c3907 --- /dev/null +++ b/include/config_manager.hpp @@ -0,0 +1,115 @@ +/* + 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 +#include +#include +#include + +#include + +namespace amd +{ +namespace ras +{ +namespace config +{ +static constexpr auto service = "com.amd.RAS"; +static constexpr auto objectPath = "/com/amd/RAS"; + +using Configuration = sdbusplus::com::amd::RAS::server::Configuration; + +/** + * @brief Manager class which adds the RAS configuration + * parameter values to the D-Bus interface. + * + * @details The class pulls the default values of ras_config.json file + * into the D-Bus interface and overrides the getAttribute() + * and setAttribute() of the RAS configuration interface. + */ +class Manager : public Configuration +{ + public: + using AttributeName = std::string; + using AttributeValue = + std::variant, + std::map>; + using ConfigTable = + std::map, + std::map>, + int64_t>>; + + Manager() = delete; + Manager(const Manager&) = delete; + Manager& operator=(const Manager&) = delete; + Manager(Manager&&) = delete; + Manager& operator=(Manager&&) = delete; + ~Manager() = default; + + /** @brief Constructs Manager object. + * + * @param[in] objectServer - object server + * @param[in] systemBus - bus connection + */ + Manager(sdbusplus::asio::object_server& objectServer, + std::shared_ptr& systemBus); + + /** @brief Updates the rasConfigTable with the user input. + * + * @details Updates the Attribute value in the rasConfigTable and + * ras_config.json with user input and the ras_config.json. + * + * @param[in] attribute - attribute name + * @param[in] value - new value for the attribute + * + * @return On failure of accessing the config file, log InvalidArgument + * D-Bus error. + */ + void setAttribute(AttributeName attribute, AttributeValue value) override; + + /** @brief Get the values of the Ras Config attribute + * + * @details The API reads the value from the RasConfigTable + * and returns the value of the attribute. + * + * @param[in] attribute - attribute name + * + * @return returns the current value of the attribute. + * On failure , throw ResourceNotFound D-Bus error. + */ + AttributeValue getAttribute(AttributeName attribute) override; + + /** @brief Update RAS configuration parameters to D-Bus interface + * + * @details Creates Config File in /var/lib/amd-bmc-ras and the + * config file values are uploaded to the D-Bus interface. + * + * @return On failure of accessing the config file, throw + * std::runtime_error exception. + */ + void updateConfigToDbus(); + + private: + sdbusplus::asio::object_server& objServer; + std::shared_ptr& systemBus; +}; + +} // namespace config +} // namespace ras +} // namespace amd diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..5afadff --- /dev/null +++ b/meson.build @@ -0,0 +1,64 @@ +project( + 'amd-ras-manager', + 'cpp', + default_options: [ + 'warning_level=3', + 'werror=true', + 'cpp_std=c++23' + ], + license: 'Apache-2.0', + version: '1.0', +) + +config_file = '/var/lib/amd-bmc-ras/ras_config.json' +src_config_file = '/usr/share/amd-bmc-ras/ras_config.json' +cpp_args = [ + '-DCONFIG_FILE="' + config_file + '"', + '-DSRC_CONFIG_FILE="' + src_config_file + '"' +] + +boost_args = [ + '-DBOOST_ALL_NO_LIB', + '-DBOOST_ASIO_DISABLE_THREADS', + '-DBOOST_ERROR_CODE_HEADER_ONLY', + '-DBOOST_NO_RTTI', + '-DBOOST_NO_TYPEID', + '-DBOOST_SYSTEM_NO_DEPRECATED', +] + +deps = [ + dependency('boost'), + dependency('phosphor-dbus-interfaces'), + dependency('phosphor-logging'), + dependency('sdbusplus'), + dependency('libsystemd'), + dependency('nlohmann_json', include_type: 'system'), +] + +sources = [ + 'src/config_manager.cpp', + 'src/main.cpp', +] + +executable( + 'amd-ras-manager', + sources, + include_directories: include_directories('include'), + dependencies: deps, + cpp_args: cpp_args + boost_args, + install: true, + install_dir: get_option('bindir')) + +ras_config_dir = join_paths(get_option('datadir'), 'amd-bmc-ras') +install_data( + join_paths(meson.current_source_dir(), 'config', 'ras_config.json'), + install_dir: ras_config_dir, + rename: 'ras_config.json' +) + +systemd = dependency('systemd') + +install_data( + ['service_files/com.amd.RAS.service'], + install_dir: systemd.get_pkgconfig_variable('systemdsystemunitdir') +) diff --git a/service_files/com.amd.RAS.service b/service_files/com.amd.RAS.service new file mode 100644 index 0000000..6f7c151 --- /dev/null +++ b/service_files/com.amd.RAS.service @@ -0,0 +1,10 @@ +[Unit] +Description=AMD RAS Manager +After=xyz.openbmc_project.Chassis.Control.Power.service + +[Service] +Restart=always +ExecStart=/usr/bin/amd-ras-manager + +[Install] +WantedBy=multi-user.target diff --git a/src/config_manager.cpp b/src/config_manager.cpp new file mode 100644 index 0000000..b0e8b81 --- /dev/null +++ b/src/config_manager.cpp @@ -0,0 +1,325 @@ +/* + 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 "config_manager.hpp" + +#include "xyz/openbmc_project/Common/error.hpp" + +#include +#include +#include + +namespace amd +{ +namespace ras +{ +namespace config +{ +namespace fs = std::filesystem; + +void Manager::setAttribute(AttributeName attribute, AttributeValue value) +{ + nlohmann::json data; + + auto configMap = rasConfigTable(); + + std::ifstream jsonFile(CONFIG_FILE); + if (!jsonFile.is_open()) + { + throw sdbusplus::xyz::openbmc_project::Common::File::Error::Open(); + } + + jsonFile >> data; + jsonFile.close(); + + bool attributeFound = false; + for (auto& configItem : data["Configuration"]) + { + if (auto it = configItem.find(attribute); it != configItem.end()) + { + bool isValidValue = false; + + if (it.value().contains("MaxBoundLimit")) + { + auto maxBoundLimit = it.value()["MaxBoundLimit"]; + + std::visit( + [&](auto&& arg) { + if constexpr (std::is_same_v< + std::decay_t, int64_t>) + { + if (maxBoundLimit.is_number_integer()) + { + isValidValue = + (arg > maxBoundLimit.get()); + + if (isValidValue) + { + lg2::error( + "Attribute {ATTRIBUTE} : Value {VALUE} is greater than max bound limit", + "ATTRIBUTE", attribute, "VALUE", arg); + throw sdbusplus::xyz::openbmc_project:: + Common::Error::InvalidArgument(); + } + } + } + }, + value); + } + + if (it.value().contains("ValidOptions")) + { + auto ValidOptions = it.value()["ValidOptions"]; + + for (const auto& ValidOption : ValidOptions) + { + if (ValidOption.is_string()) + { + if (std::holds_alternative(value) && + std::get(value) == + ValidOption.get()) + { + isValidValue = true; + break; + } + } + } + if (isValidValue == false) + { + lg2::error( + "{VALUE} is not a valid option for the attribute {ATTRIBUTE}", + "ATTRIBUTE", attribute, "VALUE", + std::get(value)); + throw sdbusplus::xyz::openbmc_project::Common::Error:: + InvalidArgument(); + } + } + + std::visit([&](auto&& arg) { it.value()["Value"] = arg; }, value); + attributeFound = true; + break; + } + } + if (attributeFound) + { + for (auto& [key, tuple] : configMap) + { + if (key == attribute) + { + std::get<2>(tuple) = value; + break; + } + } + + std::ofstream jsonFileOut(CONFIG_FILE); + + if (!jsonFileOut.is_open()) + { + throw sdbusplus::xyz::openbmc_project::Common::File::Error::Open(); + } + + jsonFileOut << data.dump(4); + jsonFileOut.close(); + rasConfigTable(configMap); + + lg2::debug("Attribute {{ATTRIBUTE} updated successfully", "ATTRIBUTE", + attribute); + } + else + { + lg2::error("Attribute {ATTRIBUTE} not found", "ATTRIBUTE", attribute); + throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); + } +} + +Manager::AttributeValue Manager::getAttribute(AttributeName attribute) +{ + const auto configMap = rasConfigTable(); + AttributeValue value; + bool found = false; + + for (const auto& [key, tuple] : configMap) + { + if (key == attribute) + { + value = std::get<2>(tuple); + found = true; + break; + } + } + + if (!found) + { + lg2::error( + "The given attribute {ATTRIBUTE} is not found in the config table", + "ATTRIBUTE", attribute); + throw sdbusplus::xyz::openbmc_project::Common::Error:: + ResourceNotFound(); + } + return value; +} + +void Manager::updateConfigToDbus() +{ + if (!fs::exists(CONFIG_FILE)) + { // Check if the config file exists + fs::path destDir = fs::path(CONFIG_FILE).parent_path(); + if (!fs::exists(destDir)) + { + if (!fs::create_directories(destDir)) + { + lg2::error("Failed to create directory: {ERROR}", "ERROR", + strerror(errno)); + throw std::runtime_error( + "Failed to create directory: " + destDir.string()); + } + } + + // Try to copy the config file, throw exception if it fails + try + { + fs::copy_file(SRC_CONFIG_FILE, CONFIG_FILE, + fs::copy_options::overwrite_existing); + } + catch (const fs::filesystem_error& e) + { + lg2::error("Failed to copy config file : {ERROR}", "ERROR", + strerror(errno)); + throw std::runtime_error("Failed to copy config file"); + } + } + + std::ifstream jsonRead(CONFIG_FILE); + nlohmann::json data = nlohmann::json::parse(jsonRead); + + if (!jsonRead.is_open()) + { + lg2::error("Could not read config file Error : {ERROR}", "ERROR", + strerror(errno)); + throw std::runtime_error("Error: Could not read config file"); + } + + ConfigTable configMap; + + for (const auto& item : data["Configuration"]) + { + AttributeType attributeType; + std::string key; + std::string description; + std::variant, + std::map> + value; + int64_t maxBoundValue = 0; + + if (item.is_object() && item.size() == 1) + { + key = item.begin().key(); + + const auto& obj = item[key]; + + if (obj.contains("Description") && obj["Description"].is_string()) + { + description = obj["Description"].get(); + } + else + { + description = "Default"; + } + + // Determine the type of the value and construct the std::variant + // accordingly + if (obj["Value"].is_boolean()) + { + value = obj["Value"].get(); + } + else if (obj["Value"].is_string()) + { + value = obj["Value"].get(); + } + else if (obj["Value"].is_number_integer()) + { + value = obj["Value"].get(); + } + else if (obj["Value"].is_array()) + { + value = obj["Value"].get>(); + } + else if (obj["Value"].is_object()) + { + value = obj["Value"].get>(); + } + else + { + value = {}; + } + + if (obj.contains("MaxBoundLimit")) + { + maxBoundValue = obj["MaxBoundLimit"]; + } + + if (value.index() == 0) + { + attributeType = sdbusplus::common::com::amd::ras:: + Configuration::AttributeType::Boolean; + } + else if (value.index() == 1) + { + attributeType = sdbusplus::common::com::amd::ras:: + Configuration::AttributeType::String; + } + else if (value.index() == 2) + { + attributeType = sdbusplus::common::com::amd::ras:: + Configuration::AttributeType::Integer; + } + else if (value.index() == 3) + { + attributeType = sdbusplus::common::com::amd::ras:: + Configuration::AttributeType::ArrayOfStrings; + } + else if (value.index() == 4) + { + attributeType = sdbusplus::common::com::amd::ras:: + Configuration::AttributeType::KeyValueMap; + } + else + { + lg2::debug( + "Unsupported attribute type. Adding default attribute type as boolean"); + attributeType = sdbusplus::common::com::amd::ras:: + Configuration::AttributeType::Boolean; + } + } + + configMap[key] = + std::make_tuple(attributeType, description, value, maxBoundValue); + } + + rasConfigTable(configMap); + + jsonRead.close(); +} + +Manager::Manager(sdbusplus::asio::object_server& objectServer, + std::shared_ptr& systemBus) : + sdbusplus::com::amd::RAS::server::Configuration(*systemBus, objectPath), + objServer(objectServer), systemBus(systemBus) +{ + updateConfigToDbus(); +} + +} // namespace config +} // namespace ras +} // namespace amd diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..5e90a1e --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,40 @@ +/* + 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 "config_manager.hpp" + +#include +#include +#include + +int main() +{ + // Setup connection to D-Bus + boost::asio::io_service io; + + // Create a shared connection to the system bus + auto systemBus = std::make_shared(io); + + // Request a unique name on the D-Bus + systemBus->request_name(amd::ras::config::service); + + // Create an object server for managing D-Bus objects + sdbusplus::asio::object_server objectServer(systemBus); + + amd::ras::config::Manager manager(objectServer, systemBus); + + io.run(); + + return 0; +}