Skip to content

Commit 5983ab1

Browse files
author
Vasily Gorbik
committed
Merge branch 'strict-mm-typechecks-support' into features
Heiko writes: "The recent large kernel Rust thread where Linus commented about that structures may be returned in registers [1] made me again aware that this is not true for s390 where the ABI defines that structures are returned in a return value buffer allocated by the caller. This was also mentioned by Alexander Gordeev a couple of weeks ago. In theory the -freg-struct-return compiler flag would allow to return small structures in registers, however that has not been implemented for s390. Juergen Christ did an experimental gcc implementation which shows the benefit of such a change (bloat-o-meter): add/remove: 3/2 grow/shrink: 12/441 up/down: 740/-7182 (-6442) This result is not very impressive, and doesn't seem to justify a new ABI for the kernel. However there is still the existing STRICT_MM_TYPECHECKS which can be used to change some mm types from structures to simple scalar types. Changing the mm types results in: add/remove: 2/8 grow/shrink: 25/116 up/down: 3902/-6204 (-2302) Which is already a third of the possible savings which would be the result of the described ABI change. Therefore add support for a configurable STRICT_MM_TYPECHECKS which allows to generate better code, but also allows to have type checking for debug builds." [1] https://lore.kernel.org/all/CAHk-=wgb1g9VVHRaAnJjrfRFWAOVT2ouNOMqt0js8h3D6zvHDw@mail.gmail.com/ * strict-mm-typechecks-support: s390/mm: Add configurable STRICT_MM_TYPECHECKS s390/mm: Convert pgste_val() into function s390/mm: Convert pgprot_val() into function s390/mm: Use pgprot_val() instead of open coding Signed-off-by: Vasily Gorbik <[email protected]>
2 parents 8751b6e + 0354486 commit 5983ab1

File tree

7 files changed

+82
-52
lines changed

7 files changed

+82
-52
lines changed

arch/s390/Kconfig.debug

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ config DEBUG_ENTRY
1313

1414
If unsure, say N.
1515

16+
config STRICT_MM_TYPECHECKS
17+
bool "Strict Memory Management Type Checks"
18+
depends on DEBUG_KERNEL
19+
help
20+
Enable strict type checking for memory management types like pte_t
21+
and pmd_t. This generates slightly worse code and should be used
22+
for debug builds.
23+
24+
If unsure, say N.
25+
1626
config CIO_INJECT
1727
bool "CIO Inject interfaces"
1828
depends on DEBUG_KERNEL && DEBUG_FS

arch/s390/configs/debug_defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,7 @@ CONFIG_SAMPLE_FTRACE_DIRECT=m
894894
CONFIG_SAMPLE_FTRACE_DIRECT_MULTI=m
895895
CONFIG_SAMPLE_FTRACE_OPS=m
896896
CONFIG_DEBUG_ENTRY=y
897+
CONFIG_STRICT_MM_TYPECHECKS=y
897898
CONFIG_CIO_INJECT=y
898899
CONFIG_KUNIT=m
899900
CONFIG_KUNIT_DEBUGFS=y

arch/s390/configs/mmtypes.config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Help: Enable strict memory management typechecks
2+
CONFIG_STRICT_MM_TYPECHECKS=y

arch/s390/include/asm/page.h

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ static inline void copy_page(void *to, void *from)
7171
#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
7272
vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)
7373

74-
/*
75-
* These are used to make use of C type-checking..
76-
*/
74+
#ifdef CONFIG_STRICT_MM_TYPECHECKS
75+
#define STRICT_MM_TYPECHECKS
76+
#endif
77+
78+
#ifdef STRICT_MM_TYPECHECKS
7779

7880
typedef struct { unsigned long pgprot; } pgprot_t;
7981
typedef struct { unsigned long pgste; } pgste_t;
@@ -82,43 +84,48 @@ typedef struct { unsigned long pmd; } pmd_t;
8284
typedef struct { unsigned long pud; } pud_t;
8385
typedef struct { unsigned long p4d; } p4d_t;
8486
typedef struct { unsigned long pgd; } pgd_t;
85-
typedef pte_t *pgtable_t;
8687

87-
#define pgprot_val(x) ((x).pgprot)
88-
#define pgste_val(x) ((x).pgste)
89-
90-
static inline unsigned long pte_val(pte_t pte)
91-
{
92-
return pte.pte;
88+
#define DEFINE_PGVAL_FUNC(name) \
89+
static __always_inline unsigned long name ## _val(name ## _t name) \
90+
{ \
91+
return name.name; \
9392
}
9493

95-
static inline unsigned long pmd_val(pmd_t pmd)
96-
{
97-
return pmd.pmd;
98-
}
94+
#else /* STRICT_MM_TYPECHECKS */
9995

100-
static inline unsigned long pud_val(pud_t pud)
101-
{
102-
return pud.pud;
103-
}
96+
typedef unsigned long pgprot_t;
97+
typedef unsigned long pgste_t;
98+
typedef unsigned long pte_t;
99+
typedef unsigned long pmd_t;
100+
typedef unsigned long pud_t;
101+
typedef unsigned long p4d_t;
102+
typedef unsigned long pgd_t;
104103

105-
static inline unsigned long p4d_val(p4d_t p4d)
106-
{
107-
return p4d.p4d;
104+
#define DEFINE_PGVAL_FUNC(name) \
105+
static __always_inline unsigned long name ## _val(name ## _t name) \
106+
{ \
107+
return name; \
108108
}
109109

110-
static inline unsigned long pgd_val(pgd_t pgd)
111-
{
112-
return pgd.pgd;
113-
}
110+
#endif /* STRICT_MM_TYPECHECKS */
111+
112+
DEFINE_PGVAL_FUNC(pgprot)
113+
DEFINE_PGVAL_FUNC(pgste)
114+
DEFINE_PGVAL_FUNC(pte)
115+
DEFINE_PGVAL_FUNC(pmd)
116+
DEFINE_PGVAL_FUNC(pud)
117+
DEFINE_PGVAL_FUNC(p4d)
118+
DEFINE_PGVAL_FUNC(pgd)
119+
120+
typedef pte_t *pgtable_t;
114121

122+
#define __pgprot(x) ((pgprot_t) { (x) } )
115123
#define __pgste(x) ((pgste_t) { (x) } )
116124
#define __pte(x) ((pte_t) { (x) } )
117125
#define __pmd(x) ((pmd_t) { (x) } )
118126
#define __pud(x) ((pud_t) { (x) } )
119127
#define __p4d(x) ((p4d_t) { (x) } )
120128
#define __pgd(x) ((pgd_t) { (x) } )
121-
#define __pgprot(x) ((pgprot_t) { (x) } )
122129

123130
static inline void page_set_storage_key(unsigned long addr,
124131
unsigned char skey, int mapped)

arch/s390/include/asm/pgtable.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,16 @@ static inline int mm_alloc_pgste(struct mm_struct *mm)
593593
return 0;
594594
}
595595

596+
static inline pgste_t clear_pgste_bit(pgste_t pgste, unsigned long mask)
597+
{
598+
return __pgste(pgste_val(pgste) & ~mask);
599+
}
600+
601+
static inline pgste_t set_pgste_bit(pgste_t pgste, unsigned long mask)
602+
{
603+
return __pgste(pgste_val(pgste) | mask);
604+
}
605+
596606
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
597607
{
598608
return __pte(pte_val(pte) & ~pgprot_val(prot));

arch/s390/mm/init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ int arch_add_memory(int nid, u64 start, u64 size,
286286
unsigned long size_pages = PFN_DOWN(size);
287287
int rc;
288288

289-
if (WARN_ON_ONCE(params->pgprot.pgprot != PAGE_KERNEL.pgprot))
289+
if (WARN_ON_ONCE(pgprot_val(params->pgprot) != pgprot_val(PAGE_KERNEL)))
290290
return -EINVAL;
291291

292292
VM_BUG_ON(!mhp_range_allowed(start, size, true));

arch/s390/mm/pgtable.c

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ static inline pgste_t pgste_update_all(pte_t pte, pgste_t pgste,
165165
skey = (unsigned long) page_get_storage_key(address);
166166
bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
167167
/* Transfer page changed & referenced bit to guest bits in pgste */
168-
pgste_val(pgste) |= bits << 48; /* GR bit & GC bit */
168+
pgste = set_pgste_bit(pgste, bits << 48); /* GR bit & GC bit */
169169
/* Copy page access key and fetch protection bit to pgste */
170-
pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
171-
pgste_val(pgste) |= (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
170+
pgste = clear_pgste_bit(pgste, PGSTE_ACC_BITS | PGSTE_FP_BIT);
171+
pgste = set_pgste_bit(pgste, (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56);
172172
#endif
173173
return pgste;
174174

@@ -212,7 +212,7 @@ static inline pgste_t pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
212212
}
213213
if (!(pte_val(entry) & _PAGE_PROTECT))
214214
/* This pte allows write access, set user-dirty */
215-
pgste_val(pgste) |= PGSTE_UC_BIT;
215+
pgste = set_pgste_bit(pgste, PGSTE_UC_BIT);
216216
}
217217
#endif
218218
set_pte(ptep, entry);
@@ -228,7 +228,7 @@ static inline pgste_t pgste_pte_notify(struct mm_struct *mm,
228228

229229
bits = pgste_val(pgste) & (PGSTE_IN_BIT | PGSTE_VSIE_BIT);
230230
if (bits) {
231-
pgste_val(pgste) ^= bits;
231+
pgste = __pgste(pgste_val(pgste) ^ bits);
232232
ptep_notify(mm, addr, ptep, bits);
233233
}
234234
#endif
@@ -601,7 +601,7 @@ void ptep_set_pte_at(struct mm_struct *mm, unsigned long addr,
601601
/* the mm_has_pgste() check is done in set_pte_at() */
602602
preempt_disable();
603603
pgste = pgste_get_lock(ptep);
604-
pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
604+
pgste = clear_pgste_bit(pgste, _PGSTE_GPS_ZERO);
605605
pgste_set_key(ptep, pgste, entry, mm);
606606
pgste = pgste_set_pte(ptep, pgste, entry);
607607
pgste_set_unlock(ptep, pgste);
@@ -614,7 +614,7 @@ void ptep_set_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
614614

615615
preempt_disable();
616616
pgste = pgste_get_lock(ptep);
617-
pgste_val(pgste) |= PGSTE_IN_BIT;
617+
pgste = set_pgste_bit(pgste, PGSTE_IN_BIT);
618618
pgste_set_unlock(ptep, pgste);
619619
preempt_enable();
620620
}
@@ -659,7 +659,7 @@ int ptep_force_prot(struct mm_struct *mm, unsigned long addr,
659659
entry = clear_pte_bit(entry, __pgprot(_PAGE_INVALID));
660660
entry = set_pte_bit(entry, __pgprot(_PAGE_PROTECT));
661661
}
662-
pgste_val(pgste) |= bit;
662+
pgste = set_pgste_bit(pgste, bit);
663663
pgste = pgste_set_pte(ptep, pgste, entry);
664664
pgste_set_unlock(ptep, pgste);
665665
return 0;
@@ -679,7 +679,7 @@ int ptep_shadow_pte(struct mm_struct *mm, unsigned long saddr,
679679
if (!(pte_val(spte) & _PAGE_INVALID) &&
680680
!((pte_val(spte) & _PAGE_PROTECT) &&
681681
!(pte_val(pte) & _PAGE_PROTECT))) {
682-
pgste_val(spgste) |= PGSTE_VSIE_BIT;
682+
spgste = set_pgste_bit(spgste, PGSTE_VSIE_BIT);
683683
tpgste = pgste_get_lock(tptep);
684684
tpte = __pte((pte_val(spte) & PAGE_MASK) |
685685
(pte_val(pte) & _PAGE_PROTECT));
@@ -737,7 +737,7 @@ void ptep_zap_unused(struct mm_struct *mm, unsigned long addr,
737737
pte_clear(mm, addr, ptep);
738738
}
739739
if (reset)
740-
pgste_val(pgste) &= ~(_PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT);
740+
pgste = clear_pgste_bit(pgste, _PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT);
741741
pgste_set_unlock(ptep, pgste);
742742
preempt_enable();
743743
}
@@ -750,8 +750,8 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
750750
/* Clear storage key ACC and F, but set R/C */
751751
preempt_disable();
752752
pgste = pgste_get_lock(ptep);
753-
pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
754-
pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT;
753+
pgste = clear_pgste_bit(pgste, PGSTE_ACC_BITS | PGSTE_FP_BIT);
754+
pgste = set_pgste_bit(pgste, PGSTE_GR_BIT | PGSTE_GC_BIT);
755755
ptev = pte_val(*ptep);
756756
if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE))
757757
page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 0);
@@ -772,7 +772,7 @@ bool ptep_test_and_clear_uc(struct mm_struct *mm, unsigned long addr,
772772

773773
pgste = pgste_get_lock(ptep);
774774
dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT);
775-
pgste_val(pgste) &= ~PGSTE_UC_BIT;
775+
pgste = clear_pgste_bit(pgste, PGSTE_UC_BIT);
776776
pte = *ptep;
777777
if (dirty && (pte_val(pte) & _PAGE_PRESENT)) {
778778
pgste = pgste_pte_notify(mm, addr, ptep, pgste);
@@ -834,11 +834,11 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
834834
if (!ptep)
835835
goto again;
836836
new = old = pgste_get_lock(ptep);
837-
pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT |
838-
PGSTE_ACC_BITS | PGSTE_FP_BIT);
837+
new = clear_pgste_bit(new, PGSTE_GR_BIT | PGSTE_GC_BIT |
838+
PGSTE_ACC_BITS | PGSTE_FP_BIT);
839839
keyul = (unsigned long) key;
840-
pgste_val(new) |= (keyul & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48;
841-
pgste_val(new) |= (keyul & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
840+
new = set_pgste_bit(new, (keyul & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48);
841+
new = set_pgste_bit(new, (keyul & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56);
842842
if (!(pte_val(*ptep) & _PAGE_INVALID)) {
843843
unsigned long bits, skey;
844844

@@ -849,12 +849,12 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
849849
/* Set storage key ACC and FP */
850850
page_set_storage_key(paddr, skey, !nq);
851851
/* Merge host changed & referenced into pgste */
852-
pgste_val(new) |= bits << 52;
852+
new = set_pgste_bit(new, bits << 52);
853853
}
854854
/* changing the guest storage key is considered a change of the page */
855855
if ((pgste_val(new) ^ pgste_val(old)) &
856856
(PGSTE_ACC_BITS | PGSTE_FP_BIT | PGSTE_GR_BIT | PGSTE_GC_BIT))
857-
pgste_val(new) |= PGSTE_UC_BIT;
857+
new = set_pgste_bit(new, PGSTE_UC_BIT);
858858

859859
pgste_set_unlock(ptep, new);
860860
pte_unmap_unlock(ptep, ptl);
@@ -942,19 +942,19 @@ int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr)
942942
goto again;
943943
new = old = pgste_get_lock(ptep);
944944
/* Reset guest reference bit only */
945-
pgste_val(new) &= ~PGSTE_GR_BIT;
945+
new = clear_pgste_bit(new, PGSTE_GR_BIT);
946946

947947
if (!(pte_val(*ptep) & _PAGE_INVALID)) {
948948
paddr = pte_val(*ptep) & PAGE_MASK;
949949
cc = page_reset_referenced(paddr);
950950
/* Merge real referenced bit into host-set */
951-
pgste_val(new) |= ((unsigned long) cc << 53) & PGSTE_HR_BIT;
951+
new = set_pgste_bit(new, ((unsigned long)cc << 53) & PGSTE_HR_BIT);
952952
}
953953
/* Reflect guest's logical view, not physical */
954954
cc |= (pgste_val(old) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 49;
955955
/* Changing the guest storage key is considered a change of the page */
956956
if ((pgste_val(new) ^ pgste_val(old)) & PGSTE_GR_BIT)
957-
pgste_val(new) |= PGSTE_UC_BIT;
957+
new = set_pgste_bit(new, PGSTE_UC_BIT);
958958

959959
pgste_set_unlock(ptep, new);
960960
pte_unmap_unlock(ptep, ptl);
@@ -1118,7 +1118,7 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
11181118
if (res)
11191119
pgstev |= _PGSTE_GPS_ZERO;
11201120

1121-
pgste_val(pgste) = pgstev;
1121+
pgste = __pgste(pgstev);
11221122
pgste_set_unlock(ptep, pgste);
11231123
pte_unmap_unlock(ptep, ptl);
11241124
return res;
@@ -1151,8 +1151,8 @@ int set_pgste_bits(struct mm_struct *mm, unsigned long hva,
11511151
return -EFAULT;
11521152
new = pgste_get_lock(ptep);
11531153

1154-
pgste_val(new) &= ~bits;
1155-
pgste_val(new) |= value & bits;
1154+
new = clear_pgste_bit(new, bits);
1155+
new = set_pgste_bit(new, value & bits);
11561156

11571157
pgste_set_unlock(ptep, new);
11581158
pte_unmap_unlock(ptep, ptl);

0 commit comments

Comments
 (0)