mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
Kernel/riscv64: Use the Zkr extension for entropy, if supported
This commit is contained in:
1 parent
3e0ef9397a
commit
048ba5b4d0
5 files changed
+110
-7
No files matched your search
@@ -28,6 +28,9 @@ enum class Address : u16 {
|
||||
VTYPE = 0xc21,
|
||||
VLENB = 0xc22,
|
||||
|
||||
// Unprivileged Entropy Source Extension CSR
|
||||
SEED = 0x015,
|
||||
|
||||
// Unprivileged Counters/Timers
|
||||
CYCLE = 0xc00,
|
||||
TIME = 0xc01,
|
||||
@@ -235,6 +238,37 @@ struct SSTATUS {
|
||||
};
|
||||
static_assert(AssertSize<SSTATUS, 8>());
|
||||
|
||||
// https://docs.riscv.org/reference/isa/unpriv/scalar-crypto.html#crypto_scalar_es
|
||||
struct SEED {
|
||||
enum class Status : u64 {
|
||||
BIST = 0b00,
|
||||
WAIT = 0b01,
|
||||
ES16 = 0b10,
|
||||
DEAD = 0b11,
|
||||
};
|
||||
|
||||
u64 entropy : 16;
|
||||
u64 : 8;
|
||||
u64 : 6;
|
||||
Status OPST : 2;
|
||||
u64 : 32;
|
||||
|
||||
static ALWAYS_INLINE SEED read()
|
||||
{
|
||||
// "Attempts to access the seed CSR using a read-only CSR-access instruction (CSRRS/CSRRC with rs1=x0 or CSRRSI/CSRRCI with uimm=0)
|
||||
// raise an illegal-instruction exception; any other CSR-access instruction may be used to access seed.
|
||||
// The write value (in rs1 or uimm) must be ignored by implementations. The purpose of the write is to signal polling and flushing.
|
||||
//
|
||||
// Software normally uses the instruction csrrw rd, seed, x0 to read the seed CSR."
|
||||
|
||||
FlatPtr value { 0 };
|
||||
asm volatile("csrrw %0, seed, x0" : "=r"(value));
|
||||
|
||||
return bit_cast<SEED>(value);
|
||||
}
|
||||
};
|
||||
static_assert(AssertSize<SEED, 8>());
|
||||
|
||||
// 4.1.8 Supervisor Cause Register (scause)
|
||||
constexpr u64 SCAUSE_INTERRUPT_MASK = 1LU << 63;
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Sönke Holz <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/riscv64/Entropy.h>
|
||||
|
||||
namespace Kernel::RISCV64 {
|
||||
|
||||
// https://docs.riscv.org/reference/isa/unpriv/scalar-crypto.html#crypto_scalar_es
|
||||
ErrorOr<u16> poll_seed_csr_for_entropy()
|
||||
{
|
||||
VERIFY(Processor::current().has_feature(CPUFeature::Zkr));
|
||||
|
||||
for (;;) {
|
||||
auto seed_csr_value = RISCV64::CSR::SEED::read();
|
||||
if (seed_csr_value.OPST == RISCV64::CSR::SEED::Status::DEAD) {
|
||||
dmesgln("RISC-V seed CSR reported an unrecoverable self-test error!");
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if (seed_csr_value.OPST == RISCV64::CSR::SEED::Status::ES16)
|
||||
return static_cast<u16>(seed_csr_value.entropy);
|
||||
|
||||
Processor::wait_check();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Sönke Holz <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace Kernel::RISCV64 {
|
||||
|
||||
ErrorOr<u16> poll_seed_csr_for_entropy();
|
||||
|
||||
}
|
||||
@@ -580,6 +580,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "riscv64")
|
||||
Arch/riscv64/CurrentTime.cpp
|
||||
Arch/riscv64/DebugOutput.cpp
|
||||
Arch/riscv64/Delay.cpp
|
||||
Arch/riscv64/Entropy.cpp
|
||||
Arch/riscv64/InterruptManagement.cpp
|
||||
Arch/riscv64/Interrupts.cpp
|
||||
Arch/riscv64/Interrupts/PLIC.cpp
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
# include <Kernel/Arch/x86_64/Time/RTC.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/ASM_wrapper.h>
|
||||
#elif ARCH(RISCV64)
|
||||
# include <Kernel/Arch/riscv64/Entropy.h>
|
||||
#endif
|
||||
#include <Kernel/Devices/Generic/RandomDevice.h>
|
||||
#include <Kernel/Sections.h>
|
||||
@@ -78,13 +80,33 @@ UNMAP_AFTER_INIT KernelRng::KernelRng()
|
||||
}
|
||||
}
|
||||
#elif ARCH(RISCV64)
|
||||
// Fallback to TimeManagement as entropy
|
||||
dmesgln("KernelRng: Using bad entropy source TimeManagement");
|
||||
auto current_time = static_cast<u64>(TimeManagement::now().milliseconds_since_epoch());
|
||||
for (size_t i = 0; i < pool_count * reseed_threshold; ++i) {
|
||||
add_random_event(current_time, i % 32);
|
||||
current_time *= 0x574au;
|
||||
current_time += 0x40b2u;
|
||||
auto try_zkr_entropy = [this] -> bool {
|
||||
if (!Processor::current().has_feature(CPUFeature::Zkr))
|
||||
return false;
|
||||
|
||||
dmesgln("KernelRng: Using Zkr extension as entropy source");
|
||||
|
||||
for (size_t i = 0; i < pool_count * reseed_threshold; ++i) {
|
||||
auto entropy_or_error = RISCV64::poll_seed_csr_for_entropy();
|
||||
if (entropy_or_error.is_error())
|
||||
return false;
|
||||
|
||||
add_random_event(entropy_or_error.value(), i % 32);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!try_zkr_entropy()) {
|
||||
// Fallback to TimeManagement as entropy
|
||||
dmesgln("KernelRng: Using bad entropy source TimeManagement");
|
||||
|
||||
auto current_time = static_cast<u64>(TimeManagement::now().milliseconds_since_epoch());
|
||||
for (size_t i = 0; i < pool_count * reseed_threshold; ++i) {
|
||||
add_random_event(current_time, i % 32);
|
||||
current_time *= 0x574au;
|
||||
current_time += 0x40b2u;
|
||||
}
|
||||
}
|
||||
#else
|
||||
dmesgln("KernelRng: No entropy source available!");
|
||||
|
||||
Reference in new issue
Block a user