xref: /openbsd-src/sys/arch/amd64/amd64/db_memrw.c (revision fe1fe620f8418f588086cadfe1b03bb5d224b548)
1 /*	$OpenBSD: db_memrw.c,v 1.9 2024/02/23 18:19:02 cheloha Exp $	*/
2 /*	$NetBSD: db_memrw.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $	*/
3 
4 /*-
5  * Copyright (c) 1996, 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Gordon W. Ross and Jason R. Thorpe.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Interface to the debugger for virtual memory read/write.
35  *
36  * To write in the text segment, we have to first make
37  * the page writable, do the write, then restore the PTE.
38  * For writes outside the text segment, and all reads,
39  * just do the access -- if it causes a fault, the debugger
40  * will recover with a longjmp to an appropriate place.
41  *
42  * ALERT!  If you want to access device registers with a
43  * specific size, then the read/write functions have to
44  * make sure to do the correct sized pointer access.
45  *
46  * Modified for i386 from hp300 version by
47  * Jason R. Thorpe <thorpej@zembu.com>.
48  *
49  * Basic copy to amd64 by fvdl.
50  */
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 
55 #include <uvm/uvm_extern.h>
56 
57 #include <machine/db_machdep.h>
58 
59 /*
60  * Read bytes from kernel address space for debugger.
61  */
62 void
db_read_bytes(vaddr_t addr,size_t size,void * datap)63 db_read_bytes(vaddr_t addr, size_t size, void *datap)
64 {
65 	char *data = datap, *src;
66 
67 	src = (char *)addr;
68 
69 	if (size == 8) {
70 		*((long *)data) = *((long *)src);
71 		return;
72 	}
73 
74 	if (size == 4) {
75 		*((int *)data) = *((int *)src);
76 		return;
77 	}
78 
79 	if (size == 2) {
80 		*((short *)data) = *((short *)src);
81 		return;
82 	}
83 
84 	while (size-- > 0)
85 		*data++ = *src++;
86 }
87 
88 /*
89  * Write bytes somewhere in the kernel text.  Make the text
90  * pages writable temporarily.
91  */
92 static void
db_write_text(vaddr_t addr,size_t size,char * data)93 db_write_text(vaddr_t addr, size_t size, char *data)
94 {
95 	pt_entry_t *pte, oldpte, tmppte;
96 	vaddr_t pgva;
97 	size_t limit;
98 	char *dst;
99 
100 	if (size == 0)
101 		return;
102 
103 	dst = (char *)addr;
104 
105 	do {
106 		/*
107 		 * Get the PTE for the page.
108 		 */
109 		pte = kvtopte(addr);
110 		oldpte = *pte;
111 
112 		if ((oldpte & PG_V) == 0) {
113 			printf(" address %p not a valid page\n", dst);
114 			return;
115 		}
116 
117 		/*
118 		 * Get the VA for the page.
119 		 */
120 		if (oldpte & PG_PS)
121 			pgva = (vaddr_t)dst & PG_LGFRAME;
122 		else
123 			pgva = trunc_page((vaddr_t)dst);
124 
125 		/*
126 		 * Compute number of bytes that can be written
127 		 * with this mapping and subtract it from the
128 		 * total size.
129 		 */
130 		if (oldpte & PG_PS)
131 			limit = NBPD_L2 - ((vaddr_t)dst & (NBPD_L2 - 1));
132 		else
133 			limit = PAGE_SIZE - ((vaddr_t)dst & PGOFSET);
134 		if (limit > size)
135 			limit = size;
136 		size -= limit;
137 
138 		tmppte = (oldpte & ~PG_KR) | PG_KW;
139 		*pte = tmppte;
140 		pmap_update_pg(pgva);
141 
142 		/*
143 		 * Page is now writable.  Do as much access as we
144 		 * can in this page.
145 		 */
146 		for (; limit > 0; limit--)
147 			*dst++ = *data++;
148 
149 		/*
150 		 * Restore the old PTE.
151 		 */
152 		*pte = oldpte;
153 
154 		pmap_update_pg(pgva);
155 
156 	} while (size != 0);
157 }
158 
159 /*
160  * Write bytes to kernel address space for debugger.
161  */
162 void
db_write_bytes(vaddr_t addr,size_t size,void * datap)163 db_write_bytes(vaddr_t addr, size_t size, void *datap)
164 {
165 	extern char etext;
166 	char *data = datap, *dst;
167 
168 	/* If any part is in kernel text, use db_write_text() */
169 	if (addr >= KERNBASE && addr < (vaddr_t)&etext) {
170 		db_write_text(addr, size, data);
171 		return;
172 	}
173 
174 	dst = (char *)addr;
175 
176 	if (size == 8) {
177 		*((long *)dst) = *((long *)data);
178 		return;
179 	}
180 
181 	if (size == 4) {
182 		*((int *)dst) = *((int *)data);
183 		return;
184 	}
185 
186 	if (size == 2) {
187 		*((short *)dst) = *((short *)data);
188 		return;
189 	}
190 
191 	while (size-- > 0)
192 		*dst++ = *data++;
193 }
194