3131#include <asm/iommu.h>
3232
3333/*
34- * The RMP entry format is not architectural. The format is defined in PPR
35- * Family 19h Model 01h, Rev B1 processor.
34+ * The RMP entry information as returned by the RMPREAD instruction.
3635 */
3736struct rmpentry {
37+ u64 gpa ;
38+ u8 assigned :1 ,
39+ rsvd1 :7 ;
40+ u8 pagesize :1 ,
41+ hpage_region_status :1 ,
42+ rsvd2 :6 ;
43+ u8 immutable :1 ,
44+ rsvd3 :7 ;
45+ u8 rsvd4 ;
46+ u32 asid ;
47+ } __packed ;
48+
49+ /*
50+ * The raw RMP entry format is not architectural. The format is defined in PPR
51+ * Family 19h Model 01h, Rev B1 processor. This format represents the actual
52+ * entry in the RMP table memory. The bitfield definitions are used for machines
53+ * without the RMPREAD instruction (Zen3 and Zen4), otherwise the "hi" and "lo"
54+ * fields are only used for dumping the raw data.
55+ */
56+ struct rmpentry_raw {
3857 union {
3958 struct {
4059 u64 assigned : 1 ,
@@ -62,7 +81,7 @@ struct rmpentry {
6281#define PFN_PMD_MASK GENMASK_ULL(63, PMD_SHIFT - PAGE_SHIFT)
6382
6483static u64 probed_rmp_base , probed_rmp_size ;
65- static struct rmpentry * rmptable __ro_after_init ;
84+ static struct rmpentry_raw * rmptable __ro_after_init ;
6685static u64 rmptable_max_pfn __ro_after_init ;
6786
6887static LIST_HEAD (snp_leaked_pages_list );
@@ -249,8 +268,8 @@ static int __init snp_rmptable_init(void)
249268 rmptable_start += RMPTABLE_CPU_BOOKKEEPING_SZ ;
250269 rmptable_size = probed_rmp_size - RMPTABLE_CPU_BOOKKEEPING_SZ ;
251270
252- rmptable = (struct rmpentry * )rmptable_start ;
253- rmptable_max_pfn = rmptable_size / sizeof (struct rmpentry ) - 1 ;
271+ rmptable = (struct rmpentry_raw * )rmptable_start ;
272+ rmptable_max_pfn = rmptable_size / sizeof (struct rmpentry_raw ) - 1 ;
254273
255274 cpuhp_setup_state (CPUHP_AP_ONLINE_DYN , "x86/rmptable_init:online" , __snp_enable , NULL );
256275
@@ -272,48 +291,77 @@ static int __init snp_rmptable_init(void)
272291 */
273292device_initcall (snp_rmptable_init );
274293
275- static struct rmpentry * get_rmpentry (u64 pfn )
294+ static struct rmpentry_raw * get_raw_rmpentry (u64 pfn )
276295{
277- if (WARN_ON_ONCE (pfn > rmptable_max_pfn ))
296+ if (!rmptable )
297+ return ERR_PTR (- ENODEV );
298+
299+ if (unlikely (pfn > rmptable_max_pfn ))
278300 return ERR_PTR (- EFAULT );
279301
280- return & rmptable [pfn ];
302+ return rmptable + pfn ;
303+ }
304+
305+ static int get_rmpentry (u64 pfn , struct rmpentry * e )
306+ {
307+ struct rmpentry_raw * e_raw ;
308+
309+ e_raw = get_raw_rmpentry (pfn );
310+ if (IS_ERR (e_raw ))
311+ return PTR_ERR (e_raw );
312+
313+ /*
314+ * Map the raw RMP table entry onto the RMPREAD output format.
315+ * The 2MB region status indicator (hpage_region_status field) is not
316+ * calculated, since the overhead could be significant and the field
317+ * is not used.
318+ */
319+ memset (e , 0 , sizeof (* e ));
320+ e -> gpa = e_raw -> gpa << PAGE_SHIFT ;
321+ e -> asid = e_raw -> asid ;
322+ e -> assigned = e_raw -> assigned ;
323+ e -> pagesize = e_raw -> pagesize ;
324+ e -> immutable = e_raw -> immutable ;
325+
326+ return 0 ;
281327}
282328
283- static struct rmpentry * __snp_lookup_rmpentry (u64 pfn , int * level )
329+ static int __snp_lookup_rmpentry (u64 pfn , struct rmpentry * e , int * level )
284330{
285- struct rmpentry * large_entry , * entry ;
331+ struct rmpentry e_large ;
332+ int ret ;
286333
287334 if (!cc_platform_has (CC_ATTR_HOST_SEV_SNP ))
288- return ERR_PTR ( - ENODEV ) ;
335+ return - ENODEV ;
289336
290- entry = get_rmpentry (pfn );
291- if (IS_ERR ( entry ) )
292- return entry ;
337+ ret = get_rmpentry (pfn , e );
338+ if (ret )
339+ return ret ;
293340
294341 /*
295342 * Find the authoritative RMP entry for a PFN. This can be either a 4K
296343 * RMP entry or a special large RMP entry that is authoritative for a
297344 * whole 2M area.
298345 */
299- large_entry = get_rmpentry (pfn & PFN_PMD_MASK );
300- if (IS_ERR ( large_entry ) )
301- return large_entry ;
346+ ret = get_rmpentry (pfn & PFN_PMD_MASK , & e_large );
347+ if (ret )
348+ return ret ;
302349
303- * level = RMP_TO_PG_LEVEL (large_entry -> pagesize );
350+ * level = RMP_TO_PG_LEVEL (e_large . pagesize );
304351
305- return entry ;
352+ return 0 ;
306353}
307354
308355int snp_lookup_rmpentry (u64 pfn , bool * assigned , int * level )
309356{
310- struct rmpentry * e ;
357+ struct rmpentry e ;
358+ int ret ;
311359
312- e = __snp_lookup_rmpentry (pfn , level );
313- if (IS_ERR ( e ) )
314- return PTR_ERR ( e ) ;
360+ ret = __snp_lookup_rmpentry (pfn , & e , level );
361+ if (ret )
362+ return ret ;
315363
316- * assigned = !!e -> assigned ;
364+ * assigned = !!e . assigned ;
317365 return 0 ;
318366}
319367EXPORT_SYMBOL_GPL (snp_lookup_rmpentry );
@@ -326,20 +374,28 @@ EXPORT_SYMBOL_GPL(snp_lookup_rmpentry);
326374 */
327375static void dump_rmpentry (u64 pfn )
328376{
377+ struct rmpentry_raw * e_raw ;
329378 u64 pfn_i , pfn_end ;
330- struct rmpentry * e ;
331- int level ;
379+ struct rmpentry e ;
380+ int level , ret ;
332381
333- e = __snp_lookup_rmpentry (pfn , & level );
334- if (IS_ERR ( e ) ) {
335- pr_err ("Failed to read RMP entry for PFN 0x%llx, error %ld \n" ,
336- pfn , PTR_ERR ( e ) );
382+ ret = __snp_lookup_rmpentry (pfn , & e , & level );
383+ if (ret ) {
384+ pr_err ("Failed to read RMP entry for PFN 0x%llx, error %d \n" ,
385+ pfn , ret );
337386 return ;
338387 }
339388
340- if (e -> assigned ) {
389+ if (e .assigned ) {
390+ e_raw = get_raw_rmpentry (pfn );
391+ if (IS_ERR (e_raw )) {
392+ pr_err ("Failed to read RMP contents for PFN 0x%llx, error %ld\n" ,
393+ pfn , PTR_ERR (e_raw ));
394+ return ;
395+ }
396+
341397 pr_info ("PFN 0x%llx, RMP entry: [0x%016llx - 0x%016llx]\n" ,
342- pfn , e -> lo , e -> hi );
398+ pfn , e_raw -> lo , e_raw -> hi );
343399 return ;
344400 }
345401
@@ -358,16 +414,16 @@ static void dump_rmpentry(u64 pfn)
358414 pfn , pfn_i , pfn_end );
359415
360416 while (pfn_i < pfn_end ) {
361- e = __snp_lookup_rmpentry (pfn_i , & level );
362- if (IS_ERR (e )) {
363- pr_err ("Error %ld reading RMP entry for PFN 0x%llx\n" ,
364- PTR_ERR (e ), pfn_i );
417+ e_raw = get_raw_rmpentry (pfn_i );
418+ if (IS_ERR (e_raw )) {
419+ pr_err ("Error %ld reading RMP contents for PFN 0x%llx\n" ,
420+ PTR_ERR (e_raw ), pfn_i );
365421 pfn_i ++ ;
366422 continue ;
367423 }
368424
369- if (e -> lo || e -> hi )
370- pr_info ("PFN: 0x%llx, [0x%016llx - 0x%016llx]\n" , pfn_i , e -> lo , e -> hi );
425+ if (e_raw -> lo || e_raw -> hi )
426+ pr_info ("PFN: 0x%llx, [0x%016llx - 0x%016llx]\n" , pfn_i , e_raw -> lo , e_raw -> hi );
371427 pfn_i ++ ;
372428 }
373429}
0 commit comments