1433d6423SLionel Sambuc
2433d6423SLionel Sambuc #define _SYSTEM 1
3433d6423SLionel Sambuc
4433d6423SLionel Sambuc #include <minix/callnr.h>
5433d6423SLionel Sambuc #include <minix/com.h>
6433d6423SLionel Sambuc #include <minix/config.h>
7433d6423SLionel Sambuc #include <minix/const.h>
8433d6423SLionel Sambuc #include <minix/ds.h>
9433d6423SLionel Sambuc #include <minix/endpoint.h>
10433d6423SLionel Sambuc #include <minix/minlib.h>
11433d6423SLionel Sambuc #include <minix/type.h>
12433d6423SLionel Sambuc #include <minix/ipc.h>
13433d6423SLionel Sambuc #include <minix/sysutil.h>
14433d6423SLionel Sambuc #include <minix/syslib.h>
15433d6423SLionel Sambuc #include <minix/bitmap.h>
16433d6423SLionel Sambuc #include <minix/debug.h>
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc #include <assert.h>
19433d6423SLionel Sambuc #include <errno.h>
20433d6423SLionel Sambuc #include <string.h>
21433d6423SLionel Sambuc
22433d6423SLionel Sambuc #include <sys/param.h>
23433d6423SLionel Sambuc
24433d6423SLionel Sambuc #include "glo.h"
25433d6423SLionel Sambuc #include "proto.h"
26433d6423SLionel Sambuc #include "util.h"
27433d6423SLionel Sambuc #include "sanitycheck.h"
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc #define SLABSIZES 200
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc #define ITEMSPERPAGE(bytes) (int)(DATABYTES / (bytes))
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc #define ELBITS (sizeof(element_t)*8)
34433d6423SLionel Sambuc #define BITPAT(b) (1UL << ((b) % ELBITS))
35433d6423SLionel Sambuc #define BITEL(f, b) (f)->sdh.usebits[(b)/ELBITS]
36433d6423SLionel Sambuc
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc #define OFF(f, b) assert(!GETBIT(f, b))
39433d6423SLionel Sambuc #define ON(f, b) assert(GETBIT(f, b))
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc #if MEMPROTECT
42433d6423SLionel Sambuc #define SLABDATAWRITABLE(data, wr) do { \
43433d6423SLionel Sambuc assert(data->sdh.writable == WRITABLE_NONE); \
44433d6423SLionel Sambuc assert(wr != WRITABLE_NONE); \
45433d6423SLionel Sambuc vm_pagelock(data, 0); \
46433d6423SLionel Sambuc data->sdh.writable = wr; \
47433d6423SLionel Sambuc } while(0)
48433d6423SLionel Sambuc
49433d6423SLionel Sambuc #define SLABDATAUNWRITABLE(data) do { \
50433d6423SLionel Sambuc assert(data->sdh.writable != WRITABLE_NONE); \
51433d6423SLionel Sambuc data->sdh.writable = WRITABLE_NONE; \
52433d6423SLionel Sambuc vm_pagelock(data, 1); \
53433d6423SLionel Sambuc } while(0)
54433d6423SLionel Sambuc
55433d6423SLionel Sambuc #define SLABDATAUSE(data, code) do { \
56433d6423SLionel Sambuc SLABDATAWRITABLE(data, WRITABLE_HEADER); \
57433d6423SLionel Sambuc code \
58433d6423SLionel Sambuc SLABDATAUNWRITABLE(data); \
59433d6423SLionel Sambuc } while(0)
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc #else
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc #define SLABDATAWRITABLE(data, wr)
64433d6423SLionel Sambuc #define SLABDATAUNWRITABLE(data)
65433d6423SLionel Sambuc #define SLABDATAUSE(data, code) do { code } while(0)
66433d6423SLionel Sambuc
67433d6423SLionel Sambuc #endif
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc #define GETBIT(f, b) (BITEL(f,b) & BITPAT(b))
70433d6423SLionel Sambuc #define SETBIT(f, b) {OFF(f,b); SLABDATAUSE(f, BITEL(f,b)|= BITPAT(b); (f)->sdh.nused++;); }
71433d6423SLionel Sambuc #define CLEARBIT(f, b) {ON(f, b); SLABDATAUSE(f, BITEL(f,b)&=~BITPAT(b); (f)->sdh.nused--; (f)->sdh.freeguess = (b);); }
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc #define OBJALIGN 8
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc #define MINSIZE 8
76433d6423SLionel Sambuc #define MAXSIZE (SLABSIZES-1+MINSIZE)
77433d6423SLionel Sambuc #define USEELEMENTS (1+(VM_PAGE_SIZE/MINSIZE/8))
78433d6423SLionel Sambuc
79433d6423SLionel Sambuc static int pages = 0;
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc typedef u8_t element_t;
82433d6423SLionel Sambuc #define BITS_FULL (~(element_t)0)
83433d6423SLionel Sambuc typedef element_t elements_t[USEELEMENTS];
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc /* This file is too low-level to have global SANITYCHECKs everywhere,
86433d6423SLionel Sambuc * as the (other) data structures are often necessarily in an
87433d6423SLionel Sambuc * inconsistent state during a slaballoc() / slabfree(). So only do
88433d6423SLionel Sambuc * our own sanity checks here, with SLABSANITYCHECK.
89433d6423SLionel Sambuc */
90433d6423SLionel Sambuc
91433d6423SLionel Sambuc
92433d6423SLionel Sambuc /* Special writable values. */
93433d6423SLionel Sambuc #define WRITABLE_NONE -2
94433d6423SLionel Sambuc #define WRITABLE_HEADER -1
95433d6423SLionel Sambuc
96433d6423SLionel Sambuc struct sdh {
97433d6423SLionel Sambuc #if SANITYCHECKS
98433d6423SLionel Sambuc u32_t magic1;
99433d6423SLionel Sambuc #endif
100433d6423SLionel Sambuc int freeguess;
101433d6423SLionel Sambuc struct slabdata *next, *prev;
102433d6423SLionel Sambuc elements_t usebits;
103433d6423SLionel Sambuc phys_bytes phys;
104433d6423SLionel Sambuc #if SANITYCHECKS
105433d6423SLionel Sambuc int writable; /* data item number or WRITABLE_* */
106433d6423SLionel Sambuc u32_t magic2;
107433d6423SLionel Sambuc #endif
108433d6423SLionel Sambuc u16_t nused; /* Number of data items used in this slab. */
109433d6423SLionel Sambuc };
110433d6423SLionel Sambuc
111433d6423SLionel Sambuc #define DATABYTES (VM_PAGE_SIZE-sizeof(struct sdh))
112433d6423SLionel Sambuc
113433d6423SLionel Sambuc #define MAGIC1 0x1f5b842f
114433d6423SLionel Sambuc #define MAGIC2 0x8bb5a420
115433d6423SLionel Sambuc #define JUNK 0xdeadbeef
116433d6423SLionel Sambuc #define NOJUNK 0xc0ffee
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc struct slabdata {
119433d6423SLionel Sambuc u8_t data[DATABYTES];
120433d6423SLionel Sambuc struct sdh sdh;
121*50b7f13fSCristiano Giuffrida };
122*50b7f13fSCristiano Giuffrida
123*50b7f13fSCristiano Giuffrida static struct slabheader {
124*50b7f13fSCristiano Giuffrida struct slabdata *list_head;
125433d6423SLionel Sambuc } slabs[SLABSIZES];
126433d6423SLionel Sambuc
127433d6423SLionel Sambuc static int objstats(void *, int, struct slabheader **, struct slabdata
128433d6423SLionel Sambuc **, int *);
129433d6423SLionel Sambuc
130433d6423SLionel Sambuc #define GETSLAB(b, s) { \
131433d6423SLionel Sambuc int _gsi; \
132433d6423SLionel Sambuc assert((b) >= MINSIZE); \
133433d6423SLionel Sambuc _gsi = (b) - MINSIZE; \
134433d6423SLionel Sambuc assert((_gsi) < SLABSIZES); \
135433d6423SLionel Sambuc assert((_gsi) >= 0); \
136433d6423SLionel Sambuc s = &slabs[_gsi]; \
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc
139433d6423SLionel Sambuc /* move slabdata nw to slabheader sl under list number l. */
140433d6423SLionel Sambuc #define ADDHEAD(nw, sl) { \
141433d6423SLionel Sambuc SLABDATAUSE(nw, \
142433d6423SLionel Sambuc (nw)->sdh.next = sl->list_head; \
143433d6423SLionel Sambuc (nw)->sdh.prev = NULL;); \
144433d6423SLionel Sambuc sl->list_head = nw; \
145433d6423SLionel Sambuc if((nw)->sdh.next) { \
146433d6423SLionel Sambuc SLABDATAUSE((nw)->sdh.next, \
147433d6423SLionel Sambuc (nw)->sdh.next->sdh.prev = (nw);); \
148433d6423SLionel Sambuc } \
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc
151433d6423SLionel Sambuc #define UNLINKNODE(node) { \
152433d6423SLionel Sambuc struct slabdata *next, *prev; \
153433d6423SLionel Sambuc prev = (node)->sdh.prev; \
154433d6423SLionel Sambuc next = (node)->sdh.next; \
155433d6423SLionel Sambuc if(prev) { SLABDATAUSE(prev, prev->sdh.next = next;); } \
156433d6423SLionel Sambuc if(next) { SLABDATAUSE(next, next->sdh.prev = prev;); } \
157433d6423SLionel Sambuc }
158433d6423SLionel Sambuc
newslabdata(void)159433d6423SLionel Sambuc static struct slabdata *newslabdata(void)
160433d6423SLionel Sambuc {
161433d6423SLionel Sambuc struct slabdata *n;
162433d6423SLionel Sambuc phys_bytes p;
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc assert(sizeof(*n) == VM_PAGE_SIZE);
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc if(!(n = vm_allocpage(&p, VMP_SLAB))) {
167433d6423SLionel Sambuc printf("newslabdata: vm_allocpage failed\n");
168433d6423SLionel Sambuc return NULL;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc memset(n->sdh.usebits, 0, sizeof(n->sdh.usebits));
171433d6423SLionel Sambuc pages++;
172433d6423SLionel Sambuc
173433d6423SLionel Sambuc n->sdh.phys = p;
174433d6423SLionel Sambuc #if SANITYCHECKS
175433d6423SLionel Sambuc n->sdh.magic1 = MAGIC1;
176433d6423SLionel Sambuc n->sdh.magic2 = MAGIC2;
177433d6423SLionel Sambuc #endif
178433d6423SLionel Sambuc n->sdh.nused = 0;
179433d6423SLionel Sambuc n->sdh.freeguess = 0;
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc #if SANITYCHECKS
182433d6423SLionel Sambuc n->sdh.writable = WRITABLE_HEADER;
183433d6423SLionel Sambuc SLABDATAUNWRITABLE(n);
184433d6423SLionel Sambuc #endif
185433d6423SLionel Sambuc
186433d6423SLionel Sambuc return n;
187433d6423SLionel Sambuc }
188433d6423SLionel Sambuc
189433d6423SLionel Sambuc #if SANITYCHECKS
190433d6423SLionel Sambuc
191433d6423SLionel Sambuc /*===========================================================================*
192433d6423SLionel Sambuc * checklist *
193433d6423SLionel Sambuc *===========================================================================*/
checklist(const char * file,int line,struct slabheader * s,int bytes)194433d6423SLionel Sambuc static int checklist(const char *file, int line,
195433d6423SLionel Sambuc struct slabheader *s, int bytes)
196433d6423SLionel Sambuc {
197433d6423SLionel Sambuc struct slabdata *n = s->list_head;
198433d6423SLionel Sambuc int ch = 0;
199433d6423SLionel Sambuc
200433d6423SLionel Sambuc while(n) {
201433d6423SLionel Sambuc int count = 0, i;
202433d6423SLionel Sambuc #if SANITYCHECKS
203433d6423SLionel Sambuc MYASSERT(n->sdh.magic1 == MAGIC1);
204433d6423SLionel Sambuc MYASSERT(n->sdh.magic2 == MAGIC2);
205433d6423SLionel Sambuc #endif
206433d6423SLionel Sambuc MYASSERT(usedpages_add(n->sdh.phys, VM_PAGE_SIZE) == OK);
207433d6423SLionel Sambuc if(n->sdh.prev)
208433d6423SLionel Sambuc MYASSERT(n->sdh.prev->sdh.next == n);
209433d6423SLionel Sambuc else
210433d6423SLionel Sambuc MYASSERT(s->list_head == n);
211433d6423SLionel Sambuc if(n->sdh.next) MYASSERT(n->sdh.next->sdh.prev == n);
212433d6423SLionel Sambuc for(i = 0; i < USEELEMENTS*8; i++)
213433d6423SLionel Sambuc if(i >= ITEMSPERPAGE(bytes))
214433d6423SLionel Sambuc MYASSERT(!GETBIT(n, i));
215433d6423SLionel Sambuc else
216433d6423SLionel Sambuc if(GETBIT(n,i))
217433d6423SLionel Sambuc count++;
218433d6423SLionel Sambuc MYASSERT(count == n->sdh.nused);
219433d6423SLionel Sambuc ch += count;
220433d6423SLionel Sambuc n = n->sdh.next;
221433d6423SLionel Sambuc }
222433d6423SLionel Sambuc
223433d6423SLionel Sambuc return ch;
224433d6423SLionel Sambuc }
225433d6423SLionel Sambuc
226433d6423SLionel Sambuc /*===========================================================================*
227433d6423SLionel Sambuc * void slab_sanitycheck *
228433d6423SLionel Sambuc *===========================================================================*/
slab_sanitycheck(const char * file,int line)229433d6423SLionel Sambuc void slab_sanitycheck(const char *file, int line)
230433d6423SLionel Sambuc {
231433d6423SLionel Sambuc int s;
232433d6423SLionel Sambuc for(s = 0; s < SLABSIZES; s++) {
233433d6423SLionel Sambuc checklist(file, line, &slabs[s], s + MINSIZE);
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc }
236433d6423SLionel Sambuc
237433d6423SLionel Sambuc /*===========================================================================*
238433d6423SLionel Sambuc * int slabsane *
239433d6423SLionel Sambuc *===========================================================================*/
slabsane_f(const char * file,int line,void * mem,int bytes)240433d6423SLionel Sambuc int slabsane_f(const char *file, int line, void *mem, int bytes)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc struct slabheader *s;
243433d6423SLionel Sambuc struct slabdata *f;
244433d6423SLionel Sambuc int i;
245433d6423SLionel Sambuc
246433d6423SLionel Sambuc bytes = roundup(bytes, OBJALIGN);
247433d6423SLionel Sambuc
248433d6423SLionel Sambuc return (objstats(mem, bytes, &s, &f, &i) == OK);
249433d6423SLionel Sambuc }
250433d6423SLionel Sambuc #endif
251433d6423SLionel Sambuc
252433d6423SLionel Sambuc #if SANITYCHECKS
253433d6423SLionel Sambuc static int nojunkwarning = 0;
254433d6423SLionel Sambuc #endif
255433d6423SLionel Sambuc
256433d6423SLionel Sambuc /*===========================================================================*
257433d6423SLionel Sambuc * void *slaballoc *
258433d6423SLionel Sambuc *===========================================================================*/
slaballoc(int bytes)259433d6423SLionel Sambuc void *slaballoc(int bytes)
260433d6423SLionel Sambuc {
261433d6423SLionel Sambuc int i;
262433d6423SLionel Sambuc int count = 0;
263433d6423SLionel Sambuc struct slabheader *s;
264433d6423SLionel Sambuc struct slabdata *newslab;
265433d6423SLionel Sambuc char *ret;
266433d6423SLionel Sambuc
267433d6423SLionel Sambuc bytes = roundup(bytes, OBJALIGN);
268433d6423SLionel Sambuc
269433d6423SLionel Sambuc SLABSANITYCHECK(SCL_FUNCTIONS);
270433d6423SLionel Sambuc
271433d6423SLionel Sambuc /* Retrieve entry in slabs[]. */
272433d6423SLionel Sambuc GETSLAB(bytes, s);
273433d6423SLionel Sambuc assert(s);
274433d6423SLionel Sambuc
275433d6423SLionel Sambuc if(!(newslab = s->list_head)) {
276433d6423SLionel Sambuc /* Make sure there is something on the freelist. */
277433d6423SLionel Sambuc newslab = newslabdata();
278433d6423SLionel Sambuc if(!newslab) return NULL;
279433d6423SLionel Sambuc ADDHEAD(newslab, s);
280433d6423SLionel Sambuc assert(newslab->sdh.nused == 0);
281433d6423SLionel Sambuc } else assert(newslab->sdh.nused > 0);
282433d6423SLionel Sambuc assert(newslab->sdh.nused < ITEMSPERPAGE(bytes));
283433d6423SLionel Sambuc
284433d6423SLionel Sambuc SLABSANITYCHECK(SCL_DETAIL);
285433d6423SLionel Sambuc
286433d6423SLionel Sambuc #if SANITYCHECKS
287433d6423SLionel Sambuc assert(newslab->sdh.magic1 == MAGIC1);
288433d6423SLionel Sambuc assert(newslab->sdh.magic2 == MAGIC2);
289433d6423SLionel Sambuc #endif
290433d6423SLionel Sambuc
291433d6423SLionel Sambuc for(i = newslab->sdh.freeguess;
292433d6423SLionel Sambuc count < ITEMSPERPAGE(bytes); count++, i++) {
293433d6423SLionel Sambuc i = i % ITEMSPERPAGE(bytes);
294433d6423SLionel Sambuc
295433d6423SLionel Sambuc if(!GETBIT(newslab, i))
296433d6423SLionel Sambuc break;
297433d6423SLionel Sambuc }
298433d6423SLionel Sambuc
299433d6423SLionel Sambuc SLABSANITYCHECK(SCL_FUNCTIONS);
300433d6423SLionel Sambuc
301433d6423SLionel Sambuc assert(count < ITEMSPERPAGE(bytes));
302433d6423SLionel Sambuc assert(i >= 0 && i < ITEMSPERPAGE(bytes));
303433d6423SLionel Sambuc
304433d6423SLionel Sambuc SETBIT(newslab, i);
305433d6423SLionel Sambuc if(newslab->sdh.nused == ITEMSPERPAGE(bytes)) {
306433d6423SLionel Sambuc UNLINKNODE(newslab);
307433d6423SLionel Sambuc s->list_head = newslab->sdh.next;
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc
310433d6423SLionel Sambuc ret = ((char *) newslab) + i*bytes;
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc #if SANITYCHECKS
313433d6423SLionel Sambuc #if MEMPROTECT
314433d6423SLionel Sambuc nojunkwarning++;
315433d6423SLionel Sambuc slabunlock(ret, bytes);
316433d6423SLionel Sambuc nojunkwarning--;
317433d6423SLionel Sambuc assert(!nojunkwarning);
318433d6423SLionel Sambuc #endif
319433d6423SLionel Sambuc *(u32_t *) ret = NOJUNK;
320433d6423SLionel Sambuc #if MEMPROTECT
321433d6423SLionel Sambuc slablock(ret, bytes);
322433d6423SLionel Sambuc #endif
323433d6423SLionel Sambuc #endif
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc SLABDATAUSE(newslab, newslab->sdh.freeguess = i+1;);
326433d6423SLionel Sambuc
327433d6423SLionel Sambuc #if SANITYCHECKS
328433d6423SLionel Sambuc if(bytes >= SLABSIZES+MINSIZE) {
329433d6423SLionel Sambuc printf("slaballoc: odd, bytes %d?\n", bytes);
330433d6423SLionel Sambuc }
331433d6423SLionel Sambuc
332433d6423SLionel Sambuc if(!slabsane_f(__FILE__, __LINE__, ret, bytes))
333433d6423SLionel Sambuc panic("slaballoc: slabsane failed");
334433d6423SLionel Sambuc #endif
335433d6423SLionel Sambuc
336433d6423SLionel Sambuc assert(!((vir_bytes) ret % OBJALIGN));
337433d6423SLionel Sambuc
338433d6423SLionel Sambuc return ret;
339433d6423SLionel Sambuc }
340433d6423SLionel Sambuc
341433d6423SLionel Sambuc /*===========================================================================*
342433d6423SLionel Sambuc * int objstats *
343433d6423SLionel Sambuc *===========================================================================*/
objstats(void * mem,int bytes,struct slabheader ** sp,struct slabdata ** fp,int * ip)344433d6423SLionel Sambuc static inline int objstats(void *mem, int bytes,
345433d6423SLionel Sambuc struct slabheader **sp, struct slabdata **fp, int *ip)
346433d6423SLionel Sambuc {
347433d6423SLionel Sambuc #if SANITYCHECKS
348433d6423SLionel Sambuc #define OBJSTATSCHECK(cond) \
349433d6423SLionel Sambuc if(!(cond)) { \
350433d6423SLionel Sambuc printf("VM: objstats: %s failed for ptr %p, %d bytes\n", \
351433d6423SLionel Sambuc #cond, mem, bytes); \
352433d6423SLionel Sambuc return EINVAL; \
353433d6423SLionel Sambuc }
354433d6423SLionel Sambuc #else
355433d6423SLionel Sambuc #define OBJSTATSCHECK(cond)
356433d6423SLionel Sambuc #endif
357433d6423SLionel Sambuc
358433d6423SLionel Sambuc struct slabheader *s;
359433d6423SLionel Sambuc struct slabdata *f;
360433d6423SLionel Sambuc int i;
361433d6423SLionel Sambuc
362433d6423SLionel Sambuc assert(!(bytes % OBJALIGN));
363433d6423SLionel Sambuc
364433d6423SLionel Sambuc OBJSTATSCHECK((char *) mem >= (char *) VM_PAGE_SIZE);
365433d6423SLionel Sambuc
366433d6423SLionel Sambuc #if SANITYCHECKS
367433d6423SLionel Sambuc if(*(u32_t *) mem == JUNK && !nojunkwarning) {
368433d6423SLionel Sambuc util_stacktrace();
369433d6423SLionel Sambuc printf("VM: WARNING: JUNK seen in slab object, likely freed\n");
370433d6423SLionel Sambuc }
371433d6423SLionel Sambuc #endif
372433d6423SLionel Sambuc /* Retrieve entry in slabs[]. */
373433d6423SLionel Sambuc GETSLAB(bytes, s);
374433d6423SLionel Sambuc
375433d6423SLionel Sambuc /* Round address down to VM_PAGE_SIZE boundary to get header. */
376433d6423SLionel Sambuc f = (struct slabdata *) ((char *) mem - (vir_bytes) mem % VM_PAGE_SIZE);
377433d6423SLionel Sambuc
378433d6423SLionel Sambuc #if SANITYCHECKS
379433d6423SLionel Sambuc OBJSTATSCHECK(f->sdh.magic1 == MAGIC1);
380433d6423SLionel Sambuc OBJSTATSCHECK(f->sdh.magic2 == MAGIC2);
381433d6423SLionel Sambuc #endif
382433d6423SLionel Sambuc
383433d6423SLionel Sambuc /* Make sure it's in range. */
384433d6423SLionel Sambuc OBJSTATSCHECK((char *) mem >= (char *) f->data);
385433d6423SLionel Sambuc OBJSTATSCHECK((char *) mem < (char *) f->data + sizeof(f->data));
386433d6423SLionel Sambuc
387433d6423SLionel Sambuc /* Get position. */
388433d6423SLionel Sambuc i = (char *) mem - (char *) f->data;
389433d6423SLionel Sambuc OBJSTATSCHECK(!(i % bytes));
390433d6423SLionel Sambuc i = i / bytes;
391433d6423SLionel Sambuc
392433d6423SLionel Sambuc /* Make sure it is marked as allocated. */
393433d6423SLionel Sambuc OBJSTATSCHECK(GETBIT(f, i));
394433d6423SLionel Sambuc
395433d6423SLionel Sambuc /* return values */
396433d6423SLionel Sambuc *ip = i;
397433d6423SLionel Sambuc *fp = f;
398433d6423SLionel Sambuc *sp = s;
399433d6423SLionel Sambuc
400433d6423SLionel Sambuc return OK;
401433d6423SLionel Sambuc }
402433d6423SLionel Sambuc
403433d6423SLionel Sambuc /*===========================================================================*
404433d6423SLionel Sambuc * void *slabfree *
405433d6423SLionel Sambuc *===========================================================================*/
slabfree(void * mem,int bytes)406433d6423SLionel Sambuc void slabfree(void *mem, int bytes)
407433d6423SLionel Sambuc {
408433d6423SLionel Sambuc int i;
409433d6423SLionel Sambuc struct slabheader *s;
410433d6423SLionel Sambuc struct slabdata *f;
411433d6423SLionel Sambuc
412433d6423SLionel Sambuc bytes = roundup(bytes, OBJALIGN);
413433d6423SLionel Sambuc
414433d6423SLionel Sambuc SLABSANITYCHECK(SCL_FUNCTIONS);
415433d6423SLionel Sambuc
416433d6423SLionel Sambuc if(objstats(mem, bytes, &s, &f, &i) != OK) {
417433d6423SLionel Sambuc panic("slabfree objstats failed");
418433d6423SLionel Sambuc }
419433d6423SLionel Sambuc
420433d6423SLionel Sambuc #if SANITYCHECKS
421433d6423SLionel Sambuc if(*(u32_t *) mem == JUNK) {
422433d6423SLionel Sambuc printf("VM: WARNING: likely double free, JUNK seen\n");
423433d6423SLionel Sambuc }
424433d6423SLionel Sambuc #endif
425433d6423SLionel Sambuc
426433d6423SLionel Sambuc #if SANITYCHECKS
427433d6423SLionel Sambuc #if MEMPROTECT
428433d6423SLionel Sambuc slabunlock(mem, bytes);
429433d6423SLionel Sambuc #endif
430433d6423SLionel Sambuc #if JUNKFREE
431433d6423SLionel Sambuc memset(mem, 0xa6, bytes);
432433d6423SLionel Sambuc #endif
433433d6423SLionel Sambuc *(u32_t *) mem = JUNK;
434433d6423SLionel Sambuc nojunkwarning++;
435433d6423SLionel Sambuc #if MEMPROTECT
436433d6423SLionel Sambuc slablock(mem, bytes);
437433d6423SLionel Sambuc #endif
438433d6423SLionel Sambuc nojunkwarning--;
439433d6423SLionel Sambuc assert(!nojunkwarning);
440433d6423SLionel Sambuc #endif
441433d6423SLionel Sambuc
442433d6423SLionel Sambuc /* Free this data. */
443433d6423SLionel Sambuc CLEARBIT(f, i);
444433d6423SLionel Sambuc
445433d6423SLionel Sambuc /* Check if this slab changes lists. */
446433d6423SLionel Sambuc if(f->sdh.nused == 0) {
447433d6423SLionel Sambuc UNLINKNODE(f);
448433d6423SLionel Sambuc if(f == s->list_head) s->list_head = f->sdh.next;
449433d6423SLionel Sambuc vm_freepages((vir_bytes) f, 1);
450433d6423SLionel Sambuc SLABSANITYCHECK(SCL_DETAIL);
451433d6423SLionel Sambuc } else if(f->sdh.nused == ITEMSPERPAGE(bytes)-1) {
452433d6423SLionel Sambuc ADDHEAD(f, s);
453433d6423SLionel Sambuc }
454433d6423SLionel Sambuc
455433d6423SLionel Sambuc SLABSANITYCHECK(SCL_FUNCTIONS);
456433d6423SLionel Sambuc
457433d6423SLionel Sambuc return;
458433d6423SLionel Sambuc }
459433d6423SLionel Sambuc
460433d6423SLionel Sambuc #if MEMPROTECT
461433d6423SLionel Sambuc /*===========================================================================*
462433d6423SLionel Sambuc * void *slablock *
463433d6423SLionel Sambuc *===========================================================================*/
slablock(void * mem,int bytes)464433d6423SLionel Sambuc void slablock(void *mem, int bytes)
465433d6423SLionel Sambuc {
466433d6423SLionel Sambuc int i;
467433d6423SLionel Sambuc struct slabheader *s;
468433d6423SLionel Sambuc struct slabdata *f;
469433d6423SLionel Sambuc
470433d6423SLionel Sambuc bytes = roundup(bytes, OBJALIGN);
471433d6423SLionel Sambuc
472433d6423SLionel Sambuc if(objstats(mem, bytes, &s, &f, &i) != OK)
473433d6423SLionel Sambuc panic("slablock objstats failed");
474433d6423SLionel Sambuc
475433d6423SLionel Sambuc SLABDATAUNWRITABLE(f);
476433d6423SLionel Sambuc
477433d6423SLionel Sambuc return;
478433d6423SLionel Sambuc }
479433d6423SLionel Sambuc
480433d6423SLionel Sambuc /*===========================================================================*
481433d6423SLionel Sambuc * void *slabunlock *
482433d6423SLionel Sambuc *===========================================================================*/
slabunlock(void * mem,int bytes)483433d6423SLionel Sambuc void slabunlock(void *mem, int bytes)
484433d6423SLionel Sambuc {
485433d6423SLionel Sambuc int i;
486433d6423SLionel Sambuc struct slabheader *s;
487433d6423SLionel Sambuc struct slabdata *f;
488433d6423SLionel Sambuc
489433d6423SLionel Sambuc bytes = roundup(bytes, OBJALIGN);
490433d6423SLionel Sambuc
491433d6423SLionel Sambuc if(objstats(mem, bytes, &s, &f, &i) != OK)
492433d6423SLionel Sambuc panic("slabunlock objstats failed");
493433d6423SLionel Sambuc
494433d6423SLionel Sambuc SLABDATAWRITABLE(f, i);
495433d6423SLionel Sambuc
496433d6423SLionel Sambuc return;
497433d6423SLionel Sambuc }
498433d6423SLionel Sambuc #endif
499433d6423SLionel Sambuc
500433d6423SLionel Sambuc #if SANITYCHECKS
501433d6423SLionel Sambuc /*===========================================================================*
502433d6423SLionel Sambuc * void slabstats *
503433d6423SLionel Sambuc *===========================================================================*/
slabstats(void)504433d6423SLionel Sambuc void slabstats(void)
505433d6423SLionel Sambuc {
506433d6423SLionel Sambuc int s, totalbytes = 0;
507433d6423SLionel Sambuc static int n;
508433d6423SLionel Sambuc n++;
509433d6423SLionel Sambuc if(n%1000) return;
510433d6423SLionel Sambuc for(s = 0; s < SLABSIZES; s++) {
511433d6423SLionel Sambuc int b, t;
512433d6423SLionel Sambuc b = s + MINSIZE;
513433d6423SLionel Sambuc t = checklist(__FILE__, __LINE__, &slabs[s], b);
514433d6423SLionel Sambuc
515433d6423SLionel Sambuc if(t > 0) {
516433d6423SLionel Sambuc int bytes = t * b;
517433d6423SLionel Sambuc printf("VMSTATS: %2d slabs: %d (%dkB)\n", b, t, bytes/1024);
518433d6423SLionel Sambuc totalbytes += bytes;
519433d6423SLionel Sambuc }
520433d6423SLionel Sambuc }
521433d6423SLionel Sambuc
522433d6423SLionel Sambuc if(pages > 0) {
523433d6423SLionel Sambuc printf("VMSTATS: %dK net used in slab objects in %d pages (%dkB): %d%% utilization\n",
524433d6423SLionel Sambuc totalbytes/1024, pages, pages*VM_PAGE_SIZE/1024,
525433d6423SLionel Sambuc 100 * totalbytes / (pages*VM_PAGE_SIZE));
526433d6423SLionel Sambuc }
527433d6423SLionel Sambuc }
528433d6423SLionel Sambuc #endif
529