1*6822f9c8Santon /* $OpenBSD: vcpu.c,v 1.8 2024/08/23 12:56:26 anton Exp $ */ 2a944cd34Sdv 3a944cd34Sdv /* 4a944cd34Sdv * Copyright (c) 2022 Dave Voutila <dv@openbsd.org> 5a944cd34Sdv * 6a944cd34Sdv * Permission to use, copy, modify, and distribute this software for any 7a944cd34Sdv * purpose with or without fee is hereby granted, provided that the above 8a944cd34Sdv * copyright notice and this permission notice appear in all copies. 9a944cd34Sdv * 10a944cd34Sdv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a944cd34Sdv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a944cd34Sdv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a944cd34Sdv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a944cd34Sdv * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a944cd34Sdv * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a944cd34Sdv * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a944cd34Sdv */ 18a944cd34Sdv 19a944cd34Sdv #include <sys/types.h> 20a944cd34Sdv #include <sys/ioctl.h> 21a944cd34Sdv #include <sys/mman.h> 22a944cd34Sdv 23a944cd34Sdv #include <machine/specialreg.h> 24a944cd34Sdv #include <machine/vmmvar.h> 25a944cd34Sdv 26a6c21945Santon #include <dev/vmm/vmm.h> 27a6c21945Santon 28a944cd34Sdv #include <err.h> 29a944cd34Sdv #include <errno.h> 30a944cd34Sdv #include <fcntl.h> 31a944cd34Sdv #include <stdio.h> 32a944cd34Sdv #include <stdlib.h> 33a944cd34Sdv #include <string.h> 34a944cd34Sdv #include <unistd.h> 35a944cd34Sdv 36a944cd34Sdv #define KIB 1024 371ebbcee8Sdv #define MIB (1UL << 20) 381ebbcee8Sdv #define GIB (1024 * MIB) 39a944cd34Sdv #define VMM_NODE "/dev/vmm" 40a944cd34Sdv 411ebbcee8Sdv #define LOW_MEM 0 421ebbcee8Sdv #define UPPER_MEM 1 431ebbcee8Sdv 4430bbc2f6Stb #define PCKBC_AUX 0x61 451ebbcee8Sdv #define PCJR_DISKCTRL 0xF0 4630bbc2f6Stb 47a944cd34Sdv const char *VM_NAME = "regress"; 48a944cd34Sdv 491ebbcee8Sdv const uint8_t PUSHW_DX[] = { 0x66, 0x52 }; // pushw %dx 501ebbcee8Sdv const uint8_t INS[] = { 0x6C }; // ins es:[di],dx 511ebbcee8Sdv const uint8_t IN_PCJR[] = { 0xE4, 0xF0 }; // in 0xF0 521ebbcee8Sdv 53a944cd34Sdv /* Originally from vmd(8)'s vm.c */ 54a944cd34Sdv const struct vcpu_reg_state vcpu_init_flat16 = { 55a944cd34Sdv .vrs_gprs[VCPU_REGS_RFLAGS] = 0x2, 56a944cd34Sdv .vrs_gprs[VCPU_REGS_RIP] = 0xFFF0, 571ebbcee8Sdv .vrs_gprs[VCPU_REGS_RDX] = PCKBC_AUX, /* Port used by INS */ 581ebbcee8Sdv .vrs_gprs[VCPU_REGS_RSP] = 0x800, /* Set our stack in low mem. */ 59a944cd34Sdv .vrs_crs[VCPU_REGS_CR0] = 0x60000010, 601ebbcee8Sdv .vrs_sregs[VCPU_REGS_CS] = { 0xF000, 0xFFFF, 0x0093, 0xFFFF0000}, 611ebbcee8Sdv .vrs_sregs[VCPU_REGS_DS] = { 0x0, 0xFFFF, 0x0093, 0x0}, 621ebbcee8Sdv .vrs_sregs[VCPU_REGS_ES] = { 0x0, 0xFFFF, 0x0093, 0x0}, 631ebbcee8Sdv .vrs_sregs[VCPU_REGS_FS] = { 0x0, 0xFFFF, 0x0093, 0x0}, 641ebbcee8Sdv .vrs_sregs[VCPU_REGS_GS] = { 0x0, 0xFFFF, 0x0093, 0x0}, 651ebbcee8Sdv .vrs_sregs[VCPU_REGS_SS] = { 0x0, 0xFFFF, 0x0093, 0x0}, 661ebbcee8Sdv .vrs_gdtr = { 0x0, 0xFFFF, 0x0082, 0x0}, 671ebbcee8Sdv .vrs_idtr = { 0x0, 0xFFFF, 0x0082, 0x0}, 68a944cd34Sdv .vrs_sregs[VCPU_REGS_LDTR] = { 0x0, 0xFFFF, 0x0082, 0x0}, 69a944cd34Sdv .vrs_sregs[VCPU_REGS_TR] = { 0x0, 0xFFFF, 0x008B, 0x0}, 70a944cd34Sdv .vrs_drs[VCPU_REGS_DR6] = 0xFFFF0FF0, 71a944cd34Sdv .vrs_drs[VCPU_REGS_DR7] = 0x400, 721ebbcee8Sdv .vrs_crs[VCPU_REGS_XCR0] = XFEATURE_X87, 731ebbcee8Sdv }; 741ebbcee8Sdv 751ebbcee8Sdv struct intr_handler { 761ebbcee8Sdv uint16_t offset; 771ebbcee8Sdv uint16_t segment; 781ebbcee8Sdv }; 791ebbcee8Sdv 801ebbcee8Sdv const struct intr_handler ivt[256] = { 811ebbcee8Sdv [VMM_EX_GP] = { .segment = 0x0, .offset = 0x0B5D }, 82a944cd34Sdv }; 83a944cd34Sdv 84a944cd34Sdv int 85a944cd34Sdv main(int argc, char **argv) 86a944cd34Sdv { 87a944cd34Sdv struct vm_create_params vcp; 88a944cd34Sdv struct vm_exit *exit = NULL; 89a944cd34Sdv struct vm_info_params vip; 90a944cd34Sdv struct vm_info_result *info = NULL, *ours = NULL; 91a944cd34Sdv struct vm_resetcpu_params vresetp; 92a944cd34Sdv struct vm_run_params vrunp; 93a944cd34Sdv struct vm_terminate_params vtp; 943c817da7Sdv struct vm_sharemem_params vsp; 95a944cd34Sdv 96a944cd34Sdv struct vm_mem_range *vmr; 97a944cd34Sdv int fd, ret = 1; 981ebbcee8Sdv size_t i; 991ebbcee8Sdv off_t off, reset = 0xFFFFFFF0, stack = 0x800; 100a944cd34Sdv void *p; 101a944cd34Sdv 102a944cd34Sdv fd = open(VMM_NODE, O_RDWR); 1037775ce89Sbluhm if (fd == -1) 1047775ce89Sbluhm err(1, "open %s", VMM_NODE); 105a944cd34Sdv 106a944cd34Sdv /* 1071ebbcee8Sdv * 1. Create our VM with 1 vcpu and 64 MiB of memory. 108a944cd34Sdv */ 109a944cd34Sdv memset(&vcp, 0, sizeof(vcp)); 110a944cd34Sdv strlcpy(vcp.vcp_name, VM_NAME, sizeof(vcp.vcp_name)); 111a944cd34Sdv vcp.vcp_ncpus = 1; 112a944cd34Sdv 113a944cd34Sdv /* Split into two ranges, similar to how vmd(8) might do it. */ 114a944cd34Sdv vcp.vcp_nmemranges = 2; 1151ebbcee8Sdv vcp.vcp_memranges[LOW_MEM].vmr_gpa = 0x0; 1161ebbcee8Sdv vcp.vcp_memranges[LOW_MEM].vmr_size = 640 * KIB; 1171ebbcee8Sdv vcp.vcp_memranges[UPPER_MEM].vmr_size = (64 * MIB) - (640 * KIB); 1181ebbcee8Sdv vcp.vcp_memranges[UPPER_MEM].vmr_gpa = (4 * GIB) 1191ebbcee8Sdv - vcp.vcp_memranges[UPPER_MEM].vmr_size; 120a944cd34Sdv 1211ebbcee8Sdv /* Allocate and Initialize our guest memory. */ 122a944cd34Sdv for (i = 0; i < vcp.vcp_nmemranges; i++) { 123a944cd34Sdv vmr = &vcp.vcp_memranges[i]; 1241ebbcee8Sdv if (vmr->vmr_size % 2 != 0) 1251ebbcee8Sdv errx(1, "memory ranges must be multiple of 2"); 1261ebbcee8Sdv 127a944cd34Sdv p = mmap(NULL, vmr->vmr_size, PROT_READ | PROT_WRITE, 128a944cd34Sdv MAP_PRIVATE | MAP_ANON, -1, 0); 129a944cd34Sdv if (p == MAP_FAILED) 130a944cd34Sdv err(1, "mmap"); 131a944cd34Sdv 132a944cd34Sdv vmr->vmr_va = (vaddr_t)p; 1333c817da7Sdv printf("created mapped region %zu: { gpa: 0x%08lx, size: %lu," 1343c817da7Sdv " hva: 0x%lx }\n", i, vmr->vmr_gpa, vmr->vmr_size, 1353c817da7Sdv vmr->vmr_va); 1361ebbcee8Sdv 1371ebbcee8Sdv /* Fill with int3 instructions. */ 1381ebbcee8Sdv memset(p, 0xcc, vmr->vmr_size); 1391ebbcee8Sdv 1401ebbcee8Sdv if (i == LOW_MEM) { 1411ebbcee8Sdv /* Write our IVT. */ 1421ebbcee8Sdv memcpy(p, &ivt, sizeof(ivt)); 1431ebbcee8Sdv 1441ebbcee8Sdv /* 1451ebbcee8Sdv * Set up a #GP handler that does a read from a 1461ebbcee8Sdv * non-existent PC Jr. Disk Controller. 1471ebbcee8Sdv */ 1481ebbcee8Sdv p = (uint8_t*)((uint8_t*)p + 0xb5d); 1491ebbcee8Sdv memcpy(p, IN_PCJR, sizeof(IN_PCJR)); 1501ebbcee8Sdv } else { 1511ebbcee8Sdv /* 1521ebbcee8Sdv * Write our code to the reset vector: 1531ebbcee8Sdv * PUSHW %dx ; inits the stack 1541ebbcee8Sdv * INS dx, es:[di] ; read from port in dx 1551ebbcee8Sdv */ 1561ebbcee8Sdv off = reset - vmr->vmr_gpa; 1571ebbcee8Sdv p = (uint8_t*)p + off; 1581ebbcee8Sdv memcpy(p, PUSHW_DX, sizeof(PUSHW_DX)); 1591ebbcee8Sdv p = (uint8_t*)p + sizeof(PUSHW_DX); 1601ebbcee8Sdv memcpy(p, INS, sizeof(INS)); 1611ebbcee8Sdv } 162a944cd34Sdv } 163a944cd34Sdv 164a944cd34Sdv if (ioctl(fd, VMM_IOC_CREATE, &vcp) == -1) 165a944cd34Sdv err(1, "VMM_IOC_CREATE"); 166a944cd34Sdv printf("created vm %d named \"%s\"\n", vcp.vcp_id, vcp.vcp_name); 167a944cd34Sdv 168a944cd34Sdv /* 1693c817da7Sdv * 2. Check we can create shared memory mappings. 1703c817da7Sdv */ 1713c817da7Sdv memset(&vsp, 0, sizeof(vsp)); 1723c817da7Sdv vsp.vsp_nmemranges = vcp.vcp_nmemranges; 1733c817da7Sdv memcpy(&vsp.vsp_memranges, &vcp.vcp_memranges, 1743c817da7Sdv sizeof(vsp.vsp_memranges)); 1753c817da7Sdv vsp.vsp_vm_id = vcp.vcp_id; 1763c817da7Sdv 1773c817da7Sdv /* Find some new va ranges... */ 1783c817da7Sdv for (i = 0; i < vsp.vsp_nmemranges; i++) { 1793c817da7Sdv vmr = &vsp.vsp_memranges[i]; 1803c817da7Sdv p = mmap(NULL, vmr->vmr_size, PROT_READ | PROT_WRITE, 1813c817da7Sdv MAP_PRIVATE | MAP_ANON, -1, 0); 1823c817da7Sdv if (p == MAP_FAILED) 1833c817da7Sdv err(1, "mmap"); 1843c817da7Sdv vmr->vmr_va = (vaddr_t)p; 1853c817da7Sdv } 1863c817da7Sdv 1873c817da7Sdv /* Release our mappings so vmm can replace them. */ 1883c817da7Sdv for (i = 0; i < vsp.vsp_nmemranges; i++) { 1893c817da7Sdv vmr = &vsp.vsp_memranges[i]; 1903c817da7Sdv munmap((void*)vmr->vmr_va, vmr->vmr_size); 1913c817da7Sdv } 1923c817da7Sdv 1933c817da7Sdv /* Perform the shared mapping. */ 1943c817da7Sdv if (ioctl(fd, VMM_IOC_SHAREMEM, &vsp) == -1) 1953c817da7Sdv err(1, "VMM_IOC_SHAREMEM"); 1963c817da7Sdv printf("created shared memory mappings\n"); 1973c817da7Sdv 1983c817da7Sdv /* We should see our reset vector instructions in the new mappings. */ 1993c817da7Sdv for (i = 0; i < vsp.vsp_nmemranges; i++) { 2003c817da7Sdv vmr = &vsp.vsp_memranges[i]; 2013c817da7Sdv p = (void*)vmr->vmr_va; 2023c817da7Sdv 2031ebbcee8Sdv if (i == LOW_MEM) { 2041ebbcee8Sdv /* Check if our IVT is there. */ 2051ebbcee8Sdv if (memcmp(&ivt, p, sizeof(ivt)) != 0) { 2061ebbcee8Sdv warnx("invalid ivt"); 2071ebbcee8Sdv goto out; 2081ebbcee8Sdv } 2091ebbcee8Sdv } else { 2101ebbcee8Sdv /* Check our code at the reset vector. */ 2111ebbcee8Sdv 2123c817da7Sdv } 2133c817da7Sdv printf("checked shared region %zu: { gpa: 0x%08lx, size: %lu," 2143c817da7Sdv " hva: 0x%lx }\n", i, vmr->vmr_gpa, vmr->vmr_size, 2153c817da7Sdv vmr->vmr_va); 2163c817da7Sdv } 2173c817da7Sdv printf("validated shared memory mappings\n"); 2183c817da7Sdv 2193c817da7Sdv /* 2203c817da7Sdv * 3. Check that our VM exists. 221a944cd34Sdv */ 222a944cd34Sdv memset(&vip, 0, sizeof(vip)); 223a944cd34Sdv vip.vip_size = 0; 224a944cd34Sdv info = NULL; 225a944cd34Sdv 226a944cd34Sdv if (ioctl(fd, VMM_IOC_INFO, &vip) == -1) { 227a944cd34Sdv warn("VMM_IOC_INFO(1)"); 228a944cd34Sdv goto out; 229a944cd34Sdv } 230a944cd34Sdv 231a944cd34Sdv if (vip.vip_size == 0) { 232a944cd34Sdv warn("no vms found"); 233a944cd34Sdv goto out; 234a944cd34Sdv } 235a944cd34Sdv 236a944cd34Sdv info = malloc(vip.vip_size); 237a944cd34Sdv if (info == NULL) { 238a944cd34Sdv warn("malloc"); 239a944cd34Sdv goto out; 240a944cd34Sdv } 241a944cd34Sdv 242a944cd34Sdv /* Second request that retrieves the VMs. */ 243a944cd34Sdv vip.vip_info = info; 244a944cd34Sdv if (ioctl(fd, VMM_IOC_INFO, &vip) == -1) { 245a944cd34Sdv warn("VMM_IOC_INFO(2)"); 246a944cd34Sdv goto out; 247a944cd34Sdv } 248a944cd34Sdv 2497775ce89Sbluhm for (i = 0; i * sizeof(*info) < vip.vip_size; i++) { 250a944cd34Sdv if (info[i].vir_id == vcp.vcp_id) { 251a944cd34Sdv ours = &info[i]; 252a944cd34Sdv break; 253a944cd34Sdv } 254a944cd34Sdv } 255a944cd34Sdv if (ours == NULL) { 256*6822f9c8Santon warn("failed to find vm %uz", vcp.vcp_id); 257a944cd34Sdv goto out; 258a944cd34Sdv } 259a944cd34Sdv 260a944cd34Sdv if (ours->vir_id != vcp.vcp_id) { 261a944cd34Sdv warnx("expected vm id %uz, got %uz", vcp.vcp_id, ours->vir_id); 262a944cd34Sdv goto out; 263a944cd34Sdv } 264a944cd34Sdv if (strncmp(ours->vir_name, VM_NAME, strlen(VM_NAME)) != 0) { 265a944cd34Sdv warnx("expected vm name \"%s\", got \"%s\"", VM_NAME, 266a944cd34Sdv ours->vir_name); 267a944cd34Sdv goto out; 268a944cd34Sdv } 269a944cd34Sdv printf("found vm %d named \"%s\"\n", vcp.vcp_id, ours->vir_name); 270a944cd34Sdv ours = NULL; 271a944cd34Sdv 272a944cd34Sdv /* 2733c817da7Sdv * 4. Reset our VCPU and initialize register state. 274a944cd34Sdv */ 275a944cd34Sdv memset(&vresetp, 0, sizeof(vresetp)); 276a944cd34Sdv vresetp.vrp_vm_id = vcp.vcp_id; 277a944cd34Sdv vresetp.vrp_vcpu_id = 0; /* XXX SP */ 278a944cd34Sdv memcpy(&vresetp.vrp_init_state, &vcpu_init_flat16, 279a944cd34Sdv sizeof(vcpu_init_flat16)); 280a944cd34Sdv 281a944cd34Sdv if (ioctl(fd, VMM_IOC_RESETCPU, &vresetp) == -1) { 282a944cd34Sdv warn("VMM_IOC_RESETCPU"); 283a944cd34Sdv goto out; 284a944cd34Sdv } 285a944cd34Sdv printf("reset vcpu %d for vm %d\n", vresetp.vrp_vcpu_id, 286a944cd34Sdv vresetp.vrp_vm_id); 287a944cd34Sdv 288a944cd34Sdv /* 2893c817da7Sdv * 5. Run the vcpu, expecting an immediate exit for IO assist. 290a944cd34Sdv */ 291a944cd34Sdv exit = malloc(sizeof(*exit)); 292a944cd34Sdv if (exit == NULL) { 293a944cd34Sdv warn("failed to allocate memory for vm_exit"); 294a944cd34Sdv goto out; 295a944cd34Sdv } 296a944cd34Sdv 297a944cd34Sdv memset(&vrunp, 0, sizeof(vrunp)); 298a944cd34Sdv vrunp.vrp_exit = exit; 299a944cd34Sdv vrunp.vrp_vcpu_id = 0; /* XXX SP */ 300a944cd34Sdv vrunp.vrp_vm_id = vcp.vcp_id; 301a944cd34Sdv vrunp.vrp_irqready = 1; 302a944cd34Sdv 303a944cd34Sdv if (ioctl(fd, VMM_IOC_RUN, &vrunp) == -1) { 304a944cd34Sdv warn("VMM_IOC_RUN"); 305a944cd34Sdv goto out; 306a944cd34Sdv } 307a944cd34Sdv 308a944cd34Sdv if (vrunp.vrp_vm_id != vcp.vcp_id) { 309*6822f9c8Santon warnx("expected vm id %uz, got %uz", vcp.vcp_id, 310a944cd34Sdv vrunp.vrp_vm_id); 311a944cd34Sdv goto out; 312a944cd34Sdv } 313a944cd34Sdv 314a944cd34Sdv switch (vrunp.vrp_exit_reason) { 315a944cd34Sdv case SVM_VMEXIT_IOIO: 316a944cd34Sdv case VMX_EXIT_IO: 3171ebbcee8Sdv printf("vcpu %d on vm %d exited for io assist @ ip = 0x%llx, " 3181ebbcee8Sdv "cs.base = 0x%llx, ss.base = 0x%llx, rsp = 0x%llx\n", 3191ebbcee8Sdv vrunp.vrp_vcpu_id, vrunp.vrp_vm_id, 3201ebbcee8Sdv vrunp.vrp_exit->vrs.vrs_gprs[VCPU_REGS_RIP], 3211ebbcee8Sdv vrunp.vrp_exit->vrs.vrs_sregs[VCPU_REGS_CS].vsi_base, 3221ebbcee8Sdv vrunp.vrp_exit->vrs.vrs_sregs[VCPU_REGS_SS].vsi_base, 3231ebbcee8Sdv vrunp.vrp_exit->vrs.vrs_gprs[VCPU_REGS_RSP]); 324a944cd34Sdv break; 325a944cd34Sdv default: 326a944cd34Sdv warnx("unexpected vm exit reason: 0%04x", 327a944cd34Sdv vrunp.vrp_exit_reason); 328a944cd34Sdv goto out; 329a944cd34Sdv } 330a944cd34Sdv 331a944cd34Sdv exit = vrunp.vrp_exit; 332a944cd34Sdv if (exit->vei.vei_port != PCKBC_AUX) { 333a944cd34Sdv warnx("expected io port to be PCKBC_AUX, got 0x%02x", 334a944cd34Sdv exit->vei.vei_port); 335a944cd34Sdv goto out; 336a944cd34Sdv } 3371ebbcee8Sdv if (exit->vei.vei_string != 1) { 3381ebbcee8Sdv warnx("expected string instruction (INS)"); 3391ebbcee8Sdv goto out; 3401ebbcee8Sdv } else 3411ebbcee8Sdv printf("got expected string instruction\n"); 3421ebbcee8Sdv 3431ebbcee8Sdv /* Advance RIP? */ 3441ebbcee8Sdv printf("insn_len = %u\n", exit->vei.vei_insn_len); 3451ebbcee8Sdv exit->vrs.vrs_gprs[VCPU_REGS_RIP] += exit->vei.vei_insn_len; 3461ebbcee8Sdv 3471ebbcee8Sdv /* 3481ebbcee8Sdv * Inject a #GP and see if we end up at our isr. 3491ebbcee8Sdv */ 3501ebbcee8Sdv vrunp.vrp_inject.vie_vector = VMM_EX_GP; 3511ebbcee8Sdv vrunp.vrp_inject.vie_errorcode = 0x11223344; 3521ebbcee8Sdv vrunp.vrp_inject.vie_type = VCPU_INJECT_EX; 3531ebbcee8Sdv printf("injecting exception 0x%x\n", vrunp.vrp_inject.vie_vector); 3541ebbcee8Sdv if (ioctl(fd, VMM_IOC_RUN, &vrunp) == -1) { 3551ebbcee8Sdv warn("VMM_IOC_RUN 2"); 3561ebbcee8Sdv goto out; 3571ebbcee8Sdv } 3581ebbcee8Sdv 3591ebbcee8Sdv switch (vrunp.vrp_exit_reason) { 3601ebbcee8Sdv case SVM_VMEXIT_IOIO: 3611ebbcee8Sdv case VMX_EXIT_IO: 3621ebbcee8Sdv printf("vcpu %d on vm %d exited for io assist @ ip = 0x%llx, " 3631ebbcee8Sdv "cs.base = 0x%llx\n", vrunp.vrp_vcpu_id, vrunp.vrp_vm_id, 3641ebbcee8Sdv vrunp.vrp_exit->vrs.vrs_gprs[VCPU_REGS_RIP], 3651ebbcee8Sdv vrunp.vrp_exit->vrs.vrs_sregs[VCPU_REGS_CS].vsi_base); 3661ebbcee8Sdv break; 3671ebbcee8Sdv default: 3681ebbcee8Sdv warnx("unexpected vm exit reason: 0%04x", 3691ebbcee8Sdv vrunp.vrp_exit_reason); 3701ebbcee8Sdv goto out; 3711ebbcee8Sdv } 3721ebbcee8Sdv 3731ebbcee8Sdv if (exit->vei.vei_port != PCJR_DISKCTRL) { 3741ebbcee8Sdv warnx("expected NMI handler to poke PCJR_DISKCTLR, got 0x%02x", 3751ebbcee8Sdv exit->vei.vei_port); 3761ebbcee8Sdv printf("rip = 0x%llx\n", exit->vrs.vrs_gprs[VCPU_REGS_RIP]); 3771ebbcee8Sdv goto out; 3781ebbcee8Sdv } 3791ebbcee8Sdv printf("exception handler called\n"); 380a944cd34Sdv 381a944cd34Sdv /* 382a944cd34Sdv * If we made it here, we're close to passing. Any failures during 383a944cd34Sdv * cleanup will reset ret back to non-zero. 384a944cd34Sdv */ 385a944cd34Sdv ret = 0; 386a944cd34Sdv 387a944cd34Sdv out: 3881ebbcee8Sdv printf("--- RESET VECTOR @ gpa 0x%llx ---\n", reset); 3891ebbcee8Sdv for (i=0; i<10; i++) { 3901ebbcee8Sdv if (i > 0) 3911ebbcee8Sdv printf(" "); 3921ebbcee8Sdv printf("%02x", *(uint8_t*) 3931ebbcee8Sdv (vsp.vsp_memranges[UPPER_MEM].vmr_va + off + i)); 3941ebbcee8Sdv } 3951ebbcee8Sdv printf("\n--- STACK @ gpa 0x%llx ---\n", stack); 3961ebbcee8Sdv for (i=0; i<16; i++) { 3971ebbcee8Sdv if (i > 0) 3981ebbcee8Sdv printf(" "); 3991ebbcee8Sdv printf("%02x", *(uint8_t*)(vsp.vsp_memranges[LOW_MEM].vmr_va 4001ebbcee8Sdv + stack - i - 1)); 4011ebbcee8Sdv } 4021ebbcee8Sdv printf("\n"); 4031ebbcee8Sdv 404a944cd34Sdv /* 4053c817da7Sdv * 6. Terminate our VM and clean up. 406a944cd34Sdv */ 407a944cd34Sdv memset(&vtp, 0, sizeof(vtp)); 408a944cd34Sdv vtp.vtp_vm_id = vcp.vcp_id; 409a944cd34Sdv if (ioctl(fd, VMM_IOC_TERM, &vtp) == -1) { 410a944cd34Sdv warn("VMM_IOC_TERM"); 411a944cd34Sdv ret = 1; 412a944cd34Sdv } else 413a944cd34Sdv printf("terminated vm %d\n", vtp.vtp_vm_id); 414a944cd34Sdv 415a944cd34Sdv close(fd); 416a944cd34Sdv free(info); 417a944cd34Sdv free(exit); 418a944cd34Sdv 419a944cd34Sdv /* Unmap memory. */ 420a944cd34Sdv for (i = 0; i < vcp.vcp_nmemranges; i++) { 421a944cd34Sdv vmr = &vcp.vcp_memranges[i]; 422a944cd34Sdv if (vmr->vmr_va) { 423a944cd34Sdv if (munmap((void *)vmr->vmr_va, vmr->vmr_size)) { 4243c817da7Sdv warn("failed to unmap orginal region %zu @ hva " 4253c817da7Sdv "0x%lx", i, vmr->vmr_va); 426a944cd34Sdv ret = 1; 427a944cd34Sdv } else 4283c817da7Sdv printf("unmapped origin region %zu @ hva " 4293c817da7Sdv "0x%lx\n", i, vmr->vmr_va); 4303c817da7Sdv } 4313c817da7Sdv vmr = &vsp.vsp_memranges[i]; 4323c817da7Sdv if (vmr->vmr_va) { 4333c817da7Sdv if (munmap((void *)vmr->vmr_va, vmr->vmr_size)) { 4343c817da7Sdv warn("failed to unmap shared region %zu @ hva " 4353c817da7Sdv "0x%lx", i, vmr->vmr_va); 4363c817da7Sdv ret = 1; 4373c817da7Sdv } else 4383c817da7Sdv printf("unmapped shared region %zu @ hva " 4393c817da7Sdv "0x%lx\n", i, vmr->vmr_va); 440a944cd34Sdv } 441a944cd34Sdv } 442a944cd34Sdv 443a944cd34Sdv return (ret); 444a944cd34Sdv } 445