AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1

Configure Feed

Select the types of activity you want to include in your feed.

ariel / core / monitor.c
13 kB 485 lines
1#include "hv/allocator.h" 2#include "hv/gicv3.h" 3#include "hv/el2_mmu.h" 4#include "hv/log.h" 5#include "hv/monitor.h" 6#include "hv/mmio_policy.h" 7#include "hv/platform.h" 8#include "hv/policy.h" 9#include "hv/psci.h" 10#include "hv/stage2.h" 11#include "hv/string.h" 12#include "hv/timer.h" 13#include "hv/uart.h" 14 15static char g_line[96]; 16static uint32_t g_pos; 17static bool g_paused; 18static struct vcpu g_snapshot; 19static bool g_snapshot_valid; 20 21static void help(void) 22{ 23#if CONFIG_MONITOR_MUTATION 24 uart_puts("commands: help status vcpu regs sysregs snapshot restore log log clear policy profile psci mappings mmio el2mmu fdt translate read64 write64 dump unmap irq irq clear resume pause reboot shutdown\n"); 25#else 26 uart_puts("commands: help status vcpu regs sysregs snapshot snapshot show log policy psci mappings mmio el2mmu fdt translate read64 dump resume pause\n"); 27#endif 28} 29 30static bool is_space(char c) 31{ 32 return c == ' ' || c == '\t'; 33} 34 35static const char *skip_spaces(const char *s) 36{ 37 while (is_space(*s)) { 38 s++; 39 } 40 return s; 41} 42 43static bool starts_with_command(const char *line, const char *cmd) 44{ 45 size_t n = hv_strlen(cmd); 46 return hv_strncmp(line, cmd, n) == 0 && (line[n] == '\0' || is_space(line[n])); 47} 48 49static bool digit_value(char c, uint64_t *out) 50{ 51 if (c >= '0' && c <= '9') { 52 *out = (uint64_t)(c - '0'); 53 return true; 54 } 55 if (c >= 'a' && c <= 'f') { 56 *out = 10u + (uint64_t)(c - 'a'); 57 return true; 58 } 59 if (c >= 'A' && c <= 'F') { 60 *out = 10u + (uint64_t)(c - 'A'); 61 return true; 62 } 63 return false; 64} 65 66static bool parse_u64(const char **cursor, uint64_t *out) 67{ 68 const char *s = skip_spaces(*cursor); 69 uint64_t base = 10u; 70 uint64_t value = 0u; 71 uint64_t digit; 72 bool any = false; 73 74 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 75 base = 16u; 76 s += 2; 77 } 78 while (digit_value(*s, &digit)) { 79 if (digit >= base) { 80 return false; 81 } 82 if (value > (UINT64_MAX - digit) / base) { 83 return false; 84 } 85 value = (value * base) + digit; 86 any = true; 87 s++; 88 } 89 if (!any) { 90 return false; 91 } 92 *cursor = s; 93 *out = value; 94 return true; 95} 96 97static bool ipa_to_host(uint64_t ipa, uint64_t len, uintptr_t *host) 98{ 99 struct stage2_translation tr; 100 uint64_t end; 101 uint64_t tr_end; 102 uint64_t off; 103 104 if (host == (uintptr_t *)0 || len == 0u || hv_add_overflow_u64(ipa, len, &end)) { 105 return false; 106 } 107 if (!stage2_translate(ipa, &tr) || 108 hv_add_overflow_u64(tr.ipa_base, tr.size, &tr_end) || 109 !hv_range_contains(tr.ipa_base, tr.size, ipa, len)) { 110 return false; 111 } 112 off = ipa - tr.ipa_base; 113 *host = (uintptr_t)(tr.pa_base + off); 114 return true; 115} 116 117static void monitor_translate(const char *args) 118{ 119 uint64_t ipa; 120 struct stage2_translation tr; 121 if (!parse_u64(&args, &ipa)) { 122 uart_puts("usage translate <ipa>\n"); 123 return; 124 } 125 if (!stage2_translate(ipa, &tr)) { 126 uart_puts("translate unmapped ipa="); 127 uart_put_hex64(ipa); 128 uart_puts("\n"); 129 return; 130 } 131 uart_puts("translate ipa="); 132 uart_put_hex64(ipa); 133 uart_puts(" block="); 134 uart_put_hex64(tr.ipa_base); 135 uart_puts(" pa="); 136 uart_put_hex64(tr.pa_base + (ipa - tr.ipa_base)); 137 uart_puts(" perms="); 138 uart_put_hex64(tr.perms); 139 uart_puts(" desc="); 140 uart_put_hex64(tr.desc); 141 uart_puts("\n"); 142} 143 144static void monitor_read64(const char *args) 145{ 146 uint64_t ipa; 147 uintptr_t host; 148 if (!parse_u64(&args, &ipa) || !hv_is_aligned_u64(ipa, 8u)) { 149 uart_puts("usage read64 <aligned-ipa>\n"); 150 return; 151 } 152 if (!ipa_to_host(ipa, 8u, &host)) { 153 uart_puts("read64 unmapped\n"); 154 return; 155 } 156 uart_puts("read64 "); 157 uart_put_hex64(ipa); 158 uart_puts("="); 159 uart_put_hex64(*(volatile uint64_t *)host); 160 uart_puts("\n"); 161} 162 163static void monitor_write64(const char *args) 164{ 165#if CONFIG_MONITOR_MUTATION 166 uint64_t ipa; 167 uint64_t value; 168 uintptr_t host; 169 if (!parse_u64(&args, &ipa) || !parse_u64(&args, &value) || !hv_is_aligned_u64(ipa, 8u)) { 170 uart_puts("usage write64 <aligned-ipa> <value>\n"); 171 return; 172 } 173 if (!ipa_to_host(ipa, 8u, &host)) { 174 uart_puts("write64 unmapped\n"); 175 return; 176 } 177 *(volatile uint64_t *)host = value; 178 uart_puts("write64 ok\n"); 179#else 180 (void)args; 181 uart_puts("write64 disabled\n"); 182#endif 183} 184 185static void monitor_dump(const char *args) 186{ 187 uint64_t ipa; 188 uint64_t len; 189 uintptr_t host; 190 if (!parse_u64(&args, &ipa) || !parse_u64(&args, &len) || len > 256u) { 191 uart_puts("usage dump <ipa> <len<=256>\n"); 192 return; 193 } 194 if (!ipa_to_host(ipa, len, &host)) { 195 uart_puts("dump unmapped\n"); 196 return; 197 } 198 for (uint64_t i = 0; i < len; i++) { 199 if ((i & 0x0full) == 0u) { 200 uart_puts("\n"); 201 uart_put_hex64(ipa + i); 202 uart_puts(":"); 203 } 204 uart_puts(" "); 205 uint8_t b = *(volatile uint8_t *)(host + i); 206 static const char hex[] = "0123456789abcdef"; 207 uart_putc(hex[b >> 4u]); 208 uart_putc(hex[b & 0x0fu]); 209 } 210 uart_puts("\n"); 211} 212 213static void monitor_unmap(const char *args) 214{ 215#if CONFIG_MONITOR_MUTATION 216 uint64_t ipa; 217 if (!parse_u64(&args, &ipa)) { 218 uart_puts("usage unmap <2MiB-aligned-ipa>\n"); 219 return; 220 } 221 if (!stage2_unmap_range(HV_ALIGN_DOWN(ipa, 0x200000ull), 0x200000ull)) { 222 uart_puts("unmap failed\n"); 223 return; 224 } 225 uart_puts("unmap ok\n"); 226#else 227 (void)args; 228 uart_puts("unmap disabled\n"); 229#endif 230} 231 232static void monitor_irq(const char *args, struct vcpu *vcpu) 233{ 234#if CONFIG_MONITOR_MUTATION 235 uint64_t intid; 236 args = skip_spaces(args); 237 if (hv_strncmp(args, "clear", 5u) == 0 && is_space(args[5])) { 238 args = skip_spaces(args + 5u); 239 if (vcpu == (struct vcpu *)0 || !parse_u64(&args, &intid) || intid >= 64u) { 240 uart_puts("usage irq clear <intid<64>\n"); 241 return; 242 } 243 vcpu_clear_pending_irq(vcpu, (uint32_t)intid); 244 gicv3_flush_vcpu_state(vcpu); 245 uart_puts("irq cleared intid="); 246 uart_put_dec64(intid); 247 uart_puts("\n"); 248 return; 249 } 250 if (vcpu == (struct vcpu *)0 || !parse_u64(&args, &intid) || intid >= 64u) { 251 uart_puts("usage irq <intid<64> | irq clear <intid<64>\n"); 252 return; 253 } 254 vcpu_set_pending_irq(vcpu, (uint32_t)intid); 255 gicv3_flush_vcpu_state(vcpu); 256 uart_puts("irq pending intid="); 257 uart_put_dec64(intid); 258 uart_puts("\n"); 259#else 260 (void)args; 261 (void)vcpu; 262 uart_puts("irq disabled\n"); 263#endif 264} 265 266static void monitor_profile(const char *args) 267{ 268#if CONFIG_MONITOR_MUTATION 269 args = skip_spaces(args); 270 if (*args == '\0') { 271 uart_puts("policy profile="); 272 uart_puts(policy_profile_name(policy_get_profile())); 273 uart_puts("\n"); 274 return; 275 } 276 if (!policy_set_profile_name(args)) { 277 uart_puts("usage profile strict|diagnostic|linux-boot|debug\n"); 278 return; 279 } 280 uart_puts("policy profile="); 281 uart_puts(policy_profile_name(policy_get_profile())); 282 uart_puts("\n"); 283#else 284 (void)args; 285 uart_puts("profile disabled\n"); 286#endif 287} 288 289static void monitor_snapshot(struct vcpu *vcpu) 290{ 291 if (vcpu == (struct vcpu *)0) { 292 uart_puts("snapshot no-vcpu\n"); 293 return; 294 } 295 if (vcpu->state != VCPU_PAUSED) { 296 uart_puts("snapshot requires-paused-vcpu\n"); 297 return; 298 } 299 g_snapshot = *vcpu; 300 g_snapshot_valid = true; 301 log_simple(LOG_MONITOR, 610u, vcpu->pc, vcpu->pstate); 302 uart_puts("snapshot saved pc="); 303 uart_put_hex64(g_snapshot.pc); 304 uart_puts(" pstate="); 305 uart_put_hex64(g_snapshot.pstate); 306 uart_puts(" id="); 307 uart_put_dec64(g_snapshot.id); 308 uart_puts("\n"); 309} 310 311static void monitor_snapshot_show(void) 312{ 313 if (!g_snapshot_valid) { 314 uart_puts("snapshot empty\n"); 315 return; 316 } 317 uart_puts("snapshot pc="); 318 uart_put_hex64(g_snapshot.pc); 319 uart_puts(" pstate="); 320 uart_put_hex64(g_snapshot.pstate); 321 uart_puts(" sp_el1="); 322 uart_put_hex64(g_snapshot.sp_el1); 323 uart_puts(" traps="); 324 uart_put_dec64(g_snapshot.stats.traps); 325 uart_puts(" state="); 326 uart_put_dec64((uint64_t)g_snapshot.state); 327 uart_puts("\n"); 328} 329 330static void monitor_restore(struct vcpu *vcpu) 331{ 332#if CONFIG_MONITOR_MUTATION 333 if (vcpu == (struct vcpu *)0 || !g_snapshot_valid || vcpu->id != g_snapshot.id) { 334 uart_puts("restore no-snapshot\n"); 335 return; 336 } 337 *vcpu = g_snapshot; 338 vcpu_set_current(vcpu); 339 log_simple(LOG_MONITOR, 611u, vcpu->pc, vcpu->pstate); 340 uart_puts("restore ok pc="); 341 uart_put_hex64(vcpu->pc); 342 uart_puts("\n"); 343#else 344 (void)vcpu; 345 uart_puts("restore disabled\n"); 346#endif 347} 348 349static void show_sysregs(const struct vcpu *vcpu) 350{ 351 if (vcpu == (const struct vcpu *)0) { 352 return; 353 } 354 uart_puts("sysregs sctlr="); 355 uart_put_hex64(vcpu->sysregs.sctlr_el1); 356 uart_puts(" ttbr0="); 357 uart_put_hex64(vcpu->sysregs.ttbr0_el1); 358 uart_puts(" ttbr1="); 359 uart_put_hex64(vcpu->sysregs.ttbr1_el1); 360 uart_puts(" tcr="); 361 uart_put_hex64(vcpu->sysregs.tcr_el1); 362 uart_puts(" mair="); 363 uart_put_hex64(vcpu->sysregs.mair_el1); 364 uart_puts(" vbar="); 365 uart_put_hex64(vcpu->sysregs.vbar_el1); 366 uart_puts("\n"); 367} 368 369static bool command(const char *line, struct vcpu *vcpu) 370{ 371 if (hv_strcmp(line, "help") == 0) { 372 help(); 373 } else if (hv_strcmp(line, "status") == 0) { 374 vcpu_dump(vcpu); 375 timer_dump(); 376 gicv3_dump(); 377 } else if (hv_strcmp(line, "vcpu") == 0 || hv_strcmp(line, "regs") == 0) { 378 vcpu_dump(vcpu); 379 } else if (hv_strcmp(line, "snapshot") == 0) { 380 monitor_snapshot(vcpu); 381 } else if (hv_strcmp(line, "snapshot show") == 0) { 382 monitor_snapshot_show(); 383 } else if (hv_strcmp(line, "restore") == 0) { 384 monitor_restore(vcpu); 385 } else if (hv_strcmp(line, "sysregs") == 0) { 386 show_sysregs(vcpu); 387 } else if (hv_strcmp(line, "log") == 0) { 388 log_dump(128u); 389 } else if (hv_strcmp(line, "log clear") == 0) { 390#if CONFIG_MONITOR_MUTATION 391 log_clear(); 392#else 393 uart_puts("log clear disabled\n"); 394#endif 395 } else if (hv_strcmp(line, "policy") == 0) { 396 policy_dump(); 397 } else if (starts_with_command(line, "profile")) { 398 monitor_profile(line + hv_strlen("profile")); 399 } else if (hv_strcmp(line, "psci") == 0) { 400 psci_dump(); 401 } else if (hv_strcmp(line, "mappings") == 0) { 402 stage2_dump(); 403 allocator_dump(); 404 } else if (hv_strcmp(line, "mmio") == 0) { 405 mmio_policy_dump(); 406 } else if (hv_strcmp(line, "el2mmu") == 0) { 407 el2_mmu_dump(); 408 } else if (hv_strcmp(line, "fdt") == 0) { 409 fdt_dump(platform_info()); 410 } else if (starts_with_command(line, "translate")) { 411 monitor_translate(line + hv_strlen("translate")); 412 } else if (starts_with_command(line, "read64")) { 413 monitor_read64(line + hv_strlen("read64")); 414 } else if (starts_with_command(line, "write64")) { 415 monitor_write64(line + hv_strlen("write64")); 416 } else if (starts_with_command(line, "dump")) { 417 monitor_dump(line + hv_strlen("dump")); 418 } else if (starts_with_command(line, "unmap")) { 419 monitor_unmap(line + hv_strlen("unmap")); 420 } else if (starts_with_command(line, "irq")) { 421 monitor_irq(line + hv_strlen("irq"), vcpu); 422 } else if (hv_strcmp(line, "resume") == 0) { 423 if (vcpu != (struct vcpu *)0) { 424 vcpu->state = VCPU_RUNNING; 425 } 426 g_paused = false; 427 return true; 428 } else if (hv_strcmp(line, "pause") == 0) { 429 g_paused = true; 430 } else if (hv_strcmp(line, "reboot") == 0 || hv_strcmp(line, "shutdown") == 0) { 431#if CONFIG_MONITOR_MUTATION 432 uart_puts("platform power control is not implemented; halting\n"); 433 for (;;) { 434 __asm__ volatile("wfe"); 435 } 436#else 437 uart_puts("power control disabled\n"); 438#endif 439 } else if (line[0] != '\0') { 440 uart_puts("error unknown-command\n"); 441 } 442 return false; 443} 444 445void monitor_init(void) 446{ 447 g_pos = 0; 448 g_paused = false; 449 g_snapshot_valid = false; 450} 451 452void monitor_poll(void) 453{ 454 char c; 455 while (uart_getc_nonblocking(&c)) { 456 if (c == '\r' || c == '\n') { 457 g_line[g_pos] = '\0'; 458 (void)command(g_line, vcpu_current()); 459 g_pos = 0; 460 uart_puts("hv> "); 461 } else if ((c == '\b' || c == 0x7f) && g_pos != 0u) { 462 g_pos--; 463 } else if (g_pos + 1u < sizeof(g_line) && c >= ' ' && c <= '~') { 464 g_line[g_pos++] = c; 465 } else { 466 uart_puts("error input-too-long\n"); 467 g_pos = 0; 468 } 469 } 470} 471 472void monitor_loop(struct vcpu *vcpu, const char *reason) 473{ 474 g_paused = true; 475 if (vcpu != (struct vcpu *)0) { 476 vcpu->state = VCPU_PAUSED; 477 } 478 uart_puts("monitor entered reason="); 479 uart_puts(reason); 480 uart_puts("\nhv> "); 481 while (g_paused) { 482 monitor_poll(); 483 __asm__ volatile("wfe"); 484 } 485}