1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libipc/lib/src/message.c Wed Aug 25 01:28:08 2021 +0200
1.3 @@ -0,0 +1,485 @@
1.4 +/*
1.5 + * Interprocess communication message abstraction.
1.6 + *
1.7 + * Copyright (C) 2018, 2019, 2021 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <string.h>
1.26 +
1.27 +#include "cap_alloc.h"
1.28 +#include "message.h"
1.29 +#include "mem_ipc.h"
1.30 +#include "util_ipc.h"
1.31 +
1.32 +
1.33 +
1.34 +/* Calculate the given length rounded up to whole word increments. */
1.35 +
1.36 +static size_t get_size_in_words(size_t length)
1.37 +{
1.38 + size_t mask = sizeof(l4_umword_t) - 1;
1.39 + return (length + mask) & ~mask;
1.40 +}
1.41 +
1.42 +
1.43 +
1.44 +/* Message operations. */
1.45 +
1.46 +/* Discard capabilities for transfer to other tasks. */
1.47 +
1.48 +void ipc_message_discard(ipc_message_t *msg)
1.49 +{
1.50 + unsigned int i;
1.51 +
1.52 + for (i = 0; i < msg->discarded_items; i++)
1.53 + ipc_cap_free_um(msg->to_discard[i]);
1.54 +}
1.55 +
1.56 +/* Initialise a message structure with the given number of expected items. */
1.57 +
1.58 +long ipc_message_expect(ipc_message_t *msg, unsigned int expected_items)
1.59 +{
1.60 + long err = ipc_message_expect_capabilities(msg, expected_items);
1.61 +
1.62 + if (err)
1.63 + return err;
1.64 +
1.65 + /* Restore the buffer registers immediately. */
1.66 +
1.67 + ipc_message_restore_buffer_registers(msg);
1.68 +
1.69 + return L4_EOK;
1.70 +}
1.71 +
1.72 +/* Free capabilities expected in messages. */
1.73 +
1.74 +void ipc_message_free(ipc_message_t *msg)
1.75 +{
1.76 + _free_expected_capabilities(&msg->bregs, msg->expected_items);
1.77 +}
1.78 +
1.79 +/* Clear message attributes for sending and response handling. */
1.80 +
1.81 +void ipc_message_new(ipc_message_t *msg)
1.82 +{
1.83 + /* Set a default for expected items. */
1.84 +
1.85 + msg->expected_items = 0;
1.86 + ipc_message_reset(msg);
1.87 +}
1.88 +
1.89 +/* Open an incoming message by resetting sending state and preserving the
1.90 + message registers plus the buffer registers for the expected number of
1.91 + items. */
1.92 +
1.93 +void ipc_message_open(ipc_message_t *msg)
1.94 +{
1.95 + ipc_message_reset(msg);
1.96 + ipc_message_preserve_buffer_registers(msg);
1.97 + ipc_message_preserve_message_registers(msg);
1.98 +}
1.99 +
1.100 +/* Preserve the buffer registers. */
1.101 +
1.102 +void ipc_message_preserve_buffer_registers(ipc_message_t *msg)
1.103 +{
1.104 + unsigned int i;
1.105 +
1.106 + /* Reference the UTCB virtual registers. */
1.107 +
1.108 + l4_buf_regs_t *bregs = l4_utcb_br();
1.109 +
1.110 + msg->bregs.bdr = bregs->bdr;
1.111 +
1.112 + for (i = 0; i < msg->expected_items; i++)
1.113 + msg->bregs.br[i] = bregs->br[i];
1.114 +}
1.115 +
1.116 +/* Preserve the message registers. */
1.117 +
1.118 +void ipc_message_preserve_message_registers(ipc_message_t *msg)
1.119 +{
1.120 + /* Compute the number of message register words affected. */
1.121 +
1.122 + unsigned int i, affected_words = l4_msgtag_words(msg->tag) +
1.123 + 2 * l4_msgtag_items(msg->tag);
1.124 +
1.125 + /* Reference the UTCB virtual registers. */
1.126 +
1.127 + l4_msg_regs_t *mregs = l4_utcb_mr();
1.128 +
1.129 + /* Copy message register information. */
1.130 +
1.131 + for (i = 0; i < affected_words; i++)
1.132 + msg->mregs.mr[i] = mregs->mr[i];
1.133 +}
1.134 +
1.135 +/* Restore the message and buffer registers. */
1.136 +
1.137 +void ipc_message_prepare(ipc_message_t *msg)
1.138 +{
1.139 + ipc_message_restore_buffer_registers(msg);
1.140 + ipc_message_restore_message_registers(msg);
1.141 +}
1.142 +
1.143 +/* Restore buffer registers so that item expectations can be set. */
1.144 +
1.145 +void ipc_message_restore_buffer_registers(ipc_message_t *msg)
1.146 +{
1.147 + unsigned int i;
1.148 +
1.149 + /* Reference the UTCB virtual registers. */
1.150 +
1.151 + l4_buf_regs_t *bregs = l4_utcb_br();
1.152 +
1.153 + /* Restore buffer register information. */
1.154 +
1.155 + bregs->bdr = msg->bregs.bdr;
1.156 +
1.157 + for (i = 0; i < msg->expected_items; i++)
1.158 + bregs->br[i] = msg->bregs.br[i];
1.159 +}
1.160 +
1.161 +/* Restore message registers to communicate recorded data and items. */
1.162 +
1.163 +void ipc_message_restore_message_registers(ipc_message_t *msg)
1.164 +{
1.165 + /* Compute the number of message register words affected. */
1.166 +
1.167 + unsigned int i, affected_words = msg->words + 2 * msg->items;
1.168 +
1.169 + /* Reference the UTCB virtual registers. */
1.170 +
1.171 + l4_msg_regs_t *mregs = l4_utcb_mr();
1.172 +
1.173 + /* Restore message register information. */
1.174 +
1.175 + for (i = 0; i < affected_words; i++)
1.176 + mregs->mr[i] = msg->mregs.mr[i];
1.177 +}
1.178 +
1.179 +/* Prepare and send a reply using the message. */
1.180 +
1.181 +void ipc_message_reply(ipc_message_t *msg)
1.182 +{
1.183 + ipc_message_prepare(msg);
1.184 + msg->tag = util_ipc_reply(ipc_message_reply_tag(msg));
1.185 +}
1.186 +
1.187 +/* Prepare and send a request using the message, involving the given operation,
1.188 + directed at the indicated endpoint. Open a message for the reply. */
1.189 +
1.190 +void ipc_message_request(ipc_message_t *msg, int op, l4_cap_idx_t endpoint)
1.191 +{
1.192 + ipc_message_prepare(msg);
1.193 + msg->tag = util_ipc_request(ipc_message_request_tag(msg, op), endpoint);
1.194 + ipc_message_open(msg);
1.195 +}
1.196 +
1.197 +/* Prepare and send a message, involving the given operation, directed at the
1.198 + indicated endpoint. No reply is expected. */
1.199 +
1.200 +void ipc_message_send(ipc_message_t *msg, int op, l4_cap_idx_t endpoint)
1.201 +{
1.202 + ipc_message_prepare(msg);
1.203 + msg->tag = util_ipc_send(ipc_message_request_tag(msg, op), endpoint);
1.204 +}
1.205 +
1.206 +/* Reset the state of the message for sending purposes. */
1.207 +
1.208 +void ipc_message_reset(ipc_message_t *msg)
1.209 +{
1.210 + /* Initialise words and items for sending. */
1.211 +
1.212 + msg->discarded_items = 0;
1.213 + msg->words = 0;
1.214 + msg->items = 0;
1.215 +
1.216 + /* Message label overriding. */
1.217 +
1.218 + msg->new_label = 0;
1.219 +
1.220 + /* Server control. */
1.221 +
1.222 + msg->terminating = 0;
1.223 +}
1.224 +
1.225 +/* Wait for an incoming message. */
1.226 +
1.227 +void ipc_message_wait(ipc_message_t *msg, l4_umword_t *label)
1.228 +{
1.229 + msg->tag = l4_ipc_wait(l4_utcb(), label, L4_IPC_NEVER);
1.230 +}
1.231 +
1.232 +
1.233 +
1.234 +/* Add a capability to the message. */
1.235 +
1.236 +void ipc_message_add_capability(ipc_message_t *msg, l4_cap_idx_t cap)
1.237 +{
1.238 + ipc_message_export_capability(msg, msg->items++, cap);
1.239 + if (cap & IPC_DISCARD_CAP_FLAG)
1.240 + ipc_message_discard_capability(msg, cap & ~IPC_DISCARD_CAP_FLAG);
1.241 +}
1.242 +
1.243 +/* Add an item to the message. */
1.244 +
1.245 +void ipc_message_add_item(ipc_message_t *msg, l4_cap_idx_t cap)
1.246 +{
1.247 + ipc_message_export_capability(msg, msg->items++, cap);
1.248 + if (cap & IPC_DISCARD_CAP_FLAG)
1.249 + ipc_message_discard_capability(msg, cap & ~IPC_DISCARD_CAP_FLAG);
1.250 +}
1.251 +
1.252 +/* Add a flexpage to the message using a type to combine the "hot spot" and
1.253 + flexpage. */
1.254 +
1.255 +void ipc_message_add_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage)
1.256 +{
1.257 + ipc_message_export_fpage(msg, msg->items++, fpage);
1.258 +}
1.259 +
1.260 +/* Add a flexpage to the message. */
1.261 +
1.262 +void ipc_message_add_page(ipc_message_t *msg, l4_umword_t hot_spot,
1.263 + l4_fpage_t fpage)
1.264 +{
1.265 + ipc_message_export_page(msg, msg->items++, hot_spot, fpage);
1.266 +}
1.267 +
1.268 +/* Add a word value to the message. */
1.269 +
1.270 +void ipc_message_add_word(ipc_message_t *msg, l4_umword_t value)
1.271 +{
1.272 + /* NOTE: Should raise an exception if there are items. */
1.273 +
1.274 + if (!msg->items)
1.275 + msg->mregs.mr[msg->words++] = value;
1.276 +}
1.277 +
1.278 +/* Add the given dimensioned data to the message. */
1.279 +
1.280 +void ipc_message_add_data(ipc_message_t *msg, const char *value, size_t length)
1.281 +{
1.282 + void *target = ipc_message_reserve_data(msg, length);
1.283 +
1.284 + memcpy(target, value, length);
1.285 +}
1.286 +
1.287 +/* Add the given null-terminated character string to the message. */
1.288 +
1.289 +void ipc_message_add_string(ipc_message_t *msg, const char *value)
1.290 +{
1.291 + ipc_message_add_data(msg, value, strlen(value) + 1);
1.292 +}
1.293 +
1.294 +/* Propagate the given item to the message. */
1.295 +
1.296 +void ipc_message_propagate_item(ipc_message_t *msg, l4_cap_idx_t cap)
1.297 +{
1.298 + ipc_message_propagate_capability(msg, msg->items++, cap);
1.299 +}
1.300 +
1.301 +/* Indicate an error condition in the message. */
1.302 +
1.303 +void ipc_message_send_error(ipc_message_t *msg, long error)
1.304 +{
1.305 + msg->new_label = error;
1.306 +}
1.307 +
1.308 +/* Return a word value from the message. */
1.309 +
1.310 +l4_umword_t ipc_message_get_word(ipc_message_t *msg, unsigned int word)
1.311 +{
1.312 + return msg->mregs.mr[word];
1.313 +}
1.314 +
1.315 +/* Return a pointer to a word in the message. */
1.316 +
1.317 +l4_umword_t *ipc_message_get_word_address(ipc_message_t *msg, unsigned int word)
1.318 +{
1.319 + return &msg->mregs.mr[word];
1.320 +}
1.321 +
1.322 +/* Return the number of received items. */
1.323 +
1.324 +unsigned int ipc_message_number_of_items(ipc_message_t *msg)
1.325 +{
1.326 + return l4_msgtag_items(msg->tag);
1.327 +}
1.328 +
1.329 +/* Return the number of received words. */
1.330 +
1.331 +unsigned int ipc_message_number_of_words(ipc_message_t *msg)
1.332 +{
1.333 + return l4_msgtag_words(msg->tag);
1.334 +}
1.335 +
1.336 +/* Message tag generation. */
1.337 +
1.338 +l4_msgtag_t ipc_message_reply_tag(ipc_message_t *msg)
1.339 +{
1.340 + return l4_msgtag(msg->new_label, msg->words, msg->items, 0);
1.341 +}
1.342 +
1.343 +l4_msgtag_t ipc_message_request_tag(ipc_message_t *msg, int op)
1.344 +{
1.345 + return l4_msgtag(op, msg->words, msg->items, 0);
1.346 +}
1.347 +
1.348 +/* Reserve space for dimensioned data, returning a pointer to use to add the
1.349 + data. The length of the data is incorporated into the message. */
1.350 +
1.351 +void *ipc_message_reserve_data(ipc_message_t *msg, size_t length)
1.352 +{
1.353 + /* Indicate the length of the data. */
1.354 +
1.355 + ipc_message_add_word(msg, length);
1.356 +
1.357 + /* Reserve the space. */
1.358 +
1.359 + return ipc_message_reserve_words(msg, length);
1.360 +}
1.361 +
1.362 +/* Reserve space for dimensioned data, returning a pointer to use to add the
1.363 + data. The length is not incorporated into the message. */
1.364 +
1.365 +void *ipc_message_reserve_words(ipc_message_t *msg, size_t length)
1.366 +{
1.367 + /* Calculate the rounded-up size of the data and the necessary padding. */
1.368 +
1.369 + size_t size = get_size_in_words(length);
1.370 + size_t padding = size - length;
1.371 + void *target;
1.372 +
1.373 + /* NOTE: Should test the length against the capacity of the message. */
1.374 +
1.375 + /* Obtain the location of the next word, where the data will be copied. */
1.376 +
1.377 + target = &msg->mregs.mr[msg->words];
1.378 +
1.379 + /* Pad the data and update the number of words. */
1.380 +
1.381 + memset(target + length, 0, padding);
1.382 + msg->words += size / sizeof(l4_umword_t);
1.383 +
1.384 + return target;
1.385 +}
1.386 +
1.387 +
1.388 +
1.389 +/* Discard a capability after replying. */
1.390 +
1.391 +void ipc_message_discard_capability(ipc_message_t *msg, l4_cap_idx_t cap)
1.392 +{
1.393 + msg->to_discard[msg->discarded_items++] = cap;
1.394 +}
1.395 +
1.396 +/* Discard a dataspace. */
1.397 +
1.398 +void ipc_message_discard_dataspace(ipc_message_t *msg, l4re_ds_t mem, l4_addr_t addr)
1.399 +{
1.400 + ipc_message_discard_capability(msg, mem);
1.401 + ipc_detach_dataspace((void *) addr);
1.402 +}
1.403 +
1.404 +/* Reserve the given number slots from zero for incoming capabilities. */
1.405 +
1.406 +long ipc_message_expect_capabilities(ipc_message_t *msg, int number)
1.407 +{
1.408 + msg->expected_items = number;
1.409 + return _expect_capabilities(&msg->bregs, number);
1.410 +}
1.411 +
1.412 +/* Reserve a slot for an incoming capability. */
1.413 +
1.414 +long ipc_message_expect_capability(ipc_message_t *msg, int item)
1.415 +{
1.416 + if (item >= (int) msg->expected_items)
1.417 + msg->expected_items = item + 1;
1.418 +
1.419 + return _expect_capability(&msg->bregs, item);
1.420 +}
1.421 +
1.422 +/* Export a capability at the given position in the message. */
1.423 +
1.424 +void ipc_message_export_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref)
1.425 +{
1.426 + msg->mregs.mr[msg->words + item * 2] = 0 | L4_ITEM_MAP;
1.427 + msg->mregs.mr[msg->words + item * 2 + 1] = l4_obj_fpage(ref, 0, L4_FPAGE_RWX).raw;
1.428 +}
1.429 +
1.430 +/* Export a flexpage at the given position in the message. Here, the snd_base
1.431 + member of the flexpage structure is used to hold the "hot spot" value. */
1.432 +
1.433 +void ipc_message_export_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t fpage)
1.434 +{
1.435 + msg->mregs.mr[msg->words + item * 2] = l4_map_control(fpage.snd_base, L4_FPAGE_CACHEABLE, 0);
1.436 + msg->mregs.mr[msg->words + item * 2 + 1] = fpage.fpage.raw;
1.437 +}
1.438 +
1.439 +/* Export a flexpage at the given position in the message. */
1.440 +
1.441 +void ipc_message_export_page(ipc_message_t *msg, int item, l4_umword_t hot_spot, l4_fpage_t fpage)
1.442 +{
1.443 + msg->mregs.mr[msg->words + item * 2] = l4_map_control(hot_spot, L4_FPAGE_CACHEABLE, 0);
1.444 + msg->mregs.mr[msg->words + item * 2 + 1] = fpage.raw;
1.445 +}
1.446 +
1.447 +/* Import from the message the capability at the given item position, updating
1.448 + the buffer registers for future capabilities. */
1.449 +
1.450 +long ipc_message_import_capability(ipc_message_t *msg, int item, l4_cap_idx_t *ref)
1.451 +{
1.452 + long err;
1.453 +
1.454 + err = _import_capability(msg->tag, &msg->bregs, &msg->mregs, item, ref);
1.455 + if (err)
1.456 + return err;
1.457 +
1.458 + return ipc_message_expect_capability(msg, item);
1.459 +}
1.460 +
1.461 +/* Import from the message a dataspace, mapping it to an address, updating the
1.462 + buffer registers for future capabilities. */
1.463 +
1.464 +long ipc_message_import_dataspace(ipc_message_t *msg, int item, l4re_ds_t *mem, l4_addr_t *addr)
1.465 +{
1.466 + long err;
1.467 +
1.468 + err = _import_dataspace(msg->tag, &msg->bregs, &msg->mregs, item, mem, addr);
1.469 + if (err)
1.470 + return err;
1.471 +
1.472 + return ipc_message_expect_capability(msg, item);
1.473 +}
1.474 +
1.475 +/* Import from the message the flexpage at the given item position. */
1.476 +
1.477 +long ipc_message_import_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t *fpage)
1.478 +{
1.479 + return _import_fpage(msg->tag, &msg->bregs, &msg->mregs, item, fpage);
1.480 +}
1.481 +
1.482 +/* Export a capability, discarding it by propagating it to the recipient. */
1.483 +
1.484 +void ipc_message_propagate_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref)
1.485 +{
1.486 + ipc_message_export_capability(msg, item, ref);
1.487 + ipc_message_discard_capability(msg, ref);
1.488 +}