1 /* 2 * Interprocess communication abstractions. 3 * 4 * Copyright (C) 2018, 2019, 2021 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 35 long _expect_capabilities(l4_buf_regs_t *bregs, int number) 36 { 37 int i; 38 long err; 39 40 for (i = 0; i < number; i++) 41 { 42 err = _expect_capability(bregs, i); 43 if (err) 44 return err; 45 } 46 47 return L4_EOK; 48 } 49 50 /* Indicate that a capability is expected at the given position. */ 51 52 long _expect_capability(l4_buf_regs_t *bregs, int item) 53 { 54 l4_cap_idx_t future = ipc_cap_alloc(); 55 56 if (l4_is_invalid_cap(future)) 57 return -L4_ENOENT; 58 59 /* Indicate the expectation of a capability in return. */ 60 61 bregs->bdr = 0; 62 bregs->br[item] = L4_RCV_ITEM_SINGLE_CAP | future; 63 64 return L4_EOK; 65 } 66 67 /* Export in the message at the given position the given capability. */ 68 69 void _export_capability(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_cap_idx_t ref) 70 { 71 int words = l4_msgtag_words(tag); 72 73 mregs->mr[words + item * 2] = 0 | L4_ITEM_MAP; 74 mregs->mr[words + item * 2 + 1] = l4_obj_fpage(ref, 0, L4_FPAGE_RWX).raw; 75 } 76 77 /* Export a flexpage at the given position in the message. Here, the snd_base 78 member of the flexpage structure is used to hold the "hot spot" value. */ 79 80 void _export_fpage(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_snd_fpage_t fpage) 81 { 82 int words = l4_msgtag_words(tag); 83 84 mregs->mr[words + item * 2] = l4_map_control(fpage.snd_base, L4_FPAGE_CACHEABLE, 0); 85 mregs->mr[words + item * 2 + 1] = fpage.fpage.raw; 86 } 87 88 /* Export a flexpage at the given position in the message. */ 89 90 void _export_page(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_umword_t hot_spot, l4_fpage_t fpage) 91 { 92 int words = l4_msgtag_words(tag); 93 94 mregs->mr[words + item * 2] = l4_map_control(hot_spot, L4_FPAGE_CACHEABLE, 0); 95 mregs->mr[words + item * 2 + 1] = fpage.raw; 96 } 97 98 /* Free expected capabilities held by the buffer registers. */ 99 100 void _free_expected_capabilities(l4_buf_regs_t *bregs, int number) 101 { 102 int i; 103 l4_cap_idx_t cap; 104 105 for (i = 0; i < number; i++) 106 { 107 cap = bregs->br[i] & L4_CAP_MASK; 108 if (l4_is_valid_cap(cap)) 109 ipc_cap_free_um(cap); 110 } 111 } 112 113 /* Import from the message the capability at the given item position. */ 114 115 long _import_capability(l4_msgtag_t tag, l4_buf_regs_t *bregs, 116 l4_msg_regs_t *mregs, int item, l4_cap_idx_t *ref) 117 { 118 l4_snd_fpage_t fpage; 119 long err = _import_fpage(tag, bregs, mregs, item, &fpage); 120 121 if (err) 122 return err; 123 124 /* Check for a received capability. */ 125 126 if ((fpage.snd_base & 0x3e) != 0x38) 127 return -L4_EIO; 128 129 /* Update the supplied capability index. */ 130 131 *ref = bregs->br[item] & L4_CAP_MASK; 132 133 return L4_EOK; 134 } 135 136 /* Import from the message a dataspace, mapping it to an address. */ 137 138 long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, 139 l4_msg_regs_t *mregs, int item, l4re_ds_t *mem, 140 l4_addr_t *addr) 141 { 142 long err; 143 unsigned long size; 144 145 *mem = ipc_cap_alloc(); 146 147 err = _import_capability(tag, bregs, mregs, item, mem); 148 149 if (err) 150 { 151 ipc_cap_free_um(*mem); 152 return err; 153 } 154 155 /* Attach the dataspace to a region. */ 156 157 err = ipc_dataspace_size(*mem, &size); 158 if (err) 159 { 160 ipc_cap_free_um(*mem); 161 return err; 162 } 163 164 err = ipc_attach_dataspace(*mem, size, (void **) addr); 165 if (err) 166 { 167 ipc_cap_free_um(*mem); 168 return err; 169 } 170 171 return L4_EOK; 172 } 173 174 /* Import from the message the flexpage at the given item position. */ 175 176 long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, 177 l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage) 178 { 179 int words = l4_msgtag_words(tag); 180 181 /* NOTE: Currently, this function does not interact with the received items, 182 but instead just returns the flexpage details from the message 183 words. */ 184 185 (void) bregs; 186 187 /* Obtain the item details for the capability. */ 188 189 if (item >= (int) l4_msgtag_items(tag)) 190 return -L4_EIO; 191 192 /* Received items should start at zero. */ 193 194 fpage->snd_base = mregs->mr[words + item * 2]; 195 fpage->fpage.raw = mregs->mr[words + item * 2 + 1]; 196 197 return L4_EOK; 198 } 199 200 201 202 /* Convenience operations. */ 203 204 /* Send a reply to a call using the given message tag. */ 205 206 l4_msgtag_t util_ipc_reply(l4_msgtag_t tag) 207 { 208 return l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_NEVER); 209 } 210 211 /* Send a request using a call with the given message tag to the indicated 212 endpoint. */ 213 214 l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint) 215 { 216 return l4_ipc_call(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 217 } 218 219 /* Send data with the given message tag to the indicated endpoint. */ 220 221 l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint) 222 { 223 return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 224 }