1/* $NetBSD: db_memrw.c,v 1.2 2016/05/12 06:45:16 maxv Exp $ */
2
3/*-
4 * Copyright (c) 1996, 2000 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/*
33 * Interface to the debugger for virtual memory read/write.
34 * This file is shared by DDB and KGDB, and must work even
35 * when only KGDB is included (thus no db_printf calls).
36 *
37 * To write in the text segment, we have to first make
38 * the page writable, do the write, then restore the PTE.
39 * For writes outside the text segment, and all reads,
40 * just do the access -- if it causes a fault, the debugger
41 * will recover with a longjmp to an appropriate place.
42 *
43 * ALERT! If you want to access device registers with a
44 * specific size, then the read/write functions have to
45 * make sure to do the correct sized pointer access.
46 *
47 * Modified for i386 from hp300 version by
48 * Jason R. Thorpe <thorpej@zembu.com>.
49 *
50 * Basic copy to amd64 by fvdl.
51 *
52 * i386 and amd64 merge by jym.
53 */
54
55#include <sys/cdefs.h>
56__KERNEL_RCSID(0, "$NetBSD: db_memrw.c,v 1.2 2016/05/12 06:45:16 maxv Exp $");
57
58#include <sys/param.h>
59#include <sys/proc.h>
60#include <sys/systm.h>
61
62#include <machine/db_machdep.h>
63
64#include <ddb/db_access.h>
65
66/*
67 * Read bytes from kernel address space for debugger.
68 */
69void
70db_read_bytes(vaddr_t addr, size_t size, char *data)
71{
72 char *src;
73
74 src = (char *)addr;
75
76 if (size == 8) {
77 *((long *)data) = *((long *)src);
78 return;
79 }
80
81 if (size == 4) {
82 *((int *)data) = *((int *)src);
83 return;
84 }
85
86 if (size == 2) {
87 *((short *)data) = *((short *)src);
88 return;
89 }
90
91 while (size-- > 0)
92 *data++ = *src++;
93}
94
95/*
96 * Write bytes somewhere in the kernel text. Make the text
97 * pages writable temporarily.
98 */
99static void
100db_write_text(vaddr_t addr, size_t size, const char *data)
101{
102 pt_entry_t *ppte, pte;
103 size_t limit;
104 char *dst;
105
106 if (size == 0)
107 return;
108
109 dst = (char *)addr;
110
111 do {
112 addr = (vaddr_t)dst;
113 /*
114 * Get the PTE for the page.
115 */
116 ppte = kvtopte(addr);
117 pte = *ppte;
118
119 if ((pte & PG_V) == 0) {
120 printf(" address %p not a valid page\n", dst);
121 return;
122 }
123
124 /*
125 * Compute number of bytes that can be written
126 * with this mapping and subtract it from the
127 * total size.
128 */
129 if (pte & PG_PS)
130 limit = NBPD_L2 - (addr & (NBPD_L2 - 1));
131 else
132 limit = PAGE_SIZE - (addr & PGOFSET);
133 if (limit > size)
134 limit = size;
135 size -= limit;
136
137 /*
138 * Make the kernel text page writable.
139 */
140 pmap_pte_clearbits(ppte, PG_KR);
141 pmap_pte_setbits(ppte, PG_KW);
142 pmap_update_pg(addr);
143
144 /*
145 * MULTIPROCESSOR: no shootdown required as the PTE continues to
146 * map the same page and other CPUs do not need write access.
147 */
148
149 /*
150 * Page is now writable. Do as much access as we
151 * can in this page.
152 */
153 for (; limit > 0; limit--)
154 *dst++ = *data++;
155
156 /*
157 * Turn the page back to read-only.
158 */
159 pmap_pte_clearbits(ppte, PG_KW);
160 pmap_pte_setbits(ppte, PG_KR);
161 pmap_update_pg(addr);
162
163 /*
164 * MULTIPROCESSOR: no shootdown required as all other CPUs
165 * should be in CPUF_PAUSE state and will not cache the PTE
166 * with the write access set.
167 */
168 } while (size != 0);
169}
170
171/*
172 * Write bytes to kernel address space for debugger.
173 */
174void
175db_write_bytes(vaddr_t addr, size_t size, const char *data)
176{
177 extern int __rodata_start;
178 extern int __data_start;
179 char *dst;
180
181 dst = (char *)addr;
182
183 /* If any part is in kernel text or rodata, use db_write_text() */
184 if ((addr >= KERNBASE && addr < (vaddr_t)&__rodata_start) ||
185 (addr >= (vaddr_t)&__rodata_start && addr < (vaddr_t)&__data_start)) {
186 db_write_text(addr, size, data);
187 return;
188 }
189
190 dst = (char *)addr;
191
192 if (size == 8) {
193 *((long *)dst) = *((const long *)data);
194 return;
195 }
196
197 if (size == 4) {
198 *((int *)dst) = *((const int *)data);
199 return;
200 }
201
202 if (size == 2) {
203 *((short *)dst) = *((const short *)data);
204 return;
205 }
206
207 while (size-- > 0)
208 *dst++ = *data++;
209}
210