| #include "tlbmc/hal/system_registry_impl.h" |
| |
| #include <array> |
| #include <cstdint> |
| #include <filesystem> // NOLINT |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| #include "gbmc_settings/bios_settings.pb.h" |
| #include "gbmc_settings/gbmc_settings.h" |
| #include "gbmc_settings/gbmc_settings.pb.h" |
| #include "gbmc-hal/api/app/cpu/bios_config.h" |
| #include "gbmc-hal/api/system/registries.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/escaping.h" |
| #include "absl/strings/str_cat.h" |
| #include "g3/macros.h" |
| #include "tlbmc/redfish/routes/action_managers/file_manager.h" |
| #include "tlbmc/utils/command_executor.h" |
| #include "tlbmc/utils/shell_command_executor.h" |
| |
| namespace milotic_tlbmc { |
| |
| using ::gbmc::settings::BootSourceOverrideTarget; |
| using ::gbmc::settings::GbmcSettings; |
| using ::gbmc::settings::SystemId; |
| using ::platforms::gbmc::hal::BiosConfigRegistry; |
| using ::platforms::gbmc::hal::BiosSettingType; |
| |
| namespace { |
| |
| constexpr auto kAllSystemIds = std::to_array<SystemId>({ |
| SystemId::SYSTEM_ID_SYSTEM, |
| SystemId::SYSTEM_ID_SYSTEM1, |
| SystemId::SYSTEM_ID_SYSTEM2, |
| }); |
| |
| } // namespace |
| |
| absl::StatusOr<SystemRegistryImpl::IfsConfig> SystemRegistryImpl::GetIfsConfig( |
| SystemId system_id) { |
| switch (system_id) { |
| case SystemId::SYSTEM_ID_SYSTEM: |
| return IfsConfig{"ifs/scan.bin", "start-ifs.service", "stop-ifs.service"}; |
| case SystemId::SYSTEM_ID_SYSTEM1: |
| return IfsConfig{"ifs_1/scan.bin", "start-ifs@1.service", |
| "stop-ifs@1.service"}; |
| case SystemId::SYSTEM_ID_SYSTEM2: |
| return IfsConfig{"ifs_2/scan.bin", "start-ifs@2.service", |
| "stop-ifs@2.service"}; |
| default: |
| return absl::InvalidArgumentError("Unhandled SystemId"); |
| } |
| } |
| |
| absl::StatusOr<uint8_t> SystemRegistryImpl::SystemIdToHostIndex( |
| SystemId system_id) { |
| switch (system_id) { |
| case SystemId::SYSTEM_ID_SYSTEM: |
| return 0; |
| case SystemId::SYSTEM_ID_SYSTEM1: |
| return 0; |
| case SystemId::SYSTEM_ID_SYSTEM2: |
| return 1; |
| default: |
| return absl::InvalidArgumentError("Invalid system id"); |
| } |
| } |
| |
| absl::StatusOr<SystemId> SystemRegistryImpl::RedfishSystemIdToSystemId( |
| std::string_view redfish_system_id) { |
| if (redfish_system_id == "system") { |
| return SystemId::SYSTEM_ID_SYSTEM; |
| } |
| if (redfish_system_id == "system1") { |
| return SystemId::SYSTEM_ID_SYSTEM1; |
| } |
| if (redfish_system_id == "system2") { |
| return SystemId::SYSTEM_ID_SYSTEM2; |
| } |
| return absl::InvalidArgumentError( |
| absl::StrCat("Invalid system id: ", redfish_system_id)); |
| } |
| |
| absl::StatusOr<uint8_t> SystemRegistryImpl::RedfishSystemIdToHostIndex( |
| std::string_view redfish_system_id) { |
| if (redfish_system_id == "system") { |
| return 0; |
| } |
| if (redfish_system_id == "system1") { |
| return 0; |
| } |
| if (redfish_system_id == "system2") { |
| return 1; |
| } |
| return absl::InvalidArgumentError( |
| absl::StrCat("Invalid system id: ", redfish_system_id)); |
| } |
| |
| absl::StatusOr<std::shared_ptr<SystemRegistryImpl>> SystemRegistryImpl::Create( |
| const Config& config) { |
| AllRegistries all_registries; |
| // Currently there is no SAL so we will have to pass in IPMI for now. |
| // Eventually we will get rid of it as SAL will know which config to use. |
| if (config.bios_config_config != nullptr) { |
| ECCLESIA_ASSIGN_OR_RETURN( |
| all_registries.bios_config, |
| BiosConfigRegistry::Create("IpmiBiosConfig", |
| *config.bios_config_config)); |
| } |
| |
| return std::make_shared<SystemRegistryImpl>( |
| Token(), std::move(all_registries), config.ifs_base_path, |
| std::make_unique<ShellExecutor>()); |
| } |
| |
| absl::Status SystemRegistryImpl::SetInitialCoreCounts() { |
| if (all_registries_.bios_config == nullptr) { |
| return absl::FailedPreconditionError( |
| "BIOS config is not initialized, cannot set initial BIOS core count."); |
| } |
| |
| // Get the BIOS core count from the settings. |
| ECCLESIA_ASSIGN_OR_RETURN(GbmcSettings settings, settings_manager_->Read()); |
| |
| // If there are no core counts set, we will reset the core count for all |
| // systems. |
| if (settings.bios_settings().system_bios_settings().empty()) { |
| for (const auto& system_id : kAllSystemIds) { |
| ECCLESIA_ASSIGN_OR_RETURN(uint8_t host_index, |
| SystemIdToHostIndex(system_id)); |
| ECCLESIA_RETURN_IF_ERROR(all_registries_.bios_config->SetBiosSetting( |
| host_index, BiosSettingType::CoreCount, std::to_string(0))); |
| } |
| return absl::OkStatus(); |
| } |
| |
| for (const auto& system_bios_setting : |
| settings.bios_settings().system_bios_settings()) { |
| ECCLESIA_ASSIGN_OR_RETURN( |
| uint8_t host_index, |
| SystemIdToHostIndex(system_bios_setting.system_id())); |
| ECCLESIA_RETURN_IF_ERROR(all_registries_.bios_config->SetBiosSetting( |
| host_index, BiosSettingType::CoreCount, |
| std::to_string(system_bios_setting.core_count()))); |
| LOG(WARNING) << "Set initial BIOS core count as configured for host " |
| << host_index << " to " << system_bios_setting.core_count(); |
| } |
| return absl::OkStatus(); |
| } |
| |
| // This will eventually contain all the logic to initialize all of the HAL |
| // registries. For now, it is empty. |
| SystemRegistryImpl::SystemRegistryImpl( |
| [[maybe_unused]] Token token, AllRegistries&& all_registries, |
| std::string_view ifs_base_path, |
| std::unique_ptr<const CommandExecutor> command_executor) |
| : all_registries_(std::move(all_registries)), |
| ifs_base_path_(ifs_base_path), |
| command_executor_(std::move(command_executor)) { |
| settings_manager_ = std::make_unique<gbmc::settings::SettingsManager>(); |
| } |
| |
| absl::StatusOr<uint32_t> SystemRegistryImpl::GetCoreCount( |
| std::string_view redfish_system_id) { |
| if (all_registries_.bios_config == nullptr) { |
| return absl::FailedPreconditionError( |
| "BIOS config is not initialized, cannot get BIOS core count."); |
| } |
| |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| |
| absl::StatusOr<uint32_t> count = |
| settings_manager_->GetBiosSettingsCoreCount(system_id); |
| |
| if (!count.ok()) { |
| if (absl::IsNotFound(count.status())) { |
| return absl::UnimplementedError( |
| absl::StrCat("Settings manager is not implemented on this system: ", |
| count.status().message())); |
| } |
| return count.status(); |
| } |
| return *count; |
| } |
| |
| absl::Status SystemRegistryImpl::SetCoreCount( |
| std::string_view redfish_system_id, uint32_t core_count) { |
| if (all_registries_.bios_config == nullptr) { |
| return absl::FailedPreconditionError( |
| "BIOS config is not initialized, cannot set BIOS core count."); |
| } |
| |
| ECCLESIA_ASSIGN_OR_RETURN(uint8_t host_index, |
| RedfishSystemIdToHostIndex(redfish_system_id)); |
| ECCLESIA_RETURN_IF_ERROR(all_registries_.bios_config->SetBiosSetting( |
| host_index, BiosSettingType::CoreCount, std::to_string(core_count))); |
| |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| // Write the settings to GbmcSettings. |
| return settings_manager_->SetBiosSettingsCoreCount(system_id, core_count); |
| } |
| absl::StatusOr<std::string> SystemRegistryImpl::GetBase64EncodedIfsPattern( |
| std::string_view redfish_system_id) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| ECCLESIA_ASSIGN_OR_RETURN(IfsConfig config, GetIfsConfig(system_id)); |
| std::filesystem::path file_path = |
| std::filesystem::path(ifs_base_path_) / config.relative_path; |
| absl::StatusOr<std::string> raw_pattern = |
| FileManager::ReadFile(file_path.string()); |
| if (absl::IsNotFound(raw_pattern.status())) { |
| return ""; |
| } |
| ECCLESIA_RETURN_IF_ERROR(raw_pattern.status()); |
| return absl::Base64Escape(*raw_pattern); |
| } |
| |
| absl::Status SystemRegistryImpl::SetIfsPattern( |
| std::string_view redfish_system_id, std::string_view base64_ifs_pattern) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| |
| std::string decoded_pattern; |
| if (!absl::Base64Unescape(base64_ifs_pattern, &decoded_pattern)) { |
| return absl::InvalidArgumentError("Failed to base64 decode IFS pattern"); |
| } |
| |
| ECCLESIA_ASSIGN_OR_RETURN(IfsConfig config, GetIfsConfig(system_id)); |
| std::filesystem::path file_path = |
| std::filesystem::path(ifs_base_path_) / config.relative_path; |
| |
| ECCLESIA_RETURN_IF_ERROR( |
| FileManager::WriteToFile(decoded_pattern, file_path.string())); |
| std::string cmd = |
| absl::StrCat("systemctl start --no-block ", config.service_name); |
| ECCLESIA_RETURN_IF_ERROR( |
| command_executor_->Execute(cmd, /*ignore_error=*/false).status()); |
| |
| return absl::OkStatus(); |
| } |
| |
| absl::Status SystemRegistryImpl::ResetIfsPattern( |
| std::string_view redfish_system_id) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| |
| ECCLESIA_ASSIGN_OR_RETURN(IfsConfig config, GetIfsConfig(system_id)); |
| |
| std::string cmd = |
| absl::StrCat("systemctl start --no-block ", config.stop_service_name); |
| ECCLESIA_RETURN_IF_ERROR( |
| command_executor_->Execute(cmd, /*ignore_error=*/false).status()); |
| |
| return absl::OkStatus(); |
| } |
| |
| absl::StatusOr<std::string> SystemRegistryImpl::GetBootNext( |
| std::string_view redfish_system_id) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| return settings_manager_->GetBiosSettingsBootNext(system_id); |
| } |
| |
| absl::Status SystemRegistryImpl::SetBootNext(std::string_view redfish_system_id, |
| std::string_view boot_next) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| return settings_manager_->SetBiosSettingsBootNext(system_id, boot_next); |
| } |
| |
| absl::StatusOr<BootSourceOverrideTarget> |
| SystemRegistryImpl::GetBootSourceOverrideTarget( |
| std::string_view redfish_system_id) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| return settings_manager_->GetBiosSettingsBootSourceOverrideTarget(system_id); |
| } |
| |
| absl::Status SystemRegistryImpl::SetBootSourceOverrideTarget( |
| std::string_view redfish_system_id, |
| BootSourceOverrideTarget boot_source_override_target) { |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| return settings_manager_->SetBiosSettingsBootSourceOverrideTarget( |
| system_id, boot_source_override_target); |
| } |
| |
| absl::StatusOr<uint32_t> SystemRegistryImpl::GetMemoryCapacityGib( |
| std::string_view redfish_system_id) { |
| if (all_registries_.bios_config == nullptr) { |
| return absl::FailedPreconditionError( |
| "BIOS config is not initialized, cannot get BIOS memory capacity."); |
| } |
| |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| |
| absl::StatusOr<uint32_t> capacity = |
| settings_manager_->GetBiosSettingsMemoryCapacityGib(system_id); |
| |
| if (!capacity.ok()) { |
| if (absl::IsNotFound(capacity.status())) { |
| return absl::UnimplementedError( |
| absl::StrCat("Settings manager is not implemented on this system: ", |
| capacity.status().message())); |
| } |
| return capacity.status(); |
| } |
| return *capacity; |
| } |
| |
| absl::Status SystemRegistryImpl::SetMemoryCapacityGib( |
| std::string_view redfish_system_id, uint32_t capacity_gib) { |
| if (all_registries_.bios_config == nullptr) { |
| return absl::FailedPreconditionError( |
| "BIOS config is not initialized, cannot set BIOS memory capacity."); |
| } |
| |
| ECCLESIA_ASSIGN_OR_RETURN(uint8_t host_index, |
| RedfishSystemIdToHostIndex(redfish_system_id)); |
| ECCLESIA_RETURN_IF_ERROR(all_registries_.bios_config->SetBiosSetting( |
| host_index, BiosSettingType::MemoryCapacityGib, |
| std::to_string(capacity_gib))); |
| |
| ECCLESIA_ASSIGN_OR_RETURN(SystemId system_id, |
| RedfishSystemIdToSystemId(redfish_system_id)); |
| // Write the settings to GbmcSettings. |
| return settings_manager_->SetBiosSettingsMemoryCapacityGib(system_id, |
| capacity_gib); |
| } |
| |
| } // namespace milotic_tlbmc |