blob: b487daf7e192a2123c9964a1a5162949077f84fd [file]
#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