133 lines
3.3 KiB
C
133 lines
3.3 KiB
C
/*
|
|
* Copyright (c) 2019 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <string.h>
|
|
#include <zephyr/arch/x86/multiboot.h>
|
|
#include <zephyr/arch/x86/memmap.h>
|
|
|
|
struct multiboot_info multiboot_info;
|
|
|
|
/*
|
|
* called very early in the boot process to fetch data out of the multiboot
|
|
* info struct. we need to grab the relevant data before any dynamic memory
|
|
* allocation takes place, lest the struct itself or any data it points to
|
|
* be overwritten before we read it.
|
|
*/
|
|
|
|
static inline void clear_memmap(int index)
|
|
{
|
|
while (index < CONFIG_X86_MEMMAP_ENTRIES) {
|
|
x86_memmap[index].type = X86_MEMMAP_ENTRY_UNUSED;
|
|
++index;
|
|
}
|
|
}
|
|
|
|
void z_multiboot_init(struct multiboot_info *info_pa)
|
|
{
|
|
struct multiboot_info *info;
|
|
|
|
#if defined(CONFIG_ARCH_MAPS_ALL_RAM) || !defined(CONFIG_X86_MMU)
|
|
/*
|
|
* Since the struct from bootloader resides in memory
|
|
* and all memory is mapped, there is no need to
|
|
* manually map it before accessing.
|
|
*
|
|
* Without MMU, all memory are identity-mapped already
|
|
* so there is no need to map them again.
|
|
*/
|
|
info = info_pa;
|
|
#else
|
|
z_phys_map((uint8_t **)&info, POINTER_TO_UINT(info_pa),
|
|
sizeof(*info_pa), K_MEM_CACHE_NONE);
|
|
#endif /* CONFIG_ARCH_MAPS_ALL_RAM */
|
|
|
|
if (info == NULL) {
|
|
return;
|
|
}
|
|
|
|
memcpy(&multiboot_info, info, sizeof(*info));
|
|
|
|
#ifdef CONFIG_MULTIBOOT_MEMMAP
|
|
/*
|
|
* If the extended map (basically, the equivalent of
|
|
* the BIOS E820 map) is available, then use that.
|
|
*/
|
|
|
|
if ((info->flags & MULTIBOOT_INFO_FLAGS_MMAP) &&
|
|
(x86_memmap_source < X86_MEMMAP_SOURCE_MULTIBOOT_MMAP)) {
|
|
uintptr_t address;
|
|
uintptr_t address_end;
|
|
struct multiboot_mmap *mmap;
|
|
int index = 0;
|
|
uint32_t type;
|
|
|
|
#if defined(CONFIG_ARCH_MAPS_ALL_RAM) || !defined(CONFIG_X86_MMU)
|
|
address = info->mmap_addr;
|
|
#else
|
|
uint8_t *address_va;
|
|
|
|
z_phys_map(&address_va, info->mmap_addr, info->mmap_length,
|
|
K_MEM_CACHE_NONE);
|
|
|
|
address = POINTER_TO_UINT(address_va);
|
|
#endif /* CONFIG_ARCH_MAPS_ALL_RAM */
|
|
|
|
address_end = address + info->mmap_length;
|
|
|
|
while ((address < address_end) &&
|
|
(index < CONFIG_X86_MEMMAP_ENTRIES)) {
|
|
mmap = UINT_TO_POINTER(address);
|
|
|
|
x86_memmap[index].base = mmap->base;
|
|
x86_memmap[index].length = mmap->length;
|
|
|
|
switch (mmap->type) {
|
|
case MULTIBOOT_MMAP_RAM:
|
|
type = X86_MEMMAP_ENTRY_RAM;
|
|
break;
|
|
case MULTIBOOT_MMAP_ACPI:
|
|
type = X86_MEMMAP_ENTRY_ACPI;
|
|
break;
|
|
case MULTIBOOT_MMAP_NVS:
|
|
type = X86_MEMMAP_ENTRY_NVS;
|
|
break;
|
|
case MULTIBOOT_MMAP_DEFECTIVE:
|
|
type = X86_MEMMAP_ENTRY_DEFECTIVE;
|
|
break;
|
|
default:
|
|
type = X86_MEMMAP_ENTRY_UNKNOWN;
|
|
}
|
|
|
|
x86_memmap[index].type = type;
|
|
++index;
|
|
address += mmap->size + sizeof(mmap->size);
|
|
}
|
|
|
|
x86_memmap_source = X86_MEMMAP_SOURCE_MULTIBOOT_MMAP;
|
|
clear_memmap(index);
|
|
}
|
|
|
|
/* If no extended map is available, fall back to the basic map. */
|
|
|
|
if ((info->flags & MULTIBOOT_INFO_FLAGS_MEM) &&
|
|
(x86_memmap_source < X86_MEMMAP_SOURCE_MULTIBOOT_MEM)) {
|
|
x86_memmap[0].base = 0;
|
|
x86_memmap[0].length = info->mem_lower * 1024ULL;
|
|
x86_memmap[0].type = X86_MEMMAP_ENTRY_RAM;
|
|
|
|
if (CONFIG_X86_MEMMAP_ENTRIES > 1) {
|
|
x86_memmap[1].base = 1048576U; /* 1MB */
|
|
x86_memmap[1].length = info->mem_upper * 1024ULL;
|
|
x86_memmap[1].type = X86_MEMMAP_ENTRY_RAM;
|
|
clear_memmap(2);
|
|
}
|
|
|
|
x86_memmap_source = X86_MEMMAP_SOURCE_MULTIBOOT_MEM;
|
|
}
|
|
#endif /* CONFIG_MULTIBOOT_MEMMAP */
|
|
}
|