1 /*
2 * Copyright (c) 2013-2023 Ali Mashtizadeh
3 * All rights reserved.
4 */
5
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <string.h>
9
10 #include <sys/cdefs.h>
11 #include <sys/kassert.h>
12 #include <sys/kdebug.h>
13 #include <sys/queue.h>
14 #include <sys/kmem.h>
15
16 #include <machine/pmap.h>
17
18 LIST_HEAD(SlabListHead, Slab) slabList = LIST_HEAD_INITIALIZER(slabList);
19
20 /**
21 * Slab_Init --
22 *
23 * Create's a slab for a single type of object in the kernel.
24 *
25 * @param [in] slab Slab that the object belongs to.
26 * @param [in] name Developer friendly name for debugging purposes.
27 * @param [in] objsz Size of the object in bytes.
28 * @param [in] align Alignment of the object in bytes.
29 */
30 void
Slab_Init(Slab * slab,const char * name,uintptr_t objsz,uintptr_t align)31 Slab_Init(Slab *slab, const char *name, uintptr_t objsz, uintptr_t align)
32 {
33 ASSERT(objsz >= sizeof(SlabElement));
34
35 slab->objsz = objsz;
36 slab->align = align;
37 slab->xmem = XMem_New();
38 slab->objs = 0;
39 slab->freeObjs = 0;
40 slab->allocs = 0;
41 slab->frees = 0;
42 LIST_INIT(&slab->freeList);
43
44 ASSERT(slab->xmem != NULL);
45
46 strncpy(&slab->name[0], name, SLAB_NAMELEN);
47
48 Spinlock_Init(&slab->lock, name, SPINLOCK_TYPE_NORMAL);
49
50 LIST_INSERT_HEAD(&slabList, slab, slabList);
51 }
52
53 /**
54 * SlabExtend --
55 *
56 * Grow the slab to allocate new objects.
57 *
58 * @param [in] slab Slab that we want to expand.
59 * @retval -1 Failed to expand the slab.
60 * @retval 0 Success.
61 */
62 int
SlabExtend(Slab * slab)63 SlabExtend(Slab *slab)
64 {
65 uintptr_t base = XMem_GetBase(slab->xmem);
66 uintptr_t len = XMem_GetLength(slab->xmem);
67 uintptr_t inc;
68 uintptr_t realObjSz = ROUNDUP(slab->objsz, slab->align);
69
70 inc = ROUNDUP(realObjSz * 64, PGSIZE);
71 if (inc < 4 * PGSIZE) {
72 inc = 4 * PGSIZE;
73 }
74
75 if (!XMem_Allocate(slab->xmem, len + inc)) {
76 kprintf("Slab: Cannot grow XMem region!\n");
77 return -1;
78 }
79
80 // Add empty objects to linked list
81 uintptr_t i;
82 uintptr_t objs = inc / realObjSz;
83 for (i = 0; i < objs; i++) {
84 SlabElement *elem = (SlabElement *)(base + len + i * realObjSz);
85
86 LIST_INSERT_HEAD(&slab->freeList, elem, free);
87 }
88
89 slab->objs += objs;
90 slab->freeObjs += objs;
91
92 return 0;
93 }
94
95 /**
96 * Slab_Alloc --
97 *
98 * Free a slab object.
99 *
100 * @param [in] slab Slab that the object belongs to.
101 * @retval NULL Could not allocate an object.
102 * @return Pointer to the allocated object.
103 */
104 void *
Slab_Alloc(Slab * slab)105 Slab_Alloc(Slab *slab)
106 {
107 SlabElement *elem;
108
109 Spinlock_Lock(&slab->lock);
110
111 if (slab->freeObjs == 0)
112 SlabExtend(slab);
113
114 elem = LIST_FIRST(&slab->freeList);
115 if (elem != NULL) {
116 LIST_REMOVE(elem, free);
117 slab->allocs++;
118 slab->freeObjs--;
119 }
120
121 Spinlock_Unlock(&slab->lock);
122
123 return (void *)elem;
124 }
125
126 /**
127 * Slab_Free --
128 *
129 * Free a slab object.
130 *
131 * @param [in] slab Slab that the object belongs to.
132 * @param [in] region Object to free.
133 */
134 void
Slab_Free(Slab * slab,void * region)135 Slab_Free(Slab *slab, void *region)
136 {
137 Spinlock_Lock(&slab->lock);
138
139 SlabElement *elem = (SlabElement *)region;
140 LIST_INSERT_HEAD(&slab->freeList, elem, free);
141 slab->frees++;
142 slab->freeObjs++;
143
144 Spinlock_Unlock(&slab->lock);
145 }
146
147 static void
Debug_Slabs(int argc,const char * argv[])148 Debug_Slabs(int argc, const char *argv[])
149 {
150 Slab *slab;
151
152 kprintf("%-36s %-10s %-10s %-10s\n", "Slab Name", "Alloc", "Free", "Total");
153 LIST_FOREACH(slab, &slabList, slabList) {
154 kprintf("%-36s %-10lld %-10lld %-10lld\n", slab->name,
155 slab->objs - slab->freeObjs, slab->freeObjs, slab->objs);
156 }
157 }
158
159 REGISTER_DBGCMD(slabs, "Display list of slabs", Debug_Slabs);
160
161