1/*	$OpenBSD: db_memrw.c,v 1.19 2024/02/23 18:19:03 cheloha Exp $	*/
2/*	$NetBSD: db_memrw.c,v 1.6 1999/04/12 20:38:19 pk Exp $	*/
3
4/*
5 * Mach Operating System
6 * Copyright (c) 1991,1990 Carnegie Mellon University
7 * All Rights Reserved.
8 *
9 * Permission to use, copy, modify and distribute this software and its
10 * documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22 *  School of Computer Science
23 *  Carnegie Mellon University
24 *  Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie Mellon
27 * the rights to redistribute these changes.
28 *
29 *	db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
30 */
31
32/*
33 * Routines to read and write memory on behalf of the debugger, used
34 * by DDB.
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39
40#include <uvm/uvm_extern.h>
41
42#include <machine/db_machdep.h>
43
44#include <ddb/db_access.h>
45
46#define PG_LGFRAME	0xffc00000	/* large (4M) page frame mask */
47#define PG_LGFRAME_PAE	0xffe00000	/* large (2M) page frame mask */
48
49/*
50 * Read bytes from kernel address space for debugger.
51 */
52void
53db_read_bytes(vaddr_t addr, size_t size, void *datap)
54{
55	char *data = datap, *src;
56
57	src = (char *)addr;
58	while (size-- > 0)
59		*data++ = *src++;
60}
61
62/*
63 * Write bytes somewhere in the kernel text.  Make the text
64 * pages writable temporarily.
65 */
66static void
67db_write_text(vaddr_t addr, size_t size, char *data)
68{
69	vaddr_t pgva;
70	size_t limit;
71	uint32_t bits;
72	char *dst;
73
74	if (size == 0)
75		return;
76
77	dst = (char *)addr;
78
79	do {
80		/*
81		 * Get the PTE for the page.
82		 */
83		bits = pmap_pte_bits(addr);
84
85		if ((bits & PG_V) == 0) {
86			printf(" address %p not a valid page\n", dst);
87			return;
88		}
89
90		/*
91		 * Get the VA for the page.
92		 */
93		if (bits & PG_PS) {
94			if (cpu_pae)
95				pgva = (vaddr_t)dst & PG_LGFRAME_PAE;
96			else
97				pgva = (vaddr_t)dst & PG_LGFRAME;
98		 } else
99			pgva = trunc_page((vaddr_t)dst);
100
101		/*
102		 * Compute number of bytes that can be written
103		 * with this mapping and subtract it from the
104		 * total size.
105		 */
106#ifdef NBPD_L2
107		if (bits & PG_PS)
108			limit = NBPD_L2 - ((vaddr_t)dst & (NBPD_L2 - 1));
109		else
110#endif
111			limit = PAGE_SIZE - ((vaddr_t)dst & PGOFSET);
112		if (limit > size)
113			limit = size;
114		size -= limit;
115
116		pmap_update_pg(pgva);
117		pmap_pte_setbits(addr, PG_RW, 0);
118
119		/*
120		 * Page is now writable.  Do as much access as we
121		 * can in this page.
122		 */
123		for (; limit > 0; limit--)
124			*dst++ = *data++;
125
126		/*
127		 * Restore the old PTE.
128		 */
129		pmap_update_pg(pgva);
130		pmap_pte_setbits(addr, bits, PG_RW);
131
132	} while (size != 0);
133}
134
135/*
136 * Write bytes to kernel address space for debugger.
137 */
138void
139db_write_bytes(vaddr_t addr, size_t size, void *datap)
140{
141	char *data = datap, *dst;
142	extern char	etext;
143
144	if (addr >= VM_MIN_KERNEL_ADDRESS &&
145	    addr < (vaddr_t)&etext) {
146		db_write_text(addr, size, data);
147		return;
148	}
149
150	dst = (char *)addr;
151
152	while (size-- > 0)
153		*dst++ = *data++;
154}
155