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