xref: /openbsd-src/usr.sbin/ldomctl/ldomctl.c (revision 116f3cbfa99016305486ec0c1fc58090ee6bb7d6)
1*116f3cbfSkn /*	$OpenBSD: ldomctl.c,v 1.41 2023/08/10 07:50:45 kn Exp $	*/
26af60be8Skettenis 
36af60be8Skettenis /*
46af60be8Skettenis  * Copyright (c) 2012 Mark Kettenis
56af60be8Skettenis  *
66af60be8Skettenis  * Permission to use, copy, modify, and distribute this software for any
76af60be8Skettenis  * purpose with or without fee is hereby granted, provided that the above
86af60be8Skettenis  * copyright notice and this permission notice appear in all copies.
96af60be8Skettenis  *
106af60be8Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116af60be8Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126af60be8Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136af60be8Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146af60be8Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
156af60be8Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
166af60be8Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176af60be8Skettenis  */
186af60be8Skettenis 
196af60be8Skettenis #include <sys/types.h>
20b01cf3d3Skettenis #include <sys/ioctl.h>
2115a1baa2Skn #include <sys/stat.h>
226af60be8Skettenis #include <err.h>
2315a1baa2Skn #include <errno.h>
246af60be8Skettenis #include <fcntl.h>
256af60be8Skettenis #include <stdlib.h>
266af60be8Skettenis #include <stdio.h>
276af60be8Skettenis #include <string.h>
286af60be8Skettenis #include <unistd.h>
2915a1baa2Skn #include <util.h>
306af60be8Skettenis 
31e32fd68fSkettenis #include "ds.h"
3287832736Skettenis #include "hvctl.h"
33cceaa36bSkettenis #include "mdstore.h"
34b01cf3d3Skettenis #include "mdesc.h"
35d73a4c4fSkn #include "ldom_util.h"
36bb93e559Skettenis #include "ldomctl.h"
37e32fd68fSkettenis 
38f5d51570Skettenis extern struct ds_service pri_service;
39f5d51570Skettenis 
406af60be8Skettenis struct command {
416af60be8Skettenis 	const char *cmd_name;
426af60be8Skettenis 	void (*cmd_func)(int, char **);
436af60be8Skettenis };
446af60be8Skettenis 
456af60be8Skettenis __dead void usage(void);
466af60be8Skettenis 
4797d8cafcSkettenis struct guest_head guest_list;
48b01cf3d3Skettenis 
49b01cf3d3Skettenis uint64_t find_guest(const char *);
50b01cf3d3Skettenis 
51e32fd68fSkettenis void fetch_pri(void);
52e32fd68fSkettenis 
53dc8fdf3dSkettenis void download(int argc, char **argv);
5419d88dc6Skettenis void dump(int argc, char **argv);
55cceaa36bSkettenis void list(int argc, char **argv);
56b300726bSkn void list_io(int argc, char **argv);
576aace0ceSkettenis void xselect(int argc, char **argv);
58dc8fdf3dSkettenis void delete(int argc, char **argv);
5915a1baa2Skn void create_vdisk(int argc, char **argv);
606af60be8Skettenis void guest_start(int argc, char **argv);
616af60be8Skettenis void guest_stop(int argc, char **argv);
6243a483c9Skettenis void guest_panic(int argc, char **argv);
63298adc64Skettenis void guest_status(int argc, char **argv);
644f98d0d5Skn void guest_console(int argc, char **argv);
6597d8cafcSkettenis void init_system(int argc, char **argv);
666af60be8Skettenis 
676af60be8Skettenis struct command commands[] = {
68dc8fdf3dSkettenis 	{ "download",	download },
6919d88dc6Skettenis 	{ "dump",	dump },
70cceaa36bSkettenis 	{ "list",	list },
71b300726bSkn 	{ "list-io",	list_io },
726aace0ceSkettenis 	{ "select",	xselect },
73dc8fdf3dSkettenis 	{ "delete",	delete },
7415a1baa2Skn 	{ "create-vdisk", create_vdisk },
756af60be8Skettenis 	{ "start",	guest_start },
766af60be8Skettenis 	{ "stop",	guest_stop },
7743a483c9Skettenis 	{ "panic",	guest_panic },
78298adc64Skettenis 	{ "status",	guest_status },
794f98d0d5Skn 	{ "console",	guest_console },
8097d8cafcSkettenis 	{ "init-system", init_system },
816af60be8Skettenis 	{ NULL,		NULL }
826af60be8Skettenis };
836af60be8Skettenis 
8487832736Skettenis void hv_open(void);
8587832736Skettenis void hv_close(void);
8676c0d977Skn void hv_config(void);
8787832736Skettenis void hv_read(uint64_t, void *, size_t);
8887832736Skettenis void hv_write(uint64_t, void *, size_t);
8987832736Skettenis 
90e32fd68fSkettenis int hvctl_seq = 1;
91e32fd68fSkettenis int hvctl_fd;
926af60be8Skettenis 
9319d88dc6Skettenis void *hvmd_buf;
9419d88dc6Skettenis size_t hvmd_len;
9587832736Skettenis uint64_t hv_mdpa;
96ecf7be60Skettenis uint64_t hv_membase;
97ecf7be60Skettenis uint64_t hv_memsize;
98b01cf3d3Skettenis 
99e32fd68fSkettenis extern void *pri_buf;
100e32fd68fSkettenis extern size_t pri_len;
101e32fd68fSkettenis 
1026af60be8Skettenis int
main(int argc,char ** argv)1036af60be8Skettenis main(int argc, char **argv)
1046af60be8Skettenis {
1056af60be8Skettenis 	struct command *cmdp;
1066af60be8Skettenis 
107b01cf3d3Skettenis 	if (argc < 2)
1086af60be8Skettenis 		usage();
1096af60be8Skettenis 
1106af60be8Skettenis 	/* Skip program name. */
1116af60be8Skettenis 	argv++;
1126af60be8Skettenis 	argc--;
1136af60be8Skettenis 
1146af60be8Skettenis 	for (cmdp = commands; cmdp->cmd_name != NULL; cmdp++)
1156af60be8Skettenis 		if (strcmp(argv[0], cmdp->cmd_name) == 0)
1166af60be8Skettenis 			break;
1176af60be8Skettenis 	if (cmdp->cmd_name == NULL)
1186af60be8Skettenis 		usage();
1196af60be8Skettenis 
1206af60be8Skettenis 	(cmdp->cmd_func)(argc, argv);
1216af60be8Skettenis 
1226af60be8Skettenis 	exit(EXIT_SUCCESS);
1236af60be8Skettenis }
1246af60be8Skettenis 
1254f98d0d5Skn __dead void
usage(void)1266af60be8Skettenis usage(void)
1276af60be8Skettenis {
12880e26870Skn 	fprintf(stderr, "usage:\t%1$s delete|select configuration\n"
12980e26870Skn 	    "\t%1$s download directory\n"
130b300726bSkn 	    "\t%1$s dump|list|list-io\n"
13199a0bfacSkn 	    "\t%1$s init-system [-n] file\n"
13215a1baa2Skn 	    "\t%1$s create-vdisk -s size file\n"
133e5932329Skn 	    "\t%1$s panic|start [-c] domain\n"
134e5932329Skn 	    "\t%1$s console|status|stop [domain]\n",
135fdd39fabSkn 	    getprogname());
136fdd39fabSkn 
1376af60be8Skettenis 	exit(EXIT_FAILURE);
1386af60be8Skettenis }
1396af60be8Skettenis 
1406af60be8Skettenis void
add_guest(struct md_node * node)141b01cf3d3Skettenis add_guest(struct md_node *node)
142b01cf3d3Skettenis {
143b01cf3d3Skettenis 	struct guest *guest;
144bc850a97Skettenis 	struct md_prop *prop;
145b01cf3d3Skettenis 
146b01cf3d3Skettenis 	guest = xmalloc(sizeof(*guest));
147b01cf3d3Skettenis 
148b01cf3d3Skettenis 	if (!md_get_prop_str(hvmd, node, "name", &guest->name))
149b01cf3d3Skettenis 		goto free;
150b01cf3d3Skettenis 	if (!md_get_prop_val(hvmd, node, "gid", &guest->gid))
151b01cf3d3Skettenis 		goto free;
15219d88dc6Skettenis 	if (!md_get_prop_val(hvmd, node, "mdpa", &guest->mdpa))
15319d88dc6Skettenis 		goto free;
154b01cf3d3Skettenis 
155bc850a97Skettenis 	guest->num_cpus = 0;
156bc850a97Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
157bc850a97Skettenis 		if (prop->tag == MD_PROP_ARC &&
158bc850a97Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
159bc850a97Skettenis 			if (strcmp(prop->d.arc.node->name->str, "cpu") == 0)
160bc850a97Skettenis 				guest->num_cpus++;
161bc850a97Skettenis 		}
162bc850a97Skettenis 	}
163bc850a97Skettenis 
16497d8cafcSkettenis 	TAILQ_INSERT_TAIL(&guest_list, guest, link);
165e8c8ae67Skettenis 	return;
166e8c8ae67Skettenis 
167b01cf3d3Skettenis free:
168b01cf3d3Skettenis 	free(guest);
169b01cf3d3Skettenis }
170b01cf3d3Skettenis 
171b01cf3d3Skettenis uint64_t
find_guest(const char * name)172b01cf3d3Skettenis find_guest(const char *name)
173b01cf3d3Skettenis {
174b01cf3d3Skettenis 	struct guest *guest;
175b01cf3d3Skettenis 
17697d8cafcSkettenis 	TAILQ_FOREACH(guest, &guest_list, link) {
177b01cf3d3Skettenis 		if (strcmp(guest->name, name) == 0)
178b01cf3d3Skettenis 			return guest->gid;
179b01cf3d3Skettenis 	}
180b01cf3d3Skettenis 
181b01cf3d3Skettenis 	errx(EXIT_FAILURE, "unknown guest '%s'", name);
182b01cf3d3Skettenis }
183b01cf3d3Skettenis 
184b01cf3d3Skettenis void
fetch_pri(void)185e32fd68fSkettenis fetch_pri(void)
186e32fd68fSkettenis {
187f5d51570Skettenis 	struct ds_conn *dc;
188e32fd68fSkettenis 
189f5d51570Skettenis 	dc = ds_conn_open("/dev/spds", NULL);
190f5d51570Skettenis 	ds_conn_register_service(dc, &pri_service);
191f5d51570Skettenis 	while (pri_buf == NULL)
192f5d51570Skettenis 		ds_conn_handle(dc);
193e32fd68fSkettenis }
194e32fd68fSkettenis 
195e32fd68fSkettenis void
dump(int argc,char ** argv)19619d88dc6Skettenis dump(int argc, char **argv)
19719d88dc6Skettenis {
19819d88dc6Skettenis 	struct guest *guest;
19919d88dc6Skettenis 	struct md_header hdr;
20019d88dc6Skettenis 	void *md_buf;
20119d88dc6Skettenis 	size_t md_len;
20219d88dc6Skettenis 	char *name;
20319d88dc6Skettenis 	FILE *fp;
20419d88dc6Skettenis 
20519d88dc6Skettenis 	if (argc != 1)
20619d88dc6Skettenis 		usage();
20719d88dc6Skettenis 
208c9bcb21bSkn 	hv_config();
209c9bcb21bSkn 
21019d88dc6Skettenis 	fp = fopen("hv.md", "w");
21119d88dc6Skettenis 	if (fp == NULL)
21219d88dc6Skettenis 		err(1, "fopen");
21319d88dc6Skettenis 	fwrite(hvmd_buf, hvmd_len, 1, fp);
21419d88dc6Skettenis 	fclose(fp);
21519d88dc6Skettenis 
216e32fd68fSkettenis 	fetch_pri();
217e32fd68fSkettenis 
218e32fd68fSkettenis 	fp = fopen("pri", "w");
219e32fd68fSkettenis 	if (fp == NULL)
220e32fd68fSkettenis 		err(1, "fopen");
221e32fd68fSkettenis 	fwrite(pri_buf, pri_len, 1, fp);
222e32fd68fSkettenis 	fclose(fp);
223e32fd68fSkettenis 
22497d8cafcSkettenis 	TAILQ_FOREACH(guest, &guest_list, link) {
22587832736Skettenis 		hv_read(guest->mdpa, &hdr, sizeof(hdr));
22619d88dc6Skettenis 		md_len = sizeof(hdr) + hdr.node_blk_sz + hdr.name_blk_sz +
22719d88dc6Skettenis 		    hdr.data_blk_sz;
228cd2fb5bfSkettenis 		md_buf = xmalloc(md_len);
22987832736Skettenis 		hv_read(guest->mdpa, md_buf, md_len);
23019d88dc6Skettenis 
23119d88dc6Skettenis 		if (asprintf(&name, "%s.md", guest->name) == -1)
23219d88dc6Skettenis 			err(1, "asprintf");
23319d88dc6Skettenis 
23419d88dc6Skettenis 		fp = fopen(name, "w");
23519d88dc6Skettenis 		if (fp == NULL)
23619d88dc6Skettenis 			err(1, "fopen");
23719d88dc6Skettenis 		fwrite(md_buf, md_len, 1, fp);
23819d88dc6Skettenis 		fclose(fp);
23919d88dc6Skettenis 
24019d88dc6Skettenis 		free(name);
24119d88dc6Skettenis 		free(md_buf);
24219d88dc6Skettenis 	}
24319d88dc6Skettenis }
24419d88dc6Skettenis 
24519d88dc6Skettenis void
init_system(int argc,char ** argv)24697d8cafcSkettenis init_system(int argc, char **argv)
24797d8cafcSkettenis {
24899a0bfacSkn 	int ch, noaction = 0;
24999a0bfacSkn 
25099a0bfacSkn 	while ((ch = getopt(argc, argv, "n")) != -1) {
25199a0bfacSkn 		switch (ch) {
25299a0bfacSkn 		case 'n':
25399a0bfacSkn 			noaction = 1;
25499a0bfacSkn 			break;
25599a0bfacSkn 		default:
25699a0bfacSkn 			usage();
25799a0bfacSkn 		}
25899a0bfacSkn 	}
25999a0bfacSkn 	argc -= optind;
26099a0bfacSkn 	argv += optind;
26199a0bfacSkn 
26299a0bfacSkn 	if (argc != 1)
26397d8cafcSkettenis 		usage();
26497d8cafcSkettenis 
26599a0bfacSkn 	if (!noaction)
26676c0d977Skn 		hv_config();
26776c0d977Skn 
26899a0bfacSkn 	build_config(argv[0], noaction);
26997d8cafcSkettenis }
27097d8cafcSkettenis 
27197d8cafcSkettenis void
list(int argc,char ** argv)272cceaa36bSkettenis list(int argc, char **argv)
273cceaa36bSkettenis {
274cceaa36bSkettenis 	struct ds_conn *dc;
275cceaa36bSkettenis 	struct mdstore_set *set;
276cceaa36bSkettenis 
277609d601bSkn 	if (argc != 1)
278609d601bSkn 		usage();
279609d601bSkn 
28076c0d977Skn 	hv_config();
28176c0d977Skn 
282cceaa36bSkettenis 	dc = ds_conn_open("/dev/spds", NULL);
283a0709405Skettenis 	mdstore_register(dc);
284cceaa36bSkettenis 	while (TAILQ_EMPTY(&mdstore_sets))
285cceaa36bSkettenis 		ds_conn_handle(dc);
286cceaa36bSkettenis 
287cceaa36bSkettenis 	TAILQ_FOREACH(set, &mdstore_sets, link) {
288cceaa36bSkettenis 		printf("%s", set->name);
289cceaa36bSkettenis 		if (set->booted_set)
290cceaa36bSkettenis 			printf(" [current]");
291cceaa36bSkettenis 		else if (set->boot_set)
292cceaa36bSkettenis 			printf(" [next]");
293cceaa36bSkettenis 		printf("\n");
294cceaa36bSkettenis 	}
295cceaa36bSkettenis }
296cceaa36bSkettenis 
297cceaa36bSkettenis void
list_io(int argc,char ** argv)298b300726bSkn list_io(int argc, char **argv)
299b300726bSkn {
300b300726bSkn 	if (argc != 1)
301b300726bSkn 		usage();
302b300726bSkn 
303b300726bSkn 	list_components();
304b300726bSkn }
305b300726bSkn 
306b300726bSkn void
xselect(int argc,char ** argv)3076aace0ceSkettenis xselect(int argc, char **argv)
3086aace0ceSkettenis {
3096aace0ceSkettenis 	struct ds_conn *dc;
3106aace0ceSkettenis 
311609d601bSkn 	if (argc != 2)
3126aace0ceSkettenis 		usage();
3136aace0ceSkettenis 
31476c0d977Skn 	hv_config();
31576c0d977Skn 
3166aace0ceSkettenis 	dc = ds_conn_open("/dev/spds", NULL);
317a0709405Skettenis 	mdstore_register(dc);
3186aace0ceSkettenis 	while (TAILQ_EMPTY(&mdstore_sets))
3196aace0ceSkettenis 		ds_conn_handle(dc);
3206aace0ceSkettenis 
3216aace0ceSkettenis 	mdstore_select(dc, argv[1]);
3226aace0ceSkettenis }
3236aace0ceSkettenis 
3246aace0ceSkettenis void
delete(int argc,char ** argv)325dc8fdf3dSkettenis delete(int argc, char **argv)
326dc8fdf3dSkettenis {
327dc8fdf3dSkettenis 	struct ds_conn *dc;
328dc8fdf3dSkettenis 
329609d601bSkn 	if (argc != 2)
330dc8fdf3dSkettenis 		usage();
331dc8fdf3dSkettenis 
3324948195dSkettenis 	if (strcmp(argv[1], "factory-default") == 0)
3334948195dSkettenis 		errx(1, "\"%s\" should not be deleted", argv[1]);
3344948195dSkettenis 
33576c0d977Skn 	hv_config();
33676c0d977Skn 
337dc8fdf3dSkettenis 	dc = ds_conn_open("/dev/spds", NULL);
338a0709405Skettenis 	mdstore_register(dc);
339dc8fdf3dSkettenis 	while (TAILQ_EMPTY(&mdstore_sets))
340dc8fdf3dSkettenis 		ds_conn_handle(dc);
341dc8fdf3dSkettenis 
342dc8fdf3dSkettenis 	mdstore_delete(dc, argv[1]);
343dc8fdf3dSkettenis }
344dc8fdf3dSkettenis 
345dc8fdf3dSkettenis void
create_vdisk(int argc,char ** argv)34615a1baa2Skn create_vdisk(int argc, char **argv)
34715a1baa2Skn {
34815a1baa2Skn 	int ch, fd, save_errno;
34915a1baa2Skn 	long long imgsize;
35015a1baa2Skn 	const char *imgfile_path;
35115a1baa2Skn 
35215a1baa2Skn 	while ((ch = getopt(argc, argv, "s:")) != -1) {
35315a1baa2Skn 		switch (ch) {
35415a1baa2Skn 		case 's':
35515a1baa2Skn 			if (scan_scaled(optarg, &imgsize) == -1)
35615a1baa2Skn 				err(1, "invalid size: %s", optarg);
35715a1baa2Skn 			break;
35815a1baa2Skn 		default:
35915a1baa2Skn 			usage();
36015a1baa2Skn 		}
36115a1baa2Skn 	}
36215a1baa2Skn 	argc -= optind;
36315a1baa2Skn 	argv += optind;
36415a1baa2Skn 
36515a1baa2Skn 	if (argc != 1)
36615a1baa2Skn 		usage();
36715a1baa2Skn 
36815a1baa2Skn 	imgfile_path = argv[0];
36915a1baa2Skn 
37015a1baa2Skn 	/* Refuse to overwrite an existing image */
37115a1baa2Skn 	if ((fd = open(imgfile_path, O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
37215a1baa2Skn 	    S_IRUSR | S_IWUSR)) == -1)
37315a1baa2Skn 		err(1, "open");
37415a1baa2Skn 
37515a1baa2Skn 	/* Extend to desired size */
37615a1baa2Skn 	if (ftruncate(fd, (off_t)imgsize) == -1) {
37715a1baa2Skn 		save_errno = errno;
37815a1baa2Skn 		close(fd);
37915a1baa2Skn 		unlink(imgfile_path);
38015a1baa2Skn 		errno = save_errno;
38115a1baa2Skn 		err(1, "ftruncate");
38215a1baa2Skn 	}
38315a1baa2Skn 
38415a1baa2Skn 	close(fd);
38515a1baa2Skn }
38615a1baa2Skn 
38715a1baa2Skn void
download(int argc,char ** argv)388dc8fdf3dSkettenis download(int argc, char **argv)
389dc8fdf3dSkettenis {
390dc8fdf3dSkettenis 	struct ds_conn *dc;
391dc8fdf3dSkettenis 
392609d601bSkn 	if (argc != 2)
393dc8fdf3dSkettenis 		usage();
394dc8fdf3dSkettenis 
39576c0d977Skn 	hv_config();
39676c0d977Skn 
397dc8fdf3dSkettenis 	dc = ds_conn_open("/dev/spds", NULL);
398a0709405Skettenis 	mdstore_register(dc);
399dc8fdf3dSkettenis 	while (TAILQ_EMPTY(&mdstore_sets))
400dc8fdf3dSkettenis 		ds_conn_handle(dc);
401dc8fdf3dSkettenis 
402dc8fdf3dSkettenis 	mdstore_download(dc, argv[1]);
403dc8fdf3dSkettenis }
404dc8fdf3dSkettenis 
405dc8fdf3dSkettenis void
console_exec(uint64_t gid)406fdd39fabSkn console_exec(uint64_t gid)
407fdd39fabSkn {
408fdd39fabSkn 	struct guest *guest;
409fdd39fabSkn 	char console_str[8];
410fdd39fabSkn 
411fdd39fabSkn 	if (gid == 0)
412fdd39fabSkn 		errx(1, "no console for primary domain");
413fdd39fabSkn 
414fdd39fabSkn 	TAILQ_FOREACH(guest, &guest_list, link) {
415fdd39fabSkn 		if (guest->gid != gid)
416fdd39fabSkn 			continue;
417fdd39fabSkn 		snprintf(console_str, sizeof(console_str),
418fdd39fabSkn 		    "ttyV%llu", guest->gid - 1);
419fdd39fabSkn 
420fdd39fabSkn 		closefrom(STDERR_FILENO + 1);
421fdd39fabSkn 		execl(LDOMCTL_CU, LDOMCTL_CU, "-r", "-l", console_str,
422fdd39fabSkn 		    (char *)NULL);
423fdd39fabSkn 		err(1, "failed to open console");
424fdd39fabSkn 	}
425fdd39fabSkn }
426fdd39fabSkn 
427fdd39fabSkn void
guest_start(int argc,char ** argv)4286af60be8Skettenis guest_start(int argc, char **argv)
4296af60be8Skettenis {
4306af60be8Skettenis 	struct hvctl_msg msg;
4316af60be8Skettenis 	ssize_t nbytes;
432fdd39fabSkn 	uint64_t gid;
433fdd39fabSkn 	int ch, console = 0;
4346af60be8Skettenis 
435fdd39fabSkn 	while ((ch = getopt(argc, argv, "c")) != -1) {
436fdd39fabSkn 		switch (ch) {
437fdd39fabSkn 		case 'c':
438fdd39fabSkn 			console = 1;
439fdd39fabSkn 			break;
440fdd39fabSkn 		default:
441fdd39fabSkn 			usage();
442fdd39fabSkn 		}
443fdd39fabSkn 	}
444fdd39fabSkn 	argc -= optind;
445fdd39fabSkn 	argv += optind;
446fdd39fabSkn 
447fdd39fabSkn 	if (argc != 1)
448b01cf3d3Skettenis 		usage();
449b01cf3d3Skettenis 
45076c0d977Skn 	hv_config();
45176c0d977Skn 
452fdd39fabSkn 	gid = find_guest(argv[0]);
453fdd39fabSkn 
4546af60be8Skettenis 	/*
4556af60be8Skettenis 	 * Start guest domain.
4566af60be8Skettenis 	 */
4576af60be8Skettenis 	bzero(&msg, sizeof(msg));
4586af60be8Skettenis 	msg.hdr.op = HVCTL_OP_GUEST_START;
459e32fd68fSkettenis 	msg.hdr.seq = hvctl_seq++;
460fdd39fabSkn 	msg.msg.guestop.guestid = gid;
461e32fd68fSkettenis 	nbytes = write(hvctl_fd, &msg, sizeof(msg));
4626af60be8Skettenis 	if (nbytes != sizeof(msg))
4636af60be8Skettenis 		err(1, "write");
4646af60be8Skettenis 
4656af60be8Skettenis 	bzero(&msg, sizeof(msg));
466e32fd68fSkettenis 	nbytes = read(hvctl_fd, &msg, sizeof(msg));
4676af60be8Skettenis 	if (nbytes != sizeof(msg))
4686af60be8Skettenis 		err(1, "read");
469fdd39fabSkn 
470fdd39fabSkn 	if (console)
471fdd39fabSkn 		console_exec(gid);
4726af60be8Skettenis }
4736af60be8Skettenis 
4746af60be8Skettenis void
guest_stop(int argc,char ** argv)4756af60be8Skettenis guest_stop(int argc, char **argv)
4766af60be8Skettenis {
4776af60be8Skettenis 	struct hvctl_msg msg;
4786af60be8Skettenis 	ssize_t nbytes;
4796af60be8Skettenis 
480609d601bSkn 	if (argc != 2)
481b01cf3d3Skettenis 		usage();
482b01cf3d3Skettenis 
48376c0d977Skn 	hv_config();
48476c0d977Skn 
4856af60be8Skettenis 	/*
4866af60be8Skettenis 	 * Stop guest domain.
4876af60be8Skettenis 	 */
4886af60be8Skettenis 	bzero(&msg, sizeof(msg));
4896af60be8Skettenis 	msg.hdr.op = HVCTL_OP_GUEST_STOP;
490e32fd68fSkettenis 	msg.hdr.seq = hvctl_seq++;
491b01cf3d3Skettenis 	msg.msg.guestop.guestid = find_guest(argv[1]);
492e32fd68fSkettenis 	nbytes = write(hvctl_fd, &msg, sizeof(msg));
4936af60be8Skettenis 	if (nbytes != sizeof(msg))
4946af60be8Skettenis 		err(1, "write");
4956af60be8Skettenis 
4966af60be8Skettenis 	bzero(&msg, sizeof(msg));
497e32fd68fSkettenis 	nbytes = read(hvctl_fd, &msg, sizeof(msg));
4986af60be8Skettenis 	if (nbytes != sizeof(msg))
4996af60be8Skettenis 		err(1, "read");
5006af60be8Skettenis }
501298adc64Skettenis 
502298adc64Skettenis void
guest_panic(int argc,char ** argv)50343a483c9Skettenis guest_panic(int argc, char **argv)
50443a483c9Skettenis {
50543a483c9Skettenis 	struct hvctl_msg msg;
50643a483c9Skettenis 	ssize_t nbytes;
507e5932329Skn 	uint64_t gid;
508e5932329Skn 	int ch, console = 0;
50943a483c9Skettenis 
510e5932329Skn 	while ((ch = getopt(argc, argv, "c")) != -1) {
511e5932329Skn 		switch (ch) {
512e5932329Skn 		case 'c':
513e5932329Skn 			console = 1;
514e5932329Skn 			break;
515e5932329Skn 		default:
516e5932329Skn 			usage();
517e5932329Skn 		}
518e5932329Skn 	}
519e5932329Skn 	argc -= optind;
520e5932329Skn 	argv += optind;
521e5932329Skn 
522e5932329Skn 	if (argc != 1)
52343a483c9Skettenis 		usage();
52443a483c9Skettenis 
52576c0d977Skn 	hv_config();
52676c0d977Skn 
527e5932329Skn 	gid = find_guest(argv[0]);
528e5932329Skn 
52943a483c9Skettenis 	/*
53043a483c9Skettenis 	 * Stop guest domain.
53143a483c9Skettenis 	 */
53243a483c9Skettenis 	bzero(&msg, sizeof(msg));
53343a483c9Skettenis 	msg.hdr.op = HVCTL_OP_GUEST_PANIC;
53443a483c9Skettenis 	msg.hdr.seq = hvctl_seq++;
535e5932329Skn 	msg.msg.guestop.guestid = gid;
53643a483c9Skettenis 	nbytes = write(hvctl_fd, &msg, sizeof(msg));
53743a483c9Skettenis 	if (nbytes != sizeof(msg))
53843a483c9Skettenis 		err(1, "write");
53943a483c9Skettenis 
54043a483c9Skettenis 	bzero(&msg, sizeof(msg));
54143a483c9Skettenis 	nbytes = read(hvctl_fd, &msg, sizeof(msg));
54243a483c9Skettenis 	if (nbytes != sizeof(msg))
54343a483c9Skettenis 		err(1, "read");
544e5932329Skn 
545e5932329Skn 	if (console)
546e5932329Skn 		console_exec(gid);
54743a483c9Skettenis }
54843a483c9Skettenis 
54943a483c9Skettenis void
guest_status(int argc,char ** argv)550298adc64Skettenis guest_status(int argc, char **argv)
551298adc64Skettenis {
552298adc64Skettenis 	struct hvctl_msg msg;
553298adc64Skettenis 	ssize_t nbytes;
554bc850a97Skettenis 	struct hvctl_rs_guest_state state;
555bc850a97Skettenis 	struct hvctl_rs_guest_softstate softstate;
556bc850a97Skettenis 	struct hvctl_rs_guest_util util;
557b01cf3d3Skettenis 	struct guest *guest;
558b01cf3d3Skettenis 	uint64_t gid = -1;
559bc850a97Skettenis 	uint64_t total_cycles, yielded_cycles;
560bc850a97Skettenis 	double utilisation = 0.0;
561b01cf3d3Skettenis 	const char *state_str;
5624a9de534Skn 	char buf[32];
5634a9de534Skn 	char console_str[8] = "-";
564b01cf3d3Skettenis 
565b01cf3d3Skettenis 	if (argc < 1 || argc > 2)
566b01cf3d3Skettenis 		usage();
56776c0d977Skn 
56876c0d977Skn 	hv_config();
56976c0d977Skn 
570b01cf3d3Skettenis 	if (argc == 2)
571b01cf3d3Skettenis 		gid = find_guest(argv[1]);
572b01cf3d3Skettenis 
57397d8cafcSkettenis 	TAILQ_FOREACH(guest, &guest_list, link) {
574b01cf3d3Skettenis 		if (gid != -1 && guest->gid != gid)
575b01cf3d3Skettenis 			continue;
576298adc64Skettenis 
577298adc64Skettenis 		/*
578298adc64Skettenis 		 * Request status.
579298adc64Skettenis 		 */
580298adc64Skettenis 		bzero(&msg, sizeof(msg));
581298adc64Skettenis 		msg.hdr.op = HVCTL_OP_GET_RES_STAT;
582e32fd68fSkettenis 		msg.hdr.seq = hvctl_seq++;
583298adc64Skettenis 		msg.msg.resstat.res = HVCTL_RES_GUEST;
584b01cf3d3Skettenis 		msg.msg.resstat.resid = guest->gid;
585298adc64Skettenis 		msg.msg.resstat.infoid = HVCTL_INFO_GUEST_STATE;
586e32fd68fSkettenis 		nbytes = write(hvctl_fd, &msg, sizeof(msg));
587298adc64Skettenis 		if (nbytes != sizeof(msg))
588298adc64Skettenis 			err(1, "write");
589298adc64Skettenis 
590298adc64Skettenis 		bzero(&msg, sizeof(msg));
591e32fd68fSkettenis 		nbytes = read(hvctl_fd, &msg, sizeof(msg));
592298adc64Skettenis 		if (nbytes != sizeof(msg))
593298adc64Skettenis 			err(1, "read");
594298adc64Skettenis 
595*116f3cbfSkn 		utilisation = 0.0;
596*116f3cbfSkn 
597bc850a97Skettenis 		memcpy(&state, msg.msg.resstat.data, sizeof(state));
598bc850a97Skettenis 		switch (state.state) {
599298adc64Skettenis 		case GUEST_STATE_STOPPED:
600b01cf3d3Skettenis 			state_str = "stopped";
601bc850a97Skettenis 			break;
602bc850a97Skettenis 		case GUEST_STATE_RESETTING:
603bc850a97Skettenis 			state_str = "resetting";
604298adc64Skettenis 			break;
605b01cf3d3Skettenis 		case GUEST_STATE_NORMAL:
606b01cf3d3Skettenis 			state_str = "running";
607298adc64Skettenis 
608298adc64Skettenis 			bzero(&msg, sizeof(msg));
609298adc64Skettenis 			msg.hdr.op = HVCTL_OP_GET_RES_STAT;
610e32fd68fSkettenis 			msg.hdr.seq = hvctl_seq++;
611298adc64Skettenis 			msg.msg.resstat.res = HVCTL_RES_GUEST;
612b01cf3d3Skettenis 			msg.msg.resstat.resid = guest->gid;
613298adc64Skettenis 			msg.msg.resstat.infoid = HVCTL_INFO_GUEST_SOFT_STATE;
614e32fd68fSkettenis 			nbytes = write(hvctl_fd, &msg, sizeof(msg));
615298adc64Skettenis 			if (nbytes != sizeof(msg))
616298adc64Skettenis 				err(1, "write");
617298adc64Skettenis 
618298adc64Skettenis 			bzero(&msg, sizeof(msg));
619e32fd68fSkettenis 			nbytes = read(hvctl_fd, &msg, sizeof(msg));
620298adc64Skettenis 			if (nbytes != sizeof(msg))
621298adc64Skettenis 				err(1, "read");
622298adc64Skettenis 
623bc850a97Skettenis 			memcpy(&softstate, msg.msg.resstat.data,
624bc850a97Skettenis 			   sizeof(softstate));
625bc850a97Skettenis 
626bc850a97Skettenis 			bzero(&msg, sizeof(msg));
627bc850a97Skettenis 			msg.hdr.op = HVCTL_OP_GET_RES_STAT;
628e32fd68fSkettenis 			msg.hdr.seq = hvctl_seq++;
629bc850a97Skettenis 			msg.msg.resstat.res = HVCTL_RES_GUEST;
630bc850a97Skettenis 			msg.msg.resstat.resid = guest->gid;
631bc850a97Skettenis 			msg.msg.resstat.infoid = HVCTL_INFO_GUEST_UTILISATION;
632e32fd68fSkettenis 			nbytes = write(hvctl_fd, &msg, sizeof(msg));
633bc850a97Skettenis 			if (nbytes != sizeof(msg))
634bc850a97Skettenis 				err(1, "write");
635bc850a97Skettenis 
636bc850a97Skettenis 			bzero(&msg, sizeof(msg));
637e32fd68fSkettenis 			nbytes = read(hvctl_fd, &msg, sizeof(msg));
638bc850a97Skettenis 			if (nbytes != sizeof(msg))
639bc850a97Skettenis 				err(1, "read");
640bc850a97Skettenis 
641bc850a97Skettenis 			memcpy(&util, msg.msg.resstat.data, sizeof(util));
642bc850a97Skettenis 
643bc850a97Skettenis 			total_cycles = util.active_delta * guest->num_cpus
644bc850a97Skettenis 			    - util.stopped_cycles;
645bc850a97Skettenis 			yielded_cycles = util.yielded_cycles;
646bc850a97Skettenis 			if (yielded_cycles <= total_cycles)
647bc850a97Skettenis 				utilisation = (100.0 * (total_cycles
648bc850a97Skettenis 				    - yielded_cycles)) / total_cycles;
649bc850a97Skettenis 
650bc850a97Skettenis 			break;
651bc850a97Skettenis 		case GUEST_STATE_SUSPENDED:
652bc850a97Skettenis 			state_str = "suspended";
653bc850a97Skettenis 			break;
654bc850a97Skettenis 		case GUEST_STATE_EXITING:
655bc850a97Skettenis 			state_str = "exiting";
656b01cf3d3Skettenis 			break;
657b01cf3d3Skettenis 		case GUEST_STATE_UNCONFIGURED:
658b01cf3d3Skettenis 			state_str = "unconfigured";
659b01cf3d3Skettenis 			break;
660b01cf3d3Skettenis 		default:
661b01cf3d3Skettenis 			snprintf(buf, sizeof(buf), "unknown (%lld)",
662bc850a97Skettenis 			    state.state);
663b01cf3d3Skettenis 			state_str = buf;
664b01cf3d3Skettenis 			break;
665b01cf3d3Skettenis 		}
666b01cf3d3Skettenis 
6674a9de534Skn 		/* primary has no console */
6684a9de534Skn 		if (guest->gid != 0) {
6694a9de534Skn 			snprintf(console_str, sizeof(console_str),
6704a9de534Skn 			    "ttyV%llu", guest->gid - 1);
6714a9de534Skn 		}
6724a9de534Skn 
6734a9de534Skn 		printf("%-16s %-8s %-16s %-32s %3.0f%%\n", guest->name,
67400e27bb9Skn 		    console_str, state_str, state.state == GUEST_STATE_NORMAL ?
67500e27bb9Skn 		    softstate.soft_state_str : "-", utilisation);
676298adc64Skettenis 	}
6774a9de534Skn }
67887832736Skettenis 
67987832736Skettenis void
guest_console(int argc,char ** argv)6804f98d0d5Skn guest_console(int argc, char **argv)
6814f98d0d5Skn {
682a4bb5ed0Skn 	uint64_t gid;
6834f98d0d5Skn 
6844f98d0d5Skn 	if (argc != 2)
6854f98d0d5Skn 		usage();
6864f98d0d5Skn 
68776c0d977Skn 	hv_config();
68876c0d977Skn 
6894f98d0d5Skn 	gid = find_guest(argv[1]);
6904f98d0d5Skn 
691fdd39fabSkn 	console_exec(gid);
6924f98d0d5Skn }
6934f98d0d5Skn 
6944f98d0d5Skn void
hv_open(void)69587832736Skettenis hv_open(void)
69687832736Skettenis {
69787832736Skettenis 	struct hvctl_msg msg;
69887832736Skettenis 	ssize_t nbytes;
69987832736Skettenis 	uint64_t code;
70087832736Skettenis 
701b7041c07Sderaadt 	hvctl_fd = open("/dev/hvctl", O_RDWR);
70287832736Skettenis 	if (hvctl_fd == -1)
70387832736Skettenis 		err(1, "cannot open /dev/hvctl");
70487832736Skettenis 
70587832736Skettenis 	/*
70687832736Skettenis 	 * Say "Hello".
70787832736Skettenis 	 */
70887832736Skettenis 	bzero(&msg, sizeof(msg));
70987832736Skettenis 	msg.hdr.op = HVCTL_OP_HELLO;
71087832736Skettenis 	msg.hdr.seq = hvctl_seq++;
71187832736Skettenis 	msg.msg.hello.major = 1;
71287832736Skettenis 	nbytes = write(hvctl_fd, &msg, sizeof(msg));
71387832736Skettenis 	if (nbytes != sizeof(msg))
71487832736Skettenis 		err(1, "write");
71587832736Skettenis 
71687832736Skettenis 	bzero(&msg, sizeof(msg));
71787832736Skettenis 	nbytes = read(hvctl_fd, &msg, sizeof(msg));
71887832736Skettenis 	if (nbytes != sizeof(msg))
71987832736Skettenis 		err(1, "read");
72087832736Skettenis 
72187832736Skettenis 	code = msg.msg.clnge.code ^ 0xbadbeef20;
72287832736Skettenis 
72387832736Skettenis 	/*
72487832736Skettenis 	 * Respond to challenge.
72587832736Skettenis 	 */
72687832736Skettenis 	bzero(&msg, sizeof(msg));
72787832736Skettenis 	msg.hdr.op = HVCTL_OP_RESPONSE;
72887832736Skettenis 	msg.hdr.seq = hvctl_seq++;
72987832736Skettenis 	msg.msg.clnge.code = code ^ 0x12cafe42a;
73087832736Skettenis 	nbytes = write(hvctl_fd, &msg, sizeof(msg));
73187832736Skettenis 	if (nbytes != sizeof(msg))
73287832736Skettenis 		err(1, "write");
73387832736Skettenis 
73487832736Skettenis 	bzero(&msg, sizeof(msg));
73587832736Skettenis 	nbytes = read(hvctl_fd, &msg, sizeof(msg));
73687832736Skettenis 	if (nbytes != sizeof(msg))
73787832736Skettenis 		err(1, "read");
73887832736Skettenis }
73987832736Skettenis 
74087832736Skettenis void
hv_close(void)74187832736Skettenis hv_close(void)
74287832736Skettenis {
74387832736Skettenis 	close(hvctl_fd);
74487832736Skettenis 	hvctl_fd = -1;
74587832736Skettenis }
74687832736Skettenis 
74787832736Skettenis void
hv_config(void)74876c0d977Skn hv_config(void)
74976c0d977Skn {
75076c0d977Skn 	struct hvctl_msg msg;
75176c0d977Skn 	ssize_t nbytes;
75276c0d977Skn 	struct md_header hdr;
75376c0d977Skn 	struct md_node *node;
75476c0d977Skn 	struct md_prop *prop;
75576c0d977Skn 
75676c0d977Skn 	hv_open();
75776c0d977Skn 
75876c0d977Skn 	/*
75976c0d977Skn 	 * Request config.
76076c0d977Skn 	 */
76176c0d977Skn 	bzero(&msg, sizeof(msg));
76276c0d977Skn 	msg.hdr.op = HVCTL_OP_GET_HVCONFIG;
76376c0d977Skn 	msg.hdr.seq = hvctl_seq++;
76476c0d977Skn 	nbytes = write(hvctl_fd, &msg, sizeof(msg));
76576c0d977Skn 	if (nbytes != sizeof(msg))
76676c0d977Skn 		err(1, "write");
76776c0d977Skn 
76876c0d977Skn 	bzero(&msg, sizeof(msg));
76976c0d977Skn 	nbytes = read(hvctl_fd, &msg, sizeof(msg));
77076c0d977Skn 	if (nbytes != sizeof(msg))
77176c0d977Skn 		err(1, "read");
77276c0d977Skn 
77376c0d977Skn 	hv_membase = msg.msg.hvcnf.hv_membase;
77476c0d977Skn 	hv_memsize = msg.msg.hvcnf.hv_memsize;
77576c0d977Skn 
77676c0d977Skn 	hv_mdpa = msg.msg.hvcnf.hvmdp;
77776c0d977Skn 	hv_read(hv_mdpa, &hdr, sizeof(hdr));
77876c0d977Skn 	hvmd_len = sizeof(hdr) + hdr.node_blk_sz + hdr.name_blk_sz +
77976c0d977Skn 	    hdr.data_blk_sz;
78076c0d977Skn 	hvmd_buf = xmalloc(hvmd_len);
78176c0d977Skn 	hv_read(hv_mdpa, hvmd_buf, hvmd_len);
78276c0d977Skn 
78376c0d977Skn 	hvmd = md_ingest(hvmd_buf, hvmd_len);
78476c0d977Skn 	node = md_find_node(hvmd, "guests");
78576c0d977Skn 	TAILQ_INIT(&guest_list);
78676c0d977Skn 	TAILQ_FOREACH(prop, &node->prop_list, link) {
78776c0d977Skn 		if (prop->tag == MD_PROP_ARC &&
78876c0d977Skn 		    strcmp(prop->name->str, "fwd") == 0)
78976c0d977Skn 			add_guest(prop->d.arc.node);
79076c0d977Skn 	}
79176c0d977Skn }
79276c0d977Skn 
79376c0d977Skn void
hv_read(uint64_t addr,void * buf,size_t len)79487832736Skettenis hv_read(uint64_t addr, void *buf, size_t len)
79587832736Skettenis {
79687832736Skettenis 	struct hv_io hi;
79787832736Skettenis 
79887832736Skettenis 	hi.hi_cookie = addr;
79987832736Skettenis 	hi.hi_addr = buf;
80087832736Skettenis 	hi.hi_len = len;
80187832736Skettenis 
80287832736Skettenis 	if (ioctl(hvctl_fd, HVIOCREAD, &hi) == -1)
80387832736Skettenis 		err(1, "ioctl");
80487832736Skettenis }
80587832736Skettenis 
80687832736Skettenis void
hv_write(uint64_t addr,void * buf,size_t len)80787832736Skettenis hv_write(uint64_t addr, void *buf, size_t len)
80887832736Skettenis {
80987832736Skettenis 	struct hv_io hi;
81087832736Skettenis 
81187832736Skettenis 	hi.hi_cookie = addr;
81287832736Skettenis 	hi.hi_addr = buf;
81387832736Skettenis 	hi.hi_len = len;
81487832736Skettenis 
81587832736Skettenis 	if (ioctl(hvctl_fd, HVIOCWRITE, &hi) == -1)
81687832736Skettenis 		err(1, "ioctl");
81787832736Skettenis }
818