blob: ff01cf9d8dbd833511c0c1bb6c92d1f7cbf9e37a [file] [log] [blame]
Markus Armbrustere2245562023-01-24 13:19:42 +01001/*
2 * Miscellaneous target-dependent HMP commands
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "qemu/osdep.h"
26#include "disas/disas.h"
27#include "exec/address-spaces.h"
Philippe Mathieu-Daudéf6e33702024-02-09 16:00:38 +010028#include "exec/memory.h"
Markus Armbrustere2245562023-01-24 13:19:42 +010029#include "monitor/hmp-target.h"
30#include "monitor/monitor-internal.h"
31#include "qapi/error.h"
32#include "qapi/qmp/qdict.h"
33#include "sysemu/hw_accel.h"
34
35/* Set the current CPU defined by the user. Callers must hold BQL. */
36int monitor_set_cpu(Monitor *mon, int cpu_index)
37{
38 CPUState *cpu;
39
40 cpu = qemu_get_cpu(cpu_index);
41 if (cpu == NULL) {
42 return -1;
43 }
44 g_free(mon->mon_cpu_path);
45 mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu));
46 return 0;
47}
48
49/* Callers must hold BQL. */
50static CPUState *mon_get_cpu_sync(Monitor *mon, bool synchronize)
51{
52 CPUState *cpu = NULL;
53
54 if (mon->mon_cpu_path) {
55 cpu = (CPUState *) object_resolve_path_type(mon->mon_cpu_path,
56 TYPE_CPU, NULL);
57 if (!cpu) {
58 g_free(mon->mon_cpu_path);
59 mon->mon_cpu_path = NULL;
60 }
61 }
62 if (!mon->mon_cpu_path) {
63 if (!first_cpu) {
64 return NULL;
65 }
66 monitor_set_cpu(mon, first_cpu->cpu_index);
67 cpu = first_cpu;
68 }
69 assert(cpu != NULL);
70 if (synchronize) {
71 cpu_synchronize_state(cpu);
72 }
73 return cpu;
74}
75
76CPUState *mon_get_cpu(Monitor *mon)
77{
78 return mon_get_cpu_sync(mon, true);
79}
80
81CPUArchState *mon_get_cpu_env(Monitor *mon)
82{
83 CPUState *cs = mon_get_cpu(mon);
84
Richard Hendersonb77af262023-09-13 17:22:49 -070085 return cs ? cpu_env(cs) : NULL;
Markus Armbrustere2245562023-01-24 13:19:42 +010086}
87
88int monitor_get_cpu_index(Monitor *mon)
89{
90 CPUState *cs = mon_get_cpu_sync(mon, false);
91
92 return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX;
93}
94
95void hmp_info_registers(Monitor *mon, const QDict *qdict)
96{
97 bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false);
98 int vcpu = qdict_get_try_int(qdict, "vcpu", -1);
99 CPUState *cs;
100
101 if (all_cpus) {
102 CPU_FOREACH(cs) {
103 monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
104 cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
105 }
106 } else {
107 cs = vcpu >= 0 ? qemu_get_cpu(vcpu) : mon_get_cpu(mon);
108
109 if (!cs) {
110 if (vcpu >= 0) {
111 monitor_printf(mon, "CPU#%d not available\n", vcpu);
112 } else {
113 monitor_printf(mon, "No CPU available\n");
114 }
115 return;
116 }
117
118 monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
119 cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
120 }
121}
122
123static void memory_dump(Monitor *mon, int count, int format, int wsize,
124 hwaddr addr, int is_physical)
125{
126 int l, line_size, i, max_digits, len;
127 uint8_t buf[16];
128 uint64_t v;
129 CPUState *cs = mon_get_cpu(mon);
130
131 if (!cs && (format == 'i' || !is_physical)) {
132 monitor_printf(mon, "Can not dump without CPU\n");
133 return;
134 }
135
136 if (format == 'i') {
137 monitor_disas(mon, cs, addr, count, is_physical);
138 return;
139 }
140
141 len = wsize * count;
142 if (wsize == 1) {
143 line_size = 8;
144 } else {
145 line_size = 16;
146 }
147 max_digits = 0;
148
149 switch(format) {
150 case 'o':
151 max_digits = DIV_ROUND_UP(wsize * 8, 3);
152 break;
153 default:
154 case 'x':
155 max_digits = (wsize * 8) / 4;
156 break;
157 case 'u':
158 case 'd':
159 max_digits = DIV_ROUND_UP(wsize * 8 * 10, 33);
160 break;
161 case 'c':
162 wsize = 1;
163 break;
164 }
165
166 while (len > 0) {
167 if (is_physical) {
168 monitor_printf(mon, HWADDR_FMT_plx ":", addr);
169 } else {
170 monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr);
171 }
172 l = len;
173 if (l > line_size)
174 l = line_size;
175 if (is_physical) {
176 AddressSpace *as = cs ? cs->as : &address_space_memory;
177 MemTxResult r = address_space_read(as, addr,
178 MEMTXATTRS_UNSPECIFIED, buf, l);
179 if (r != MEMTX_OK) {
180 monitor_printf(mon, " Cannot access memory\n");
181 break;
182 }
183 } else {
184 if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) {
185 monitor_printf(mon, " Cannot access memory\n");
186 break;
187 }
188 }
189 i = 0;
190 while (i < l) {
191 switch(wsize) {
192 default:
193 case 1:
194 v = ldub_p(buf + i);
195 break;
196 case 2:
197 v = lduw_p(buf + i);
198 break;
199 case 4:
200 v = (uint32_t)ldl_p(buf + i);
201 break;
202 case 8:
203 v = ldq_p(buf + i);
204 break;
205 }
206 monitor_printf(mon, " ");
207 switch(format) {
208 case 'o':
209 monitor_printf(mon, "%#*" PRIo64, max_digits, v);
210 break;
211 case 'x':
212 monitor_printf(mon, "0x%0*" PRIx64, max_digits, v);
213 break;
214 case 'u':
215 monitor_printf(mon, "%*" PRIu64, max_digits, v);
216 break;
217 case 'd':
218 monitor_printf(mon, "%*" PRId64, max_digits, v);
219 break;
220 case 'c':
221 monitor_printc(mon, v);
222 break;
223 }
224 i += wsize;
225 }
226 monitor_printf(mon, "\n");
227 addr += l;
228 len -= l;
229 }
230}
231
232void hmp_memory_dump(Monitor *mon, const QDict *qdict)
233{
234 int count = qdict_get_int(qdict, "count");
235 int format = qdict_get_int(qdict, "format");
236 int size = qdict_get_int(qdict, "size");
237 target_long addr = qdict_get_int(qdict, "addr");
238
239 memory_dump(mon, count, format, size, addr, 0);
240}
241
242void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict)
243{
244 int count = qdict_get_int(qdict, "count");
245 int format = qdict_get_int(qdict, "format");
246 int size = qdict_get_int(qdict, "size");
247 hwaddr addr = qdict_get_int(qdict, "addr");
248
249 memory_dump(mon, count, format, size, addr, 1);
250}
251
252void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp)
253{
254 Int128 gpa_region_size;
255 MemoryRegionSection mrs = memory_region_find(get_system_memory(),
256 addr, size);
257
258 if (!mrs.mr) {
259 error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, addr);
260 return NULL;
261 }
262
263 if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) {
Yao Xingtaoa158c632024-03-19 10:16:10 +0800264 error_setg(errp, "Memory at address 0x%" HWADDR_PRIx " is not RAM", addr);
Markus Armbrustere2245562023-01-24 13:19:42 +0100265 memory_region_unref(mrs.mr);
266 return NULL;
267 }
268
269 gpa_region_size = int128_make64(size);
270 if (int128_lt(mrs.size, gpa_region_size)) {
271 error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx
272 " exceeded.", addr);
273 memory_region_unref(mrs.mr);
274 return NULL;
275 }
276
277 *p_mr = mrs.mr;
278 return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
279}
280
281void hmp_gpa2hva(Monitor *mon, const QDict *qdict)
282{
283 hwaddr addr = qdict_get_int(qdict, "addr");
284 Error *local_err = NULL;
285 MemoryRegion *mr = NULL;
286 void *ptr;
287
288 ptr = gpa2hva(&mr, addr, 1, &local_err);
289 if (local_err) {
290 error_report_err(local_err);
291 return;
292 }
293
294 monitor_printf(mon, "Host virtual address for 0x%" HWADDR_PRIx
295 " (%s) is %p\n",
296 addr, mr->name, ptr);
297
298 memory_region_unref(mr);
299}
300
301void hmp_gva2gpa(Monitor *mon, const QDict *qdict)
302{
303 target_ulong addr = qdict_get_int(qdict, "addr");
304 MemTxAttrs attrs;
305 CPUState *cs = mon_get_cpu(mon);
306 hwaddr gpa;
307
308 if (!cs) {
309 monitor_printf(mon, "No cpu\n");
310 return;
311 }
312
313 gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs);
314 if (gpa == -1) {
315 monitor_printf(mon, "Unmapped\n");
316 } else {
317 monitor_printf(mon, "gpa: %#" HWADDR_PRIx "\n",
318 gpa + (addr & ~TARGET_PAGE_MASK));
319 }
320}
321
322#ifdef CONFIG_LINUX
323static uint64_t vtop(void *ptr, Error **errp)
324{
325 uint64_t pinfo;
326 uint64_t ret = -1;
327 uintptr_t addr = (uintptr_t) ptr;
328 uintptr_t pagesize = qemu_real_host_page_size();
329 off_t offset = addr / pagesize * sizeof(pinfo);
330 int fd;
331
332 fd = open("/proc/self/pagemap", O_RDONLY);
333 if (fd == -1) {
334 error_setg_errno(errp, errno, "Cannot open /proc/self/pagemap");
335 return -1;
336 }
337
338 /* Force copy-on-write if necessary. */
339 qatomic_add((uint8_t *)ptr, 0);
340
341 if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) {
342 error_setg_errno(errp, errno, "Cannot read pagemap");
343 goto out;
344 }
345 if ((pinfo & (1ull << 63)) == 0) {
346 error_setg(errp, "Page not present");
347 goto out;
348 }
349 ret = ((pinfo & 0x007fffffffffffffull) * pagesize) | (addr & (pagesize - 1));
350
351out:
352 close(fd);
353 return ret;
354}
355
356void hmp_gpa2hpa(Monitor *mon, const QDict *qdict)
357{
358 hwaddr addr = qdict_get_int(qdict, "addr");
359 Error *local_err = NULL;
360 MemoryRegion *mr = NULL;
361 void *ptr;
362 uint64_t physaddr;
363
364 ptr = gpa2hva(&mr, addr, 1, &local_err);
365 if (local_err) {
366 error_report_err(local_err);
367 return;
368 }
369
370 physaddr = vtop(ptr, &local_err);
371 if (local_err) {
372 error_report_err(local_err);
373 } else {
374 monitor_printf(mon, "Host physical address for 0x%" HWADDR_PRIx
375 " (%s) is 0x%" PRIx64 "\n",
376 addr, mr->name, (uint64_t) physaddr);
377 }
378
379 memory_region_unref(mr);
380}
381#endif