]> 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   if (0)
27     printf("Kmem_alloc::base_init(): kip=%p\n", Kip::k());
28   unsigned long available_size = 0;
29   unsigned long requested_size;
30
31   Mem_region_map<64> map;
32
33   available_size = create_free_map(Kip::k(), &map);
34
35   requested_size = Koptions::o()->kmemsize << 10;
36   if (!requested_size)
37     {
38       requested_size = available_size / 100 * Config::kernel_mem_per_cent;
39       if (requested_size > Config::kernel_mem_max)
40         requested_size = Config::kernel_mem_max;
41     }
42
43   if (requested_size > (0 - Mem_layout::Physmem))
44     requested_size = 0 - Mem_layout::Physmem; // maximum mappable memory
45
46   requested_size =    (requested_size + Config::PAGE_SIZE - 1)
47                    & ~(Config::PAGE_SIZE - 1);
48
49   if (0)
50     {
51       printf("Kmem_alloc: available_memory=%lu KB requested_size=%lu\n",
52              available_size / 1024, requested_size / 1024);
53
54       printf("Kmem_alloc:: available blocks:\n");
55       for (unsigned i = 0; i < map.length(); ++i)
56         printf("  %2u [%014lx; %014lx)\n", i, map[i].start, map[i].end + 1);
57     }
58
59   unsigned long base = 0;
60   unsigned long sp_base = 0;
61   unsigned long end = map[map.length() - 1].end;
62   unsigned last = map.length();
63   unsigned i;
64   unsigned long size = requested_size;
65
66   for (i = last; i > 0 && size > 0; --i)
67     {
68       if (map[i - 1].size() >= size)
69         { // next block is sufficient
70           base = map[i - 1].end - size + 1;
71           sp_base = base & ~(Config::SUPERPAGE_SIZE - 1);
72           if ((end - sp_base + 1) > (0 - Mem_layout::Physmem))
73             {
74               if (last == i)
75                 { // already a single block, try to align
76                   if (sp_base >= map[i - 1].start)
77                     {
78                       base = sp_base;
79                       end  = sp_base + size - 1;
80                       size = 0;
81                     }
82                   continue;
83                 }
84               else if (last > 1)
85                 { // too much virtual memory, try other blocks
86                   // free last block
87                   size += map[last - 1].size();
88                   end = map[last - 2].end;
89                   --last;
90                   ++i; // try same block again
91                   continue;
92                 }
93             }
94           else
95             size = 0;
96         }
97       else
98         size -= map[i - 1].size();
99     }
100
101   if (size)
102     return false;
103
104   if (0)
105     {
106       printf("Kmem_alloc: kernel memory from %014lx to %014lx\n", base, end + 1);
107       printf("Kmem_alloc: blocks %u-%u\n", i, last - 1);
108     }
109
110   Kip::k()->add_mem_region(Mem_desc(base, end <= map[i].end ? end : map[i].end,
111                                     Mem_desc::Kernel_tmp));
112   ++i;
113   for (; i < last; ++i)
114     Kip::k()->add_mem_region(Mem_desc(map[i].start, map[i].end,
115                                       Mem_desc::Kernel_tmp));
116
117   Mem_layout::kphys_base(sp_base);
118   Mem_layout::pmem_size =    (end + 1 - sp_base + Config::SUPERPAGE_SIZE - 1)
119                           & ~(Config::SUPERPAGE_SIZE - 1);
120   assert(Mem_layout::pmem_size <= Config::kernel_mem_max);
121
122   return true;
123 }
124
125 IMPLEMENT
126 Kmem_alloc::Kmem_alloc()
127 {
128   if (0)
129     printf("Kmem_alloc::Kmem_alloc()\n");
130   bool initialized = false;
131
132   for (auto &md: Kip::k()->mem_descs_a())
133     {
134       if (md.is_virtual())
135         continue;
136
137       unsigned long s = md.start(), e = md.end();
138
139       // Sweep out stupid descriptors (that have the end before the start)
140       if (s >= e)
141         {
142           md.type(Mem_desc::Undefined);
143           continue;
144         }
145
146       if (md.type() == Mem_desc::Kernel_tmp)
147         {
148           unsigned long s_v = Mem_layout::phys_to_pmem(s);
149           if (!initialized)
150             {
151               initialized = true;
152               a->init(s_v & ~(Kmem_alloc::Alloc::Max_size - 1));
153               if (0)
154                 printf("Kmem_alloc: allocator base = %014lx\n",
155                        s_v & ~(Kmem_alloc::Alloc::Max_size - 1));
156             }
157           if (0)
158             printf("  Kmem_alloc: block %014lx(%014lx) size=%lx\n",
159                    s_v, s, e - s + 1);
160           a->add_mem((void *)s_v, e - s + 1);
161           md.type(Mem_desc::Reserved);
162           _orig_free += e - s + 1;
163         }
164     }
165   if (0)
166     printf("Kmem_alloc: construction done\n");
167 }
168
169 //-----------------------------------------------------------------------------
170 IMPLEMENTATION [{ia32,ux,amd64}-debug]:
171
172 #include "div32.h"
173
174 PUBLIC
175 void
176 Kmem_alloc::debug_dump()
177 {
178   a->dump();
179
180   unsigned long free = a->avail();
181   printf("Used %lu%%, %luKB out of %luKB of Kmem\n",
182          (unsigned long)div32(100ULL * (orig_free() - free), orig_free()),
183          (orig_free() - free + 1023) / 1024,
184          (orig_free()        + 1023) / 1024);
185 }
186
187 PRIVATE inline
188 unsigned long
189 Kmem_alloc::orig_free()
190 {
191   return _orig_free;
192 }