mirror of https://github.com/wolfSSL/wolfBoot.git
367 lines
10 KiB
C
367 lines
10 KiB
C
/* multiboot.c
|
|
*
|
|
* Copyright (C) 2025 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfBoot.
|
|
*
|
|
* wolfBoot is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfBoot is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#ifdef WOLFBOOT_MULTIBOOT2
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <printf.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <x86/hob.h>
|
|
#include <multiboot.h>
|
|
|
|
#ifdef WOLFBOOT_FSP
|
|
#include <stage2_params.h>
|
|
#endif
|
|
|
|
#define MB2_HEADER_MAX_OFF (32768 - 4)
|
|
#define MB2_HEADER_MAGIC 0xe85250d6
|
|
#define MB2_TAG_TYPE_INFO_REQ 1
|
|
#define MB2_REQ_TAG_BASIC_MEM_INFO 4
|
|
#define MB2_REQ_TAG_MEM_MAP 6
|
|
#define MB2_MEM_INFO_MEM_RAM 1
|
|
#define MB2_MEM_INFO_MEM_RESERVED 2
|
|
|
|
#ifdef DEBUG_MB2
|
|
#define MB2_DEBUG_PRINTF(...) wolfBoot_printf(__VA_ARGS__)
|
|
#else
|
|
#define MB2_DEBUG_PRINTF(...) do {} while(0)
|
|
#endif /* DEBUG_MB2 */
|
|
|
|
|
|
struct mb2_tag_info_req {
|
|
uint16_t type;
|
|
uint16_t flags;
|
|
uint32_t size;
|
|
uint32_t mbi_tag_types[];
|
|
};
|
|
|
|
struct mb2_tag {
|
|
uint16_t type;
|
|
uint16_t flags;
|
|
uint32_t size;
|
|
};
|
|
|
|
struct mb2_header {
|
|
uint32_t magic;
|
|
uint32_t architecture;
|
|
uint32_t header_length;
|
|
uint32_t checksum;
|
|
};
|
|
|
|
struct mb2_mem_map_entry {
|
|
uint64_t base_addr;
|
|
uint64_t length;
|
|
uint32_t type;
|
|
uint32_t reserved;
|
|
};
|
|
|
|
struct mb2_mem_map_header {
|
|
uint32_t type;
|
|
uint32_t size;
|
|
uint32_t entry_size;
|
|
uint32_t entry_version;
|
|
};
|
|
|
|
struct mb2_basic_memory_info {
|
|
uint32_t type;
|
|
uint32_t size;
|
|
uint32_t mem_lower;
|
|
uint32_t mem_upper;
|
|
};
|
|
|
|
struct mb2_boot_info_header {
|
|
uint32_t total_size;
|
|
uint32_t reserved;
|
|
};
|
|
|
|
static uint8_t* mb2_align_address_up(uint8_t *addr, int align)
|
|
{
|
|
uintptr_t v = (uintptr_t)addr;
|
|
uintptr_t mask = align - 1;
|
|
|
|
return (uint8_t*)((v + mask) & ~(mask));
|
|
}
|
|
|
|
static uint8_t *mb2_find_tag_by_type(uint8_t *tags, uint32_t type)
|
|
{
|
|
struct mb2_tag* tag = (struct mb2_tag*)tags;
|
|
|
|
while (tag->type != 0) {
|
|
if (tag->type == type)
|
|
return (uint8_t*)tag;
|
|
tag = (struct mb2_tag*)mb2_align_address_up((uint8_t*)tag + tag->size,
|
|
8);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int mb2_start_mem_map(uint8_t *tag)
|
|
{
|
|
struct mb2_mem_map_header *map;
|
|
|
|
map = (struct mb2_mem_map_header *)tag;
|
|
map->type = 6;
|
|
map->entry_size = sizeof(struct mb2_mem_map_entry);
|
|
map->entry_version = 0;
|
|
map->size = sizeof(struct mb2_mem_map_header);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef WOLFBOOT_FSP
|
|
|
|
struct mb2_mem_map_cb_info {
|
|
struct mb2_mem_map_header *map_hdr;
|
|
unsigned *max_size;
|
|
};
|
|
|
|
static int mb2_add_mem_entry_cb(uint64_t baseAddr, uint64_t length,
|
|
uint32_t type, void *ctx) {
|
|
struct mb2_mem_map_header *mem_map;
|
|
struct mb2_mem_map_cb_info *info;
|
|
struct mb2_mem_map_entry *e;
|
|
|
|
info = (struct mb2_mem_map_cb_info *)ctx;
|
|
if (*info->max_size < sizeof(struct mb2_mem_map_entry)) {
|
|
MB2_DEBUG_PRINTF("Not enough size to build mb2 mep map\r\n");
|
|
return -1;
|
|
}
|
|
*info->max_size = *info->max_size - sizeof(struct mb2_mem_map_entry);
|
|
mem_map = info->map_hdr;
|
|
e = (struct mb2_mem_map_entry*)((uint8_t*)mem_map + mem_map->size);
|
|
e->base_addr = baseAddr;
|
|
e->length = length;
|
|
e->type =
|
|
(type == EFI_RESOURCE_SYSTEM_MEMORY) ? MB2_MEM_INFO_MEM_RAM : MB2_MEM_INFO_MEM_RESERVED;
|
|
e->reserved = 0;
|
|
mem_map->size += sizeof(struct mb2_mem_map_entry);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mb2_add_mem_basic_info_cb(uint64_t baseAddr, uint64_t length,
|
|
uint32_t type, void *ctx)
|
|
{
|
|
struct mb2_basic_memory_info *mem_info =
|
|
(struct mb2_basic_memory_info *)ctx;
|
|
|
|
(void)type;
|
|
if (baseAddr == 0)
|
|
mem_info->mem_lower = length / 1024;
|
|
if (baseAddr == 1 * 1024 * 1024)
|
|
mem_info->mem_upper = length / 1024;
|
|
return 0;
|
|
}
|
|
#endif /* WOLFBOOT_FSP */
|
|
|
|
static int mb2_add_basic_mem_info(uint8_t **idx, void *stage2_param,
|
|
unsigned *max_size)
|
|
{
|
|
#ifdef WOLFBOOT_FSP
|
|
struct mb2_basic_memory_info *meminfo = (struct mb2_basic_memory_info*)(*idx);
|
|
struct stage2_parameter *p = (struct stage2_parameter*)stage2_param;
|
|
struct efi_hob *hobs = (struct efi_hob*)(uintptr_t)p->hobList;
|
|
int r;
|
|
|
|
if (*max_size < sizeof(struct mb2_basic_memory_info)) {
|
|
MB2_DEBUG_PRINTF("Not enough size to build mb2 basic info\r\n");
|
|
return -1;
|
|
}
|
|
*max_size -= sizeof(struct mb2_basic_memory_info);
|
|
|
|
meminfo->type = MB2_REQ_TAG_BASIC_MEM_INFO;
|
|
meminfo->size = sizeof(*meminfo);
|
|
meminfo->mem_lower = 0;
|
|
meminfo->mem_upper = 0;
|
|
r = hob_iterate_memory_map(hobs,
|
|
mb2_add_mem_basic_info_cb, (void*)meminfo);
|
|
if (r != 0)
|
|
return r;
|
|
*idx += sizeof(*meminfo);
|
|
return 0;
|
|
#else
|
|
(void)idx;
|
|
(void)stage2_param;
|
|
(void)max_size;
|
|
return -1;
|
|
#endif /* WOLFBOOT_FSP */
|
|
}
|
|
|
|
static int mb2_add_mem_map(uint8_t **idx, void *stage2_param, unsigned *max_size)
|
|
{
|
|
#ifdef WOLFBOOT_FSP
|
|
struct mb2_mem_map_header *map_hdr = (struct mb2_mem_map_header*)(*idx);
|
|
struct stage2_parameter *p = (struct stage2_parameter*)stage2_param;
|
|
struct efi_hob *hobs = (struct efi_hob*)(uintptr_t)p->hobList;
|
|
struct mb2_mem_map_cb_info info;
|
|
int r;
|
|
|
|
if (*max_size < sizeof(struct mb2_mem_map_header)) {
|
|
MB2_DEBUG_PRINTF("Not enough size to build mb2 map header\r\n");
|
|
return -1;
|
|
}
|
|
info.map_hdr = map_hdr;
|
|
info.max_size = max_size;
|
|
*info.max_size = *info.max_size - sizeof(struct mb2_mem_map_header);
|
|
r = mb2_start_mem_map(*idx);
|
|
if (r != 0)
|
|
return r;
|
|
r = hob_iterate_memory_map(hobs, mb2_add_mem_entry_cb, (void *)&info);
|
|
if (r != 0)
|
|
return r;
|
|
*idx += map_hdr->size;
|
|
return 0;
|
|
#else
|
|
(void)idx;
|
|
(void)stage2_param;
|
|
(void)max_size;
|
|
return -1;
|
|
#endif /* WOLFBOOT_FSP */
|
|
}
|
|
|
|
int mb2_build_boot_info_header(uint8_t *mb2_boot_info,
|
|
uint8_t *mb2_header,
|
|
void* stage2_params,
|
|
unsigned max_size)
|
|
{
|
|
struct mb2_boot_info_header *hdr =
|
|
(struct mb2_boot_info_header *)mb2_boot_info;
|
|
struct mb2_tag_info_req *info_req_tag;
|
|
int requested_tags, i, r;
|
|
uint8_t *idx;
|
|
|
|
if (max_size < sizeof(*hdr)) {
|
|
MB2_DEBUG_PRINTF("Not enough size to build mb2 info header\r\n");
|
|
return -1;
|
|
}
|
|
max_size -= sizeof(*hdr);
|
|
idx = (uint8_t*)hdr + sizeof(*hdr);
|
|
hdr->reserved = 0;
|
|
info_req_tag =
|
|
(struct mb2_tag_info_req *)mb2_find_tag_by_type(mb2_header + sizeof(struct mb2_header), MB2_TAG_TYPE_INFO_REQ);
|
|
if (info_req_tag == NULL)
|
|
return -1;
|
|
requested_tags = (info_req_tag->size - sizeof(struct mb2_tag_info_req)) / sizeof(uint32_t);
|
|
for (i = 0; i < requested_tags; i++) {
|
|
switch (info_req_tag->mbi_tag_types[i]) {
|
|
case MB2_REQ_TAG_BASIC_MEM_INFO:
|
|
r = mb2_add_basic_mem_info(&idx, stage2_params, &max_size);
|
|
if (r != 0)
|
|
return r;
|
|
break;
|
|
case MB2_REQ_TAG_MEM_MAP:
|
|
r = mb2_add_mem_map(&idx, stage2_params, &max_size);
|
|
if (r != 0)
|
|
return r;
|
|
break;
|
|
default:
|
|
wolfBoot_printf("mb2: unsupported info request tag: %d\r\n", i);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
hdr->total_size = idx - (uint8_t*)hdr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DEBUG_MB2
|
|
static void mb2_parse_info_request_tag(void* tag) {
|
|
struct mb2_tag_info_req *infoTag = (struct mb2_tag_info_req*)tag;
|
|
|
|
uint32_t numTagTypes =
|
|
(infoTag->size - sizeof(struct mb2_tag_info_req)) / sizeof(uint32_t);
|
|
|
|
MB2_DEBUG_PRINTF("Information Request Tag:\r\n");
|
|
MB2_DEBUG_PRINTF("Tag Type: %u\r\n", infoTag->type);
|
|
MB2_DEBUG_PRINTF("Tag Flags: 0x%x\r\n", infoTag->flags);
|
|
MB2_DEBUG_PRINTF("Tag Size: %u\r\n", infoTag->size);
|
|
MB2_DEBUG_PRINTF("Number of Tag Types: %u\r\n", numTagTypes);
|
|
|
|
for (uint32_t i = 0; i < numTagTypes; i++) {
|
|
uint32_t tagType = infoTag->mbi_tag_types[i];
|
|
MB2_DEBUG_PRINTF("Tag Type %u: %u\r\n", i, tagType);
|
|
}
|
|
}
|
|
|
|
static void mb2_dump_tags(void* mbTags) {
|
|
struct mb2_tag* tag = (struct mb2_tag*)mbTags;
|
|
|
|
while (tag->type != 0) {
|
|
MB2_DEBUG_PRINTF("Tag Type: %u\r\n", tag->type);
|
|
MB2_DEBUG_PRINTF("Tag Flags: 0x%x\r\n", tag->flags);
|
|
MB2_DEBUG_PRINTF("Tag Size: %u\r\n", tag->size);
|
|
|
|
if (tag->type == MB2_TAG_TYPE_INFO_REQ)
|
|
mb2_parse_info_request_tag(tag);
|
|
|
|
tag = (struct mb2_tag*)mb2_align_address_up((uint8_t*)tag + tag->size,
|
|
8);
|
|
}
|
|
}
|
|
|
|
static void mb2_dump_header(void* mbHeader) {
|
|
struct mb2_header* header = (struct mb2_header*)mbHeader;
|
|
uint8_t *tags;
|
|
|
|
MB2_DEBUG_PRINTF("Magic: 0x%x\r\n", header->magic);
|
|
MB2_DEBUG_PRINTF("Architecture: 0x%x\r\n", header->architecture);
|
|
MB2_DEBUG_PRINTF("Header Length: %u\r\n", header->header_length);
|
|
MB2_DEBUG_PRINTF("Checksum: 0x%x\r\n", header->checksum);
|
|
|
|
tags = (uint8_t*)header + sizeof(*header);
|
|
mb2_dump_tags(tags);
|
|
}
|
|
#endif /* DEBUG_MB2 */
|
|
|
|
uint8_t *mb2_find_header(uint8_t *image, int size)
|
|
{
|
|
uint32_t *ptr;
|
|
int i;
|
|
|
|
if (size > MB2_HEADER_MAX_OFF/4)
|
|
size = MB2_HEADER_MAX_OFF;
|
|
size = size / 4;
|
|
for (ptr = (uint32_t*)image,i = 0; i < size; ++i) {
|
|
if (ptr[i] == MB2_HEADER_MAGIC) {
|
|
#ifdef DEBUG_MB2
|
|
mb2_dump_header(&ptr[i]);
|
|
#endif /* DEBUG_MB2 */
|
|
return (uint8_t*)&ptr[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void mb2_jump(uintptr_t entry, uint32_t mb2_boot_info)
|
|
{
|
|
__asm__(
|
|
"mov $0x36d76289, %%eax\r\n"
|
|
"mov %0, %%ebx\r\n"
|
|
"jmp *%1\r\n"
|
|
:
|
|
: "g"(mb2_boot_info), "g"(entry)
|
|
: "eax", "ebx");
|
|
}
|
|
|
|
#endif /* WOLFBOOT_MULTIBOOT2 */
|