11b09c13cSSteffen Eiden /* SPDX-License-Identifier: GPL-2.0 */ 21b09c13cSSteffen Eiden /* 31b09c13cSSteffen Eiden * KVM guest address space mapping code 41b09c13cSSteffen Eiden * 51b09c13cSSteffen Eiden * Copyright IBM Corp. 2024, 2025 61b09c13cSSteffen Eiden * Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com> 71b09c13cSSteffen Eiden */ 81b09c13cSSteffen Eiden 91b09c13cSSteffen Eiden #ifndef ARCH_KVM_GMAP_DAT_H 101b09c13cSSteffen Eiden #define ARCH_KVM_GMAP_DAT_H 111b09c13cSSteffen Eiden 12a07276d5SSteffen Eiden #include <linux/kvm_host.h> 131b09c13cSSteffen Eiden #include <linux/radix-tree.h> 141b09c13cSSteffen Eiden #include <linux/refcount.h> 151b09c13cSSteffen Eiden #include <linux/io.h> 161b09c13cSSteffen Eiden #include <linux/kvm_types.h> 171b09c13cSSteffen Eiden #include <linux/pgalloc.h> 181b09c13cSSteffen Eiden #include <asm/tlbflush.h> 191b09c13cSSteffen Eiden #include <asm/dat-bits.h> 201b09c13cSSteffen Eiden 211b09c13cSSteffen Eiden /* 221b09c13cSSteffen Eiden * Base address and length must be sent at the start of each block, therefore 231b09c13cSSteffen Eiden * it's cheaper to send some clean data, as long as it's less than the size of 241b09c13cSSteffen Eiden * two longs. 251b09c13cSSteffen Eiden */ 261b09c13cSSteffen Eiden #define KVM_S390_MAX_BIT_DISTANCE (2 * sizeof(void *)) 271b09c13cSSteffen Eiden /* For consistency */ 281b09c13cSSteffen Eiden #define KVM_S390_CMMA_SIZE_MAX ((u32)KVM_S390_SKEYS_MAX) 291b09c13cSSteffen Eiden 301b09c13cSSteffen Eiden #define _ASCE(x) ((union asce) { .val = (x), }) 311b09c13cSSteffen Eiden #define NULL_ASCE _ASCE(0) 321b09c13cSSteffen Eiden 331b09c13cSSteffen Eiden enum { 341b09c13cSSteffen Eiden _DAT_TOKEN_NONE = 0, 351b09c13cSSteffen Eiden _DAT_TOKEN_PIC, 361b09c13cSSteffen Eiden }; 371b09c13cSSteffen Eiden 381b09c13cSSteffen Eiden #define _CRSTE_TOK(l, t, p) ((union crste) { \ 391b09c13cSSteffen Eiden .tok.i = 1, \ 401b09c13cSSteffen Eiden .tok.tt = (l), \ 411b09c13cSSteffen Eiden .tok.type = (t), \ 421b09c13cSSteffen Eiden .tok.par = (p) \ 431b09c13cSSteffen Eiden }) 441b09c13cSSteffen Eiden #define _CRSTE_PIC(l, p) _CRSTE_TOK(l, _DAT_TOKEN_PIC, p) 451b09c13cSSteffen Eiden 461b09c13cSSteffen Eiden #define _CRSTE_HOLE(l) _CRSTE_PIC(l, PGM_ADDRESSING) 471b09c13cSSteffen Eiden #define _CRSTE_EMPTY(l) _CRSTE_TOK(l, _DAT_TOKEN_NONE, 0) 481b09c13cSSteffen Eiden 491b09c13cSSteffen Eiden #define _PMD_EMPTY _CRSTE_EMPTY(TABLE_TYPE_SEGMENT) 501b09c13cSSteffen Eiden 511b09c13cSSteffen Eiden #define _PTE_TOK(t, p) ((union pte) { .tok.i = 1, .tok.type = (t), .tok.par = (p) }) 521b09c13cSSteffen Eiden #define _PTE_EMPTY _PTE_TOK(_DAT_TOKEN_NONE, 0) 531b09c13cSSteffen Eiden 541b09c13cSSteffen Eiden /* This fake table type is used for page table walks (both for normal page tables and vSIE) */ 551b09c13cSSteffen Eiden #define TABLE_TYPE_PAGE_TABLE -1 561b09c13cSSteffen Eiden 571b09c13cSSteffen Eiden enum dat_walk_flags { 581b09c13cSSteffen Eiden DAT_WALK_USES_SKEYS = 0x40, 591b09c13cSSteffen Eiden DAT_WALK_CONTINUE = 0x20, 601b09c13cSSteffen Eiden DAT_WALK_IGN_HOLES = 0x10, 611b09c13cSSteffen Eiden DAT_WALK_SPLIT = 0x08, 621b09c13cSSteffen Eiden DAT_WALK_ALLOC = 0x04, 631b09c13cSSteffen Eiden DAT_WALK_ANY = 0x02, 641b09c13cSSteffen Eiden DAT_WALK_LEAF = 0x01, 651b09c13cSSteffen Eiden DAT_WALK_DEFAULT = 0 661b09c13cSSteffen Eiden }; 671b09c13cSSteffen Eiden 681b09c13cSSteffen Eiden #define DAT_WALK_SPLIT_ALLOC (DAT_WALK_SPLIT | DAT_WALK_ALLOC) 691b09c13cSSteffen Eiden #define DAT_WALK_ALLOC_CONTINUE (DAT_WALK_CONTINUE | DAT_WALK_ALLOC) 701b09c13cSSteffen Eiden #define DAT_WALK_LEAF_ALLOC (DAT_WALK_LEAF | DAT_WALK_ALLOC) 711b09c13cSSteffen Eiden 721b09c13cSSteffen Eiden union pte { 731b09c13cSSteffen Eiden unsigned long val; 741b09c13cSSteffen Eiden union page_table_entry h; 751b09c13cSSteffen Eiden struct { 761b09c13cSSteffen Eiden unsigned long :56; /* Hardware bits */ 771b09c13cSSteffen Eiden unsigned long u : 1; /* Page unused */ 781b09c13cSSteffen Eiden unsigned long s : 1; /* Special */ 791b09c13cSSteffen Eiden unsigned long w : 1; /* Writable */ 801b09c13cSSteffen Eiden unsigned long r : 1; /* Readable */ 811b09c13cSSteffen Eiden unsigned long d : 1; /* Dirty */ 821b09c13cSSteffen Eiden unsigned long y : 1; /* Young */ 831b09c13cSSteffen Eiden unsigned long sd: 1; /* Soft dirty */ 841b09c13cSSteffen Eiden unsigned long pr: 1; /* Present */ 851b09c13cSSteffen Eiden } s; 861b09c13cSSteffen Eiden struct { 871b09c13cSSteffen Eiden unsigned char hwbytes[7]; 881b09c13cSSteffen Eiden unsigned char swbyte; 891b09c13cSSteffen Eiden }; 901b09c13cSSteffen Eiden union { 911b09c13cSSteffen Eiden struct { 921b09c13cSSteffen Eiden unsigned long type :16; /* Token type */ 931b09c13cSSteffen Eiden unsigned long par :16; /* Token parameter */ 941b09c13cSSteffen Eiden unsigned long :20; 951b09c13cSSteffen Eiden unsigned long : 1; /* Must be 0 */ 961b09c13cSSteffen Eiden unsigned long i : 1; /* Must be 1 */ 971b09c13cSSteffen Eiden unsigned long : 2; 981b09c13cSSteffen Eiden unsigned long : 7; 991b09c13cSSteffen Eiden unsigned long pr : 1; /* Must be 0 */ 1001b09c13cSSteffen Eiden }; 1011b09c13cSSteffen Eiden struct { 1021b09c13cSSteffen Eiden unsigned long token:32; /* Token and parameter */ 1031b09c13cSSteffen Eiden unsigned long :32; 1041b09c13cSSteffen Eiden }; 1051b09c13cSSteffen Eiden } tok; 1061b09c13cSSteffen Eiden }; 1071b09c13cSSteffen Eiden 1081b09c13cSSteffen Eiden #define _SEGMENT_FR_MASK (_SEGMENT_MASK >> PAGE_SHIFT) 1091b09c13cSSteffen Eiden #define _REGION3_FR_MASK (_REGION3_MASK >> PAGE_SHIFT) 1101b09c13cSSteffen Eiden #define _PAGES_PER_SEGMENT _PAGE_ENTRIES 1111b09c13cSSteffen Eiden #define _PAGES_PER_REGION3 (_PAGES_PER_SEGMENT * _CRST_ENTRIES) 1121b09c13cSSteffen Eiden 1131b09c13cSSteffen Eiden /* Soft dirty, needed as macro for atomic operations on ptes */ 1141b09c13cSSteffen Eiden #define _PAGE_SD 0x002 1151b09c13cSSteffen Eiden 1161b09c13cSSteffen Eiden /* Needed as macro to perform atomic operations */ 1171b09c13cSSteffen Eiden #define PGSTE_PCL_BIT 0x0080000000000000UL /* PCL lock, HW bit */ 1181b09c13cSSteffen Eiden #define PGSTE_CMMA_D_BIT 0x0000000000008000UL /* CMMA dirty soft-bit */ 1191b09c13cSSteffen Eiden 1201b09c13cSSteffen Eiden enum pgste_gps_usage { 1211b09c13cSSteffen Eiden PGSTE_GPS_USAGE_STABLE = 0, 1221b09c13cSSteffen Eiden PGSTE_GPS_USAGE_UNUSED, 1231b09c13cSSteffen Eiden PGSTE_GPS_USAGE_POT_VOLATILE, 1241b09c13cSSteffen Eiden PGSTE_GPS_USAGE_VOLATILE, 1251b09c13cSSteffen Eiden }; 1261b09c13cSSteffen Eiden 1271b09c13cSSteffen Eiden union pgste { 1281b09c13cSSteffen Eiden unsigned long val; 1291b09c13cSSteffen Eiden struct { 1301b09c13cSSteffen Eiden unsigned long acc : 4; 1311b09c13cSSteffen Eiden unsigned long fp : 1; 1321b09c13cSSteffen Eiden unsigned long : 3; 1331b09c13cSSteffen Eiden unsigned long pcl : 1; 1341b09c13cSSteffen Eiden unsigned long hr : 1; 1351b09c13cSSteffen Eiden unsigned long hc : 1; 1361b09c13cSSteffen Eiden unsigned long : 2; 1371b09c13cSSteffen Eiden unsigned long gr : 1; 1381b09c13cSSteffen Eiden unsigned long gc : 1; 1391b09c13cSSteffen Eiden unsigned long : 1; 1401b09c13cSSteffen Eiden unsigned long :16; /* val16 */ 1411b09c13cSSteffen Eiden unsigned long zero : 1; 1421b09c13cSSteffen Eiden unsigned long nodat : 1; 1431b09c13cSSteffen Eiden unsigned long : 4; 1441b09c13cSSteffen Eiden unsigned long usage : 2; 1451b09c13cSSteffen Eiden unsigned long : 8; 1461b09c13cSSteffen Eiden unsigned long cmma_d : 1; /* Dirty flag for CMMA bits */ 1471b09c13cSSteffen Eiden unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */ 1481b09c13cSSteffen Eiden unsigned long vsie_notif : 1; /* Referenced in a shadow table */ 1491b09c13cSSteffen Eiden unsigned long vsie_gmem : 1; /* Contains nested guest memory */ 1501b09c13cSSteffen Eiden unsigned long : 4; 1511b09c13cSSteffen Eiden unsigned long : 8; 1521b09c13cSSteffen Eiden }; 1531b09c13cSSteffen Eiden struct { 1541b09c13cSSteffen Eiden unsigned short hwbytes0; 1551b09c13cSSteffen Eiden unsigned short val16; /* Used to store chunked values, see dat_{s,g}et_ptval() */ 1561b09c13cSSteffen Eiden unsigned short hwbytes4; 1571b09c13cSSteffen Eiden unsigned char flags; /* Maps to the software bits */ 1581b09c13cSSteffen Eiden unsigned char hwbyte7; 1591b09c13cSSteffen Eiden } __packed; 1601b09c13cSSteffen Eiden }; 1611b09c13cSSteffen Eiden 1621b09c13cSSteffen Eiden union pmd { 1631b09c13cSSteffen Eiden unsigned long val; 1641b09c13cSSteffen Eiden union segment_table_entry h; 1651b09c13cSSteffen Eiden struct { 1661b09c13cSSteffen Eiden struct { 1671b09c13cSSteffen Eiden unsigned long :44; /* HW */ 1681b09c13cSSteffen Eiden unsigned long : 3; /* Unused */ 1691b09c13cSSteffen Eiden unsigned long : 1; /* HW */ 1701b09c13cSSteffen Eiden unsigned long s : 1; /* Special */ 1711b09c13cSSteffen Eiden unsigned long w : 1; /* Writable soft-bit */ 1721b09c13cSSteffen Eiden unsigned long r : 1; /* Readable soft-bit */ 1731b09c13cSSteffen Eiden unsigned long d : 1; /* Dirty */ 1741b09c13cSSteffen Eiden unsigned long y : 1; /* Young */ 1751b09c13cSSteffen Eiden unsigned long : 3; /* HW */ 1761b09c13cSSteffen Eiden unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */ 1771b09c13cSSteffen Eiden unsigned long vsie_notif : 1; /* Referenced in a shadow table */ 1781b09c13cSSteffen Eiden unsigned long : 4; /* HW */ 1791b09c13cSSteffen Eiden unsigned long sd : 1; /* Soft-Dirty */ 1801b09c13cSSteffen Eiden unsigned long pr : 1; /* Present */ 1811b09c13cSSteffen Eiden } fc1; 1821b09c13cSSteffen Eiden } s; 1831b09c13cSSteffen Eiden }; 1841b09c13cSSteffen Eiden 1851b09c13cSSteffen Eiden union pud { 1861b09c13cSSteffen Eiden unsigned long val; 1871b09c13cSSteffen Eiden union region3_table_entry h; 1881b09c13cSSteffen Eiden struct { 1891b09c13cSSteffen Eiden struct { 1901b09c13cSSteffen Eiden unsigned long :33; /* HW */ 1911b09c13cSSteffen Eiden unsigned long :14; /* Unused */ 1921b09c13cSSteffen Eiden unsigned long : 1; /* HW */ 1931b09c13cSSteffen Eiden unsigned long s : 1; /* Special */ 1941b09c13cSSteffen Eiden unsigned long w : 1; /* Writable soft-bit */ 1951b09c13cSSteffen Eiden unsigned long r : 1; /* Readable soft-bit */ 1961b09c13cSSteffen Eiden unsigned long d : 1; /* Dirty */ 1971b09c13cSSteffen Eiden unsigned long y : 1; /* Young */ 1981b09c13cSSteffen Eiden unsigned long : 3; /* HW */ 1991b09c13cSSteffen Eiden unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */ 2001b09c13cSSteffen Eiden unsigned long vsie_notif : 1; /* Referenced in a shadow table */ 2011b09c13cSSteffen Eiden unsigned long : 4; /* HW */ 2021b09c13cSSteffen Eiden unsigned long sd : 1; /* Soft-Dirty */ 2031b09c13cSSteffen Eiden unsigned long pr : 1; /* Present */ 2041b09c13cSSteffen Eiden } fc1; 2051b09c13cSSteffen Eiden } s; 2061b09c13cSSteffen Eiden }; 2071b09c13cSSteffen Eiden 2081b09c13cSSteffen Eiden union p4d { 2091b09c13cSSteffen Eiden unsigned long val; 2101b09c13cSSteffen Eiden union region2_table_entry h; 2111b09c13cSSteffen Eiden }; 2121b09c13cSSteffen Eiden 2131b09c13cSSteffen Eiden union pgd { 2141b09c13cSSteffen Eiden unsigned long val; 2151b09c13cSSteffen Eiden union region1_table_entry h; 2161b09c13cSSteffen Eiden }; 2171b09c13cSSteffen Eiden 2181b09c13cSSteffen Eiden union crste { 2191b09c13cSSteffen Eiden unsigned long val; 2201b09c13cSSteffen Eiden union { 2211b09c13cSSteffen Eiden struct { 2221b09c13cSSteffen Eiden unsigned long :52; 2231b09c13cSSteffen Eiden unsigned long : 1; 2241b09c13cSSteffen Eiden unsigned long fc: 1; 2251b09c13cSSteffen Eiden unsigned long p : 1; 2261b09c13cSSteffen Eiden unsigned long : 1; 2271b09c13cSSteffen Eiden unsigned long : 2; 2281b09c13cSSteffen Eiden unsigned long i : 1; 2291b09c13cSSteffen Eiden unsigned long : 1; 2301b09c13cSSteffen Eiden unsigned long tt: 2; 2311b09c13cSSteffen Eiden unsigned long : 2; 2321b09c13cSSteffen Eiden }; 2331b09c13cSSteffen Eiden struct { 2341b09c13cSSteffen Eiden unsigned long to:52; 2351b09c13cSSteffen Eiden unsigned long : 1; 2361b09c13cSSteffen Eiden unsigned long fc: 1; 2371b09c13cSSteffen Eiden unsigned long p : 1; 2381b09c13cSSteffen Eiden unsigned long : 1; 2391b09c13cSSteffen Eiden unsigned long tf: 2; 2401b09c13cSSteffen Eiden unsigned long i : 1; 2411b09c13cSSteffen Eiden unsigned long : 1; 2421b09c13cSSteffen Eiden unsigned long tt: 2; 2431b09c13cSSteffen Eiden unsigned long tl: 2; 2441b09c13cSSteffen Eiden } fc0; 2451b09c13cSSteffen Eiden struct { 2461b09c13cSSteffen Eiden unsigned long :47; 2471b09c13cSSteffen Eiden unsigned long av : 1; /* ACCF-Validity Control */ 2481b09c13cSSteffen Eiden unsigned long acc: 4; /* Access-Control Bits */ 2491b09c13cSSteffen Eiden unsigned long f : 1; /* Fetch-Protection Bit */ 2501b09c13cSSteffen Eiden unsigned long fc : 1; /* Format-Control */ 2511b09c13cSSteffen Eiden unsigned long p : 1; /* DAT-Protection Bit */ 2521b09c13cSSteffen Eiden unsigned long iep: 1; /* Instruction-Execution-Protection */ 2531b09c13cSSteffen Eiden unsigned long : 2; 2541b09c13cSSteffen Eiden unsigned long i : 1; /* Segment-Invalid Bit */ 2551b09c13cSSteffen Eiden unsigned long cs : 1; /* Common-Segment Bit */ 2561b09c13cSSteffen Eiden unsigned long tt : 2; /* Table-Type Bits */ 2571b09c13cSSteffen Eiden unsigned long : 2; 2581b09c13cSSteffen Eiden } fc1; 2591b09c13cSSteffen Eiden } h; 2601b09c13cSSteffen Eiden struct { 2611b09c13cSSteffen Eiden struct { 2621b09c13cSSteffen Eiden unsigned long :47; 2631b09c13cSSteffen Eiden unsigned long : 1; /* HW (should be 0) */ 2641b09c13cSSteffen Eiden unsigned long s : 1; /* Special */ 2651b09c13cSSteffen Eiden unsigned long w : 1; /* Writable */ 2661b09c13cSSteffen Eiden unsigned long r : 1; /* Readable */ 2671b09c13cSSteffen Eiden unsigned long d : 1; /* Dirty */ 2681b09c13cSSteffen Eiden unsigned long y : 1; /* Young */ 2691b09c13cSSteffen Eiden unsigned long : 3; /* HW */ 2701b09c13cSSteffen Eiden unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */ 2711b09c13cSSteffen Eiden unsigned long vsie_notif : 1; /* Referenced in a shadow table */ 2721b09c13cSSteffen Eiden unsigned long : 4; /* HW */ 2731b09c13cSSteffen Eiden unsigned long sd : 1; /* Soft-Dirty */ 2741b09c13cSSteffen Eiden unsigned long pr : 1; /* Present */ 2751b09c13cSSteffen Eiden } fc1; 2761b09c13cSSteffen Eiden } s; 2771b09c13cSSteffen Eiden union { 2781b09c13cSSteffen Eiden struct { 2791b09c13cSSteffen Eiden unsigned long type :16; /* Token type */ 2801b09c13cSSteffen Eiden unsigned long par :16; /* Token parameter */ 2811b09c13cSSteffen Eiden unsigned long :26; 2821b09c13cSSteffen Eiden unsigned long i : 1; /* Must be 1 */ 2831b09c13cSSteffen Eiden unsigned long : 1; 2841b09c13cSSteffen Eiden unsigned long tt : 2; 2851b09c13cSSteffen Eiden unsigned long : 1; 2861b09c13cSSteffen Eiden unsigned long pr : 1; /* Must be 0 */ 2871b09c13cSSteffen Eiden }; 2881b09c13cSSteffen Eiden struct { 2891b09c13cSSteffen Eiden unsigned long token:32; /* Token and parameter */ 2901b09c13cSSteffen Eiden unsigned long :32; 2911b09c13cSSteffen Eiden }; 2921b09c13cSSteffen Eiden } tok; 2931b09c13cSSteffen Eiden union pmd pmd; 2941b09c13cSSteffen Eiden union pud pud; 2951b09c13cSSteffen Eiden union p4d p4d; 2961b09c13cSSteffen Eiden union pgd pgd; 2971b09c13cSSteffen Eiden }; 2981b09c13cSSteffen Eiden 2991b09c13cSSteffen Eiden union skey { 3001b09c13cSSteffen Eiden unsigned char skey; 3011b09c13cSSteffen Eiden struct { 3021b09c13cSSteffen Eiden unsigned char acc :4; 3031b09c13cSSteffen Eiden unsigned char fp :1; 3041b09c13cSSteffen Eiden unsigned char r :1; 3051b09c13cSSteffen Eiden unsigned char c :1; 3061b09c13cSSteffen Eiden unsigned char zero:1; 3071b09c13cSSteffen Eiden }; 3081b09c13cSSteffen Eiden }; 3091b09c13cSSteffen Eiden 3101b09c13cSSteffen Eiden static_assert(sizeof(union pgste) == sizeof(unsigned long)); 3111b09c13cSSteffen Eiden static_assert(sizeof(union pte) == sizeof(unsigned long)); 3121b09c13cSSteffen Eiden static_assert(sizeof(union pmd) == sizeof(unsigned long)); 3131b09c13cSSteffen Eiden static_assert(sizeof(union pud) == sizeof(unsigned long)); 3141b09c13cSSteffen Eiden static_assert(sizeof(union p4d) == sizeof(unsigned long)); 3151b09c13cSSteffen Eiden static_assert(sizeof(union pgd) == sizeof(unsigned long)); 3161b09c13cSSteffen Eiden static_assert(sizeof(union crste) == sizeof(unsigned long)); 3171b09c13cSSteffen Eiden static_assert(sizeof(union skey) == sizeof(char)); 3181b09c13cSSteffen Eiden 3191b09c13cSSteffen Eiden struct segment_table { 3201b09c13cSSteffen Eiden union pmd pmds[_CRST_ENTRIES]; 3211b09c13cSSteffen Eiden }; 3221b09c13cSSteffen Eiden 3231b09c13cSSteffen Eiden struct region3_table { 3241b09c13cSSteffen Eiden union pud puds[_CRST_ENTRIES]; 3251b09c13cSSteffen Eiden }; 3261b09c13cSSteffen Eiden 3271b09c13cSSteffen Eiden struct region2_table { 3281b09c13cSSteffen Eiden union p4d p4ds[_CRST_ENTRIES]; 3291b09c13cSSteffen Eiden }; 3301b09c13cSSteffen Eiden 3311b09c13cSSteffen Eiden struct region1_table { 3321b09c13cSSteffen Eiden union pgd pgds[_CRST_ENTRIES]; 3331b09c13cSSteffen Eiden }; 3341b09c13cSSteffen Eiden 3351b09c13cSSteffen Eiden struct crst_table { 3361b09c13cSSteffen Eiden union { 3371b09c13cSSteffen Eiden union crste crstes[_CRST_ENTRIES]; 3381b09c13cSSteffen Eiden struct segment_table segment; 3391b09c13cSSteffen Eiden struct region3_table region3; 3401b09c13cSSteffen Eiden struct region2_table region2; 3411b09c13cSSteffen Eiden struct region1_table region1; 3421b09c13cSSteffen Eiden }; 3431b09c13cSSteffen Eiden }; 3441b09c13cSSteffen Eiden 3451b09c13cSSteffen Eiden struct page_table { 3461b09c13cSSteffen Eiden union pte ptes[_PAGE_ENTRIES]; 3471b09c13cSSteffen Eiden union pgste pgstes[_PAGE_ENTRIES]; 3481b09c13cSSteffen Eiden }; 3491b09c13cSSteffen Eiden 3501b09c13cSSteffen Eiden static_assert(sizeof(struct crst_table) == _CRST_TABLE_SIZE); 3511b09c13cSSteffen Eiden static_assert(sizeof(struct page_table) == PAGE_SIZE); 3521b09c13cSSteffen Eiden 3531b09c13cSSteffen Eiden struct dat_walk; 3541b09c13cSSteffen Eiden 3551b09c13cSSteffen Eiden typedef long (*dat_walk_op)(union crste *crste, gfn_t gfn, gfn_t next, struct dat_walk *w); 3561b09c13cSSteffen Eiden 3571b09c13cSSteffen Eiden struct dat_walk_ops { 3581b09c13cSSteffen Eiden union { 3591b09c13cSSteffen Eiden dat_walk_op crste_ops[4]; 3601b09c13cSSteffen Eiden struct { 3611b09c13cSSteffen Eiden dat_walk_op pmd_entry; 3621b09c13cSSteffen Eiden dat_walk_op pud_entry; 3631b09c13cSSteffen Eiden dat_walk_op p4d_entry; 3641b09c13cSSteffen Eiden dat_walk_op pgd_entry; 3651b09c13cSSteffen Eiden }; 3661b09c13cSSteffen Eiden }; 3671b09c13cSSteffen Eiden long (*pte_entry)(union pte *pte, gfn_t gfn, gfn_t next, struct dat_walk *w); 3681b09c13cSSteffen Eiden }; 3691b09c13cSSteffen Eiden 3701b09c13cSSteffen Eiden struct dat_walk { 3711b09c13cSSteffen Eiden const struct dat_walk_ops *ops; 3721b09c13cSSteffen Eiden union crste *last; 3731b09c13cSSteffen Eiden union pte *last_pte; 3741b09c13cSSteffen Eiden union asce asce; 3751b09c13cSSteffen Eiden gfn_t start; 3761b09c13cSSteffen Eiden gfn_t end; 3771b09c13cSSteffen Eiden int flags; 3781b09c13cSSteffen Eiden void *priv; 3791b09c13cSSteffen Eiden }; 3801b09c13cSSteffen Eiden 3811b09c13cSSteffen Eiden struct ptval_param { 3821b09c13cSSteffen Eiden unsigned char offset : 6; 3831b09c13cSSteffen Eiden unsigned char len : 2; 3841b09c13cSSteffen Eiden }; 3851b09c13cSSteffen Eiden 3861b09c13cSSteffen Eiden /** 3871b09c13cSSteffen Eiden * _pte() - Useful constructor for union pte 3881b09c13cSSteffen Eiden * @pfn: the pfn this pte should point to. 3891b09c13cSSteffen Eiden * @writable: whether the pte should be writable. 3901b09c13cSSteffen Eiden * @dirty: whether the pte should be dirty. 3911b09c13cSSteffen Eiden * @special: whether the pte should be marked as special 3921b09c13cSSteffen Eiden * 3931b09c13cSSteffen Eiden * The pte is also marked as young and present. If the pte is marked as dirty, 3941b09c13cSSteffen Eiden * it gets marked as soft-dirty too. If the pte is not dirty, the hardware 3951b09c13cSSteffen Eiden * protect bit is set (independently of the write softbit); this way proper 3961b09c13cSSteffen Eiden * dirty tracking can be performed. 3971b09c13cSSteffen Eiden * 3981b09c13cSSteffen Eiden * Return: a union pte value. 3991b09c13cSSteffen Eiden */ 4001b09c13cSSteffen Eiden static inline union pte _pte(kvm_pfn_t pfn, bool writable, bool dirty, bool special) 4011b09c13cSSteffen Eiden { 4021b09c13cSSteffen Eiden union pte res = { .val = PFN_PHYS(pfn) }; 4031b09c13cSSteffen Eiden 4041b09c13cSSteffen Eiden res.h.p = !dirty; 4051b09c13cSSteffen Eiden res.s.y = 1; 4061b09c13cSSteffen Eiden res.s.pr = 1; 4071b09c13cSSteffen Eiden res.s.w = writable; 4081b09c13cSSteffen Eiden res.s.d = dirty; 4091b09c13cSSteffen Eiden res.s.sd = dirty; 4101b09c13cSSteffen Eiden res.s.s = special; 4111b09c13cSSteffen Eiden return res; 4121b09c13cSSteffen Eiden } 4131b09c13cSSteffen Eiden 4141b09c13cSSteffen Eiden static inline union crste _crste_fc0(kvm_pfn_t pfn, int tt) 4151b09c13cSSteffen Eiden { 4161b09c13cSSteffen Eiden union crste res = { .val = PFN_PHYS(pfn) }; 4171b09c13cSSteffen Eiden 4181b09c13cSSteffen Eiden res.h.tt = tt; 4191b09c13cSSteffen Eiden res.h.fc0.tl = _REGION_ENTRY_LENGTH; 4201b09c13cSSteffen Eiden res.h.fc0.tf = 0; 4211b09c13cSSteffen Eiden return res; 4221b09c13cSSteffen Eiden } 4231b09c13cSSteffen Eiden 4241b09c13cSSteffen Eiden /** 4251b09c13cSSteffen Eiden * _crste() - Useful constructor for union crste with FC=1 4261b09c13cSSteffen Eiden * @pfn: the pfn this pte should point to. 4271b09c13cSSteffen Eiden * @tt: the table type 4281b09c13cSSteffen Eiden * @writable: whether the pte should be writable. 4291b09c13cSSteffen Eiden * @dirty: whether the pte should be dirty. 4301b09c13cSSteffen Eiden * 4311b09c13cSSteffen Eiden * The crste is also marked as young and present. If the crste is marked as 4321b09c13cSSteffen Eiden * dirty, it gets marked as soft-dirty too. If the crste is not dirty, the 4331b09c13cSSteffen Eiden * hardware protect bit is set (independently of the write softbit); this way 4341b09c13cSSteffen Eiden * proper dirty tracking can be performed. 4351b09c13cSSteffen Eiden * 4361b09c13cSSteffen Eiden * Return: a union crste value. 4371b09c13cSSteffen Eiden */ 4381b09c13cSSteffen Eiden static inline union crste _crste_fc1(kvm_pfn_t pfn, int tt, bool writable, bool dirty) 4391b09c13cSSteffen Eiden { 4401b09c13cSSteffen Eiden union crste res = { .val = PFN_PHYS(pfn) & _SEGMENT_MASK }; 4411b09c13cSSteffen Eiden 4421b09c13cSSteffen Eiden res.h.tt = tt; 4431b09c13cSSteffen Eiden res.h.p = !dirty; 4441b09c13cSSteffen Eiden res.h.fc = 1; 4451b09c13cSSteffen Eiden res.s.fc1.y = 1; 4461b09c13cSSteffen Eiden res.s.fc1.pr = 1; 4471b09c13cSSteffen Eiden res.s.fc1.w = writable; 4481b09c13cSSteffen Eiden res.s.fc1.d = dirty; 4491b09c13cSSteffen Eiden res.s.fc1.sd = dirty; 4501b09c13cSSteffen Eiden return res; 4511b09c13cSSteffen Eiden } 4521b09c13cSSteffen Eiden 4531b09c13cSSteffen Eiden union essa_state { 4541b09c13cSSteffen Eiden unsigned char val; 4551b09c13cSSteffen Eiden struct { 4561b09c13cSSteffen Eiden unsigned char : 2; 4571b09c13cSSteffen Eiden unsigned char nodat : 1; 4581b09c13cSSteffen Eiden unsigned char exception : 1; 4591b09c13cSSteffen Eiden unsigned char usage : 2; 4601b09c13cSSteffen Eiden unsigned char content : 2; 4611b09c13cSSteffen Eiden }; 4621b09c13cSSteffen Eiden }; 4631b09c13cSSteffen Eiden 4641b09c13cSSteffen Eiden /** 4651b09c13cSSteffen Eiden * struct vsie_rmap - reverse mapping for shadow page table entries 4661b09c13cSSteffen Eiden * @next: pointer to next rmap in the list 4671b09c13cSSteffen Eiden * @r_gfn: virtual rmap address in the shadow guest address space 4681b09c13cSSteffen Eiden */ 4691b09c13cSSteffen Eiden struct vsie_rmap { 4701b09c13cSSteffen Eiden struct vsie_rmap *next; 4711b09c13cSSteffen Eiden union { 4721b09c13cSSteffen Eiden unsigned long val; 4731b09c13cSSteffen Eiden struct { 4741b09c13cSSteffen Eiden long level: 8; 4751b09c13cSSteffen Eiden unsigned long : 4; 4761b09c13cSSteffen Eiden unsigned long r_gfn:52; 4771b09c13cSSteffen Eiden }; 4781b09c13cSSteffen Eiden }; 4791b09c13cSSteffen Eiden }; 4801b09c13cSSteffen Eiden 4811b09c13cSSteffen Eiden static_assert(sizeof(struct vsie_rmap) == 2 * sizeof(long)); 4821b09c13cSSteffen Eiden 4831b09c13cSSteffen Eiden #define KVM_S390_MMU_CACHE_N_CRSTS 6 4841b09c13cSSteffen Eiden #define KVM_S390_MMU_CACHE_N_PTS 2 4851b09c13cSSteffen Eiden #define KVM_S390_MMU_CACHE_N_RMAPS 16 4861b09c13cSSteffen Eiden struct kvm_s390_mmu_cache { 4871b09c13cSSteffen Eiden void *crsts[KVM_S390_MMU_CACHE_N_CRSTS]; 4881b09c13cSSteffen Eiden void *pts[KVM_S390_MMU_CACHE_N_PTS]; 4891b09c13cSSteffen Eiden void *rmaps[KVM_S390_MMU_CACHE_N_RMAPS]; 4901b09c13cSSteffen Eiden short int n_crsts; 4911b09c13cSSteffen Eiden short int n_pts; 4921b09c13cSSteffen Eiden short int n_rmaps; 4931b09c13cSSteffen Eiden }; 4941b09c13cSSteffen Eiden 4951b09c13cSSteffen Eiden struct guest_fault { 4961b09c13cSSteffen Eiden gfn_t gfn; /* Guest frame */ 4971b09c13cSSteffen Eiden kvm_pfn_t pfn; /* Host PFN */ 4981b09c13cSSteffen Eiden struct page *page; /* Host page */ 4991b09c13cSSteffen Eiden union pte *ptep; /* Used to resolve the fault, or NULL */ 5001b09c13cSSteffen Eiden union crste *crstep; /* Used to resolve the fault, or NULL */ 5011b09c13cSSteffen Eiden bool writable; /* Mapping is writable */ 5021b09c13cSSteffen Eiden bool write_attempt; /* Write access attempted */ 5031b09c13cSSteffen Eiden bool attempt_pfault; /* Attempt a pfault first */ 5041b09c13cSSteffen Eiden bool valid; /* This entry contains valid data */ 5051b09c13cSSteffen Eiden bool crste_region3; /* Whether crstep refers to a region3 entry */ 5061b09c13cSSteffen Eiden void (*callback)(struct guest_fault *f); 5071b09c13cSSteffen Eiden void *priv; 5081b09c13cSSteffen Eiden }; 5091b09c13cSSteffen Eiden 5101b09c13cSSteffen Eiden /* 5111b09c13cSSteffen Eiden * 0 1 2 3 4 5 6 7 5121b09c13cSSteffen Eiden * +-------+-------+-------+-------+-------+-------+-------+-------+ 5131b09c13cSSteffen Eiden * 0 | | PGT_ADDR | 5141b09c13cSSteffen Eiden * 8 | VMADDR | | 5151b09c13cSSteffen Eiden * 16 | | 5161b09c13cSSteffen Eiden * 24 | | 5171b09c13cSSteffen Eiden */ 5181b09c13cSSteffen Eiden #define MKPTVAL(o, l) ((struct ptval_param) { .offset = (o), .len = ((l) + 1) / 2 - 1}) 5191b09c13cSSteffen Eiden #define PTVAL_PGT_ADDR MKPTVAL(4, 8) 5201b09c13cSSteffen Eiden #define PTVAL_VMADDR MKPTVAL(8, 6) 5211b09c13cSSteffen Eiden 5221b09c13cSSteffen Eiden union pgste __must_check __dat_ptep_xchg(union pte *ptep, union pgste pgste, union pte new, 5231b09c13cSSteffen Eiden gfn_t gfn, union asce asce, bool uses_skeys); 5241b09c13cSSteffen Eiden bool dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new, gfn_t gfn, 5251b09c13cSSteffen Eiden union asce asce); 5261b09c13cSSteffen Eiden void dat_crstep_xchg(union crste *crstep, union crste new, gfn_t gfn, union asce asce); 5271b09c13cSSteffen Eiden 5281b09c13cSSteffen Eiden long _dat_walk_gfn_range(gfn_t start, gfn_t end, union asce asce, 5291b09c13cSSteffen Eiden const struct dat_walk_ops *ops, int flags, void *priv); 5301b09c13cSSteffen Eiden 5311b09c13cSSteffen Eiden int dat_entry_walk(struct kvm_s390_mmu_cache *mc, gfn_t gfn, union asce asce, int flags, 5321b09c13cSSteffen Eiden int walk_level, union crste **last, union pte **ptepp); 5331b09c13cSSteffen Eiden void dat_free_level(struct crst_table *table, bool owns_ptes); 5341b09c13cSSteffen Eiden struct crst_table *dat_alloc_crst_sleepable(unsigned long init); 5351b09c13cSSteffen Eiden int dat_set_asce_limit(struct kvm_s390_mmu_cache *mc, union asce *asce, int newtype); 536a07276d5SSteffen Eiden 537a07276d5SSteffen Eiden #if KVM_S390_MANAGES_S390_GUEST 5381b09c13cSSteffen Eiden int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey); 5391b09c13cSSteffen Eiden int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn, 5401b09c13cSSteffen Eiden union skey skey, bool nq); 5411b09c13cSSteffen Eiden int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn, 5421b09c13cSSteffen Eiden union skey skey, union skey *oldkey, bool nq, bool mr, bool mc); 5431b09c13cSSteffen Eiden int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey); 5441b09c13cSSteffen Eiden long dat_reset_skeys(union asce asce, gfn_t start); 545a07276d5SSteffen Eiden #endif /* KVM_S390_MANAGES_S390_GUEST */ 5461b09c13cSSteffen Eiden 5471b09c13cSSteffen Eiden unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param); 5481b09c13cSSteffen Eiden void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val); 5491b09c13cSSteffen Eiden 5501b09c13cSSteffen Eiden int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end, 5511b09c13cSSteffen Eiden u16 type, u16 param); 552*188a15ccSSteffen Eiden 553*188a15ccSSteffen Eiden #if KVM_S390_MANAGES_S390_GUEST 5541b09c13cSSteffen Eiden int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn); 555*188a15ccSSteffen Eiden #else 556*188a15ccSSteffen Eiden static inline int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn) 557*188a15ccSSteffen Eiden { 558*188a15ccSSteffen Eiden return 0; 559*188a15ccSSteffen Eiden } 560*188a15ccSSteffen Eiden #endif /* KVM_S390_MANAGES_S390_GUEST */ 561*188a15ccSSteffen Eiden 5621b09c13cSSteffen Eiden bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end); 5631b09c13cSSteffen Eiden 564ce4bee6aSSteffen Eiden #if KVM_S390_MANAGES_S390_GUEST 5651b09c13cSSteffen Eiden int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty); 5661b09c13cSSteffen Eiden long dat_reset_cmma(union asce asce, gfn_t start_gfn); 5671b09c13cSSteffen Eiden int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values); 5681b09c13cSSteffen Eiden int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem); 5691b09c13cSSteffen Eiden int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn, 5701b09c13cSSteffen Eiden unsigned long count, unsigned long mask, const uint8_t *bits); 571ce4bee6aSSteffen Eiden #endif /* KVM_S390_MANAGES_S390_GUEST */ 5721b09c13cSSteffen Eiden 5731b09c13cSSteffen Eiden int kvm_s390_mmu_cache_topup(struct kvm_s390_mmu_cache *mc); 5741b09c13cSSteffen Eiden 5751b09c13cSSteffen Eiden #define GFP_KVM_S390_MMU_CACHE (GFP_ATOMIC | __GFP_ACCOUNT | __GFP_NOWARN) 5761b09c13cSSteffen Eiden 5771b09c13cSSteffen Eiden static inline struct page_table *kvm_s390_mmu_cache_alloc_pt(struct kvm_s390_mmu_cache *mc) 5781b09c13cSSteffen Eiden { 5791b09c13cSSteffen Eiden if (mc->n_pts) 5801b09c13cSSteffen Eiden return mc->pts[--mc->n_pts]; 5811b09c13cSSteffen Eiden return (void *)__get_free_page(GFP_KVM_S390_MMU_CACHE); 5821b09c13cSSteffen Eiden } 5831b09c13cSSteffen Eiden 5841b09c13cSSteffen Eiden static inline struct crst_table *kvm_s390_mmu_cache_alloc_crst(struct kvm_s390_mmu_cache *mc) 5851b09c13cSSteffen Eiden { 5861b09c13cSSteffen Eiden if (mc->n_crsts) 5871b09c13cSSteffen Eiden return mc->crsts[--mc->n_crsts]; 5881b09c13cSSteffen Eiden return (void *)__get_free_pages(GFP_KVM_S390_MMU_CACHE | __GFP_COMP, CRST_ALLOC_ORDER); 5891b09c13cSSteffen Eiden } 5901b09c13cSSteffen Eiden 5911b09c13cSSteffen Eiden static inline struct vsie_rmap *kvm_s390_mmu_cache_alloc_rmap(struct kvm_s390_mmu_cache *mc) 5921b09c13cSSteffen Eiden { 5931b09c13cSSteffen Eiden if (mc->n_rmaps) 5941b09c13cSSteffen Eiden return mc->rmaps[--mc->n_rmaps]; 5951b09c13cSSteffen Eiden return kzalloc_obj(struct vsie_rmap, GFP_KVM_S390_MMU_CACHE); 5961b09c13cSSteffen Eiden } 5971b09c13cSSteffen Eiden 5981b09c13cSSteffen Eiden static inline struct crst_table *crste_table_start(union crste *crstep) 5991b09c13cSSteffen Eiden { 6001b09c13cSSteffen Eiden return (struct crst_table *)ALIGN_DOWN((unsigned long)crstep, _CRST_TABLE_SIZE); 6011b09c13cSSteffen Eiden } 6021b09c13cSSteffen Eiden 6031b09c13cSSteffen Eiden static inline struct page_table *pte_table_start(union pte *ptep) 6041b09c13cSSteffen Eiden { 6051b09c13cSSteffen Eiden return (struct page_table *)ALIGN_DOWN((unsigned long)ptep, _PAGE_TABLE_SIZE); 6061b09c13cSSteffen Eiden } 6071b09c13cSSteffen Eiden 6081b09c13cSSteffen Eiden static inline bool crdte_crste(union crste *crstep, union crste old, union crste new, gfn_t gfn, 6091b09c13cSSteffen Eiden union asce asce) 6101b09c13cSSteffen Eiden { 6111b09c13cSSteffen Eiden unsigned long dtt = 0x10 | new.h.tt << 2; 6121b09c13cSSteffen Eiden void *table = crste_table_start(crstep); 6131b09c13cSSteffen Eiden 6141b09c13cSSteffen Eiden return crdte(old.val, new.val, table, dtt, gfn_to_gpa(gfn), asce.val); 6151b09c13cSSteffen Eiden } 6161b09c13cSSteffen Eiden 6171b09c13cSSteffen Eiden /** 6181b09c13cSSteffen Eiden * idte_crste() - invalidate a crste entry using idte 6191b09c13cSSteffen Eiden * @crstep: pointer to the crste to be invalidated 6201b09c13cSSteffen Eiden * @gfn: a gfn mapped by the crste 6211b09c13cSSteffen Eiden * @opt: options for the idte instruction 6221b09c13cSSteffen Eiden * @asce: the asce 6231b09c13cSSteffen Eiden * @local: whether the operation is cpu-local 6241b09c13cSSteffen Eiden */ 6251b09c13cSSteffen Eiden static __always_inline void idte_crste(union crste *crstep, gfn_t gfn, unsigned long opt, 6261b09c13cSSteffen Eiden union asce asce, int local) 6271b09c13cSSteffen Eiden { 6281b09c13cSSteffen Eiden unsigned long table_origin = __pa(crste_table_start(crstep)); 6291b09c13cSSteffen Eiden unsigned long gaddr = gfn_to_gpa(gfn) & HPAGE_MASK; 6301b09c13cSSteffen Eiden 6311b09c13cSSteffen Eiden if (__builtin_constant_p(opt) && opt == 0) { 6321b09c13cSSteffen Eiden /* flush without guest asce */ 6331b09c13cSSteffen Eiden asm volatile("idte %[table_origin],0,%[gaddr],%[local]" 6341b09c13cSSteffen Eiden : "+m" (*crstep) 6351b09c13cSSteffen Eiden : [table_origin] "a" (table_origin), [gaddr] "a" (gaddr), 6361b09c13cSSteffen Eiden [local] "i" (local) 6371b09c13cSSteffen Eiden : "cc"); 6381b09c13cSSteffen Eiden } else { 6391b09c13cSSteffen Eiden /* flush with guest asce */ 6401b09c13cSSteffen Eiden asm volatile("idte %[table_origin],%[asce],%[gaddr_opt],%[local]" 6411b09c13cSSteffen Eiden : "+m" (*crstep) 6421b09c13cSSteffen Eiden : [table_origin] "a" (table_origin), [gaddr_opt] "a" (gaddr | opt), 6431b09c13cSSteffen Eiden [asce] "a" (asce.val), [local] "i" (local) 6441b09c13cSSteffen Eiden : "cc"); 6451b09c13cSSteffen Eiden } 6461b09c13cSSteffen Eiden } 6471b09c13cSSteffen Eiden 6481b09c13cSSteffen Eiden static inline void dat_init_pgstes(struct page_table *pt, unsigned long val) 6491b09c13cSSteffen Eiden { 6501b09c13cSSteffen Eiden memset64((void *)pt->pgstes, val, PTRS_PER_PTE); 6511b09c13cSSteffen Eiden } 6521b09c13cSSteffen Eiden 6531b09c13cSSteffen Eiden static inline void dat_init_page_table(struct page_table *pt, unsigned long ptes, 6541b09c13cSSteffen Eiden unsigned long pgstes) 6551b09c13cSSteffen Eiden { 6561b09c13cSSteffen Eiden memset64((void *)pt->ptes, ptes, PTRS_PER_PTE); 6571b09c13cSSteffen Eiden dat_init_pgstes(pt, pgstes); 6581b09c13cSSteffen Eiden } 6591b09c13cSSteffen Eiden 6601b09c13cSSteffen Eiden static inline gfn_t asce_end(union asce asce) 6611b09c13cSSteffen Eiden { 6621b09c13cSSteffen Eiden return 1ULL << ((asce.dt + 1) * 11 + _SEGMENT_SHIFT - PAGE_SHIFT); 6631b09c13cSSteffen Eiden } 6641b09c13cSSteffen Eiden 6651b09c13cSSteffen Eiden #define _CRSTE(x) ((union crste) { .val = _Generic((x), \ 6661b09c13cSSteffen Eiden union pgd : (x).val, \ 6671b09c13cSSteffen Eiden union p4d : (x).val, \ 6681b09c13cSSteffen Eiden union pud : (x).val, \ 6691b09c13cSSteffen Eiden union pmd : (x).val, \ 6701b09c13cSSteffen Eiden union crste : (x).val)}) 6711b09c13cSSteffen Eiden 6721b09c13cSSteffen Eiden #define _CRSTEP(x) ((union crste *)_Generic((*(x)), \ 6731b09c13cSSteffen Eiden union pgd : (x), \ 6741b09c13cSSteffen Eiden union p4d : (x), \ 6751b09c13cSSteffen Eiden union pud : (x), \ 6761b09c13cSSteffen Eiden union pmd : (x), \ 6771b09c13cSSteffen Eiden union crste : (x))) 6781b09c13cSSteffen Eiden 6791b09c13cSSteffen Eiden #define _CRSTP(x) ((struct crst_table *)_Generic((*(x)), \ 6801b09c13cSSteffen Eiden struct crst_table : (x), \ 6811b09c13cSSteffen Eiden struct segment_table : (x), \ 6821b09c13cSSteffen Eiden struct region3_table : (x), \ 6831b09c13cSSteffen Eiden struct region2_table : (x), \ 6841b09c13cSSteffen Eiden struct region1_table : (x))) 6851b09c13cSSteffen Eiden 6861b09c13cSSteffen Eiden static inline bool asce_contains_gfn(union asce asce, gfn_t gfn) 6871b09c13cSSteffen Eiden { 6881b09c13cSSteffen Eiden return gfn < asce_end(asce); 6891b09c13cSSteffen Eiden } 6901b09c13cSSteffen Eiden 6911b09c13cSSteffen Eiden static inline bool is_pmd(union crste crste) 6921b09c13cSSteffen Eiden { 6931b09c13cSSteffen Eiden return crste.h.tt == TABLE_TYPE_SEGMENT; 6941b09c13cSSteffen Eiden } 6951b09c13cSSteffen Eiden 6961b09c13cSSteffen Eiden static inline bool is_pud(union crste crste) 6971b09c13cSSteffen Eiden { 6981b09c13cSSteffen Eiden return crste.h.tt == TABLE_TYPE_REGION3; 6991b09c13cSSteffen Eiden } 7001b09c13cSSteffen Eiden 7011b09c13cSSteffen Eiden static inline bool is_p4d(union crste crste) 7021b09c13cSSteffen Eiden { 7031b09c13cSSteffen Eiden return crste.h.tt == TABLE_TYPE_REGION2; 7041b09c13cSSteffen Eiden } 7051b09c13cSSteffen Eiden 7061b09c13cSSteffen Eiden static inline bool is_pgd(union crste crste) 7071b09c13cSSteffen Eiden { 7081b09c13cSSteffen Eiden return crste.h.tt == TABLE_TYPE_REGION1; 7091b09c13cSSteffen Eiden } 7101b09c13cSSteffen Eiden 7111b09c13cSSteffen Eiden static inline phys_addr_t pmd_origin_large(union pmd pmd) 7121b09c13cSSteffen Eiden { 7131b09c13cSSteffen Eiden return pmd.val & _SEGMENT_ENTRY_ORIGIN_LARGE; 7141b09c13cSSteffen Eiden } 7151b09c13cSSteffen Eiden 7161b09c13cSSteffen Eiden static inline phys_addr_t pud_origin_large(union pud pud) 7171b09c13cSSteffen Eiden { 7181b09c13cSSteffen Eiden return pud.val & _REGION3_ENTRY_ORIGIN_LARGE; 7191b09c13cSSteffen Eiden } 7201b09c13cSSteffen Eiden 7211b09c13cSSteffen Eiden /** 7221b09c13cSSteffen Eiden * crste_origin_large() - Return the large frame origin of a large crste 7231b09c13cSSteffen Eiden * @crste: The crste whose origin is to be returned. Should be either a 7241b09c13cSSteffen Eiden * region-3 table entry or a segment table entry, in both cases with 7251b09c13cSSteffen Eiden * FC set to 1 (large pages). 7261b09c13cSSteffen Eiden * 7271b09c13cSSteffen Eiden * Return: The origin of the large frame pointed to by @crste, or -1 if the 7281b09c13cSSteffen Eiden * crste was not large (wrong table type, or FC==0) 7291b09c13cSSteffen Eiden */ 7301b09c13cSSteffen Eiden static inline phys_addr_t crste_origin_large(union crste crste) 7311b09c13cSSteffen Eiden { 7321b09c13cSSteffen Eiden if (unlikely(!crste.h.fc || crste.h.tt > TABLE_TYPE_REGION3)) 7331b09c13cSSteffen Eiden return -1; 7341b09c13cSSteffen Eiden if (is_pmd(crste)) 7351b09c13cSSteffen Eiden return pmd_origin_large(crste.pmd); 7361b09c13cSSteffen Eiden return pud_origin_large(crste.pud); 7371b09c13cSSteffen Eiden } 7381b09c13cSSteffen Eiden 7391b09c13cSSteffen Eiden #define crste_origin(x) (_Generic((x), \ 7401b09c13cSSteffen Eiden union pmd : (x).val & _SEGMENT_ENTRY_ORIGIN, \ 7411b09c13cSSteffen Eiden union pud : (x).val & _REGION_ENTRY_ORIGIN, \ 7421b09c13cSSteffen Eiden union p4d : (x).val & _REGION_ENTRY_ORIGIN, \ 7431b09c13cSSteffen Eiden union pgd : (x).val & _REGION_ENTRY_ORIGIN)) 7441b09c13cSSteffen Eiden 7451b09c13cSSteffen Eiden static inline unsigned long pte_origin(union pte pte) 7461b09c13cSSteffen Eiden { 7471b09c13cSSteffen Eiden return pte.val & PAGE_MASK; 7481b09c13cSSteffen Eiden } 7491b09c13cSSteffen Eiden 7501b09c13cSSteffen Eiden static inline bool pmd_prefix(union pmd pmd) 7511b09c13cSSteffen Eiden { 7521b09c13cSSteffen Eiden return pmd.h.fc && pmd.s.fc1.prefix_notif; 7531b09c13cSSteffen Eiden } 7541b09c13cSSteffen Eiden 7551b09c13cSSteffen Eiden static inline bool pud_prefix(union pud pud) 7561b09c13cSSteffen Eiden { 7571b09c13cSSteffen Eiden return pud.h.fc && pud.s.fc1.prefix_notif; 7581b09c13cSSteffen Eiden } 7591b09c13cSSteffen Eiden 7601b09c13cSSteffen Eiden static inline bool crste_leaf(union crste crste) 7611b09c13cSSteffen Eiden { 7621b09c13cSSteffen Eiden return (crste.h.tt <= TABLE_TYPE_REGION3) && crste.h.fc; 7631b09c13cSSteffen Eiden } 7641b09c13cSSteffen Eiden 7651b09c13cSSteffen Eiden static inline bool crste_prefix(union crste crste) 7661b09c13cSSteffen Eiden { 7671b09c13cSSteffen Eiden return crste_leaf(crste) && crste.s.fc1.prefix_notif; 7681b09c13cSSteffen Eiden } 7691b09c13cSSteffen Eiden 7701b09c13cSSteffen Eiden static inline bool crste_dirty(union crste crste) 7711b09c13cSSteffen Eiden { 7721b09c13cSSteffen Eiden return crste_leaf(crste) && crste.s.fc1.d; 7731b09c13cSSteffen Eiden } 7741b09c13cSSteffen Eiden 7751b09c13cSSteffen Eiden static inline union pgste *pgste_of(union pte *pte) 7761b09c13cSSteffen Eiden { 7771b09c13cSSteffen Eiden return (union pgste *)(pte + _PAGE_ENTRIES); 7781b09c13cSSteffen Eiden } 7791b09c13cSSteffen Eiden 7801b09c13cSSteffen Eiden static inline bool pte_hole(union pte pte) 7811b09c13cSSteffen Eiden { 7821b09c13cSSteffen Eiden return pte.h.i && !pte.tok.pr && pte.tok.type != _DAT_TOKEN_NONE; 7831b09c13cSSteffen Eiden } 7841b09c13cSSteffen Eiden 7851b09c13cSSteffen Eiden static inline bool _crste_hole(union crste crste) 7861b09c13cSSteffen Eiden { 7871b09c13cSSteffen Eiden return crste.h.i && !crste.tok.pr && crste.tok.type != _DAT_TOKEN_NONE; 7881b09c13cSSteffen Eiden } 7891b09c13cSSteffen Eiden 7901b09c13cSSteffen Eiden #define crste_hole(x) _crste_hole(_CRSTE(x)) 7911b09c13cSSteffen Eiden 7921b09c13cSSteffen Eiden static inline bool _crste_none(union crste crste) 7931b09c13cSSteffen Eiden { 7941b09c13cSSteffen Eiden return crste.h.i && !crste.tok.pr && crste.tok.type == _DAT_TOKEN_NONE; 7951b09c13cSSteffen Eiden } 7961b09c13cSSteffen Eiden 7971b09c13cSSteffen Eiden #define crste_none(x) _crste_none(_CRSTE(x)) 7981b09c13cSSteffen Eiden 7991b09c13cSSteffen Eiden static inline phys_addr_t large_pud_to_phys(union pud pud, gfn_t gfn) 8001b09c13cSSteffen Eiden { 8011b09c13cSSteffen Eiden return pud_origin_large(pud) | (gfn_to_gpa(gfn) & ~_REGION3_MASK); 8021b09c13cSSteffen Eiden } 8031b09c13cSSteffen Eiden 8041b09c13cSSteffen Eiden static inline phys_addr_t large_pmd_to_phys(union pmd pmd, gfn_t gfn) 8051b09c13cSSteffen Eiden { 8061b09c13cSSteffen Eiden return pmd_origin_large(pmd) | (gfn_to_gpa(gfn) & ~_SEGMENT_MASK); 8071b09c13cSSteffen Eiden } 8081b09c13cSSteffen Eiden 8091b09c13cSSteffen Eiden static inline phys_addr_t large_crste_to_phys(union crste crste, gfn_t gfn) 8101b09c13cSSteffen Eiden { 8111b09c13cSSteffen Eiden if (unlikely(!crste.h.fc || crste.h.tt > TABLE_TYPE_REGION3)) 8121b09c13cSSteffen Eiden return -1; 8131b09c13cSSteffen Eiden if (is_pmd(crste)) 8141b09c13cSSteffen Eiden return large_pmd_to_phys(crste.pmd, gfn); 8151b09c13cSSteffen Eiden return large_pud_to_phys(crste.pud, gfn); 8161b09c13cSSteffen Eiden } 8171b09c13cSSteffen Eiden 8181b09c13cSSteffen Eiden static inline bool cspg_crste(union crste *crstep, union crste old, union crste new) 8191b09c13cSSteffen Eiden { 8201b09c13cSSteffen Eiden return cspg(&crstep->val, old.val, new.val); 8211b09c13cSSteffen Eiden } 8221b09c13cSSteffen Eiden 8231b09c13cSSteffen Eiden static inline struct page_table *dereference_pmd(union pmd pmd) 8241b09c13cSSteffen Eiden { 8251b09c13cSSteffen Eiden return phys_to_virt(crste_origin(pmd)); 8261b09c13cSSteffen Eiden } 8271b09c13cSSteffen Eiden 8281b09c13cSSteffen Eiden static inline struct segment_table *dereference_pud(union pud pud) 8291b09c13cSSteffen Eiden { 8301b09c13cSSteffen Eiden return phys_to_virt(crste_origin(pud)); 8311b09c13cSSteffen Eiden } 8321b09c13cSSteffen Eiden 8331b09c13cSSteffen Eiden static inline struct region3_table *dereference_p4d(union p4d p4d) 8341b09c13cSSteffen Eiden { 8351b09c13cSSteffen Eiden return phys_to_virt(crste_origin(p4d)); 8361b09c13cSSteffen Eiden } 8371b09c13cSSteffen Eiden 8381b09c13cSSteffen Eiden static inline struct region2_table *dereference_pgd(union pgd pgd) 8391b09c13cSSteffen Eiden { 8401b09c13cSSteffen Eiden return phys_to_virt(crste_origin(pgd)); 8411b09c13cSSteffen Eiden } 8421b09c13cSSteffen Eiden 8431b09c13cSSteffen Eiden static inline struct crst_table *_dereference_crste(union crste crste) 8441b09c13cSSteffen Eiden { 8451b09c13cSSteffen Eiden if (unlikely(is_pmd(crste))) 8461b09c13cSSteffen Eiden return NULL; 8471b09c13cSSteffen Eiden return phys_to_virt(crste_origin(crste.pud)); 8481b09c13cSSteffen Eiden } 8491b09c13cSSteffen Eiden 8501b09c13cSSteffen Eiden #define dereference_crste(x) (_Generic((x), \ 8511b09c13cSSteffen Eiden union pud : _dereference_crste(_CRSTE(x)), \ 8521b09c13cSSteffen Eiden union p4d : _dereference_crste(_CRSTE(x)), \ 8531b09c13cSSteffen Eiden union pgd : _dereference_crste(_CRSTE(x)), \ 8541b09c13cSSteffen Eiden union crste : _dereference_crste(_CRSTE(x)))) 8551b09c13cSSteffen Eiden 8561b09c13cSSteffen Eiden static inline struct crst_table *dereference_asce(union asce asce) 8571b09c13cSSteffen Eiden { 8581b09c13cSSteffen Eiden return phys_to_virt(asce.val & _ASCE_ORIGIN); 8591b09c13cSSteffen Eiden } 8601b09c13cSSteffen Eiden 8611b09c13cSSteffen Eiden static inline void asce_flush_tlb(union asce asce) 8621b09c13cSSteffen Eiden { 8631b09c13cSSteffen Eiden __tlb_flush_idte(asce.val); 8641b09c13cSSteffen Eiden } 8651b09c13cSSteffen Eiden 8661b09c13cSSteffen Eiden static inline bool pgste_get_trylock(union pte *ptep, union pgste *res) 8671b09c13cSSteffen Eiden { 8681b09c13cSSteffen Eiden union pgste *pgstep = pgste_of(ptep); 8691b09c13cSSteffen Eiden union pgste old_pgste; 8701b09c13cSSteffen Eiden 8711b09c13cSSteffen Eiden if (READ_ONCE(pgstep->val) & PGSTE_PCL_BIT) 8721b09c13cSSteffen Eiden return false; 8731b09c13cSSteffen Eiden old_pgste.val = __atomic64_or_barrier(PGSTE_PCL_BIT, &pgstep->val); 8741b09c13cSSteffen Eiden if (old_pgste.pcl) 8751b09c13cSSteffen Eiden return false; 8761b09c13cSSteffen Eiden old_pgste.pcl = 1; 8771b09c13cSSteffen Eiden *res = old_pgste; 8781b09c13cSSteffen Eiden return true; 8791b09c13cSSteffen Eiden } 8801b09c13cSSteffen Eiden 8811b09c13cSSteffen Eiden static inline union pgste pgste_get_lock(union pte *ptep) 8821b09c13cSSteffen Eiden { 8831b09c13cSSteffen Eiden union pgste res; 8841b09c13cSSteffen Eiden 8851b09c13cSSteffen Eiden while (!pgste_get_trylock(ptep, &res)) 8861b09c13cSSteffen Eiden cpu_relax(); 8871b09c13cSSteffen Eiden return res; 8881b09c13cSSteffen Eiden } 8891b09c13cSSteffen Eiden 8901b09c13cSSteffen Eiden static inline void pgste_set_unlock(union pte *ptep, union pgste pgste) 8911b09c13cSSteffen Eiden { 8921b09c13cSSteffen Eiden pgste.pcl = 0; 8931b09c13cSSteffen Eiden barrier(); 8941b09c13cSSteffen Eiden WRITE_ONCE(*pgste_of(ptep), pgste); 8951b09c13cSSteffen Eiden } 8961b09c13cSSteffen Eiden 8971b09c13cSSteffen Eiden static inline void dat_ptep_xchg(union pte *ptep, union pte new, gfn_t gfn, union asce asce, 8981b09c13cSSteffen Eiden bool has_skeys) 8991b09c13cSSteffen Eiden { 9001b09c13cSSteffen Eiden union pgste pgste; 9011b09c13cSSteffen Eiden 9021b09c13cSSteffen Eiden pgste = pgste_get_lock(ptep); 9031b09c13cSSteffen Eiden pgste = __dat_ptep_xchg(ptep, pgste, new, gfn, asce, has_skeys); 9041b09c13cSSteffen Eiden pgste_set_unlock(ptep, pgste); 9051b09c13cSSteffen Eiden } 9061b09c13cSSteffen Eiden 9071b09c13cSSteffen Eiden static inline void dat_ptep_clear(union pte *ptep, gfn_t gfn, union asce asce, bool has_skeys) 9081b09c13cSSteffen Eiden { 9091b09c13cSSteffen Eiden dat_ptep_xchg(ptep, _PTE_EMPTY, gfn, asce, has_skeys); 9101b09c13cSSteffen Eiden } 9111b09c13cSSteffen Eiden 9121b09c13cSSteffen Eiden static inline void dat_free_pt(struct page_table *pt) 9131b09c13cSSteffen Eiden { 9141b09c13cSSteffen Eiden free_page((unsigned long)pt); 9151b09c13cSSteffen Eiden } 9161b09c13cSSteffen Eiden 9171b09c13cSSteffen Eiden static inline void _dat_free_crst(struct crst_table *table) 9181b09c13cSSteffen Eiden { 9191b09c13cSSteffen Eiden free_pages((unsigned long)table, CRST_ALLOC_ORDER); 9201b09c13cSSteffen Eiden } 9211b09c13cSSteffen Eiden 9221b09c13cSSteffen Eiden #define dat_free_crst(x) _dat_free_crst(_CRSTP(x)) 9231b09c13cSSteffen Eiden 9241b09c13cSSteffen Eiden static inline void kvm_s390_free_mmu_cache(struct kvm_s390_mmu_cache *mc) 9251b09c13cSSteffen Eiden { 9261b09c13cSSteffen Eiden if (!mc) 9271b09c13cSSteffen Eiden return; 9281b09c13cSSteffen Eiden while (mc->n_pts) 9291b09c13cSSteffen Eiden dat_free_pt(mc->pts[--mc->n_pts]); 9301b09c13cSSteffen Eiden while (mc->n_crsts) 9311b09c13cSSteffen Eiden _dat_free_crst(mc->crsts[--mc->n_crsts]); 9321b09c13cSSteffen Eiden while (mc->n_rmaps) 9331b09c13cSSteffen Eiden kfree(mc->rmaps[--mc->n_rmaps]); 9341b09c13cSSteffen Eiden kfree(mc); 9351b09c13cSSteffen Eiden } 9361b09c13cSSteffen Eiden 9371b09c13cSSteffen Eiden DEFINE_FREE(kvm_s390_mmu_cache, struct kvm_s390_mmu_cache *, if (_T) kvm_s390_free_mmu_cache(_T)) 9381b09c13cSSteffen Eiden 9391b09c13cSSteffen Eiden static inline struct kvm_s390_mmu_cache *kvm_s390_new_mmu_cache(void) 9401b09c13cSSteffen Eiden { 9411b09c13cSSteffen Eiden struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL; 9421b09c13cSSteffen Eiden 9431b09c13cSSteffen Eiden mc = kzalloc_obj(*mc, GFP_KERNEL_ACCOUNT); 9441b09c13cSSteffen Eiden if (mc && !kvm_s390_mmu_cache_topup(mc)) 9451b09c13cSSteffen Eiden return_ptr(mc); 9461b09c13cSSteffen Eiden return NULL; 9471b09c13cSSteffen Eiden } 9481b09c13cSSteffen Eiden 9491b09c13cSSteffen Eiden static inline bool dat_pmdp_xchg_atomic(union pmd *pmdp, union pmd old, union pmd new, 9501b09c13cSSteffen Eiden gfn_t gfn, union asce asce) 9511b09c13cSSteffen Eiden { 9521b09c13cSSteffen Eiden return dat_crstep_xchg_atomic(_CRSTEP(pmdp), _CRSTE(old), _CRSTE(new), gfn, asce); 9531b09c13cSSteffen Eiden } 9541b09c13cSSteffen Eiden 9551b09c13cSSteffen Eiden static inline bool dat_pudp_xchg_atomic(union pud *pudp, union pud old, union pud new, 9561b09c13cSSteffen Eiden gfn_t gfn, union asce asce) 9571b09c13cSSteffen Eiden { 9581b09c13cSSteffen Eiden return dat_crstep_xchg_atomic(_CRSTEP(pudp), _CRSTE(old), _CRSTE(new), gfn, asce); 9591b09c13cSSteffen Eiden } 9601b09c13cSSteffen Eiden 9611b09c13cSSteffen Eiden static inline union crste dat_crstep_clear_atomic(union crste *crstep, gfn_t gfn, union asce asce) 9621b09c13cSSteffen Eiden { 9631b09c13cSSteffen Eiden union crste oldcrste, empty = _CRSTE_EMPTY(crstep->h.tt); 9641b09c13cSSteffen Eiden 9651b09c13cSSteffen Eiden do { 9661b09c13cSSteffen Eiden oldcrste = READ_ONCE(*crstep); 9671b09c13cSSteffen Eiden } while (!dat_crstep_xchg_atomic(crstep, oldcrste, empty, gfn, asce)); 9681b09c13cSSteffen Eiden return oldcrste; 9691b09c13cSSteffen Eiden } 9701b09c13cSSteffen Eiden 9711b09c13cSSteffen Eiden static inline int get_level(union crste *crstep, union pte *ptep) 9721b09c13cSSteffen Eiden { 9731b09c13cSSteffen Eiden return ptep ? TABLE_TYPE_PAGE_TABLE : crstep->h.tt; 9741b09c13cSSteffen Eiden } 9751b09c13cSSteffen Eiden 9761b09c13cSSteffen Eiden static inline int dat_delete_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, 9771b09c13cSSteffen Eiden unsigned long npages) 9781b09c13cSSteffen Eiden { 9791b09c13cSSteffen Eiden return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_PIC, PGM_ADDRESSING); 9801b09c13cSSteffen Eiden } 9811b09c13cSSteffen Eiden 9821b09c13cSSteffen Eiden static inline int dat_create_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, 9831b09c13cSSteffen Eiden unsigned long npages) 9841b09c13cSSteffen Eiden { 9851b09c13cSSteffen Eiden return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_NONE, 0); 9861b09c13cSSteffen Eiden } 9871b09c13cSSteffen Eiden 9881b09c13cSSteffen Eiden static inline bool crste_is_ucas(union crste crste) 9891b09c13cSSteffen Eiden { 9901b09c13cSSteffen Eiden return is_pmd(crste) && crste.h.i && crste.h.fc0.tl == 1 && crste.h.fc == 0; 9911b09c13cSSteffen Eiden } 9921b09c13cSSteffen Eiden 9931b09c13cSSteffen Eiden #endif /* ARCH_KVM_GMAP_DAT_H */ 994