Merge large page support code.
[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  * Copyright (c) 2014, HP Labs.
9  * All rights reserved.
10  *
11  * This file is distributed under the terms in the attached LICENSE file.
12  * If you do not find this file, copies can be found by writing to:
13  * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
14  */
15
16 #include <barrelfish/barrelfish.h>
17 #include <barrelfish/core_state.h>
18 #include <barrelfish/morecore.h>
19 #include <stdio.h>
20
21 /// Amount of virtual space for malloc
22 #ifdef __x86_64__
23 #       define HEAP_REGION (3500UL * 1024 * 1024) /* 2GB */
24 #else
25 #       define HEAP_REGION (512UL * 1024 * 1024) /* 512MB */
26 #endif
27
28 typedef void *(*morecore_alloc_func_t)(size_t bytes, size_t *retbytes);
29 extern morecore_alloc_func_t sys_morecore_alloc;
30
31 typedef void (*morecore_free_func_t)(void *base, size_t bytes);
32 extern morecore_free_func_t sys_morecore_free;
33
34 /**
35  * \brief Allocate some memory for malloc to use
36  *
37  * This function will keep trying with smaller and smaller frames till
38  * it finds a set of frames that satisfy the requirement. retbytes can
39  * be smaller than bytes if we were able to allocate a smaller memory
40  * region than requested for.
41  */
42 static void *morecore_alloc(size_t bytes, size_t *retbytes)
43 {
44     errval_t err;
45     struct morecore_state *state = get_morecore_state();
46
47     void *buf = NULL;
48     size_t mapped = 0;
49     size_t step = bytes;
50     while (mapped < bytes) {
51         struct capref cap;
52         err = slot_alloc(&cap);
53         if (err_is_fail(err)) {
54             USER_PANIC_ERR(err, "slot_alloc failed");
55         }
56
57         void *mid_buf = NULL;
58         err = vspace_mmu_aware_map(&state->mmu_state, cap, step,
59                                    &mid_buf, &step);
60         if (err_is_ok(err)) {
61             if (buf == NULL) {
62                 buf = mid_buf;
63             }
64             mapped += step;
65         } else {
66             /*
67               vspace_mmu_aware_map failed probably because we asked
68               for a very large frame, will try asking for smaller one.
69              */
70             if (err_no(err) == LIB_ERR_FRAME_CREATE_MS_CONSTRAINTS) {
71                 err = slot_free(cap);
72                 if (err_is_fail(err)) {
73                     debug_err(__FILE__, __func__, __LINE__, err,
74                               "slot_free failed");
75                     return NULL;
76                 }
77                 if (step < BASE_PAGE_SIZE) {
78                     // Return whatever we have allocated until now
79                     break;
80                 }
81                 step /= 2;
82                 continue;
83             } else {
84                 debug_err(__FILE__, __func__, __LINE__, err,
85                           "vspace_mmu_aware_map fail");
86                 return NULL;
87             }
88         }
89     }
90
91     *retbytes = mapped;
92     return buf;
93 }
94
95 static void morecore_free(void *base, size_t bytes)
96 {
97     struct morecore_state *state = get_morecore_state();
98     errval_t err = vspace_mmu_aware_unmap(&state->mmu_state,
99                                           (lvaddr_t)base, bytes);
100     if(err_is_fail(err)) {
101         USER_PANIC_ERR(err, "vspace_mmu_aware_unmap");
102     }
103 }
104
105 Header *get_malloc_freep(void);
106 Header *get_malloc_freep(void)
107 {
108     return get_morecore_state()->header_freep;
109 }
110
111 errval_t morecore_init(size_t alignment)
112 {
113     errval_t err;
114     struct morecore_state *state = get_morecore_state();
115
116     thread_mutex_init(&state->mutex);
117
118     // setup flags that match the alignment
119     vregion_flags_t morecore_flags = VREGION_FLAGS_READ_WRITE;
120 #if __x86_64__
121     morecore_flags |= (alignment == HUGE_PAGE_SIZE ? VREGION_FLAGS_HUGE : 0);
122 #endif
123     morecore_flags |= (alignment == LARGE_PAGE_SIZE ? VREGION_FLAGS_LARGE : 0);
124
125     err = vspace_mmu_aware_init_aligned(&state->mmu_state, HEAP_REGION,
126             alignment, morecore_flags);
127     if (err_is_fail(err)) {
128         return err_push(err, LIB_ERR_VSPACE_MMU_AWARE_INIT);
129     }
130
131     sys_morecore_alloc = morecore_alloc;
132     sys_morecore_free = morecore_free;
133
134     return SYS_ERR_OK;
135 }
136
137 errval_t morecore_reinit(void)
138 {
139     errval_t err;
140     struct morecore_state *state = get_morecore_state();
141
142     size_t mapoffset = state->mmu_state.mapoffset;
143     size_t remapsize = ROUND_UP(mapoffset, state->mmu_state.alignment);
144     if (remapsize <= mapoffset) {
145         // don't need to do anything if we only recreate the exact same
146         // mapping
147         return SYS_ERR_OK;
148     }
149     struct capref frame;
150     size_t retsize;
151     err = frame_alloc(&frame, remapsize, &retsize);
152     if (err_is_fail(err)) {
153         return err;
154     }
155     return vspace_mmu_aware_reset(&state->mmu_state, frame, remapsize);
156 }