[app][uefi] Place linux kernel at identity mapped virtual memory addresses

This commit is contained in:
Kelvin Zhang
2024-08-20 12:31:06 -07:00
parent 253e3099ec
commit 347db09959
6 changed files with 101 additions and 35 deletions

View File

@@ -259,7 +259,7 @@ void vmm_context_switch(vmm_aspace_t *oldspace, vmm_aspace_t *newaspace);
/* set the current user aspace as active on the current thread.
NULL is a valid argument, which unmaps the current user address space */
void vmm_set_active_aspace(vmm_aspace_t *aspace);
vmm_aspace_t* vmm_set_active_aspace(vmm_aspace_t *aspace);
__END_CDECLS

View File

@@ -12,6 +12,7 @@
#include <lk/err.h>
#include <lk/trace.h>
#include <string.h>
#include "kernel/thread.h"
#include "vm_priv.h"
#define LOCAL_TRACE 0
@@ -751,21 +752,24 @@ void vmm_context_switch(vmm_aspace_t *oldspace, vmm_aspace_t *newaspace) {
arch_mmu_context_switch(newaspace ? &newaspace->arch_aspace : NULL);
}
void vmm_set_active_aspace(vmm_aspace_t *aspace) {
vmm_aspace_t* vmm_set_active_aspace(vmm_aspace_t *aspace) {
LTRACEF("aspace %p\n", aspace);
thread_t *t = get_current_thread();
DEBUG_ASSERT(t);
if (aspace == t->aspace)
return;
return aspace;
/* grab the thread lock and switch to the new address space */
THREAD_LOCK(state);
vmm_aspace_t *old = t->aspace;
t->aspace = aspace;
vmm_context_switch(old, t->aspace);
if (old != aspace) {
t->aspace = aspace;
vmm_context_switch(old, t->aspace);
}
THREAD_UNLOCK(state);
return old;
}
static void dump_region(const vmm_region_t *r) {

View File

@@ -22,6 +22,79 @@
#include <stdlib.h>
#include <string.h>
static vmm_aspace_t *old_aspace = nullptr;
vmm_aspace_t *set_boot_aspace() {
static vmm_aspace_t *aspace = nullptr;
if (aspace == nullptr) {
auto err = vmm_create_aspace(&aspace, "linux_kernel", 0);
if (err) {
printf("Failed to create address space for linux kernel %d\n", err);
return nullptr;
}
old_aspace = vmm_set_active_aspace(aspace);
}
return aspace;
}
void restore_aspace() { vmm_set_active_aspace(old_aspace); }
void *identity_map(void *addr, size_t size) {
size = ROUNDUP(size, PAGE_SIZE);
auto vaddr = reinterpret_cast<vaddr_t>(addr);
paddr_t pa{};
uint flags{};
auto aspace = set_boot_aspace();
auto err = arch_mmu_query(&aspace->arch_aspace, vaddr, &pa, &flags);
if (err) {
printf("Failed to query physical address for memory 0x%p\n", addr);
return nullptr;
}
err = arch_mmu_unmap(&aspace->arch_aspace, vaddr, size / PAGE_SIZE);
if (err) {
printf("Failed to unmap virtual address 0x%lx\n", vaddr);
return nullptr;
}
arch_mmu_map(&aspace->arch_aspace, pa, pa, size / PAGE_SIZE, flags);
if (err) {
printf("Failed to identity map physical address 0x%lx\n", pa);
return nullptr;
}
printf("Identity mapped physical address 0x%lx flags 0x%x\n", pa, flags);
return reinterpret_cast<void *>(pa);
}
void *alloc_page(size_t size, size_t align_log2) {
auto aspace = set_boot_aspace();
void *vptr{};
status_t err = vmm_alloc_contiguous(aspace, "uefi_program", size, &vptr,
align_log2, 0, 0);
if (err) {
printf("Failed to allocate memory for uefi program %d\n", err);
return nullptr;
}
return identity_map(vptr, size);
}
void *alloc_page(void *addr, size_t size, size_t align_log2) {
if (addr == nullptr) {
return alloc_page(size, align_log2);
}
auto err =
vmm_alloc_contiguous(set_boot_aspace(), "uefi_program", size, &addr,
align_log2, VMM_FLAG_VALLOC_SPECIFIC, 0);
if (err) {
printf(
"Failed to allocate memory for uefi program @ fixed address 0x%p %d , "
"falling back to non-fixed allocation\n",
addr, err);
return alloc_page(size, align_log2);
}
return identity_map(addr, size);
}
namespace {
EfiStatus unload(EfiHandle handle) { return SUCCESS; }
@@ -34,7 +107,7 @@ bool guid_eq(const EfiGuid *a, const EfiGuid &b) {
return memcmp(a, &b, sizeof(*a)) == 0;
}
EfiStatus handle_protocol(const EfiHandle handle, const EfiGuid *protocol,
EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol,
void **intf) {
if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) {
printf("handle_protocol(%p, LOADED_IMAGE_PROTOCOL_GUID, %p);\n", handle,
@@ -115,6 +188,13 @@ EfiStatus get_memory_map(size_t *memory_map_size,
memory_map[i].virtual_start = region->base;
memory_map[i].physical_start = memory_map[i].virtual_start;
memory_map[i].number_of_pages = region->size / PAGE_SIZE;
paddr_t pa{};
uint flags{};
status_t err =
arch_mmu_query(&aspace->arch_aspace, region->base, &pa, &flags);
if (err >= 0) {
memory_map[i].physical_start = pa;
}
i++;
}

View File

@@ -17,7 +17,9 @@
#ifndef __BOOT_SERVICE_PROVIDER_
#define __BOOT_SERVICE_PROVIDER_
#include "arch/defines.h"
#include "boot_service.h"
#include "kernel/vm.h"
#include "system_table.h"
void setup_boot_service_table(EfiBootService *service);
@@ -90,5 +92,9 @@ struct EFI_LOADED_IMAGE_PROTOCOL {
};
static constexpr size_t EFI_LOADED_IMAGE_PROTOCOL_REVISION = 0x1000;
vmm_aspace_t *set_boot_aspace();
void *alloc_page(void *addr, size_t size, size_t align_log2 = PAGE_SIZE_SHIFT);
void *alloc_page(size_t size, size_t align_log2 = PAGE_SIZE_SHIFT);
#endif

View File

@@ -64,7 +64,7 @@ using EfiTimerDelay = enum EFI_TIMER_DELAY {
TIMER_RELATIVE
};
using EFI_MEMORY_TYPE = enum {
enum EFI_MEMORY_TYPE {
RESERVED_MEMORY_TYPE,
LOADER_CODE,
LOADER_DATA,

View File

@@ -1,3 +1,4 @@
#include "arch/mmu.h"
#include "boot_service.h"
#include "boot_service_provider.h"
#include "defer.h"
@@ -28,32 +29,6 @@ constexpr auto EFI_SYSTEM_TABLE_SIGNATURE =
using EfiEntry = int (*)(void *, struct EfiSystemTable *);
void *alloc_page(size_t size) {
void *vptr{};
status_t err =
vmm_alloc(vmm_get_kernel_aspace(), "uefi_program", size, &vptr, 0, 0, 0);
if (err) {
printf("Failed to allocate memory for uefi program %d\n", err);
return nullptr;
}
return vptr;
}
void *alloc_page(void *addr, size_t size) {
if (addr == nullptr) {
return alloc_page(size);
}
auto err = vmm_alloc(vmm_get_kernel_aspace(), "uefi_program", size, &addr,
PAGE_SIZE_SHIFT, VMM_FLAG_VALLOC_SPECIFIC, 0);
if (err) {
printf("Failed to allocate memory for uefi program @ fixed address %p %d , "
"falling back to non-fixed allocation\n",
addr, err);
return alloc_page(size);
}
return addr;
}
template <typename T> void fill(T *data, size_t skip, uint8_t begin = 0) {
auto ptr = reinterpret_cast<char *>(data);
for (size_t i = 0; i < sizeof(T); i++) {
@@ -265,8 +240,9 @@ int load_sections_and_execute(bdev_t *dev,
const auto &last_section = section_header[sections - 1];
const auto virtual_size =
last_section.VirtualAddress + last_section.Misc.VirtualSize;
const auto image_base = reinterpret_cast<char *>(alloc_page(
reinterpret_cast<void *>(optional_header->ImageBase), virtual_size));
const auto image_base = reinterpret_cast<char *>(
alloc_page(reinterpret_cast<void *>(optional_header->ImageBase),
virtual_size, 21 /* Kernel requires 2MB alignment */));
if (image_base == nullptr) {
return -7;
}