mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
c7d19189d7
Long time ago we had a config item called STRICT_MM_TYPECHECKS to build the kernel with pte_t defined as a structure in order to perform additional build checks or build it with pte_t defined as a simple type in order to get simpler generated code. Commit670eea9241
("powerpc/mm: Always use STRICT_MM_TYPECHECKS") made the struct based definition the only one, considering that the generated code was similar in both cases. That's right on ppc64 because the ABI is such that the content of a struct having a single simple type element is passed as register, but on ppc32 such a structure is passed via the stack like any structure. Simple test function: pte_t test(pte_t pte) { return pte; } Before this patch we get c00108ec <test>: c00108ec: 81 24 00 00 lwz r9,0(r4) c00108f0: 91 23 00 00 stw r9,0(r3) c00108f4: 4e 80 00 20 blr So, for PPC32, restore the simple type behaviour we got before commit670eea9241
, but instead of adding a config option to activate type check, do it when __CHECKER__ is set so that type checking is performed by 'sparse' and provides feedback like: arch/powerpc/mm/pgtable.c:466:16: warning: incorrect type in return expression (different base types) arch/powerpc/mm/pgtable.c:466:16: expected unsigned long arch/powerpc/mm/pgtable.c:466:16: got struct pte_t [usertype] x With this patch we now get c0010890 <test>: c0010890: 4e 80 00 20 blr Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> [mpe: Define STRICT_MM_TYPECHECKS rather than repeating the condition] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/c904599f33aaf6bb7ee2836a9ff8368509e0d78d.1631887042.git.christophe.leroy@csgroup.eu
93 lines
2.2 KiB
C
93 lines
2.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_POWERPC_PGTABLE_TYPES_H
|
|
#define _ASM_POWERPC_PGTABLE_TYPES_H
|
|
|
|
#if defined(__CHECKER__) || !defined(CONFIG_PPC32)
|
|
#define STRICT_MM_TYPECHECKS
|
|
#endif
|
|
|
|
/* PTE level */
|
|
#if defined(CONFIG_PPC_8xx) && defined(CONFIG_PPC_16K_PAGES)
|
|
typedef struct { pte_basic_t pte, pte1, pte2, pte3; } pte_t;
|
|
#elif defined(STRICT_MM_TYPECHECKS)
|
|
typedef struct { pte_basic_t pte; } pte_t;
|
|
#else
|
|
typedef pte_basic_t pte_t;
|
|
#endif
|
|
|
|
#if defined(STRICT_MM_TYPECHECKS) || \
|
|
(defined(CONFIG_PPC_8xx) && defined(CONFIG_PPC_16K_PAGES))
|
|
#define __pte(x) ((pte_t) { (x) })
|
|
static inline pte_basic_t pte_val(pte_t x)
|
|
{
|
|
return x.pte;
|
|
}
|
|
#else
|
|
#define __pte(x) ((pte_t)(x))
|
|
static inline pte_basic_t pte_val(pte_t x)
|
|
{
|
|
return x;
|
|
}
|
|
#endif
|
|
|
|
/* PMD level */
|
|
#ifdef CONFIG_PPC64
|
|
typedef struct { unsigned long pmd; } pmd_t;
|
|
#define __pmd(x) ((pmd_t) { (x) })
|
|
static inline unsigned long pmd_val(pmd_t x)
|
|
{
|
|
return x.pmd;
|
|
}
|
|
|
|
/* 64 bit always use 4 level table. */
|
|
typedef struct { unsigned long pud; } pud_t;
|
|
#define __pud(x) ((pud_t) { (x) })
|
|
static inline unsigned long pud_val(pud_t x)
|
|
{
|
|
return x.pud;
|
|
}
|
|
#endif /* CONFIG_PPC64 */
|
|
|
|
/* PGD level */
|
|
typedef struct { unsigned long pgd; } pgd_t;
|
|
#define __pgd(x) ((pgd_t) { (x) })
|
|
static inline unsigned long pgd_val(pgd_t x)
|
|
{
|
|
return x.pgd;
|
|
}
|
|
|
|
/* Page protection bits */
|
|
typedef struct { unsigned long pgprot; } pgprot_t;
|
|
#define pgprot_val(x) ((x).pgprot)
|
|
#define __pgprot(x) ((pgprot_t) { (x) })
|
|
|
|
/*
|
|
* With hash config 64k pages additionally define a bigger "real PTE" type that
|
|
* gathers the "second half" part of the PTE for pseudo 64k pages
|
|
*/
|
|
#ifdef CONFIG_PPC_64K_PAGES
|
|
typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
|
|
#else
|
|
typedef struct { pte_t pte; } real_pte_t;
|
|
#endif
|
|
|
|
#ifdef CONFIG_PPC_BOOK3S_64
|
|
#include <asm/cmpxchg.h>
|
|
|
|
static inline bool pte_xchg(pte_t *ptep, pte_t old, pte_t new)
|
|
{
|
|
unsigned long *p = (unsigned long *)ptep;
|
|
|
|
/* See comment in switch_mm_irqs_off() */
|
|
return pte_val(old) == __cmpxchg_u64(p, pte_val(old), pte_val(new));
|
|
}
|
|
#endif
|
|
|
|
typedef struct { unsigned long pd; } hugepd_t;
|
|
#define __hugepd(x) ((hugepd_t) { (x) })
|
|
static inline unsigned long hpd_val(hugepd_t x)
|
|
{
|
|
return x.pd;
|
|
}
|
|
|
|
#endif /* _ASM_POWERPC_PGTABLE_TYPES_H */
|