blob: e9150195ad5b5142e15e5dda15605cfdc81e3fec [file] [log] [blame]
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <string.h>
#include <arch/x86/multiboot.h>
#include <arch/x86/memmap.h>
#ifdef CONFIG_MULTIBOOT_INFO
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)
{
if (info != NULL) {
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)) {
u32_t address = info->mmap_addr;
struct multiboot_mmap *mmap;
int index = 0;
u32_t type;
while ((address < (info->mmap_addr + info->mmap_length)) &&
(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 */
}
#ifdef CONFIG_MULTIBOOT_FRAMEBUF
#include <display/framebuf.h>
static struct framebuf_dev_data multiboot_framebuf_data = {
.width = CONFIG_MULTIBOOT_FRAMEBUF_X,
.height = CONFIG_MULTIBOOT_FRAMEBUF_Y
};
static int multiboot_framebuf_init(struct device *dev)
{
struct framebuf_dev_data *data = FRAMEBUF_DATA(dev);
struct multiboot_info *info = &multiboot_info;
if ((info->flags & MULTIBOOT_INFO_FLAGS_FB) &&
(info->fb_width >= CONFIG_MULTIBOOT_FRAMEBUF_X) &&
(info->fb_height >= CONFIG_MULTIBOOT_FRAMEBUF_Y) &&
(info->fb_bpp == 32) && (info->fb_addr_hi == 0)) {
/*
* We have a usable multiboot framebuffer - it is 32 bpp
* and at least as large as the requested dimensions. Compute
* the pitch and adjust the start address center our canvas.
*/
u16_t adj_x;
u16_t adj_y;
u32_t *buffer;
adj_x = info->fb_width - CONFIG_MULTIBOOT_FRAMEBUF_X;
adj_y = info->fb_height - CONFIG_MULTIBOOT_FRAMEBUF_Y;
data->pitch = (info->fb_pitch / 4) + adj_x;
adj_x /= 2;
adj_y /= 2;
buffer = (uint32_t *) (uintptr_t) info->fb_addr_lo;
buffer += adj_x;
buffer += adj_y * data->pitch;
data->buffer = buffer;
return 0;
} else {
return -ENOTSUP;
}
}
DEVICE_AND_API_INIT(multiboot_framebuf,
"FRAMEBUF",
multiboot_framebuf_init,
&multiboot_framebuf_data,
NULL,
PRE_KERNEL_1,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&framebuf_display_api);
#endif /* CONFIG_MULTIBOOT_FRAMEBUF */
#endif /* CONFIG_MULTIBOOT_INFO */