@@ -51,6 +51,12 @@ static void fixup_pgm_int(void)
*/
lc->pgm_old_psw.mask &= ~PSW_MASK_PSTATE;
break;
+ case PGM_INT_CODE_PROTECTION:
+ /* Handling for iep.c test case. */
+ if (lc->trans_exc_id & 0x80UL && lc->trans_exc_id & 0x04UL &&
+ !(lc->trans_exc_id & 0x08UL))
+ lc->pgm_old_psw.addr = lc->sw_int_grs[14];
+ break;
case PGM_INT_CODE_SEGMENT_TRANSLATION:
case PGM_INT_CODE_PAGE_TRANSLATION:
case PGM_INT_CODE_TRACE_TABLE:
@@ -16,6 +16,8 @@
#include <asm/barrier.h>
#include <vmalloc.h>
+static pgd_t *table_root;
+
void configure_dat(int enable)
{
uint64_t mask;
@@ -62,7 +64,7 @@ phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *vaddr)
((unsigned long)vaddr & ~PAGE_MASK);
}
-pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr)
+static pteval_t *set_pte(pgd_t *pgtable, pteval_t val, void *vaddr)
{
pteval_t *p_pte = get_pte(pgtable, (uintptr_t)vaddr);
@@ -70,10 +72,49 @@ pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr)
if (!(*p_pte & PAGE_ENTRY_I))
ipte((uintptr_t)vaddr, p_pte);
- *p_pte = __pa(phys);
+ *p_pte = val;
return p_pte;
}
+pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr)
+{
+ return set_pte(pgtable, __pa(phys), vaddr);
+}
+
+void protect_page(void *vaddr, unsigned long prot)
+{
+ pteval_t *p_pte = get_pte(table_root, (uintptr_t)vaddr);
+ pteval_t n_pte = *p_pte | prot;
+
+ set_pte(table_root, n_pte, vaddr);
+}
+
+void unprotect_page(void *vaddr, unsigned long prot)
+{
+ pteval_t *p_pte = get_pte(table_root, (uintptr_t)vaddr);
+ pteval_t n_pte = *p_pte & ~prot;
+
+ set_pte(table_root, n_pte, vaddr);
+}
+
+void protect_range(void *start, unsigned long len, unsigned long prot)
+{
+ uintptr_t curr = (uintptr_t)start & PAGE_MASK;
+
+ len &= PAGE_MASK;
+ for (; len; len -= PAGE_SIZE, curr += PAGE_SIZE)
+ protect_page((void *)curr, prot);
+}
+
+void unprotect_range(void *start, unsigned long len, unsigned long prot)
+{
+ uintptr_t curr = (uintptr_t)start & PAGE_MASK;
+
+ len &= PAGE_MASK;
+ for (; len; len -= PAGE_SIZE, curr += PAGE_SIZE)
+ unprotect_page((void *)curr, prot);
+}
+
static void setup_identity(pgd_t *pgtable, phys_addr_t start_addr,
phys_addr_t end_addr)
{
@@ -104,5 +145,6 @@ void *setup_mmu(phys_addr_t phys_end){
/* finally enable DAT with the new table */
mmu_enable(page_root);
+ table_root = page_root;
return page_root;
}
new file mode 100644
@@ -0,0 +1,20 @@
+/*
+ * s390x mmu functions
+ *
+ * Copyright (c) 2018 IBM Corp
+ *
+ * Authors:
+ * Janosch Frank <frankja@de.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+#ifndef _ASMS390X_MMU_H_
+#define _ASMS390X_MMU_H_
+
+void protect_page(void *vaddr, unsigned long prot);
+void protect_range(void *start, unsigned long len, unsigned long prot);
+void unprotect_page(void *vaddr, unsigned long prot);
+void unprotect_range(void *start, unsigned long len, unsigned long prot);
+
+#endif /* _ASMS390X_MMU_H_ */
@@ -9,6 +9,7 @@ tests += $(TEST_DIR)/pfmf.elf
tests += $(TEST_DIR)/cmm.elf
tests += $(TEST_DIR)/vector.elf
tests += $(TEST_DIR)/gs.elf
+tests += $(TEST_DIR)/iep.elf
all: directories test_cases
new file mode 100644
@@ -0,0 +1,62 @@
+/*
+ * Instruction Execution Prevention (IEP) DAT test.
+ *
+ * Copyright (c) 2018 IBM Corp
+ *
+ * Authors:
+ * Janosch Frank <frankja@de.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+#include <libcflat.h>
+#include <vmalloc.h>
+#include <asm/facility.h>
+#include <asm/interrupt.h>
+#include <mmu.h>
+#include <asm/pgtable.h>
+#include <asm-generic/barrier.h>
+
+static void test_iep(void)
+{
+ uint16_t *code;
+ uint8_t *iepbuf = NULL;
+ void (*fn)(void);
+
+ /* Enable IEP */
+ ctl_set_bit(0, 20);
+
+ /* Get and protect a page with the IEP bit */
+ iepbuf = alloc_page();
+ protect_page(iepbuf, PAGE_ENTRY_IEP);
+
+ /* Code branches into r14 which contains the return address. */
+ code = (uint16_t *)iepbuf;
+ *code = 0x07fe;
+ fn = (void *)code;
+
+ expect_pgm_int();
+ /* Jump into protected page */
+ fn();
+ check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+ unprotect_page(iepbuf, PAGE_ENTRY_IEP);
+ ctl_clear_bit(0, 20);
+}
+
+int main(void)
+{
+ bool has_iep = test_facility(130);
+
+ report_prefix_push("iep");
+ report_xfail("DAT IEP available", !has_iep, has_iep);
+ if (!has_iep)
+ goto done;
+
+ /* Setup DAT 1:1 mapping and memory management */
+ setup_vm();
+ test_iep();
+
+done:
+ report_prefix_pop();
+ return report_summary();
+}
@@ -55,3 +55,6 @@ file = vector.elf
[gs]
file = gs.elf
+
+[iep]
+file = iep.elf