1 /* 2 * Interprocess communication abstractions. 3 * 4 * Copyright (C) 2018, 2019, 2021, 2022, 2023 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 | L4_RCV_ITEM_LOCAL_ID; 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 int *local) 131 { 132 l4_snd_fpage_t fpage; 133 long err = _import_fpage(tag, bregs, mregs, item, &fpage); 134 135 if (err) 136 return err; 137 138 /* Check for a received capability and update the supplied capability 139 index. */ 140 141 /* Inter-task capability transfer. */ 142 143 if ((fpage.snd_base & 0x3e) == 0x38) 144 { 145 *ref = bregs->br[item] & L4_CAP_MASK; 146 *local = 0; 147 } 148 149 /* Local capability transfer. */ 150 151 else if ((fpage.snd_base & 0x3e) == 0x3e) 152 { 153 *ref = l4_fpage_obj(fpage.fpage); 154 *local = 1; 155 } 156 157 /* Unsupported item which may legitimately be an invalid capability. */ 158 159 else 160 *ref = L4_INVALID_CAP; 161 162 return L4_EOK; 163 } 164 165 /* Import from the message a dataspace, mapping it to an address. */ 166 167 long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, 168 l4_msg_regs_t *mregs, int item, l4re_ds_t *mem, 169 l4_addr_t *addr, int *local) 170 { 171 long err; 172 unsigned long size; 173 174 *mem = ipc_cap_alloc(); 175 176 err = _import_capability(tag, bregs, mregs, item, mem, local); 177 178 if (err) 179 { 180 if (!*local) 181 ipc_cap_free_um(*mem); 182 return err; 183 } 184 185 /* Attach the dataspace to a region. */ 186 187 err = ipc_dataspace_size(*mem, &size); 188 if (err) 189 { 190 ipc_cap_free_um(*mem); 191 return err; 192 } 193 194 err = ipc_attach_dataspace(*mem, size, (void **) addr); 195 if (err) 196 { 197 ipc_cap_free_um(*mem); 198 return err; 199 } 200 201 return L4_EOK; 202 } 203 204 /* Import from the message the flexpage at the given item position. */ 205 206 long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, 207 l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage) 208 { 209 int words = l4_msgtag_words(tag); 210 211 /* NOTE: Currently, this function does not interact with the received items, 212 but instead just returns the flexpage details from the message 213 words. */ 214 215 (void) bregs; 216 217 /* Obtain the item details for the capability. */ 218 219 if (item >= (int) l4_msgtag_items(tag)) 220 return -L4_EIO; 221 222 /* Received items should start at zero. */ 223 224 fpage->snd_base = mregs->mr[words + item * 2]; 225 fpage->fpage.raw = mregs->mr[words + item * 2 + 1]; 226 227 return L4_EOK; 228 } 229 230 231 232 /* Convenience operations. */ 233 234 /* Send a reply to a call using the given message tag. */ 235 236 l4_msgtag_t util_ipc_reply(l4_msgtag_t tag) 237 { 238 return l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_NEVER); 239 } 240 241 /* Send a request using a call with the given message tag to the indicated 242 endpoint. */ 243 244 l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint) 245 { 246 return l4_ipc_call(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 247 } 248 249 /* Send data with the given message tag to the indicated endpoint. */ 250 251 l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint) 252 { 253 return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 254 } 255 256 /* vim: tabstop=2 expandtab shiftwidth=2 257 */