[kernel][arm64][phys] Use hardware RNG when available for stack-guard
Also convert uses of the ISA/CPU feature registers to arch::SysReg.
Change-Id: I848be7ffd20223bcae0434236b98235447b4d719
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/500267
Commit-Queue: Roland McGrath <mcgrathr@google.com>
Reviewed-by: Travis Geiselbrecht <travisg@google.com>
Reviewed-by: Joshua Seaton <joshuaseaton@google.com>
diff --git a/zircon/kernel/arch/arm64/feature.cc b/zircon/kernel/arch/arm64/feature.cc
index 3a737b2..7e492f1 100644
--- a/zircon/kernel/arch/arm64/feature.cc
+++ b/zircon/kernel/arch/arm64/feature.cc
@@ -7,6 +7,7 @@
#include <bits.h>
#include <inttypes.h>
+#include <lib/arch/arm64/feature.h>
#include <lib/arch/intrin.h>
#include <arch/arm64.h>
@@ -318,60 +319,69 @@
// parse the ISA feature bits
arm64_isa_features |= ZX_HAS_CPU_FEATURES;
- uint64_t isar0 = __arm_rsr64("id_aa64isar0_el1");
- if (BITS_SHIFT(isar0, 7, 4) >= 1) {
- arm64_isa_features |= ZX_ARM64_FEATURE_ISA_AES;
+
+ auto isar0 = arch::ArmIdAa64IsaR0El1::Read();
+
+ // Other values are reserved. When assigned they will probably be
+ // supersets of FEAT_PMULL, but don't presume that.
+ switch (isar0.aes()) {
+ case arch::ArmIdAa64IsaR0El1::Aes::kPmull:
+ arm64_isa_features |= ZX_ARM64_FEATURE_ISA_PMULL;
+ [[fallthrough]];
+ case arch::ArmIdAa64IsaR0El1::Aes::kAes:
+ arm64_isa_features |= ZX_ARM64_FEATURE_ISA_AES;
+ break;
+ case arch::ArmIdAa64IsaR0El1::Aes::kNone:
+ break;
}
- if (BITS_SHIFT(isar0, 7, 4) >= 2) {
- arm64_isa_features |= ZX_ARM64_FEATURE_ISA_PMULL;
- }
- if (BITS_SHIFT(isar0, 11, 8) >= 1) {
+
+ if (isar0.sha1() != arch::ArmIdAa64IsaR0El1::Sha1::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_SHA1;
}
- if (BITS_SHIFT(isar0, 15, 12) >= 1) {
+ if (isar0.sha2() != arch::ArmIdAa64IsaR0El1::Sha2::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_SHA2;
}
- if (BITS_SHIFT(isar0, 19, 16) >= 1) {
+ if (isar0.crc32() != arch::ArmIdAa64IsaR0El1::Crc32::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_CRC32;
}
- if (BITS_SHIFT(isar0, 23, 20) >= 1) {
+ if (isar0.atomic() != arch::ArmIdAa64IsaR0El1::Atomic::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_ATOMICS;
}
- if (BITS_SHIFT(isar0, 31, 28) >= 1) {
+ if (isar0.rdm() != arch::ArmIdAa64IsaR0El1::Rdm::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_RDM;
}
- if (BITS_SHIFT(isar0, 35, 32) >= 1) {
+ if (isar0.sha3() != arch::ArmIdAa64IsaR0El1::Sha3::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_SHA3;
}
- if (BITS_SHIFT(isar0, 39, 36) >= 1) {
+ if (isar0.sm3() != arch::ArmIdAa64IsaR0El1::Sm3::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_SM3;
}
- if (BITS_SHIFT(isar0, 43, 40) >= 1) {
+ if (isar0.sm4() != arch::ArmIdAa64IsaR0El1::Sm4::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_SM4;
}
- if (BITS_SHIFT(isar0, 47, 44) >= 1) {
+ if (isar0.dp() != arch::ArmIdAa64IsaR0El1::DotProd::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_DP;
}
- if (BITS_SHIFT(isar0, 51, 48) >= 1) {
+ if (isar0.fhm() != arch::ArmIdAa64IsaR0El1::Fhm::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_FHM;
}
- if (BITS_SHIFT(isar0, 55, 52) >= 1) {
+ if (isar0.ts() != arch::ArmIdAa64IsaR0El1::Ts::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_TS;
}
- if (BITS_SHIFT(isar0, 63, 60) >= 1) {
+ if (isar0.rndr() != arch::ArmIdAa64IsaR0El1::Rndr::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_RNDR;
}
- uint64_t isar1 = __arm_rsr64("id_aa64isar1_el1");
- if (BITS_SHIFT(isar1, 3, 0) >= 1) {
+ auto isar1 = arch::ArmIdAa64IsaR1El1::Read();
+ if (isar1.dpb() != arch::ArmIdAa64IsaR1El1::Dpb::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_DPB;
}
- uint64_t pfr0 = __arm_rsr64("id_aa64pfr0_el1");
- if (BITS_SHIFT(pfr0, 19, 16) < 0b1111) {
+ auto pfr0 = arch::ArmIdAa64Pfr0El1::Read();
+ if (pfr0.fp() != arch::ArmIdAa64Pfr0El1::Fp::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_FP;
}
- if (BITS_SHIFT(pfr0, 23, 20) < 0b1111) {
+ if (pfr0.advsimd() != arch::ArmIdAa64Pfr0El1::Fp::kNone) {
arm64_isa_features |= ZX_ARM64_FEATURE_ISA_ASIMD;
}
diff --git a/zircon/kernel/arch/arm64/phys/start.S b/zircon/kernel/arch/arm64/phys/start.S
index 279f015..4359d53 100644
--- a/zircon/kernel/arch/arm64/phys/start.S
+++ b/zircon/kernel/arch/arm64/phys/start.S
@@ -4,6 +4,7 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
+#include <lib/arch/arm64/feature-asm.h>
#include <lib/arch/asm.h>
#include <lib/arch/ticks.h>
#include <zircon/tls.h>
@@ -43,11 +44,26 @@
adr_global tp, boot_thread_pointer
msr tpidr_el1, tp
- // Stack guard canary value. The only "randomness" readily available is
- // our own load address, so swizzle that in with some arbitrary bits.
+ // Stack guard canary value.
boot_stack_guard .req x10
+
+ // If hardware random numbers are available, use them.
+ .arch armv8.5-a+rng
+ mrs boot_stack_guard, ID_AA64ISAR0_EL1
+ tst boot_stack_guard, #ID_AA64ISAR0_EL1_RNDR
+ beq .Lno_rndr
+ // Reading this register sets the Z flag if no good randomness is delivered.
+ mrs boot_stack_guard, RNDRRS
+ bne .Lstack_guard_done
+ mrs boot_stack_guard, RNDR
+ bne .Lstack_guard_done
+
+.Lno_rndr:
+ // The only "randomness" readily available is our own load address, so
+ // swizzle that in with some arbitrary bits.
movlit boot_stack_guard, 0xdeadbeef1ee2d00d
eor boot_stack_guard, tp, boot_stack_guard
+.Lstack_guard_done:
#if __has_feature(safe_stack)
boot_unsafe_stack_ptr .req x11
diff --git a/zircon/kernel/lib/arch/BUILD.gn b/zircon/kernel/lib/arch/BUILD.gn
index ed4c865..d273dd0 100644
--- a/zircon/kernel/lib/arch/BUILD.gn
+++ b/zircon/kernel/lib/arch/BUILD.gn
@@ -38,6 +38,7 @@
# library need never realize it's distinct.
deps += [ zircon_cpu ]
public_deps += [
+ ":gen-arm64-feature-asm",
":gen-x86-msr-asm",
"$zircon_cpu:headers",
]
@@ -50,3 +51,10 @@
sources = [ "gen-x86-msr-asm.cc" ]
deps = [ ":arch" ]
}
+
+hwreg_asm_header("gen-arm64-feature-asm") {
+ visibility = [ ":*" ]
+ output_name = "lib/arch/arm64/feature-asm.h"
+ sources = [ "gen-arm64-feature-asm.cc" ]
+ deps = [ ":arch" ]
+}
diff --git a/zircon/kernel/lib/arch/gen-arm64-feature-asm.cc b/zircon/kernel/lib/arch/gen-arm64-feature-asm.cc
new file mode 100644
index 0000000..01a22f5
--- /dev/null
+++ b/zircon/kernel/lib/arch/gen-arm64-feature-asm.cc
@@ -0,0 +1,15 @@
+// Copyright 2021 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
+
+#include <lib/arch/arm64/feature.h>
+
+#include <hwreg/asm.h>
+
+int main(int argc, char** argv) {
+ return hwreg::AsmHeader() //
+ .Register<arch::ArmIdAa64IsaR0El1>("ID_AA64ISAR0_EL1_")
+ .Main(argc, argv);
+}
diff --git a/zircon/kernel/lib/arch/include/lib/arch/arm64/feature.h b/zircon/kernel/lib/arch/include/lib/arch/arm64/feature.h
new file mode 100644
index 0000000..400fc1b
--- /dev/null
+++ b/zircon/kernel/lib/arch/include/lib/arch/arm64/feature.h
@@ -0,0 +1,297 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_ARM64_FEATURE_H_
+#define ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_ARM64_FEATURE_H_
+
+#include <lib/arch/sysreg.h>
+
+#include <hwreg/bitfields.h>
+
+namespace arch {
+
+// [arm/sysreg]/ID_AA64ISAR0_EL1: AArch64 Instruction Set Attribute Register 0
+struct ArmIdAa64IsaR0El1 : public SysRegBase<ArmIdAa64IsaR0El1, uint64_t, hwreg::EnablePrinter> {
+ enum class Rndr : uint8_t {
+ kNone = 0b0000,
+ kRng = 0b0001,
+ };
+
+ enum class Tlb : uint8_t {
+ kNone = 0b0000,
+ kTlbios = 0b0001,
+ kkTlbirange = 0b0010,
+ };
+
+ enum class Ts : uint8_t {
+ kNone = 0b0000,
+ kFlagM = 0b0001,
+ kFlagM2 = 0b0010,
+ };
+
+ enum class Fhm : uint8_t {
+ kNone = 0b0000,
+ kFhm = 0b0001,
+ };
+
+ enum class DotProd : uint8_t {
+ kNone = 0b0000,
+ kDotProd = 0b0001,
+ };
+
+ enum class Sm4 : uint8_t {
+ kNone = 0b0000,
+ kSm4 = 0b0001,
+ };
+
+ enum class Sm3 : uint8_t {
+ kNone = 0b0000,
+ kSm3 = 0b0001,
+ };
+
+ enum class Sha3 : uint8_t {
+ kNone = 0b0000,
+ kSha3 = 0b0001,
+ };
+
+ enum class Rdm : uint8_t {
+ kNone = 0b0000,
+ kRdm = 0b0001,
+ };
+
+ enum class Atomic : uint8_t {
+ kNone = 0b0000,
+ kLse = 0b0010,
+ };
+
+ enum class Crc32 : uint8_t {
+ kNone = 0b0000,
+ kCrc32 = 0b0001,
+ };
+
+ enum class Sha2 : uint8_t {
+ kNone = 0b0000,
+ kSha256 = 0b0001,
+ kSha512 = 0b0010,
+ };
+
+ enum class Sha1 : uint8_t {
+ kNone = 0b0000,
+ kSha1 = 0b0001,
+ };
+
+ enum class Aes : uint8_t {
+ kNone = 0b0000,
+ kAes = 0b0001,
+ kPmull = 0b0010,
+ };
+
+ DEF_ENUM_FIELD(Rndr, 63, 60, rndr);
+ DEF_ENUM_FIELD(Tlb, 59, 56, tlb);
+ DEF_ENUM_FIELD(Ts, 55, 52, ts);
+ DEF_ENUM_FIELD(Fhm, 51, 48, fhm);
+ DEF_ENUM_FIELD(DotProd, 47, 44, dp);
+ DEF_ENUM_FIELD(Sm4, 43, 40, sm4);
+ DEF_ENUM_FIELD(Sm3, 39, 36, sm3);
+ DEF_ENUM_FIELD(Sha3, 35, 32, sha3);
+ DEF_ENUM_FIELD(Rdm, 31, 28, rdm);
+ DEF_RSVDZ_FIELD(27, 24);
+ DEF_ENUM_FIELD(Atomic, 23, 20, atomic);
+ DEF_ENUM_FIELD(Crc32, 19, 16, crc32);
+ DEF_ENUM_FIELD(Sha2, 15, 12, sha2);
+ DEF_ENUM_FIELD(Sha1, 11, 8, sha1);
+ DEF_ENUM_FIELD(Aes, 7, 4, aes);
+ DEF_RSVDZ_FIELD(3, 0);
+};
+ARCH_ARM64_SYSREG(ArmIdAa64IsaR0El1, "ID_AA64ISAR0_EL1");
+
+// [arm/sysreg]/ID_AA64ISAR1_EL1: AArch64 Instruction Set Attribute Register 1
+struct ArmIdAa64IsaR1El1 : public SysRegBase<ArmIdAa64IsaR1El1> {
+ enum class Ls64 : uint8_t {
+ kNone = 0b0000,
+ kLs64 = 0b0001,
+ kLs64V = 0b0010,
+ kLs64Accdata = 0b0011,
+ };
+
+ enum class Xs : uint8_t {
+ kNone = 0b0000,
+ kXs = 0b0001,
+ };
+
+ enum class I8mm : uint8_t {
+ kNone = 0b0000,
+ kI8mm = 0b0001,
+ };
+
+ enum class Dgh : uint8_t {
+ kNone = 0b0000,
+ kDgh = 0b0001,
+ };
+
+ enum class Bf16 : uint8_t {
+ kNone = 0b0000,
+ kBf16 = 0b0001,
+ };
+
+ enum class Specres : uint8_t {
+ kNone = 0b0000,
+ kSpecres = 0b0001,
+ };
+
+ enum class Sb : uint8_t {
+ kNone = 0b0000,
+ kSb = 0b0001,
+ };
+
+ enum class Frintts : uint8_t {
+ kNone = 0b0000,
+ kFrintts = 0b0001,
+ };
+
+ enum class Gpi : uint8_t {
+ kNone = 0b0000,
+ kGpi = 0b0001,
+ };
+
+ enum class Gpa : uint8_t {
+ kNone = 0b0000,
+ kGpa = 0b0001,
+ };
+
+ enum class Lrcpc : uint8_t {
+ kNone = 0b0000,
+ kLrcpc = 0b0001,
+ kLrcpc2 = 0b0010,
+ };
+
+ enum class Fcma : uint8_t {
+ kNone = 0b0000,
+ kFcma = 0b0001,
+ };
+
+ enum class Jscvt : uint8_t {
+ kNone = 0b0000,
+ kJscvt = 0b0001,
+ };
+
+ enum class Pauth : uint8_t {
+ kNone = 0b0000,
+ kPauth = 0b0001,
+ kPauthEnhanced = 0b0010,
+ kPauth2 = 0b0011,
+ kFpac = 0b0100,
+ kFpacCombined = 0b0101,
+ };
+
+ enum class Dpb : uint8_t {
+ kNone = 0b0000,
+ kDpb = 0b0001,
+ kDpb2 = 0b0010,
+ };
+
+ DEF_ENUM_FIELD(Ls64, 63, 60, ls64);
+ DEF_ENUM_FIELD(Xs, 59, 56, xs);
+ DEF_ENUM_FIELD(I8mm, 55, 52, i8mm);
+ DEF_ENUM_FIELD(Dgh, 51, 48, dgh);
+ DEF_ENUM_FIELD(Bf16, 47, 44, bf16);
+ DEF_ENUM_FIELD(Specres, 43, 40, specres);
+ DEF_ENUM_FIELD(Sb, 39, 36, sb);
+ DEF_ENUM_FIELD(Frintts, 35, 32, frintts);
+ DEF_ENUM_FIELD(Gpi, 31, 28, gpi);
+ DEF_ENUM_FIELD(Gpa, 27, 24, gpa);
+ DEF_ENUM_FIELD(Lrcpc, 23, 20, lrcpc);
+ DEF_ENUM_FIELD(Fcma, 19, 16, fcma);
+ DEF_ENUM_FIELD(Jscvt, 15, 12, jscvt);
+ DEF_ENUM_FIELD(Pauth, 11, 8, api);
+ DEF_ENUM_FIELD(Pauth, 7, 4, apa);
+ DEF_ENUM_FIELD(Dpb, 3, 0, dpb);
+};
+ARCH_ARM64_SYSREG(ArmIdAa64IsaR1El1, "ID_AA64ISAR1_EL1");
+
+// [arm/sysreg]/ID_AA64PFR0_EL1: AArch64 Processor Feature Register 0
+struct ArmIdAa64Pfr0El1 : public SysRegBase<ArmIdAa64Pfr0El1> {
+ enum class Csv3 : uint8_t {
+ kNone = 0b0000,
+ kCsv3 = 0b0001,
+ };
+
+ enum class Csv2 : uint8_t {
+ kNone = 0b0000,
+ kCsv2 = 0b0001,
+ kCsv2_2 = 0b0010,
+ };
+
+ enum class Dit : uint8_t {
+ kNone = 0b0000,
+ kDit = 0b0001,
+ };
+
+ enum class Amu : uint8_t {
+ kNone = 0b0000,
+ kAmuv1 = 0b0001,
+ kAmuv1p1 = 0b0010,
+ };
+
+ enum class Mpam : uint8_t {
+ kNone = 0b0000,
+ kMpam = 0b0001,
+ };
+
+ enum class Sel2 : uint8_t {
+ kNone = 0b0000,
+ kSel2 = 0b0001,
+ };
+
+ enum class Sve : uint8_t {
+ kNone = 0b0000,
+ kSve = 0b0001,
+ };
+
+ enum class Ras : uint8_t {
+ kNone = 0b0000,
+ kRas = 0b0001,
+ kRasv1p1 = 0b0010,
+ };
+
+ enum class Gic : uint8_t {
+ kNone = 0b0000,
+ kGic4 = 0b0001,
+ kGic4_1 = 0b0010,
+ };
+
+ enum class Fp : uint8_t {
+ kFp = 0b0000,
+ kFp16 = 0b0001,
+ kNone = 0b1111,
+ };
+
+ enum class El : uint8_t {
+ kNone = 0b0000, // EL[23] not implemented.
+ k64 = 0b0001, // ELn supported in AAarch64 state
+ k32 = 0b0010, // ELn supported in AAarch64 or AAarch32 state
+ };
+
+ DEF_ENUM_FIELD(Csv3, 63, 60, csv3);
+ DEF_ENUM_FIELD(Csv2, 59, 56, csv2);
+ DEF_RSVDZ_FIELD(55, 52);
+ DEF_ENUM_FIELD(Dit, 51, 48, dit);
+ DEF_ENUM_FIELD(Amu, 47, 44, amu);
+ DEF_ENUM_FIELD(Mpam, 43, 40, mpam);
+ DEF_ENUM_FIELD(Sel2, 39, 36, sel2);
+ DEF_ENUM_FIELD(Sve, 35, 32, sve);
+ DEF_ENUM_FIELD(Ras, 31, 28, ras);
+ DEF_ENUM_FIELD(Gic, 27, 24, gic);
+ DEF_ENUM_FIELD(Fp, 23, 20, advsimd);
+ DEF_ENUM_FIELD(Fp, 19, 16, fp);
+ DEF_ENUM_FIELD(El, 15, 12, el3);
+ DEF_ENUM_FIELD(El, 11, 8, el2);
+ DEF_ENUM_FIELD(El, 7, 4, el1);
+ DEF_ENUM_FIELD(El, 3, 0, el0);
+};
+ARCH_ARM64_SYSREG(ArmIdAa64Pfr0El1, "ID_AA64PFR0_EL1");
+
+} // namespace arch
+
+#endif // ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_ARM64_FEATURE_H_
diff --git a/zircon/kernel/lib/arch/include/lib/arch/sysreg.h b/zircon/kernel/lib/arch/include/lib/arch/sysreg.h
index 6e0c90f..2a85148 100644
--- a/zircon/kernel/lib/arch/include/lib/arch/sysreg.h
+++ b/zircon/kernel/lib/arch/include/lib/arch/sysreg.h
@@ -210,8 +210,8 @@
// layout type with arch::SysRegDerivedBase<LT> and then defining separate
// register tag types using `struct T : public arch::SysRegDerived<T, LT> {};`.
-template <class RegisterType, typename IntType = uint64_t>
-class SysRegDerivedBase : public hwreg::RegisterBase<RegisterType, IntType, void> {
+template <class RegisterType, typename IntType = uint64_t, typename Printer = void>
+class SysRegDerivedBase : public hwreg::RegisterBase<RegisterType, IntType, Printer> {
public:
using SelfType = RegisterType;
using ValueType = IntType;
@@ -234,8 +234,8 @@
}
};
-template <class RegisterTag, typename IntType = uint64_t>
-using SysRegBase = SysRegDerived<RegisterTag, SysRegDerivedBase<RegisterTag, IntType>>;
+template <class RegisterTag, typename IntType = uint64_t, typename Printer = void>
+using SysRegBase = SysRegDerived<RegisterTag, SysRegDerivedBase<RegisterTag, IntType, Printer>>;
} // namespace arch