Skip to content

Commit c0f1d47

Browse files
committed
s390/mm: simplify kernel mapping setup
The kernel mapping is setup in two stages: in the decompressor map all pages with RWX permissions, and within the kernel change all mappings to their final permissions, where most of the mappings are changed from RWX to RWNX. Change this and map all pages RWNX from the beginning, however without enabling noexec via control register modification. This means that effectively all pages are used with RWX permissions like before. When the final permissions have been applied to the kernel mapping enable noexec via control register modification. This allows to remove quite a bit of non-obvious code. Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
1 parent b6f10e2 commit c0f1d47

File tree

4 files changed

+15
-114
lines changed

4 files changed

+15
-114
lines changed

arch/s390/boot/startup.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@ static void detect_facilities(void)
5353
}
5454
if (test_facility(78))
5555
machine.has_edat2 = 1;
56-
if (test_facility(130)) {
56+
if (test_facility(130))
5757
machine.has_nx = 1;
58-
__ctl_set_bit(0, 20);
59-
}
6058
}
6159

6260
static void setup_lpp(void)

arch/s390/boot/vmem.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,9 @@ static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long e
287287
if (kasan_pte_populate_zero_shadow(pte, mode))
288288
continue;
289289
entry = __pte(_pa(addr, PAGE_SIZE, mode));
290-
entry = set_pte_bit(entry, PAGE_KERNEL_EXEC);
290+
entry = set_pte_bit(entry, PAGE_KERNEL);
291+
if (!machine.has_nx)
292+
entry = clear_pte_bit(entry, __pgprot(_PAGE_NOEXEC));
291293
set_pte(pte, entry);
292294
pages++;
293295
}
@@ -311,7 +313,9 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e
311313
continue;
312314
if (can_large_pmd(pmd, addr, next)) {
313315
entry = __pmd(_pa(addr, _SEGMENT_SIZE, mode));
314-
entry = set_pmd_bit(entry, SEGMENT_KERNEL_EXEC);
316+
entry = set_pmd_bit(entry, SEGMENT_KERNEL);
317+
if (!machine.has_nx)
318+
entry = clear_pmd_bit(entry, __pgprot(_SEGMENT_ENTRY_NOEXEC));
315319
set_pmd(pmd, entry);
316320
pages++;
317321
continue;
@@ -342,7 +346,9 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e
342346
continue;
343347
if (can_large_pud(pud, addr, next)) {
344348
entry = __pud(_pa(addr, _REGION3_SIZE, mode));
345-
entry = set_pud_bit(entry, REGION3_KERNEL_EXEC);
349+
entry = set_pud_bit(entry, REGION3_KERNEL);
350+
if (!machine.has_nx)
351+
entry = clear_pud_bit(entry, __pgprot(_REGION_ENTRY_NOEXEC));
346352
set_pud(pud, entry);
347353
pages++;
348354
continue;

arch/s390/kernel/early.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,8 @@ static __init void detect_machine_facilities(void)
232232
S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
233233
__ctl_set_bit(0, 17);
234234
}
235-
if (test_facility(130)) {
235+
if (test_facility(130))
236236
S390_lowcore.machine_flags |= MACHINE_FLAG_NX;
237-
__ctl_set_bit(0, 20);
238-
}
239237
if (test_facility(133))
240238
S390_lowcore.machine_flags |= MACHINE_FLAG_GS;
241239
if (test_facility(139) && (tod_clock_base.tod >> 63)) {

arch/s390/mm/vmem.c

Lines changed: 4 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include <linux/memory_hotplug.h>
77
#include <linux/memblock.h>
8-
#include <linux/kasan.h>
98
#include <linux/pfn.h>
109
#include <linux/mm.h>
1110
#include <linux/init.h>
@@ -650,108 +649,8 @@ void vmem_unmap_4k_page(unsigned long addr)
650649
mutex_unlock(&vmem_mutex);
651650
}
652651

653-
static int __init memblock_region_cmp(const void *a, const void *b)
654-
{
655-
const struct memblock_region *r1 = a;
656-
const struct memblock_region *r2 = b;
657-
658-
if (r1->base < r2->base)
659-
return -1;
660-
if (r1->base > r2->base)
661-
return 1;
662-
return 0;
663-
}
664-
665-
static void __init memblock_region_swap(void *a, void *b, int size)
666-
{
667-
swap(*(struct memblock_region *)a, *(struct memblock_region *)b);
668-
}
669-
670-
#ifdef CONFIG_KASAN
671-
#define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x))
672-
673-
static inline int set_memory_kasan(unsigned long start, unsigned long end)
674-
{
675-
start = PAGE_ALIGN_DOWN(__sha(start));
676-
end = PAGE_ALIGN(__sha(end));
677-
return set_memory_rwnx(start, (end - start) >> PAGE_SHIFT);
678-
}
679-
#endif
680-
681-
/*
682-
* map whole physical memory to virtual memory (identity mapping)
683-
* we reserve enough space in the vmalloc area for vmemmap to hotplug
684-
* additional memory segments.
685-
*/
686652
void __init vmem_map_init(void)
687653
{
688-
struct memblock_region memory_rwx_regions[] = {
689-
{
690-
.base = 0,
691-
.size = sizeof(struct lowcore),
692-
.flags = MEMBLOCK_NONE,
693-
#ifdef CONFIG_NUMA
694-
.nid = NUMA_NO_NODE,
695-
#endif
696-
},
697-
{
698-
.base = __pa(_stext),
699-
.size = _etext - _stext,
700-
.flags = MEMBLOCK_NONE,
701-
#ifdef CONFIG_NUMA
702-
.nid = NUMA_NO_NODE,
703-
#endif
704-
},
705-
{
706-
.base = __pa(_sinittext),
707-
.size = _einittext - _sinittext,
708-
.flags = MEMBLOCK_NONE,
709-
#ifdef CONFIG_NUMA
710-
.nid = NUMA_NO_NODE,
711-
#endif
712-
},
713-
{
714-
.base = __stext_amode31,
715-
.size = __etext_amode31 - __stext_amode31,
716-
.flags = MEMBLOCK_NONE,
717-
#ifdef CONFIG_NUMA
718-
.nid = NUMA_NO_NODE,
719-
#endif
720-
},
721-
};
722-
struct memblock_type memory_rwx = {
723-
.regions = memory_rwx_regions,
724-
.cnt = ARRAY_SIZE(memory_rwx_regions),
725-
.max = ARRAY_SIZE(memory_rwx_regions),
726-
};
727-
phys_addr_t base, end;
728-
u64 i;
729-
730-
/*
731-
* Set RW+NX attribute on all memory, except regions enumerated with
732-
* memory_rwx exclude type. These regions need different attributes,
733-
* which are enforced afterwards.
734-
*
735-
* __for_each_mem_range() iterate and exclude types should be sorted.
736-
* The relative location of _stext and _sinittext is hardcoded in the
737-
* linker script. However a location of __stext_amode31 and the kernel
738-
* image itself are chosen dynamically. Thus, sort the exclude type.
739-
*/
740-
sort(&memory_rwx_regions,
741-
ARRAY_SIZE(memory_rwx_regions), sizeof(memory_rwx_regions[0]),
742-
memblock_region_cmp, memblock_region_swap);
743-
__for_each_mem_range(i, &memblock.memory, &memory_rwx,
744-
NUMA_NO_NODE, MEMBLOCK_NONE, &base, &end, NULL) {
745-
set_memory_rwnx((unsigned long)__va(base),
746-
(end - base) >> PAGE_SHIFT);
747-
}
748-
749-
#ifdef CONFIG_KASAN
750-
for_each_mem_range(i, &base, &end) {
751-
set_memory_kasan((unsigned long)__va(base),
752-
(unsigned long)__va(end));
753-
}
754-
#endif
755654
set_memory_rox((unsigned long)_stext,
756655
(unsigned long)(_etext - _stext) >> PAGE_SHIFT);
757656
set_memory_ro((unsigned long)_etext,
@@ -762,14 +661,14 @@ void __init vmem_map_init(void)
762661
(__etext_amode31 - __stext_amode31) >> PAGE_SHIFT);
763662

764663
/* lowcore must be executable for LPSWE */
765-
if (static_key_enabled(&cpu_has_bear))
766-
set_memory_nx(0, 1);
767-
set_memory_nx(PAGE_SIZE, 1);
664+
if (!static_key_enabled(&cpu_has_bear))
665+
set_memory_x(0, 1);
768666
if (debug_pagealloc_enabled()) {
769667
set_memory_4k((unsigned long)__va(0),
770668
ident_map_size >> PAGE_SHIFT);
771669
}
772-
670+
if (MACHINE_HAS_NX)
671+
ctl_set_bit(0, 20);
773672
pr_info("Write protected kernel read-only data: %luk\n",
774673
(unsigned long)(__end_rodata - _stext) >> 10);
775674
}

0 commit comments

Comments
 (0)