1 /* 2 * Interprocess communication abstractions. 3 * 4 * Copyright (C) 2018-2024 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->br[item] = L4_RCV_ITEM_SINGLE_CAP | future | L4_RCV_ITEM_LOCAL_ID; 64 65 return L4_EOK; 66 } 67 68 /* Indicate that a flexpage is expected at the given position. */ 69 70 long _expect_fpage(l4_buf_regs_t *bregs, int item, l4_umword_t map_control, l4_fpage_t fpage) 71 { 72 bregs->br[item] = map_control; 73 bregs->br[item + 1] = fpage.raw; 74 75 return L4_EOK; 76 } 77 78 /* Export in the message at the given position the given capability. */ 79 80 void _export_capability(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_cap_idx_t ref) 81 { 82 int words = l4_msgtag_words(tag); 83 84 mregs->mr[words + item * 2] = 0 | L4_ITEM_MAP; 85 mregs->mr[words + item * 2 + 1] = l4_obj_fpage(ref, 0, L4_FPAGE_RWX).raw; 86 } 87 88 /* Export a flexpage at the given position in the message. Here, the snd_base 89 member of the flexpage structure is used to hold the "hot spot" value. */ 90 91 void _export_fpage(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_snd_fpage_t fpage) 92 { 93 int words = l4_msgtag_words(tag); 94 95 mregs->mr[words + item * 2] = l4_map_control(fpage.snd_base, L4_FPAGE_CACHEABLE, 0); 96 mregs->mr[words + item * 2 + 1] = fpage.fpage.raw; 97 } 98 99 /* Export a flexpage at the given position in the message. */ 100 101 void _export_page(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_umword_t hot_spot, l4_fpage_t fpage) 102 { 103 int words = l4_msgtag_words(tag); 104 105 mregs->mr[words + item * 2] = l4_map_control(hot_spot, L4_FPAGE_CACHEABLE, 0); 106 mregs->mr[words + item * 2 + 1] = fpage.raw; 107 } 108 109 /* Free expected capabilities held by the buffer registers. */ 110 111 void _free_expected_capabilities(l4_buf_regs_t *bregs, int start, int limit) 112 { 113 int i; 114 l4_cap_idx_t cap; 115 116 for (i = start; i < limit; i++) 117 { 118 cap = bregs->br[i] & L4_CAP_MASK; 119 if (l4_is_valid_cap(cap)) 120 ipc_cap_free_um(cap); 121 } 122 } 123 124 /* Import from the message the capability at the given item position. */ 125 126 long _import_capability(l4_msgtag_t tag, l4_buf_regs_t *bregs, 127 l4_msg_regs_t *mregs, int item, int buf_item, 128 l4_cap_idx_t *ref, int *local) 129 { 130 l4_snd_fpage_t fpage; 131 long err = _import_fpage(tag, bregs, mregs, item, &fpage); 132 133 if (err) 134 return err; 135 136 /* Check for a received capability and update the supplied capability 137 index. */ 138 139 /* Inter-task capability transfer. */ 140 141 if ((fpage.snd_base & 0x3e) == 0x38) 142 { 143 *ref = bregs->br[buf_item] & L4_CAP_MASK; 144 *local = 0; 145 } 146 147 /* Local capability transfer. */ 148 149 else if ((fpage.snd_base & 0x3e) == 0x3e) 150 { 151 *ref = l4_fpage_obj(fpage.fpage); 152 *local = 1; 153 } 154 155 /* Unsupported item which may legitimately be an invalid capability. */ 156 157 else 158 *ref = L4_INVALID_CAP; 159 160 return L4_EOK; 161 } 162 163 /* Import from the message a dataspace, mapping it to an address. */ 164 165 long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, 166 l4_msg_regs_t *mregs, int item, int buf_item, 167 l4_cap_idx_t *mem, l4_addr_t *addr, int *local) 168 { 169 long err; 170 offset_t size; 171 172 *mem = ipc_cap_alloc(); 173 174 err = _import_capability(tag, bregs, mregs, item, buf_item, mem, local); 175 176 if (err) 177 { 178 if (!*local) 179 ipc_cap_free_um(*mem); 180 return err; 181 } 182 183 /* Attach the dataspace to a region. */ 184 185 err = ipc_dataspace_size(*mem, &size); 186 if (err) 187 { 188 ipc_cap_free_um(*mem); 189 return err; 190 } 191 192 err = ipc_attach_dataspace(*mem, size, (void **) addr); 193 if (err) 194 { 195 ipc_cap_free_um(*mem); 196 return err; 197 } 198 199 return L4_EOK; 200 } 201 202 /* Import from the message the flexpage at the given item position. */ 203 204 long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, 205 l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage) 206 { 207 int words = l4_msgtag_words(tag); 208 209 /* NOTE: Currently, this function does not interact with the received items, 210 but instead just returns the flexpage details from the message 211 words. */ 212 213 (void) bregs; 214 215 /* Obtain the item details for the capability. */ 216 217 if (item >= (int) l4_msgtag_items(tag)) 218 return -L4_EIO; 219 220 /* Received items should start at zero. */ 221 222 fpage->snd_base = mregs->mr[words + item * 2]; 223 fpage->fpage.raw = mregs->mr[words + item * 2 + 1]; 224 225 return L4_EOK; 226 } 227 228 229 230 /* Convenience operations. */ 231 232 /* Send a reply to a call using the given message tag. */ 233 234 l4_msgtag_t util_ipc_reply(l4_msgtag_t tag) 235 { 236 return l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_NEVER); 237 } 238 239 /* Send a request using a call with the given message tag to the indicated 240 endpoint. */ 241 242 l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint) 243 { 244 return l4_ipc_call(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 245 } 246 247 /* Send data with the given message tag to the indicated endpoint. */ 248 249 l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint) 250 { 251 return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 252 } 253 254 /* vim: tabstop=2 expandtab shiftwidth=2 255 */