mmu: Actually read multiboot mmap data

This commit is contained in:
K. Lange 2021-09-12 22:40:29 +09:00
parent 9037902717
commit 04b21aed13
2 changed files with 62 additions and 46 deletions

View File

@ -21,6 +21,7 @@
#include <kernel/ramdisk.h>
#include <kernel/args.h>
#include <kernel/ksym.h>
#include <kernel/misc.h>
#include <kernel/arch/x86_64/ports.h>
#include <kernel/arch/x86_64/cmos.h>
@ -43,6 +44,8 @@ extern void serial_initialize(void);
extern void fbterm_initialize(void);
extern void pci_remap(void);
struct multiboot * mboot_struct = NULL;
#define EARLY_LOG_DEVICE 0x3F8
static size_t _early_log_write(size_t size, uint8_t * buffer) {
for (unsigned int i = 0; i < size; ++i) {
@ -56,52 +59,48 @@ static void early_log_initialize(void) {
printf_output = &_early_log_write;
}
static size_t memCount = 0;
static uintptr_t maxAddress = (uintptr_t)&end;
static uintptr_t highest_valid_address = 0;
static uintptr_t highest_kernel_address = (uintptr_t)&end;
static void multiboot_initialize(struct multiboot * mboot) {
/* Set memCount to 1M + high mem */
if (mboot->flags & MULTIBOOT_FLAG_MEM) {
/* mem_upper is in kibibytes and is one mebibyte less than
* actual available memory, so add that back in and multiply... */
memCount = (uintptr_t)mboot->mem_upper * 0x400 + 0x100000;
if (!(mboot->flags & MULTIBOOT_FLAG_MMAP)) {
printf("fatal: unable to boot without memory map from loader\n");
arch_fatal();
}
/**
* FIXME:
* The multiboot 0.6.96 spec actually says the upper_memory is at most
* the address of the first hole, minus 1MiB, so in theory there should
* not be any unavailable memory between 1MiB and mem_upper... that
* also technically means there might be even higher memory above that
* hole that we're missing... We should really be scanning the whole map
* to find the highest address of available memory, using that as our
* memory count, and then ensuring all of the holes are marked unavailable.
* but for now we'll just accept that there's a hole in lower memory and
* mem_upper is probably the total available physical RAM. That's probably
* good enough for 1GiB~4GiB cases...
*/
#if 0
printf("mem_upper = %#zx\n", mboot->mem_upper);
if (mboot->flags & MULTIBOOT_FLAG_MMAP) {
mboot_memmap_t * mmap = (void *)(uintptr_t)mboot->mmap_addr;
while ((uintptr_t)mmap < mboot->mmap_addr + mboot->mmap_length) {
printf(" 0x%016zx:0x%016zx %d (%s)\n", mmap->base_addr, mmap->length, mmap->type,
mmap->type == 1 ? "available" : (mmap->type == 2 ? "reserved" : "unknown")
);
mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uint32_t));
mboot_memmap_t * mmap = (void *)(uintptr_t)mboot->mmap_addr;
while ((uintptr_t)mmap < mboot->mmap_addr + mboot->mmap_length) {
if (mmap->type == 1 && mmap->length && mmap->base_addr + mmap->length - 1> highest_valid_address) {
highest_valid_address = mmap->base_addr + mmap->length - 1;
}
mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uint32_t));
}
#endif
if (mboot->flags & MULTIBOOT_FLAG_MODS) {
mboot_mod_t * mods = (mboot_mod_t *)(uintptr_t)mboot->mods_addr;
for (unsigned int i = 0; i < mboot->mods_count; ++i) {
uintptr_t addr = (uintptr_t)mods[i].mod_start + mods[i].mod_end;
if (addr > maxAddress) maxAddress = addr;
if (addr > highest_kernel_address) highest_kernel_address = addr;
}
}
/* Round the max address up a page */
maxAddress = (maxAddress + 0xFFF) & 0xFFFFffffFFFFf000;
highest_kernel_address = (highest_kernel_address + 0xFFF) & 0xFFFFffffFFFFf000;
}
void mboot_unmark_valid_memory(void) {
/* multiboot memory is now mapped high, if you want it. */
mboot_memmap_t * mmap = mmu_map_from_physical((uintptr_t)mboot_struct->mmap_addr);
size_t frames_marked = 0;
while ((uintptr_t)mmap < (uintptr_t)mmu_map_from_physical(mboot_struct->mmap_addr + mboot_struct->mmap_length)) {
if (mmap->type == 1) {
for (uintptr_t base = mmap->base_addr; base < mmap->base_addr + (mmap->length & 0xFFFFffffFFFFf000); base += 0x1000) {
mmu_frame_clear(base);
frames_marked++;
}
}
mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uint32_t));
}
}
static void symbols_install(void) {
@ -161,8 +160,6 @@ void fpu_initialize(void) {
: : : "rax");
}
struct multiboot * mboot_struct = NULL;
/**
* @brief Decompress compressed ramdisks and hand them to the ramdisk driver.
*
@ -253,12 +250,12 @@ int kmain(struct multiboot * mboot, uint32_t mboot_mag, void* esp) {
/* Parse multiboot data so we can get memory map, modules, command line, etc. */
multiboot_initialize(mboot);
/* memCount and maxAddress come from multiboot data */
mmu_init(memCount, maxAddress);
/* multiboot memory is now mapped high, if you want it. */
mboot_struct = mmu_map_from_physical((uintptr_t)mboot);
/* memCount and maxAddress come from multiboot data */
mmu_init(highest_valid_address, highest_kernel_address);
/* With the MMU initialized, set up things required for the scheduler. */
pat_initialize();
symbols_install();

View File

@ -19,7 +19,9 @@ extern void arch_tlb_shootdown(uintptr_t);
* bitmap page allocator for 4KiB pages
*/
static volatile uint32_t *frames;
static uint32_t nframes;
static size_t nframes;
static size_t total_memory = 0;
static size_t unavailable_memory = 0;
#define PAGE_SHIFT 12
#define PAGE_SIZE 0x1000UL
@ -55,7 +57,7 @@ static uint32_t nframes;
void mmu_frame_set(uintptr_t frame_addr) {
/* If the frame is within bounds... */
if (frame_addr < nframes * 4 * 0x400) {
if (frame_addr < nframes * PAGE_SIZE) {
uint64_t frame = frame_addr >> 12;
uint64_t index = INDEX_FROM_BIT(frame);
uint32_t offset = OFFSET_FROM_BIT(frame);
@ -66,7 +68,7 @@ void mmu_frame_set(uintptr_t frame_addr) {
void mmu_frame_clear(uintptr_t frame_addr) {
/* If the frame is within bounds... */
if (frame_addr < nframes * 4 * 0x400) {
if (frame_addr < nframes * PAGE_SIZE) {
uint64_t frame = frame_addr >> PAGE_SHIFT;
uint64_t index = INDEX_FROM_BIT(frame);
uint32_t offset = OFFSET_FROM_BIT(frame);
@ -76,7 +78,7 @@ void mmu_frame_clear(uintptr_t frame_addr) {
}
int mmu_frame_test(uintptr_t frame_addr) {
if (!(frame_addr < nframes * 4 * 0x400)) return 0;
if (!(frame_addr < nframes * PAGE_SIZE)) return 0;
uint64_t frame = frame_addr >> PAGE_SHIFT;
uint64_t index = INDEX_FROM_BIT(frame);
uint32_t offset = OFFSET_FROM_BIT(frame);
@ -516,12 +518,10 @@ size_t mmu_count_shm(union PML * from) {
/**
* @brief Return the total amount of usable memory.
*
* Just returns the number of frames in the bitmap allocator, times 4.
*
* @returns the total amount of usable memory in KiB.
*/
size_t mmu_total_memory(void) {
return nframes * 4;
return total_memory;
}
/**
@ -543,7 +543,7 @@ size_t mmu_used_memory(void) {
}
}
}
return ret * 4;
return ret * 4 - unavailable_memory;
}
/**
@ -721,7 +721,26 @@ void mmu_init(size_t memsize, uintptr_t firstFreePage) {
/* We are now in the new stuff. */
frames = (void*)((uintptr_t)KERNEL_HEAP_START);
memset((void*)frames, 0, bytesOfFrames);
memset((void*)frames, 0xFF, bytesOfFrames);
extern void mboot_unmark_valid_memory(void);
mboot_unmark_valid_memory();
/* Don't trust anything but our own bitmap... */
size_t unavail = 0, avail = 0;
for (size_t i = 0; i < INDEX_FROM_BIT(nframes); ++i) {
for (size_t j = 0; j < 32; ++j) {
uint32_t testFrame = (uint32_t)0x1 << j;
if (frames[i] & testFrame) {
unavail++;
} else {
avail++;
}
}
}
total_memory = avail * 4;
unavailable_memory = unavail * 4;
/* Now mark everything up to (firstFreePage + bytesOfFrames) as in use */
for (uintptr_t i = 0; i < firstFreePage + bytesOfFrames; i += PAGE_SIZE) {