summaryrefslogtreecommitdiff
path: root/usr/src/boot
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2018-02-03 14:16:26 +0200
committerHans Rosenfeld <hans.rosenfeld@joyent.com>2018-02-06 14:28:11 +0100
commitaf8443c4728e4601db72fb8089035223de906eb9 (patch)
treef0de63ec6310ec619b174ebc9f5f809fea09fbf8 /usr/src/boot
parentbd0ce624be4492bab2f6c53383a40618647aba28 (diff)
downloadillumos-joyent-af8443c4728e4601db72fb8089035223de906eb9.tar.gz
9022 loader.efi: module placement must check memory map
Reviewed by: Yuri Pankov <yuripv@yuripv.net> Reviewed by: C Fraire <cfraire@me.com> Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com> Approved by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
Diffstat (limited to 'usr/src/boot')
-rw-r--r--usr/src/boot/sys/boot/common/multiboot2.c48
-rw-r--r--usr/src/boot/sys/boot/efi/loader/copy.c106
-rw-r--r--usr/src/boot/sys/boot/efi/loader/loader_efi.h2
3 files changed, 139 insertions, 17 deletions
diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/sys/boot/common/multiboot2.c
index 876a5cd6a2..0e3b7bbaa3 100644
--- a/usr/src/boot/sys/boot/common/multiboot2.c
+++ b/usr/src/boot/sys/boot/common/multiboot2.c
@@ -791,8 +791,9 @@ multiboot2_exec(struct preloaded_file *fp)
size_t size;
struct bios_smap *smap;
#if defined (EFI)
- multiboot_tag_module_t *module;
+ multiboot_tag_module_t *module, *mp;
EFI_MEMORY_DESCRIPTOR *map;
+ UINTN map_size, desc_size;
struct relocator *relocator;
struct chunk_head *head;
struct chunk *chunk;
@@ -928,7 +929,7 @@ multiboot2_exec(struct preloaded_file *fp)
* - tmp != mfp->f_addr only in case of EFI.
*/
#if defined (EFI)
- tmp = roundup2(load_addr + fp->f_size, MULTIBOOT_MOD_ALIGN);
+ tmp = roundup2(load_addr + fp->f_size + 1, MULTIBOOT_MOD_ALIGN);
module = (multiboot_tag_module_t *)last_addr;
#endif
@@ -958,9 +959,12 @@ multiboot2_exec(struct preloaded_file *fp)
tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE;
tag->mb_size = sizeof (*tag) + num;
#if defined (EFI)
- tag->mb_mod_start = tmp;
- tag->mb_mod_end = tmp + mfp->f_size;
- tmp = roundup2(tag->mb_mod_end + 1, MULTIBOOT_MOD_ALIGN);
+ /*
+ * We can assign module addresses only after BS have been
+ * switched off.
+ */
+ tag->mb_mod_start = 0;
+ tag->mb_mod_end = mfp->f_size;
#else
tag->mb_mod_start = mfp->f_addr;
tag->mb_mod_end = mfp->f_addr + mfp->f_size;
@@ -1100,21 +1104,21 @@ multiboot2_exec(struct preloaded_file *fp)
/* Leave EFI memmap last as we will also switch off the BS. */
{
multiboot_tag_efi_mmap_t *tag;
- UINTN size, desc_size, key;
+ UINTN key;
EFI_STATUS status;
tag = (multiboot_tag_efi_mmap_t *)
mb_malloc(sizeof (*tag));
- size = 0;
- status = BS->GetMemoryMap(&size,
+ map_size = 0;
+ status = BS->GetMemoryMap(&map_size,
(EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
&desc_size, &tag->mb_descr_vers);
if (status != EFI_BUFFER_TOO_SMALL) {
error = EINVAL;
goto error;
}
- status = BS->GetMemoryMap(&size,
+ status = BS->GetMemoryMap(&map_size,
(EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
&desc_size, &tag->mb_descr_vers);
if (EFI_ERROR(status)) {
@@ -1122,7 +1126,7 @@ multiboot2_exec(struct preloaded_file *fp)
goto error;
}
tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
- tag->mb_size = sizeof (*tag) + size;
+ tag->mb_size = sizeof (*tag) + map_size;
tag->mb_descr_size = (uint32_t) desc_size;
/*
@@ -1132,7 +1136,7 @@ multiboot2_exec(struct preloaded_file *fp)
* relocator data, trampoline, copy, memmove, stack.
*/
for (i = 0, map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
- i < size / desc_size;
+ i < map_size / desc_size;
i++, map = NextMemoryDescriptor(map, desc_size)) {
if (map->PhysicalStart == 0)
continue;
@@ -1154,7 +1158,7 @@ multiboot2_exec(struct preloaded_file *fp)
}
}
- last_addr += size;
+ last_addr += map_size;
last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN);
}
#endif
@@ -1191,20 +1195,32 @@ multiboot2_exec(struct preloaded_file *fp)
STAILQ_INSERT_TAIL(head, chunk, chunk_next);
+ mp = module;
for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
chunk = &relocator->rel_chunklist[i++];
chunk->chunk_vaddr = mfp->f_addr;
- chunk->chunk_paddr = module->mb_mod_start;
+
+ /*
+ * fix the mb_mod_start and mb_mod_end.
+ */
+ mp->mb_mod_start = efi_physaddr(module, tmp, map,
+ map_size / desc_size, desc_size, mp->mb_mod_end);
+ if (mp->mb_mod_start == 0)
+ panic("Could not find memory for module\n");
+
+ mp->mb_mod_end += mp->mb_mod_start;
+ chunk->chunk_paddr = mp->mb_mod_start;
chunk->chunk_size = mfp->f_size;
STAILQ_INSERT_TAIL(head, chunk, chunk_next);
- module = (multiboot_tag_module_t *)
- roundup2((uintptr_t)module + module->mb_size,
+ mp = (multiboot_tag_module_t *)
+ roundup2((uintptr_t)mp + mp->mb_size,
MULTIBOOT_TAG_ALIGN);
}
chunk = &relocator->rel_chunklist[i++];
chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)mbi;
- chunk->chunk_paddr = tmp;
+ chunk->chunk_paddr = efi_physaddr(module, tmp, map,
+ map_size / desc_size, desc_size, mbi->mbi_total_size);
chunk->chunk_size = mbi->mbi_total_size;
STAILQ_INSERT_TAIL(head, chunk, chunk_next);
diff --git a/usr/src/boot/sys/boot/efi/loader/copy.c b/usr/src/boot/sys/boot/efi/loader/copy.c
index a4f44bc072..9658a659d4 100644
--- a/usr/src/boot/sys/boot/efi/loader/copy.c
+++ b/usr/src/boot/sys/boot/efi/loader/copy.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 2013 The FreeBSD Foundation
* All rights reserved.
*
@@ -41,6 +41,110 @@
#include "loader_efi.h"
/*
+ * Verify the address is not in use by existing modules.
+ */
+static vm_offset_t
+addr_verify(multiboot_tag_module_t *module, vm_offset_t addr, size_t size)
+{
+ vm_offset_t start, end;
+
+ for (;module->mb_type == MULTIBOOT_TAG_TYPE_MODULE;
+ module = (multiboot_tag_module_t *)
+ roundup((uintptr_t)module + module->mb_size, MULTIBOOT_TAG_ALIGN)) {
+
+ start = module->mb_mod_start;
+ end = module->mb_mod_end;
+
+ /* Does this module have address assigned? */
+ if (start == 0)
+ continue;
+
+ if ((start <= addr) && (end >= addr)) {
+ return (0);
+ }
+ if ((start >= addr) && (start <= addr + size)) {
+ return (0);
+ }
+ }
+ return (addr);
+}
+
+/*
+ * Find memory map entry above 1MB, able to contain size bytes from addr.
+ */
+static vm_offset_t
+memmap_find(EFI_MEMORY_DESCRIPTOR *map, size_t count, UINTN dsize,
+ vm_offset_t addr, size_t size)
+{
+ int i;
+
+ for (i = 0; i < count; i++, map = NextMemoryDescriptor(map, dsize)) {
+
+ if (map->Type != EfiConventionalMemory)
+ continue;
+
+ /* We do not want address below 1MB. */
+ if (map->PhysicalStart < 0x100000)
+ continue;
+
+ /* Do we fit into current entry? */
+ if ((map->PhysicalStart <= addr) &&
+ (map->PhysicalStart +
+ (map->NumberOfPages << EFI_PAGE_SHIFT) >= addr + size)) {
+ return (addr);
+ }
+
+ /* Do we fit into new entry? */
+ if ((map->PhysicalStart > addr) &&
+ (map->NumberOfPages >= EFI_SIZE_TO_PAGES(size))) {
+ return (map->PhysicalStart);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Find usable address for loading. The address for the kernel is fixed, as
+ * it is determined by kernel linker map (dboot PT_LOAD address).
+ * For modules, we need to consult memory map, the module address has to be
+ * aligned to page boundary and we have to fit into map entry.
+ */
+vm_offset_t
+efi_physaddr(multiboot_tag_module_t *module, vm_offset_t addr,
+ EFI_MEMORY_DESCRIPTOR *map, size_t count, UINTN dsize, size_t size)
+{
+ multiboot_tag_module_t *mp;
+ vm_offset_t off;
+
+ if (addr == 0)
+ return (addr);
+
+ mp = module;
+ do {
+ off = addr;
+ /* Test proposed address */
+ off = memmap_find(map, count, dsize, off, size);
+ if (off != 0)
+ off = addr_verify(module, off, size);
+ if (off != 0)
+ break;
+
+ /* The module list is exhausted */
+ if (mp->mb_type != MULTIBOOT_TAG_TYPE_MODULE)
+ break;
+
+ if (mp->mb_mod_start != 0) {
+ addr = roundup2(mp->mb_mod_end + 1,
+ MULTIBOOT_MOD_ALIGN);
+ }
+ mp = (multiboot_tag_module_t *)
+ roundup((uintptr_t)mp + mp->mb_size, MULTIBOOT_TAG_ALIGN);
+ } while (off == 0);
+
+ return (off);
+}
+
+/*
* Allocate pages for data to be loaded. As we can not expect AllocateAddress
* to succeed, we allocate using AllocateMaxAddress from 4GB limit.
* 4GB limit is because reportedly some 64bit systems are reported to have
diff --git a/usr/src/boot/sys/boot/efi/loader/loader_efi.h b/usr/src/boot/sys/boot/efi/loader/loader_efi.h
index 6378a662d3..59b1ecc5bd 100644
--- a/usr/src/boot/sys/boot/efi/loader/loader_efi.h
+++ b/usr/src/boot/sys/boot/efi/loader/loader_efi.h
@@ -65,6 +65,8 @@ ssize_t efi_readin(const int, vm_offset_t, const size_t);
uint64_t efi_loadaddr(u_int, void *, uint64_t);
void efi_free_loadaddr(uint64_t, uint64_t);
void * efi_translate(vm_offset_t);
+vm_offset_t efi_physaddr(multiboot_tag_module_t *, vm_offset_t,
+ EFI_MEMORY_DESCRIPTOR *, size_t, UINTN, size_t);
multiboot2_info_header_t *efi_copy_finish(struct relocator *);
void multiboot_tramp(uint32_t, struct relocator *, uint64_t);