123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /*
- * memory/main.c
- *
- * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <new_memory.h>
- #include <boot/multiboot.h>
- #define MULTIBOOT_LOAD_ADDRESS 0x00100000
- #define VIRTUAL_LOAD_ADDRESS 0x80000000
- extern void memory_init_mapping_hack(void);
- extern void memory_init_physical(memory_map_entry_t *mmap, size_t num_entries);
- extern void (*_end)();
- uintptr_t memory_metadata_base = MEMORY_METADATA_TOP;
- static int compare_map_entry(const void *p1, const void *p2)
- {
- memory_map_entry_t *a = (memory_map_entry_t*)p1;
- memory_map_entry_t *b = (memory_map_entry_t*)p2;
- if (a->address < b->address) return -1;
- else if (a->address > b->address) return 1;
- else return 0;
- }
- static size_t plot_memory_map(uintptr_t mboot_tags, size_t mboot_size, memory_map_entry_t *map, size_t max_entries)
- {
- multiboot_tag_t *mboot = (multiboot_tag_t*)(PAGE_ALIGN_UP((uintptr_t)&_end) + PAGE_OFFSET(mboot_tags)); // HACK
- size_t num_entries = 0;
- if (num_entries >= max_entries) return 0;
- map[num_entries++] = (memory_map_entry_t) {
- .address = MULTIBOOT_LOAD_ADDRESS,
- .length = PAGE_ALIGN_UP((uintptr_t)&_end - VIRTUAL_LOAD_ADDRESS),
- .status = PAGE_STATUS_ALLOCATED,
- };
- if (num_entries >= max_entries) return 0;
- map[num_entries++] = (memory_map_entry_t) {
- .address = PAGE_ALIGN(mboot_tags),
- .length = PAGE_ALIGN_UP(mboot_tags + mboot_size) - PAGE_ALIGN(mboot_tags),
- .status = PAGE_STATUS_ALLOCATED,
- };
- if (num_entries >= max_entries) return 0;
- map[num_entries++] = (memory_map_entry_t) { .address = 0, .length = 0x1000, .status = PAGE_STATUS_RESERVED };
- for (multiboot_tag_t *tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
- {
- switch (tag->type)
- {
- case MULTIBOOT_INFO_MEMORY_MAP:
- {
- multiboot_tag_mmap_t *mmap = (multiboot_tag_mmap_t*)tag;
- for (multiboot_mmap_entry_t *entry = (multiboot_mmap_entry_t*)(mmap + 1);
- (uintptr_t)entry < ((uintptr_t)mmap + mmap->size);
- entry = (multiboot_mmap_entry_t*)((uintptr_t)entry + mmap->entry_size))
- {
- if (entry->type == 5) continue;
- if (num_entries >= max_entries) return 0;
- map[num_entries++] = (memory_map_entry_t) {
- .address = PAGE_ALIGN(entry->base),
- .length = PAGE_ALIGN_UP(entry->base + entry->length) - PAGE_ALIGN(entry->base),
- .status = (entry->type == 1) ? PAGE_STATUS_FREE : PAGE_STATUS_RESERVED,
- };
- }
- break;
- }
- case MULTIBOOT_INFO_MODULES:
- {
- multiboot_tag_module_t *module = (multiboot_tag_module_t*)tag;
- if (num_entries >= max_entries) return 0;
- map[num_entries++] = (memory_map_entry_t) {
- .address = PAGE_ALIGN(module->mod_start),
- .length = PAGE_ALIGN_UP(module->mod_end) - PAGE_ALIGN(module->mod_start),
- .status = PAGE_STATUS_ALLOCATED,
- };
- break;
- }
- }
- }
- qsort(map, num_entries, sizeof(memory_map_entry_t), compare_map_entry);
- for (size_t i = 1; i < num_entries; i++)
- {
- uintptr_t current_end = map[i].address + map[i].length;
- uintptr_t previous_end = map[i - 1].address + map[i - 1].length;
- if (map[i].status > map[i - 1].status)
- {
- if (previous_end > current_end)
- {
- if (num_entries >= max_entries) return 0;
- memmove(&map[i + 2], &map[i + 1], (num_entries - i - 1) * sizeof(memory_map_entry_t));
- map[i + 1].address = current_end;
- map[i + 1].length = previous_end - current_end;
- map[i + 1].status = map[i - 1].status;
- num_entries++;
- }
- if (previous_end > map[i].address)
- {
- if (map[i - 1].length > previous_end - map[i].address)
- {
- map[i - 1].length -= previous_end - map[i].address;
- }
- else
- {
- memmove(&map[i - 1], &map[i], (num_entries - i) * sizeof(memory_map_entry_t));
- i -= 2;
- num_entries--;
- }
- }
- }
- else if (map[i].status < map[i - 1].status)
- {
- if (previous_end >= current_end)
- {
- memmove(&map[i], &map[i + 1], (num_entries - i - 1) * sizeof(memory_map_entry_t));
- i--;
- num_entries--;
- }
- else if (previous_end > map[i].address)
- {
- map[i].length -= previous_end - map[i].address;
- map[i].address = previous_end;
- }
- }
- else if (map[i].address <= previous_end)
- {
- map[i - 1].length = (current_end > previous_end ? current_end : previous_end) - map[i - 1].address;
- memmove(&map[i], &map[i + 1], (num_entries - i - 1) * sizeof(memory_map_entry_t));
- num_entries--;
- }
- }
- return num_entries;
- }
- void *memory_request_metadata_space(size_t count, size_t size)
- {
- memory_metadata_base -= count * size;
- if (memory_metadata_base % size) memory_metadata_base = size * (memory_metadata_base / size);
- return (void*)memory_metadata_base;
- }
- void new_memory_init(uintptr_t mboot_tags, size_t mboot_size)
- {
- cpu_max_physical_bits = 32; // No PAE for now
- memory_init_mapping_hack();
- size_t num_entries, max_entries = 1024;
- for (;;)
- {
- memory_map_entry_t map[max_entries];
- if ((num_entries = plot_memory_map(mboot_tags, mboot_size, map, max_entries)))
- {
- memory_init_physical(map, num_entries);
- break;
- }
- max_entries += max_entries;
- }
- area_t kernel_area = {
- .pages = memory_find_page_by_address(MULTIBOOT_LOAD_ADDRESS),
- .count = PAGE_NUMBER(PAGE_ALIGN_UP((uintptr_t)&_end - VIRTUAL_LOAD_ADDRESS)),
- };
- ASSERT(kernel_area.pages != NULL);
- memory_init_virtual(&kernel_area);
- }
|