diff --git a/.gitignore b/.gitignore index 1e566f4de..6ff425546 100644 --- a/.gitignore +++ b/.gitignore @@ -111,6 +111,10 @@ cscope.* *.swp *.swo +# x86 UEFI files +cpu/x86/uefi/Makefile.uefi +cpu/x86/uefi/edk2 + # galileo bsp files platform/galileo/bsp/libc/Makefile.libc platform/galileo/bsp/libc/i586-elf/ @@ -120,4 +124,6 @@ platform/galileo/bsp/grub/bin/ # galileo build and debug artefacts *.galileo +*.galileo.dll +*.galileo.efi LOG_OPENOCD diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index c243dddcd..d6e692e9a 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -14,6 +14,12 @@ STRIP = strip # tables saves space and has not caused any readily-apparent functional # changes. # +# Furthermore, the .eh_frame and .eh_frame_hdr sections that are otherwise +# generated are treated as code sections by the UEFI GenFw program, since they +# are read-only alloc sections. They get grouped with the actual code +# sections, ahead of the data sections. This perturbs symbols and complicates +# debugging. +# # Synchronize the unwind table options here with the CFLAGS and CXXFLAGS in # ./bsp/libc/build_newlib.sh. CFLAGS += -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables @@ -23,7 +29,9 @@ ifeq ($(BUILD_RELEASE),1) CFLAGS += -Os -fno-strict-aliasing -ffunction-sections -fdata-sections # XXX: --gc-sections can be very tricky sometimes. If somehow the release # binary seems to be broken, check if removing this option fixes the issue. - LDFLAGS += -Wl,--strip-all,--gc-sections +# Applying the --strip-all option to the UEFI build may induce an "Invalid operation" error. +# The UEFI GenFw program strips symbols. + MULTIBOOT_LDFLAGS += -Wl,--strip-all,--gc-sections else CFLAGS += -O0 ifeq ($(findstring clang,$(CC)),clang) diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 192fd302b..59601d8d5 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -7,3 +7,31 @@ CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci. CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/cpu/x86/quarkX1000.ld ASFLAGS += --32 -march=i586 -mtune=i586 + +### UEFI support + +UEFI_DIR = $(CONTIKI_CPU)/uefi + +ifndef EN_UEFI +# Include a Makefile generated by the build_uefi.sh script, if available. +# If that script was not run, then UEFI support will not be built. +-include $(UEFI_DIR)/Makefile.uefi +endif + +ifeq ($(EN_UEFI),1) + EDK2_DIR = $(UEFI_DIR)/edk2 + + GEN_FW = $(EDK2_DIR)/BaseTools/Source/C/bin/GenFw + + CONTIKI_CPU_DIRS += uefi + CONTIKI_SOURCEFILES += bootstrap_uefi.c + CFLAGS += -I$(EDK2_DIR)/MdePkg/Include -I$(EDK2_DIR)/MdePkg/Include/Ia32 +else + $(info Note: UEFI support is disabled.) + ifndef EN_UEFI + $(info To enable UEFI support, run $(CONTIKI_CPU)/uefi/build_uefi.sh prior) + $(info to building Contiki.) + else + $(info LTO and UEFI support are mututally-exclusive.) + endif +endif diff --git a/cpu/x86/quarkX1000.ld b/cpu/x86/quarkX1000.ld index 8beb425cf..b50c47bb8 100644 --- a/cpu/x86/quarkX1000.ld +++ b/cpu/x86/quarkX1000.ld @@ -36,26 +36,39 @@ SECTIONS { /* OS-Dev Wiki says it is common for kernels to start at 1M. Addresses before that are used by BIOS/EFI, the bootloader and memory-mapped I/O. - */ - . = 1M; - .text ALIGN (4K) : + The UEFI GenFw program inserts a 0x240-byte offset between the image base and + the .text section. We add that same offset here to align the symbols in the + UEFI DLL with those in the final UEFI binary to make debugging easier. We also + apply 32-byte alignments to sections rather than more conventional 4K-byte + alignments to avoid symbols being shifted from the intermediate DLL to the + final UEFI image as would occur if the GenFw program shifted the .text section + from a higher, 4K-aligned offset to the 0x240-byte offset from the image base. + Such shifting may make debugging more difficult by preventing the DLL from + being a directly-useful source of symbol information. The debugging symbols + are not included in the final UEFI image. The GenFw program uses a minimum + section alignment of 32 bytes, so smaller alignment granularities may also + result in symbol perturbation. + */ + . = 1M + 0x240; + + .text ALIGN (32) : { KEEP(*(.multiboot)) *(.text*) } - .rodata ALIGN (4K) : + .rodata ALIGN (32) : { *(.rodata*) } - .data ALIGN (4K) : + .data ALIGN (32) : { *(.data*) } - .bss ALIGN (4K) : + .bss ALIGN (32) : { *(COMMON) *(.bss*) diff --git a/cpu/x86/uefi/bootstrap_uefi.c b/cpu/x86/uefi/bootstrap_uefi.c new file mode 100644 index 000000000..f6981eb96 --- /dev/null +++ b/cpu/x86/uefi/bootstrap_uefi.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT 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. + */ + +#include +#include + +#define MAX_MEM_DESC 128 + +void start(void); + +EFI_STATUS EFIAPI +uefi_start(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_MEMORY_DESCRIPTOR mem_map[MAX_MEM_DESC]; + UINTN mem_map_len = sizeof(mem_map); + UINTN mem_map_key; + UINTN mem_map_desc_sz; + UINT32 mem_map_rev; + + EFI_STATUS res; + + res = SystemTable->BootServices->GetMemoryMap(&mem_map_len, + mem_map, + &mem_map_key, + &mem_map_desc_sz, + &mem_map_rev); + if(res != EFI_SUCCESS) { + return EFI_ABORTED; + } + + res = SystemTable->BootServices->ExitBootServices(ImageHandle, mem_map_key); + if(res != EFI_SUCCESS) { + return EFI_ABORTED; + } + + start(); + + /* Should not be reachable: */ + return EFI_SUCCESS; +} diff --git a/cpu/x86/uefi/build_uefi.sh b/cpu/x86/uefi/build_uefi.sh new file mode 100755 index 000000000..5b7cba644 --- /dev/null +++ b/cpu/x86/uefi/build_uefi.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# This script will always run on its own basepath, no matter where you call it from. +pushd ${SCRIPT_DIR} + +# Download the UEFI tool and library sources: +git clone --depth=1 https://github.com/tianocore/edk2 || exit +# This script only supports building the tools on 64-bit hosts: +export ARCH=X64 +# Build common sources required by the GenFw tool: +make -C edk2/BaseTools/Source/C/Common || exit +# Build the GenFw tool that is used to generate UEFI binaries: +make -C edk2/BaseTools/Source/C/GenFw || exit +# Create a makefile that indicates to the Contiki build system that UEFI support +# should be built: +echo "EN_UEFI = 1" > Makefile.uefi + +popd diff --git a/platform/galileo/Makefile.customrules-galileo b/platform/galileo/Makefile.customrules-galileo index eceebb9c4..d0527cf8f 100644 --- a/platform/galileo/Makefile.customrules-galileo +++ b/platform/galileo/Makefile.customrules-galileo @@ -1,15 +1,48 @@ GDB ?= gdb OPENOCD_SCRIPTS = $(CONTIKI)/platform/galileo/bsp/openocd-scripts -.PHONY: debug +.PHONY: debug $(CONTIKI_PROJECT) -debug: $(CONTIKI_PROJECT).$(TARGET) +# Multiboot ELF binary +MULTIBOOT_SFX = $(TARGET) +MULTIBOOT = $(CONTIKI_PROJECT).$(MULTIBOOT_SFX) +# UEFI binary +UEFI_DLL_SFX = $(TARGET).dll +UEFI_DLL = $(CONTIKI_PROJECT).$(UEFI_SFX) +UEFI_LDFLAGS += -Xlinker --emit-relocs -Xlinker --entry=uefi_start +UEFI_SFX = $(TARGET).efi +UEFI = $(CONTIKI_PROJECT).$(UEFI_SFX) + +# Suffixes for final (non-intermediate) files to be built +FINAL_SFXS = $(MULTIBOOT_SFX) +ifeq ($(EN_UEFI),1) +FINAL_SFXS += $(UEFI_SFX) +endif + +debug: $(MULTIBOOT) @openocd -s $(OPENOCD_SCRIPTS) -f debug.cfg &> $(shell pwd)/LOG_OPENOCD & @$(GDB) $< -ex "target remote :3333" CUSTOM_RULE_LINK=1 -%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a - $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ - ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ - @$(SIZE) $@ +define LINK_template = +%.$(1): %.co $$(PROJECT_OBJECTFILES) $$(PROJECT_LIBRARIES) contiki-$$(TARGET).a + $$(TRACE_LD) + $$(Q)$$(LD) $$(LDFLAGS) $(2) $$(TARGET_STARTFILES) $${filter-out %.a,$$^} \ + $${filter %.a,$$^} $$(TARGET_LIBFILES) -o $$@ +endef + +$(eval $(call LINK_template,$(MULTIBOOT_SFX),$(MULTIBOOT_LDFLAGS))) +$(eval $(call LINK_template,$(UEFI_DLL_SFX),$(UEFI_LDFLAGS))) + +%.$(UEFI_SFX): %.$(UEFI_DLL_SFX) + $(Q)$(GEN_FW) -o $@ -e UEFI_APPLICATION $^ + # The Intel Galileo firmware has been observed to not relocate the image + # if its base is set to the 1M boundary. This makes debugging easier, + # since the symbols in the intermediate DLL then correspond to the load + # addresses. + $(Q)$(GEN_FW) -o $@ --rebase 0x100000 $@ + +$(CONTIKI_PROJECT): $(addprefix $(CONTIKI_PROJECT).,$(FINAL_SFXS)) + @$(SIZE) $^ + +CLEAN += $(addprefix $(CONTIKI_PROJECT).,$(FINAL_SFXS)) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index e58722634..e769cf068 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -71,6 +71,12 @@ You can also build a "Release" image by setting the BUILD_RELEASE variable to $ cd examples/hello-world/ && make TARGET=galileo BUILD_RELEASE=1 ``` +To also generate an '.galileo.efi' file which is a UEFI [4] image, +you can run the following command prior to building applications: +``` +$ cpu/x86/uefi/build_uefi.sh +``` + Running ------- @@ -90,6 +96,8 @@ detailed instructions. Mount the sdcard in directory /mnt/sdcard. +#### Approach for Multiboot-compliant ELF Image + Copy Contiki binary image to sdcard ``` $ cp examples/hello-world/hello-world.galileo /mnt/sdcard @@ -100,6 +108,13 @@ Copy grub binary to sdcard $ cp platform/galileo/bsp/grub/bin/grub.efi /mnt/sdcard ``` +#### Approach for UEFI Image + +Copy Contiki binary image to sdcard +``` +$ cp examples/hello-world/hello-world.galileo.efi /mnt/sdcard +``` + ### Connect to the console output Connect the serial cable to your computer as shown in [2]. @@ -117,8 +132,11 @@ Press [Enter] to directly boot. Press [F7] to show boot menu options. ``` -Press and select the option "UEFI Internal Shell" within the menu. Once -you have a shell, run the following commands to run grub application: +Press and select the option "UEFI Internal Shell" within the menu. + +#### Boot Multiboot-compliant ELF Image + +Once you have a shell, run the following commands to run grub application: ``` $ fs0: $ grub.efi @@ -131,6 +149,16 @@ $ multiboot /hello-world.galileo $ boot ``` +#### Boot UEFI Image + +Once you have a shell, run the following commands to boot Contiki image: +``` +$ fs0: +$ hello-world.galileo.efi +``` + +### Verify that Contiki is Running + This should boot the Contiki image, resulting in the following messages being sent to the serial console: ``` @@ -176,3 +204,5 @@ References [2] http://www.intel.com/support/galileo/sb/CS-035124.htm [3] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html + +[4] http://www.uefi.org/ diff --git a/platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch b/platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch new file mode 100644 index 000000000..97c7f4f3a --- /dev/null +++ b/platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch @@ -0,0 +1,19 @@ +--- newlib/libc/stdio/nano-vfprintf_local.h 2014-07-04 10:21:43.000000000 -0700 ++++ newlib/libc/stdio/nano-vfprintf_local.h 2015-07-17 12:51:12.974269921 -0700 +@@ -230,5 +230,5 @@ _printf_float (struct _reent *data, + FILE *fp, + int (*pfunc)(struct _reent *, FILE *, + _CONST char *, size_t len), +- va_list *ap) _ATTRIBUTE((__weak__)); ++ va_list *ap); + #endif +--- newlib/libc/stdio/nano-vfscanf_local.h 2014-07-04 10:21:44.000000000 -0700 ++++ newlib/libc/stdio/nano-vfscanf_local.h 2015-07-17 12:51:33.967362409 -0700 +@@ -173,6 +173,6 @@ _scanf_i (struct _reent *rptr, + extern int + _scanf_float (struct _reent *rptr, + struct _scan_data_t *pdata, +- FILE *fp, va_list *ap) _ATTRIBUTE((__weak__)); ++ FILE *fp, va_list *ap); + + #endif