xref: /illumos-gate/usr/src/cmd/mdb/intel/modules/vmm/vmm.c (revision 1a2d662a91cee3bf82f41cd47c7ae6f3825d9db2)
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