* Confidential Computing Platform Capability checks
  *
  * Copyright (C) 2021 Advanced Micro Devices, Inc.
+ * Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  *
  * Author: Tom Lendacky <thomas.lendacky@amd.com>
  */
 
 #include <linux/export.h>
 #include <linux/cc_platform.h>
+#include <linux/string.h>
+#include <linux/random.h>
 
+#include <asm/archrandom.h>
 #include <asm/coco.h>
 #include <asm/processor.h>
 
        }
 }
 EXPORT_SYMBOL_GPL(cc_mkdec);
+
+__init void cc_random_init(void)
+{
+       /*
+        * The seed is 32 bytes (in units of longs), which is 256 bits, which
+        * is the security level that the RNG is targeting.
+        */
+       unsigned long rng_seed[32 / sizeof(long)];
+       size_t i, longs;
+
+       if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
+               return;
+
+       /*
+        * Since the CoCo threat model includes the host, the only reliable
+        * source of entropy that can be neither observed nor manipulated is
+        * RDRAND. Usually, RDRAND failure is considered tolerable, but since
+        * CoCo guests have no other unobservable source of entropy, it's
+        * important to at least ensure the RNG gets some initial random seeds.
+        */
+       for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) {
+               longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i);
+
+               /*
+                * A zero return value means that the guest doesn't have RDRAND
+                * or the CPU is physically broken, and in both cases that
+                * means most crypto inside of the CoCo instance will be
+                * broken, defeating the purpose of CoCo in the first place. So
+                * just panic here because it's absolutely unsafe to continue
+                * executing.
+                */
+               if (longs == 0)
+                       panic("RDRAND is defective.");
+       }
+       add_device_randomness(rng_seed, sizeof(rng_seed));
+       memzero_explicit(rng_seed, sizeof(rng_seed));
+}