1 /* 2 * Interprocess communication abstractions. 3 * 4 * Copyright (C) 2018, 2019, 2021, 2022 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/re/env.h> 23 #include <l4/util/util.h> 24 #include <l4/sys/factory.h> 25 #include <l4/sys/irq.h> 26 27 #include "cap_alloc.h" 28 #include "mem_ipc.h" 29 #include "util_ipc.h" 30 31 32 33 /* Declare expected capabilities. 34 NOTE: This does not support the mixing of expected capabilities and other 35 items. */ 36 37 long _expect_capabilities(l4_buf_regs_t *bregs, int number) 38 { 39 int i; 40 long err; 41 42 for (i = 0; i < number; i++) 43 { 44 err = _expect_capability(bregs, i); 45 if (err) 46 return err; 47 } 48 49 return L4_EOK; 50 } 51 52 /* Indicate that a capability is expected at the given position. */ 53 54 long _expect_capability(l4_buf_regs_t *bregs, int item) 55 { 56 l4_cap_idx_t future = ipc_cap_alloc(); 57 58 if (l4_is_invalid_cap(future)) 59 return -L4_ENOENT; 60 61 /* Indicate the expectation of a capability in return. */ 62 63 bregs->bdr = 0; 64 bregs->br[item] = L4_RCV_ITEM_SINGLE_CAP | future; 65 66 return L4_EOK; 67 } 68 69 /* Indicate that a flexpage is expected at the given position. */ 70 71 long _expect_fpage(l4_buf_regs_t *bregs, int item, l4_umword_t map_control, l4_fpage_t fpage) 72 { 73 bregs->bdr = 0; 74 bregs->br[item] = map_control; 75 bregs->br[item + 1] = fpage.raw; 76 77 return L4_EOK; 78 } 79 80 /* Export in the message at the given position the given capability. */ 81 82 void _export_capability(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_cap_idx_t ref) 83 { 84 int words = l4_msgtag_words(tag); 85 86 mregs->mr[words + item * 2] = 0 | L4_ITEM_MAP; 87 mregs->mr[words + item * 2 + 1] = l4_obj_fpage(ref, 0, L4_FPAGE_RWX).raw; 88 } 89 90 /* Export a flexpage at the given position in the message. Here, the snd_base 91 member of the flexpage structure is used to hold the "hot spot" value. */ 92 93 void _export_fpage(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_snd_fpage_t fpage) 94 { 95 int words = l4_msgtag_words(tag); 96 97 mregs->mr[words + item * 2] = l4_map_control(fpage.snd_base, L4_FPAGE_CACHEABLE, 0); 98 mregs->mr[words + item * 2 + 1] = fpage.fpage.raw; 99 } 100 101 /* Export a flexpage at the given position in the message. */ 102 103 void _export_page(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_umword_t hot_spot, l4_fpage_t fpage) 104 { 105 int words = l4_msgtag_words(tag); 106 107 mregs->mr[words + item * 2] = l4_map_control(hot_spot, L4_FPAGE_CACHEABLE, 0); 108 mregs->mr[words + item * 2 + 1] = fpage.raw; 109 } 110 111 /* Free expected capabilities held by the buffer registers. */ 112 113 void _free_expected_capabilities(l4_buf_regs_t *bregs, int number) 114 { 115 int i; 116 l4_cap_idx_t cap; 117 118 for (i = 0; i < number; i++) 119 { 120 cap = bregs->br[i] & L4_CAP_MASK; 121 if (l4_is_valid_cap(cap)) 122 ipc_cap_free_um(cap); 123 } 124 } 125 126 /* Import from the message the capability at the given item position. */ 127 128 long _import_capability(l4_msgtag_t tag, l4_buf_regs_t *bregs, 129 l4_msg_regs_t *mregs, int item, l4_cap_idx_t *ref) 130 { 131 l4_snd_fpage_t fpage; 132 long err = _import_fpage(tag, bregs, mregs, item, &fpage); 133 134 if (err) 135 return err; 136 137 /* Check for a received capability. */ 138 139 if ((fpage.snd_base & 0x3e) != 0x38) 140 return -L4_EIO; 141 142 /* Update the supplied capability index. */ 143 144 *ref = bregs->br[item] & L4_CAP_MASK; 145 146 return L4_EOK; 147 } 148 149 /* Import from the message a dataspace, mapping it to an address. */ 150 151 long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, 152 l4_msg_regs_t *mregs, int item, l4re_ds_t *mem, 153 l4_addr_t *addr) 154 { 155 long err; 156 unsigned long size; 157 158 *mem = ipc_cap_alloc(); 159 160 err = _import_capability(tag, bregs, mregs, item, mem); 161 162 if (err) 163 { 164 ipc_cap_free_um(*mem); 165 return err; 166 } 167 168 /* Attach the dataspace to a region. */ 169 170 err = ipc_dataspace_size(*mem, &size); 171 if (err) 172 { 173 ipc_cap_free_um(*mem); 174 return err; 175 } 176 177 err = ipc_attach_dataspace(*mem, size, (void **) addr); 178 if (err) 179 { 180 ipc_cap_free_um(*mem); 181 return err; 182 } 183 184 return L4_EOK; 185 } 186 187 /* Import from the message the flexpage at the given item position. */ 188 189 long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, 190 l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage) 191 { 192 int words = l4_msgtag_words(tag); 193 194 /* NOTE: Currently, this function does not interact with the received items, 195 but instead just returns the flexpage details from the message 196 words. */ 197 198 (void) bregs; 199 200 /* Obtain the item details for the capability. */ 201 202 if (item >= (int) l4_msgtag_items(tag)) 203 return -L4_EIO; 204 205 /* Received items should start at zero. */ 206 207 fpage->snd_base = mregs->mr[words + item * 2]; 208 fpage->fpage.raw = mregs->mr[words + item * 2 + 1]; 209 210 return L4_EOK; 211 } 212 213 214 215 /* Convenience operations. */ 216 217 /* Send a reply to a call using the given message tag. */ 218 219 l4_msgtag_t util_ipc_reply(l4_msgtag_t tag) 220 { 221 return l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_NEVER); 222 } 223 224 /* Send a request using a call with the given message tag to the indicated 225 endpoint. */ 226 227 l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint) 228 { 229 return l4_ipc_call(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 230 } 231 232 /* Send data with the given message tag to the indicated endpoint. */ 233 234 l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint) 235 { 236 return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 237 } 238 239 /* vim: tabstop=2 expandtab shiftwidth=2 240 */