25 |
#include <alloca.h> |
#include <alloca.h> |
26 |
|
|
27 |
#include "wortel.h" |
#include "wortel.h" |
28 |
|
#include "sigma0.h" |
29 |
|
|
30 |
|
|
31 |
/* The program name. */ |
/* The program name. */ |
36 |
l4_word_t wortel_end; |
l4_word_t wortel_end; |
37 |
|
|
38 |
|
|
39 |
|
/* Unused memory. These fpages mark memory which we needed at some |
40 |
|
time, but don't need anymore. It can be granted to the physical |
41 |
|
memory server at startup. This includes architecture dependent |
42 |
|
boot data as well as the physical memory server module. */ |
43 |
|
#define MAX_UNUSED_FPAGES 32 |
44 |
|
l4_fpage_t wortel_unused_fpages[MAX_UNUSED_FPAGES]; |
45 |
|
unsigned int wortel_unused_fpages_count; |
46 |
|
|
47 |
|
|
48 |
/* Room for the arguments. 1 KB is a cramped half-screen full, which |
/* Room for the arguments. 1 KB is a cramped half-screen full, which |
49 |
should be more than enough. */ |
should be more than enough. */ |
50 |
char mods_args[1024]; |
char mods_args[1024]; |
150 |
} |
} |
151 |
|
|
152 |
|
|
|
/* Request the fpage FPAGE from sigma0. */ |
|
|
static void |
|
|
sigma0_get_fpage (l4_fpage_t fpage) |
|
|
{ |
|
|
l4_msg_t msg; |
|
|
l4_msg_tag_t msg_tag; |
|
|
l4_map_item_t map_item; |
|
|
|
|
|
l4_accept (l4_map_grant_items (l4_complete_address_space)); |
|
|
l4_msg_clear (&msg); |
|
|
l4_set_msg_label (&msg, 0xffa0); |
|
|
l4_msg_append_word (&msg, fpage.raw); |
|
|
l4_msg_append_word (&msg, L4_DEFAULT_MEMORY); |
|
|
l4_msg_load (&msg); |
|
|
msg_tag = l4_call (l4_global_id (l4_thread_user_base (), 1)); |
|
|
if (l4_ipc_failed (msg_tag)) |
|
|
panic ("sigma0 request failed during %s: %u", |
|
|
l4_error_code () & 1 ? "receive" : "send", |
|
|
(l4_error_code () >> 1) & 0x7); |
|
|
if (l4_untyped_words (msg_tag) != 0 |
|
|
|| l4_typed_words (msg_tag) != 2) |
|
|
panic ("Invalid format of sigma0 reply"); |
|
|
l4_msg_store (msg_tag, &msg); |
|
|
l4_msg_get_map_item (&msg, 0, &map_item); |
|
|
if (map_item.send_fpage.raw == l4_nilpage.raw) |
|
|
panic ("sigma0 rejected mapping"); |
|
|
} |
|
|
|
|
|
/* Request an fpage of the size 2^SIZE from sigma0. */ |
|
|
static l4_fpage_t |
|
|
sigma0_get_any (unsigned int size) |
|
|
{ |
|
|
l4_msg_t msg; |
|
|
l4_msg_tag_t msg_tag; |
|
|
l4_map_item_t map_item; |
|
|
l4_fpage_t fpage = l4_fpage_add_rights (l4_fpage_log2 (-1, size), |
|
|
l4_fully_accessible); |
|
|
|
|
|
l4_accept (l4_map_grant_items (l4_complete_address_space)); |
|
|
l4_msg_clear (&msg); |
|
|
l4_set_msg_label (&msg, 0xffa0); |
|
|
debug ("Request 0x%x\n", fpage.raw); |
|
|
l4_msg_append_word (&msg, fpage.raw); |
|
|
l4_msg_append_word (&msg, L4_DEFAULT_MEMORY); |
|
|
l4_msg_load (&msg); |
|
|
msg_tag = l4_call (l4_global_id (l4_thread_user_base (), 1)); |
|
|
if (l4_ipc_failed (msg_tag)) |
|
|
panic ("sigma0 request failed during %s: %u", |
|
|
l4_error_code () & 1 ? "receive" : "send", |
|
|
(l4_error_code () >> 1) & 0x7); |
|
|
if (l4_untyped_words (msg_tag) != 0 |
|
|
|| l4_typed_words (msg_tag) != 2) |
|
|
panic ("Invalid format of sigma0 reply"); |
|
|
l4_msg_store (msg_tag, &msg); |
|
|
l4_msg_get_map_item (&msg, 0, &map_item); |
|
|
debug ("Got 0x%x\n", map_item.send_fpage.raw); |
|
|
return map_item.send_fpage; |
|
|
} |
|
|
|
|
153 |
|
|
154 |
static void |
static void |
155 |
load_components (void) |
load_components (void) |
158 |
unsigned int nr_fpages; |
unsigned int nr_fpages; |
159 |
l4_word_t min_page_size = getpagesize (); |
l4_word_t min_page_size = getpagesize (); |
160 |
unsigned int i; |
unsigned int i; |
161 |
|
l4_word_t addr; |
162 |
|
l4_word_t end_addr; |
163 |
|
|
164 |
/* One issue we have to solve is to make sure that when the physical |
/* One issue we have to solve is to make sure that when the physical |
165 |
memory server requests all the available physical pages, we know |
memory server requests all the available physical fpages, we know |
166 |
which pages we can give to it, and which we can't. This can be |
which fpages we can give to it, and which we can't. This can be |
167 |
left to sigma0, as long as we request all pages from sigma0 we |
left to sigma0, as long as we request all fpages from sigma0 we |
168 |
can't give to the physical memory server up-front. |
can't give to the physical memory server up-front. |
169 |
|
|
170 |
We do this in several steps: First, we copy all of the startup |
We do this in several steps: First, we copy all of the startup |
171 |
information to memory that is part of the wortel binary image |
information to memory that is part of the wortel binary image |
172 |
itself. This is done by the architecture dependant |
itself. This is done by the architecture dependent |
173 |
find_components function. Then we request all of our own memory, |
find_components function. Then we request all of our own memory, |
174 |
and all the memory needed for the physical memory server image |
all the memory for our modules, and finally all the memory needed |
175 |
(at its destination address), and all the memory for each module |
for the physical memory server image (at its destination |
176 |
(at their corresponding load addresses). */ |
address). */ |
177 |
|
|
178 |
if (wortel_start & (min_page_size - 1)) |
if (wortel_start & (min_page_size - 1)) |
179 |
panic ("%s does not start on a page boundary", program_name); |
panic ("%s does not start on a page boundary", program_name); |
180 |
loader_add_region (program_name, wortel_start, wortel_end); |
loader_add_region (program_name, wortel_start, wortel_end); |
181 |
nr_fpages = make_fpages (wortel_start, wortel_end, fpages); |
|
182 |
while (nr_fpages--) |
/* We must request our own memory using the smallest fpages |
183 |
sigma0_get_fpage (fpages[nr_fpages]); |
possible, because we already have some memory mapped due to page |
184 |
|
faults, and fpages are specified as inseparable objects. */ |
185 |
|
for (addr = wortel_start; addr < wortel_end; addr += min_page_size) |
186 |
|
sigma0_get_fpage (l4_fpage (addr, min_page_size)); |
187 |
|
|
188 |
/* First protect all pages covered by the modules. This will also |
/* First protect all pages covered by the modules. This will also |
189 |
show if each module starts (and ends) on its own page. */ |
show if each module starts (and ends) on its own page. Request |
190 |
|
all memory for all modules. Although we can release the memory |
191 |
|
for the physmem module later on, we have to touch it anyway to |
192 |
|
load it to its destination address, and requesting the fpages now |
193 |
|
allows us to choose how we want to split up the module in |
194 |
|
(inseparable) fpages. */ |
195 |
for (i = 0; i < mods_count; i++) |
for (i = 0; i < mods_count; i++) |
196 |
{ |
{ |
197 |
if (mods[i].start & (min_page_size - 1)) |
if (mods[i].start & (min_page_size - 1)) |
198 |
panic ("Module %s does not start on a page boundary", mods[i].name); |
panic ("Module %s does not start on a page boundary", mods[i].name); |
199 |
loader_add_region (mods[i].name, mods[i].start, mods[i].end); |
loader_add_region (mods[i].name, mods[i].start, mods[i].end); |
200 |
|
|
201 |
|
nr_fpages = make_fpages (mods[i].start, mods[i].end, fpages); |
202 |
|
if (i == MOD_PHYSMEM) |
203 |
|
{ |
204 |
|
/* The physical memory server module memory can be recycled |
205 |
|
later. */ |
206 |
|
if (nr_fpages + wortel_unused_fpages_count > MAX_UNUSED_FPAGES) |
207 |
|
panic ("not enough room in unused fpages list for physmem-mod"); |
208 |
|
memcpy (&wortel_unused_fpages[wortel_unused_fpages_count], |
209 |
|
fpages, sizeof (l4_fpage_t) * nr_fpages); |
210 |
|
wortel_unused_fpages_count += nr_fpages; |
211 |
|
} |
212 |
|
|
213 |
|
while (nr_fpages--) |
214 |
|
sigma0_get_fpage (fpages[nr_fpages]); |
215 |
} |
} |
216 |
|
|
217 |
|
/* Because loading the physical memory server to its destination |
218 |
|
address will touch the destination memory, which we later want to |
219 |
|
grant to the physical memory server using (inseparable) fpages, |
220 |
|
we request the desired fpages up-front. */ |
221 |
|
loader_elf_dest ("physmem-server", mods[MOD_PHYSMEM].start, |
222 |
|
mods[MOD_PHYSMEM].end, &addr, &end_addr); |
223 |
|
nr_fpages = make_fpages (addr, end_addr, fpages); |
224 |
|
while (nr_fpages--) |
225 |
|
sigma0_get_fpage (fpages[nr_fpages]); |
226 |
|
|
227 |
/* Now load the physical memory server to its destination |
/* Now load the physical memory server to its destination |
228 |
address. */ |
address. */ |
229 |
if (!mods[MOD_PHYSMEM].start) |
addr = mods[MOD_PHYSMEM].start; |
230 |
|
end_addr = mods[MOD_PHYSMEM].end; |
231 |
|
if (!addr) |
232 |
panic ("No physical memory server found"); |
panic ("No physical memory server found"); |
233 |
loader_elf_load ("physmem-server", mods[MOD_PHYSMEM].start, |
loader_elf_load ("physmem-server", addr, end_addr, |
|
mods[MOD_PHYSMEM].end, |
|
234 |
&mods[MOD_PHYSMEM].start, &mods[MOD_PHYSMEM].end, |
&mods[MOD_PHYSMEM].start, &mods[MOD_PHYSMEM].end, |
235 |
&mods[MOD_PHYSMEM].ip); |
&mods[MOD_PHYSMEM].ip); |
236 |
loader_remove_region ("physmem-mod"); |
loader_remove_region ("physmem-mod"); |
|
|
|
|
/* Finally we can request all the memory for the physical memory |
|
|
server and all other modules from sigma0. This will register the |
|
|
memory as taken by us, and the memory will not be returned by any |
|
|
future request. */ |
|
|
for (i = 0; i < mods_count; i++) |
|
|
{ |
|
|
nr_fpages = make_fpages (mods[i].start, mods[i].end, fpages); |
|
|
while (nr_fpages--) |
|
|
sigma0_get_fpage (fpages[nr_fpages]); |
|
|
} |
|
237 |
} |
} |
238 |
|
|
239 |
|
|
252 |
|| mods[MOD_PHYSMEM].ip > mods[MOD_PHYSMEM].end) |
|| mods[MOD_PHYSMEM].ip > mods[MOD_PHYSMEM].end) |
253 |
panic ("physmem has invalid IP"); |
panic ("physmem has invalid IP"); |
254 |
|
|
|
|
|
255 |
cap_id = wortel_add_user (2); |
cap_id = wortel_add_user (2); |
256 |
/* FIXME: Pass cap_id to physmem. */ |
/* FIXME: Pass cap_id to physmem. */ |
257 |
/* Thread nr is next available after rootserver thread nr, |
/* Thread nr is next available after rootserver thread nr, |
368 |
/* The size of the region that we are currently trying to allocate |
/* The size of the region that we are currently trying to allocate |
369 |
for GET_MEM requests. If this is smaller than 2^10, no more |
for GET_MEM requests. If this is smaller than 2^10, no more |
370 |
memory is available. */ |
memory is available. */ |
371 |
unsigned int get_mem_size = 12; |
unsigned int get_mem_size = sizeof (l4_word_t) * 8 - 1; |
372 |
|
|
373 |
|
while (get_mem_size >= 10 |
374 |
|
&& ! ((1 << get_mem_size) & l4_page_size_mask ())) |
375 |
|
get_mem_size--; |
376 |
|
|
377 |
do |
do |
378 |
{ |
{ |
379 |
l4_thread_id_t from; |
l4_thread_id_t from; |
417 |
if (get_mem_size < 10) |
if (get_mem_size < 10) |
418 |
panic ("physmem server does not stop requesting memory"); |
panic ("physmem server does not stop requesting memory"); |
419 |
|
|
420 |
do |
/* Give out the memory. First our unused fpages, then the |
421 |
{ |
fpages we can get from sigma0. */ |
422 |
fpage = sigma0_get_any (get_mem_size); |
if (wortel_unused_fpages_count) |
423 |
if (fpage.raw == l4_nilpage.raw) |
fpage = wortel_unused_fpages[--wortel_unused_fpages_count]; |
424 |
get_mem_size--; |
else |
425 |
} |
do |
426 |
while (fpage.raw == l4_nilpage.raw && get_mem_size >= 10); |
{ |
427 |
|
fpage = sigma0_get_any (get_mem_size); |
428 |
|
if (fpage.raw == l4_nilpage.raw) |
429 |
|
{ |
430 |
|
get_mem_size--; |
431 |
|
while (get_mem_size >= 10 |
432 |
|
&& ! ((1 << get_mem_size) & l4_page_size_mask ())) |
433 |
|
get_mem_size--; |
434 |
|
} |
435 |
|
} |
436 |
|
while (fpage.raw == l4_nilpage.raw && get_mem_size >= 10); |
437 |
|
|
438 |
grant_item = l4_grant_item (fpage, l4_address (fpage)); |
grant_item = l4_grant_item (fpage, l4_address (fpage)); |
439 |
l4_msg_clear (&msg); |
l4_msg_clear (&msg); |