Create "ProcessManager" and "Domain" capabilities.
[barrelfish] / usr / proc_mgmt / service.c
1 /**
2  * \file
3  * \brief Process management service.
4  */
5
6 /*
7  * Copyright (c) 2017, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <stdio.h>
16 #include <barrelfish/barrelfish.h>
17 #include <barrelfish/nameservice_client.h>
18 #include <barrelfish/proc_mgmt_client.h>
19 #include <barrelfish/spawn_client.h>
20 #include <if/monitor_defs.h>
21 #include <if/proc_mgmt_defs.h>
22
23 #include "internal.h"
24 #include "spawnd_state.h"
25
26 static void add_spawnd_handler(struct proc_mgmt_binding *b, coreid_t core_id,
27                                iref_t iref)
28 {
29     if (spawnd_state_exists(core_id)) {
30         DEBUG_ERR(PROC_MGMT_ERR_SPAWND_EXISTS, "spawnd_state_exists");
31         return;
32     }
33
34     // Bind with the spawnd.
35     struct spawn_binding *spawnb;
36     errval_t err = spawn_bind_iref(iref, &spawnb);
37     if (err_is_fail(err)) {
38         DEBUG_ERR(err, "spawn_bind_iref");
39         return;
40     }
41
42     err = spawnd_state_alloc(core_id, spawnb);
43     if (err_is_fail(err)) {
44         DEBUG_ERR(err, "spawnd_state_alloc");
45     }
46
47     debug_printf("Process manager bound with spawnd.%u on iref %u\n", core_id,
48             iref);
49
50     err = spawnd_state_get_binding(core_id)->rpc_tx_vtbl.echo(
51             spawnd_state_get_binding(core_id),
52             SERVICE_BASENAME,
53             disp_get_current_core_id());
54     if (err_is_fail(err)) {
55         USER_PANIC_ERR(err, "spawnd echo request failed");
56     }
57 }
58
59 static void add_spawnd_handler_non_monitor(struct proc_mgmt_binding *b,
60                                            coreid_t core_id, iref_t iref)
61 {
62     debug_printf("Ignoring add_spawnd call: %s\n",
63                  err_getstring(PROC_MGMT_ERR_NOT_MONITOR));
64 }
65
66 // static errval_t spawn_handler(struct proc_mgmt_binding *b,
67 //                           coreid_t core,
68 //                           const char *path,
69 //                           const char *argvbuf,
70 //                           size_t argvbytes,
71 //                           const char *envbuf,
72 //                           size_t envbytes,
73 //                           uint8_t flags,
74 //                           errval_t *err,
75 //                           struct capref *domainid_cap)
76 // {
77 //     return LIB_ERR_NOT_IMPLEMENTED;
78 // }
79
80 // static errval_t span_handler(struct proc_mgmt_binding *b,
81 //                          struct capref domainid_cap,
82 //                          coreid_t core,
83 //                          struct capref vroot,
84 //                          struct capref disp_mem,
85 //                          errval_t *err)
86 // {
87 //     return LIB_ERR_NOT_IMPLEMENTED;
88 // }
89
90 // static errval_t kill_handler(struct proc_mgmt_binding *b,
91 //                          struct capref domainid_cap,
92 //                          errval_t *err)
93 // {
94 //     return LIB_ERR_NOT_IMPLEMENTED;
95 // }
96
97 static struct proc_mgmt_rx_vtbl monitor_vtbl = {
98     .add_spawnd = add_spawnd_handler
99 };
100
101 static struct proc_mgmt_rx_vtbl non_monitor_vtbl = {
102     .add_spawnd = add_spawnd_handler_non_monitor
103 };
104
105 static errval_t alloc_ep_for_monitor(struct capref *ep)
106 {
107     struct proc_mgmt_lmp_binding *lmpb =
108         malloc(sizeof(struct proc_mgmt_lmp_binding));
109     assert(lmpb != NULL);
110
111     // setup our end of the binding
112     errval_t err = proc_mgmt_client_lmp_accept(lmpb, get_default_waitset(),
113                                                DEFAULT_LMP_BUF_WORDS);
114     if (err_is_fail(err)) {
115         free(lmpb);
116         return err_push(err, LIB_ERR_PROC_MGMT_CLIENT_ACCEPT);
117     }
118
119     *ep = lmpb->chan.local_cap;
120     lmpb->b.rx_vtbl = monitor_vtbl;
121
122     return SYS_ERR_OK;
123 }
124
125 static void export_cb(void *st, errval_t err, iref_t iref)
126 {
127     if (err_is_fail(err)) {
128         USER_PANIC_ERR(err, "export failed");
129     }
130
131     // Allocate an endpoint for the local monitor, who will use it to inform
132     // us about new spawnd irefs on behalf of other monitors.
133     struct capref ep;
134     err = alloc_ep_for_monitor(&ep);
135     if (err_is_fail(err)) {
136         USER_PANIC_ERR(err, "failed to allocate LMP EP for local monitor");
137     }
138
139     // Send the endpoint to the monitor, so it can finish the handshake.
140     struct monitor_binding *mb = get_monitor_binding();
141     err = mb->tx_vtbl.set_proc_mgmt_ep_request(mb, NOP_CONT, ep);
142     if (err_is_fail(err)) {
143         USER_PANIC_ERR(err, "failed to send set_proc_mgmt_ep_request to "
144                        "monitor");
145     }
146
147     // Also register this iref with the name service, for arbitrary client
148     // domains to use for spawn-related ops.
149     err = nameservice_register(SERVICE_BASENAME, iref);
150     if (err_is_fail(err)) {
151         USER_PANIC_ERR(err, "nameservice_register failed");
152     }
153
154     // Try to create a few domains?
155     // TODO(razvan): Remove this.
156     size_t num_domains = 5;
157     struct capref domain_caps[num_domains];
158     for (size_t i = 1; i <= num_domains; ++i) {
159         err = slot_alloc(&domain_caps[i]);
160         if (err_is_fail(err)) {
161             USER_PANIC_ERR(err, "slot_alloc domain_cap");
162         }
163         err = cap_retype(domain_caps[i], cap_procmng, 0, ObjType_Domain, 0, 1);
164         if (err_is_fail(err)) {
165             USER_PANIC_ERR(err, "cap_retype domain_cap from cap_procmng");
166         }
167         struct capability ret;
168         err = debug_cap_identify(domain_caps[i], &ret);
169         if (err_is_fail(err)) {
170             USER_PANIC_ERR(err, "cap identify domain_cap");
171         }
172         debug_printf("Process manager successfully created domain { .coreid=%u,"
173                      " .core_local_id=%u } (%lu/%lu)\n", ret.u.domain.coreid,
174                      ret.u.domain.core_local_id, i, num_domains);
175     }
176 }
177
178 static errval_t connect_cb(void *st, struct proc_mgmt_binding *b)
179 {
180     b->rx_vtbl = non_monitor_vtbl;
181     return SYS_ERR_OK;
182 }
183
184 errval_t start_service(void)
185 {
186     return proc_mgmt_export(NULL, export_cb, connect_cb, get_default_waitset(),
187             IDC_EXPORT_FLAGS_DEFAULT);
188 }