New version 0.6.6: app edit was improved; app nc was improved + code cleanup; app...
[ZeXOS.git] / kernel / core / mm / usermem.c
blob9b34f3b12e22640ee3df2b0b5e89cc0a0fe21d5f
1 /*
2 * ZeX/OS
3 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <system.h>
21 #include <string.h>
22 #include <build.h>
23 #include <config.h>
24 #include <mutex.h>
25 #include <errno.h>
28 #define UMEM_HEAP_ADDR 0x800000 // MEMORY HEAP is placed at 8MB address
29 #define UMEM_MALLOC_MAGIC 0xebc9 // MALLOC STRUCTURE signature
31 #define UMEM_MALLOC_STATE_FREE 0xaa // MEMORY is FREE at moment
32 #define UMEM_MALLOC_STATE_USED 0xcc // MEMORY is USED at moment
35 typedef struct {
36 unsigned short magic;
37 unsigned char state;
38 void *next;
39 proc_t *proc;
40 } __attribute__ ((__packed__)) malloc_t;
42 typedef struct {
43 void *addr; /* heap structure is covered by own heap structure address */
44 void *first; /* first malloc structure */
45 void *last; /* last malloc structure - usefully for calculate memory usage */
46 void *curr; /* current malloc structure */
47 } __attribute__ ((__packed__)) heap_t;
50 static heap_t *heap; /* heap structure of memory */
51 static MUTEX_CREATE (mutex_umalloc);
52 static MUTEX_CREATE (mutex_ufree);
55 void *umalloc (proc_t *proc, size_t size)
57 if (!size)
58 return 0;
60 mutex_lock (&mutex_umalloc);
62 unsigned malloc_len = sizeof (malloc_t); /* check malloc structure size */
63 unsigned need_alloc = 0;
65 /* let's find new or free malloc structure in memory */
66 malloc_t *malloc = (malloc_t *) heap->first;
68 while (1) {
69 //DPRINT ("malloc: 0x%x\n", malloc);
71 if (!malloc) {
72 DPRINT ("!malloc");
73 need_alloc = 1;
74 break;
77 if (malloc->magic != UMEM_MALLOC_MAGIC) {
78 DPRINT ("malloc->magic != UMEM_MALLOC_MAGIC");
79 need_alloc = 1;
80 break;
83 if (malloc->state == UMEM_MALLOC_STATE_USED) { /* It's OK */
84 DPRINT ("malloc->state == UMEM_MALLOC_STATE_USED");
85 //need_alloc = 1;
86 malloc = (malloc_t *) malloc->next;
87 continue;
90 /* we've found FREE memory block, at moment it is not used */
91 if (malloc->state == UMEM_MALLOC_STATE_FREE) {
92 /* read next malloc structure, right behind free block */
93 malloc_t *next = (malloc_t *) malloc;
95 DPRINT ("malloc->state == UMEM_MALLOC_STATE_FREE");
97 while (1) {
98 next = (malloc_t *) next->next;
100 if (next->magic != UMEM_MALLOC_MAGIC) {
101 DPRINT ("2: next->magic != UMEM_MALLOC_MAGIC");
102 break;
105 if ((unsigned) ((void *) malloc + malloc_len + size) <= (unsigned) next) {
106 //kprintf ("Je mensi\n");
107 break;
108 } else {
109 if (next->state == UMEM_MALLOC_STATE_USED)
110 need_alloc = 1;
112 if (next->state == UMEM_MALLOC_STATE_USED)
113 break;
115 if (next->state != UMEM_MALLOC_STATE_FREE)
116 break;
119 /*if (need_alloc)
120 break;
122 unsigned diff = (unsigned) ((void *) next - (void *) malloc);
124 DPRINT ("diff: %d", diff);
126 if (diff < size) {
127 malloc = (malloc_t *) malloc->next;
128 continue;
131 break;
134 malloc = (malloc_t *) malloc->next;
137 if (need_alloc) {
138 /* when old malloc structures are full, let's grab new block of memory */
139 malloc = heap->curr;
141 malloc->magic = UMEM_MALLOC_MAGIC;
143 malloc->next = (void *) ((void *) malloc + malloc_len + size);
145 heap->curr = malloc->next;
148 malloc->state = UMEM_MALLOC_STATE_USED;
150 malloc->proc = proc;
152 /* calculate size of process image (binary file) */
153 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
155 /* save last malloc structure pointer to heap */
156 if ((unsigned) heap->curr > (unsigned) heap->last)
157 heap->last = heap->curr;
159 unsigned l;
160 unsigned s = proc->heap;
161 for (l = s; l < (unsigned) ((char *) malloc + malloc_len + size); l += 0x1000) {
162 page_mmap (proc->task->page_cover, (void *) proc->heap+p, (void *) proc->heap+p + 0x1000, 0, 1);
163 //kprintf ("OD: 0x%x DO: 0x%x | 0x%x | 0x%x\n", (void *) proc->heap + p, (void *) proc->heap + 0x1000 + p, s, size);
164 proc->heap += 0x1000;
167 mutex_unlock (&mutex_umalloc);
169 return (void *) ((void *) malloc + malloc_len + p);
172 void ufree (proc_t *proc, void *ptr)
174 if (!ptr || !proc)
175 return;
177 mutex_lock (&mutex_ufree);
179 /* calculate size of process image (binary file) */
180 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
182 /* we need find malloc structure - it could be risk working with lower memory address */
183 malloc_t *malloc = (void *) ((void *) ptr - sizeof (malloc_t) - p);
185 /* check malloc signature, when not agree, ptr pointing to wrong memory address */
186 if (malloc->magic != UMEM_MALLOC_MAGIC) {
187 kprintf ("free: malloc->magic != UMEM_MALLOC_MAGIC\n");
188 goto end;
191 /* is this memory block our ? */
192 if (malloc->proc != proc) {
193 kprintf ("free: malloc->proc != proc\n");
194 goto end;
197 if (malloc->state == UMEM_MALLOC_STATE_FREE) {
198 kprintf ("kfree () - memory is FREE - double free !\n");
199 goto end;
202 if (malloc->state != UMEM_MALLOC_STATE_USED) {
203 kprintf ("malloc->state != UMEM_MALLOC_STATE_USED\n");
204 goto end;
207 /* match malloc as FREE */
208 malloc->state = UMEM_MALLOC_STATE_FREE;
210 end:
211 mutex_unlock (&mutex_ufree);
214 void *urealloc (proc_t *proc, void *ptr, size_t size)
216 if (!ptr || !proc)
217 return 0;
219 /* calculate size of process image (binary file) */
220 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
222 /* we need find malloc structure - it could be risk working with lower memory address */
223 malloc_t *malloc = (void *) ((char *) ptr - sizeof (malloc_t) - p);
225 /* check malloc signature, when not agree, ptr pointing to wrong memory address */
226 if (malloc->magic != UMEM_MALLOC_MAGIC) {
227 kprintf ("urealloc: malloc->magic != UMEM_MALLOC_MAGIC\n");
228 return 0;
231 int s = (int) (malloc->next - ptr) + p;
232 printf ("s: %d size: %d\n", s, size);
233 if (s >= size) {
234 ufree (proc, ptr);
235 return 0;
237 printf ("err\n");
238 char *ptr_new = umalloc (proc, size);
240 if (!ptr_new) {
241 ufree (proc, ptr);
242 errno_set (ENOMEM);
243 return 0;
246 /* copy old memory block to new one (-p because ptr and ptr_new got virtual mapped address) */
247 memcpy (ptr_new - p, ptr - p, s);
249 ufree (proc, ptr);
251 return ptr_new;
254 /* free all memory blocks allocated by process */
255 unsigned ufree_proc (proc_t *proc)
257 #ifndef ARCH_arm
258 paging_disable ();
259 #endif
260 unsigned used = 0;
261 malloc_t *malloc;
263 for (malloc = (malloc_t *) heap->first; malloc->magic == UMEM_MALLOC_MAGIC; malloc = (malloc_t *) malloc->next)
264 if (malloc->proc == proc)
265 if (malloc->state == UMEM_MALLOC_STATE_USED)
266 malloc->state = UMEM_MALLOC_STATE_FREE;
267 #ifndef ARCH_arm
268 paging_enable ();
269 #endif
270 return used;
273 /* calculate used memory by process */
274 unsigned umem_used_proc (proc_t *proc)
276 #ifndef ARCH_arm
277 paging_disable ();
278 #endif
279 unsigned used = 0;
280 malloc_t *malloc;
282 for (malloc = (malloc_t *) heap->first; malloc->magic == UMEM_MALLOC_MAGIC; malloc = (malloc_t *) malloc->next)
283 if (malloc->proc == proc)
284 if (malloc->state == UMEM_MALLOC_STATE_USED)
285 used += (int) ((unsigned) malloc->next - (unsigned) malloc);
286 #ifndef ARCH_arm
287 paging_enable ();
288 #endif
289 return used;
292 /* calculate used memory from all apps */
293 unsigned umem_used ()
295 #ifndef ARCH_arm
296 paging_disable ();
297 #endif
298 unsigned used = 0;
299 malloc_t *malloc;
301 for (malloc = (malloc_t *) heap->first; malloc->magic == UMEM_MALLOC_MAGIC; malloc = (malloc_t *) malloc->next)
302 if (malloc->state == UMEM_MALLOC_STATE_USED)
303 used += (int) ((unsigned) malloc->next - (unsigned) malloc);
304 #ifndef ARCH_arm
305 paging_enable ();
306 #endif
307 return used;
310 unsigned umem_init ()
312 heap = (heap_t *) UMEM_HEAP_ADDR;
314 /* we rather clear heap structure */
315 heap->addr = (void *) heap;
316 heap->first = (void *) ((void *) heap + sizeof (heap_t)); /* first malloc structure should be right behind heap structure */
317 heap->last = heap->first; /* last malloc structure - it is first at init */
318 heap->curr = heap->first; /* point to first malloc structure - well, it is clear and not used yet */
320 return 1;