diff options
author | Toomas Soome <tsoome@me.com> | 2016-10-09 17:30:28 +0300 |
---|---|---|
committer | Richard Lowe <richlowe@richlowe.net> | 2017-08-30 14:18:41 -0400 |
commit | f9feecc12f00b97b49d542398fb3b5a452da0bbc (patch) | |
tree | 8af199520a67a45cc90e9161e09f52aa7e7e2c71 /usr/src/boot | |
parent | a058d1cc571af5fbcfe7f1d719df1abbfdb722f3 (diff) | |
download | illumos-joyent-f9feecc12f00b97b49d542398fb3b5a452da0bbc.tar.gz |
8139 loader: efi multiboot2 update
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/boot')
-rw-r--r-- | usr/src/boot/lib/libstand/bootp.c | 13 | ||||
-rw-r--r-- | usr/src/boot/lib/libstand/bootp.h | 5 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/common/bootstrap.h | 14 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/common/multiboot2.c | 310 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/boot1/Makefile | 2 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/Makefile | 7 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc | 6 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S | 119 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/conf.c | 11 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/copy.c | 193 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/loader_efi.h | 53 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/main.c | 107 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/memmap.c | 180 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/libi386.h | 6 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/multiboot.c | 22 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/pxe.c | 2 |
16 files changed, 924 insertions, 126 deletions
diff --git a/usr/src/boot/lib/libstand/bootp.c b/usr/src/boot/lib/libstand/bootp.c index 98ecb2750b..117229753c 100644 --- a/usr/src/boot/lib/libstand/bootp.c +++ b/usr/src/boot/lib/libstand/bootp.c @@ -88,6 +88,7 @@ static void setenv_(u_char *cp, u_char *ep, struct dhcp_opt *opts); static char expected_dhcpmsgtype = -1, dhcp_ok; struct in_addr dhcp_serverip; #endif +struct bootp *bootp_response; /* Fetch required bootp infomation */ void @@ -320,6 +321,18 @@ bootprecv(struct iodesc *d, void *pkt, size_t len, time_t tleft) if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0) goto bad; + + /* Save copy of bootp reply or DHCP ACK message */ + if (bp->bp_op == BOOTREPLY && + ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) || + dhcp_ok == 0)) { + free(bootp_response); + bootp_response = malloc(sizeof (*bootp_response)); + if (bootp_response != NULL) { + bcopy(bp, bootp_response, + sizeof (*bootp_response)); + } + } } #ifdef BOOTP_VEND_CMU else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) diff --git a/usr/src/boot/lib/libstand/bootp.h b/usr/src/boot/lib/libstand/bootp.h index 3c5c333180..72c781994b 100644 --- a/usr/src/boot/lib/libstand/bootp.h +++ b/usr/src/boot/lib/libstand/bootp.h @@ -20,6 +20,8 @@ * without express or implied warranty. */ +#include <netinet/in.h> + #ifndef _BOOTP_H_ #define _BOOTP_H_ @@ -145,6 +147,9 @@ struct cmu_vend { /* v_flags values */ #define VF_SMASK 1 /* Subnet mask field contains valid data */ +/* cached bootp response/dhcp ack */ +extern struct bootp *bootp_response; + int dhcp_try_rfc1048(uint8_t *cp, size_t len); #endif /* _BOOTP_H_ */ diff --git a/usr/src/boot/sys/boot/common/bootstrap.h b/usr/src/boot/sys/boot/common/bootstrap.h index 8b0d9c50f0..83495af92c 100644 --- a/usr/src/boot/sys/boot/common/bootstrap.h +++ b/usr/src/boot/sys/boot/common/bootstrap.h @@ -245,15 +245,17 @@ extern u_int64_t __elfN(relocation_offset); struct elf_file; typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx); -int __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result); -int __elfN(obj_loadfile)(char *filename, u_int64_t dest, - struct preloaded_file **result); +int elf64_loadfile(char *, uint64_t, struct preloaded_file **); +int elf32_loadfile(char *, uint64_t, struct preloaded_file **); +int elf64_obj_loadfile(char *, uint64_t, struct preloaded_file **); +int elf32_obj_loadfile(char *, uint64_t, struct preloaded_file **); int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len); -int __elfN(loadfile_raw)(char *filename, u_int64_t dest, - struct preloaded_file **result, int multiboot); -int __elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest); +int elf64_loadfile_raw(char *, uint64_t, struct preloaded_file **, int); +int elf32_loadfile_raw(char *, uint64_t, struct preloaded_file **, int); +int elf64_load_modmetadata(struct preloaded_file *, uint64_t); +int elf32_load_modmetadata(struct preloaded_file *, uint64_t); #endif /* diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/sys/boot/common/multiboot2.c index 74f6e9c4cd..1808d09c89 100644 --- a/usr/src/boot/sys/boot/common/multiboot2.c +++ b/usr/src/boot/sys/boot/common/multiboot2.c @@ -18,6 +18,7 @@ * kernel. This code is only built to support the illumos kernel, it does * not support xen. */ + #include <sys/cdefs.h> #include <sys/stddef.h> @@ -29,6 +30,7 @@ #include <sys/multiboot2.h> #include <stand.h> #include <stdbool.h> +#include <machine/elf.h> #include "libzfs.h" #include "bootstrap.h" @@ -36,12 +38,20 @@ #include <machine/metadata.h> #include <machine/pc/bios.h> +#define SUPPORT_DHCP +#include <bootp.h> + +#if !defined(EFI) #include "../i386/libi386/libi386.h" #include "../i386/btx/lib/btxv86.h" -#include "pxe.h" -extern BOOTPLAYER bootplayer; /* dhcp info */ -extern void multiboot_tramp(); +#else +#include <efi.h> +#include <efilib.h> +#include "loader_efi.h" + +static void (*trampoline)(uint32_t, struct relocator *, uint64_t); +#endif #include "platform/acfreebsd.h" #include "acconfig.h" @@ -55,8 +65,6 @@ extern ACPI_TABLE_RSDP *rsdp; static vm_offset_t last_addr; extern char bootprog_info[]; -extern int elf32_loadfile_raw(char *filename, u_int64_t dest, - struct preloaded_file **result, int multiboot); static int multiboot2_loadfile(char *, u_int64_t, struct preloaded_file **); static int multiboot2_exec(struct preloaded_file *); @@ -276,6 +284,12 @@ multiboot2_loadfile(char *filename, u_int64_t dest, fp->f_metadata = NULL; error = 0; } else { +#if defined(EFI) + /* 32-bit kernel is not yet supported for EFI */ + printf("32-bit kernel is not supported by UEFI loader\n"); + error = ENOTSUP; + goto out; +#endif /* elf32_loadfile_raw will fill the attributes in fp. */ error = elf32_loadfile_raw(filename, dest, &fp, 2); if (error != 0) { @@ -295,7 +309,11 @@ multiboot2_loadfile(char *filename, u_int64_t dest, } setenv("kernelname", fp->f_name, 1); +#if defined(EFI) + efi_addsmapdata(fp); +#else bios_addsmapdata(fp); +#endif *result = fp; out: free(header_search); @@ -656,6 +674,42 @@ module_size(struct preloaded_file *fp) return (size); } +#if defined (EFI) +/* + * Calculate size for UEFI memory map tag. + */ +static int +efimemmap_size(void) +{ + UINTN size, cur_size, desc_size; + EFI_MEMORY_DESCRIPTOR *mmap; + EFI_STATUS ret; + + size = EFI_PAGE_SIZE; /* Start with 4k. */ + while (1) { + cur_size = size; + mmap = malloc(cur_size); + if (mmap == NULL) + return (0); + ret = BS->GetMemoryMap(&cur_size, mmap, NULL, &desc_size, NULL); + free(mmap); + if (ret == EFI_SUCCESS) + break; + if (ret == EFI_BUFFER_TOO_SMALL) { + if (size < cur_size) + size = cur_size; + size += (EFI_PAGE_SIZE); + } else + return (0); + } + + /* EFI MMAP will grow when we allocate MBI, set some buffer. */ + size += (3 << EFI_PAGE_SHIFT); + size = roundup(size, desc_size); + return (sizeof (multiboot_tag_efi_mmap_t) + size); +} +#endif + /* * Calculate size for bios smap tag. */ @@ -684,15 +738,29 @@ mbi_size(struct preloaded_file *fp, char *cmdline) size = roundup2(size, MULTIBOOT_TAG_ALIGN); size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#if !defined (EFI) size += sizeof (multiboot_tag_basic_meminfo_t); size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#endif size += module_size(fp); size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#if defined (EFI) + size += sizeof (multiboot_tag_efi64_t); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + size += efimemmap_size(); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + + if (have_framebuffer == true) { + size += sizeof (multiboot_tag_framebuffer_t); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + } +#endif size += biossmap_size(fp); size = roundup2(size, MULTIBOOT_TAG_ALIGN); - if (strstr(getenv("loaddev"), "pxe") != NULL) { - size += sizeof(multiboot_tag_network_t) + sizeof (BOOTPLAYER); + if (bootp_response != NULL) { + size += sizeof(multiboot_tag_network_t) + + sizeof (*bootp_response); size = roundup2(size, MULTIBOOT_TAG_ALIGN); } @@ -724,7 +792,17 @@ multiboot2_exec(struct preloaded_file *fp) size_t size; struct bios_smap *smap; vm_offset_t tmp; +#if defined (EFI) + multiboot_tag_module_t *module; + EFI_MEMORY_DESCRIPTOR *map; + struct relocator *relocator; + struct chunk_head *head; + struct chunk *chunk; + + efi_getdev((void **)(&rootdev), NULL, NULL); +#else i386_getdev((void **)(&rootdev), NULL, NULL); +#endif error = EINVAL; if (rootdev == NULL) { @@ -756,8 +834,28 @@ multiboot2_exec(struct preloaded_file *fp) size = mbi_size(fp, cmdline); /* Get the size for MBI. */ /* Set up the base for mb_malloc. */ - for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next); + i = 0; + for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next) + i++; + +#if defined (EFI) + /* We need space for kernel + MBI + # modules */ + num = (EFI_PAGE_SIZE - offsetof(struct relocator, rel_chunklist)) / + sizeof (struct chunk); + if (i + 2 >= num) { + printf("Too many modules, do not have space for relocator.\n"); + error = ENOMEM; + goto error; + } + last_addr = efi_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size); + mbi = (multiboot2_info_header_t *)last_addr; + if (mbi == NULL) { + error = ENOMEM; + goto error; + } + last_addr = (vm_offset_t)mbi->mbi_tags; +#else /* Start info block from the new page. */ last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN); @@ -769,6 +867,7 @@ multiboot2_exec(struct preloaded_file *fp) mbi = (multiboot2_info_header_t *)PTOV(last_addr); last_addr = (vm_offset_t)mbi->mbi_tags; +#endif /* EFI */ { multiboot_tag_string_t *tag; @@ -793,6 +892,8 @@ multiboot2_exec(struct preloaded_file *fp) strlen(bootprog_info) + 1); } +#if !defined (EFI) + /* Only set in case of BIOS. */ { multiboot_tag_basic_meminfo_t *tag; tag = (multiboot_tag_basic_meminfo_t *) @@ -803,6 +904,7 @@ multiboot2_exec(struct preloaded_file *fp) tag->mb_mem_lower = bios_basemem / 1024; tag->mb_mem_upper = bios_extmem / 1024; } +#endif num = 0; for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { @@ -824,8 +926,12 @@ multiboot2_exec(struct preloaded_file *fp) * - Modules are aligned to page boundary. * - MBI is aligned to page boundary. * - Set the tmp to point to physical address of the first module. + * - tmp != mfp->f_addr only in case of EFI. */ tmp = roundup2(load_addr + fp->f_size, MULTIBOOT_MOD_ALIGN); +#if defined (EFI) + module = (multiboot_tag_module_t *)last_addr; +#endif for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { multiboot_tag_module_t *tag; @@ -893,14 +999,15 @@ multiboot2_exec(struct preloaded_file *fp) } } - if (strstr(getenv("loaddev"), "pxe") != NULL) { + if (bootp_response != NULL) { multiboot_tag_network_t *tag; tag = (multiboot_tag_network_t *) - mb_malloc(sizeof(*tag) + sizeof (BOOTPLAYER)); + mb_malloc(sizeof (*tag) + sizeof (*bootp_response)); tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK; - tag->mb_size = sizeof(*tag) + sizeof (BOOTPLAYER); - memcpy(tag->mb_dhcpack, &bootplayer, sizeof (BOOTPLAYER)); + tag->mb_size = sizeof (*tag) + sizeof (*bootp_response); + memcpy(tag->mb_dhcpack, bootp_response, + sizeof (*bootp_response)); } if (rsdp != NULL) { @@ -923,6 +1030,132 @@ multiboot2_exec(struct preloaded_file *fp) } } +#if defined (EFI) + { + multiboot_tag_efi64_t *tag; + tag = (multiboot_tag_efi64_t *) + mb_malloc(sizeof (*tag)); + + tag->mb_type = MULTIBOOT_TAG_TYPE_EFI64; + tag->mb_size = sizeof (*tag); + tag->mb_pointer = (uint64_t)(uintptr_t)ST; + } + + if (have_framebuffer == true) { + multiboot_tag_framebuffer_t *tag; + int bpp; + struct efi_fb fb; + extern int efi_find_framebuffer(struct efi_fb *efifb); + + if (efi_find_framebuffer(&fb) == 0) { + tag = (multiboot_tag_framebuffer_t *) + mb_malloc(sizeof (*tag)); + + /* + * We assume contiguous color bitmap, and use + * the msb for bits per pixel calculation. + */ + bpp = fls(fb.fb_mask_red | fb.fb_mask_green | + fb.fb_mask_blue | fb.fb_mask_reserved); + + tag->framebuffer_common.mb_type = + MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->framebuffer_common.mb_size = + sizeof (multiboot_tag_framebuffer_t); + tag->framebuffer_common.framebuffer_addr = fb.fb_addr; + tag->framebuffer_common.framebuffer_width = fb.fb_width; + tag->framebuffer_common.framebuffer_height = + fb.fb_height; + tag->framebuffer_common.framebuffer_bpp = bpp; + /* + * Pitch is stride * bytes per pixel. + * Stride is pixels per scanline. + */ + tag->framebuffer_common.framebuffer_pitch = + fb.fb_stride * (bpp / 8); + tag->framebuffer_common.framebuffer_type = + MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->framebuffer_common.mb_reserved = 0; + + /* + * The RGB or BGR color ordering. + */ + if (fb.fb_mask_red & 0x000000ff) { + tag->u.fb2.framebuffer_red_field_position = 0; + tag->u.fb2.framebuffer_blue_field_position = 16; + } else { + tag->u.fb2.framebuffer_red_field_position = 16; + tag->u.fb2.framebuffer_blue_field_position = 0; + } + tag->u.fb2.framebuffer_red_mask_size = 8; + tag->u.fb2.framebuffer_green_field_position = 8; + tag->u.fb2.framebuffer_green_mask_size = 8; + tag->u.fb2.framebuffer_blue_mask_size = 8; + } + } + + /* Leave EFI memmap last as we will also switch off the BS. */ + { + multiboot_tag_efi_mmap_t *tag; + UINTN size, desc_size, key; + EFI_STATUS status; + + tag = (multiboot_tag_efi_mmap_t *) + mb_malloc(sizeof (*tag)); + + size = 0; + status = BS->GetMemoryMap(&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, + (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key, + &desc_size, &tag->mb_descr_vers); + if (EFI_ERROR(status)) { + error = EINVAL; + goto error; + } + tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP; + tag->mb_size = sizeof (*tag) + size; + tag->mb_descr_size = (uint32_t) desc_size; + + /* + * Find relocater pages. We assume we have free pages + * below kernel load address. + * In this version we are using 5 pages: + * relocator data, trampoline, copy, memmove, stack. + */ + for (i = 0, map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap; + i < size / desc_size; + i++, map = NextMemoryDescriptor(map, desc_size)) { + if (map->PhysicalStart == 0) + continue; + if (map->Type != EfiConventionalMemory) + continue; + if (map->PhysicalStart < load_addr && + map->NumberOfPages > 5) + break; + } + if (map->PhysicalStart == 0) + panic("Could not find memory for relocater\n"); + + if (keep_bs == 0) { + status = BS->ExitBootServices(IH, key); + if (EFI_ERROR(status)) { + printf("Call to ExitBootServices failed\n"); + error = EINVAL; + goto error; + } + } + + last_addr += size; + last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN); + } +#endif + /* * MB tag list end marker. */ @@ -936,13 +1169,66 @@ multiboot2_exec(struct preloaded_file *fp) mbi->mbi_total_size = last_addr - (vm_offset_t)mbi; mbi->mbi_reserved = 0; +#if defined (EFI) + /* At this point we have load_addr pointing to kernel load + * address, module list in MBI having physical addresses, + * module list in fp having logical addresses and tmp pointing to + * physical address for MBI. + * Now we must move all pieces to place and start the kernel. + */ + relocator = (struct relocator *)(uintptr_t)map->PhysicalStart; + head = &relocator->rel_chunk_head; + STAILQ_INIT(head); + + i = 0; + chunk = &relocator->rel_chunklist[i++]; + chunk->chunk_vaddr = fp->f_addr; + chunk->chunk_paddr = load_addr; + chunk->chunk_size = fp->f_size; + + STAILQ_INSERT_TAIL(head, chunk, chunk_next); + + 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; + 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, + MULTIBOOT_TAG_ALIGN); + } + chunk = &relocator->rel_chunklist[i++]; + chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)mbi; + chunk->chunk_paddr = tmp; + chunk->chunk_size = mbi->mbi_total_size; + STAILQ_INSERT_TAIL(head, chunk, chunk_next); + + trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE; + memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE); + + relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE; + memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE); + + relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE; + memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE); + relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8; + + trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr); +#else dev_cleanup(); __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC, (void *)entry_addr, (void *)VTOP(mbi)); +#endif panic("exec returned"); error: if (cmdline != NULL) free(cmdline); +#if defined (EFI) + if (mbi != NULL) + efi_free_loadaddr((uint64_t)mbi, EFI_SIZE_TO_PAGES(size)); +#endif return (error); } diff --git a/usr/src/boot/sys/boot/efi/boot1/Makefile b/usr/src/boot/sys/boot/efi/boot1/Makefile index 413e7115fc..ac32e257c4 100644 --- a/usr/src/boot/sys/boot/efi/boot1/Makefile +++ b/usr/src/boot/sys/boot/efi/boot1/Makefile @@ -40,7 +40,7 @@ CPPFLAGS += -I./../../../../include CPPFLAGS += -I./../../../sys CPPFLAGS += -I./../../.. CPPFLAGS += -I../../../../lib/libstand -CPPFLAGS += -DEFI_UFS_BOOT +CPPFLAGS += -DEFI_UFS_BOOT -DUFS1_ONLY # CPPFLAGS += -DEFI_DEBUG CPPFLAGS += -I./../../zfs/ diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile b/usr/src/boot/sys/boot/efi/loader/Makefile index 4823f7ccd8..4baf9a2413 100644 --- a/usr/src/boot/sys/boot/efi/loader/Makefile +++ b/usr/src/boot/sys/boot/efi/loader/Makefile @@ -27,9 +27,9 @@ MACHINE= $(MACH64) # architecture-specific loader code SRCS= autoload.c bootinfo.c conf.c copy.c devicename.c main.c self_reloc.c \ - smbios.c acpi.c vers.c + smbios.c acpi.c vers.c memmap.c multiboot2.c OBJS= autoload.o bootinfo.o conf.o copy.o devicename.o main.o self_reloc.o \ - smbios.o acpi.o vers.o + smbios.o acpi.o vers.o memmap.o multiboot2.o ASFLAGS=-m64 -fPIC CFLAGS= -O2 @@ -83,6 +83,9 @@ LIBZFSBOOT= ../../zfs/${MACHINE}/libzfsboot.a include ./Makefile.common CPPFLAGS += -I../../common +# For multiboot2.h, must be last, to avoid conflicts +CPPFLAGS += -I$(SRC)/uts/common + FILES= loader.efi FILEMODE= 0555 ROOT_BOOT= $(ROOT)/boot diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc b/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc index 4f6be8a2e2..47dd322f91 100644 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc +++ b/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc @@ -1,15 +1,13 @@ -SRCS += amd64_tramp.S \ +SRCS += multiboot_tramp.S \ start.S \ framebuffer.c \ - elf64_freebsd.c \ trap.c \ exc.S -OBJS += amd64_tramp.o \ +OBJS += multiboot_tramp.o \ start.o \ framebuffer.o \ - elf64_freebsd.o \ trap.o \ exc.o diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S b/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S new file mode 100644 index 0000000000..dffa273563 --- /dev/null +++ b/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S @@ -0,0 +1,119 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome <tsoome@me.com> + */ + +#include <x86/specialreg.h> + + .file "multiboot_tramp.s" + +/* + * The current dboot in illumos kernel is running in 32bit mode + * and expecting following 32-bit multiboot execution environment: + * + * EAX: MB magic + * EBX: 32-bit physical address of MBI + * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF + * DS: 32-bit read/write code segment with offset 0 and limit 0xFFFFFFFF + * ES: 32-bit read/write code segment with offset 0 and limit 0xFFFFFFFF + * FS: 32-bit read/write code segment with offset 0 and limit 0xFFFFFFFF + * GS: 32-bit read/write code segment with offset 0 and limit 0xFFFFFFFF + * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * A20 enabled + * CR0: PG cleared, PE set + * EFLAGS: VM cleared, IF cleared + * interrupts disabled + */ + + .set SEL_SCODE,0x8 + .set SEL_SDATA,0x10 + + .text + .p2align 4 + .globl multiboot_tramp + .type multiboot_tramp, STT_FUNC + +/* + * void multiboot_tramp(uint32_t magic, struct relocator *relocator, + * uint64_t entry) + */ +multiboot_tramp: + cli + movq (%rsi), %rax + movq %rax, %rsp /* Switch to temporary stack. */ + movq 0x8(%rsi), %rax /* relocator->copy */ + pushq %rdi /* save magic */ + pushq %rdx /* save entry */ + movq %rsi, %rdi + callq *%rax + movq %rax, %rbx /* MBI */ + popq %rsi /* entry to rsi */ + popq %rdi /* restore magic */ + movq gdt@GOTPCREL(%rip), %rax + movq gdtaddr@GOTPCREL(%rip), %rdx + movq %rax, (%rdx) + movq gdtdesc@GOTPCREL(%rip), %rax + lgdt (%rax) + + /* record the address */ + movq multiboot_tramp_2@GOTPCREL(%rip), %rcx + movq %rsp, %rax + pushq $SEL_SDATA + pushq %rax + pushf + pushq $SEL_SCODE + movq multiboot_tramp_1@GOTPCREL(%rip), %rax + pushq %rax + iretq + + .code32 +multiboot_tramp_1: + movl $SEL_SDATA, %eax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + movl %cr0, %eax /* disable paging */ + btrl $31, %eax + movl %eax, %cr0 + jmp *%ecx +multiboot_tramp_2: + movl %cr4, %eax /* disable PAE, PGE, PSE */ + andl $~(CR4_PGE | CR4_PAE | CR4_PSE), %eax + movl %eax, %cr4 + movl $MSR_EFER, %ecx + rdmsr /* updates %edx:%eax */ + btcl $8, %eax /* clear long mode */ + wrmsr + movl %edi, %eax /* magic */ + jmp *%esi /* jump to kernel */ + +/* GDT record */ + .p2align 4 +gdt: + .word 0x0, 0x0 /* NULL entry */ + .byte 0x0, 0x0, 0x0, 0x0 + .word 0xffff, 0x0 /* code segment */ + .byte 0x0, 0x9a, 0xcf, 0x0 + .word 0xffff, 0x0 /* data segment */ + .byte 0x0, 0x92, 0xcf, 0x0 +gdt_end: + + .p2align 4 +gdtdesc: .word gdt_end - gdt - 1 /* limit */ +gdtaddr: .long 0 /* base */ + .long 0 + +multiboot_tramp_end: diff --git a/usr/src/boot/sys/boot/efi/loader/conf.c b/usr/src/boot/sys/boot/efi/loader/conf.c index 1af649a022..7da0afc6ca 100644 --- a/usr/src/boot/sys/boot/efi/loader/conf.c +++ b/usr/src/boot/sys/boot/efi/loader/conf.c @@ -88,3 +88,14 @@ struct console *consoles[] = { #endif NULL }; + +#if defined(__amd64__) || defined(__i386__) +extern struct file_format multiboot2; +#endif + +struct file_format *file_formats[] = { +#if defined(__amd64__) || defined(__i386__) + &multiboot2, +#endif + NULL +}; diff --git a/usr/src/boot/sys/boot/efi/loader/copy.c b/usr/src/boot/sys/boot/efi/loader/copy.c index 128196e269..8b287b108a 100644 --- a/usr/src/boot/sys/boot/efi/loader/copy.c +++ b/usr/src/boot/sys/boot/efi/loader/copy.c @@ -27,91 +27,91 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/multiboot2.h> #include <stand.h> #include <bootstrap.h> #include <efi.h> #include <efilib.h> +#include <assert.h> #include "loader_efi.h" -#ifndef EFI_STAGING_SIZE -#define EFI_STAGING_SIZE 48 -#endif +/* + * 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 + * issues with memory above 4GB. It should be quite enough anyhow. + * Note: AllocateMaxAddress will only make sure we are below the specified + * address, we can not make any assumptions about actual location or + * about the order of the allocated blocks. + */ +uint64_t +efi_loadaddr(u_int type, void *data, uint64_t addr) +{ + EFI_PHYSICAL_ADDRESS paddr; + struct stat st; + int size; + uint64_t pages; + EFI_STATUS status; + + if (addr == 0) + return (addr); /* nothing to do */ + + if (type == LOAD_ELF) + return (0); /* not supported */ + + if (type == LOAD_MEM) + size = *(int *)data; + else { + stat(data, &st); + size = st.st_size; + } -#define STAGE_PAGES EFI_SIZE_TO_PAGES((EFI_STAGING_SIZE) * 1024 * 1024) + pages = EFI_SIZE_TO_PAGES(size); + /* 4GB upper limit */ + paddr = 0x0000000100000000; -EFI_PHYSICAL_ADDRESS staging, staging_end; -int stage_offset_set = 0; -ssize_t stage_offset; + status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, + pages, &paddr); -int -efi_copy_init(void) -{ - EFI_STATUS status; - - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, - STAGE_PAGES, &staging); if (EFI_ERROR(status)) { - printf("failed to allocate staging area: %lu\n", - EFI_ERROR_CODE(status)); - return (status); + printf("failed to allocate %d bytes for staging area: %lu\n", + size, EFI_ERROR_CODE(status)); + return (0); } - staging_end = staging + STAGE_PAGES * EFI_PAGE_SIZE; -#if defined(__aarch64__) || defined(__arm__) - /* - * Round the kernel load address to a 2MiB value. This is needed - * because the kernel builds a page table based on where it has - * been loaded in physical address space. As the kernel will use - * either a 1MiB or 2MiB page for this we need to make sure it - * is correctly aligned for both cases. - */ - staging = roundup2(staging, 2 * 1024 * 1024); -#endif + return (paddr); +} - return (0); +void +efi_free_loadaddr(uint64_t addr, uint64_t pages) +{ + (void) BS->FreePages(addr, pages); } void * efi_translate(vm_offset_t ptr) { - - return ((void *)(ptr + stage_offset)); + return ((void *)ptr); } ssize_t efi_copyin(const void *src, vm_offset_t dest, const size_t len) { - - if (!stage_offset_set) { - stage_offset = (vm_offset_t)staging - dest; - stage_offset_set = 1; - } - - /* XXX: Callers do not check for failure. */ - if (dest + stage_offset + len > staging_end) { - errno = ENOMEM; - return (-1); - } - bcopy(src, (void *)(dest + stage_offset), len); + assert(dest < 0x100000000); + bcopy(src, (void *)(uintptr_t)dest, len); return (len); } ssize_t efi_copyout(const vm_offset_t src, void *dest, const size_t len) { - - /* XXX: Callers do not check for failure. */ - if (src + stage_offset + len > staging_end) { - errno = ENOMEM; - return (-1); - } - bcopy((void *)(src + stage_offset), dest, len); + assert(src < 0x100000000); + bcopy((void *)(uintptr_t)src, dest, len); return (len); } @@ -119,23 +119,86 @@ efi_copyout(const vm_offset_t src, void *dest, const size_t len) ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len) { - - if (dest + stage_offset + len > staging_end) { - errno = ENOMEM; - return (-1); - } - return (read(fd, (void *)(dest + stage_offset), len)); + return (read(fd, (void *)dest, len)); } -void -efi_copy_finish(void) +/* + * Relocate chunks and return pointer to MBI. + * This function is relocated before being called and we only have + * memmove() available, as most likely moving chunks into the final + * destination will destroy the rest of the loader code. + * + * In safe area we have relocator data, multiboot_tramp, efi_copy_finish, + * memmove and stack. + */ +multiboot2_info_header_t * +efi_copy_finish(struct relocator *relocator) { - uint64_t *src, *dst, *last; + multiboot2_info_header_t *mbi; + struct chunk *chunk, *c; + struct chunk_head *head; + UINT64 size; + int done = 0; + void (*move)(void *s1, const void *s2, size_t n); + + move = (void *)relocator->rel_memmove; + + /* MBI is the last chunk in the list. */ + head = &relocator->rel_chunk_head; + chunk = STAILQ_LAST(head, chunk, chunk_next); + mbi = (multiboot2_info_header_t *)chunk->chunk_paddr; - src = (uint64_t *)staging; - dst = (uint64_t *)(staging - stage_offset); - last = (uint64_t *)staging_end; + /* + * If chunk paddr == vaddr, the chunk is in place. + * If all chunks are in place, we are done. + */ + chunk = NULL; + while (done == 0) { + /* First check if we have anything to do. */ + if (chunk == NULL) { + done = 1; + STAILQ_FOREACH(chunk, head, chunk_next) { + if (chunk->chunk_paddr != chunk->chunk_vaddr) { + done = 0; + break; + } + } + } + if (done == 1) + break; + + /* + * Make sure the destination is not conflicting + * with rest of the modules. + */ + STAILQ_FOREACH(c, head, chunk_next) { + /* Moved already? */ + if (c->chunk_vaddr == c->chunk_paddr) + continue; + /* Is it the chunk itself? */ + if (c->chunk_vaddr == chunk->chunk_vaddr && + c->chunk_size == chunk->chunk_size) + continue; + if ((c->chunk_vaddr >= chunk->chunk_paddr && + c->chunk_vaddr <= + chunk->chunk_paddr + chunk->chunk_size) || + (c->chunk_vaddr + c->chunk_size >= + chunk->chunk_paddr && + c->chunk_vaddr + c->chunk_size <= + chunk->chunk_paddr + chunk->chunk_size)) + break; + } + /* If there are no conflicts, move to place and restart. */ + if (c == NULL) { + move((void *)chunk->chunk_paddr, + (void *)chunk->chunk_vaddr, + chunk->chunk_size); + chunk->chunk_vaddr = chunk->chunk_paddr; + chunk = NULL; + continue; + } + chunk = STAILQ_NEXT(chunk, chunk_next); + } - while (src < last) - *dst++ = *src++; + return (mbi); } 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 ee7c4bb72e..6378a662d3 100644 --- a/usr/src/boot/sys/boot/efi/loader/loader_efi.h +++ b/usr/src/boot/sys/boot/efi/loader/loader_efi.h @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 2013 The FreeBSD Foundation * All rights reserved. * @@ -24,28 +24,51 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ -#ifndef _LOADER_EFI_COPY_H_ -#define _LOADER_EFI_COPY_H_ +#ifndef _LOADER_EFI_H +#define _LOADER_EFI_H #include <stand.h> +#include <efi.h> +#include <efilib.h> +#include <sys/multiboot2.h> +#include <sys/queue.h> +#include <bootstrap.h> + +struct chunk { + EFI_VIRTUAL_ADDRESS chunk_vaddr; + EFI_PHYSICAL_ADDRESS chunk_paddr; + UINT64 chunk_size; + STAILQ_ENTRY(chunk) chunk_next; +}; + +STAILQ_HEAD(chunk_head, chunk); + +struct relocator { + UINT64 rel_stack; + UINT64 rel_copy; + UINT64 rel_memmove; + struct chunk_head rel_chunk_head; + struct chunk rel_chunklist[]; +}; int efi_autoload(void); -int efi_getdev(void **vdev, const char *devspec, const char **path); -char *efi_fmtdev(void *vdev); -int efi_setcurrdev(struct env_var *ev, int flags, const void *value); +int efi_getdev(void **, const char *, const char **); +char *efi_fmtdev(void *); +int efi_setcurrdev(struct env_var *, int, const void *); -int efi_copy_init(void); +ssize_t efi_copyin(const void *, vm_offset_t, const size_t); +ssize_t efi_copyout(const vm_offset_t, void *, const size_t); +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); -ssize_t efi_copyin(const void *src, vm_offset_t dest, const size_t len); -ssize_t efi_copyout(const vm_offset_t src, void *dest, const size_t len); -ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len); -void * efi_translate(vm_offset_t ptr); +multiboot2_info_header_t *efi_copy_finish(struct relocator *); +void multiboot_tramp(uint32_t, struct relocator *, uint64_t); -void efi_copy_finish(void); +void efi_addsmapdata(struct preloaded_file *); -#endif /* _LOADER_EFI_COPY_H_ */ +#endif /* _LOADER_EFI_H */ diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/sys/boot/efi/loader/main.c index 269f7dfaeb..472ce86509 100644 --- a/usr/src/boot/sys/boot/efi/loader/main.c +++ b/usr/src/boot/sys/boot/efi/loader/main.c @@ -65,6 +65,7 @@ EFI_GUID serial_io = SERIAL_IO_PROTOCOL; extern void acpi_detect(void); void efi_serial_init(void); +extern void efi_getsmap(void); #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void); #endif @@ -209,6 +210,8 @@ main(int argc, CHAR16 *argv[]) archsw.arch_copyin = efi_copyin; archsw.arch_copyout = efi_copyout; archsw.arch_readin = efi_readin; + archsw.arch_loadaddr = efi_loadaddr; + archsw.arch_free_loadaddr = efi_free_loadaddr; #ifdef EFI_ZFS_BOOT /* Note this needs to be set before ZFS init. */ archsw.arch_zfs_probe = efi_zfs_probe; @@ -226,6 +229,7 @@ main(int argc, CHAR16 *argv[]) * printf() etc. once this is done. */ cons_probe(); + efi_getsmap(); /* * Initialise the block cache. Set the upper limit. @@ -329,11 +333,6 @@ main(int argc, CHAR16 *argv[]) setenv("console", "ttya" , 1); } - if (efi_copy_init()) { - printf("failed to allocate staging area\n"); - return (EFI_BUFFER_TOO_SMALL); - } - /* * March through the device switch probing for things. */ @@ -796,6 +795,104 @@ command_fdt(int argc, char *argv[]) COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif +/* + * Chain load another efi loader. + */ +static int +command_chain(int argc, char *argv[]) +{ + EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + EFI_STATUS status; + struct stat st; + struct devdesc *dev; + char *name, *path; + void *buf; + int fd; + + if (argc < 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + name = argv[1]; + + if ((fd = open(name, O_RDONLY)) < 0) { + command_errmsg = "no such file"; + return (CMD_ERROR); + } + + if (fstat(fd, &st) < -1) { + command_errmsg = "stat failed"; + close(fd); + return (CMD_ERROR); + } + + status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); + if (status != EFI_SUCCESS) { + command_errmsg = "failed to allocate buffer"; + close(fd); + return (CMD_ERROR); + } + if (read(fd, buf, st.st_size) != st.st_size) { + command_errmsg = "error while reading the file"; + (void)BS->FreePool(buf); + close(fd); + return (CMD_ERROR); + } + close(fd); + status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); + (void)BS->FreePool(buf); + if (status != EFI_SUCCESS) { + command_errmsg = "LoadImage failed"; + return (CMD_ERROR); + } + status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, + (void **)&loaded_image); + + if (argc > 2) { + int i, len = 0; + CHAR16 *argp; + + for (i = 2; i < argc; i++) + len += strlen(argv[i]) + 1; + + len *= sizeof (*argp); + loaded_image->LoadOptions = argp = malloc (len); + if (loaded_image->LoadOptions == NULL) { + (void) BS->UnloadImage(loaded_image); + return (CMD_ERROR); + } + loaded_image->LoadOptionsSize = len; + for (i = 2; i < argc; i++) { + char *ptr = argv[i]; + while (*ptr) + *(argp++) = *(ptr++); + *(argp++) = ' '; + } + *(--argv) = 0; + } + + if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) + loaded_image->DeviceHandle = + efi_find_handle(dev->d_dev, dev->d_unit); + + dev_cleanup(); + status = BS->StartImage(loaderhandle, NULL, NULL); + if (status != EFI_SUCCESS) { + command_errmsg = "StartImage failed"; + free(loaded_image->LoadOptions); + loaded_image->LoadOptions = NULL; + status = BS->UnloadImage(loaded_image); + return (CMD_ERROR); + } + + return (CMD_ERROR); /* not reached */ +} + +COMMAND_SET(chain, "chain", "chain load file", command_chain); + #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void) diff --git a/usr/src/boot/sys/boot/efi/loader/memmap.c b/usr/src/boot/sys/boot/efi/loader/memmap.c new file mode 100644 index 0000000000..50834ab44e --- /dev/null +++ b/usr/src/boot/sys/boot/efi/loader/memmap.c @@ -0,0 +1,180 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome <tsoome@me.com> + */ + +/* + * Build smap like memory map from efi memmap. + */ + +#include <stand.h> +#include <inttypes.h> +#include <efi.h> +#include <efilib.h> +#include <sys/param.h> +#include <sys/linker.h> +#include <sys/queue.h> +#include <sys/stddef.h> +#include <machine/metadata.h> +#include <machine/pc/bios.h> +#include "bootstrap.h" + +struct smap_buf { + struct bios_smap sb_smap; + STAILQ_ENTRY(smap_buf) sb_bufs; +}; + +static struct bios_smap *smapbase; +static int smaplen; + +/* + * See ACPI 6.1 Table 15-330 UEFI Memory Types and mapping to ACPI address + * range types. + */ +static int +smap_type(int type) +{ + switch (type) { + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: + return (SMAP_TYPE_MEMORY); + case EfiReservedMemoryType: + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + case EfiPalCode: + case EfiUnusableMemory: + return (SMAP_TYPE_RESERVED); + case EfiACPIReclaimMemory: + return (SMAP_TYPE_ACPI_RECLAIM); + case EfiACPIMemoryNVS: + return (SMAP_TYPE_ACPI_NVS); + } + return (SMAP_TYPE_RESERVED); +} + +void +efi_getsmap(void) +{ + UINTN size, desc_size, key; + EFI_MEMORY_DESCRIPTOR *efi_mmap, *p; + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS status; + STAILQ_HEAD(smap_head, smap_buf) head = + STAILQ_HEAD_INITIALIZER(head); + struct smap_buf *cur, *next; + int i, n, ndesc; + int type = -1; + + size = 0; + status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); + efi_mmap = malloc(size); + status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); + if (EFI_ERROR(status)) { + printf("GetMemoryMap: error %lu\n", EFI_ERROR_CODE(status)); + free(efi_mmap); + return; + } + + STAILQ_INIT(&head); + n = 0; + i = 0; + p = efi_mmap; + next = NULL; + ndesc = size / desc_size; + while (i < ndesc) { + if (next == NULL) { + next = malloc(sizeof(*next)); + if (next == NULL) + break; + + next->sb_smap.base = p->PhysicalStart; + next->sb_smap.length = + p->NumberOfPages << EFI_PAGE_SHIFT; + /* + * ACPI 6.1 tells the lower memory should be + * reported as normal memory, so we enforce + * page 0 type even as vmware maps it as + * acpi reclaimable. + */ + if (next->sb_smap.base == 0) + type = SMAP_TYPE_MEMORY; + else + type = smap_type(p->Type); + next->sb_smap.type = type; + + STAILQ_INSERT_TAIL(&head, next, sb_bufs); + n++; + p = NextMemoryDescriptor(p, desc_size); + i++; + continue; + } + addr = next->sb_smap.base + next->sb_smap.length; + if ((smap_type(p->Type) == type) && + (p->PhysicalStart == addr)) { + next->sb_smap.length += + (p->NumberOfPages << EFI_PAGE_SHIFT); + p = NextMemoryDescriptor(p, desc_size); + i++; + } else + next = NULL; + } + smaplen = n; + if (smaplen > 0) { + smapbase = malloc(smaplen * sizeof(*smapbase)); + if (smapbase != NULL) { + n = 0; + STAILQ_FOREACH(cur, &head, sb_bufs) + smapbase[n++] = cur->sb_smap; + } + cur = STAILQ_FIRST(&head); + while (cur != NULL) { + next = STAILQ_NEXT(cur, sb_bufs); + free(cur); + cur = next; + } + } + free(efi_mmap); +} + +void +efi_addsmapdata(struct preloaded_file *kfp) +{ + size_t size; + + if (smapbase == NULL || smaplen == 0) + return; + size = smaplen * sizeof(*smapbase); + file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase); +} + +COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap); + +static int +command_smap(int argc, char *argv[]) +{ + u_int i; + + if (smapbase == NULL || smaplen == 0) + return (CMD_ERROR); + + for (i = 0; i < smaplen; i++) + printf("SMAP type=%02" PRIx32 " base=%016" PRIx64 + " len=%016" PRIx64 "\n", smapbase[i].type, + smapbase[i].base, smapbase[i].length); + return (CMD_OK); +} diff --git a/usr/src/boot/sys/boot/i386/libi386/libi386.h b/usr/src/boot/sys/boot/i386/libi386/libi386.h index ac614ae2eb..433e8f7563 100644 --- a/usr/src/boot/sys/boot/i386/libi386/libi386.h +++ b/usr/src/boot/sys/boot/i386/libi386/libi386.h @@ -25,6 +25,8 @@ * */ +#ifndef _LIBI386_H +#define _LIBI386_H /* * i386 fully-qualified device descriptor. @@ -153,4 +155,8 @@ int bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, vm_offset_t *kernend, int add_smap); int bi_checkcpu(void); +int mb_kernel_cmdline(struct preloaded_file *, struct devdesc *, char **); +void multiboot_tramp(uint32_t, vm_offset_t, vm_offset_t); void pxe_enable(void *pxeinfo); + +#endif /* _LIBI386_H */ diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot.c b/usr/src/boot/sys/boot/i386/libi386/multiboot.c index 32e4fe3b07..e6329240b6 100644 --- a/usr/src/boot/sys/boot/i386/libi386/multiboot.c +++ b/usr/src/boot/sys/boot/i386/libi386/multiboot.c @@ -50,11 +50,13 @@ #include "bootstrap.h" #include "multiboot.h" -#include "pxe.h" #include "../zfs/libzfs.h" #include "../i386/libi386/libi386.h" #include "../i386/btx/lib/btxv86.h" +#define SUPPORT_DHCP +#include <bootp.h> + #define MULTIBOOT_SUPPORTED_FLAGS \ (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO) #define METADATA_FIXED_SIZE (PAGE_SIZE*4) @@ -67,16 +69,6 @@ static vm_offset_t last_addr; extern char bootprog_info[]; -extern int elf32_loadfile_raw(char *filename, u_int64_t dest, - struct preloaded_file **result, int multiboot); -extern int elf64_load_modmetadata(struct preloaded_file *fp, u_int64_t dest); -extern int elf64_obj_loadfile(char *filename, u_int64_t dest, - struct preloaded_file **result); -extern int mb_kernel_cmdline(struct preloaded_file *, struct devdesc *, - char **); - -extern void multiboot_tramp(); - static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **); static int multiboot_exec(struct preloaded_file *); @@ -261,7 +253,6 @@ multiboot_exec(struct preloaded_file *fp) multiboot_memory_map_t *mmap; struct bios_smap *smap; struct devdesc *rootdev; - extern BOOTPLAYER bootplayer; /* dhcp info */ char *cmdline = NULL; size_t len; int error, num, i; @@ -393,10 +384,11 @@ multiboot_exec(struct preloaded_file *fp) mb_info->mmap_addr = VTOP(mmap); mb_info->flags |= MULTIBOOT_INFO_MEM_MAP; - if (strstr(getenv("loaddev"), "pxe") != NULL) { - mb_info->drives_length = sizeof (BOOTPLAYER); + if (strstr(getenv("loaddev"), "pxe") != NULL && + bootp_response != NULL) { + mb_info->drives_length = sizeof (*bootp_response); mb_info->drives_addr = mb_malloc(mb_info->drives_length); - i386_copyin(&bootplayer, mb_info->drives_addr, + i386_copyin(bootp_response, mb_info->drives_addr, mb_info->drives_length); mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO; } diff --git a/usr/src/boot/sys/boot/i386/libi386/pxe.c b/usr/src/boot/sys/boot/i386/libi386/pxe.c index 4a7880f64c..2feb4d0f69 100644 --- a/usr/src/boot/sys/boot/i386/libi386/pxe.c +++ b/usr/src/boot/sys/boot/i386/libi386/pxe.c @@ -58,7 +58,7 @@ static char data_buffer[PXE_BUFFER_SIZE]; static pxenv_t *pxenv_p = NULL; /* PXENV+ */ static pxe_t *pxe_p = NULL; /* !PXE */ -BOOTPLAYER bootplayer = {0}; /* PXE Cached information. */ +static BOOTPLAYER bootplayer = {0}; /* PXE Cached information. */ static int pxe_debug = 0; static int pxe_sock = -1; |