core.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Confidential Computing Platform Capability checks
  4. *
  5. * Copyright (C) 2021 Advanced Micro Devices, Inc.
  6. * Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  7. *
  8. * Author: Tom Lendacky <thomas.lendacky@amd.com>
  9. */
  10. #include <linux/export.h>
  11. #include <linux/cc_platform.h>
  12. #include <linux/string.h>
  13. #include <linux/random.h>
  14. #include <asm/archrandom.h>
  15. #include <asm/coco.h>
  16. #include <asm/processor.h>
  17. enum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE;
  18. u64 cc_mask __ro_after_init;
  19. static struct cc_attr_flags {
  20. __u64 host_sev_snp : 1,
  21. __resv : 63;
  22. } cc_flags;
  23. static bool noinstr intel_cc_platform_has(enum cc_attr attr)
  24. {
  25. switch (attr) {
  26. case CC_ATTR_GUEST_UNROLL_STRING_IO:
  27. case CC_ATTR_GUEST_MEM_ENCRYPT:
  28. case CC_ATTR_MEM_ENCRYPT:
  29. return true;
  30. default:
  31. return false;
  32. }
  33. }
  34. /*
  35. * Handle the SEV-SNP vTOM case where sme_me_mask is zero, and
  36. * the other levels of SME/SEV functionality, including C-bit
  37. * based SEV-SNP, are not enabled.
  38. */
  39. static __maybe_unused __always_inline bool amd_cc_platform_vtom(enum cc_attr attr)
  40. {
  41. switch (attr) {
  42. case CC_ATTR_GUEST_MEM_ENCRYPT:
  43. case CC_ATTR_MEM_ENCRYPT:
  44. return true;
  45. default:
  46. return false;
  47. }
  48. }
  49. /*
  50. * SME and SEV are very similar but they are not the same, so there are
  51. * times that the kernel will need to distinguish between SME and SEV. The
  52. * cc_platform_has() function is used for this. When a distinction isn't
  53. * needed, the CC_ATTR_MEM_ENCRYPT attribute can be used.
  54. *
  55. * The trampoline code is a good example for this requirement. Before
  56. * paging is activated, SME will access all memory as decrypted, but SEV
  57. * will access all memory as encrypted. So, when APs are being brought
  58. * up under SME the trampoline area cannot be encrypted, whereas under SEV
  59. * the trampoline area must be encrypted.
  60. */
  61. static bool noinstr amd_cc_platform_has(enum cc_attr attr)
  62. {
  63. #ifdef CONFIG_AMD_MEM_ENCRYPT
  64. if (sev_status & MSR_AMD64_SNP_VTOM)
  65. return amd_cc_platform_vtom(attr);
  66. switch (attr) {
  67. case CC_ATTR_MEM_ENCRYPT:
  68. return sme_me_mask;
  69. case CC_ATTR_HOST_MEM_ENCRYPT:
  70. return sme_me_mask && !(sev_status & MSR_AMD64_SEV_ENABLED);
  71. case CC_ATTR_GUEST_MEM_ENCRYPT:
  72. return sev_status & MSR_AMD64_SEV_ENABLED;
  73. case CC_ATTR_GUEST_STATE_ENCRYPT:
  74. return sev_status & MSR_AMD64_SEV_ES_ENABLED;
  75. /*
  76. * With SEV, the rep string I/O instructions need to be unrolled
  77. * but SEV-ES supports them through the #VC handler.
  78. */
  79. case CC_ATTR_GUEST_UNROLL_STRING_IO:
  80. return (sev_status & MSR_AMD64_SEV_ENABLED) &&
  81. !(sev_status & MSR_AMD64_SEV_ES_ENABLED);
  82. case CC_ATTR_GUEST_SEV_SNP:
  83. return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
  84. case CC_ATTR_HOST_SEV_SNP:
  85. return cc_flags.host_sev_snp;
  86. default:
  87. return false;
  88. }
  89. #else
  90. return false;
  91. #endif
  92. }
  93. bool noinstr cc_platform_has(enum cc_attr attr)
  94. {
  95. switch (cc_vendor) {
  96. case CC_VENDOR_AMD:
  97. return amd_cc_platform_has(attr);
  98. case CC_VENDOR_INTEL:
  99. return intel_cc_platform_has(attr);
  100. default:
  101. return false;
  102. }
  103. }
  104. EXPORT_SYMBOL_GPL(cc_platform_has);
  105. u64 cc_mkenc(u64 val)
  106. {
  107. /*
  108. * Both AMD and Intel use a bit in the page table to indicate
  109. * encryption status of the page.
  110. *
  111. * - for AMD, bit *set* means the page is encrypted
  112. * - for AMD with vTOM and for Intel, *clear* means encrypted
  113. */
  114. switch (cc_vendor) {
  115. case CC_VENDOR_AMD:
  116. if (sev_status & MSR_AMD64_SNP_VTOM)
  117. return val & ~cc_mask;
  118. else
  119. return val | cc_mask;
  120. case CC_VENDOR_INTEL:
  121. return val & ~cc_mask;
  122. default:
  123. return val;
  124. }
  125. }
  126. u64 cc_mkdec(u64 val)
  127. {
  128. /* See comment in cc_mkenc() */
  129. switch (cc_vendor) {
  130. case CC_VENDOR_AMD:
  131. if (sev_status & MSR_AMD64_SNP_VTOM)
  132. return val | cc_mask;
  133. else
  134. return val & ~cc_mask;
  135. case CC_VENDOR_INTEL:
  136. return val | cc_mask;
  137. default:
  138. return val;
  139. }
  140. }
  141. EXPORT_SYMBOL_GPL(cc_mkdec);
  142. static void amd_cc_platform_clear(enum cc_attr attr)
  143. {
  144. switch (attr) {
  145. case CC_ATTR_HOST_SEV_SNP:
  146. cc_flags.host_sev_snp = 0;
  147. break;
  148. default:
  149. break;
  150. }
  151. }
  152. void cc_platform_clear(enum cc_attr attr)
  153. {
  154. switch (cc_vendor) {
  155. case CC_VENDOR_AMD:
  156. amd_cc_platform_clear(attr);
  157. break;
  158. default:
  159. break;
  160. }
  161. }
  162. static void amd_cc_platform_set(enum cc_attr attr)
  163. {
  164. switch (attr) {
  165. case CC_ATTR_HOST_SEV_SNP:
  166. cc_flags.host_sev_snp = 1;
  167. break;
  168. default:
  169. break;
  170. }
  171. }
  172. void cc_platform_set(enum cc_attr attr)
  173. {
  174. switch (cc_vendor) {
  175. case CC_VENDOR_AMD:
  176. amd_cc_platform_set(attr);
  177. break;
  178. default:
  179. break;
  180. }
  181. }
  182. __init void cc_random_init(void)
  183. {
  184. /*
  185. * The seed is 32 bytes (in units of longs), which is 256 bits, which
  186. * is the security level that the RNG is targeting.
  187. */
  188. unsigned long rng_seed[32 / sizeof(long)];
  189. size_t i, longs;
  190. if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
  191. return;
  192. /*
  193. * Since the CoCo threat model includes the host, the only reliable
  194. * source of entropy that can be neither observed nor manipulated is
  195. * RDRAND. Usually, RDRAND failure is considered tolerable, but since
  196. * CoCo guests have no other unobservable source of entropy, it's
  197. * important to at least ensure the RNG gets some initial random seeds.
  198. */
  199. for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) {
  200. longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i);
  201. /*
  202. * A zero return value means that the guest doesn't have RDRAND
  203. * or the CPU is physically broken, and in both cases that
  204. * means most crypto inside of the CoCo instance will be
  205. * broken, defeating the purpose of CoCo in the first place. So
  206. * just panic here because it's absolutely unsafe to continue
  207. * executing.
  208. */
  209. if (longs == 0)
  210. panic("RDRAND is defective.");
  211. }
  212. add_device_randomness(rng_seed, sizeof(rng_seed));
  213. memzero_explicit(rng_seed, sizeof(rng_seed));
  214. }