unsigned long __bootdata(memory_end);
int __bootdata(memory_end_set);
+int __bootdata(noexec_disabled);
static inline int __diag308(unsigned long subcode, void *addr)
{
static char command_line_buf[COMMAND_LINE_SIZE] __section(.data);
static void parse_mem_opt(void)
{
- char *args;
char *param, *val;
+ bool enabled;
+ char *args;
+ int rc;
args = strcpy(command_line_buf, early_command_line);
while (*args) {
memory_end = memparse(val, NULL);
memory_end_set = 1;
}
+
+ if (!strcmp(param, "noexec")) {
+ rc = kstrtobool(val, &enabled);
+ if (!rc && !enabled)
+ noexec_disabled = 1;
+ }
}
}
#include <asm/kasan.h>
#include <asm/processor.h>
#include <asm/sclp.h>
+#include <asm/facility.h>
#include <asm/sections.h>
#include <asm/setup.h>
+static unsigned long segment_pos __initdata;
+static unsigned long segment_low __initdata;
static unsigned long pgalloc_pos __initdata;
static unsigned long pgalloc_low __initdata;
+static bool has_edat __initdata;
+static bool has_nx __initdata;
#define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x))
disabled_wait(0);
}
+static void * __init kasan_early_alloc_segment(void)
+{
+ segment_pos -= _SEGMENT_SIZE;
+
+ if (segment_pos < segment_low)
+ kasan_early_panic("out of memory during initialisation\n");
+
+ return (void *)segment_pos;
+}
+
static void * __init kasan_early_alloc_pages(unsigned int order)
{
pgalloc_pos -= (PAGE_SIZE << order);
unsigned long end,
enum populate_mode mode)
{
- unsigned long pgt_prot_zero, pgt_prot;
+ unsigned long pgt_prot_zero, pgt_prot, sgt_prot;
pgd_t *pg_dir;
p4d_t *p4_dir;
pud_t *pu_dir;
pte_t *pt_dir;
pgt_prot_zero = pgprot_val(PAGE_KERNEL_RO);
- pgt_prot_zero &= ~_PAGE_NOEXEC;
+ if (!has_nx)
+ pgt_prot_zero &= ~_PAGE_NOEXEC;
pgt_prot = pgprot_val(PAGE_KERNEL_EXEC);
+ sgt_prot = pgprot_val(SEGMENT_KERNEL_EXEC);
while (address < end) {
pg_dir = pgd_offset_k(address);
address = (address + PMD_SIZE) & PMD_MASK;
continue;
}
+ /* the first megabyte of 1:1 is mapped with 4k pages */
+ if (has_edat && address && end - address >= PMD_SIZE &&
+ mode != POPULATE_ZERO_SHADOW) {
+ void *page;
+
+ if (mode == POPULATE_ONE2ONE) {
+ page = (void *)address;
+ } else {
+ page = kasan_early_alloc_segment();
+ memset(page, 0, _SEGMENT_SIZE);
+ }
+ pmd_val(*pm_dir) = __pa(page) | sgt_prot;
+ address = (address + PMD_SIZE) & PMD_MASK;
+ continue;
+ }
+
pt_dir = kasan_early_pte_alloc();
pmd_populate(&init_mm, pm_dir, pt_dir);
+ } else if (pmd_large(*pm_dir)) {
+ address = (address + PMD_SIZE) & PMD_MASK;
+ continue;
}
pt_dir = pte_offset_kernel(pm_dir, address);
__load_psw_mask(psw.mask);
}
+static void __init kasan_early_detect_facilities(void)
+{
+ stfle(S390_lowcore.stfle_fac_list,
+ ARRAY_SIZE(S390_lowcore.stfle_fac_list));
+ if (test_facility(8)) {
+ has_edat = true;
+ __ctl_set_bit(0, 23);
+ }
+ if (!noexec_disabled && test_facility(130)) {
+ has_nx = true;
+ __ctl_set_bit(0, 20);
+ }
+}
+
void __init kasan_early_init(void)
{
unsigned long untracked_mem_end;
pud_t pud_z = __pud(__pa(kasan_zero_pmd) | _REGION3_ENTRY);
p4d_t p4d_z = __p4d(__pa(kasan_zero_pud) | _REGION2_ENTRY);
- pgt_prot &= ~_PAGE_NOEXEC;
+ kasan_early_detect_facilities();
+ if (!has_nx)
+ pgt_prot &= ~_PAGE_NOEXEC;
pte_z = __pte(__pa(kasan_zero_page) | pgt_prot);
/* 3 level paging */
if (pgalloc_low + shadow_alloc_size > memsize)
kasan_early_panic("out of memory during initialisation\n");
- pgalloc_pos = memsize;
+ if (has_edat) {
+ segment_pos = round_down(memsize, _SEGMENT_SIZE);
+ segment_low = segment_pos - shadow_alloc_size;
+ pgalloc_pos = segment_low;
+ } else {
+ pgalloc_pos = memsize;
+ }
init_mm.pgd = early_pg_dir;
/*
* Current memory layout: