1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. 14 */ 15 16 #include <mdb/mdb_param.h> 17 #include <mdb/mdb_modapi.h> 18 #include <mdb/mdb_ctf.h> 19 20 #define _SYS_MACHPARAM_H 21 #include <sys/vmm_impl.h> 22 23 #include <stddef.h> 24 #include <stdbool.h> 25 26 typedef struct mdb_mem_map { 27 size_t len; 28 int segid; 29 } mdb_mem_map_t; 30 31 #define MDB_VM_MAX_MEMMAPS 8 32 33 typedef struct mdb_vm { 34 mdb_mem_map_t mem_maps[MDB_VM_MAX_MEMMAPS]; 35 uint16_t sockets, cores, threads; 36 bool mem_transient; 37 } mdb_vm_t; 38 39 typedef struct mdb_vmm_softc { 40 mdb_vm_t *vmm_vm; 41 char vmm_name[VM_MAX_NAMELEN]; 42 zone_t *vmm_zone; 43 uint_t vmm_flags; 44 } mdb_vmm_softc_t; 45 46 static uintptr_t mdb_zone0; 47 48 static int 49 i_vmm_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 50 { 51 mdb_vmm_softc_t vmm; 52 const char *vmname = NULL; 53 mdb_vm_t vm; 54 55 if (mdb_getopts(argc, argv, 56 'n', MDB_OPT_STR, &vmname, 57 NULL) != argc) { 58 return (DCMD_USAGE); 59 } 60 61 if (mdb_zone0 == 0) { 62 GElf_Sym sym; 63 64 if (mdb_lookup_by_name("zone0", &sym) == -1) 65 mdb_warn("failed to find 'zone0'"); 66 else 67 mdb_zone0 = sym.st_value; 68 } 69 70 if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) { 71 mdb_printf("%<u>%?s %?s %?s %5s %-6s %-3s %-6s %</u>\n", 72 "SOFTC", "VM", "ZONE", "TOPO", "MiB", "F", "NAME"); 73 } 74 75 if (mdb_ctf_vread(&vmm, "vmm_softc_t", "mdb_vmm_softc_t", 76 addr, 0) == -1) { 77 mdb_warn("can't read vmm_softc_t structure at %p", addr); 78 return (DCMD_ERR); 79 } 80 81 if (vmname && strcmp(vmname, vmm.vmm_name) != 0) 82 return (DCMD_OK); 83 84 if (flags & DCMD_PIPE_OUT) { 85 mdb_printf("%lr\n", addr); 86 return (DCMD_OK); 87 } 88 89 if (mdb_ctf_vread(&vm, "struct vm", "mdb_vm_t", 90 (uintptr_t)vmm.vmm_vm, 0) == -1) { 91 mdb_warn("can't read struct vm at %p", vmm.vmm_vm); 92 return (DCMD_ERR); 93 } 94 95 96 size_t memsize = 0; 97 for (uint_t i = 0; i < MDB_VM_MAX_MEMMAPS; i++) 98 memsize += vm.mem_maps[i].len; 99 100 mdb_printf("%0?p %0?p %0?p %d/%d/%d %-6d %c%c%c %s \n", 101 addr, vmm.vmm_vm, vmm.vmm_zone, 102 vm.sockets, vm.cores, vm.threads, 103 memsize / (1024 * 1024), 104 (uintptr_t)vmm.vmm_zone == mdb_zone0 ? 'G' : ' ', 105 vm.mem_transient ? 'T' : 'R', 106 (vmm.vmm_flags & VMM_AUTODESTROY) != 0 ? 'D' : ' ', 107 vmm.vmm_name); 108 109 return (DCMD_OK); 110 } 111 112 static int 113 vmm_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 114 { 115 if ((flags & DCMD_ADDRSPEC)) 116 return (i_vmm_dcmd(addr, flags, argc, argv)); 117 118 if (mdb_fpwalk_dcmd("vmm", "vmm", argc, argv, 0, 119 flags & DCMD_PIPE_OUT) == -1) { 120 mdb_warn("can't walk virtual machines"); 121 return (DCMD_ERR); 122 } 123 124 return (DCMD_OK); 125 } 126 127 static int 128 vmm_walk_init(mdb_walk_state_t *wsp) 129 { 130 GElf_Sym sym; 131 132 if (wsp->walk_addr == 0) { 133 if (mdb_lookup_by_name("vmm_list", &sym) == -1) { 134 mdb_warn("failed to find 'vmm_list'"); 135 return (WALK_ERR); 136 } 137 wsp->walk_addr = (uintptr_t)sym.st_value; 138 } 139 if (mdb_layered_walk("list", wsp) == -1) { 140 mdb_warn("couldn't walk 'list'"); 141 return (WALK_ERR); 142 } 143 return (WALK_NEXT); 144 } 145 146 static int 147 vmm_walk_step(mdb_walk_state_t *wsp) 148 { 149 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 150 wsp->walk_cbdata)); 151 } 152 153 static void 154 vmm_help(void) 155 { 156 mdb_printf("Prints summary information about vmm instances.\n"); 157 mdb_printf("\n%s", 158 "The resulting output is a table of bhyve virtual machines on the " 159 "system.\n" 160 "The columns in the output are:\n\n"); 161 mdb_printf("%s", 162 "SOFTC\t\tSoft state, pointer to vmm_softc_t\n" 163 "VM\t\tstate, pointer to 'struct vm'\n" 164 "TOPO\t\ttopology as sockets/cores/threads\n" 165 "MiB\t\tallocated memory\n" 166 "F\t\tFlags" 167 "\tG - VMM is created in the global zone.\n" 168 "\t\t\tT - VMM is using transient memory.\n" 169 "\t\t\tR - VMM is using memory from reservoir.\n" 170 "\t\t\tD - VMM is set to auto-destruct.\n" 171 "NAME\t\tThe virtual machine name.\n" 172 "ZONE\t\tThe zone_t pointer to zone where the vm is running.\n"); 173 mdb_dec_indent(2); 174 mdb_printf("\n%<b>OPTIONS%</b>\n"); 175 mdb_inc_indent(2); 176 mdb_printf("-n <name>\tOnly show the virtual machine called <name>\n"); 177 mdb_dec_indent(2); 178 mdb_printf("\n%<b>NOTES%</b>\n"); 179 mdb_inc_indent(2); 180 mdb_printf("%s", 181 "The MiB column sums up all memory segments and includes any\n" 182 "memory allocated for the bootrom or framebuffer.\n" 183 "\n" 184 "Passing the output of this command into a pipeline results in\n" 185 "the address of the vmm_softc_t in '.'\n"); 186 } 187 188 static const mdb_dcmd_t dcmds[] = { 189 { "vmm", "?[-n vmname]", 190 "print virtual machine information", vmm_dcmd, vmm_help }, 191 { NULL } 192 }; 193 194 static const mdb_walker_t walkers[] = { 195 { "vmm", "walk a list of virtual machines", 196 vmm_walk_init, vmm_walk_step, NULL }, 197 { NULL } 198 }; 199 200 static const mdb_modinfo_t modinfo = { 201 MDB_API_VERSION, dcmds, walkers 202 }; 203 204 const mdb_modinfo_t * 205 _mdb_init(void) 206 { 207 return (&modinfo); 208 } 209