Kevin O'Connor | 3061815 | 2013-09-28 22:00:49 -0400 | [diff] [blame] | 1 | // Internal dynamic memory allocations. |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 2 | // |
Kevin O'Connor | 3061815 | 2013-09-28 22:00:49 -0400 | [diff] [blame] | 3 | // Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net> |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 4 | // |
| 5 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
| 6 | |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 7 | #include "biosvar.h" // GET_BDA |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 8 | #include "config.h" // BUILD_BIOS_ADDR |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 9 | #include "list.h" // hlist_node |
| 10 | #include "malloc.h" // _malloc |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 11 | #include "memmap.h" // struct e820entry |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 12 | #include "output.h" // dprintf |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 13 | #include "stacks.h" // wait_preempt |
Kevin O'Connor | 8fb3a5e | 2013-09-14 22:27:14 -0400 | [diff] [blame] | 14 | #include "std/optionrom.h" // OPTION_ROM_ALIGN |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 15 | #include "string.h" // memset |
| 16 | |
| 17 | // Information on a reserved area. |
| 18 | struct allocinfo_s { |
| 19 | struct hlist_node node; |
| 20 | void *data, *dataend, *allocend; |
| 21 | }; |
| 22 | |
| 23 | // Information on a tracked memory allocation. |
| 24 | struct allocdetail_s { |
| 25 | struct allocinfo_s detailinfo; |
| 26 | struct allocinfo_s datainfo; |
| 27 | u32 handle; |
| 28 | }; |
| 29 | |
| 30 | // The various memory zones. |
| 31 | struct zone_s { |
| 32 | struct hlist_head head; |
| 33 | }; |
| 34 | |
| 35 | struct zone_s ZoneLow VARVERIFY32INIT, ZoneHigh VARVERIFY32INIT; |
| 36 | struct zone_s ZoneFSeg VARVERIFY32INIT; |
| 37 | struct zone_s ZoneTmpLow VARVERIFY32INIT, ZoneTmpHigh VARVERIFY32INIT; |
| 38 | |
| 39 | static struct zone_s *Zones[] VARVERIFY32INIT = { |
| 40 | &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh |
| 41 | }; |
| 42 | |
| 43 | |
| 44 | /**************************************************************** |
| 45 | * low-level memory reservations |
| 46 | ****************************************************************/ |
| 47 | |
| 48 | // Find and reserve space from a given zone |
| 49 | static void * |
| 50 | allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill) |
| 51 | { |
| 52 | struct allocinfo_s *info; |
| 53 | hlist_for_each_entry(info, &zone->head, node) { |
| 54 | void *dataend = info->dataend; |
| 55 | void *allocend = info->allocend; |
| 56 | void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align); |
| 57 | if (newallocend >= dataend && newallocend <= allocend) { |
| 58 | // Found space - now reserve it. |
| 59 | if (!fill) |
| 60 | fill = newallocend; |
| 61 | fill->data = newallocend; |
| 62 | fill->dataend = newallocend + size; |
| 63 | fill->allocend = allocend; |
| 64 | |
| 65 | info->allocend = newallocend; |
| 66 | hlist_add_before(&fill->node, &info->node); |
| 67 | return newallocend; |
| 68 | } |
| 69 | } |
| 70 | return NULL; |
| 71 | } |
| 72 | |
| 73 | // Release space allocated with allocSpace() |
| 74 | static void |
| 75 | freeSpace(struct allocinfo_s *info) |
| 76 | { |
| 77 | struct allocinfo_s *next = container_of_or_null( |
| 78 | info->node.next, struct allocinfo_s, node); |
| 79 | if (next && next->allocend == info->data) |
| 80 | next->allocend = info->allocend; |
| 81 | hlist_del(&info->node); |
| 82 | } |
| 83 | |
| 84 | // Add new memory to a zone |
| 85 | static void |
| 86 | addSpace(struct zone_s *zone, void *start, void *end) |
| 87 | { |
| 88 | // Find position to add space |
| 89 | struct allocinfo_s *info; |
| 90 | struct hlist_node **pprev; |
| 91 | hlist_for_each_entry_pprev(info, pprev, &zone->head, node) { |
| 92 | if (info->data < start) |
| 93 | break; |
| 94 | } |
| 95 | |
| 96 | // Add space using temporary allocation info. |
| 97 | struct allocdetail_s tempdetail; |
| 98 | tempdetail.datainfo.data = tempdetail.datainfo.dataend = start; |
| 99 | tempdetail.datainfo.allocend = end; |
| 100 | hlist_add(&tempdetail.datainfo.node, pprev); |
| 101 | |
| 102 | // Allocate final allocation info. |
| 103 | struct allocdetail_s *detail = allocSpace( |
| 104 | &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL); |
| 105 | if (!detail) { |
| 106 | detail = allocSpace(&ZoneTmpLow, sizeof(*detail) |
| 107 | , MALLOC_MIN_ALIGN, NULL); |
| 108 | if (!detail) { |
| 109 | hlist_del(&tempdetail.datainfo.node); |
| 110 | warn_noalloc(); |
| 111 | return; |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | // Replace temp alloc space with final alloc space |
| 116 | pprev = tempdetail.datainfo.node.pprev; |
| 117 | hlist_del(&tempdetail.datainfo.node); |
| 118 | memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo)); |
| 119 | detail->handle = MALLOC_DEFAULT_HANDLE; |
| 120 | hlist_add(&detail->datainfo.node, pprev); |
| 121 | } |
| 122 | |
| 123 | // Search all zones for an allocation obtained from allocSpace() |
| 124 | static struct allocinfo_s * |
| 125 | findAlloc(void *data) |
| 126 | { |
| 127 | int i; |
| 128 | for (i=0; i<ARRAY_SIZE(Zones); i++) { |
| 129 | struct allocinfo_s *info; |
| 130 | hlist_for_each_entry(info, &Zones[i]->head, node) { |
| 131 | if (info->data == data) |
| 132 | return info; |
| 133 | } |
| 134 | } |
| 135 | return NULL; |
| 136 | } |
| 137 | |
| 138 | // Return the last sentinal node of a zone |
| 139 | static struct allocinfo_s * |
| 140 | findLast(struct zone_s *zone) |
| 141 | { |
| 142 | struct allocinfo_s *info, *last = NULL; |
| 143 | hlist_for_each_entry(info, &zone->head, node) { |
| 144 | last = info; |
| 145 | } |
| 146 | return last; |
| 147 | } |
| 148 | |
| 149 | |
| 150 | /**************************************************************** |
| 151 | * ebda movement |
| 152 | ****************************************************************/ |
| 153 | |
| 154 | // Move ebda |
| 155 | static int |
| 156 | relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size) |
| 157 | { |
| 158 | u32 lowram = GET_BDA(mem_size_kb) * 1024; |
| 159 | if (oldebda != lowram) |
| 160 | // EBDA isn't at end of ram - give up. |
| 161 | return -1; |
| 162 | |
| 163 | // Do copy |
| 164 | memmove((void*)newebda, (void*)oldebda, ebda_size * 1024); |
| 165 | |
| 166 | // Update indexes |
| 167 | dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda); |
| 168 | SET_BDA(mem_size_kb, newebda / 1024); |
| 169 | SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda)); |
| 170 | return 0; |
| 171 | } |
| 172 | |
| 173 | // Support expanding the ZoneLow dynamically. |
| 174 | static void * |
| 175 | zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill) |
| 176 | { |
| 177 | // Make sure to not move ebda while an optionrom is running. |
| 178 | if (unlikely(wait_preempt())) { |
| 179 | void *data = allocSpace(&ZoneLow, size, align, fill); |
| 180 | if (data) |
| 181 | return data; |
| 182 | } |
| 183 | |
| 184 | struct allocinfo_s *info = findLast(&ZoneLow); |
| 185 | if (!info) |
| 186 | return NULL; |
| 187 | u32 oldpos = (u32)info->allocend; |
| 188 | u32 newpos = ALIGN_DOWN(oldpos - size, align); |
| 189 | u32 bottom = (u32)info->dataend; |
| 190 | if (newpos >= bottom && newpos <= oldpos) |
| 191 | // Space already present. |
| 192 | return allocSpace(&ZoneLow, size, align, fill); |
| 193 | u16 ebda_seg = get_ebda_seg(); |
| 194 | u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0); |
| 195 | u8 ebda_size = GET_EBDA(ebda_seg, size); |
| 196 | u32 ebda_end = ebda_pos + ebda_size * 1024; |
| 197 | if (ebda_end != bottom) |
| 198 | // Something else is after ebda - can't use any existing space. |
| 199 | newpos = ALIGN_DOWN(ebda_end - size, align); |
| 200 | u32 newbottom = ALIGN_DOWN(newpos, 1024); |
| 201 | u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024); |
| 202 | if (newebda < BUILD_EBDA_MINIMUM) |
| 203 | // Not enough space. |
| 204 | return NULL; |
| 205 | |
| 206 | // Move ebda |
| 207 | int ret = relocate_ebda(newebda, ebda_pos, ebda_size); |
| 208 | if (ret) |
| 209 | return NULL; |
| 210 | |
| 211 | // Update zone |
| 212 | if (ebda_end == bottom) { |
| 213 | info->data = (void*)newbottom; |
| 214 | info->dataend = (void*)newbottom; |
| 215 | } else |
| 216 | addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end); |
| 217 | |
| 218 | return allocSpace(&ZoneLow, size, align, fill); |
| 219 | } |
| 220 | |
| 221 | |
| 222 | /**************************************************************** |
| 223 | * tracked memory allocations |
| 224 | ****************************************************************/ |
| 225 | |
| 226 | // Allocate memory from the given zone and track it as a PMM allocation |
| 227 | void * __malloc |
| 228 | _malloc(struct zone_s *zone, u32 handle, u32 size, u32 align) |
| 229 | { |
| 230 | ASSERT32FLAT(); |
| 231 | if (!size) |
| 232 | return NULL; |
| 233 | |
| 234 | // Find and reserve space for bookkeeping. |
| 235 | struct allocdetail_s *detail = allocSpace( |
| 236 | &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL); |
| 237 | if (!detail) { |
| 238 | detail = allocSpace(&ZoneTmpLow, sizeof(*detail) |
| 239 | , MALLOC_MIN_ALIGN, NULL); |
| 240 | if (!detail) |
| 241 | return NULL; |
| 242 | } |
| 243 | |
| 244 | // Find and reserve space for main allocation |
| 245 | void *data = allocSpace(zone, size, align, &detail->datainfo); |
| 246 | if (!CONFIG_MALLOC_UPPERMEMORY && !data && zone == &ZoneLow) |
| 247 | data = zonelow_expand(size, align, &detail->datainfo); |
| 248 | if (!data) { |
| 249 | freeSpace(&detail->detailinfo); |
| 250 | return NULL; |
| 251 | } |
| 252 | |
| 253 | dprintf(8, "_malloc zone=%p handle=%x size=%d align=%x ret=%p (detail=%p)\n" |
| 254 | , zone, handle, size, align, data, detail); |
| 255 | detail->handle = handle; |
| 256 | |
| 257 | return data; |
| 258 | } |
| 259 | |
| 260 | // Free a data block allocated with _malloc |
| 261 | int |
| 262 | _free(void *data) |
| 263 | { |
| 264 | ASSERT32FLAT(); |
| 265 | struct allocinfo_s *info = findAlloc(data); |
| 266 | if (!info || data == (void*)info || data == info->dataend) |
| 267 | return -1; |
| 268 | struct allocdetail_s *detail = container_of( |
| 269 | info, struct allocdetail_s, datainfo); |
| 270 | dprintf(8, "_free %p (detail=%p)\n", data, detail); |
| 271 | freeSpace(info); |
| 272 | freeSpace(&detail->detailinfo); |
| 273 | return 0; |
| 274 | } |
| 275 | |
| 276 | // Find the amount of free space in a given zone. |
| 277 | u32 |
| 278 | malloc_getspace(struct zone_s *zone) |
| 279 | { |
| 280 | // XXX - doesn't account for ZoneLow being able to grow. |
| 281 | // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS |
| 282 | u32 maxspace = 0; |
| 283 | struct allocinfo_s *info; |
| 284 | hlist_for_each_entry(info, &zone->head, node) { |
| 285 | u32 space = info->allocend - info->dataend; |
| 286 | if (space > maxspace) |
| 287 | maxspace = space; |
| 288 | } |
| 289 | |
| 290 | if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow) |
| 291 | return maxspace; |
| 292 | // Account for space needed for PMM tracking. |
| 293 | u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN); |
| 294 | if (maxspace <= reserve) |
| 295 | return 0; |
| 296 | return maxspace - reserve; |
| 297 | } |
| 298 | |
| 299 | // Find the data block allocated with _malloc with a given handle. |
| 300 | void * |
| 301 | malloc_find(u32 handle) |
| 302 | { |
| 303 | int i; |
| 304 | for (i=0; i<ARRAY_SIZE(Zones); i++) { |
| 305 | struct allocinfo_s *info; |
| 306 | hlist_for_each_entry(info, &Zones[i]->head, node) { |
| 307 | if (info->data != (void*)info) |
| 308 | continue; |
| 309 | struct allocdetail_s *detail = container_of( |
| 310 | info, struct allocdetail_s, detailinfo); |
| 311 | if (detail->handle == handle) |
| 312 | return detail->datainfo.data; |
| 313 | } |
| 314 | } |
| 315 | return NULL; |
| 316 | } |
| 317 | |
| 318 | |
| 319 | /**************************************************************** |
| 320 | * 0xc0000-0xf0000 management |
| 321 | ****************************************************************/ |
| 322 | |
| 323 | static u32 RomEnd = BUILD_ROM_START; |
| 324 | static struct allocinfo_s *RomBase; |
| 325 | |
| 326 | #define OPROM_HEADER_RESERVE 16 |
| 327 | |
| 328 | // Return the maximum memory position option roms may use. |
| 329 | u32 |
| 330 | rom_get_max(void) |
| 331 | { |
| 332 | if (CONFIG_MALLOC_UPPERMEMORY) |
| 333 | return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE |
| 334 | , OPTION_ROM_ALIGN); |
Kevin O'Connor | b94170c | 2013-12-06 13:52:16 -0500 | [diff] [blame^] | 335 | extern u8 final_readonly_start[]; |
| 336 | return (u32)final_readonly_start; |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 337 | } |
| 338 | |
| 339 | // Return the end of the last deployed option rom. |
| 340 | u32 |
| 341 | rom_get_last(void) |
| 342 | { |
| 343 | return RomEnd; |
| 344 | } |
| 345 | |
| 346 | // Request space for an optionrom in 0xc0000-0xf0000 area. |
| 347 | struct rom_header * |
| 348 | rom_reserve(u32 size) |
| 349 | { |
| 350 | u32 newend = ALIGN(RomEnd + size, OPTION_ROM_ALIGN); |
| 351 | if (newend > rom_get_max()) |
| 352 | return NULL; |
| 353 | if (CONFIG_MALLOC_UPPERMEMORY) { |
| 354 | if (newend < (u32)zonelow_base) |
| 355 | newend = (u32)zonelow_base; |
| 356 | RomBase->data = RomBase->dataend = (void*)newend + OPROM_HEADER_RESERVE; |
| 357 | } |
| 358 | return (void*)RomEnd; |
| 359 | } |
| 360 | |
| 361 | // Confirm space as in use by an optionrom. |
| 362 | int |
| 363 | rom_confirm(u32 size) |
| 364 | { |
| 365 | void *new = rom_reserve(size); |
| 366 | if (!new) { |
| 367 | warn_noalloc(); |
| 368 | return -1; |
| 369 | } |
| 370 | RomEnd = ALIGN(RomEnd + size, OPTION_ROM_ALIGN); |
| 371 | return 0; |
| 372 | } |
| 373 | |
| 374 | |
| 375 | /**************************************************************** |
| 376 | * Setup |
| 377 | ****************************************************************/ |
| 378 | |
| 379 | void |
| 380 | malloc_preinit(void) |
| 381 | { |
| 382 | ASSERT32FLAT(); |
| 383 | dprintf(3, "malloc preinit\n"); |
| 384 | |
| 385 | // Don't declare any memory between 0xa0000 and 0x100000 |
| 386 | add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); |
| 387 | |
| 388 | // Mark known areas as reserved. |
| 389 | add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); |
| 390 | |
| 391 | // Populate temp high ram |
| 392 | u32 highram = 0; |
| 393 | int i; |
| 394 | for (i=e820_count-1; i>=0; i--) { |
| 395 | struct e820entry *en = &e820_list[i]; |
| 396 | u64 end = en->start + en->size; |
| 397 | if (end < 1024*1024) |
| 398 | break; |
| 399 | if (en->type != E820_RAM || end > 0xffffffff) |
| 400 | continue; |
| 401 | u32 s = en->start, e = end; |
| 402 | if (!highram) { |
| 403 | u32 newe = ALIGN_DOWN(e - BUILD_MAX_HIGHTABLE, MALLOC_MIN_ALIGN); |
| 404 | if (newe <= e && newe >= s) { |
| 405 | highram = newe; |
| 406 | e = newe; |
| 407 | } |
| 408 | } |
| 409 | addSpace(&ZoneTmpHigh, (void*)s, (void*)e); |
| 410 | } |
| 411 | |
| 412 | // Populate regions |
| 413 | addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM); |
| 414 | if (highram) { |
| 415 | addSpace(&ZoneHigh, (void*)highram |
| 416 | , (void*)highram + BUILD_MAX_HIGHTABLE); |
| 417 | add_e820(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | void |
| 422 | csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size) |
| 423 | { |
| 424 | ASSERT32FLAT(); |
| 425 | |
| 426 | if (hi_pmm_size > BUILD_MAX_HIGHTABLE) { |
| 427 | void *hi_pmm_end = (void *)hi_pmm + hi_pmm_size; |
| 428 | addSpace(&ZoneTmpHigh, (void *)hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE); |
| 429 | addSpace(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end); |
| 430 | } else { |
| 431 | addSpace(&ZoneTmpHigh, (void *)hi_pmm, (void *)hi_pmm + hi_pmm_size); |
| 432 | } |
| 433 | addSpace(&ZoneTmpLow, (void *)low_pmm, (void *)low_pmm + low_pmm_size); |
| 434 | } |
| 435 | |
| 436 | u32 LegacyRamSize VARFSEG; |
| 437 | |
| 438 | // Calculate the maximum ramsize (less than 4gig) from e820 map. |
| 439 | static void |
| 440 | calcRamSize(void) |
| 441 | { |
| 442 | u32 rs = 0; |
| 443 | int i; |
| 444 | for (i=e820_count-1; i>=0; i--) { |
| 445 | struct e820entry *en = &e820_list[i]; |
| 446 | u64 end = en->start + en->size; |
| 447 | u32 type = en->type; |
| 448 | if (end <= 0xffffffff && (type == E820_ACPI || type == E820_RAM)) { |
| 449 | rs = end; |
| 450 | break; |
| 451 | } |
| 452 | } |
| 453 | LegacyRamSize = rs >= 1024*1024 ? rs : 1024*1024; |
| 454 | } |
| 455 | |
| 456 | // Update pointers after code relocation. |
| 457 | void |
| 458 | malloc_init(void) |
| 459 | { |
| 460 | ASSERT32FLAT(); |
| 461 | dprintf(3, "malloc init\n"); |
| 462 | |
| 463 | if (CONFIG_RELOCATE_INIT) { |
| 464 | // Fixup malloc pointers after relocation |
| 465 | int i; |
| 466 | for (i=0; i<ARRAY_SIZE(Zones); i++) { |
| 467 | struct zone_s *zone = Zones[i]; |
| 468 | if (zone->head.first) |
| 469 | zone->head.first->pprev = &zone->head.first; |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | // Initialize low-memory region |
| 474 | extern u8 varlow_start[], varlow_end[], final_varlow_start[]; |
| 475 | memmove(final_varlow_start, varlow_start, varlow_end - varlow_start); |
| 476 | if (CONFIG_MALLOC_UPPERMEMORY) { |
| 477 | addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE |
| 478 | , final_varlow_start); |
| 479 | RomBase = findLast(&ZoneLow); |
| 480 | } else { |
| 481 | addSpace(&ZoneLow, (void*)ALIGN_DOWN((u32)final_varlow_start, 1024) |
| 482 | , final_varlow_start); |
| 483 | } |
| 484 | |
| 485 | // Add space available in f-segment to ZoneFSeg |
| 486 | extern u8 zonefseg_start[], zonefseg_end[]; |
| 487 | memset(zonefseg_start, 0, zonefseg_end - zonefseg_start); |
| 488 | addSpace(&ZoneFSeg, zonefseg_start, zonefseg_end); |
| 489 | |
| 490 | calcRamSize(); |
| 491 | } |
| 492 | |
| 493 | void |
| 494 | malloc_prepboot(void) |
| 495 | { |
| 496 | ASSERT32FLAT(); |
| 497 | dprintf(3, "malloc finalize\n"); |
| 498 | |
| 499 | u32 base = rom_get_max(); |
| 500 | memset((void*)RomEnd, 0, base-RomEnd); |
| 501 | if (CONFIG_MALLOC_UPPERMEMORY) { |
| 502 | // Place an optionrom signature around used low mem area. |
| 503 | struct rom_header *dummyrom = (void*)base; |
| 504 | dummyrom->signature = OPTION_ROM_SIGNATURE; |
| 505 | int size = (BUILD_BIOS_ADDR - base) / 512; |
| 506 | dummyrom->size = (size > 255) ? 255 : size; |
| 507 | } |
| 508 | |
| 509 | // Reserve more low-mem if needed. |
| 510 | u32 endlow = GET_BDA(mem_size_kb)*1024; |
| 511 | add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED); |
| 512 | |
| 513 | // Clear unused f-seg ram. |
| 514 | struct allocinfo_s *info = findLast(&ZoneFSeg); |
| 515 | memset(info->dataend, 0, info->allocend - info->dataend); |
| 516 | dprintf(1, "Space available for UMB: %x-%x, %x-%x\n" |
| 517 | , RomEnd, base, (u32)info->dataend, (u32)info->allocend); |
| 518 | |
| 519 | // Give back unused high ram. |
| 520 | info = findLast(&ZoneHigh); |
| 521 | if (info) { |
| 522 | u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE); |
| 523 | add_e820((u32)info->dataend, giveback, E820_RAM); |
| 524 | dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback); |
| 525 | } |
| 526 | |
| 527 | calcRamSize(); |
| 528 | } |