1 2 /* Library functions to maintain internal data copying tables. 3 * 4 * April 21 2006: Initial version (Ben Gras) 5 * 6 */ 7 8 #include <lib.h> 9 #include <errno.h> 10 #include <minix/sysutil.h> 11 #include <assert.h> 12 #include <stdlib.h> 13 #include <minix/syslib.h> 14 #include <minix/safecopies.h> 15 #include <minix/com.h> 16 #include <string.h> 17 18 #define ACCESS_CHECK(a) { \ 19 if((a) & ~(CPF_READ|CPF_WRITE|CPF_TRY)) { \ 20 errno = EINVAL; \ 21 return -1; \ 22 } \ 23 } 24 25 #define GID_CHECK(gid) { \ 26 if(!GRANT_VALID(gid) || GRANT_IDX(gid) >= ngrants || \ 27 GRANT_SEQ(gid) != grants[GRANT_IDX(gid)].cp_seq) { \ 28 errno = EINVAL; \ 29 return -1; \ 30 } \ 31 } 32 33 #define GID_CHECK_USED(gid) { \ 34 GID_CHECK(gid); \ 35 if(!(grants[GRANT_IDX(gid)].cp_flags & CPF_USED)) { \ 36 errno = EINVAL; \ 37 return -1; \ 38 } \ 39 } 40 41 #define NR_STATIC_GRANTS 3 42 static cp_grant_t static_grants[NR_STATIC_GRANTS]; 43 static cp_grant_t *grants = NULL; 44 static int ngrants = 0; 45 static int freelist = -1; 46 47 /* 48 * Preallocate more grants that will be free for subsequent use. If a specific 49 * number of grants is given (i.e., count > 0), the total number of grants will 50 * be increased by that amount. If no number of grants is given (count == 0), 51 * double(ish) the size of the table. The latter is used internally. This 52 * function may fail, either because the maximum number of slots is reached or 53 * because no new memory can be allocated. In that case, nothing will change; 54 * the caller must check afterward whether there are newly available grants. 55 */ 56 void 57 cpf_prealloc(unsigned int count) 58 { 59 cp_grant_t *new_grants; 60 int g, new_size; 61 62 if (!ngrants && count <= NR_STATIC_GRANTS) { 63 /* Use statically allocated grants the first time. */ 64 new_size = NR_STATIC_GRANTS; 65 new_grants = static_grants; 66 } 67 else { 68 if (ngrants >= GRANT_MAX_IDX) 69 return; 70 if (count != 0) { 71 if (count > (unsigned)(GRANT_MAX_IDX - ngrants)) 72 count = (unsigned)(GRANT_MAX_IDX - ngrants); 73 new_size = ngrants + (int)count; 74 } else 75 new_size = (1+ngrants)*2; 76 if (new_size >= GRANT_MAX_IDX) 77 new_size = GRANT_MAX_IDX; 78 assert(new_size > ngrants); 79 80 /* Allocate a block of new size. */ 81 if(!(new_grants=malloc(new_size * sizeof(grants[0])))) { 82 return; 83 } 84 } 85 86 /* Copy old block to new block. */ 87 if(grants && ngrants > 0) 88 memcpy(new_grants, grants, ngrants * sizeof(grants[0])); 89 90 /* 91 * Make sure new slots are marked unused (CPF_USED is clear). 92 * Also start with a zero sequence number, for consistency; since the 93 * grant table is never shrunk, this introduces no issues by itself. 94 * Finally, form a new free list, in ascending order so that the lowest 95 * IDs get allocated first. Both the zeroed sequence number and the 96 * ascending order are necessary so that the first grant to be 97 * allocated has a zero ID (see the live update comment below). 98 */ 99 for(g = ngrants; g < new_size; g++) { 100 new_grants[g].cp_flags = 0; 101 new_grants[g].cp_seq = 0; 102 new_grants[g].cp_u.cp_free.cp_next = 103 (g < new_size - 1) ? (g + 1) : freelist; 104 } 105 106 /* Inform kernel about new size (and possibly new location). */ 107 if((sys_setgrant(new_grants, new_size))) { 108 if(new_grants != static_grants) free(new_grants); 109 return; /* Failed - don't grow then. */ 110 } 111 112 /* Update internal data. */ 113 if(grants && ngrants > 0 && grants != static_grants) free(grants); 114 freelist = ngrants; 115 grants = new_grants; 116 ngrants = new_size; 117 } 118 119 static int 120 cpf_new_grantslot(void) 121 { 122 /* Find a new, free grant slot in the grant table, grow it if 123 * necessary. If no free slot is found and the grow failed, 124 * return -1. Otherwise, return grant slot number. 125 */ 126 int g; 127 128 /* Obtain a free slot. */ 129 if ((g = freelist) == -1) { 130 /* Table full - try to make the table larger. */ 131 cpf_prealloc(0); 132 if ((g = freelist) == -1) { 133 /* ngrants hasn't increased. */ 134 errno = ENOSPC; 135 return -1; 136 } 137 } 138 139 /* Basic sanity checks - if we get this far, g must be a valid, 140 * free slot. 141 */ 142 assert(g >= 0); 143 assert(g < ngrants); 144 assert(!(grants[g].cp_flags & CPF_USED)); 145 146 /* Take the slot off the free list, and return its slot number. */ 147 freelist = grants[g].cp_u.cp_free.cp_next; 148 149 return g; 150 } 151 152 cp_grant_id_t 153 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access) 154 { 155 int g; 156 157 ACCESS_CHECK(access); 158 159 /* Get new slot to put new grant in. */ 160 if((g = cpf_new_grantslot()) < 0) 161 return -1; 162 163 /* Fill in new slot data. */ 164 grants[g].cp_u.cp_direct.cp_who_to = who_to; 165 grants[g].cp_u.cp_direct.cp_start = addr; 166 grants[g].cp_u.cp_direct.cp_len = bytes; 167 grants[g].cp_faulted = GRANT_INVALID; 168 __insn_barrier(); 169 grants[g].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID; 170 171 return GRANT_ID(g, grants[g].cp_seq); 172 } 173 174 cp_grant_id_t 175 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr) 176 { 177 /* Grant process A access into process B. B has granted us access as grant 178 * id 'gr'. 179 */ 180 int g; 181 182 /* Obtain new slot. */ 183 if((g = cpf_new_grantslot()) < 0) 184 return -1; 185 186 /* Fill in new slot data. */ 187 grants[g].cp_u.cp_indirect.cp_who_to = who_to; 188 grants[g].cp_u.cp_indirect.cp_who_from = who_from; 189 grants[g].cp_u.cp_indirect.cp_grant = gr; 190 grants[g].cp_faulted = GRANT_INVALID; 191 __insn_barrier(); 192 grants[g].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID; 193 194 return GRANT_ID(g, grants[g].cp_seq); 195 } 196 197 cp_grant_id_t 198 cpf_grant_magic(endpoint_t who_to, endpoint_t who_from, 199 vir_bytes addr, size_t bytes, int access) 200 { 201 /* Grant process A access into process B. Not everyone can do this. */ 202 int g; 203 204 ACCESS_CHECK(access); 205 206 /* Obtain new slot. */ 207 if((g = cpf_new_grantslot()) < 0) 208 return -1; 209 210 /* Fill in new slot data. */ 211 grants[g].cp_u.cp_magic.cp_who_to = who_to; 212 grants[g].cp_u.cp_magic.cp_who_from = who_from; 213 grants[g].cp_u.cp_magic.cp_start = addr; 214 grants[g].cp_u.cp_magic.cp_len = bytes; 215 grants[g].cp_faulted = GRANT_INVALID; 216 __insn_barrier(); 217 grants[g].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access; 218 219 return GRANT_ID(g, grants[g].cp_seq); 220 } 221 222 /* 223 * Revoke previously granted access, identified by grant ID. Return -1 on 224 * error, with errno set as appropriate. Return 0 on success, with one 225 * exception: return GRANT_FAULTED (1) if a grant was created with CPF_TRY and 226 * during its lifetime, a copy from or to the grant experienced a soft fault. 227 */ 228 int 229 cpf_revoke(cp_grant_id_t grant) 230 { 231 int r, g; 232 233 GID_CHECK_USED(grant); 234 235 g = GRANT_IDX(grant); 236 237 /* 238 * If a safecopy action on a (direct or magic) grant with the CPF_TRY 239 * flag failed on a soft fault, the kernel will have set the cp_faulted 240 * field to the grant identifier. Here, we test this and return 241 * GRANT_FAULTED (1) on a match. 242 */ 243 r = ((grants[g].cp_flags & CPF_TRY) && 244 grants[g].cp_faulted == grant) ? GRANT_FAULTED : 0; 245 246 /* 247 * Make grant invalid by setting flags to 0, clearing CPF_USED. 248 * This invalidates the grant. 249 */ 250 grants[g].cp_flags = 0; 251 __insn_barrier(); 252 253 /* 254 * Increase the grant slot's sequence number now, rather than on 255 * allocation, because live update relies on the first allocated grant 256 * having a zero ID (SEF_STATE_TRANSFER_GID) and thus a zero sequence 257 * number. 258 */ 259 if (grants[g].cp_seq < GRANT_MAX_SEQ - 1) 260 grants[g].cp_seq++; 261 else 262 grants[g].cp_seq = 0; 263 264 /* 265 * Put the grant back on the free list. The list is single-headed, so 266 * the last freed grant will be the first to be reused. Especially 267 * given the presence of sequence numbers, this is not a problem. 268 */ 269 grants[g].cp_u.cp_free.cp_next = freelist; 270 freelist = g; 271 272 return r; 273 } 274 275 /* 276 * START OF DEPRECATED API 277 * 278 * The grant preallocation and (re)assignment API below imposes that grant IDs 279 * stay the same across reuse, thus disallowing that the grants' sequence 280 * numbers be updated as a part of reassignment. As a result, this API does 281 * not offer the same protection against accidental reuse of an old grant by a 282 * remote party as the regular API does, and is therefore deprecated. 283 */ 284 int 285 cpf_getgrants(cp_grant_id_t *grant_ids, int n) 286 { 287 int i; 288 289 for(i = 0; i < n; i++) { 290 if((grant_ids[i] = cpf_new_grantslot()) < 0) 291 break; 292 grants[grant_ids[i]].cp_flags = CPF_USED; 293 grants[grant_ids[i]].cp_seq = 0; 294 } 295 296 /* return however many grants were assigned. */ 297 return i; 298 } 299 300 int 301 cpf_setgrant_direct(gid, who, addr, bytes, access) 302 cp_grant_id_t gid; 303 endpoint_t who; 304 vir_bytes addr; 305 size_t bytes; 306 int access; 307 { 308 GID_CHECK(gid); 309 ACCESS_CHECK(access); 310 311 /* Fill in new slot data. */ 312 grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID; 313 grants[gid].cp_u.cp_direct.cp_who_to = who; 314 grants[gid].cp_u.cp_direct.cp_start = addr; 315 grants[gid].cp_u.cp_direct.cp_len = bytes; 316 317 return 0; 318 } 319 320 int 321 cpf_setgrant_indirect(gid, who_to, who_from, his_gid) 322 cp_grant_id_t gid; 323 endpoint_t who_to, who_from; 324 cp_grant_id_t his_gid; 325 { 326 GID_CHECK(gid); 327 328 /* Fill in new slot data. */ 329 grants[gid].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID; 330 grants[gid].cp_u.cp_indirect.cp_who_to = who_to; 331 grants[gid].cp_u.cp_indirect.cp_who_from = who_from; 332 grants[gid].cp_u.cp_indirect.cp_grant = his_gid; 333 334 return 0; 335 } 336 337 int 338 cpf_setgrant_magic(gid, who_to, who_from, addr, bytes, access) 339 cp_grant_id_t gid; 340 endpoint_t who_to, who_from; 341 vir_bytes addr; 342 size_t bytes; 343 int access; 344 { 345 GID_CHECK(gid); 346 ACCESS_CHECK(access); 347 348 /* Fill in new slot data. */ 349 grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access; 350 grants[gid].cp_u.cp_magic.cp_who_to = who_to; 351 grants[gid].cp_u.cp_magic.cp_who_from = who_from; 352 grants[gid].cp_u.cp_magic.cp_start = addr; 353 grants[gid].cp_u.cp_magic.cp_len = bytes; 354 355 return 0; 356 } 357 358 int 359 cpf_setgrant_disable(gid) 360 cp_grant_id_t gid; 361 { 362 GID_CHECK(gid); 363 364 /* Grant is now no longer valid, but still in use. */ 365 grants[gid].cp_flags = CPF_USED; 366 367 return 0; 368 } 369 /* 370 * END OF DEPRECATED API 371 */ 372 373 void 374 cpf_reload(void) 375 { 376 /* Inform the kernel about the location of the grant table. This is needed 377 * after a fork. 378 */ 379 if (grants) 380 sys_setgrant(grants, ngrants); /* Do we need error checking? */ 381 } 382