Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / lib / libsys / safecopies.c
blob607a67e9dcdbc06f9069c029ce3e5eb7a7ea72f1
2 /* Library functions to maintain internal data copying tables.
4 * April 21 2006: Initial version (Ben Gras)
6 */
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>
18 #define ACCESS_CHECK(a) { \
19 if((a) & ~(CPF_READ|CPF_WRITE|CPF_TRY)) { \
20 errno = EINVAL; \
21 return -1; \
22 } \
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 } \
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 } \
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;
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.
56 void
57 cpf_prealloc(unsigned int count)
59 cp_grant_t *new_grants;
60 int g, new_size;
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;
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);
80 /* Allocate a block of new size. */
81 if(!(new_grants=malloc(new_size * sizeof(grants[0])))) {
82 return;
86 /* Copy old block to new block. */
87 if(grants && ngrants > 0)
88 memcpy(new_grants, grants, ngrants * sizeof(grants[0]));
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).
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;
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. */
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;
119 static int
120 cpf_new_grantslot(void)
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.
126 int g;
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;
139 /* Basic sanity checks - if we get this far, g must be a valid,
140 * free slot.
142 assert(g >= 0);
143 assert(g < ngrants);
144 assert(!(grants[g].cp_flags & CPF_USED));
146 /* Take the slot off the free list, and return its slot number. */
147 freelist = grants[g].cp_u.cp_free.cp_next;
149 return g;
152 cp_grant_id_t
153 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access)
155 int g;
157 ACCESS_CHECK(access);
159 /* Get new slot to put new grant in. */
160 if((g = cpf_new_grantslot()) < 0)
161 return -1;
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;
171 return GRANT_ID(g, grants[g].cp_seq);
174 cp_grant_id_t
175 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr)
177 /* Grant process A access into process B. B has granted us access as grant
178 * id 'gr'.
180 int g;
182 /* Obtain new slot. */
183 if((g = cpf_new_grantslot()) < 0)
184 return -1;
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;
194 return GRANT_ID(g, grants[g].cp_seq);
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)
201 /* Grant process A access into process B. Not everyone can do this. */
202 int g;
204 ACCESS_CHECK(access);
206 /* Obtain new slot. */
207 if((g = cpf_new_grantslot()) < 0)
208 return -1;
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;
219 return GRANT_ID(g, grants[g].cp_seq);
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.
229 cpf_revoke(cp_grant_id_t grant)
231 int r, g;
233 GID_CHECK_USED(grant);
235 g = GRANT_IDX(grant);
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.
243 r = ((grants[g].cp_flags & CPF_TRY) &&
244 grants[g].cp_faulted == grant) ? GRANT_FAULTED : 0;
247 * Make grant invalid by setting flags to 0, clearing CPF_USED.
248 * This invalidates the grant.
250 grants[g].cp_flags = 0;
251 __insn_barrier();
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.
259 if (grants[g].cp_seq < GRANT_MAX_SEQ - 1)
260 grants[g].cp_seq++;
261 else
262 grants[g].cp_seq = 0;
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.
269 grants[g].cp_u.cp_free.cp_next = freelist;
270 freelist = g;
272 return r;
276 * START OF DEPRECATED API
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.
285 cpf_getgrants(cp_grant_id_t *grant_ids, int n)
287 int i;
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;
296 /* return however many grants were assigned. */
297 return i;
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;
308 GID_CHECK(gid);
309 ACCESS_CHECK(access);
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;
317 return 0;
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;
326 GID_CHECK(gid);
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;
334 return 0;
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;
345 GID_CHECK(gid);
346 ACCESS_CHECK(access);
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;
355 return 0;
359 cpf_setgrant_disable(gid)
360 cp_grant_id_t gid;
362 GID_CHECK(gid);
364 /* Grant is now no longer valid, but still in use. */
365 grants[gid].cp_flags = CPF_USED;
367 return 0;
370 * END OF DEPRECATED API
373 void
374 cpf_reload(void)
376 /* Inform the kernel about the location of the grant table. This is needed
377 * after a fork.
379 if (grants)
380 sys_setgrant(grants, ngrants); /* Do we need error checking? */