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 477 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 end > tr_end) { 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 g_snapshot = *vcpu; 296 g_snapshot_valid = true; 297 log_simple(LOG_MONITOR, 610u, vcpu->pc, vcpu->pstate); 298 uart_puts("snapshot saved pc="); 299 uart_put_hex64(g_snapshot.pc); 300 uart_puts(" pstate="); 301 uart_put_hex64(g_snapshot.pstate); 302 uart_puts("\n"); 303} 304 305static void monitor_snapshot_show(void) 306{ 307 if (!g_snapshot_valid) { 308 uart_puts("snapshot empty\n"); 309 return; 310 } 311 uart_puts("snapshot pc="); 312 uart_put_hex64(g_snapshot.pc); 313 uart_puts(" pstate="); 314 uart_put_hex64(g_snapshot.pstate); 315 uart_puts(" sp_el1="); 316 uart_put_hex64(g_snapshot.sp_el1); 317 uart_puts(" traps="); 318 uart_put_dec64(g_snapshot.stats.traps); 319 uart_puts("\n"); 320} 321 322static void monitor_restore(struct vcpu *vcpu) 323{ 324#if CONFIG_MONITOR_MUTATION 325 if (vcpu == (struct vcpu *)0 || !g_snapshot_valid) { 326 uart_puts("restore no-snapshot\n"); 327 return; 328 } 329 *vcpu = g_snapshot; 330 vcpu_set_current(vcpu); 331 log_simple(LOG_MONITOR, 611u, vcpu->pc, vcpu->pstate); 332 uart_puts("restore ok pc="); 333 uart_put_hex64(vcpu->pc); 334 uart_puts("\n"); 335#else 336 (void)vcpu; 337 uart_puts("restore disabled\n"); 338#endif 339} 340 341static void show_sysregs(const struct vcpu *vcpu) 342{ 343 if (vcpu == (const struct vcpu *)0) { 344 return; 345 } 346 uart_puts("sysregs sctlr="); 347 uart_put_hex64(vcpu->sysregs.sctlr_el1); 348 uart_puts(" ttbr0="); 349 uart_put_hex64(vcpu->sysregs.ttbr0_el1); 350 uart_puts(" ttbr1="); 351 uart_put_hex64(vcpu->sysregs.ttbr1_el1); 352 uart_puts(" tcr="); 353 uart_put_hex64(vcpu->sysregs.tcr_el1); 354 uart_puts(" mair="); 355 uart_put_hex64(vcpu->sysregs.mair_el1); 356 uart_puts(" vbar="); 357 uart_put_hex64(vcpu->sysregs.vbar_el1); 358 uart_puts("\n"); 359} 360 361static bool command(const char *line, struct vcpu *vcpu) 362{ 363 if (hv_strcmp(line, "help") == 0) { 364 help(); 365 } else if (hv_strcmp(line, "status") == 0) { 366 vcpu_dump(vcpu); 367 timer_dump(); 368 gicv3_dump(); 369 } else if (hv_strcmp(line, "vcpu") == 0 || hv_strcmp(line, "regs") == 0) { 370 vcpu_dump(vcpu); 371 } else if (hv_strcmp(line, "snapshot") == 0) { 372 monitor_snapshot(vcpu); 373 } else if (hv_strcmp(line, "snapshot show") == 0) { 374 monitor_snapshot_show(); 375 } else if (hv_strcmp(line, "restore") == 0) { 376 monitor_restore(vcpu); 377 } else if (hv_strcmp(line, "sysregs") == 0) { 378 show_sysregs(vcpu); 379 } else if (hv_strcmp(line, "log") == 0) { 380 log_dump(128u); 381 } else if (hv_strcmp(line, "log clear") == 0) { 382#if CONFIG_MONITOR_MUTATION 383 log_clear(); 384#else 385 uart_puts("log clear disabled\n"); 386#endif 387 } else if (hv_strcmp(line, "policy") == 0) { 388 policy_dump(); 389 } else if (starts_with_command(line, "profile")) { 390 monitor_profile(line + hv_strlen("profile")); 391 } else if (hv_strcmp(line, "psci") == 0) { 392 psci_dump(); 393 } else if (hv_strcmp(line, "mappings") == 0) { 394 stage2_dump(); 395 allocator_dump(); 396 } else if (hv_strcmp(line, "mmio") == 0) { 397 mmio_policy_dump(); 398 } else if (hv_strcmp(line, "el2mmu") == 0) { 399 el2_mmu_dump(); 400 } else if (hv_strcmp(line, "fdt") == 0) { 401 fdt_dump(platform_info()); 402 } else if (starts_with_command(line, "translate")) { 403 monitor_translate(line + hv_strlen("translate")); 404 } else if (starts_with_command(line, "read64")) { 405 monitor_read64(line + hv_strlen("read64")); 406 } else if (starts_with_command(line, "write64")) { 407 monitor_write64(line + hv_strlen("write64")); 408 } else if (starts_with_command(line, "dump")) { 409 monitor_dump(line + hv_strlen("dump")); 410 } else if (starts_with_command(line, "unmap")) { 411 monitor_unmap(line + hv_strlen("unmap")); 412 } else if (starts_with_command(line, "irq")) { 413 monitor_irq(line + hv_strlen("irq"), vcpu); 414 } else if (hv_strcmp(line, "resume") == 0) { 415 if (vcpu != (struct vcpu *)0) { 416 vcpu->state = VCPU_RUNNING; 417 } 418 g_paused = false; 419 return true; 420 } else if (hv_strcmp(line, "pause") == 0) { 421 g_paused = true; 422 } else if (hv_strcmp(line, "reboot") == 0 || hv_strcmp(line, "shutdown") == 0) { 423#if CONFIG_MONITOR_MUTATION 424 uart_puts("platform power control is not implemented; halting\n"); 425 for (;;) { 426 __asm__ volatile("wfe"); 427 } 428#else 429 uart_puts("power control disabled\n"); 430#endif 431 } else if (line[0] != '\0') { 432 uart_puts("error unknown-command\n"); 433 } 434 return false; 435} 436 437void monitor_init(void) 438{ 439 g_pos = 0; 440 g_paused = false; 441 g_snapshot_valid = false; 442} 443 444void monitor_poll(void) 445{ 446 char c; 447 while (uart_getc_nonblocking(&c)) { 448 if (c == '\r' || c == '\n') { 449 g_line[g_pos] = '\0'; 450 (void)command(g_line, vcpu_current()); 451 g_pos = 0; 452 uart_puts("hv> "); 453 } else if ((c == '\b' || c == 0x7f) && g_pos != 0u) { 454 g_pos--; 455 } else if (g_pos + 1u < sizeof(g_line) && c >= ' ' && c <= '~') { 456 g_line[g_pos++] = c; 457 } else { 458 uart_puts("error input-too-long\n"); 459 g_pos = 0; 460 } 461 } 462} 463 464void monitor_loop(struct vcpu *vcpu, const char *reason) 465{ 466 g_paused = true; 467 if (vcpu != (struct vcpu *)0) { 468 vcpu->state = VCPU_PAUSED; 469 } 470 uart_puts("monitor entered reason="); 471 uart_puts(reason); 472 uart_puts("\nhv> "); 473 while (g_paused) { 474 monitor_poll(); 475 __asm__ volatile("wfe"); 476 } 477}