Merge from ASPLOS tree.
[barrelfish] / lib / barrelfish / morecore.c
1 /**
2  * \file
3  * \brief Morecore implementation for malloc
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/core_state.h>
17 #include <barrelfish/morecore.h>
18 #include <stdio.h>
19
20 /// Amount of virtual space for malloc
21 #ifdef __x86_64__
22 #       define HEAP_REGION (2UL * 1024 * 1024 * 1024) /* 2GB */
23 #elif defined(__i386__) || defined(__arm__) || defined(__BEEHIVE__)
24 #       define HEAP_REGION (512UL * 1024 * 1024) /* 512MB */
25 #else
26 #       error "HEAP_REGION needs to be defined for this system."
27 #endif
28
29 typedef void *(*morecore_alloc_func_t)(size_t bytes, size_t *retbytes);
30 extern morecore_alloc_func_t sys_morecore_alloc;
31
32 typedef void (*morecore_free_func_t)(void *base, size_t bytes);
33 extern morecore_free_func_t sys_morecore_free;
34
35 /**
36  * \brief Allocate some memory for malloc to use
37  *
38  * This function will keep trying with smaller and smaller frames till
39  * it finds a set of frames that satisfy the requirement. retbytes can
40  * be smaller than bytes if we were able to allocate a smaller memory
41  * region than requested for.
42  */
43 static void *morecore_alloc(size_t bytes, size_t *retbytes)
44 {
45     errval_t err;
46     struct morecore_state *state = get_morecore_state();
47
48     void *buf = NULL;
49     size_t mapped = 0;
50     size_t step = bytes;
51     while (mapped < bytes) {
52         struct capref cap;
53         err = slot_alloc(&cap);
54         if (err_is_fail(err)) {
55             USER_PANIC_ERR(err, "slot_alloc failed");
56         }
57
58         void *mid_buf = NULL;
59         err = vspace_mmu_aware_map(&state->mmu_state, cap, step,
60                                    &mid_buf, &step);
61         if (err_is_ok(err)) {
62             if (buf == NULL) {
63                 buf = mid_buf;
64             }
65             mapped += step;
66         } else {
67             /*
68               vspace_mmu_aware_map failed probably because we asked
69               for a very large frame, will try asking for smaller one.
70              */
71             if (err_no(err) == LIB_ERR_FRAME_CREATE_MS_CONSTRAINTS) {
72                 err = slot_free(cap);
73                 if (err_is_fail(err)) {
74                     debug_err(__FILE__, __func__, __LINE__, err,
75                               "slot_free failed");
76                     return NULL;
77                 }
78                 if (step < BASE_PAGE_SIZE) {
79                     // Return whatever we have allocated until now
80                     break;
81                 }
82                 step /= 2;
83                 continue;
84             } else {
85                 debug_err(__FILE__, __func__, __LINE__, err,
86                           "vspace_mmu_aware_map fail");
87                 return NULL;
88             }
89         }
90     }
91
92     *retbytes = mapped;
93     return buf;
94 }
95
96 static void morecore_free(void *base, size_t bytes)
97 {
98     struct morecore_state *state = get_morecore_state();
99     errval_t err = vspace_mmu_aware_unmap(&state->mmu_state,
100                                           (lvaddr_t)base, bytes);
101     if(err_is_fail(err)) {
102         USER_PANIC_ERR(err, "vspace_mmu_aware_unmap");
103     }
104 }
105
106 Header *get_malloc_freep(void);
107 Header *get_malloc_freep(void)
108 {
109     return get_morecore_state()->header_freep;
110 }
111
112 errval_t morecore_init(void)
113 {
114     errval_t err;
115     struct morecore_state *state = get_morecore_state();
116
117     thread_mutex_init(&state->mutex);
118
119     err = vspace_mmu_aware_init(&state->mmu_state, HEAP_REGION);
120     if (err_is_fail(err)) {
121         return err_push(err, LIB_ERR_VSPACE_MMU_AWARE_INIT);
122     }
123
124     sys_morecore_alloc = morecore_alloc;
125     sys_morecore_free = morecore_free;
126
127     return SYS_ERR_OK;
128 }