db_memrw.c revision 1.12 1 1.12 gwr /* $NetBSD: db_memrw.c,v 1.12 1996/06/17 15:40:48 gwr Exp $ */
2 1.1 gwr
3 1.1 gwr /*
4 1.9 gwr * Copyright (c) 1996 Gordon W. Ross
5 1.1 gwr * All rights reserved.
6 1.1 gwr *
7 1.1 gwr * Redistribution and use in source and binary forms, with or without
8 1.1 gwr * modification, are permitted provided that the following conditions
9 1.1 gwr * are met:
10 1.1 gwr * 1. Redistributions of source code must retain the above copyright
11 1.1 gwr * notice, this list of conditions and the following disclaimer.
12 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 gwr * notice, this list of conditions and the following disclaimer in the
14 1.1 gwr * documentation and/or other materials provided with the distribution.
15 1.1 gwr * 3. The name of the author may not be used to endorse or promote products
16 1.1 gwr * derived from this software without specific prior written permission.
17 1.1 gwr *
18 1.1 gwr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 1.1 gwr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 1.1 gwr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 1.1 gwr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 1.1 gwr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 1.1 gwr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 1.1 gwr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 1.1 gwr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 1.1 gwr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 1.1 gwr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1 gwr */
29 1.1 gwr
30 1.1 gwr /*
31 1.9 gwr * Interface to the debugger for virtual memory read/write.
32 1.12 gwr * This file is shared by DDB and KGDB, and must work even
33 1.12 gwr * when only KGDB is included (thus no db_printf calls).
34 1.9 gwr *
35 1.9 gwr * To write in the text segment, we have to first make
36 1.9 gwr * the page writable, do the write, then restore the PTE.
37 1.9 gwr * For writes outside the text segment, and all reads,
38 1.9 gwr * just do the access -- if it causes a fault, the debugger
39 1.9 gwr * will recover with a longjmp to an appropriate place.
40 1.9 gwr *
41 1.9 gwr * ALERT! If you want to access device registers with a
42 1.9 gwr * specific size, then the read/write functions have to
43 1.9 gwr * make sure to do the correct sized pointer access.
44 1.1 gwr */
45 1.1 gwr
46 1.1 gwr #include <sys/param.h>
47 1.1 gwr #include <sys/proc.h>
48 1.1 gwr
49 1.1 gwr #include <vm/vm.h>
50 1.1 gwr
51 1.10 gwr #include <machine/pte.h>
52 1.1 gwr #include <machine/db_machdep.h>
53 1.10 gwr
54 1.10 gwr #include <ddb/db_access.h>
55 1.1 gwr
56 1.9 gwr #include "cache.h"
57 1.7 gwr
58 1.7 gwr /*
59 1.3 gwr * Read bytes from kernel address space for debugger.
60 1.5 gwr * This used to check for valid PTEs, but now that
61 1.5 gwr * traps in DDB work correctly, "Just Do It!"
62 1.3 gwr */
63 1.3 gwr void
64 1.3 gwr db_read_bytes(addr, size, data)
65 1.3 gwr vm_offset_t addr;
66 1.10 gwr register size_t size;
67 1.3 gwr register char *data;
68 1.3 gwr {
69 1.9 gwr register char *src = (char*)addr;
70 1.9 gwr
71 1.9 gwr if (size == 4) {
72 1.9 gwr *((int*)data) = *((int*)src);
73 1.9 gwr return;
74 1.9 gwr }
75 1.9 gwr
76 1.9 gwr if (size == 2) {
77 1.9 gwr *((short*)data) = *((short*)src);
78 1.9 gwr return;
79 1.9 gwr }
80 1.3 gwr
81 1.11 gwr while (size > 0) {
82 1.11 gwr --size;
83 1.5 gwr *data++ = *src++;
84 1.11 gwr }
85 1.3 gwr }
86 1.3 gwr
87 1.3 gwr /*
88 1.9 gwr * Write bytes somewhere in kernel text.
89 1.9 gwr * Makes text page writable temporarily.
90 1.1 gwr */
91 1.1 gwr static void
92 1.9 gwr db_write_text(addr, size, data)
93 1.9 gwr vm_offset_t addr;
94 1.10 gwr register size_t size;
95 1.9 gwr register char *data;
96 1.1 gwr {
97 1.9 gwr register char *dst;
98 1.9 gwr int ch, oldpte, tmppte;
99 1.9 gwr vm_offset_t pgva, prevpg;
100 1.9 gwr
101 1.9 gwr /* Prevent restoring a garbage PTE. */
102 1.9 gwr if (size <= 0)
103 1.9 gwr return;
104 1.1 gwr
105 1.9 gwr dst = (char*)addr;
106 1.1 gwr pgva = sun3_trunc_page((long)dst);
107 1.1 gwr
108 1.9 gwr goto firstpage;
109 1.9 gwr do {
110 1.9 gwr
111 1.9 gwr /*
112 1.9 gwr * If we are on a new page, restore the PTE
113 1.9 gwr * for the previous page, and make the new
114 1.9 gwr * page writable.
115 1.9 gwr */
116 1.9 gwr pgva = sun3_trunc_page((long)dst);
117 1.9 gwr if (pgva != prevpg) {
118 1.9 gwr /*
119 1.9 gwr * Restore old PTE. No cache flush,
120 1.9 gwr * because the tmp PTE has no-cache.
121 1.9 gwr */
122 1.9 gwr set_pte(prevpg, oldpte);
123 1.9 gwr
124 1.9 gwr firstpage:
125 1.9 gwr /*
126 1.9 gwr * Flush the VAC to prevent a cache hit
127 1.9 gwr * on the old, read-only PTE.
128 1.9 gwr */
129 1.9 gwr #ifdef HAVECACHE
130 1.9 gwr if (cache_size)
131 1.9 gwr cache_flush_page(pgva);
132 1.9 gwr #endif
133 1.9 gwr oldpte = get_pte(pgva);
134 1.9 gwr if ((oldpte & PG_VALID) == 0) {
135 1.12 gwr printf(" address 0x%x not a valid page\n", dst);
136 1.9 gwr return;
137 1.9 gwr }
138 1.9 gwr tmppte = oldpte | PG_WRITE | PG_NC;
139 1.9 gwr set_pte(pgva, tmppte);
140 1.9 gwr
141 1.9 gwr prevpg = pgva;
142 1.9 gwr }
143 1.9 gwr
144 1.9 gwr /* Now we can write in this page of kernel text... */
145 1.9 gwr *dst++ = *data++;
146 1.1 gwr
147 1.9 gwr } while (--size > 0);
148 1.1 gwr
149 1.9 gwr /* Restore old PTE for the last page touched. */
150 1.9 gwr set_pte(prevpg, oldpte);
151 1.1 gwr
152 1.9 gwr /* Finally, clear the instruction cache. */
153 1.9 gwr ICIA();
154 1.1 gwr }
155 1.1 gwr
156 1.1 gwr /*
157 1.1 gwr * Write bytes to kernel address space for debugger.
158 1.1 gwr */
159 1.9 gwr extern char kernel_text[], etext[];
160 1.1 gwr void
161 1.1 gwr db_write_bytes(addr, size, data)
162 1.1 gwr vm_offset_t addr;
163 1.10 gwr register size_t size;
164 1.9 gwr register char *data;
165 1.1 gwr {
166 1.9 gwr register char *dst = (char *)addr;
167 1.1 gwr
168 1.9 gwr /* If any part is in kernel text, use db_write_text() */
169 1.9 gwr if ((dst < etext) && ((dst + size) > kernel_text)) {
170 1.9 gwr db_write_text(dst, size, data);
171 1.9 gwr return;
172 1.1 gwr }
173 1.7 gwr
174 1.9 gwr if (size == 4) {
175 1.9 gwr *((int*)dst) = *((int*)data);
176 1.9 gwr return;
177 1.9 gwr }
178 1.7 gwr
179 1.9 gwr if (size == 2) {
180 1.9 gwr *((short*)dst) = *((short*)data);
181 1.9 gwr return;
182 1.9 gwr }
183 1.7 gwr
184 1.11 gwr while (size > 0) {
185 1.11 gwr --size;
186 1.9 gwr *dst++ = *data++;
187 1.11 gwr }
188 1.7 gwr }
189 1.7 gwr
190