xref: /netbsd-src/sys/arch/m68k/m68k/db_memrw.c (revision 4aa16837d6c5a854ea7598ac4deb33c3d4a4f074)
1 /*	$NetBSD: db_memrw.c,v 1.8 2023/09/26 12:46:30 tsutsui Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Gordon W. Ross and Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*
32  * Mach Operating System
33  * Copyright (c) 1992 Carnegie Mellon University
34  * All Rights Reserved.
35  *
36  * Permission to use, copy, modify and distribute this software and its
37  * documentation is hereby granted, provided that both the copyright
38  * notice and this permission notice appear in all copies of the
39  * software, derivative works or modified versions, and any portions
40  * thereof, and that both notices appear in supporting documentation.
41  *
42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45  *
46  * Carnegie Mellon requests users of this software to return to
47  *
48  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
49  *  School of Computer Science
50  *  Carnegie Mellon University
51  *  Pittsburgh PA 15213-3890
52  *
53  * any improvements or extensions that they make and grant Carnegie Mellon
54  * the rights to redistribute these changes.
55  */
56 
57 /*
58  * Interface to the debugger for virtual memory read/write.
59  * This file is shared by DDB and KGDB, and must work even
60  * when only KGDB is included (thus no db_printf calls).
61  *
62  * To write in the text segment, we have to first make
63  * the page writable, do the write, then restore the PTE.
64  * For writes outside the text segment, and all reads,
65  * just do the access -- if it causes a fault, the debugger
66  * will recover with a longjmp to an appropriate place.
67  *
68  * ALERT!  If you want to access device registers with a
69  * specific size, then the read/write functions have to
70  * make sure to do the correct sized pointer access.
71  */
72 
73 #include <sys/cdefs.h>
74 __KERNEL_RCSID(0, "$NetBSD: db_memrw.c,v 1.8 2023/09/26 12:46:30 tsutsui Exp $");
75 
76 #include <sys/param.h>
77 
78 #include <machine/cpu.h>
79 #include <m68k/cacheops.h>
80 #include <uvm/uvm_extern.h>
81 
82 #include <machine/db_machdep.h>
83 #include <ddb/db_access.h>
84 
85 /*
86  * Read bytes from kernel address space for debugger.
87  */
88 void
db_read_bytes(db_addr_t addr,size_t size,char * data)89 db_read_bytes(db_addr_t addr, size_t size, char *data)
90 {
91 	char *src = (char *)addr;
92 
93 	if (size == 4) {
94 		*((uint32_t *)data) = *((uint32_t *)src);
95 		return;
96 	}
97 
98 	if (size == 2) {
99 		*((uint16_t *)data) = *((uint16_t *)src);
100 		return;
101 	}
102 
103 	while (size-- > 0) {
104 		*data++ = *src++;
105 	}
106 }
107 
108 static void
db_write_text(db_addr_t addr,size_t size,const char * data)109 db_write_text(db_addr_t addr, size_t size, const char *data)
110 {
111 	char *dst, *odst;
112 	pt_entry_t *pte, oldpte, tmppte;
113 	vaddr_t pgva;
114 	int limit;
115 
116 	dst = (char *)addr;
117 	while (size > 0) {
118 
119 		/*
120 		 * Get the VA for the page.
121 		 */
122 		pgva = trunc_page((vaddr_t)dst);
123 
124 		/*
125 		 * Save this destination address, for TLB flush.
126 		 */
127 		odst = dst;
128 
129 		/*
130 		 * Compute number of bytes that can be written
131 		 * with this mapping and subtract it from the total size.
132 		 */
133 		limit = round_page((vaddr_t)dst + 1) - (vaddr_t)dst;
134 		if (limit > size)
135 			limit = size;
136 		size -= limit;
137 
138 #ifdef M68K_MMU_HP
139 		/*
140 		 * Flush the supervisor side of the VAC to
141 		 * prevent a cache hit on the old, read-only PTE.
142 		 */
143 		if (ectype == EC_VIRT)
144 			DCIS();
145 #endif
146 
147 		/*
148 		 * Make the page writable.  Note the mapping is
149 		 * cache-inhibited to save hair.
150 		 */
151 		pte = kvtopte(pgva);
152 		oldpte = *pte;
153 		if ((oldpte & PG_V) == 0) {
154 			printf(" address %p not a valid page\n", dst);
155 			return;
156 		}
157 		tmppte = (oldpte & ~PG_RO) | PG_RW | PG_CI;
158 		*pte = tmppte;
159 		TBIS((vaddr_t)odst);
160 
161 		/*
162 		 * Page is now writable.  Do as much access as we can.
163 		 */
164 		for (; limit > 0; limit--)
165 			*dst++ = *data++;
166 
167 		/*
168 		 * Restore the old PTE.
169 		 */
170 		*pte = oldpte;
171 		TBIS((vaddr_t)odst);
172 	}
173 
174 	/*
175 	 * Invalidate the instruction cache so our changes take effect.
176 	 */
177 	ICIA();
178 }
179 
180 /*
181  * Write bytes to kernel address space for debugger.
182  */
183 void
db_write_bytes(db_addr_t addr,size_t size,const char * data)184 db_write_bytes(db_addr_t addr, size_t size, const char *data)
185 {
186 	char *dst = (char *)addr;
187 	extern char kernel_text[], etext[];
188 
189 	/* If any part is in kernel text, use db_write_text() */
190 	if (dst + size > kernel_text && dst < etext) {
191 		db_write_text(addr, size, data);
192 		return;
193 	}
194 
195 	if (size == 4) {
196 		*((uint32_t *)dst) = *((const uint32_t *)data);
197 		return;
198 	}
199 
200 	if (size == 2) {
201 		*((uint16_t *)dst) = *((const uint16_t *)data);
202 		return;
203 	}
204 
205 	while (size-- > 0) {
206 		*dst++ = *data++;
207 	}
208 }
209