diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 5b9e9dadf7..b49d7cf048 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -158,24 +158,30 @@ $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIR $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') # Don't use $(wildcard ...) here - at least make 3.80 expands this too early! $(TARGET).efi: guard = $(if $(shell echo efi/dis* | grep disabled),:) + ifneq ($(build_id_linker),) -$(TARGET).efi: note.o +ifeq ($(call ld-ver-build-id,$(LD) $(filter -m%,$(EFI_LDFLAGS))),y) +CFLAGS += -DBUILD_ID_EFI +EFI_LDFLAGS += $(build_id_linker) +note_file := efi/buildid.o +else note_file := note.o +endif else note_file := endif -$(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbols-dummy.o efi/mkreloc +$(TARGET).efi: prelink-efi.o $(note_file) efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbols-dummy.o efi/mkreloc $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \ - $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).$(base).0 &&) : + $(BASEDIR)/common/symbols-dummy.o $(note_file) -o $(@D)/.$(@F).$(base).0 &&) : $(guard) efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S $(guard) $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).0 \ | $(guard) $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).0s.S $(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< \ - $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o -o $(@D)/.$(@F).$(base).1 &&) : + $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o $(note_file) -o $(@D)/.$(@F).$(base).1 &&) : $(guard) efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S $(guard) $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).1 \ | $(guard) $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).1s.S @@ -185,8 +191,8 @@ $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbol if $(guard) false; then rm -f $@; echo 'EFI support disabled'; fi rm -f $(@D)/.$(@F).[0-9]* -efi/boot.init.o efi/runtime.o efi/compat.o: $(BASEDIR)/arch/x86/efi/built_in.o -efi/boot.init.o efi/runtime.o efi/compat.o: ; +efi/boot.init.o efi/runtime.o efi/compat.o efi/buildid.o: $(BASEDIR)/arch/x86/efi/built_in.o +efi/boot.init.o efi/runtime.o efi/compat.o efi/buildid.o: ; asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c $(CC) $(filter-out -flto,$(CFLAGS)) -S -o $@ $< diff --git a/xen/arch/x86/efi/Makefile b/xen/arch/x86/efi/Makefile index d62b14fcff..ad3fdf7ff7 100644 --- a/xen/arch/x86/efi/Makefile +++ b/xen/arch/x86/efi/Makefile @@ -9,7 +9,10 @@ efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y) .%.d,$(CFLAGS)) -c che efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y)) efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(call create,runtime.o))) -extra-$(efi) += boot.init.o relocs-dummy.o runtime.o compat.o +extra-$(efi) += boot.init.o relocs-dummy.o runtime.o compat.o buildid.o + +%.o: %.ihex + $(OBJCOPY) -I ihex -O binary $< $@ stub.o: $(extra-y) nogcov-$(efi) += stub.o diff --git a/xen/arch/x86/efi/buildid.ihex b/xen/arch/x86/efi/buildid.ihex new file mode 100644 index 0000000000..a89046db8f --- /dev/null +++ b/xen/arch/x86/efi/buildid.ihex @@ -0,0 +1,3 @@ +:10000000648600004D8DAD57140000000000000014 +:0400100000000000EC +:00000001FF diff --git a/xen/arch/x86/efi/mkreloc.c b/xen/arch/x86/efi/mkreloc.c index 6e52a2e647..bddcce07d3 100644 --- a/xen/arch/x86/efi/mkreloc.c +++ b/xen/arch/x86/efi/mkreloc.c @@ -342,6 +342,7 @@ int main(int argc, char *argv[]) */ if ( memcmp(sec1[i].name, ".initcal", sizeof(sec1[i].name)) == 0 || memcmp(sec1[i].name, ".init.se", sizeof(sec1[i].name)) == 0 || + memcmp(sec1[i].name, ".buildid", sizeof(sec1[i].name)) == 0 || memcmp(sec1[i].name, ".lockpro", sizeof(sec1[i].name)) == 0 ) continue; diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 2d1d43df2d..67cfda1ddd 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -93,7 +93,7 @@ SECTIONS *(.rodata) *(.rodata.*) -#if defined(BUILD_ID) && defined(EFI) +#if defined(BUILD_ID) && defined(EFI) && !defined(BUILD_ID_EFI) /* * No mechanism to put an PT_NOTE in the EFI file - so put * it in .rodata section. (notes.o supplies us with .note.gnu.build-id). @@ -122,19 +122,26 @@ SECTIONS #endif } :text -#if defined(BUILD_ID) && !defined(EFI) +#if defined(BUILD_ID) +#if !defined(EFI) /* * What a strange section name. The reason is that on ELF builds this section * is extracted to notes.o (which then is ingested in the EFI file). But the * compiler may want to inject other things in the .note which we don't care * about - hence this unique name. */ - . = ALIGN(4); .note.gnu.build-id : { __note_gnu_build_id_start = .; *(.note.gnu.build-id) __note_gnu_build_id_end = .; } :note :text +#elif defined(BUILD_ID_EFI) + .buildid : { + __note_gnu_build_id_start = .; + *(.buildid) + __note_gnu_build_id_end = .; + } :text +#endif #endif _erodata = .; diff --git a/xen/common/version.c b/xen/common/version.c index b2afe9624b..4375ea2bd7 100644 --- a/xen/common/version.c +++ b/xen/common/version.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -117,10 +118,33 @@ int xen_build_id_check(const Elf_Note *n, unsigned int n_sz, return 0; } +struct pe_external_debug_directory +{ + uint32_t characteristics; + uint32_t time_stamp; + uint16_t major_version; + uint16_t minor_version; +#define PE_IMAGE_DEBUG_TYPE_CODEVIEW 2 + uint32_t type; + uint32_t size; + uint32_t rva_of_data; + uint32_t filepos_of_data; +}; + +struct cv_info_pdb70 +{ +#define CVINFO_PDB70_CVSIGNATURE 0x53445352 /* "RSDS" */ + uint32_t cv_signature; + unsigned char signature[16]; + uint32_t age; + char pdb_filename[]; +}; + static int __init xen_build_init(void) { const Elf_Note *n = __note_gnu_build_id_start; unsigned int sz; + int rc; /* --build-id invoked with wrong parameters. */ if ( __note_gnu_build_id_end <= &n[0] ) @@ -132,7 +156,38 @@ static int __init xen_build_init(void) sz = (void *)__note_gnu_build_id_end - (void *)n; - return xen_build_id_check(n, sz, &build_id_p, &build_id_len); + rc = xen_build_id_check(n, sz, &build_id_p, &build_id_len); + +#ifdef CONFIG_X86 + /* Alternatively we may have a CodeView record from an EFI build. */ + if ( rc && efi_enabled ) + { + const struct pe_external_debug_directory *dir = (const void *)n; + + /* + * Validate that the full-note-header check above won't prevent + * fall-through to the CodeView case here. + */ + BUILD_BUG_ON(sizeof(*n) > sizeof(*dir)); + + if ( sz > sizeof(*dir) + sizeof(struct cv_info_pdb70) && + dir->type == PE_IMAGE_DEBUG_TYPE_CODEVIEW && + dir->size > sizeof(struct cv_info_pdb70) && + XEN_VIRT_START + dir->rva_of_data == (unsigned long)(dir + 1) ) + { + const struct cv_info_pdb70 *info = (const void *)(dir + 1); + + if ( info->cv_signature == CVINFO_PDB70_CVSIGNATURE ) + { + build_id_p = info->signature; + build_id_len = sizeof(info->signature); + rc = 0; + } + } + } +#endif + + return rc; } __initcall(xen_build_init); #endif