From e6520f9064a89b143a2f5931fcad74cf3bcb0f14 Mon Sep 17 00:00:00 2001 From: David Karoly Date: Wed, 20 Oct 2021 18:48:38 +0200 Subject: [PATCH] boot/efi: generate memory map for arm Change-Id: I02a7f8c27187f6375dd4deeeaf3587dad1e3349c Reviewed-on: https://review.haiku-os.org/c/haiku/+/4631 Tested-by: Commit checker robot Reviewed-by: waddlesplash --- .../boot/platform/efi/arch/arm/arch_mmu.cpp | 206 +++++++++++++++++- .../boot/platform/efi/arch/arm/arch_start.cpp | 18 +- 2 files changed, 220 insertions(+), 4 deletions(-) diff --git a/src/system/boot/platform/efi/arch/arm/arch_mmu.cpp b/src/system/boot/platform/efi/arch/arm/arch_mmu.cpp index 9a86a8590b..67cd81e3ea 100644 --- a/src/system/boot/platform/efi/arch/arm/arch_mmu.cpp +++ b/src/system/boot/platform/efi/arch/arm/arch_mmu.cpp @@ -1,10 +1,212 @@ /* - * Copyright 2019-2020 Haiku, Inc. All rights reserved. + * Copyright 2019-2021 Haiku, Inc. All rights reserved. * Released under the terms of the MIT License. */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mmu.h" +#include "efi_platform.h" + + +static void +map_range(addr_t virt_addr, phys_addr_t phys_addr, size_t size, uint32_t flags) +{ + ASSERT_ALWAYS(insert_virtual_allocated_range(virt_addr, size) >= B_OK); +} + + +static void +build_physical_memory_list(size_t memory_map_size, + efi_memory_descriptor *memory_map, size_t descriptor_size, + uint32_t descriptor_version) +{ + addr_t addr = (addr_t)memory_map; + + gKernelArgs.num_physical_memory_ranges = 0; + + // First scan: Add all usable ranges + for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { + efi_memory_descriptor* entry = (efi_memory_descriptor *)(addr + i * descriptor_size); + switch (entry->Type) { + case EfiLoaderCode: + case EfiLoaderData: + entry->VirtualStart = entry->PhysicalStart; + break; + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: { + // Usable memory. + uint64_t base = entry->PhysicalStart; + uint64_t size = entry->NumberOfPages * B_PAGE_SIZE; + insert_physical_memory_range(base, size); + break; + } + case EfiACPIReclaimMemory: + // ACPI reclaim -- physical memory we could actually use later + break; + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + entry->VirtualStart = entry->PhysicalStart; + break; + case EfiMemoryMappedIO: + entry->VirtualStart = entry->PhysicalStart; + break; + } + } + + uint64_t initialPhysicalMemory = total_physical_memory(); + + // Second scan: Remove everything reserved that may overlap + for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { + efi_memory_descriptor* entry = (efi_memory_descriptor *)(addr + i * descriptor_size); + switch (entry->Type) { + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: + break; + default: + uint64_t base = entry->PhysicalStart; + uint64_t size = entry->NumberOfPages * B_PAGE_SIZE; + remove_physical_memory_range(base, size); + } + } + + gKernelArgs.ignored_physical_memory + += initialPhysicalMemory - total_physical_memory(); + + sort_address_ranges(gKernelArgs.physical_memory_range, + gKernelArgs.num_physical_memory_ranges); +} + + +static void +build_physical_allocated_list(size_t memory_map_size, + efi_memory_descriptor *memory_map, size_t descriptor_size, + uint32_t descriptor_version) +{ + addr_t addr = (addr_t)memory_map; + for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { + efi_memory_descriptor* entry = (efi_memory_descriptor *)(addr + i * descriptor_size); + switch (entry->Type) { + case EfiLoaderData: { + uint64_t base = entry->PhysicalStart; + uint64_t size = entry->NumberOfPages * B_PAGE_SIZE; + insert_physical_allocated_range(base, size); + break; + } + default: + ; + } + } + + sort_address_ranges(gKernelArgs.physical_allocated_range, + gKernelArgs.num_physical_allocated_ranges); +} + + void arch_mmu_init() { - // Stub +} + + +void +arch_mmu_post_efi_setup(size_t memory_map_size, + efi_memory_descriptor *memory_map, size_t descriptor_size, + uint32_t descriptor_version) +{ + build_physical_allocated_list(memory_map_size, memory_map, + descriptor_size, descriptor_version); + + // Switch EFI to virtual mode, using the kernel pmap. + // Something involving ConvertPointer might need to be done after this? + // http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES + //kRuntimeServices->SetVirtualAddressMap(memory_map_size, descriptor_size, + // descriptor_version, memory_map); + + dprintf("phys memory ranges:\n"); + for (uint32_t i = 0; i < gKernelArgs.num_physical_memory_ranges; i++) { + uint32_t start = (uint32_t)gKernelArgs.physical_memory_range[i].start; + uint32_t size = (uint32_t)gKernelArgs.physical_memory_range[i].size; + dprintf(" 0x%08x-0x%08x, length 0x%08x\n", + start, start + size, size); + } + + dprintf("allocated phys memory ranges:\n"); + for (uint32_t i = 0; i < gKernelArgs.num_physical_allocated_ranges; i++) { + uint32_t start = (uint32_t)gKernelArgs.physical_allocated_range[i].start; + uint32_t size = (uint32_t)gKernelArgs.physical_allocated_range[i].size; + dprintf(" 0x%08x-0x%08x, length 0x%08x\n", + start, start + size, size); + } + + dprintf("allocated virt memory ranges:\n"); + for (uint32_t i = 0; i < gKernelArgs.num_virtual_allocated_ranges; i++) { + uint32_t start = (uint32_t)gKernelArgs.virtual_allocated_range[i].start; + uint32_t size = (uint32_t)gKernelArgs.virtual_allocated_range[i].size; + dprintf(" 0x%08x-0x%08x, length 0x%08x\n", + start, start + size, size); + } +} + + +uint32_t +arch_mmu_generate_post_efi_page_tables(size_t memory_map_size, + efi_memory_descriptor *memory_map, size_t descriptor_size, + uint32_t descriptor_version) +{ + addr_t memory_map_addr = (addr_t)memory_map; + + build_physical_memory_list(memory_map_size, memory_map, + descriptor_size, descriptor_version); + + for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { + efi_memory_descriptor* entry = + (efi_memory_descriptor *)(memory_map_addr + i * descriptor_size); + switch (entry->Type) { + case EfiLoaderCode: + case EfiLoaderData: + map_range(entry->VirtualStart, entry->PhysicalStart, + entry->NumberOfPages * B_PAGE_SIZE, 0); + break; + default: + ; + } + } + + for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { + efi_memory_descriptor* entry = + (efi_memory_descriptor *)(memory_map_addr + i * descriptor_size); + if ((entry->Attribute & EFI_MEMORY_RUNTIME) != 0) + map_range(entry->VirtualStart, entry->PhysicalStart, + entry->NumberOfPages * B_PAGE_SIZE, 0); + } + + void* cookie = NULL; + addr_t vaddr; + phys_addr_t paddr; + size_t size; + while (mmu_next_region(&cookie, &vaddr, &paddr, &size)) { + map_range(vaddr, paddr, size, 0); + } + + // identity mapping for the debug uart + map_range(0x09000000, 0x09000000, B_PAGE_SIZE, 0); + + sort_address_ranges(gKernelArgs.virtual_allocated_range, + gKernelArgs.num_virtual_allocated_ranges); + + return 0; } diff --git a/src/system/boot/platform/efi/arch/arm/arch_start.cpp b/src/system/boot/platform/efi/arch/arm/arch_start.cpp index 17a25044f7..265c0ec9c7 100644 --- a/src/system/boot/platform/efi/arch/arm/arch_start.cpp +++ b/src/system/boot/platform/efi/arch/arm/arch_start.cpp @@ -14,6 +14,16 @@ extern "C" void arch_enter_kernel(struct kernel_args *kernelArgs, addr_t kernelEntry, addr_t kernelStackTop); +// From arch_mmu.cpp +extern void arch_mmu_post_efi_setup(size_t memory_map_size, + efi_memory_descriptor *memory_map, size_t descriptor_size, + uint32_t descriptor_version); + +extern uint32_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size, + efi_memory_descriptor *memory_map, size_t descriptor_size, + uint32_t descriptor_version); + + void arch_start_kernel(addr_t kernelEntry) { @@ -57,6 +67,10 @@ arch_start_kernel(addr_t kernelEntry) entry->VirtualStart, entry->Type, entry->Attribute); } + // Generate page tables for use after ExitBootServices. + arch_mmu_generate_post_efi_page_tables( + memory_map_size, memory_map, descriptor_size, descriptor_version); + // Attempt to fetch the memory map and exit boot services. // This needs to be done in a loop, as ExitBootServices can change the // memory map. @@ -86,8 +100,8 @@ arch_start_kernel(addr_t kernelEntry) } // Update EFI, generate final kernel physical memory map, etc. - //arch_mmu_post_efi_setup(memory_map_size, memory_map, - // descriptor_size, descriptor_version); + arch_mmu_post_efi_setup(memory_map_size, memory_map, + descriptor_size, descriptor_version); //smp_boot_other_cpus(final_pml4, kernelEntry);