Commit 03544866 authored by Heiko Carstens's avatar Heiko Carstens Committed by Vasily Gorbik
Browse files

s390/mm: Add configurable STRICT_MM_TYPECHECKS



Add support for configurable STRICT_MM_TYPECHECKS. The s390 ABI defines
that return values with complex types like structures and unions are
returned in a return value buffer allocated by the caller. This is also
true for small structures and unions which would fit into a register.  On
the other hand when such types are passed as arguments to functions they
are passed in registers, if they are small enough.
This leads to inefficient code when such a return value of a function call
is then passed as argument to a subsequent function call.

This is especially true for all mm types, like pte_t and others, which are
only for type checking reasons defined as a structure. This however can be
bypassed with the STRICT_MM_TYPECHECKS feature, which is used by a few
other architectures, which seem to have the same problem.

Add CONFIG_STRICT_MM_TYPECHECKS which can be used to change the type of
pte_t and other structures. If the config option is not enabled the types
are defined to unsigned long, allowing for better code generation, however
there is no type checking anymore. If it is enabled the types are
structures like before so that type checking is performed, but less
efficient code is generated.

The option is always enabled in debug_defconfig, and for convenience an
mmtypes.config topic target is added, which allows to easily enable it, in
case memory management code is changed.

CONFIG_STRICT_MM_TYPECHECKS and STRICT_MM_TYPECHECKS are kept separate,
since STRICT_MM_TYPECHECKS is common across architectures and common
code. Therefore use the same define also for s390 code.

Add CONFIG_STRICT_MM_TYPECHECKS to make it build time configurable.

Reviewed-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 94d553ce
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -13,6 +13,16 @@ config DEBUG_ENTRY

	  If unsure, say N.

config STRICT_MM_TYPECHECKS
	bool "Strict Memory Management Type Checks"
	depends on DEBUG_KERNEL
	help
	  Enable strict type checking for memory management types like pte_t
	  and pmd_t. This generates slightly worse code and should be used
	  for debug builds.

	  If unsure, say N.

config CIO_INJECT
	bool "CIO Inject interfaces"
	depends on DEBUG_KERNEL && DEBUG_FS
+1 −0
Original line number Diff line number Diff line
@@ -893,6 +893,7 @@ CONFIG_SAMPLE_FTRACE_DIRECT=m
CONFIG_SAMPLE_FTRACE_DIRECT_MULTI=m
CONFIG_SAMPLE_FTRACE_OPS=m
CONFIG_DEBUG_ENTRY=y
CONFIG_STRICT_MM_TYPECHECKS=y
CONFIG_CIO_INJECT=y
CONFIG_KUNIT=m
CONFIG_KUNIT_DEBUGFS=y
+2 −0
Original line number Diff line number Diff line
# Help: Enable strict memory management typechecks
CONFIG_STRICT_MM_TYPECHECKS=y
+30 −30
Original line number Diff line number Diff line
@@ -71,9 +71,11 @@ static inline void copy_page(void *to, void *from)
#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)

/*
 * These are used to make use of C type-checking..
 */
#ifdef CONFIG_STRICT_MM_TYPECHECKS
#define STRICT_MM_TYPECHECKS
#endif

#ifdef STRICT_MM_TYPECHECKS

typedef struct { unsigned long pgprot; } pgprot_t;
typedef struct { unsigned long pgste; } pgste_t;
@@ -82,42 +84,40 @@ typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
typedef struct { unsigned long p4d; } p4d_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef pte_t *pgtable_t;

static inline unsigned long pgprot_val(pgprot_t pgprot)
{
	return pgprot.pgprot;
#define DEFINE_PGVAL_FUNC(name)						\
static __always_inline unsigned long name ## _val(name ## _t name)	\
{									\
	return name.name;						\
}

static inline unsigned long pgste_val(pgste_t pgste)
{
	return pgste.pgste;
}
#else /* STRICT_MM_TYPECHECKS */

static inline unsigned long pte_val(pte_t pte)
{
	return pte.pte;
}
typedef unsigned long pgprot_t;
typedef unsigned long pgste_t;
typedef unsigned long pte_t;
typedef unsigned long pmd_t;
typedef unsigned long pud_t;
typedef unsigned long p4d_t;
typedef unsigned long pgd_t;

static inline unsigned long pmd_val(pmd_t pmd)
{
	return pmd.pmd;
#define DEFINE_PGVAL_FUNC(name)						\
static __always_inline unsigned long name ## _val(name ## _t name)	\
{									\
	return name;							\
}

static inline unsigned long pud_val(pud_t pud)
{
	return pud.pud;
}
#endif /* STRICT_MM_TYPECHECKS */

static inline unsigned long p4d_val(p4d_t p4d)
{
	return p4d.p4d;
}
DEFINE_PGVAL_FUNC(pgprot)
DEFINE_PGVAL_FUNC(pgste)
DEFINE_PGVAL_FUNC(pte)
DEFINE_PGVAL_FUNC(pmd)
DEFINE_PGVAL_FUNC(pud)
DEFINE_PGVAL_FUNC(p4d)
DEFINE_PGVAL_FUNC(pgd)

static inline unsigned long pgd_val(pgd_t pgd)
{
	return pgd.pgd;
}
typedef pte_t *pgtable_t;

#define __pgprot(x)	((pgprot_t) { (x) } )
#define __pgste(x)	((pgste_t) { (x) } )