| // Copyright 2020 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #ifndef ZIRCON_KERNEL_LIB_BOOT_OPTIONS_ENUM_H_ |
| #define ZIRCON_KERNEL_LIB_BOOT_OPTIONS_ENUM_H_ |
| |
| #include <lib/boot-options/types.h> |
| #include <stdio.h> |
| #include <zircon/assert.h> |
| |
| #include <optional> |
| #include <string_view> |
| |
| // This is specialized for each Enum type with a generic lambda that calls |
| // either EnumParser::Case or EnumPrinter::Case once for each enum value. |
| template <typename T> |
| constexpr bool Enum = false; // Will cause errors since it's not callable. |
| |
| #if BOOT_OPTIONS_TESTONLY_OPTIONS |
| template <> |
| constexpr auto Enum<TestEnum> = [](auto&& Switch) { |
| return Switch // |
| .Case("default", TestEnum::kDefault) |
| .Case("value1", TestEnum::kValue1) |
| .Case("value2", TestEnum::kValue2); |
| }; |
| #endif |
| |
| template <> |
| constexpr auto Enum<OomBehavior> = [](auto&& Switch) { |
| return Switch // |
| .Case("reboot", OomBehavior::kReboot) |
| .Case("jobkill", OomBehavior::kJobKill); |
| }; |
| |
| template <> |
| constexpr auto Enum<PageTableEvictionPolicy> = [](auto&& Switch) { |
| return Switch // |
| .Case("always", PageTableEvictionPolicy::kAlways) |
| .Case("never", PageTableEvictionPolicy::kNever) |
| .Case("on_request", PageTableEvictionPolicy::kOnRequest); |
| }; |
| |
| template <> |
| constexpr auto Enum<EntropyTestSource> = [](auto&& Switch) { |
| return Switch // |
| .Case("hw_rng", EntropyTestSource::kHwRng) |
| .Case("jitterentropy", EntropyTestSource::kJitterEntropy); |
| }; |
| |
| template <> |
| constexpr auto Enum<SerialDebugSyscalls> = [](auto&& Switch) { |
| return Switch // |
| .Case("false", SerialDebugSyscalls::kDisabled) |
| .Case("true", SerialDebugSyscalls::kEnabled) |
| .Case("output-only", SerialDebugSyscalls::kOutputOnly); |
| }; |
| |
| template <> |
| constexpr auto Enum<GfxConsoleFont> = [](auto&& Switch) { |
| return Switch // |
| .Case("9x16", GfxConsoleFont::k9x16) |
| .Case("18x32", GfxConsoleFont::k18x32); |
| }; |
| |
| template <> |
| constexpr auto Enum<RootJobBehavior> = [](auto&& Switch) { |
| return Switch // |
| .Case("halt", RootJobBehavior::kHalt) |
| .Case("reboot", RootJobBehavior::kReboot) |
| .Case("bootloader", RootJobBehavior::kBootloader) |
| .Case("recovery", RootJobBehavior::kRecovery) |
| .Case("shutdown", RootJobBehavior::kShutdown); |
| }; |
| |
| template <> |
| constexpr auto Enum<WallclockType> = [](auto&& Switch) { |
| return Switch // |
| .Case("auto", WallclockType::kAutoDetect) |
| .Case("tsc", WallclockType::kTsc) |
| .Case("pit", WallclockType::kPit) |
| .Case("hpet", WallclockType::kHpet); |
| }; |
| |
| template <> |
| constexpr auto Enum<ScannerLruAction> = [](auto&& Switch) { |
| return Switch // |
| .Case("none", ScannerLruAction::kNone) |
| .Case("evict_only", ScannerLruAction::kEvictOnly) |
| .Case("compress_only", ScannerLruAction::kCompressOnly) |
| .Case("evict_and_compress", ScannerLruAction::kEvictAndCompress); |
| }; |
| |
| template <> |
| constexpr auto Enum<CompressionStrategy> = [](auto&& Switch) { |
| return Switch // |
| .Case("none", CompressionStrategy::kNone) |
| .Case("lz4", CompressionStrategy::kLz4); |
| }; |
| |
| template <> |
| constexpr auto Enum<CompressionStorageStrategy> = [](auto&& Switch) { |
| return Switch // |
| .Case("none", CompressionStorageStrategy::kNone) |
| .Case("tri_page", CompressionStorageStrategy::kTriPage); |
| }; |
| |
| #if BOOT_OPTIONS_GENERATOR || defined(__aarch64__) |
| |
| template <> |
| constexpr auto Enum<Arm64PhysPsciReset> = [](auto&& Switch) { |
| return Switch // |
| .Case("disabled", Arm64PhysPsciReset::kDisabled) |
| .Case("shutdown", Arm64PhysPsciReset::kShutdown) |
| .Case("reboot", Arm64PhysPsciReset::kReboot) |
| .Case("reboot-bootloader", Arm64PhysPsciReset::kRebootBootloader) |
| .Case("reboot-recovery", Arm64PhysPsciReset::kRebootRecovery); |
| }; |
| |
| #endif // BOOT_OPTIONS_GENERATOR || defined(__x86_64__) |
| |
| #if BOOT_OPTIONS_GENERATOR || defined(__x86_64__) |
| |
| template <> |
| constexpr auto Enum<IntelHwpPolicy> = [](auto&& Switch) { |
| return Switch // |
| .Case("bios-specified", IntelHwpPolicy::kBiosSpecified) |
| .Case("performance", IntelHwpPolicy::kPerformance) |
| .Case("balanced", IntelHwpPolicy::kBalanced) |
| .Case("power-save", IntelHwpPolicy::kPowerSave) |
| .Case("stable-performance", IntelHwpPolicy::kStablePerformance); |
| }; |
| |
| #endif // BOOT_OPTIONS_GENERATOR || defined(__x86_64__) |
| |
| // Helpers for enum overrides. |
| |
| template <typename F, typename T> |
| class EnumEnumerator { |
| public: |
| EnumEnumerator(F call, T value) : call_(std::move(call)), value_(std::move(value)) {} |
| |
| constexpr EnumEnumerator& Case(std::string_view name, T value) { |
| call_(name); |
| return *this; |
| } |
| |
| private: |
| F call_; |
| T value_; |
| }; |
| |
| template <typename T> |
| class EnumParser { |
| public: |
| EnumParser(std::string_view name, T* result) : name_(name), result_(result) {} |
| constexpr EnumParser(const EnumParser&) noexcept = delete; |
| constexpr EnumParser(EnumParser&& other) noexcept { |
| result_ = other.result_; |
| name_ = other.name_; |
| other.result_ = nullptr; |
| } |
| ~EnumParser() { |
| ZX_DEBUG_ASSERT_MSG(result_ == nullptr, "Failed to call EnumParser::Check() value: %.*s", |
| static_cast<int>(name_.size()), name_.data()); |
| } |
| |
| bool Check() { |
| T* actual = result_; |
| result_ = nullptr; |
| if (actual) { |
| printf("WARN: Ignored unknown value '%.*s' for multiple-choice option %p\n", |
| static_cast<int>(name_.size()), name_.data(), this); |
| printf("WARN: Valid choices are:"); |
| Enum<T>(EnumEnumerator{[](std::string_view name) { |
| printf(" %.*s", static_cast<int>(name.size()), name.data()); |
| }, |
| *actual}); |
| printf("\n"); |
| } |
| return actual == nullptr; |
| } |
| |
| constexpr EnumParser&& Case(std::string_view name, T value) { |
| if (result_ && name == name_) { |
| *result_ = value; |
| result_ = nullptr; |
| } |
| return std::move(*this); |
| } |
| |
| private: |
| std::string_view name_; |
| T* result_ = nullptr; |
| }; |
| |
| template <typename T> |
| class EnumPrinter { |
| public: |
| EnumPrinter(T value, FILE* out) : value_(std::move(value)), out_(out) {} |
| |
| EnumPrinter& Case(std::string_view name, T value) { |
| if (value_ && *value_ == value) { |
| value_.reset(); |
| fprintf(out_, "%.*s", static_cast<int>(name.size()), name.data()); |
| } |
| return *this; |
| } |
| |
| ~EnumPrinter() { |
| if (value_) { |
| fprintf(out_, "<unknown.enum.value.%#lx>", static_cast<unsigned long int>(*value_)); |
| } |
| } |
| |
| private: |
| std::optional<T> value_; |
| FILE* out_ = nullptr; |
| }; |
| |
| // Deduction guides. |
| |
| template <typename F, typename T> |
| EnumEnumerator(F, T) -> EnumEnumerator<F, T>; |
| |
| template <typename T> |
| EnumParser(std::string_view, T*) -> EnumParser<T>; |
| |
| template <typename T> |
| EnumPrinter(const T&, FILE*) -> EnumPrinter<T>; |
| |
| #endif // ZIRCON_KERNEL_LIB_BOOT_OPTIONS_ENUM_H_ |