1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2023 ARM Ltd. |
4 | */ |
5 | |
6 | #include <linux/jump_label.h> |
7 | #include <linux/memblock.h> |
8 | #include <linux/psci.h> |
9 | #include <linux/swiotlb.h> |
10 | #include <linux/cc_platform.h> |
11 | #include <linux/platform_device.h> |
12 | |
13 | #include <asm/io.h> |
14 | #include <asm/mem_encrypt.h> |
15 | #include <asm/rsi.h> |
16 | |
17 | static struct realm_config config; |
18 | |
19 | unsigned long prot_ns_shared; |
20 | EXPORT_SYMBOL(prot_ns_shared); |
21 | |
22 | DEFINE_STATIC_KEY_FALSE_RO(rsi_present); |
23 | EXPORT_SYMBOL(rsi_present); |
24 | |
25 | bool cc_platform_has(enum cc_attr attr) |
26 | { |
27 | switch (attr) { |
28 | case CC_ATTR_MEM_ENCRYPT: |
29 | return is_realm_world(); |
30 | default: |
31 | return false; |
32 | } |
33 | } |
34 | EXPORT_SYMBOL_GPL(cc_platform_has); |
35 | |
36 | static bool rsi_version_matches(void) |
37 | { |
38 | unsigned long ver_lower, ver_higher; |
39 | unsigned long ret = rsi_request_version(RSI_ABI_VERSION, |
40 | &ver_lower, |
41 | &ver_higher); |
42 | |
43 | if (ret == SMCCC_RET_NOT_SUPPORTED) |
44 | return false; |
45 | |
46 | if (ret != RSI_SUCCESS) { |
47 | pr_err("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n" , |
48 | RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR, |
49 | RSI_ABI_VERSION_GET_MAJOR(ver_lower), |
50 | RSI_ABI_VERSION_GET_MINOR(ver_lower), |
51 | RSI_ABI_VERSION_GET_MAJOR(ver_higher), |
52 | RSI_ABI_VERSION_GET_MINOR(ver_higher)); |
53 | return false; |
54 | } |
55 | |
56 | pr_info("RME: Using RSI version %lu.%lu\n" , |
57 | RSI_ABI_VERSION_GET_MAJOR(ver_lower), |
58 | RSI_ABI_VERSION_GET_MINOR(ver_lower)); |
59 | |
60 | return true; |
61 | } |
62 | |
63 | static void __init arm64_rsi_setup_memory(void) |
64 | { |
65 | u64 i; |
66 | phys_addr_t start, end; |
67 | |
68 | /* |
69 | * Iterate over the available memory ranges and convert the state to |
70 | * protected memory. We should take extra care to ensure that we DO NOT |
71 | * permit any "DESTROYED" pages to be converted to "RAM". |
72 | * |
73 | * panic() is used because if the attempt to switch the memory to |
74 | * protected has failed here, then future accesses to the memory are |
75 | * simply going to be reflected as a SEA (Synchronous External Abort) |
76 | * which we can't handle. Bailing out early prevents the guest limping |
77 | * on and dying later. |
78 | */ |
79 | for_each_mem_range(i, &start, &end) { |
80 | if (rsi_set_memory_range_protected_safe(start, end)) { |
81 | panic(fmt: "Failed to set memory range to protected: %pa-%pa" , |
82 | &start, &end); |
83 | } |
84 | } |
85 | } |
86 | |
87 | bool __arm64_is_protected_mmio(phys_addr_t base, size_t size) |
88 | { |
89 | enum ripas ripas; |
90 | phys_addr_t end, top; |
91 | |
92 | /* Overflow ? */ |
93 | if (WARN_ON(base + size <= base)) |
94 | return false; |
95 | |
96 | end = ALIGN(base + size, RSI_GRANULE_SIZE); |
97 | base = ALIGN_DOWN(base, RSI_GRANULE_SIZE); |
98 | |
99 | while (base < end) { |
100 | if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top))) |
101 | break; |
102 | if (WARN_ON(top <= base)) |
103 | break; |
104 | if (ripas != RSI_RIPAS_DEV) |
105 | break; |
106 | base = top; |
107 | } |
108 | |
109 | return base >= end; |
110 | } |
111 | EXPORT_SYMBOL(__arm64_is_protected_mmio); |
112 | |
113 | static int realm_ioremap_hook(phys_addr_t phys, size_t size, pgprot_t *prot) |
114 | { |
115 | if (__arm64_is_protected_mmio(phys, size)) |
116 | *prot = pgprot_encrypted(*prot); |
117 | else |
118 | *prot = pgprot_decrypted(*prot); |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | void __init arm64_rsi_init(void) |
124 | { |
125 | if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC) |
126 | return; |
127 | if (!rsi_version_matches()) |
128 | return; |
129 | if (WARN_ON(rsi_get_realm_config(&config))) |
130 | return; |
131 | prot_ns_shared = BIT(config.ipa_bits - 1); |
132 | |
133 | if (arm64_ioremap_prot_hook_register(realm_ioremap_hook)) |
134 | return; |
135 | |
136 | if (realm_register_memory_enc_ops()) |
137 | return; |
138 | |
139 | arm64_rsi_setup_memory(); |
140 | |
141 | static_branch_enable(&rsi_present); |
142 | } |
143 | |
144 | static struct platform_device rsi_dev = { |
145 | .name = RSI_PDEV_NAME, |
146 | .id = PLATFORM_DEVID_NONE |
147 | }; |
148 | |
149 | static int __init arm64_create_dummy_rsi_dev(void) |
150 | { |
151 | if (is_realm_world() && |
152 | platform_device_register(&rsi_dev)) |
153 | pr_err("failed to register rsi platform device\n" ); |
154 | return 0; |
155 | } |
156 | |
157 | arch_initcall(arm64_create_dummy_rsi_dev) |
158 | |