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) || (gid) < 0 || (gid) >= ngrants) {\ 27 errno = EINVAL; \ 28 return -1; \ 29 } \ 30 } 31 32 #define GID_CHECK_USED(gid) { \ 33 GID_CHECK(gid); \ 34 if(!(grants[gid].cp_flags & CPF_USED)) { \ 35 errno = EINVAL; \ 36 return -1; \ 37 } \ 38 } 39 40 #define CLICK_ALIGNMENT_CHECK(addr, bytes) { \ 41 if(((vir_bytes)(addr) % CLICK_SIZE != 0) \ 42 || ((vir_bytes)(bytes) % CLICK_SIZE != 0)) { \ 43 return EINVAL; \ 44 } \ 45 } 46 47 #define NR_STATIC_GRANTS 3 48 static cp_grant_t static_grants[NR_STATIC_GRANTS]; 49 static cp_grant_t *grants = NULL; 50 static int ngrants = 0; 51 52 static void 53 cpf_grow(void) 54 { 55 /* Grow the grants table if possible. */ 56 cp_grant_t *new_grants; 57 cp_grant_id_t g; 58 int new_size; 59 60 if(!ngrants) { 61 /* Use statically allocated grants the first time. */ 62 new_size = NR_STATIC_GRANTS; 63 new_grants = static_grants; 64 } 65 else { 66 new_size = (1+ngrants)*2; 67 assert(new_size > ngrants); 68 69 /* Allocate a block of new size. */ 70 if(!(new_grants=malloc(new_size * sizeof(grants[0])))) { 71 return; 72 } 73 } 74 75 /* Copy old block to new block. */ 76 if(grants && ngrants > 0) 77 memcpy(new_grants, grants, ngrants * sizeof(grants[0])); 78 79 /* Make sure new slots are marked unused (CPF_USED is clear). */ 80 for(g = ngrants; g < new_size; g++) 81 new_grants[g].cp_flags = 0; 82 83 /* Inform kernel about new size (and possibly new location). */ 84 if((sys_setgrant(new_grants, new_size))) { 85 if(new_grants != static_grants) free(new_grants); 86 return; /* Failed - don't grow then. */ 87 } 88 89 /* Update internal data. */ 90 if(grants && ngrants > 0 && grants != static_grants) free(grants); 91 grants = new_grants; 92 ngrants = new_size; 93 } 94 95 static cp_grant_id_t 96 cpf_new_grantslot(void) 97 { 98 /* Find a new, free grant slot in the grant table, grow it if 99 * necessary. If no free slot is found and the grow failed, 100 * return -1. Otherwise, return grant slot number. 101 */ 102 cp_grant_id_t g; 103 104 /* Find free slot. */ 105 for(g = 0; g < ngrants && (grants[g].cp_flags & CPF_USED); g++) 106 ; 107 108 assert(g <= ngrants); 109 110 /* No free slot found? */ 111 if(g == ngrants) { 112 cpf_grow(); 113 assert(g <= ngrants); /* ngrants can't shrink. */ 114 if(g == ngrants) { 115 /* ngrants hasn't increased. */ 116 errno = ENOSPC; 117 return -1; 118 } 119 } 120 121 /* Basic sanity checks - if we get this far, g must be a valid, 122 * free slot. 123 */ 124 assert(GRANT_VALID(g)); 125 assert(g >= 0); 126 assert(g < ngrants); 127 assert(!(grants[g].cp_flags & CPF_USED)); 128 129 return g; 130 } 131 132 cp_grant_id_t 133 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access) 134 { 135 cp_grant_id_t g; 136 int r; 137 138 /* Get new slot to put new grant in. */ 139 if((g = cpf_new_grantslot()) < 0) 140 return(GRANT_INVALID); 141 142 assert(GRANT_VALID(g)); 143 assert(g >= 0); 144 assert(g < ngrants); 145 assert(!(grants[g].cp_flags & CPF_USED)); 146 147 if((r=cpf_setgrant_direct(g, who_to, addr, bytes, access)) < 0) { 148 cpf_revoke(g); 149 return(GRANT_INVALID); 150 } 151 152 return g; 153 } 154 155 cp_grant_id_t 156 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr) 157 { 158 /* Grant process A access into process B. B has granted us access as grant 159 * id 'gr'. 160 */ 161 cp_grant_id_t g; 162 int r; 163 164 /* Obtain new slot. */ 165 if((g = cpf_new_grantslot()) < 0) 166 return -1; 167 168 /* Basic sanity checks. */ 169 assert(GRANT_VALID(g)); 170 assert(g >= 0); 171 assert(g < ngrants); 172 assert(!(grants[g].cp_flags & CPF_USED)); 173 174 /* Fill in new slot data. */ 175 if((r=cpf_setgrant_indirect(g, who_to, who_from, gr)) < 0) { 176 cpf_revoke(g); 177 return GRANT_INVALID; 178 } 179 180 return g; 181 } 182 183 cp_grant_id_t 184 cpf_grant_magic(endpoint_t who_to, endpoint_t who_from, 185 vir_bytes addr, size_t bytes, int access) 186 { 187 /* Grant process A access into process B. Not everyone can do this. */ 188 cp_grant_id_t g; 189 int r; 190 191 ACCESS_CHECK(access); 192 193 /* Obtain new slot. */ 194 if((g = cpf_new_grantslot()) < 0) 195 return -1; 196 197 /* Basic sanity checks. */ 198 assert(GRANT_VALID(g)); 199 assert(g >= 0); 200 assert(g < ngrants); 201 assert(!(grants[g].cp_flags & CPF_USED)); 202 203 if((r=cpf_setgrant_magic(g, who_to, who_from, addr, 204 bytes, access)) < 0) { 205 cpf_revoke(g); 206 return -1; 207 } 208 209 return g; 210 } 211 212 int 213 cpf_revoke(cp_grant_id_t g) 214 { 215 /* Revoke previously granted access, identified by grant id. */ 216 GID_CHECK_USED(g); 217 218 /* Make grant invalid by setting flags to 0, clearing CPF_USED. 219 * This invalidates the grant. 220 */ 221 grants[g].cp_flags = 0; 222 223 return 0; 224 } 225 226 int 227 cpf_lookup(cp_grant_id_t g, endpoint_t *granter, endpoint_t *grantee) 228 { 229 /* First check slot validity, and if it's in use currently. */ 230 GID_CHECK_USED(g); 231 232 if(grants[g].cp_flags & CPF_DIRECT) { 233 if(granter) *granter = SELF; 234 if(grantee) *grantee = grants[g].cp_u.cp_direct.cp_who_to; 235 } else if(grants[g].cp_flags & CPF_MAGIC) { 236 if(granter) *granter = grants[g].cp_u.cp_magic.cp_who_from; 237 if(grantee) *grantee = grants[g].cp_u.cp_magic.cp_who_to; 238 } else return -1; 239 240 return 0; 241 } 242 243 int 244 cpf_getgrants(cp_grant_id_t *grant_ids, int n) 245 { 246 int i; 247 248 for(i = 0; i < n; i++) { 249 if((grant_ids[i] = cpf_new_grantslot()) < 0) 250 break; 251 grants[grant_ids[i]].cp_flags = CPF_USED; 252 } 253 254 /* return however many grants were assigned. */ 255 return i; 256 } 257 258 int 259 cpf_setgrant_direct(gid, who, addr, bytes, access) 260 cp_grant_id_t gid; 261 endpoint_t who; 262 vir_bytes addr; 263 size_t bytes; 264 int access; 265 { 266 GID_CHECK(gid); 267 ACCESS_CHECK(access); 268 269 /* Fill in new slot data. */ 270 grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID; 271 grants[gid].cp_u.cp_direct.cp_who_to = who; 272 grants[gid].cp_u.cp_direct.cp_start = addr; 273 grants[gid].cp_u.cp_direct.cp_len = bytes; 274 275 return 0; 276 } 277 278 int 279 cpf_setgrant_indirect(gid, who_to, who_from, his_gid) 280 cp_grant_id_t gid; 281 endpoint_t who_to, who_from; 282 cp_grant_id_t his_gid; 283 { 284 GID_CHECK(gid); 285 286 /* Fill in new slot data. */ 287 grants[gid].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID; 288 grants[gid].cp_u.cp_indirect.cp_who_to = who_to; 289 grants[gid].cp_u.cp_indirect.cp_who_from = who_from; 290 grants[gid].cp_u.cp_indirect.cp_grant = his_gid; 291 292 return 0; 293 } 294 295 int 296 cpf_setgrant_magic(gid, who_to, who_from, addr, bytes, access) 297 cp_grant_id_t gid; 298 endpoint_t who_to, who_from; 299 vir_bytes addr; 300 size_t bytes; 301 int access; 302 { 303 GID_CHECK(gid); 304 ACCESS_CHECK(access); 305 306 /* Fill in new slot data. */ 307 grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access; 308 grants[gid].cp_u.cp_magic.cp_who_to = who_to; 309 grants[gid].cp_u.cp_magic.cp_who_from = who_from; 310 grants[gid].cp_u.cp_magic.cp_start = addr; 311 grants[gid].cp_u.cp_magic.cp_len = bytes; 312 313 return 0; 314 } 315 316 int 317 cpf_setgrant_disable(gid) 318 cp_grant_id_t gid; 319 { 320 GID_CHECK(gid); 321 322 /* Grant is now no longer valid, but still in use. */ 323 grants[gid].cp_flags = CPF_USED; 324 325 return 0; 326 } 327 328 void 329 cpf_reload(void) 330 { 331 /* Inform the kernel about the location of the grant table. This is needed 332 * after a fork. 333 */ 334 if (grants) 335 sys_setgrant(grants, ngrants); /* Do we need error checking? */ 336 } 337 338