xref: /linux/arch/s390/kvm/dat.h (revision 8934827db5403eae57d4537114a9ff88b0a8460f)
15a74e3d9SClaudio Imbrenda /* SPDX-License-Identifier: GPL-2.0 */
25a74e3d9SClaudio Imbrenda /*
35a74e3d9SClaudio Imbrenda  *  KVM guest address space mapping code
45a74e3d9SClaudio Imbrenda  *
55a74e3d9SClaudio Imbrenda  *    Copyright IBM Corp. 2024, 2025
65a74e3d9SClaudio Imbrenda  *    Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
75a74e3d9SClaudio Imbrenda  */
85a74e3d9SClaudio Imbrenda 
95a74e3d9SClaudio Imbrenda #ifndef __KVM_S390_DAT_H
105a74e3d9SClaudio Imbrenda #define __KVM_S390_DAT_H
115a74e3d9SClaudio Imbrenda 
125a74e3d9SClaudio Imbrenda #include <linux/radix-tree.h>
135a74e3d9SClaudio Imbrenda #include <linux/refcount.h>
145a74e3d9SClaudio Imbrenda #include <linux/io.h>
155a74e3d9SClaudio Imbrenda #include <linux/kvm_types.h>
165a74e3d9SClaudio Imbrenda #include <linux/pgalloc.h>
175a74e3d9SClaudio Imbrenda #include <asm/tlbflush.h>
185a74e3d9SClaudio Imbrenda #include <asm/dat-bits.h>
195a74e3d9SClaudio Imbrenda 
207b368470SClaudio Imbrenda /*
217b368470SClaudio Imbrenda  * Base address and length must be sent at the start of each block, therefore
227b368470SClaudio Imbrenda  * it's cheaper to send some clean data, as long as it's less than the size of
237b368470SClaudio Imbrenda  * two longs.
247b368470SClaudio Imbrenda  */
257b368470SClaudio Imbrenda #define KVM_S390_MAX_BIT_DISTANCE (2 * sizeof(void *))
267b368470SClaudio Imbrenda /* For consistency */
277b368470SClaudio Imbrenda #define KVM_S390_CMMA_SIZE_MAX ((u32)KVM_S390_SKEYS_MAX)
287b368470SClaudio Imbrenda 
295a74e3d9SClaudio Imbrenda #define _ASCE(x) ((union asce) { .val = (x), })
305a74e3d9SClaudio Imbrenda #define NULL_ASCE _ASCE(0)
315a74e3d9SClaudio Imbrenda 
325a74e3d9SClaudio Imbrenda enum {
335a74e3d9SClaudio Imbrenda 	_DAT_TOKEN_NONE = 0,
345a74e3d9SClaudio Imbrenda 	_DAT_TOKEN_PIC,
355a74e3d9SClaudio Imbrenda };
365a74e3d9SClaudio Imbrenda 
375a74e3d9SClaudio Imbrenda #define _CRSTE_TOK(l, t, p) ((union crste) {	\
385a74e3d9SClaudio Imbrenda 		.tok.i = 1,			\
395a74e3d9SClaudio Imbrenda 		.tok.tt = (l),			\
405a74e3d9SClaudio Imbrenda 		.tok.type = (t),		\
415a74e3d9SClaudio Imbrenda 		.tok.par = (p)			\
425a74e3d9SClaudio Imbrenda 	})
435a74e3d9SClaudio Imbrenda #define _CRSTE_PIC(l, p) _CRSTE_TOK(l, _DAT_TOKEN_PIC, p)
445a74e3d9SClaudio Imbrenda 
455a74e3d9SClaudio Imbrenda #define _CRSTE_HOLE(l) _CRSTE_PIC(l, PGM_ADDRESSING)
465a74e3d9SClaudio Imbrenda #define _CRSTE_EMPTY(l) _CRSTE_TOK(l, _DAT_TOKEN_NONE, 0)
475a74e3d9SClaudio Imbrenda 
485a74e3d9SClaudio Imbrenda #define _PMD_EMPTY _CRSTE_EMPTY(TABLE_TYPE_SEGMENT)
495a74e3d9SClaudio Imbrenda 
505a74e3d9SClaudio Imbrenda #define _PTE_TOK(t, p) ((union pte) { .tok.i = 1, .tok.type = (t), .tok.par = (p) })
515a74e3d9SClaudio Imbrenda #define _PTE_EMPTY _PTE_TOK(_DAT_TOKEN_NONE, 0)
525a74e3d9SClaudio Imbrenda 
535a74e3d9SClaudio Imbrenda /* This fake table type is used for page table walks (both for normal page tables and vSIE) */
545a74e3d9SClaudio Imbrenda #define TABLE_TYPE_PAGE_TABLE -1
555a74e3d9SClaudio Imbrenda 
565a74e3d9SClaudio Imbrenda enum dat_walk_flags {
572db149a0SClaudio Imbrenda 	DAT_WALK_USES_SKEYS	= 0x40,
585a74e3d9SClaudio Imbrenda 	DAT_WALK_CONTINUE	= 0x20,
595a74e3d9SClaudio Imbrenda 	DAT_WALK_IGN_HOLES	= 0x10,
605a74e3d9SClaudio Imbrenda 	DAT_WALK_SPLIT		= 0x08,
615a74e3d9SClaudio Imbrenda 	DAT_WALK_ALLOC		= 0x04,
625a74e3d9SClaudio Imbrenda 	DAT_WALK_ANY		= 0x02,
635a74e3d9SClaudio Imbrenda 	DAT_WALK_LEAF		= 0x01,
645a74e3d9SClaudio Imbrenda 	DAT_WALK_DEFAULT	= 0
655a74e3d9SClaudio Imbrenda };
665a74e3d9SClaudio Imbrenda 
675a74e3d9SClaudio Imbrenda #define DAT_WALK_SPLIT_ALLOC (DAT_WALK_SPLIT | DAT_WALK_ALLOC)
685a74e3d9SClaudio Imbrenda #define DAT_WALK_ALLOC_CONTINUE (DAT_WALK_CONTINUE | DAT_WALK_ALLOC)
695a74e3d9SClaudio Imbrenda #define DAT_WALK_LEAF_ALLOC (DAT_WALK_LEAF | DAT_WALK_ALLOC)
705a74e3d9SClaudio Imbrenda 
715a74e3d9SClaudio Imbrenda union pte {
725a74e3d9SClaudio Imbrenda 	unsigned long val;
735a74e3d9SClaudio Imbrenda 	union page_table_entry h;
745a74e3d9SClaudio Imbrenda 	struct {
755a74e3d9SClaudio Imbrenda 		unsigned long   :56; /* Hardware bits */
765a74e3d9SClaudio Imbrenda 		unsigned long u : 1; /* Page unused */
775a74e3d9SClaudio Imbrenda 		unsigned long s : 1; /* Special */
785a74e3d9SClaudio Imbrenda 		unsigned long w : 1; /* Writable */
795a74e3d9SClaudio Imbrenda 		unsigned long r : 1; /* Readable */
805a74e3d9SClaudio Imbrenda 		unsigned long d : 1; /* Dirty */
815a74e3d9SClaudio Imbrenda 		unsigned long y : 1; /* Young */
825a74e3d9SClaudio Imbrenda 		unsigned long sd: 1; /* Soft dirty */
835a74e3d9SClaudio Imbrenda 		unsigned long pr: 1; /* Present */
845a74e3d9SClaudio Imbrenda 	} s;
855a74e3d9SClaudio Imbrenda 	struct {
865a74e3d9SClaudio Imbrenda 		unsigned char hwbytes[7];
875a74e3d9SClaudio Imbrenda 		unsigned char swbyte;
885a74e3d9SClaudio Imbrenda 	};
895a74e3d9SClaudio Imbrenda 	union {
905a74e3d9SClaudio Imbrenda 		struct {
915a74e3d9SClaudio Imbrenda 			unsigned long type :16; /* Token type */
925a74e3d9SClaudio Imbrenda 			unsigned long par  :16; /* Token parameter */
935a74e3d9SClaudio Imbrenda 			unsigned long      :20;
945a74e3d9SClaudio Imbrenda 			unsigned long      : 1; /* Must be 0 */
955a74e3d9SClaudio Imbrenda 			unsigned long i    : 1; /* Must be 1 */
965a74e3d9SClaudio Imbrenda 			unsigned long      : 2;
975a74e3d9SClaudio Imbrenda 			unsigned long      : 7;
985a74e3d9SClaudio Imbrenda 			unsigned long pr   : 1; /* Must be 0 */
995a74e3d9SClaudio Imbrenda 		};
1005a74e3d9SClaudio Imbrenda 		struct {
1015a74e3d9SClaudio Imbrenda 			unsigned long token:32; /* Token and parameter */
1025a74e3d9SClaudio Imbrenda 			unsigned long      :32;
1035a74e3d9SClaudio Imbrenda 		};
1045a74e3d9SClaudio Imbrenda 	} tok;
1055a74e3d9SClaudio Imbrenda };
1065a74e3d9SClaudio Imbrenda 
1075a74e3d9SClaudio Imbrenda /* Soft dirty, needed as macro for atomic operations on ptes */
1085a74e3d9SClaudio Imbrenda #define _PAGE_SD 0x002
1095a74e3d9SClaudio Imbrenda 
1105a74e3d9SClaudio Imbrenda /* Needed as macro to perform atomic operations */
111728b0e21SClaudio Imbrenda #define PGSTE_PCL_BIT		0x0080000000000000UL	/* PCL lock, HW bit */
1125a74e3d9SClaudio Imbrenda #define PGSTE_CMMA_D_BIT	0x0000000000008000UL	/* CMMA dirty soft-bit */
1135a74e3d9SClaudio Imbrenda 
1145a74e3d9SClaudio Imbrenda enum pgste_gps_usage {
1155a74e3d9SClaudio Imbrenda 	PGSTE_GPS_USAGE_STABLE = 0,
1165a74e3d9SClaudio Imbrenda 	PGSTE_GPS_USAGE_UNUSED,
1175a74e3d9SClaudio Imbrenda 	PGSTE_GPS_USAGE_POT_VOLATILE,
1185a74e3d9SClaudio Imbrenda 	PGSTE_GPS_USAGE_VOLATILE,
1195a74e3d9SClaudio Imbrenda };
1205a74e3d9SClaudio Imbrenda 
1215a74e3d9SClaudio Imbrenda union pgste {
1225a74e3d9SClaudio Imbrenda 	unsigned long val;
1235a74e3d9SClaudio Imbrenda 	struct {
1245a74e3d9SClaudio Imbrenda 		unsigned long acc          : 4;
1255a74e3d9SClaudio Imbrenda 		unsigned long fp           : 1;
1265a74e3d9SClaudio Imbrenda 		unsigned long              : 3;
1275a74e3d9SClaudio Imbrenda 		unsigned long pcl          : 1;
1285a74e3d9SClaudio Imbrenda 		unsigned long hr           : 1;
1295a74e3d9SClaudio Imbrenda 		unsigned long hc           : 1;
1305a74e3d9SClaudio Imbrenda 		unsigned long              : 2;
1315a74e3d9SClaudio Imbrenda 		unsigned long gr           : 1;
1325a74e3d9SClaudio Imbrenda 		unsigned long gc           : 1;
1335a74e3d9SClaudio Imbrenda 		unsigned long              : 1;
1345a74e3d9SClaudio Imbrenda 		unsigned long              :16; /* val16 */
1355a74e3d9SClaudio Imbrenda 		unsigned long zero         : 1;
1365a74e3d9SClaudio Imbrenda 		unsigned long nodat        : 1;
1375a74e3d9SClaudio Imbrenda 		unsigned long              : 4;
1385a74e3d9SClaudio Imbrenda 		unsigned long usage        : 2;
1395a74e3d9SClaudio Imbrenda 		unsigned long              : 8;
1405a74e3d9SClaudio Imbrenda 		unsigned long cmma_d       : 1; /* Dirty flag for CMMA bits */
1415a74e3d9SClaudio Imbrenda 		unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
1425a74e3d9SClaudio Imbrenda 		unsigned long vsie_notif   : 1; /* Referenced in a shadow table */
1435a74e3d9SClaudio Imbrenda 		unsigned long              : 5;
1445a74e3d9SClaudio Imbrenda 		unsigned long              : 8;
1455a74e3d9SClaudio Imbrenda 	};
1465a74e3d9SClaudio Imbrenda 	struct {
1475a74e3d9SClaudio Imbrenda 		unsigned short hwbytes0;
1485a74e3d9SClaudio Imbrenda 		unsigned short val16;	/* Used to store chunked values, see dat_{s,g}et_ptval() */
1495a74e3d9SClaudio Imbrenda 		unsigned short hwbytes4;
1505a74e3d9SClaudio Imbrenda 		unsigned char flags;	/* Maps to the software bits */
1515a74e3d9SClaudio Imbrenda 		unsigned char hwbyte7;
1525a74e3d9SClaudio Imbrenda 	} __packed;
1535a74e3d9SClaudio Imbrenda };
1545a74e3d9SClaudio Imbrenda 
1555a74e3d9SClaudio Imbrenda union pmd {
1565a74e3d9SClaudio Imbrenda 	unsigned long val;
1575a74e3d9SClaudio Imbrenda 	union segment_table_entry h;
1585a74e3d9SClaudio Imbrenda 	struct {
1595a74e3d9SClaudio Imbrenda 		struct {
1605a74e3d9SClaudio Imbrenda 			unsigned long              :44; /* HW */
1615a74e3d9SClaudio Imbrenda 			unsigned long              : 3; /* Unused */
1625a74e3d9SClaudio Imbrenda 			unsigned long              : 1; /* HW */
1635a74e3d9SClaudio Imbrenda 			unsigned long w            : 1; /* Writable soft-bit */
1645a74e3d9SClaudio Imbrenda 			unsigned long r            : 1; /* Readable soft-bit */
1655a74e3d9SClaudio Imbrenda 			unsigned long d            : 1; /* Dirty */
1665a74e3d9SClaudio Imbrenda 			unsigned long y            : 1; /* Young */
1675a74e3d9SClaudio Imbrenda 			unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
1685a74e3d9SClaudio Imbrenda 			unsigned long              : 3; /* HW */
1695a74e3d9SClaudio Imbrenda 			unsigned long vsie_notif   : 1; /* Referenced in a shadow table */
1705a74e3d9SClaudio Imbrenda 			unsigned long              : 1; /* Unused */
1715a74e3d9SClaudio Imbrenda 			unsigned long              : 4; /* HW */
1725a74e3d9SClaudio Imbrenda 			unsigned long sd           : 1; /* Soft-Dirty */
1735a74e3d9SClaudio Imbrenda 			unsigned long pr           : 1; /* Present */
1745a74e3d9SClaudio Imbrenda 		} fc1;
1755a74e3d9SClaudio Imbrenda 	} s;
1765a74e3d9SClaudio Imbrenda };
1775a74e3d9SClaudio Imbrenda 
1785a74e3d9SClaudio Imbrenda union pud {
1795a74e3d9SClaudio Imbrenda 	unsigned long val;
1805a74e3d9SClaudio Imbrenda 	union region3_table_entry h;
1815a74e3d9SClaudio Imbrenda 	struct {
1825a74e3d9SClaudio Imbrenda 		struct {
1835a74e3d9SClaudio Imbrenda 			unsigned long              :33; /* HW */
1845a74e3d9SClaudio Imbrenda 			unsigned long              :14; /* Unused */
1855a74e3d9SClaudio Imbrenda 			unsigned long              : 1; /* HW */
1865a74e3d9SClaudio Imbrenda 			unsigned long w            : 1; /* Writable soft-bit */
1875a74e3d9SClaudio Imbrenda 			unsigned long r            : 1; /* Readable soft-bit */
1885a74e3d9SClaudio Imbrenda 			unsigned long d            : 1; /* Dirty */
1895a74e3d9SClaudio Imbrenda 			unsigned long y            : 1; /* Young */
1905a74e3d9SClaudio Imbrenda 			unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
1915a74e3d9SClaudio Imbrenda 			unsigned long              : 3; /* HW */
1925a74e3d9SClaudio Imbrenda 			unsigned long vsie_notif   : 1; /* Referenced in a shadow table */
1935a74e3d9SClaudio Imbrenda 			unsigned long              : 1; /* Unused */
1945a74e3d9SClaudio Imbrenda 			unsigned long              : 4; /* HW */
1955a74e3d9SClaudio Imbrenda 			unsigned long sd           : 1; /* Soft-Dirty */
1965a74e3d9SClaudio Imbrenda 			unsigned long pr           : 1; /* Present */
1975a74e3d9SClaudio Imbrenda 		} fc1;
1985a74e3d9SClaudio Imbrenda 	} s;
1995a74e3d9SClaudio Imbrenda };
2005a74e3d9SClaudio Imbrenda 
2015a74e3d9SClaudio Imbrenda union p4d {
2025a74e3d9SClaudio Imbrenda 	unsigned long val;
2035a74e3d9SClaudio Imbrenda 	union region2_table_entry h;
2045a74e3d9SClaudio Imbrenda };
2055a74e3d9SClaudio Imbrenda 
2065a74e3d9SClaudio Imbrenda union pgd {
2075a74e3d9SClaudio Imbrenda 	unsigned long val;
2085a74e3d9SClaudio Imbrenda 	union region1_table_entry h;
2095a74e3d9SClaudio Imbrenda };
2105a74e3d9SClaudio Imbrenda 
2115a74e3d9SClaudio Imbrenda union crste {
2125a74e3d9SClaudio Imbrenda 	unsigned long val;
2135a74e3d9SClaudio Imbrenda 	union {
2145a74e3d9SClaudio Imbrenda 		struct {
2155a74e3d9SClaudio Imbrenda 			unsigned long   :52;
2165a74e3d9SClaudio Imbrenda 			unsigned long   : 1;
2175a74e3d9SClaudio Imbrenda 			unsigned long fc: 1;
2185a74e3d9SClaudio Imbrenda 			unsigned long p : 1;
2195a74e3d9SClaudio Imbrenda 			unsigned long   : 1;
2205a74e3d9SClaudio Imbrenda 			unsigned long   : 2;
2215a74e3d9SClaudio Imbrenda 			unsigned long i : 1;
2225a74e3d9SClaudio Imbrenda 			unsigned long   : 1;
2235a74e3d9SClaudio Imbrenda 			unsigned long tt: 2;
2245a74e3d9SClaudio Imbrenda 			unsigned long   : 2;
2255a74e3d9SClaudio Imbrenda 		};
2265a74e3d9SClaudio Imbrenda 		struct {
2275a74e3d9SClaudio Imbrenda 			unsigned long to:52;
2285a74e3d9SClaudio Imbrenda 			unsigned long   : 1;
2295a74e3d9SClaudio Imbrenda 			unsigned long fc: 1;
2305a74e3d9SClaudio Imbrenda 			unsigned long p : 1;
2315a74e3d9SClaudio Imbrenda 			unsigned long   : 1;
2325a74e3d9SClaudio Imbrenda 			unsigned long tf: 2;
2335a74e3d9SClaudio Imbrenda 			unsigned long i : 1;
2345a74e3d9SClaudio Imbrenda 			unsigned long   : 1;
2355a74e3d9SClaudio Imbrenda 			unsigned long tt: 2;
2365a74e3d9SClaudio Imbrenda 			unsigned long tl: 2;
2375a74e3d9SClaudio Imbrenda 		} fc0;
2385a74e3d9SClaudio Imbrenda 		struct {
2395a74e3d9SClaudio Imbrenda 			unsigned long    :47;
2405a74e3d9SClaudio Imbrenda 			unsigned long av : 1; /* ACCF-Validity Control */
2415a74e3d9SClaudio Imbrenda 			unsigned long acc: 4; /* Access-Control Bits */
2425a74e3d9SClaudio Imbrenda 			unsigned long f  : 1; /* Fetch-Protection Bit */
2435a74e3d9SClaudio Imbrenda 			unsigned long fc : 1; /* Format-Control */
2445a74e3d9SClaudio Imbrenda 			unsigned long p  : 1; /* DAT-Protection Bit */
2455a74e3d9SClaudio Imbrenda 			unsigned long iep: 1; /* Instruction-Execution-Protection */
2465a74e3d9SClaudio Imbrenda 			unsigned long    : 2;
2475a74e3d9SClaudio Imbrenda 			unsigned long i  : 1; /* Segment-Invalid Bit */
2485a74e3d9SClaudio Imbrenda 			unsigned long cs : 1; /* Common-Segment Bit */
2495a74e3d9SClaudio Imbrenda 			unsigned long tt : 2; /* Table-Type Bits */
2505a74e3d9SClaudio Imbrenda 			unsigned long    : 2;
2515a74e3d9SClaudio Imbrenda 		} fc1;
2525a74e3d9SClaudio Imbrenda 	} h;
2535a74e3d9SClaudio Imbrenda 	struct {
2545a74e3d9SClaudio Imbrenda 		struct {
2555a74e3d9SClaudio Imbrenda 			unsigned long              :47;
2565a74e3d9SClaudio Imbrenda 			unsigned long              : 1; /* HW (should be 0) */
2575a74e3d9SClaudio Imbrenda 			unsigned long w            : 1; /* Writable */
2585a74e3d9SClaudio Imbrenda 			unsigned long r            : 1; /* Readable */
2595a74e3d9SClaudio Imbrenda 			unsigned long d            : 1; /* Dirty */
2605a74e3d9SClaudio Imbrenda 			unsigned long y            : 1; /* Young */
2615a74e3d9SClaudio Imbrenda 			unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
2625a74e3d9SClaudio Imbrenda 			unsigned long              : 3; /* HW */
2635a74e3d9SClaudio Imbrenda 			unsigned long vsie_notif   : 1; /* Referenced in a shadow table */
2645a74e3d9SClaudio Imbrenda 			unsigned long              : 1;
2655a74e3d9SClaudio Imbrenda 			unsigned long              : 4; /* HW */
2665a74e3d9SClaudio Imbrenda 			unsigned long sd           : 1; /* Soft-Dirty */
2675a74e3d9SClaudio Imbrenda 			unsigned long pr           : 1; /* Present */
2685a74e3d9SClaudio Imbrenda 		} fc1;
2695a74e3d9SClaudio Imbrenda 	} s;
2705a74e3d9SClaudio Imbrenda 	union {
2715a74e3d9SClaudio Imbrenda 		struct {
2725a74e3d9SClaudio Imbrenda 			unsigned long type :16; /* Token type */
2735a74e3d9SClaudio Imbrenda 			unsigned long par  :16; /* Token parameter */
2745a74e3d9SClaudio Imbrenda 			unsigned long      :26;
2755a74e3d9SClaudio Imbrenda 			unsigned long i    : 1; /* Must be 1 */
2765a74e3d9SClaudio Imbrenda 			unsigned long      : 1;
2775a74e3d9SClaudio Imbrenda 			unsigned long tt   : 2;
2785a74e3d9SClaudio Imbrenda 			unsigned long      : 1;
2795a74e3d9SClaudio Imbrenda 			unsigned long pr   : 1; /* Must be 0 */
2805a74e3d9SClaudio Imbrenda 		};
2815a74e3d9SClaudio Imbrenda 		struct {
2825a74e3d9SClaudio Imbrenda 			unsigned long token:32; /* Token and parameter */
2835a74e3d9SClaudio Imbrenda 			unsigned long      :32;
2845a74e3d9SClaudio Imbrenda 		};
2855a74e3d9SClaudio Imbrenda 	} tok;
2865a74e3d9SClaudio Imbrenda 	union pmd pmd;
2875a74e3d9SClaudio Imbrenda 	union pud pud;
2885a74e3d9SClaudio Imbrenda 	union p4d p4d;
2895a74e3d9SClaudio Imbrenda 	union pgd pgd;
2905a74e3d9SClaudio Imbrenda };
2915a74e3d9SClaudio Imbrenda 
2925a74e3d9SClaudio Imbrenda union skey {
2935a74e3d9SClaudio Imbrenda 	unsigned char skey;
2945a74e3d9SClaudio Imbrenda 	struct {
2955a74e3d9SClaudio Imbrenda 		unsigned char acc :4;
2965a74e3d9SClaudio Imbrenda 		unsigned char fp  :1;
2975a74e3d9SClaudio Imbrenda 		unsigned char r   :1;
2985a74e3d9SClaudio Imbrenda 		unsigned char c   :1;
2995a74e3d9SClaudio Imbrenda 		unsigned char zero:1;
3005a74e3d9SClaudio Imbrenda 	};
3015a74e3d9SClaudio Imbrenda };
3025a74e3d9SClaudio Imbrenda 
3035a74e3d9SClaudio Imbrenda static_assert(sizeof(union pgste) == sizeof(unsigned long));
3045a74e3d9SClaudio Imbrenda static_assert(sizeof(union pte) == sizeof(unsigned long));
3055a74e3d9SClaudio Imbrenda static_assert(sizeof(union pmd) == sizeof(unsigned long));
3065a74e3d9SClaudio Imbrenda static_assert(sizeof(union pud) == sizeof(unsigned long));
3075a74e3d9SClaudio Imbrenda static_assert(sizeof(union p4d) == sizeof(unsigned long));
3085a74e3d9SClaudio Imbrenda static_assert(sizeof(union pgd) == sizeof(unsigned long));
3095a74e3d9SClaudio Imbrenda static_assert(sizeof(union crste) == sizeof(unsigned long));
3105a74e3d9SClaudio Imbrenda static_assert(sizeof(union skey) == sizeof(char));
3115a74e3d9SClaudio Imbrenda 
3125a74e3d9SClaudio Imbrenda struct segment_table {
3135a74e3d9SClaudio Imbrenda 	union pmd pmds[_CRST_ENTRIES];
3145a74e3d9SClaudio Imbrenda };
3155a74e3d9SClaudio Imbrenda 
3165a74e3d9SClaudio Imbrenda struct region3_table {
3175a74e3d9SClaudio Imbrenda 	union pud puds[_CRST_ENTRIES];
3185a74e3d9SClaudio Imbrenda };
3195a74e3d9SClaudio Imbrenda 
3205a74e3d9SClaudio Imbrenda struct region2_table {
3215a74e3d9SClaudio Imbrenda 	union p4d p4ds[_CRST_ENTRIES];
3225a74e3d9SClaudio Imbrenda };
3235a74e3d9SClaudio Imbrenda 
3245a74e3d9SClaudio Imbrenda struct region1_table {
3255a74e3d9SClaudio Imbrenda 	union pgd pgds[_CRST_ENTRIES];
3265a74e3d9SClaudio Imbrenda };
3275a74e3d9SClaudio Imbrenda 
3285a74e3d9SClaudio Imbrenda struct crst_table {
3295a74e3d9SClaudio Imbrenda 	union {
3305a74e3d9SClaudio Imbrenda 		union crste crstes[_CRST_ENTRIES];
3315a74e3d9SClaudio Imbrenda 		struct segment_table segment;
3325a74e3d9SClaudio Imbrenda 		struct region3_table region3;
3335a74e3d9SClaudio Imbrenda 		struct region2_table region2;
3345a74e3d9SClaudio Imbrenda 		struct region1_table region1;
3355a74e3d9SClaudio Imbrenda 	};
3365a74e3d9SClaudio Imbrenda };
3375a74e3d9SClaudio Imbrenda 
3385a74e3d9SClaudio Imbrenda struct page_table {
3395a74e3d9SClaudio Imbrenda 	union pte ptes[_PAGE_ENTRIES];
3405a74e3d9SClaudio Imbrenda 	union pgste pgstes[_PAGE_ENTRIES];
3415a74e3d9SClaudio Imbrenda };
3425a74e3d9SClaudio Imbrenda 
3435a74e3d9SClaudio Imbrenda static_assert(sizeof(struct crst_table) == _CRST_TABLE_SIZE);
3445a74e3d9SClaudio Imbrenda static_assert(sizeof(struct page_table) == PAGE_SIZE);
3455a74e3d9SClaudio Imbrenda 
3462db149a0SClaudio Imbrenda struct dat_walk;
3472db149a0SClaudio Imbrenda 
3482db149a0SClaudio Imbrenda typedef long (*dat_walk_op)(union crste *crste, gfn_t gfn, gfn_t next, struct dat_walk *w);
3492db149a0SClaudio Imbrenda 
3502db149a0SClaudio Imbrenda struct dat_walk_ops {
3512db149a0SClaudio Imbrenda 	union {
3522db149a0SClaudio Imbrenda 		dat_walk_op crste_ops[4];
3532db149a0SClaudio Imbrenda 		struct {
3542db149a0SClaudio Imbrenda 			dat_walk_op pmd_entry;
3552db149a0SClaudio Imbrenda 			dat_walk_op pud_entry;
3562db149a0SClaudio Imbrenda 			dat_walk_op p4d_entry;
3572db149a0SClaudio Imbrenda 			dat_walk_op pgd_entry;
3582db149a0SClaudio Imbrenda 		};
3592db149a0SClaudio Imbrenda 	};
3602db149a0SClaudio Imbrenda 	long (*pte_entry)(union pte *pte, gfn_t gfn, gfn_t next, struct dat_walk *w);
3612db149a0SClaudio Imbrenda };
3622db149a0SClaudio Imbrenda 
3632db149a0SClaudio Imbrenda struct dat_walk {
3642db149a0SClaudio Imbrenda 	const struct dat_walk_ops *ops;
3652db149a0SClaudio Imbrenda 	union crste *last;
3662db149a0SClaudio Imbrenda 	union pte *last_pte;
3672db149a0SClaudio Imbrenda 	union asce asce;
3682db149a0SClaudio Imbrenda 	gfn_t start;
3692db149a0SClaudio Imbrenda 	gfn_t end;
3702db149a0SClaudio Imbrenda 	int flags;
3712db149a0SClaudio Imbrenda 	void *priv;
3722db149a0SClaudio Imbrenda };
3732db149a0SClaudio Imbrenda 
37494fd9b16SClaudio Imbrenda struct ptval_param {
37594fd9b16SClaudio Imbrenda 	unsigned char offset : 6;
37694fd9b16SClaudio Imbrenda 	unsigned char len : 2;
37794fd9b16SClaudio Imbrenda };
37894fd9b16SClaudio Imbrenda 
3795a74e3d9SClaudio Imbrenda /**
3805a74e3d9SClaudio Imbrenda  * _pte() - Useful constructor for union pte
3815a74e3d9SClaudio Imbrenda  * @pfn: the pfn this pte should point to.
3825a74e3d9SClaudio Imbrenda  * @writable: whether the pte should be writable.
3835a74e3d9SClaudio Imbrenda  * @dirty: whether the pte should be dirty.
3845a74e3d9SClaudio Imbrenda  * @special: whether the pte should be marked as special
3855a74e3d9SClaudio Imbrenda  *
3865a74e3d9SClaudio Imbrenda  * The pte is also marked as young and present. If the pte is marked as dirty,
3875a74e3d9SClaudio Imbrenda  * it gets marked as soft-dirty too. If the pte is not dirty, the hardware
3885a74e3d9SClaudio Imbrenda  * protect bit is set (independently of the write softbit); this way proper
3895a74e3d9SClaudio Imbrenda  * dirty tracking can be performed.
3905a74e3d9SClaudio Imbrenda  *
3915a74e3d9SClaudio Imbrenda  * Return: a union pte value.
3925a74e3d9SClaudio Imbrenda  */
_pte(kvm_pfn_t pfn,bool writable,bool dirty,bool special)3935a74e3d9SClaudio Imbrenda static inline union pte _pte(kvm_pfn_t pfn, bool writable, bool dirty, bool special)
3945a74e3d9SClaudio Imbrenda {
3955a74e3d9SClaudio Imbrenda 	union pte res = { .val = PFN_PHYS(pfn) };
3965a74e3d9SClaudio Imbrenda 
3975a74e3d9SClaudio Imbrenda 	res.h.p = !dirty;
3985a74e3d9SClaudio Imbrenda 	res.s.y = 1;
3995a74e3d9SClaudio Imbrenda 	res.s.pr = 1;
4005a74e3d9SClaudio Imbrenda 	res.s.w = writable;
4015a74e3d9SClaudio Imbrenda 	res.s.d = dirty;
4025a74e3d9SClaudio Imbrenda 	res.s.sd = dirty;
4035a74e3d9SClaudio Imbrenda 	res.s.s = special;
4045a74e3d9SClaudio Imbrenda 	return res;
4055a74e3d9SClaudio Imbrenda }
4065a74e3d9SClaudio Imbrenda 
_crste_fc0(kvm_pfn_t pfn,int tt)4075a74e3d9SClaudio Imbrenda static inline union crste _crste_fc0(kvm_pfn_t pfn, int tt)
4085a74e3d9SClaudio Imbrenda {
4095a74e3d9SClaudio Imbrenda 	union crste res = { .val = PFN_PHYS(pfn) };
4105a74e3d9SClaudio Imbrenda 
4115a74e3d9SClaudio Imbrenda 	res.h.tt = tt;
4125a74e3d9SClaudio Imbrenda 	res.h.fc0.tl = _REGION_ENTRY_LENGTH;
4135a74e3d9SClaudio Imbrenda 	res.h.fc0.tf = 0;
4145a74e3d9SClaudio Imbrenda 	return res;
4155a74e3d9SClaudio Imbrenda }
4165a74e3d9SClaudio Imbrenda 
4175a74e3d9SClaudio Imbrenda /**
4185a74e3d9SClaudio Imbrenda  * _crste() - Useful constructor for union crste with FC=1
4195a74e3d9SClaudio Imbrenda  * @pfn: the pfn this pte should point to.
4205a74e3d9SClaudio Imbrenda  * @tt: the table type
4215a74e3d9SClaudio Imbrenda  * @writable: whether the pte should be writable.
4225a74e3d9SClaudio Imbrenda  * @dirty: whether the pte should be dirty.
4235a74e3d9SClaudio Imbrenda  *
4245a74e3d9SClaudio Imbrenda  * The crste is also marked as young and present. If the crste is marked as
4255a74e3d9SClaudio Imbrenda  * dirty, it gets marked as soft-dirty too. If the crste is not dirty, the
4265a74e3d9SClaudio Imbrenda  * hardware protect bit is set (independently of the write softbit); this way
4275a74e3d9SClaudio Imbrenda  * proper dirty tracking can be performed.
4285a74e3d9SClaudio Imbrenda  *
4295a74e3d9SClaudio Imbrenda  * Return: a union crste value.
4305a74e3d9SClaudio Imbrenda  */
_crste_fc1(kvm_pfn_t pfn,int tt,bool writable,bool dirty)4315a74e3d9SClaudio Imbrenda static inline union crste _crste_fc1(kvm_pfn_t pfn, int tt, bool writable, bool dirty)
4325a74e3d9SClaudio Imbrenda {
4335a74e3d9SClaudio Imbrenda 	union crste res = { .val = PFN_PHYS(pfn) & _SEGMENT_MASK };
4345a74e3d9SClaudio Imbrenda 
4355a74e3d9SClaudio Imbrenda 	res.h.tt = tt;
4365a74e3d9SClaudio Imbrenda 	res.h.p = !dirty;
4375a74e3d9SClaudio Imbrenda 	res.h.fc = 1;
4385a74e3d9SClaudio Imbrenda 	res.s.fc1.y = 1;
4395a74e3d9SClaudio Imbrenda 	res.s.fc1.pr = 1;
4405a74e3d9SClaudio Imbrenda 	res.s.fc1.w = writable;
4415a74e3d9SClaudio Imbrenda 	res.s.fc1.d = dirty;
4425a74e3d9SClaudio Imbrenda 	res.s.fc1.sd = dirty;
4435a74e3d9SClaudio Imbrenda 	return res;
4445a74e3d9SClaudio Imbrenda }
4455a74e3d9SClaudio Imbrenda 
4467b368470SClaudio Imbrenda union essa_state {
4477b368470SClaudio Imbrenda 	unsigned char val;
4487b368470SClaudio Imbrenda 	struct {
4497b368470SClaudio Imbrenda 		unsigned char		: 2;
4507b368470SClaudio Imbrenda 		unsigned char nodat	: 1;
4517b368470SClaudio Imbrenda 		unsigned char exception	: 1;
4527b368470SClaudio Imbrenda 		unsigned char usage	: 2;
4537b368470SClaudio Imbrenda 		unsigned char content	: 2;
4547b368470SClaudio Imbrenda 	};
4557b368470SClaudio Imbrenda };
4567b368470SClaudio Imbrenda 
4575a74e3d9SClaudio Imbrenda /**
4585a74e3d9SClaudio Imbrenda  * struct vsie_rmap - reverse mapping for shadow page table entries
4595a74e3d9SClaudio Imbrenda  * @next: pointer to next rmap in the list
4605a74e3d9SClaudio Imbrenda  * @r_gfn: virtual rmap address in the shadow guest address space
4615a74e3d9SClaudio Imbrenda  */
4625a74e3d9SClaudio Imbrenda struct vsie_rmap {
4635a74e3d9SClaudio Imbrenda 	struct vsie_rmap *next;
4645a74e3d9SClaudio Imbrenda 	union {
4655a74e3d9SClaudio Imbrenda 		unsigned long val;
4665a74e3d9SClaudio Imbrenda 		struct {
4675a74e3d9SClaudio Imbrenda 			long          level: 8;
4685a74e3d9SClaudio Imbrenda 			unsigned long      : 4;
4695a74e3d9SClaudio Imbrenda 			unsigned long r_gfn:52;
4705a74e3d9SClaudio Imbrenda 		};
4715a74e3d9SClaudio Imbrenda 	};
4725a74e3d9SClaudio Imbrenda };
4735a74e3d9SClaudio Imbrenda 
4745a74e3d9SClaudio Imbrenda static_assert(sizeof(struct vsie_rmap) == 2 * sizeof(long));
4755a74e3d9SClaudio Imbrenda 
47612f2f61aSClaudio Imbrenda #define KVM_S390_MMU_CACHE_N_CRSTS	6
47712f2f61aSClaudio Imbrenda #define KVM_S390_MMU_CACHE_N_PTS	2
47812f2f61aSClaudio Imbrenda #define KVM_S390_MMU_CACHE_N_RMAPS	16
47912f2f61aSClaudio Imbrenda struct kvm_s390_mmu_cache {
48012f2f61aSClaudio Imbrenda 	void *crsts[KVM_S390_MMU_CACHE_N_CRSTS];
48112f2f61aSClaudio Imbrenda 	void *pts[KVM_S390_MMU_CACHE_N_PTS];
48212f2f61aSClaudio Imbrenda 	void *rmaps[KVM_S390_MMU_CACHE_N_RMAPS];
48312f2f61aSClaudio Imbrenda 	short int n_crsts;
48412f2f61aSClaudio Imbrenda 	short int n_pts;
48512f2f61aSClaudio Imbrenda 	short int n_rmaps;
48612f2f61aSClaudio Imbrenda };
48712f2f61aSClaudio Imbrenda 
48894fd9b16SClaudio Imbrenda struct guest_fault {
48994fd9b16SClaudio Imbrenda 	gfn_t gfn;		/* Guest frame */
49094fd9b16SClaudio Imbrenda 	kvm_pfn_t pfn;		/* Host PFN */
49194fd9b16SClaudio Imbrenda 	struct page *page;	/* Host page */
49294fd9b16SClaudio Imbrenda 	union pte *ptep;	/* Used to resolve the fault, or NULL */
49394fd9b16SClaudio Imbrenda 	union crste *crstep;	/* Used to resolve the fault, or NULL */
49494fd9b16SClaudio Imbrenda 	bool writable;		/* Mapping is writable */
49594fd9b16SClaudio Imbrenda 	bool write_attempt;	/* Write access attempted */
49694fd9b16SClaudio Imbrenda 	bool attempt_pfault;	/* Attempt a pfault first */
49794fd9b16SClaudio Imbrenda 	bool valid;		/* This entry contains valid data */
49894fd9b16SClaudio Imbrenda 	void (*callback)(struct guest_fault *f);
49994fd9b16SClaudio Imbrenda 	void *priv;
50094fd9b16SClaudio Imbrenda };
50194fd9b16SClaudio Imbrenda 
50294fd9b16SClaudio Imbrenda /*
50394fd9b16SClaudio Imbrenda  *	0	1	2	3	4	5	6	7
50494fd9b16SClaudio Imbrenda  *	+-------+-------+-------+-------+-------+-------+-------+-------+
50594fd9b16SClaudio Imbrenda  *  0	|				|	    PGT_ADDR		|
50694fd9b16SClaudio Imbrenda  *  8	|	 VMADDR		|					|
50794fd9b16SClaudio Imbrenda  * 16	|								|
50894fd9b16SClaudio Imbrenda  * 24	|								|
50994fd9b16SClaudio Imbrenda  */
51094fd9b16SClaudio Imbrenda #define MKPTVAL(o, l) ((struct ptval_param) { .offset = (o), .len = ((l) + 1) / 2 - 1})
51194fd9b16SClaudio Imbrenda #define PTVAL_PGT_ADDR	MKPTVAL(4, 8)
51294fd9b16SClaudio Imbrenda #define PTVAL_VMADDR	MKPTVAL(8, 6)
51394fd9b16SClaudio Imbrenda 
514589071eaSClaudio Imbrenda union pgste __must_check __dat_ptep_xchg(union pte *ptep, union pgste pgste, union pte new,
515589071eaSClaudio Imbrenda 					 gfn_t gfn, union asce asce, bool uses_skeys);
516589071eaSClaudio Imbrenda bool dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new, gfn_t gfn,
517589071eaSClaudio Imbrenda 			    union asce asce);
518589071eaSClaudio Imbrenda void dat_crstep_xchg(union crste *crstep, union crste new, gfn_t gfn, union asce asce);
519589071eaSClaudio Imbrenda 
5202db149a0SClaudio Imbrenda long _dat_walk_gfn_range(gfn_t start, gfn_t end, union asce asce,
5212db149a0SClaudio Imbrenda 			 const struct dat_walk_ops *ops, int flags, void *priv);
5222db149a0SClaudio Imbrenda 
5232db149a0SClaudio Imbrenda int dat_entry_walk(struct kvm_s390_mmu_cache *mc, gfn_t gfn, union asce asce, int flags,
5242db149a0SClaudio Imbrenda 		   int walk_level, union crste **last, union pte **ptepp);
52512f2f61aSClaudio Imbrenda void dat_free_level(struct crst_table *table, bool owns_ptes);
52612f2f61aSClaudio Imbrenda struct crst_table *dat_alloc_crst_sleepable(unsigned long init);
52794fd9b16SClaudio Imbrenda int dat_set_asce_limit(struct kvm_s390_mmu_cache *mc, union asce *asce, int newtype);
5288e03e831SClaudio Imbrenda int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey);
5298e03e831SClaudio Imbrenda int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
5308e03e831SClaudio Imbrenda 			union skey skey, bool nq);
5318e03e831SClaudio Imbrenda int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
5328e03e831SClaudio Imbrenda 			     union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);
5338e03e831SClaudio Imbrenda int dat_reset_reference_bit(union asce asce, gfn_t gfn);
5348e03e831SClaudio Imbrenda long dat_reset_skeys(union asce asce, gfn_t start);
53512f2f61aSClaudio Imbrenda 
53694fd9b16SClaudio Imbrenda unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);
53794fd9b16SClaudio Imbrenda void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val);
53894fd9b16SClaudio Imbrenda 
53994fd9b16SClaudio Imbrenda int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end,
54094fd9b16SClaudio Imbrenda 		 u16 type, u16 param);
54194fd9b16SClaudio Imbrenda int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
54294fd9b16SClaudio Imbrenda bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end);
54394fd9b16SClaudio Imbrenda int dat_link(struct kvm_s390_mmu_cache *mc, union asce asce, int level,
54494fd9b16SClaudio Imbrenda 	     bool uses_skeys, struct guest_fault *f);
54594fd9b16SClaudio Imbrenda 
5467b368470SClaudio Imbrenda int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);
5477b368470SClaudio Imbrenda long dat_reset_cmma(union asce asce, gfn_t start_gfn);
5487b368470SClaudio Imbrenda int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values);
5497b368470SClaudio Imbrenda int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem);
5507b368470SClaudio Imbrenda int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
5517b368470SClaudio Imbrenda 		      unsigned long count, unsigned long mask, const uint8_t *bits);
5527b368470SClaudio Imbrenda 
55312f2f61aSClaudio Imbrenda int kvm_s390_mmu_cache_topup(struct kvm_s390_mmu_cache *mc);
55412f2f61aSClaudio Imbrenda 
55512f2f61aSClaudio Imbrenda #define GFP_KVM_S390_MMU_CACHE (GFP_ATOMIC | __GFP_ACCOUNT | __GFP_NOWARN)
55612f2f61aSClaudio Imbrenda 
kvm_s390_mmu_cache_alloc_pt(struct kvm_s390_mmu_cache * mc)55712f2f61aSClaudio Imbrenda static inline struct page_table *kvm_s390_mmu_cache_alloc_pt(struct kvm_s390_mmu_cache *mc)
55812f2f61aSClaudio Imbrenda {
55912f2f61aSClaudio Imbrenda 	if (mc->n_pts)
56012f2f61aSClaudio Imbrenda 		return mc->pts[--mc->n_pts];
56112f2f61aSClaudio Imbrenda 	return (void *)__get_free_page(GFP_KVM_S390_MMU_CACHE);
56212f2f61aSClaudio Imbrenda }
56312f2f61aSClaudio Imbrenda 
kvm_s390_mmu_cache_alloc_crst(struct kvm_s390_mmu_cache * mc)56412f2f61aSClaudio Imbrenda static inline struct crst_table *kvm_s390_mmu_cache_alloc_crst(struct kvm_s390_mmu_cache *mc)
56512f2f61aSClaudio Imbrenda {
56612f2f61aSClaudio Imbrenda 	if (mc->n_crsts)
56712f2f61aSClaudio Imbrenda 		return mc->crsts[--mc->n_crsts];
56812f2f61aSClaudio Imbrenda 	return (void *)__get_free_pages(GFP_KVM_S390_MMU_CACHE | __GFP_COMP, CRST_ALLOC_ORDER);
56912f2f61aSClaudio Imbrenda }
57012f2f61aSClaudio Imbrenda 
kvm_s390_mmu_cache_alloc_rmap(struct kvm_s390_mmu_cache * mc)57112f2f61aSClaudio Imbrenda static inline struct vsie_rmap *kvm_s390_mmu_cache_alloc_rmap(struct kvm_s390_mmu_cache *mc)
57212f2f61aSClaudio Imbrenda {
57312f2f61aSClaudio Imbrenda 	if (mc->n_rmaps)
57412f2f61aSClaudio Imbrenda 		return mc->rmaps[--mc->n_rmaps];
575*69050f8dSKees Cook 	return kzalloc_obj(struct vsie_rmap, GFP_KVM_S390_MMU_CACHE);
57612f2f61aSClaudio Imbrenda }
57712f2f61aSClaudio Imbrenda 
crste_table_start(union crste * crstep)5785a74e3d9SClaudio Imbrenda static inline struct crst_table *crste_table_start(union crste *crstep)
5795a74e3d9SClaudio Imbrenda {
5805a74e3d9SClaudio Imbrenda 	return (struct crst_table *)ALIGN_DOWN((unsigned long)crstep, _CRST_TABLE_SIZE);
5815a74e3d9SClaudio Imbrenda }
5825a74e3d9SClaudio Imbrenda 
pte_table_start(union pte * ptep)5835a74e3d9SClaudio Imbrenda static inline struct page_table *pte_table_start(union pte *ptep)
5845a74e3d9SClaudio Imbrenda {
5855a74e3d9SClaudio Imbrenda 	return (struct page_table *)ALIGN_DOWN((unsigned long)ptep, _PAGE_TABLE_SIZE);
5865a74e3d9SClaudio Imbrenda }
5875a74e3d9SClaudio Imbrenda 
crdte_crste(union crste * crstep,union crste old,union crste new,gfn_t gfn,union asce asce)5885a74e3d9SClaudio Imbrenda static inline bool crdte_crste(union crste *crstep, union crste old, union crste new, gfn_t gfn,
5895a74e3d9SClaudio Imbrenda 			       union asce asce)
5905a74e3d9SClaudio Imbrenda {
5915a74e3d9SClaudio Imbrenda 	unsigned long dtt = 0x10 | new.h.tt << 2;
5925a74e3d9SClaudio Imbrenda 	void *table = crste_table_start(crstep);
5935a74e3d9SClaudio Imbrenda 
5945a74e3d9SClaudio Imbrenda 	return crdte(old.val, new.val, table, dtt, gfn_to_gpa(gfn), asce.val);
5955a74e3d9SClaudio Imbrenda }
5965a74e3d9SClaudio Imbrenda 
5975a74e3d9SClaudio Imbrenda /**
5985a74e3d9SClaudio Imbrenda  * idte_crste() - invalidate a crste entry using idte
5995a74e3d9SClaudio Imbrenda  * @crstep: pointer to the crste to be invalidated
6005a74e3d9SClaudio Imbrenda  * @gfn: a gfn mapped by the crste
6015a74e3d9SClaudio Imbrenda  * @opt: options for the idte instruction
6025a74e3d9SClaudio Imbrenda  * @asce: the asce
6035a74e3d9SClaudio Imbrenda  * @local: whether the operation is cpu-local
6045a74e3d9SClaudio Imbrenda  */
idte_crste(union crste * crstep,gfn_t gfn,unsigned long opt,union asce asce,int local)6055a74e3d9SClaudio Imbrenda static __always_inline void idte_crste(union crste *crstep, gfn_t gfn, unsigned long opt,
6065a74e3d9SClaudio Imbrenda 				       union asce asce, int local)
6075a74e3d9SClaudio Imbrenda {
6085a74e3d9SClaudio Imbrenda 	unsigned long table_origin = __pa(crste_table_start(crstep));
6095a74e3d9SClaudio Imbrenda 	unsigned long gaddr = gfn_to_gpa(gfn) & HPAGE_MASK;
6105a74e3d9SClaudio Imbrenda 
6115a74e3d9SClaudio Imbrenda 	if (__builtin_constant_p(opt) && opt == 0) {
6125a74e3d9SClaudio Imbrenda 		/* flush without guest asce */
6135a74e3d9SClaudio Imbrenda 		asm volatile("idte	%[table_origin],0,%[gaddr],%[local]"
6145a74e3d9SClaudio Imbrenda 			: "+m" (*crstep)
6155a74e3d9SClaudio Imbrenda 			: [table_origin] "a" (table_origin), [gaddr] "a" (gaddr),
6165a74e3d9SClaudio Imbrenda 			  [local] "i" (local)
6175a74e3d9SClaudio Imbrenda 			: "cc");
6185a74e3d9SClaudio Imbrenda 	} else {
6195a74e3d9SClaudio Imbrenda 		/* flush with guest asce */
6205a74e3d9SClaudio Imbrenda 		asm volatile("idte %[table_origin],%[asce],%[gaddr_opt],%[local]"
6215a74e3d9SClaudio Imbrenda 			: "+m" (*crstep)
6225a74e3d9SClaudio Imbrenda 			: [table_origin] "a" (table_origin), [gaddr_opt] "a" (gaddr | opt),
6235a74e3d9SClaudio Imbrenda 			  [asce] "a" (asce.val), [local] "i" (local)
6245a74e3d9SClaudio Imbrenda 			: "cc");
6255a74e3d9SClaudio Imbrenda 	}
6265a74e3d9SClaudio Imbrenda }
6275a74e3d9SClaudio Imbrenda 
dat_init_pgstes(struct page_table * pt,unsigned long val)6285a74e3d9SClaudio Imbrenda static inline void dat_init_pgstes(struct page_table *pt, unsigned long val)
6295a74e3d9SClaudio Imbrenda {
6305a74e3d9SClaudio Imbrenda 	memset64((void *)pt->pgstes, val, PTRS_PER_PTE);
6315a74e3d9SClaudio Imbrenda }
6325a74e3d9SClaudio Imbrenda 
dat_init_page_table(struct page_table * pt,unsigned long ptes,unsigned long pgstes)6335a74e3d9SClaudio Imbrenda static inline void dat_init_page_table(struct page_table *pt, unsigned long ptes,
6345a74e3d9SClaudio Imbrenda 				       unsigned long pgstes)
6355a74e3d9SClaudio Imbrenda {
6365a74e3d9SClaudio Imbrenda 	memset64((void *)pt->ptes, ptes, PTRS_PER_PTE);
6375a74e3d9SClaudio Imbrenda 	dat_init_pgstes(pt, pgstes);
6385a74e3d9SClaudio Imbrenda }
6395a74e3d9SClaudio Imbrenda 
asce_end(union asce asce)6405a74e3d9SClaudio Imbrenda static inline gfn_t asce_end(union asce asce)
6415a74e3d9SClaudio Imbrenda {
6425a74e3d9SClaudio Imbrenda 	return 1ULL << ((asce.dt + 1) * 11 + _SEGMENT_SHIFT - PAGE_SHIFT);
6435a74e3d9SClaudio Imbrenda }
6445a74e3d9SClaudio Imbrenda 
6455a74e3d9SClaudio Imbrenda #define _CRSTE(x) ((union crste) { .val = _Generic((x),	\
6465a74e3d9SClaudio Imbrenda 			union pgd : (x).val,		\
6475a74e3d9SClaudio Imbrenda 			union p4d : (x).val,		\
6485a74e3d9SClaudio Imbrenda 			union pud : (x).val,		\
6495a74e3d9SClaudio Imbrenda 			union pmd : (x).val,		\
6505a74e3d9SClaudio Imbrenda 			union crste : (x).val)})
6515a74e3d9SClaudio Imbrenda 
6525a74e3d9SClaudio Imbrenda #define _CRSTEP(x) ((union crste *)_Generic((*(x)),	\
6535a74e3d9SClaudio Imbrenda 				union pgd : (x),	\
6545a74e3d9SClaudio Imbrenda 				union p4d : (x),	\
6555a74e3d9SClaudio Imbrenda 				union pud : (x),	\
6565a74e3d9SClaudio Imbrenda 				union pmd : (x),	\
6575a74e3d9SClaudio Imbrenda 				union crste : (x)))
6585a74e3d9SClaudio Imbrenda 
6595a74e3d9SClaudio Imbrenda #define _CRSTP(x) ((struct crst_table *)_Generic((*(x)),	\
6605a74e3d9SClaudio Imbrenda 		struct crst_table : (x),			\
6615a74e3d9SClaudio Imbrenda 		struct segment_table : (x),			\
6625a74e3d9SClaudio Imbrenda 		struct region3_table : (x),			\
6635a74e3d9SClaudio Imbrenda 		struct region2_table : (x),			\
6645a74e3d9SClaudio Imbrenda 		struct region1_table : (x)))
6655a74e3d9SClaudio Imbrenda 
asce_contains_gfn(union asce asce,gfn_t gfn)6665a74e3d9SClaudio Imbrenda static inline bool asce_contains_gfn(union asce asce, gfn_t gfn)
6675a74e3d9SClaudio Imbrenda {
6685a74e3d9SClaudio Imbrenda 	return gfn < asce_end(asce);
6695a74e3d9SClaudio Imbrenda }
6705a74e3d9SClaudio Imbrenda 
is_pmd(union crste crste)6715a74e3d9SClaudio Imbrenda static inline bool is_pmd(union crste crste)
6725a74e3d9SClaudio Imbrenda {
6735a74e3d9SClaudio Imbrenda 	return crste.h.tt == TABLE_TYPE_SEGMENT;
6745a74e3d9SClaudio Imbrenda }
6755a74e3d9SClaudio Imbrenda 
is_pud(union crste crste)6765a74e3d9SClaudio Imbrenda static inline bool is_pud(union crste crste)
6775a74e3d9SClaudio Imbrenda {
6785a74e3d9SClaudio Imbrenda 	return crste.h.tt == TABLE_TYPE_REGION3;
6795a74e3d9SClaudio Imbrenda }
6805a74e3d9SClaudio Imbrenda 
is_p4d(union crste crste)6815a74e3d9SClaudio Imbrenda static inline bool is_p4d(union crste crste)
6825a74e3d9SClaudio Imbrenda {
6835a74e3d9SClaudio Imbrenda 	return crste.h.tt == TABLE_TYPE_REGION2;
6845a74e3d9SClaudio Imbrenda }
6855a74e3d9SClaudio Imbrenda 
is_pgd(union crste crste)6865a74e3d9SClaudio Imbrenda static inline bool is_pgd(union crste crste)
6875a74e3d9SClaudio Imbrenda {
6885a74e3d9SClaudio Imbrenda 	return crste.h.tt == TABLE_TYPE_REGION1;
6895a74e3d9SClaudio Imbrenda }
6905a74e3d9SClaudio Imbrenda 
pmd_origin_large(union pmd pmd)6915a74e3d9SClaudio Imbrenda static inline phys_addr_t pmd_origin_large(union pmd pmd)
6925a74e3d9SClaudio Imbrenda {
6935a74e3d9SClaudio Imbrenda 	return pmd.val & _SEGMENT_ENTRY_ORIGIN_LARGE;
6945a74e3d9SClaudio Imbrenda }
6955a74e3d9SClaudio Imbrenda 
pud_origin_large(union pud pud)6965a74e3d9SClaudio Imbrenda static inline phys_addr_t pud_origin_large(union pud pud)
6975a74e3d9SClaudio Imbrenda {
6985a74e3d9SClaudio Imbrenda 	return pud.val & _REGION3_ENTRY_ORIGIN_LARGE;
6995a74e3d9SClaudio Imbrenda }
7005a74e3d9SClaudio Imbrenda 
7015a74e3d9SClaudio Imbrenda /**
7025a74e3d9SClaudio Imbrenda  * crste_origin_large() - Return the large frame origin of a large crste
7035a74e3d9SClaudio Imbrenda  * @crste: The crste whose origin is to be returned. Should be either a
7045a74e3d9SClaudio Imbrenda  *         region-3 table entry or a segment table entry, in both cases with
7055a74e3d9SClaudio Imbrenda  *         FC set to 1 (large pages).
7065a74e3d9SClaudio Imbrenda  *
7075a74e3d9SClaudio Imbrenda  * Return: The origin of the large frame pointed to by @crste, or -1 if the
7085a74e3d9SClaudio Imbrenda  *         crste was not large (wrong table type, or FC==0)
7095a74e3d9SClaudio Imbrenda  */
crste_origin_large(union crste crste)7105a74e3d9SClaudio Imbrenda static inline phys_addr_t crste_origin_large(union crste crste)
7115a74e3d9SClaudio Imbrenda {
7125a74e3d9SClaudio Imbrenda 	if (unlikely(!crste.h.fc || crste.h.tt > TABLE_TYPE_REGION3))
7135a74e3d9SClaudio Imbrenda 		return -1;
7145a74e3d9SClaudio Imbrenda 	if (is_pmd(crste))
7155a74e3d9SClaudio Imbrenda 		return pmd_origin_large(crste.pmd);
7165a74e3d9SClaudio Imbrenda 	return pud_origin_large(crste.pud);
7175a74e3d9SClaudio Imbrenda }
7185a74e3d9SClaudio Imbrenda 
7195a74e3d9SClaudio Imbrenda #define crste_origin(x) (_Generic((x),				\
7205a74e3d9SClaudio Imbrenda 		union pmd : (x).val & _SEGMENT_ENTRY_ORIGIN,	\
7215a74e3d9SClaudio Imbrenda 		union pud : (x).val & _REGION_ENTRY_ORIGIN,	\
7225a74e3d9SClaudio Imbrenda 		union p4d : (x).val & _REGION_ENTRY_ORIGIN,	\
7235a74e3d9SClaudio Imbrenda 		union pgd : (x).val & _REGION_ENTRY_ORIGIN))
7245a74e3d9SClaudio Imbrenda 
pte_origin(union pte pte)7255a74e3d9SClaudio Imbrenda static inline unsigned long pte_origin(union pte pte)
7265a74e3d9SClaudio Imbrenda {
7275a74e3d9SClaudio Imbrenda 	return pte.val & PAGE_MASK;
7285a74e3d9SClaudio Imbrenda }
7295a74e3d9SClaudio Imbrenda 
pmd_prefix(union pmd pmd)7305a74e3d9SClaudio Imbrenda static inline bool pmd_prefix(union pmd pmd)
7315a74e3d9SClaudio Imbrenda {
7325a74e3d9SClaudio Imbrenda 	return pmd.h.fc && pmd.s.fc1.prefix_notif;
7335a74e3d9SClaudio Imbrenda }
7345a74e3d9SClaudio Imbrenda 
pud_prefix(union pud pud)7355a74e3d9SClaudio Imbrenda static inline bool pud_prefix(union pud pud)
7365a74e3d9SClaudio Imbrenda {
7375a74e3d9SClaudio Imbrenda 	return pud.h.fc && pud.s.fc1.prefix_notif;
7385a74e3d9SClaudio Imbrenda }
7395a74e3d9SClaudio Imbrenda 
crste_leaf(union crste crste)7405a74e3d9SClaudio Imbrenda static inline bool crste_leaf(union crste crste)
7415a74e3d9SClaudio Imbrenda {
7425a74e3d9SClaudio Imbrenda 	return (crste.h.tt <= TABLE_TYPE_REGION3) && crste.h.fc;
7435a74e3d9SClaudio Imbrenda }
7445a74e3d9SClaudio Imbrenda 
crste_prefix(union crste crste)7455a74e3d9SClaudio Imbrenda static inline bool crste_prefix(union crste crste)
7465a74e3d9SClaudio Imbrenda {
7475a74e3d9SClaudio Imbrenda 	return crste_leaf(crste) && crste.s.fc1.prefix_notif;
7485a74e3d9SClaudio Imbrenda }
7495a74e3d9SClaudio Imbrenda 
crste_dirty(union crste crste)7505a74e3d9SClaudio Imbrenda static inline bool crste_dirty(union crste crste)
7515a74e3d9SClaudio Imbrenda {
7525a74e3d9SClaudio Imbrenda 	return crste_leaf(crste) && crste.s.fc1.d;
7535a74e3d9SClaudio Imbrenda }
7545a74e3d9SClaudio Imbrenda 
pgste_of(union pte * pte)7555a74e3d9SClaudio Imbrenda static inline union pgste *pgste_of(union pte *pte)
7565a74e3d9SClaudio Imbrenda {
7575a74e3d9SClaudio Imbrenda 	return (union pgste *)(pte + _PAGE_ENTRIES);
7585a74e3d9SClaudio Imbrenda }
7595a74e3d9SClaudio Imbrenda 
pte_hole(union pte pte)7605a74e3d9SClaudio Imbrenda static inline bool pte_hole(union pte pte)
7615a74e3d9SClaudio Imbrenda {
7625a74e3d9SClaudio Imbrenda 	return pte.h.i && !pte.tok.pr && pte.tok.type != _DAT_TOKEN_NONE;
7635a74e3d9SClaudio Imbrenda }
7645a74e3d9SClaudio Imbrenda 
_crste_hole(union crste crste)7655a74e3d9SClaudio Imbrenda static inline bool _crste_hole(union crste crste)
7665a74e3d9SClaudio Imbrenda {
7675a74e3d9SClaudio Imbrenda 	return crste.h.i && !crste.tok.pr && crste.tok.type != _DAT_TOKEN_NONE;
7685a74e3d9SClaudio Imbrenda }
7695a74e3d9SClaudio Imbrenda 
7705a74e3d9SClaudio Imbrenda #define crste_hole(x) _crste_hole(_CRSTE(x))
7715a74e3d9SClaudio Imbrenda 
_crste_none(union crste crste)7725a74e3d9SClaudio Imbrenda static inline bool _crste_none(union crste crste)
7735a74e3d9SClaudio Imbrenda {
7745a74e3d9SClaudio Imbrenda 	return crste.h.i && !crste.tok.pr && crste.tok.type == _DAT_TOKEN_NONE;
7755a74e3d9SClaudio Imbrenda }
7765a74e3d9SClaudio Imbrenda 
7775a74e3d9SClaudio Imbrenda #define crste_none(x) _crste_none(_CRSTE(x))
7785a74e3d9SClaudio Imbrenda 
large_pud_to_phys(union pud pud,gfn_t gfn)7795a74e3d9SClaudio Imbrenda static inline phys_addr_t large_pud_to_phys(union pud pud, gfn_t gfn)
7805a74e3d9SClaudio Imbrenda {
7815a74e3d9SClaudio Imbrenda 	return pud_origin_large(pud) | (gfn_to_gpa(gfn) & ~_REGION3_MASK);
7825a74e3d9SClaudio Imbrenda }
7835a74e3d9SClaudio Imbrenda 
large_pmd_to_phys(union pmd pmd,gfn_t gfn)7845a74e3d9SClaudio Imbrenda static inline phys_addr_t large_pmd_to_phys(union pmd pmd, gfn_t gfn)
7855a74e3d9SClaudio Imbrenda {
7865a74e3d9SClaudio Imbrenda 	return pmd_origin_large(pmd) | (gfn_to_gpa(gfn) & ~_SEGMENT_MASK);
7875a74e3d9SClaudio Imbrenda }
7885a74e3d9SClaudio Imbrenda 
large_crste_to_phys(union crste crste,gfn_t gfn)7895a74e3d9SClaudio Imbrenda static inline phys_addr_t large_crste_to_phys(union crste crste, gfn_t gfn)
7905a74e3d9SClaudio Imbrenda {
7915a74e3d9SClaudio Imbrenda 	if (unlikely(!crste.h.fc || crste.h.tt > TABLE_TYPE_REGION3))
7925a74e3d9SClaudio Imbrenda 		return -1;
7935a74e3d9SClaudio Imbrenda 	if (is_pmd(crste))
7945a74e3d9SClaudio Imbrenda 		return large_pmd_to_phys(crste.pmd, gfn);
7955a74e3d9SClaudio Imbrenda 	return large_pud_to_phys(crste.pud, gfn);
7965a74e3d9SClaudio Imbrenda }
7975a74e3d9SClaudio Imbrenda 
cspg_crste(union crste * crstep,union crste old,union crste new)7985a74e3d9SClaudio Imbrenda static inline bool cspg_crste(union crste *crstep, union crste old, union crste new)
7995a74e3d9SClaudio Imbrenda {
8005a74e3d9SClaudio Imbrenda 	return cspg(&crstep->val, old.val, new.val);
8015a74e3d9SClaudio Imbrenda }
8025a74e3d9SClaudio Imbrenda 
dereference_pmd(union pmd pmd)8035a74e3d9SClaudio Imbrenda static inline struct page_table *dereference_pmd(union pmd pmd)
8045a74e3d9SClaudio Imbrenda {
8055a74e3d9SClaudio Imbrenda 	return phys_to_virt(crste_origin(pmd));
8065a74e3d9SClaudio Imbrenda }
8075a74e3d9SClaudio Imbrenda 
dereference_pud(union pud pud)8085a74e3d9SClaudio Imbrenda static inline struct segment_table *dereference_pud(union pud pud)
8095a74e3d9SClaudio Imbrenda {
8105a74e3d9SClaudio Imbrenda 	return phys_to_virt(crste_origin(pud));
8115a74e3d9SClaudio Imbrenda }
8125a74e3d9SClaudio Imbrenda 
dereference_p4d(union p4d p4d)8135a74e3d9SClaudio Imbrenda static inline struct region3_table *dereference_p4d(union p4d p4d)
8145a74e3d9SClaudio Imbrenda {
8155a74e3d9SClaudio Imbrenda 	return phys_to_virt(crste_origin(p4d));
8165a74e3d9SClaudio Imbrenda }
8175a74e3d9SClaudio Imbrenda 
dereference_pgd(union pgd pgd)8185a74e3d9SClaudio Imbrenda static inline struct region2_table *dereference_pgd(union pgd pgd)
8195a74e3d9SClaudio Imbrenda {
8205a74e3d9SClaudio Imbrenda 	return phys_to_virt(crste_origin(pgd));
8215a74e3d9SClaudio Imbrenda }
8225a74e3d9SClaudio Imbrenda 
_dereference_crste(union crste crste)8235a74e3d9SClaudio Imbrenda static inline struct crst_table *_dereference_crste(union crste crste)
8245a74e3d9SClaudio Imbrenda {
8255a74e3d9SClaudio Imbrenda 	if (unlikely(is_pmd(crste)))
8265a74e3d9SClaudio Imbrenda 		return NULL;
8275a74e3d9SClaudio Imbrenda 	return phys_to_virt(crste_origin(crste.pud));
8285a74e3d9SClaudio Imbrenda }
8295a74e3d9SClaudio Imbrenda 
8305a74e3d9SClaudio Imbrenda #define dereference_crste(x) (_Generic((x),			\
8315a74e3d9SClaudio Imbrenda 		union pud : _dereference_crste(_CRSTE(x)),	\
8325a74e3d9SClaudio Imbrenda 		union p4d : _dereference_crste(_CRSTE(x)),	\
8335a74e3d9SClaudio Imbrenda 		union pgd : _dereference_crste(_CRSTE(x)),	\
8345a74e3d9SClaudio Imbrenda 		union crste : _dereference_crste(_CRSTE(x))))
8355a74e3d9SClaudio Imbrenda 
dereference_asce(union asce asce)8365a74e3d9SClaudio Imbrenda static inline struct crst_table *dereference_asce(union asce asce)
8375a74e3d9SClaudio Imbrenda {
8385a74e3d9SClaudio Imbrenda 	return phys_to_virt(asce.val & _ASCE_ORIGIN);
8395a74e3d9SClaudio Imbrenda }
8405a74e3d9SClaudio Imbrenda 
asce_flush_tlb(union asce asce)8415a74e3d9SClaudio Imbrenda static inline void asce_flush_tlb(union asce asce)
8425a74e3d9SClaudio Imbrenda {
8435a74e3d9SClaudio Imbrenda 	__tlb_flush_idte(asce.val);
8445a74e3d9SClaudio Imbrenda }
8455a74e3d9SClaudio Imbrenda 
pgste_get_trylock(union pte * ptep,union pgste * res)8465a74e3d9SClaudio Imbrenda static inline bool pgste_get_trylock(union pte *ptep, union pgste *res)
8475a74e3d9SClaudio Imbrenda {
8485a74e3d9SClaudio Imbrenda 	union pgste *pgstep = pgste_of(ptep);
8495a74e3d9SClaudio Imbrenda 	union pgste old_pgste;
8505a74e3d9SClaudio Imbrenda 
8515a74e3d9SClaudio Imbrenda 	if (READ_ONCE(pgstep->val) & PGSTE_PCL_BIT)
8525a74e3d9SClaudio Imbrenda 		return false;
8535a74e3d9SClaudio Imbrenda 	old_pgste.val = __atomic64_or_barrier(PGSTE_PCL_BIT, &pgstep->val);
8545a74e3d9SClaudio Imbrenda 	if (old_pgste.pcl)
8555a74e3d9SClaudio Imbrenda 		return false;
8565a74e3d9SClaudio Imbrenda 	old_pgste.pcl = 1;
8575a74e3d9SClaudio Imbrenda 	*res = old_pgste;
8585a74e3d9SClaudio Imbrenda 	return true;
8595a74e3d9SClaudio Imbrenda }
8605a74e3d9SClaudio Imbrenda 
pgste_get_lock(union pte * ptep)8615a74e3d9SClaudio Imbrenda static inline union pgste pgste_get_lock(union pte *ptep)
8625a74e3d9SClaudio Imbrenda {
8635a74e3d9SClaudio Imbrenda 	union pgste res;
8645a74e3d9SClaudio Imbrenda 
8655a74e3d9SClaudio Imbrenda 	while (!pgste_get_trylock(ptep, &res))
8665a74e3d9SClaudio Imbrenda 		cpu_relax();
8675a74e3d9SClaudio Imbrenda 	return res;
8685a74e3d9SClaudio Imbrenda }
8695a74e3d9SClaudio Imbrenda 
pgste_set_unlock(union pte * ptep,union pgste pgste)8705a74e3d9SClaudio Imbrenda static inline void pgste_set_unlock(union pte *ptep, union pgste pgste)
8715a74e3d9SClaudio Imbrenda {
8725a74e3d9SClaudio Imbrenda 	pgste.pcl = 0;
8735a74e3d9SClaudio Imbrenda 	barrier();
8745a74e3d9SClaudio Imbrenda 	WRITE_ONCE(*pgste_of(ptep), pgste);
8755a74e3d9SClaudio Imbrenda }
8765a74e3d9SClaudio Imbrenda 
dat_ptep_xchg(union pte * ptep,union pte new,gfn_t gfn,union asce asce,bool has_skeys)877589071eaSClaudio Imbrenda static inline void dat_ptep_xchg(union pte *ptep, union pte new, gfn_t gfn, union asce asce,
878589071eaSClaudio Imbrenda 				 bool has_skeys)
879589071eaSClaudio Imbrenda {
880589071eaSClaudio Imbrenda 	union pgste pgste;
881589071eaSClaudio Imbrenda 
882589071eaSClaudio Imbrenda 	pgste = pgste_get_lock(ptep);
883589071eaSClaudio Imbrenda 	pgste = __dat_ptep_xchg(ptep, pgste, new, gfn, asce, has_skeys);
884589071eaSClaudio Imbrenda 	pgste_set_unlock(ptep, pgste);
885589071eaSClaudio Imbrenda }
886589071eaSClaudio Imbrenda 
dat_ptep_clear(union pte * ptep,gfn_t gfn,union asce asce,bool has_skeys)887589071eaSClaudio Imbrenda static inline void dat_ptep_clear(union pte *ptep, gfn_t gfn, union asce asce, bool has_skeys)
888589071eaSClaudio Imbrenda {
889589071eaSClaudio Imbrenda 	dat_ptep_xchg(ptep, _PTE_EMPTY, gfn, asce, has_skeys);
890589071eaSClaudio Imbrenda }
891589071eaSClaudio Imbrenda 
dat_free_pt(struct page_table * pt)89212f2f61aSClaudio Imbrenda static inline void dat_free_pt(struct page_table *pt)
89312f2f61aSClaudio Imbrenda {
89412f2f61aSClaudio Imbrenda 	free_page((unsigned long)pt);
89512f2f61aSClaudio Imbrenda }
89612f2f61aSClaudio Imbrenda 
_dat_free_crst(struct crst_table * table)89712f2f61aSClaudio Imbrenda static inline void _dat_free_crst(struct crst_table *table)
89812f2f61aSClaudio Imbrenda {
89912f2f61aSClaudio Imbrenda 	free_pages((unsigned long)table, CRST_ALLOC_ORDER);
90012f2f61aSClaudio Imbrenda }
90112f2f61aSClaudio Imbrenda 
90212f2f61aSClaudio Imbrenda #define dat_free_crst(x) _dat_free_crst(_CRSTP(x))
90312f2f61aSClaudio Imbrenda 
kvm_s390_free_mmu_cache(struct kvm_s390_mmu_cache * mc)90412f2f61aSClaudio Imbrenda static inline void kvm_s390_free_mmu_cache(struct kvm_s390_mmu_cache *mc)
90512f2f61aSClaudio Imbrenda {
90612f2f61aSClaudio Imbrenda 	if (!mc)
90712f2f61aSClaudio Imbrenda 		return;
90812f2f61aSClaudio Imbrenda 	while (mc->n_pts)
90912f2f61aSClaudio Imbrenda 		dat_free_pt(mc->pts[--mc->n_pts]);
91012f2f61aSClaudio Imbrenda 	while (mc->n_crsts)
91112f2f61aSClaudio Imbrenda 		_dat_free_crst(mc->crsts[--mc->n_crsts]);
91212f2f61aSClaudio Imbrenda 	while (mc->n_rmaps)
91312f2f61aSClaudio Imbrenda 		kfree(mc->rmaps[--mc->n_rmaps]);
91412f2f61aSClaudio Imbrenda 	kfree(mc);
91512f2f61aSClaudio Imbrenda }
91612f2f61aSClaudio Imbrenda 
DEFINE_FREE(kvm_s390_mmu_cache,struct kvm_s390_mmu_cache *,if (_T)kvm_s390_free_mmu_cache (_T))91712f2f61aSClaudio Imbrenda DEFINE_FREE(kvm_s390_mmu_cache, struct kvm_s390_mmu_cache *, if (_T) kvm_s390_free_mmu_cache(_T))
91812f2f61aSClaudio Imbrenda 
91912f2f61aSClaudio Imbrenda static inline struct kvm_s390_mmu_cache *kvm_s390_new_mmu_cache(void)
92012f2f61aSClaudio Imbrenda {
92112f2f61aSClaudio Imbrenda 	struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
92212f2f61aSClaudio Imbrenda 
923*69050f8dSKees Cook 	mc = kzalloc_obj(*mc, GFP_KERNEL_ACCOUNT);
92412f2f61aSClaudio Imbrenda 	if (mc && !kvm_s390_mmu_cache_topup(mc))
92512f2f61aSClaudio Imbrenda 		return_ptr(mc);
92612f2f61aSClaudio Imbrenda 	return NULL;
92712f2f61aSClaudio Imbrenda }
92812f2f61aSClaudio Imbrenda 
dat_pmdp_xchg_atomic(union pmd * pmdp,union pmd old,union pmd new,gfn_t gfn,union asce asce)929589071eaSClaudio Imbrenda static inline bool dat_pmdp_xchg_atomic(union pmd *pmdp, union pmd old, union pmd new,
930589071eaSClaudio Imbrenda 					gfn_t gfn, union asce asce)
931589071eaSClaudio Imbrenda {
932589071eaSClaudio Imbrenda 	return dat_crstep_xchg_atomic(_CRSTEP(pmdp), _CRSTE(old), _CRSTE(new), gfn, asce);
933589071eaSClaudio Imbrenda }
934589071eaSClaudio Imbrenda 
dat_pudp_xchg_atomic(union pud * pudp,union pud old,union pud new,gfn_t gfn,union asce asce)935589071eaSClaudio Imbrenda static inline bool dat_pudp_xchg_atomic(union pud *pudp, union pud old, union pud new,
936589071eaSClaudio Imbrenda 					gfn_t gfn, union asce asce)
937589071eaSClaudio Imbrenda {
938589071eaSClaudio Imbrenda 	return dat_crstep_xchg_atomic(_CRSTEP(pudp), _CRSTE(old), _CRSTE(new), gfn, asce);
939589071eaSClaudio Imbrenda }
940589071eaSClaudio Imbrenda 
dat_crstep_clear(union crste * crstep,gfn_t gfn,union asce asce)941589071eaSClaudio Imbrenda static inline void dat_crstep_clear(union crste *crstep, gfn_t gfn, union asce asce)
942589071eaSClaudio Imbrenda {
943589071eaSClaudio Imbrenda 	union crste newcrste = _CRSTE_EMPTY(crstep->h.tt);
944589071eaSClaudio Imbrenda 
945589071eaSClaudio Imbrenda 	dat_crstep_xchg(crstep, newcrste, gfn, asce);
946589071eaSClaudio Imbrenda }
947589071eaSClaudio Imbrenda 
get_level(union crste * crstep,union pte * ptep)9482db149a0SClaudio Imbrenda static inline int get_level(union crste *crstep, union pte *ptep)
9492db149a0SClaudio Imbrenda {
9502db149a0SClaudio Imbrenda 	return ptep ? TABLE_TYPE_PAGE_TABLE : crstep->h.tt;
9512db149a0SClaudio Imbrenda }
9522db149a0SClaudio Imbrenda 
dat_delete_slot(struct kvm_s390_mmu_cache * mc,union asce asce,gfn_t start,unsigned long npages)95394fd9b16SClaudio Imbrenda static inline int dat_delete_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start,
95494fd9b16SClaudio Imbrenda 				  unsigned long npages)
95594fd9b16SClaudio Imbrenda {
95694fd9b16SClaudio Imbrenda 	return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_PIC, PGM_ADDRESSING);
95794fd9b16SClaudio Imbrenda }
95894fd9b16SClaudio Imbrenda 
dat_create_slot(struct kvm_s390_mmu_cache * mc,union asce asce,gfn_t start,unsigned long npages)95994fd9b16SClaudio Imbrenda static inline int dat_create_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start,
96094fd9b16SClaudio Imbrenda 				  unsigned long npages)
96194fd9b16SClaudio Imbrenda {
96294fd9b16SClaudio Imbrenda 	return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_NONE, 0);
96394fd9b16SClaudio Imbrenda }
96494fd9b16SClaudio Imbrenda 
crste_is_ucas(union crste crste)96594fd9b16SClaudio Imbrenda static inline bool crste_is_ucas(union crste crste)
96694fd9b16SClaudio Imbrenda {
96794fd9b16SClaudio Imbrenda 	return is_pmd(crste) && crste.h.i && crste.h.fc0.tl == 1 && crste.h.fc == 0;
96894fd9b16SClaudio Imbrenda }
96994fd9b16SClaudio Imbrenda 
9705a74e3d9SClaudio Imbrenda #endif /* __KVM_S390_DAT_H */
971