mmu: Actually read multiboot mmap data
This commit is contained in:
parent
9037902717
commit
04b21aed13
@ -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();
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user