VM: full munmap
[minix.git] / lib / libsys / safecopies.c
blobf4f7f83bdad2ee2473d6cc54146c993933fd5bfd
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_MAP)) { \
20 errno = EINVAL; \
21 return -1; \
22 } \
25 #define GID_CHECK(gid) { \
26 if(!GRANT_VALID(gid) || (gid) < 0 || (gid) >= ngrants) {\
27 errno = EINVAL; \
28 return -1; \
29 } \
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 } \
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 } \
47 #define NR_STATIC_GRANTS 2
48 static cp_grant_t static_grants[NR_STATIC_GRANTS];
49 static cp_grant_t *grants = NULL;
50 static int ngrants = 0;
52 static void
53 cpf_grow(void)
55 /* Grow the grants table if possible. */
56 cp_grant_t *new_grants;
57 cp_grant_id_t g;
58 int new_size;
60 if(!ngrants) {
61 /* Use statically allocated grants the first time. */
62 new_size = NR_STATIC_GRANTS;
63 new_grants = static_grants;
65 else {
66 new_size = (1+ngrants)*2;
67 assert(new_size > ngrants);
69 /* Allocate a block of new size. */
70 if(!(new_grants=malloc(new_size * sizeof(grants[0])))) {
71 return;
75 /* Copy old block to new block. */
76 if(grants && ngrants > 0)
77 memcpy(new_grants, grants, ngrants * sizeof(grants[0]));
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;
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. */
89 /* Update internal data. */
90 if(grants && ngrants > 0 && grants != static_grants) free(grants);
91 grants = new_grants;
92 ngrants = new_size;
95 static cp_grant_id_t
96 cpf_new_grantslot(void)
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.
102 cp_grant_id_t g;
104 /* Find free slot. */
105 for(g = 0; g < ngrants && (grants[g].cp_flags & CPF_USED); g++)
108 assert(g <= ngrants);
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;
121 /* Basic sanity checks - if we get this far, g must be a valid,
122 * free slot.
124 assert(GRANT_VALID(g));
125 assert(g >= 0);
126 assert(g < ngrants);
127 assert(!(grants[g].cp_flags & CPF_USED));
129 return g;
132 cp_grant_id_t
133 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access)
135 cp_grant_id_t g;
136 int r;
138 /* Get new slot to put new grant in. */
139 if((g = cpf_new_grantslot()) < 0)
140 return(GRANT_INVALID);
142 assert(GRANT_VALID(g));
143 assert(g >= 0);
144 assert(g < ngrants);
145 assert(!(grants[g].cp_flags & CPF_USED));
147 if((r=cpf_setgrant_direct(g, who_to, addr, bytes, access)) < 0) {
148 cpf_revoke(g);
149 return(GRANT_INVALID);
152 return g;
155 cp_grant_id_t
156 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr)
158 /* Grant process A access into process B. B has granted us access as grant
159 * id 'gr'.
161 cp_grant_id_t g;
162 int r;
164 /* Obtain new slot. */
165 if((g = cpf_new_grantslot()) < 0)
166 return -1;
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));
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;
180 return g;
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)
187 /* Grant process A access into process B. Not everyone can do this. */
188 cp_grant_id_t g;
189 int r;
191 ACCESS_CHECK(access);
193 /* Obtain new slot. */
194 if((g = cpf_new_grantslot()) < 0)
195 return -1;
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));
203 if((r=cpf_setgrant_magic(g, who_to, who_from, addr,
204 bytes, access)) < 0) {
205 cpf_revoke(g);
206 return -1;
209 return g;
213 cpf_revoke(cp_grant_id_t g)
215 /* Revoke previously granted access, identified by grant id. */
216 int r;
217 GID_CHECK_USED(g);
219 /* If this grant is for memory mapping, revoke the mapping first. */
220 if(grants[g].cp_flags & CPF_MAP) {
221 r = sys_saferevmap_gid(g);
222 if(r != 0)
223 return r;
226 /* Make grant invalid by setting flags to 0, clearing CPF_USED.
227 * This invalidates the grant.
229 grants[g].cp_flags = 0;
231 return 0;
235 cpf_lookup(cp_grant_id_t g, endpoint_t *granter, endpoint_t *grantee)
237 /* First check slot validity, and if it's in use currently. */
238 GID_CHECK_USED(g);
240 if(grants[g].cp_flags & CPF_DIRECT) {
241 if(granter) *granter = SELF;
242 if(grantee) *grantee = grants[g].cp_u.cp_direct.cp_who_to;
243 } else if(grants[g].cp_flags & CPF_MAGIC) {
244 if(granter) *granter = grants[g].cp_u.cp_magic.cp_who_from;
245 if(grantee) *grantee = grants[g].cp_u.cp_magic.cp_who_to;
246 } else return -1;
248 return 0;
252 cpf_getgrants(cp_grant_id_t *grant_ids, int n)
254 int i;
256 for(i = 0; i < n; i++) {
257 if((grant_ids[i] = cpf_new_grantslot()) < 0)
258 break;
259 grants[grant_ids[i]].cp_flags = CPF_USED;
262 /* return however many grants were assigned. */
263 return i;
267 cpf_setgrant_direct(gid, who, addr, bytes, access)
268 cp_grant_id_t gid;
269 endpoint_t who;
270 vir_bytes addr;
271 size_t bytes;
272 int access;
274 GID_CHECK(gid);
275 ACCESS_CHECK(access);
277 /* Check click alignment in case of memory mapping grant. */
278 if(access & CPF_MAP) {
279 CLICK_ALIGNMENT_CHECK(addr, bytes);
282 /* Fill in new slot data. */
283 grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID;
284 grants[gid].cp_u.cp_direct.cp_who_to = who;
285 grants[gid].cp_u.cp_direct.cp_start = addr;
286 grants[gid].cp_u.cp_direct.cp_len = bytes;
288 return 0;
292 cpf_setgrant_indirect(gid, who_to, who_from, his_gid)
293 cp_grant_id_t gid;
294 endpoint_t who_to, who_from;
295 cp_grant_id_t his_gid;
297 GID_CHECK(gid);
299 /* Fill in new slot data. */
300 grants[gid].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID;
301 grants[gid].cp_u.cp_indirect.cp_who_to = who_to;
302 grants[gid].cp_u.cp_indirect.cp_who_from = who_from;
303 grants[gid].cp_u.cp_indirect.cp_grant = his_gid;
305 return 0;
309 cpf_setgrant_magic(gid, who_to, who_from, addr, bytes, access)
310 cp_grant_id_t gid;
311 endpoint_t who_to, who_from;
312 vir_bytes addr;
313 size_t bytes;
314 int access;
316 GID_CHECK(gid);
317 ACCESS_CHECK(access);
319 /* Check click alignment in case of memory mapping grant. */
320 if(access & CPF_MAP) {
321 CLICK_ALIGNMENT_CHECK(addr, bytes);
324 /* Fill in new slot data. */
325 grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access;
326 grants[gid].cp_u.cp_magic.cp_who_to = who_to;
327 grants[gid].cp_u.cp_magic.cp_who_from = who_from;
328 grants[gid].cp_u.cp_magic.cp_start = addr;
329 grants[gid].cp_u.cp_magic.cp_len = bytes;
331 return 0;
335 cpf_setgrant_disable(gid)
336 cp_grant_id_t gid;
338 GID_CHECK(gid);
340 /* Grant is now no longer valid, but still in use. */
341 grants[gid].cp_flags = CPF_USED;
343 return 0;
346 void
347 cpf_reload(void)
349 /* Inform the kernel about the location of the grant table. This is needed
350 * after a fork.
352 if (grants)
353 sys_setgrant(grants, ngrants); /* Do we need error checking? */