Module Name:    src
Committed By:   ryo
Date:           Mon Aug  6 12:50:56 UTC 2018

Modified Files:
        src/sys/arch/aarch64/aarch64: db_interface.c locore.S pmap.c
        src/sys/arch/aarch64/include: pmap.h

Log Message:
set kernel text/rodata readonly by default.
add function db_write_text() for setting ddb breakpoint.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/aarch64/aarch64/db_interface.c
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/aarch64/aarch64/locore.S
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/aarch64/aarch64/pmap.c
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/aarch64/include/pmap.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/aarch64/aarch64/db_interface.c
diff -u src/sys/arch/aarch64/aarch64/db_interface.c:1.4 src/sys/arch/aarch64/aarch64/db_interface.c:1.5
--- src/sys/arch/aarch64/aarch64/db_interface.c:1.4	Sun Jun  3 20:18:10 2018
+++ src/sys/arch/aarch64/aarch64/db_interface.c	Mon Aug  6 12:50:56 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: db_interface.c,v 1.4 2018/06/03 20:18:10 christos Exp $ */
+/* $NetBSD: db_interface.c,v 1.5 2018/08/06 12:50:56 ryo Exp $ */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -27,16 +27,18 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.4 2018/06/03 20:18:10 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.5 2018/08/06 12:50:56 ryo Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <uvm/uvm.h>
+#include <uvm/uvm_prot.h>
 
 #include <aarch64/db_machdep.h>
 #include <aarch64/machdep.h>
 #include <aarch64/pmap.h>
+#include <aarch64/cpufunc.h>
 
 #include <ddb/db_access.h>
 #include <ddb/db_command.h>
@@ -88,12 +90,74 @@ db_read_bytes(vaddr_t addr, size_t size,
 	}
 }
 
+static void
+db_write_text(vaddr_t addr, size_t size, const char *data)
+{
+	pt_entry_t *ptep, pte;
+	size_t s;
+
+	/*
+	 * consider page boundary, and
+	 * it works even if kernel_text is mapped with L2 or L3.
+	 */
+	if (atop(addr) != atop(addr + size - 1)) {
+		s = PAGE_SIZE - (addr & PAGE_MASK);
+		db_write_text(addr, s, data);
+		addr += s;
+		size -= s;
+		data += s;
+	}
+	while (size > 0) {
+		ptep = kvtopte(addr);
+		KASSERT(ptep != NULL);
+
+		/* save pte */
+		pte = *ptep;
+
+		/* change to writable */
+		pmap_kvattr(addr, VM_PROT_READ|VM_PROT_WRITE);
+		aarch64_tlbi_all();
+
+		s = size;
+		if (size > PAGE_SIZE)
+			s = PAGE_SIZE;
+
+		memcpy((void *)addr, data, s);
+		cpu_icache_sync_range(addr, size);
+
+		/* restore pte */
+		*ptep = pte;
+		aarch64_tlbi_all();
+
+		addr += s;
+		size -= s;
+		data += s;
+	}
+}
+
 void
 db_write_bytes(vaddr_t addr, size_t size, const char *data)
 {
+	vaddr_t kernstart, datastart;
 	vaddr_t lastpage = -1;
 	char *dst;
 
+	/* if readonly page, require changing attribute to write */
+	extern char __kernel_text[], __data_start[];
+	kernstart = trunc_page((vaddr_t)__kernel_text);
+	datastart = trunc_page((vaddr_t)__data_start);
+	if (kernstart <= addr && addr < datastart) {
+		size_t s;
+
+		s = datastart - addr;
+		if (s > size)
+			s = size;
+		db_write_text(addr, s, data);
+		addr += s;
+		size -= s;
+		data += s;
+	}
+
 	/* XXX: need to check read only block/page */
 	for (dst = (char *)addr; size > 0;) {
 		uintptr_t tmp;

Index: src/sys/arch/aarch64/aarch64/locore.S
diff -u src/sys/arch/aarch64/aarch64/locore.S:1.14 src/sys/arch/aarch64/aarch64/locore.S:1.15
--- src/sys/arch/aarch64/aarch64/locore.S:1.14	Fri Aug  3 16:32:55 2018
+++ src/sys/arch/aarch64/aarch64/locore.S	Mon Aug  6 12:50:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: locore.S,v 1.14 2018/08/03 16:32:55 ryo Exp $	*/
+/*	$NetBSD: locore.S,v 1.15 2018/08/06 12:50:56 ryo Exp $	*/
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -35,7 +35,7 @@
 #include <aarch64/hypervisor.h>
 #include "assym.h"
 
-RCSID("$NetBSD: locore.S,v 1.14 2018/08/03 16:32:55 ryo Exp $")
+RCSID("$NetBSD: locore.S,v 1.15 2018/08/06 12:50:56 ryo Exp $")
 
 /* #define DEBUG_LOCORE */
 /* #define DEBUG_MMU */
@@ -650,7 +650,6 @@ arm_boot_l0pt_init:
 	lsr	x4, x4, #L2_SHIFT
 	bl	l2_setblocks
 
-#ifndef DDB
 	/* map READONLY from VM_MIN_KERNEL_ADDRESS to __data_start */
 	VERBOSE("Set kernel text/rodata READONLY\r\n")
 	ldr	x3, =__data_start
@@ -684,7 +683,6 @@ arm_boot_l0pt_init:
 9:
 	cmp	x2, x3
 	blo	1b
-#endif
 
 	VERBOSE("Creating devmap tables\r\n")
 	/* devmap=PA table for L1 */

Index: src/sys/arch/aarch64/aarch64/pmap.c
diff -u src/sys/arch/aarch64/aarch64/pmap.c:1.16 src/sys/arch/aarch64/aarch64/pmap.c:1.17
--- src/sys/arch/aarch64/aarch64/pmap.c:1.16	Tue Jul 31 07:00:48 2018
+++ src/sys/arch/aarch64/aarch64/pmap.c	Mon Aug  6 12:50:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.16 2018/07/31 07:00:48 skrll Exp $	*/
+/*	$NetBSD: pmap.c,v 1.17 2018/08/06 12:50:56 ryo Exp $	*/
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.16 2018/07/31 07:00:48 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.17 2018/08/06 12:50:56 ryo Exp $");
 
 #include "opt_arm_debug.h"
 #include "opt_ddb.h"
@@ -1990,6 +1990,90 @@ pmap_is_referenced(struct vm_page *pg)
 }
 
 #ifdef DDB
+/* get pointer to kernel segment L2 or L3 table entry */
+pt_entry_t *
+kvtopte(vaddr_t va)
+{
+	pd_entry_t *l0, *l1, *l2, *l3;
+	pd_entry_t pde;
+	pt_entry_t *ptep;
+	unsigned int idx;
+
+	KASSERT(VM_MIN_KERNEL_ADDRESS <= va && va < VM_MAX_KERNEL_ADDRESS);
+
+	/*
+	 * traverse L0 -> L1 -> L2 block (or -> L3 table)
+	 */
+	l0 = pmap_kernel()->pm_l0table;
+
+	idx = l0pde_index(va);
+	pde = l0[idx];
+	if (!l0pde_valid(pde))
+		return NULL;
+
+	l1 = (void *)AARCH64_PA_TO_KVA(l0pde_pa(pde));
+	idx = l1pde_index(va);
+	pde = l1[idx];
+	if (!l1pde_valid(pde))
+		return NULL;
+
+	if (l1pde_is_block(pde))
+		return NULL;
+
+	l2 = (void *)AARCH64_PA_TO_KVA(l1pde_pa(pde));
+	idx = l2pde_index(va);
+	pde = l2[idx];
+	if (!l2pde_valid(pde))
+		return NULL;
+	if (l2pde_is_block(pde))
+		return &l2[idx];	/* kernel text/data use L2 blocks */
+
+	l3 = (void *)AARCH64_PA_TO_KVA(l2pde_pa(pde));
+	idx = l3pte_index(va);
+	ptep = &l3[idx];		/* or may use L3 page? */
+
+	return ptep;
+}
+
+/* change attribute of kernel segment */
+pt_entry_t
+pmap_kvattr(vaddr_t va, vm_prot_t prot)
+{
+	pt_entry_t *ptep, pte, opte;
+
+	KASSERT(VM_MIN_KERNEL_ADDRESS <= va && va < VM_MAX_KERNEL_ADDRESS);
+
+	ptep = kvtopte(va);
+	if (ptep == NULL)
+		panic("%s: %016lx is not mapped\n", __func__, va);
+
+	opte = pte = *ptep;
+
+	pte &= ~(LX_BLKPAG_AF|LX_BLKPAG_AP);
+	switch (prot & (VM_PROT_READ|VM_PROT_WRITE)) {
+	case 0:
+		break;
+	case VM_PROT_READ:
+		pte |= (LX_BLKPAG_AF|LX_BLKPAG_AP_RO);
+		break;
+	case VM_PROT_WRITE:
+	case VM_PROT_READ|VM_PROT_WRITE:
+		pte |= (LX_BLKPAG_AF|LX_BLKPAG_AP_RW);
+		break;
+	}
+
+	if ((prot & VM_PROT_EXECUTE) == 0) {
+		pte |= (LX_BLKPAG_UXN|LX_BLKPAG_PXN);
+	} else {
+		pte |= LX_BLKPAG_AF;
+		pte &= ~(LX_BLKPAG_UXN|LX_BLKPAG_PXN);
+	}
+
+	*ptep = pte;
+
+	return opte;
+}
+
 static void
 pmap_db_pte_print(pt_entry_t pte, int level, void (*pr)(const char *, ...))
 {

Index: src/sys/arch/aarch64/include/pmap.h
diff -u src/sys/arch/aarch64/include/pmap.h:1.6 src/sys/arch/aarch64/include/pmap.h:1.7
--- src/sys/arch/aarch64/include/pmap.h:1.6	Fri Jul 27 07:04:04 2018
+++ src/sys/arch/aarch64/include/pmap.h	Mon Aug  6 12:50:56 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.6 2018/07/27 07:04:04 ryo Exp $ */
+/* $NetBSD: pmap.h,v 1.7 2018/08/06 12:50:56 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -107,7 +107,11 @@ struct vm_page_md {
 
 void pmap_bootstrap(vaddr_t, vaddr_t);
 bool pmap_fault_fixup(struct pmap *, vaddr_t, vm_prot_t, bool user);
+
+/* for ddb */
 void pmap_db_pteinfo(vaddr_t, void (*)(const char *, ...));
+pt_entry_t *kvtopte(vaddr_t);
+pt_entry_t pmap_kvattr(vaddr_t, vm_prot_t);
 
 /* Hooks for the pool allocator */
 paddr_t vtophys(vaddr_t);

Reply via email to