Fixed possible memory corruption in commands exec and netexec; fixed command netcp...
[ZeXOS.git] / kernel / core / mm / usermem.c
blob988dda2fb199df824bc0505c1293a55697ef9cbe
1 /*
2 * ZeX/OS
3 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <system.h>
22 #include <string.h>
23 #include <build.h>
24 #include <config.h>
25 #include <mutex.h>
26 #include <errno.h>
27 #include <signal.h>
29 #define UMEM_HEAP_ADDR 0x800000 // MEMORY HEAP is placed at 8MB address
30 #define UMEM_MALLOC_MAGIC 0xebc9 // MALLOC STRUCTURE signature
32 #define UMEM_MALLOC_STATE_FREE 0xaa // MEMORY is FREE at moment
33 #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;
49 static heap_t *heap; /* heap structure of memory */
50 static MUTEX_CREATE (mutex_umalloc);
51 static MUTEX_CREATE (mutex_ufree);
53 void *umalloc (proc_t *proc, size_t size)
55 if (!size)
56 return 0;
58 mutex_lock (&mutex_umalloc);
60 unsigned malloc_len = sizeof (malloc_t); /* check malloc structure size */
61 unsigned need_alloc = 0;
63 /* let's find new or free malloc structure in memory */
64 malloc_t *malloc = (malloc_t *) heap->first;
66 for (;;) {
67 //DPRINT (DBG_MM | DBG_UMEM, "malloc: 0x%x\n", malloc);
69 if (!malloc) {
70 DPRINT (DBG_MM | DBG_UMEM, "!malloc");
71 need_alloc = 1;
72 break;
75 if (malloc->magic != UMEM_MALLOC_MAGIC) {
76 DPRINT (DBG_MM | DBG_UMEM, "malloc->magic != UMEM_MALLOC_MAGIC");
77 need_alloc = 1;
78 break;
81 if (malloc->state == UMEM_MALLOC_STATE_USED) { /* It's OK */
82 DPRINT (DBG_MM | DBG_UMEM, "malloc->state == UMEM_MALLOC_STATE_USED");
83 //need_alloc = 1;
84 malloc = (malloc_t *) malloc->next;
85 continue;
88 /* we've found FREE memory block, at moment it is not used */
89 if (malloc->state == UMEM_MALLOC_STATE_FREE) {
90 /* read next malloc structure, right behind free block */
91 malloc_t *next = (malloc_t *) malloc;
93 DPRINT (DBG_MM | DBG_UMEM, "malloc->state == UMEM_MALLOC_STATE_FREE");
95 for (;;) {
96 if (next->magic != UMEM_MALLOC_MAGIC) {
97 DPRINT (DBG_MM | DBG_UMEM, "2: next->magic != UMEM_MALLOC_MAGIC (%x/%x)", next->magic, UMEM_MALLOC_MAGIC);
98 break;
101 /* unused memory size between current and next block */
102 long diff = ((unsigned) (next->next) - (unsigned) (malloc));
104 /* does needed block fit in unused one ? */
105 if (diff >= (unsigned) size + malloc_len) {
106 need_alloc = 2;
108 /* we have to join all continuous free blocks into one and match last (next) */
109 if (next != malloc)
110 malloc->next = (malloc_t *) ((void *) malloc + size + malloc_len);
112 if (diff > size + malloc_len) {
114 unsigned mnext = (unsigned) next->next;
116 malloc_t *n = (malloc_t *) ((void *) malloc + size + malloc_len);
118 n->magic = UMEM_MALLOC_MAGIC;
119 n->state = UMEM_MALLOC_STATE_FREE;
120 n->next = (void *) mnext;
122 next->next = n;
124 //malloc = (char *) next;
126 //heap->curr = mnext;
127 //kprintf ("DIFF: %d - 0x%x / 0x%x\n", diff - malloc_len, mnext, n);
129 break;
130 } else {
131 if (next->state == UMEM_MALLOC_STATE_USED)
132 need_alloc = 1;
134 if (next->state == UMEM_MALLOC_STATE_USED)
135 break;
137 if (next->state != UMEM_MALLOC_STATE_FREE)
138 break;
140 next = (malloc_t *) next->next;
143 /*if (need_alloc)
144 break;
146 unsigned diff = (unsigned) ((void *) next - (void *) malloc);
148 DPRINT (DBG_MM | DBG_UMEM, "diff: %d", diff);
150 if (diff < size) {
151 malloc = (malloc_t *) malloc->next;
152 continue;
155 break;
158 if (need_alloc)
159 break;
161 malloc = (malloc_t *) malloc->next;
164 if (need_alloc == 1) {
165 /* when old malloc structures are full, let's grab new block of memory */
166 malloc = heap->curr;
168 malloc->magic = UMEM_MALLOC_MAGIC;
170 malloc->next = (void *) ((void *) malloc + malloc_len + size);
172 heap->curr = malloc->next;
175 malloc->state = UMEM_MALLOC_STATE_USED;
177 malloc->proc = proc;
179 /* calculate size of process image (binary file) */
180 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
182 /* save last malloc structure pointer to heap */
183 if ((unsigned) heap->curr > (unsigned) heap->last)
184 heap->last = heap->curr;
186 unsigned l;
187 unsigned s = proc->heap;
188 for (l = s; l < (unsigned) ((char *) malloc + malloc_len + size); l += 0x1000) {
189 #ifdef ARCH_i386
190 page_mmap (proc->task->page_cover, (void *) proc->heap+p, (void *) proc->heap+p + 0x1000, 0, 1);
191 #endif
192 //kprintf ("OD: 0x%x DO: 0x%x | 0x%x | 0x%x\n", (void *) proc->heap + p, (void *) proc->heap + 0x1000 + p, s, size);
193 proc->heap += 0x1000;
196 mutex_unlock (&mutex_umalloc);
197 //kprintf ("MEM: 0x%x - %d - 0x%x\n", ((void *) malloc + malloc_len + p), size, p);
198 return (void *) ((void *) malloc + malloc_len + p);
201 void ufree (proc_t *proc, void *ptr)
203 if (!ptr || !proc)
204 return;
206 mutex_lock (&mutex_ufree);
208 /* calculate size of process image (binary file) */
209 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
211 /* we need find malloc structure - it could be risk working with lower memory address */
212 malloc_t *malloc = (void *) ((void *) ptr - sizeof (malloc_t) - p);
214 /* check malloc signature, when not agree, ptr pointing to wrong memory address */
215 if (malloc->magic != UMEM_MALLOC_MAGIC) {
216 DPRINT (DBG_MM | DBG_UMEM, "free: malloc->magic != UMEM_MALLOC_MAGIC");
217 goto end;
220 /* is this memory block our ? */
221 if (malloc->proc != proc) {
222 DPRINT (DBG_MM | DBG_UMEM, "free: malloc->proc != proc");
223 goto end;
226 if (malloc->state == UMEM_MALLOC_STATE_FREE) {
227 DPRINT (DBG_MM | DBG_UMEM, "free () - memory is FREE - double free !");
228 goto end;
231 if (malloc->state != UMEM_MALLOC_STATE_USED) {
232 DPRINT (DBG_MM | DBG_UMEM, "malloc->state != UMEM_MALLOC_STATE_USED");
233 goto end;
236 /* match malloc as FREE */
237 malloc->state = UMEM_MALLOC_STATE_FREE;
239 end:
240 mutex_unlock (&mutex_ufree);
243 void *urealloc (proc_t *proc, void *ptr, size_t size)
245 if (!proc)
246 return 0;
248 if (!ptr)
249 return umalloc (proc, size);
251 if (!size) {
252 ufree (proc, ptr);
253 return 0;
256 /* calculate size of process image (binary file) */
257 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
259 /* we need find malloc structure - it could be risk working with lower memory address */
260 malloc_t *malloc = (void *) ((char *) ptr - sizeof (malloc_t) - p);
262 /* check malloc signature, when not agree, ptr pointing to wrong memory address */
263 if (malloc->magic != UMEM_MALLOC_MAGIC) {
264 DPRINT (DBG_MM | DBG_UMEM, "urealloc: malloc->magic != UMEM_MALLOC_MAGIC");
265 return 0;
268 int s = (int) (malloc->next - ptr) + p;
270 if (s >= size)
271 return 0;
273 char *ptr_new = umalloc (proc, size);
275 if (!ptr_new) {
276 ufree (proc, ptr);
277 errno_set (ENOMEM);
278 return 0;
281 /* copy old memory block to new one (-p because ptr and ptr_new got virtual mapped address) */
282 memcpy (ptr_new - p, ptr - p, s);
284 ufree (proc, ptr);
286 return ptr_new;
289 /* free all memory blocks allocated by process */
290 unsigned ufree_proc (proc_t *proc)
292 #ifndef ARCH_arm
293 paging_disable ();
294 #endif
295 unsigned used = 0;
296 malloc_t *malloc;
298 for (malloc = (malloc_t *) heap->first; malloc->magic == UMEM_MALLOC_MAGIC; malloc = (malloc_t *) malloc->next)
299 if (malloc->proc == proc)
300 if (malloc->state == UMEM_MALLOC_STATE_USED)
301 malloc->state = UMEM_MALLOC_STATE_FREE;
302 #ifndef ARCH_arm
303 paging_enable ();
304 #endif
305 return used;
308 /* calculate used memory by process */
309 unsigned umem_used_proc (proc_t *proc)
311 #ifndef ARCH_arm
312 paging_disable ();
313 #endif
314 unsigned used = 0;
315 malloc_t *malloc;
317 for (malloc = (malloc_t *) heap->first; malloc->magic == UMEM_MALLOC_MAGIC; malloc = (malloc_t *) malloc->next)
318 if (malloc->proc == proc)
319 if (malloc->state == UMEM_MALLOC_STATE_USED)
320 used += (int) ((unsigned) malloc->next - (unsigned) malloc);
321 #ifndef ARCH_arm
322 paging_enable ();
323 #endif
324 return used;
327 /* calculate used memory from all apps */
328 unsigned umem_used ()
330 #ifndef ARCH_arm
331 paging_disable ();
332 #endif
333 unsigned used = 0;
334 malloc_t *malloc;
336 for (malloc = (malloc_t *) heap->first; malloc->magic == UMEM_MALLOC_MAGIC; malloc = (malloc_t *) malloc->next)
337 if (malloc->state == UMEM_MALLOC_STATE_USED)
338 used += (int) ((unsigned) malloc->next - (unsigned) malloc);
339 #ifndef ARCH_arm
340 paging_enable ();
341 #endif
342 return used;
345 unsigned umem_init ()
347 heap = (heap_t *) UMEM_HEAP_ADDR;
349 /* we rather clear heap structure */
350 heap->addr = (void *) heap;
351 heap->first = (void *) ((void *) heap + sizeof (heap_t)); /* first malloc structure should be right behind heap structure */
352 heap->last = heap->first; /* last malloc structure - it is first at init */
353 heap->curr = heap->first; /* point to first malloc structure - well, it is clear and not used yet */
355 return 1;