]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/kmem_alloc-ia32.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / kmem_alloc-ia32.cpp
1 // base_init() puts those Mem_region_map's on the stack which is slightly
2 // larger than our warning limit, it's init code only, so it's ok
3 #pragma GCC diagnostic ignored "-Wframe-larger-than="
4
5 IMPLEMENTATION [ia32,ux,amd64]:
6
7 #include <cstdio>
8
9 #include "kip.h"
10 #include "koptions.h"
11 #include "mem_region.h"
12 #include "panic.h"
13 #include "types.h"
14
15 PUBLIC static inline
16 Phys_mem_addr::Value
17 Kmem_alloc::to_phys(void *v)
18 {
19   return Mem_layout::pmem_to_phys(v);
20 }
21
22 PUBLIC static FIASCO_INIT
23 bool
24 Kmem_alloc::base_init()
25 {
26   //printf("Kmem_alloc::base_init(): kip=%p\n", Kip::k());
27   unsigned long available_size = 0;
28   unsigned long requested_size;
29
30   Mem_region_map<64> map;
31   //Kip::k()->add_mem_region(Mem_desc(0xc7ed000, 0xfeecfff, Mem_desc::Reserved));
32   //Kip::k()->add_mem_region(Mem_desc(0xea00000, 0xfeecfff, Mem_desc::Reserved));
33
34   available_size = create_free_map(Kip::k(), &map);
35
36   requested_size = Koptions::o()->kmemsize << 10;
37   if (!requested_size)
38     {
39       requested_size = available_size / 100 * Config::kernel_mem_per_cent;
40       if (requested_size > Config::kernel_mem_max)
41         requested_size = Config::kernel_mem_max;
42     }
43
44   if (requested_size > (0-Mem_layout::Physmem))
45     requested_size = 0-Mem_layout::Physmem; // maximum mappable memory
46
47   requested_size = (requested_size + Config::PAGE_SIZE - 1)
48                    & ~(Config::PAGE_SIZE - 1);
49
50   //printf("Kmem_alloc: available_memory=%lu KB requested_size=%lu\n",
51   //       available_size / 1024, requested_size / 1024);
52
53   //printf("Kmem_alloc:: available blocks:\n");
54   //for (unsigned i = 0; i < map.length(); ++i)
55   //  printf("  %2u [%014lx; %014lx)\n", i, map[i].start, map[i].end+1);
56
57   unsigned long base = 0;
58   unsigned long sp_base = 0;
59   unsigned long end = map[map.length()-1].end;
60   unsigned last = map.length();
61   unsigned i;
62   unsigned long size = requested_size;
63   for (i = last; i > 0 && size > 0; --i)
64     {
65       if (map[i-1].size() >= size)
66         { // next block is sufficient
67           base = map[i-1].end - size + 1;
68           sp_base = base & ~(Config::SUPERPAGE_SIZE-1);
69           if ((end - sp_base + 1) > (0-Mem_layout::Physmem))
70             {
71               if (last == i)
72                 { // already a single block, try to align
73                   if (sp_base >= map[i-1].start)
74                     {
75                       base = sp_base;
76                       end  = sp_base + size -1;
77                       size = 0;
78                     }
79                   continue;
80                 }
81               else if (last > 1)
82                 { // too much virtual memory, try other blocks
83                   // free last block
84                   size += map[last-1].size();
85                   end = map[last-2].end;
86                   --last;
87                   ++i; // try same block again
88                   continue;
89                 }
90             }
91           else
92             size = 0;
93         }
94       else
95         size -= map[i-1].size();
96     }
97
98   if (size)
99     return false;
100
101   //printf("Kmem_alloc: kernel memory from %014lx to %014lx\n", base, end+1);
102   //printf("Kmem_alloc: blocks %u-%u\n", i, last-1);
103
104   Kip::k()->add_mem_region(Mem_desc(base,
105         end <= map[i].end ? end : map[i].end, Mem_desc::Kernel_tmp));
106   ++i;
107   for (; i < last; ++i)
108     Kip::k()->add_mem_region(Mem_desc(map[i].start, map[i].end, Mem_desc::Kernel_tmp));
109
110   Mem_layout::kphys_base(sp_base);
111   Mem_layout::pmem_size = (end + 1 - sp_base + Config::SUPERPAGE_SIZE - 1) & ~(Config::SUPERPAGE_SIZE-1);
112   return true;
113 }
114
115 IMPLEMENT
116 Kmem_alloc::Kmem_alloc()
117 {
118   //printf("Kmem_alloc::Kmem_alloc()\n");
119   Mem_desc *md = Kip::k()->mem_descs();
120   Mem_desc const *const md_end = md + Kip::k()->num_mem_descs();
121   bool initialized = false;
122
123   for (; md < md_end; ++md)
124     {
125       if (md->is_virtual())
126         continue;
127
128       unsigned long s = md->start(), e = md->end();
129
130       // Speep out stupid descriptors (that have the end before the start)
131       if (s>=e)
132         {
133           md->type(Mem_desc::Undefined);
134           continue;
135         }
136
137       if (md->type() == Mem_desc::Kernel_tmp)
138         {
139           unsigned long s_v = Mem_layout::phys_to_pmem(s);
140           if (!initialized)
141             {
142               initialized = true;
143               a->init(s_v & ~(Kmem_alloc::Alloc::Max_size - 1));
144               //printf("Kmem_alloc: allocator base = %014lx\n", s_v & ~(Kmem_alloc::Alloc::Max_size - 1));
145             }
146           //printf("  Kmem_alloc: block %014lx(%014lx) size=%lx\n", s_v, s, e - s + 1);
147           a->add_mem((void*)s_v, e - s + 1);
148           md->type(Mem_desc::Reserved);
149           _orig_free += e - s + 1;
150         }
151     }
152   //printf("Kmem_alloc: construction done\n");
153 }
154
155 //-----------------------------------------------------------------------------
156 IMPLEMENTATION [{ia32,ux,amd64}-debug]:
157
158 #include "div32.h"
159
160 PUBLIC
161 void
162 Kmem_alloc::debug_dump()
163
164   a->dump(); 
165
166   unsigned long free = a->avail();
167   printf("Used %ld%%, %ldKB out of %ldKB of Kmem\n",
168          (unsigned long) div32(100ULL * (orig_free() - free), orig_free()),
169          (orig_free() - free + 1023)/1024,
170          (orig_free()        + 1023)/1024);
171 }
172
173 PRIVATE inline
174 unsigned long
175 Kmem_alloc::orig_free()
176 {
177   return _orig_free;
178 }