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 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 /* Indicate that a flexpage is expected at the given position. */ 68 69 long _expect_fpage(l4_buf_regs_t *bregs, int item, l4_umword_t map_control, l4_fpage_t fpage) 70 { 71 bregs->bdr = 0; 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 number) 112 { 113 int i; 114 l4_cap_idx_t cap; 115 116 for (i = 0; i < number; 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, l4_cap_idx_t *ref) 128 { 129 l4_snd_fpage_t fpage; 130 long err = _import_fpage(tag, bregs, mregs, item, &fpage); 131 132 if (err) 133 return err; 134 135 /* Check for a received capability. */ 136 137 if ((fpage.snd_base & 0x3e) != 0x38) 138 return -L4_EIO; 139 140 /* Update the supplied capability index. */ 141 142 *ref = bregs->br[item] & L4_CAP_MASK; 143 144 return L4_EOK; 145 } 146 147 /* Import from the message a dataspace, mapping it to an address. */ 148 149 long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, 150 l4_msg_regs_t *mregs, int item, l4re_ds_t *mem, 151 l4_addr_t *addr) 152 { 153 long err; 154 unsigned long size; 155 156 *mem = ipc_cap_alloc(); 157 158 err = _import_capability(tag, bregs, mregs, item, mem); 159 160 if (err) 161 { 162 ipc_cap_free_um(*mem); 163 return err; 164 } 165 166 /* Attach the dataspace to a region. */ 167 168 err = ipc_dataspace_size(*mem, &size); 169 if (err) 170 { 171 ipc_cap_free_um(*mem); 172 return err; 173 } 174 175 err = ipc_attach_dataspace(*mem, size, (void **) addr); 176 if (err) 177 { 178 ipc_cap_free_um(*mem); 179 return err; 180 } 181 182 return L4_EOK; 183 } 184 185 /* Import from the message the flexpage at the given item position. */ 186 187 long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, 188 l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage) 189 { 190 int words = l4_msgtag_words(tag); 191 192 /* NOTE: Currently, this function does not interact with the received items, 193 but instead just returns the flexpage details from the message 194 words. */ 195 196 (void) bregs; 197 198 /* Obtain the item details for the capability. */ 199 200 if (item >= (int) l4_msgtag_items(tag)) 201 return -L4_EIO; 202 203 /* Received items should start at zero. */ 204 205 fpage->snd_base = mregs->mr[words + item * 2]; 206 fpage->fpage.raw = mregs->mr[words + item * 2 + 1]; 207 208 return L4_EOK; 209 } 210 211 212 213 /* Convenience operations. */ 214 215 /* Send a reply to a call using the given message tag. */ 216 217 l4_msgtag_t util_ipc_reply(l4_msgtag_t tag) 218 { 219 return l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_NEVER); 220 } 221 222 /* Send a request using a call with the given message tag to the indicated 223 endpoint. */ 224 225 l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint) 226 { 227 return l4_ipc_call(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 228 } 229 230 /* Send data with the given message tag to the indicated endpoint. */ 231 232 l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint) 233 { 234 return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER); 235 }