.globl _lkrn_start
_lkrn_start:
+/*****************************************************************************
+ *
+ * OEM information
+ *
+ * For UEFI, we (ab)use the PE format OEM information field to
+ * communicate information to external processing utilities such as
+ * genfsimg.
+ *
+ * Since these fields lie in an unused location in a bzImage kernel
+ * header (and since hybrid PE/bzImage is already a well-known file
+ * format used for dual-mode BIOS/UEFI kernels), we choose to use the
+ * same field locations for BIOS.
+ *
+ */
+
+ .org 0x24
+oem_id:
+ .word 0x18ae
+oem_info:
+ .word 0
+
+#if __x86_64__
+#define R_X86_16 R_X86_64_16
+#else
+#define R_X86_16 R_386_16
+#endif
+
+ /* Allow linked-in objects to request a log partition from genfsimg */
+ .weak ipxe_oem_info_disklog
+ .reloc oem_info, R_X86_16, ipxe_oem_info_disklog
+
/*****************************************************************************
*
* Kernel header
/** @} */
+/**
+ * @defgroup ipxenote Macros to provide ELF notes
+ * @{
+ */
+
+/* Construct an iPXE-specific ELF note */
+#define IPXE_NOTE( type ) \
+ __asm__ ( ".section \".note.ipxe\", \"\", " \
+ _S2 ( ASM_TCHAR ) "note\n\t" \
+ /* Owner name length */ \
+ ".long 4\n\t" \
+ /* Content length */ \
+ ".long 0\n\t" \
+ /* Type */ \
+ ".long " _S2 ( _C2 ( IPXE_NOTE_, type ) ) \
+ "\n\t" \
+ /* Owner name */ \
+ ".ascii \"iPXE\"\n\t" \
+ ".previous\n\t" )
+
+/** Build will use a disk-based console log, if present */
+#define IPXE_NOTE_DISKLOG 0x18aed109
+
+/** @} */
+
/**
* @defgroup objmacros Macros to provide or require explicit objects
* @{
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Shdr Elf32_Shdr
+#define Elf_Nhdr Elf32_Nhdr
#define Elf_Sym Elf32_Sym
#define Elf_Addr Elf32_Addr
#define Elf_Rel Elf32_Rel
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Shdr Elf64_Shdr
+#define Elf_Nhdr Elf64_Nhdr
#define Elf_Sym Elf64_Sym
#define Elf_Addr Elf64_Addr
#define Elf_Rel Elf64_Rel
/** Number of data directory entries */
#define NUMBER_OF_DIRECTORY_ENTRIES 8
+/** Build requested a console log partition */
+#define IPXE_NOTE_DISKLOG 0x18aed109
+
+/** OEM identifier used for iPXE */
+#define IPXE_OEM_ID 0x18ae
+
+/** OEM information: console log partition requested */
+#define IPXE_OEM_INFO_DISKLOG 0x0001
+
struct elf_file {
void *data;
size_t len;
static struct pe_header efi_pe_header = {
.dos = {
.e_magic = EFI_IMAGE_DOS_SIGNATURE,
+ .e_oemid = IPXE_OEM_ID,
.e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
},
.nt = {
unsigned int subsystem;
/** Create hybrid BIOS/UEFI binary */
int hybrid;
+ /** Use disk-based console log */
+ int disklog;
};
/**
}
}
+/**
+ * Process note records
+ *
+ * @v elf ELF file
+ * @v shdr ELF section header
+ * @v opts Options
+ */
+static void process_notes ( struct elf_file *elf, const Elf_Shdr *shdr,
+ struct options *opts ) {
+ const struct {
+ Elf_Nhdr hdr;
+ char name[4];
+ } __attribute__ (( packed )) *note;
+ static const char name[4] = { 'i', 'P', 'X', 'E' };
+ size_t remaining;
+
+ /* Process each note */
+ note = ( elf->data + shdr->sh_offset );
+ remaining = shdr->sh_size;
+ while ( remaining ) {
+
+ /* Sanity check */
+ if ( ( remaining < sizeof ( *note ) ) ||
+ ( note->hdr.n_namesz != sizeof ( name ) ) ||
+ ( note->hdr.n_descsz != 0 ) ||
+ ( memcmp ( note->name, name, sizeof ( name ) ) != 0 ) ) {
+ eprintf ( "Invalid iPXE note\n" );
+ exit ( 1 );
+ }
+
+ /* Handle note type */
+ switch ( note->hdr.n_type ) {
+ case IPXE_NOTE_DISKLOG:
+ opts->disklog = 1;
+ break;
+ default:
+ eprintf ( "Unrecognised iPXE note type %#x\n",
+ note->hdr.n_type );
+ exit ( 1 );
+ }
+
+ /* Move to next note */
+ note = ( ( ( void * ) note ) + sizeof ( *note ) );
+ remaining -= sizeof ( *note );
+ }
+}
+
/**
* Create relocations section
*
/* Process .rela relocations */
process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
&pe_reltab, opts );
+
+ } else if ( shdr->sh_type == SHT_NOTE ) {
+
+ /* Process .note records */
+ process_notes ( &elf, shdr, opts );
}
}
/* Update image base address */
update_image_base ( &pe_header, pe_sections, pe_reltab );
+ /* Update OEM information */
+ if ( opts->disklog )
+ pe_header.dos.e_oeminfo |= IPXE_OEM_INFO_DISKLOG;
+
/* Create the .reloc section */
*(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
next_pe_section = &(*next_pe_section)->next;
esac
}
+# Check if binary wants a log partition
+#
+wants_disklog() {
+ local FILENAME
+ local OEMID
+ local OEMINFO
+ local FLAG
+
+ FILENAME="${1}"
+
+ OEMID=$(get_word "${FILENAME}" 0x24)
+ OEMINFO=$(get_word "${FILENAME}" 0x26)
+ FLAG=$(( OEMINFO & 0x0001 ))
+ [ "${OEMID}" = "18ae" -a "${FLAG}" -ne "0" ]
+}
+
# Find syslinux file
#
find_syslinux_file() {
BIOSDIR="${ISODIR}"
SYSLINUXCFG="${ISODIR}/isolinux.cfg"
FATPART=
+ LOGPART=
;;
*.sdsk)
ISOIMG=
BIOSDIR="${FATDIR}"
SYSLINUXCFG="${FATDIR}/syslinux.cfg"
FATPART=
+ LOGPART=
;;
*)
ISOIMG=
BIOSDIR="${FATDIR}"
SYSLINUXCFG="${FATDIR}/syslinux.cfg"
FATPART="4"
+ LOGPART="3"
;;
esac
drive F:
file="${FATIMG}"
${FATPART:+partition=}${FATPART}
+drive L:
+ file="${FATIMG}"
+ ${LOGPART:+partition=}${LOGPART}
EOF
export MTOOLSRC
#
LKRN=
EFI=
+DISKLOG=
for FILENAME ; do
case "${FILENAME}" in
*.lkrn)
exit 1
fi
cp "${FILENAME}" "${DESTDIR}/${DESTFILE}"
+ if wants_disklog "${FILENAME}" ; then
+ DISKLOG=1
+ fi
done
# Configure ISO image, if applicable
FATSERIAL=$(( SOURCE_DATE_EPOCH % 100000000 ))
FATARGS="${FATARGS} -N ${FATSERIAL}"
fi
+ if [ -n "${DISKLOG}" -a -n "${LOGPART}" ] ; then
+ LOGTYPE=0xe0
+ LOGCYLS=1
+ LOGSIZE=$(( LOGCYLS * FATALIGN ))
+ FATSIZE=$(( LOGSIZE + FATSIZE ))
+ LOGOFFS="${FATOFFS}"
+ FATOFFS="${LOGSIZE}"
+ fi
touch "${FATIMG}"
truncate -s 0 "${FATIMG}"
truncate -s $(( FATSIZE * 512 )) "${FATIMG}"
-b "${FATOFFS}" F:
mpartition -a F:
fi
+ if [ -n "${DISKLOG}" -a -n "${LOGPART}" ] ; then
+ mpartition -c -t "${LOGCYLS}" -h "${FATHEADS}" -s "${FATSECTS}" \
+ -b "${LOGOFFS}" -T "${LOGTYPE}" L:
+ printf "iPXE LOG\n\n" |
+ dd of="${FATIMG}" seek="${LOGOFFS}" conv=notrunc status=none
+ fi
mformat -v iPXE ${FATARGS} F:
mcopy -s "${FATDIR}"/* F:
if [ "${BIOSDIR}" = "${FATDIR}" ] ; then