21
21
#include <linux/hw_random.h>
22
22
#include <linux/ccp.h>
23
23
#include <linux/firmware.h>
24
+ #include <linux/panic_notifier.h>
24
25
#include <linux/gfp.h>
25
26
#include <linux/cpufeature.h>
26
27
#include <linux/fs.h>
@@ -143,6 +144,25 @@ static int sev_wait_cmd_ioc(struct sev_device *sev,
143
144
{
144
145
int ret ;
145
146
147
+ /*
148
+ * If invoked during panic handling, local interrupts are disabled,
149
+ * so the PSP command completion interrupt can't be used. Poll for
150
+ * PSP command completion instead.
151
+ */
152
+ if (irqs_disabled ()) {
153
+ unsigned long timeout_usecs = (timeout * USEC_PER_SEC ) / 10 ;
154
+
155
+ /* Poll for SEV command completion: */
156
+ while (timeout_usecs -- ) {
157
+ * reg = ioread32 (sev -> io_regs + sev -> vdata -> cmdresp_reg );
158
+ if (* reg & PSP_CMDRESP_RESP )
159
+ return 0 ;
160
+
161
+ udelay (10 );
162
+ }
163
+ return - ETIMEDOUT ;
164
+ }
165
+
146
166
ret = wait_event_timeout (sev -> int_queue ,
147
167
sev -> int_rcvd , timeout * HZ );
148
168
if (!ret )
@@ -1338,17 +1358,6 @@ static int __sev_platform_shutdown_locked(int *error)
1338
1358
return ret ;
1339
1359
}
1340
1360
1341
- static int sev_platform_shutdown (int * error )
1342
- {
1343
- int rc ;
1344
-
1345
- mutex_lock (& sev_cmd_mutex );
1346
- rc = __sev_platform_shutdown_locked (NULL );
1347
- mutex_unlock (& sev_cmd_mutex );
1348
-
1349
- return rc ;
1350
- }
1351
-
1352
1361
static int sev_get_platform_state (int * state , int * error )
1353
1362
{
1354
1363
struct sev_user_data_status data ;
@@ -1624,7 +1633,7 @@ static int sev_update_firmware(struct device *dev)
1624
1633
return ret ;
1625
1634
}
1626
1635
1627
- static int __sev_snp_shutdown_locked (int * error )
1636
+ static int __sev_snp_shutdown_locked (int * error , bool panic )
1628
1637
{
1629
1638
struct sev_device * sev = psp_master -> sev_data ;
1630
1639
struct sev_data_snp_shutdown_ex data ;
@@ -1637,7 +1646,16 @@ static int __sev_snp_shutdown_locked(int *error)
1637
1646
data .len = sizeof (data );
1638
1647
data .iommu_snp_shutdown = 1 ;
1639
1648
1640
- wbinvd_on_all_cpus ();
1649
+ /*
1650
+ * If invoked during panic handling, local interrupts are disabled
1651
+ * and all CPUs are stopped, so wbinvd_on_all_cpus() can't be called.
1652
+ * In that case, a wbinvd() is done on remote CPUs via the NMI
1653
+ * callback, so only a local wbinvd() is needed here.
1654
+ */
1655
+ if (!panic )
1656
+ wbinvd_on_all_cpus ();
1657
+ else
1658
+ wbinvd ();
1641
1659
1642
1660
ret = __sev_do_cmd_locked (SEV_CMD_SNP_SHUTDOWN_EX , & data , error );
1643
1661
/* SHUTDOWN may require DF_FLUSH */
@@ -1681,17 +1699,6 @@ static int __sev_snp_shutdown_locked(int *error)
1681
1699
return ret ;
1682
1700
}
1683
1701
1684
- static int sev_snp_shutdown (int * error )
1685
- {
1686
- int rc ;
1687
-
1688
- mutex_lock (& sev_cmd_mutex );
1689
- rc = __sev_snp_shutdown_locked (error );
1690
- mutex_unlock (& sev_cmd_mutex );
1691
-
1692
- return rc ;
1693
- }
1694
-
1695
1702
static int sev_ioctl_do_pek_import (struct sev_issue_cmd * argp , bool writable )
1696
1703
{
1697
1704
struct sev_device * sev = psp_master -> sev_data ;
@@ -2139,19 +2146,28 @@ int sev_dev_init(struct psp_device *psp)
2139
2146
return ret ;
2140
2147
}
2141
2148
2142
- static void sev_firmware_shutdown (struct sev_device * sev )
2149
+ static void __sev_firmware_shutdown (struct sev_device * sev , bool panic )
2143
2150
{
2144
2151
int error ;
2145
2152
2146
- sev_platform_shutdown (NULL );
2153
+ __sev_platform_shutdown_locked (NULL );
2147
2154
2148
2155
if (sev_es_tmr ) {
2149
- /* The TMR area was encrypted, flush it from the cache */
2150
- wbinvd_on_all_cpus ();
2156
+ /*
2157
+ * The TMR area was encrypted, flush it from the cache.
2158
+ *
2159
+ * If invoked during panic handling, local interrupts are
2160
+ * disabled and all CPUs are stopped, so wbinvd_on_all_cpus()
2161
+ * can't be used. In that case, wbinvd() is done on remote CPUs
2162
+ * via the NMI callback, and done for this CPU later during
2163
+ * SNP shutdown, so wbinvd_on_all_cpus() can be skipped.
2164
+ */
2165
+ if (!panic )
2166
+ wbinvd_on_all_cpus ();
2151
2167
2152
2168
__snp_free_firmware_pages (virt_to_page (sev_es_tmr ),
2153
2169
get_order (sev_es_tmr_size ),
2154
- false );
2170
+ true );
2155
2171
sev_es_tmr = NULL ;
2156
2172
}
2157
2173
@@ -2167,7 +2183,14 @@ static void sev_firmware_shutdown(struct sev_device *sev)
2167
2183
snp_range_list = NULL ;
2168
2184
}
2169
2185
2170
- sev_snp_shutdown (& error );
2186
+ __sev_snp_shutdown_locked (& error , panic );
2187
+ }
2188
+
2189
+ static void sev_firmware_shutdown (struct sev_device * sev )
2190
+ {
2191
+ mutex_lock (& sev_cmd_mutex );
2192
+ __sev_firmware_shutdown (sev , false);
2193
+ mutex_unlock (& sev_cmd_mutex );
2171
2194
}
2172
2195
2173
2196
void sev_dev_destroy (struct psp_device * psp )
@@ -2185,6 +2208,29 @@ void sev_dev_destroy(struct psp_device *psp)
2185
2208
psp_clear_sev_irq_handler (psp );
2186
2209
}
2187
2210
2211
+ static int snp_shutdown_on_panic (struct notifier_block * nb ,
2212
+ unsigned long reason , void * arg )
2213
+ {
2214
+ struct sev_device * sev = psp_master -> sev_data ;
2215
+
2216
+ /*
2217
+ * If sev_cmd_mutex is already acquired, then it's likely
2218
+ * another PSP command is in flight and issuing a shutdown
2219
+ * would fail in unexpected ways. Rather than create even
2220
+ * more confusion during a panic, just bail out here.
2221
+ */
2222
+ if (mutex_is_locked (& sev_cmd_mutex ))
2223
+ return NOTIFY_DONE ;
2224
+
2225
+ __sev_firmware_shutdown (sev , true);
2226
+
2227
+ return NOTIFY_DONE ;
2228
+ }
2229
+
2230
+ static struct notifier_block snp_panic_notifier = {
2231
+ .notifier_call = snp_shutdown_on_panic ,
2232
+ };
2233
+
2188
2234
int sev_issue_cmd_external_user (struct file * filep , unsigned int cmd ,
2189
2235
void * data , int * error )
2190
2236
{
@@ -2222,6 +2268,8 @@ void sev_pci_init(void)
2222
2268
dev_info (sev -> dev , "SEV%s API:%d.%d build:%d\n" , sev -> snp_initialized ?
2223
2269
"-SNP" : "" , sev -> api_major , sev -> api_minor , sev -> build );
2224
2270
2271
+ atomic_notifier_chain_register (& panic_notifier_list ,
2272
+ & snp_panic_notifier );
2225
2273
return ;
2226
2274
2227
2275
err :
@@ -2236,4 +2284,7 @@ void sev_pci_exit(void)
2236
2284
return ;
2237
2285
2238
2286
sev_firmware_shutdown (sev );
2287
+
2288
+ atomic_notifier_chain_unregister (& panic_notifier_list ,
2289
+ & snp_panic_notifier );
2239
2290
}
0 commit comments