]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap_custom/server/src/platform/x86_pc.cc
17b24edbaecf1abdde1a26808239f01512fddab8
[l4.git] / l4 / pkg / bootstrap_custom / server / src / platform / x86_pc.cc
1 /*!
2  * \file   support_x86.cc
3  * \brief  Support for the x86 platform
4  *
5  * \date   2008-01-02
6  * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
7  *
8  */
9 /*
10  * (c) 2008-2009 Author(s)
11  *     economic rights: Technische Universität Dresden (Germany)
12  *
13  * This file is part of TUD:OS and distributed under the terms of the
14  * GNU General Public License 2.
15  * Please see the COPYING-GPL-2 file for details.
16  */
17
18 #include "support.h"
19 #include "x86_pc-base.h"
20
21 #include <string.h>
22 #include "startup.h"
23 #include "panic.h"
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 enum { Verbose_mbi = 1 };
30
31 namespace {
32
33 #ifdef REALMODE_LOADING
34 struct Platform_x86_1 : Platform_x86
35 {
36   char const *realmode_pointer;
37
38   void setup_memory_map()
39   {
40     Region_list *ram = mem_manager->ram;
41     Region_list *regions = mem_manager->regions;
42
43     unsigned long m = *(l4_uint32_t*)(realmode_pointer + 0x1e0);
44     printf("Detected memory size: %ldKB\n", m);
45     ram->add(Region::n(0, 0x9fc00, ".ram", Region::Ram));
46     ram->add(Region::n(0x100000, (m + 1024) << 10, ".ram", Region::Ram));
47     regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
48     // Quirks
49
50     // Fix EBDA in conventional memory
51     unsigned long p = *(l4_uint16_t *)0x40e << 4;
52
53     if (p > 0x400)
54       {
55         unsigned long e = p + 1024;
56         Region *r = ram->find(Region(p, e - 1));
57         if (r)
58           {
59             if (e - 1 < r->end())
60               ram->add(Region::n(e, r->end(), ".ram", Region::Ram), true);
61             r->end(p);
62           }
63       }
64   }
65
66   char const *cmdline() const
67   {
68     return 0;
69     l4_uint32_t p = *(l4_uint32_t*)(realmode_pointer + 0x228);
70     if (!p)
71       return 0;
72
73     return (char const *)p;
74   }
75 };
76
77 #else // REALMODE_LOADING
78
79 struct Platform_x86_1 : Platform_x86
80 {
81   l4util_mb_info_t *mbi;
82
83   void setup_memory_map()
84   {
85     Region_list *ram = mem_manager->ram;
86     Region_list *regions = mem_manager->regions;
87
88 #ifdef ARCH_amd64
89     // add the page-table on which we're running in 64bit mode
90     regions->add(Region::n(ptab64_info->addr, ptab64_info->addr + ptab64_info->size,
91                  ".bootstrap-ptab64", Region::Boot));
92 #endif
93    if (!(mbi->flags & L4UTIL_MB_MEM_MAP))
94       {
95         assert(mbi->flags & L4UTIL_MB_MEMORY);
96         ram->add(Region::n(0, (mbi->mem_lower + 1024) << 10, ".ram",
97                            Region::Ram));
98         ram->add(Region::n(0x100000, (mbi->mem_upper + 1024) << 10, ".ram",
99                            Region::Ram));
100       }
101     else
102       {
103         l4util_mb_addr_range_t *mmap;
104         l4util_mb_for_each_mmap_entry(mmap, mbi)
105           {
106             unsigned long long start = (unsigned long long)mmap->addr;
107             unsigned long long end = (unsigned long long)mmap->addr + mmap->size;
108
109             switch (mmap->type)
110               {
111               case 1:
112                 ram->add(Region::n(start, end, ".ram", Region::Ram));
113                 break;
114               case 2:
115               case 3:
116               case 4:
117                 regions->add(Region::n(start, end, ".BIOS", Region::Arch, mmap->type));
118                 break;
119               case 5:
120                 regions->add(Region::n(start, end, ".BIOS", Region::No_mem));
121                 break;
122               default:
123                 break;
124               }
125           }
126       }
127
128     regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
129
130
131     // Quirks
132
133     // Fix EBDA in conventional memory
134     unsigned long p = *(l4_uint16_t *)0x40e << 4;
135
136     if (p > 0x400)
137       {
138         unsigned long e = p + 1024;
139         Region *r = ram->find(Region(p, e - 1));
140         if (r)
141           {
142             if (e - 1 < r->end())
143               ram->add(Region::n(e, r->end(), ".ram", Region::Ram), true);
144             r->end(p);
145           }
146       }
147   }
148 };
149
150 #endif // !REALMODE_LOADING
151
152
153 #ifdef IMAGE_MODE
154
155 class Platform_x86_loader_mbi :
156   public Platform_x86_1,
157   public Boot_modules_image_mode
158 {
159 public:
160   Boot_modules *modules() { return this; }
161
162 };
163
164 Platform_x86_loader_mbi _x86_pc_platform;
165
166 #else // IMAGE_MODE
167
168 class Platform_x86_multiboot : public Platform_x86_1, public Boot_modules
169 {
170 public:
171   Boot_modules *modules() { return this; }
172
173   Module module(unsigned index, bool) const
174   {
175     Module m;
176     l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
177
178     m.start   = (char const *)(l4_addr_t)mb_mod[index].mod_start;
179     m.end     = (char const *)(l4_addr_t)mb_mod[index].mod_end;
180     m.cmdline = (char const *)(l4_addr_t)mb_mod[index].cmdline;
181     return m;
182   }
183
184   unsigned num_modules() const { return mbi->mods_count; }
185
186   void reserve()
187   {
188     Region_list *regions = mem_manager->regions;
189
190     regions->add(Region::n((unsigned long)mbi,
191                            (unsigned long)mbi + sizeof(*mbi),
192                            ".mbi", Region::Boot));
193
194     if (mbi->flags & L4UTIL_MB_CMDLINE)
195       regions->add(Region::n((unsigned long)mbi->cmdline,
196                              (unsigned long)mbi->cmdline
197                              + strlen((char const *)(l4_addr_t)mbi->cmdline) + 1,
198                              ".mbi", Region::Boot));
199
200     l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
201     regions->add(Region::n((unsigned long)mb_mod,
202                            (unsigned long)&mb_mod[mbi->mods_count],
203                            ".mbi", Region::Boot));
204
205     if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
206       {
207         if (mbi->vbe_mode_info)
208           regions->add(Region::start_size(mbi->vbe_mode_info,
209                                           sizeof(l4util_mb_vbe_mode_t),
210                                           ".mbi", Region::Boot));
211         if (mbi->vbe_ctrl_info)
212           regions->add(Region::start_size(mbi->vbe_ctrl_info,
213                                           sizeof(l4util_mb_vbe_ctrl_t),
214                                           ".mbi", Region::Boot));
215       }
216
217
218     for (unsigned i = 0; i < mbi->mods_count; ++i)
219       regions->add(Region::n(mb_mod[i].cmdline,
220                              (unsigned long)mb_mod[i].cmdline
221                              + strlen((char const *)(l4_addr_t)mb_mod[i].cmdline) + 1,
222                              ".mbi", Region::Boot));
223
224     for (unsigned i = 0; i < mbi->mods_count; ++i)
225       regions->add(mod_region(i, mb_mod[i].mod_start,
226                               mb_mod[i].mod_end - mb_mod[i].mod_start));
227   }
228
229   void move_module(unsigned index, void *dest,
230                    bool overlap_check)
231   {
232     l4util_mb_mod_t *mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr + index;
233     unsigned long size = mod->mod_end - mod->mod_start;
234     _move_module(index, dest, (char const *)(l4_addr_t)mod->mod_start,
235                  size, overlap_check);
236
237     assert ((l4_addr_t)dest < 0xfffffff0);
238     assert ((l4_addr_t)dest < 0xfffffff0 - size);
239     mod->mod_start = (l4_addr_t)dest;
240     mod->mod_end   = (l4_addr_t)dest + size;
241   }
242
243   l4util_mb_info_t *construct_mbi(unsigned long mod_addr)
244   {
245     // calculate the size needed to cover the full MBI, including command lines
246     unsigned long total_size = sizeof(l4util_mb_info_t);
247
248     // consider the global command line
249     if (mbi->flags & L4UTIL_MB_CMDLINE)
250       total_size += round_wordsize(strlen((char const *)(l4_addr_t)mbi->cmdline) + 1);
251
252     // consider VBE info
253     if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
254       {
255         if (mbi->vbe_mode_info)
256           total_size += sizeof(l4util_mb_vbe_mode_t);
257
258         if (mbi->vbe_ctrl_info)
259           total_size += sizeof(l4util_mb_vbe_ctrl_t);
260       }
261
262     // consider modules
263     total_size += sizeof(l4util_mb_mod_t) * mbi->mods_count;
264
265     // scan through all modules and add the command line
266     l4util_mb_mod_t *mods = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
267     for (l4util_mb_mod_t *m = mods; m != mods + mbi->mods_count; ++m)
268       if (m->cmdline)
269         total_size += round_wordsize(strlen((char const *)(l4_addr_t)m->cmdline) + 1);
270
271     if (Verbose_mbi)
272       printf("  need %ld bytes to copy MBI\n", total_size);
273
274     // try to find a free region for the MBI
275     char *_mb = (char *)mem_manager->find_free_ram(total_size);
276     if (!_mb)
277       panic("fatal: could not allocate memory for multi-boot info\n");
278
279     // mark the region as reserved
280     mem_manager->regions->add(Region::start_size((l4_addr_t)_mb, total_size, ".mbi_rt",
281                                                  Region::Root));
282     if (Verbose_mbi)
283       printf("  reserved %ld bytes at %p\n", total_size, _mb);
284
285     // copy the whole MBI
286     l4util_mb_info_t *dst = (l4util_mb_info_t *)_mb;
287     *dst = *mbi;
288
289     l4util_mb_mod_t *dst_mods = (l4util_mb_mod_t *)(dst + 1);
290     dst->mods_addr = (l4_addr_t)dst_mods;
291     _mb = (char *)(dst_mods + mbi->mods_count);
292
293     if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
294       {
295         if (mbi->vbe_mode_info)
296           {
297             l4util_mb_vbe_mode_t *d = (l4util_mb_vbe_mode_t *)_mb;
298             *d = *((l4util_mb_vbe_mode_t *)(l4_addr_t)mbi->vbe_mode_info);
299             dst->vbe_mode_info = (l4_addr_t)d;
300             _mb = (char *)(d + 1);
301           }
302
303         if (mbi->vbe_ctrl_info)
304           {
305             l4util_mb_vbe_ctrl_t *d = (l4util_mb_vbe_ctrl_t *)_mb;
306             *d = *((l4util_mb_vbe_ctrl_t *)(l4_addr_t)mbi->vbe_ctrl_info);
307             dst->vbe_ctrl_info = (l4_addr_t)d;
308             _mb = (char *)(d + 1);
309           }
310       }
311
312     if (mbi->cmdline)
313       {
314         strcpy(_mb, (char const *)(l4_addr_t)mbi->cmdline);
315         dst->cmdline = (l4_addr_t)_mb;
316         _mb += round_wordsize(strlen(_mb) + 1);
317       }
318
319     for (unsigned i = 0; i < mbi->mods_count; ++i)
320       {
321         dst_mods[i] = mods[i];
322         if (char const *c = (char const *)(l4_addr_t)(mods[i].cmdline))
323           {
324             unsigned l = strlen(c) + 1;
325             dst_mods[i].cmdline = (l4_addr_t)_mb;
326             memcpy(_mb, c, l);
327             _mb += round_wordsize(l);
328           }
329       }
330
331     mbi = dst;
332
333     // remove the old MBI from the reserved memory
334     for (Region *r = mem_manager->regions->begin();
335          r != mem_manager->regions->end();)
336       {
337         if (strcmp(r->name(), ".mbi"))
338           ++r;
339         else
340           r = mem_manager->regions->remove(r);
341       }
342
343     move_modules(mod_addr);
344     return mbi;
345   }
346 };
347
348 Platform_x86_multiboot _x86_pc_platform;
349
350 #endif // !IMAGE_MODE
351 }
352
353 extern "C"
354 void __main(l4util_mb_info_t *mbi, unsigned long p2, char const *realmode_si,
355             ptab64_mem_info_t const *ptab64_info);
356
357 void __main(l4util_mb_info_t *mbi, unsigned long p2, char const *realmode_si,
358             ptab64_mem_info_t const *ptab64_info)
359 {
360   ctor_init();
361   Platform_base::platform = &_x86_pc_platform;
362   _x86_pc_platform.init();
363 #ifdef ARCH_amd64
364   // remember this info to reserve the memory in setup_memory_map later
365   _x86_pc_platform.ptab64_info = ptab64_info;
366 #else
367   (void)ptab64_info;
368 #endif
369   char const *cmdline;
370 #if defined(REALMODE_LOADING)
371   /* create synthetic multi boot info, if loaded from realmode */
372   (void)mbi;
373   (void)p2;
374   _x86_pc_platform.realmode_pointer = realmode_si;
375   cmdline = _x86_pc_platform.cmdline();
376 //  if (!cmdline)
377 //    cmdline = _mbi_cmdline;
378 #else
379   (void)realmode_si;
380   assert(p2 == L4UTIL_MB_VALID); /* we need to be multiboot-booted */
381   _x86_pc_platform.mbi = mbi;
382   cmdline = (char const *)(l4_addr_t)mbi->cmdline;
383 #endif
384   _x86_pc_platform.setup_uart(cmdline);
385
386   startup(cmdline);
387 }
388
389