From 9e8d431a0d58caba3c5f65d4e30fd259d2f782e1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 10 Jun 2012 18:25:26 +0100 Subject: [PATCH] [romprefix] Add a dummy ROM header to cover the .mrom payload The header of a .mrom image declares its length to be only a few kilobytes; the remainder is accessed via a sideband mechanism. This makes it difficult to append an additional ROM image, such as an EFI ROM. Add a second, dummy ROM header covering the payload portion of the .mrom image, allowing consumers to locate any appended ROM images in the usual way. Signed-off-by: Michael Brown --- src/arch/i386/prefix/libprefix.S | 26 ++++---- src/arch/i386/prefix/mromprefix.S | 105 +++++++++++++++++++++++------- src/arch/i386/prefix/romprefix.S | 46 +++++-------- src/arch/i386/scripts/i386.lds | 25 ++++++- src/util/zbin.c | 70 +++++++++++++++++--- 5 files changed, 198 insertions(+), 74 deletions(-) diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index 0962debb..e5bc7bb1 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -663,18 +663,22 @@ install_prealloc: /* Save decompression temporary area physical address */ pushl %edi - /* Install .text16.early */ + /* Install .text16.early and calculate %ecx as offset to next block */ progress " .text16.early\n" pushl %esi xorl %esi, %esi movw %cs, %si shll $4, %esi + pushl %esi /* Save original %cs:0000 */ addl $_text16_early_lma, %esi movzwl %ax, %edi shll $4, %edi movl $_text16_early_filesz, %ecx movl $_text16_early_memsz, %edx call install_block /* .text16.early */ + popl %ecx /* Calculate offset to next block */ + subl %esi, %ecx + negl %ecx popl %esi #ifndef KEEP_IT_REAL @@ -729,7 +733,7 @@ payload_death_message: jnz 1f movw %cs, %si shll $4, %esi -1: addl payload_lma, %esi +1: addl %ecx, %esi /* Install .text16.late and .data16 */ progress " .text16.late\n" @@ -850,17 +854,6 @@ close_payload_vector: .word 0 .size close_payload_vector, . - close_payload_vector - /* Payload address */ - .section ".prefix.lib", "awx", @progbits -payload_lma: - .long 0 - .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "ADHL" - .long payload_lma - .long 1 - .long 0 - .previous - /* Dummy routines to open and close payload */ .section ".text16.early.data", "aw", @progbits .weak open_payload @@ -914,6 +907,10 @@ uninstall: .ascii "PAYL" .long 0 .long 0 + .long _payload_align + .ascii "COPY" + .long _pprefix_lma + .long _pprefix_filesz .long _max_align .ascii PACK_OR_COPY .long _text16_late_lma @@ -927,3 +924,6 @@ uninstall: .long _textdata_lma .long _textdata_filesz .long _max_align + + .weak _payload_align + .equ _payload_align, 1 diff --git a/src/arch/i386/prefix/mromprefix.S b/src/arch/i386/prefix/mromprefix.S index 7bbe44c4..d7b7fc3f 100644 --- a/src/arch/i386/prefix/mromprefix.S +++ b/src/arch/i386/prefix/mromprefix.S @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PCI_BAR_EXPROM 0x30 #define ROMPREFIX_EXCLUDE_PAYLOAD 1 +#define ROMPREFIX_MORE_IMAGES 1 #define _rom_start _mrom_start #include "romprefix.S" @@ -46,8 +47,10 @@ FILE_LICENCE ( GPL2_OR_LATER ) * Parameters: * %ds:0000 : Prefix * %esi : Buffer for copy of image source (or zero if no buffer available) + * %ecx : Expected offset within buffer of first payload block * Returns: * %esi : Valid image source address (buffered or unbuffered) + * %ecx : Actual offset within buffer of first payload block * CF set on error */ .section ".text16.early", "awx", @progbits @@ -56,23 +59,25 @@ open_payload: /* Preserve registers */ pushl %eax pushw %bx - pushl %ecx pushl %edx pushl %edi pushw %bp + pushw %es pushw %ds - /* Retrieve bus:dev.fn and image source length from .prefix */ + /* Retrieve bus:dev.fn from .prefix */ movw init_pci_busdevfn, %bx - movl image_source_len_dword, %ecx /* Set up %ds for access to .text16.early */ pushw %cs popw %ds - /* Store bus:dev.fn and image source length to .text16.early */ + /* Set up %es for access to flat address space */ + xorw %ax, %ax + movw %ax, %es + + /* Store bus:dev.fn to .text16.early */ movw %bx, payload_pci_busdevfn - movl %ecx, rom_bar_copy_len_dword /* Get expansion ROM BAR current value */ movw $PCI_BAR_EXPROM, %di @@ -159,27 +164,32 @@ find_mem_bar: * properly support flat real mode, it will die horribly.) */ pushl %esi - pushw %es movl %esi, %edi movl %eax, %esi - movl rom_bar_copy_len_dword, %ecx - xorw %ax, %ax - movw %ax, %es + addr32 es movzbl 2(%esi), %ecx + shll $7, %ecx + addr32 es movzbl 2(%esi,%ecx,4), %edx + shll $7, %edx + addl %edx, %ecx addr32 es rep movsl - popw %es popl %esi jmp 2f 1: /* We have no buffer; set %esi to the BAR address */ movl %eax, %esi 2: + /* Locate first payload block (after the dummy ROM header) */ + addr32 es movzbl 2(%esi), %ecx + shll $9, %ecx + addl $_pprefix_skip, %ecx + clc /* Restore registers and return */ 99: popw %ds + popw %es popw %bp popl %edi popl %edx - popl %ecx popw %bx popl %eax lret @@ -200,11 +210,6 @@ rom_bar_size: .long 0 .size rom_bar_size, . - rom_bar_size - .section ".text16.early.data", "aw", @progbits -rom_bar_copy_len_dword: - .long 0 - .size rom_bar_copy_len_dword, . - rom_bar_copy_len_dword - .section ".text16.early.data", "aw", @progbits stolen_bar_register: .word 0 @@ -419,16 +424,68 @@ pci_set_mem_access: ret .size pci_set_mem_access, . - pci_set_mem_access -/* Image source area length (in dwords) +/* Payload prefix * + * We include a dummy ROM header to cover the "hidden" portion of the + * overall ROM image. */ - .section ".prefix", "ax", @progbits -image_source_len_dword: - .long 0 - .size image_source_len_dword, . - image_source_len_dword + .globl _payload_align + .equ _payload_align, 512 + .section ".pprefix", "ax", @progbits + .org 0x00 +mromheader: + .word 0xaa55 /* BIOS extension signature */ +mromheader_size: .byte 0 /* Size in 512-byte blocks */ + .org 0x18 + .word mpciheader + .org 0x1a + .word 0 + .size mromheader, . - mromheader + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "ADDL" - .long image_source_len_dword - .long 4 + .ascii "APPB" + .long mromheader_size + .long 512 + .long 0 + .previous + +mpciheader: + .ascii "PCIR" /* Signature */ + .word pci_vendor_id /* Vendor identification */ + .word pci_device_id /* Device identification */ + .word 0x0000 /* Device list pointer */ + .word mpciheader_len /* PCI data structure length */ + .byte 0x03 /* PCI data structure revision */ + .byte 0x02, 0x00, 0x00 /* Class code */ +mpciheader_image_length: + .word 0 /* Image length */ + .word 0x0001 /* Revision level */ + .byte 0xff /* Code type */ + .byte 0x80 /* Last image indicator */ +mpciheader_runtime_length: + .word 0 /* Maximum run-time image length */ + .word 0x0000 /* Configuration utility code header */ + .word 0x0000 /* DMTF CLP entry point */ + .equ mpciheader_len, . - mpciheader + .size mpciheader, . - mpciheader + + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "APPW" + .long mpciheader_image_length + .long 512 + .long 0 + .ascii "APPW" + .long mpciheader_runtime_length + .long 512 + .long 0 + .previous + +/* Fix up additional image source size + * + */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADPW" + .long extra_size + .long 512 .long 0 .previous diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 0f924153..950e0845 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -39,6 +39,14 @@ FILE_LICENCE ( GPL2_OR_LATER ) #else #define ZINFO_TYPE_ADxB "ADDB" #define ZINFO_TYPE_ADxW "ADDW" +#endif + +/* Allow ROM to be marked as containing multiple images + */ +#if ROMPREFIX_MORE_IMAGES +#define INDICATOR 0x00 +#else +#define INDICATOR 0x80 #endif .text @@ -85,7 +93,7 @@ pciheader_image_length: .word 0 /* Image length */ .word 0x0001 /* Revision level */ .byte 0x00 /* Code type */ - .byte 0x80 /* Last image indicator */ + .byte INDICATOR /* Last image indicator */ pciheader_runtime_length: .word 0 /* Maximum run-time image length */ .word 0x0000 /* Configuration utility code header */ @@ -98,7 +106,7 @@ pciheader_runtime_length: .long pciheader_image_length .long 512 .long 0 - .ascii ZINFO_TYPE_ADxW + .ascii "ADHW" .long pciheader_runtime_length .long 512 .long 0 @@ -327,7 +335,8 @@ pmm_scan: /* We have PMM and so a 1kB stack: preserve whole registers */ pushal /* Allocate image source PMM block */ - movzwl image_source_size, %ecx + movzbl romheader_size, %ecx + addw extra_size, %cx shll $5, %ecx movl $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx movw $get_pmm_image_source, %bp @@ -341,11 +350,11 @@ pmm_scan: movl %esi, %edi xorl %esi, %esi movzbl romheader_size, %ecx - shll $9, %ecx - addr32 rep movsb /* PMM presence implies flat real mode */ + shll $7, %ecx + addr32 rep movsl /* PMM presence implies flat real mode */ popw %es /* Shrink ROM */ - movb shrunk_rom_size, %al + movw pciheader_runtime_length, %ax movb %al, romheader_size 1: /* Allocate decompression PMM block. Round up the size to the * nearest 128kB and use the size within the PMM handle; this @@ -573,31 +582,12 @@ image_source: .long 0 .size image_source, . - image_source -/* Image source size (in 512-byte sectors) +/* Additional image source size (in 512-byte sectors) * */ -image_source_size: +extra_size: .word 0 - .size image_source_size, . - image_source_size - .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "ADDW" - .long image_source_size - .long 512 - .long 0 - .previous - -/* Shrunk ROM size (in 512-byte sectors) - * - */ -shrunk_rom_size: - .byte 0 - .size shrunk_rom_size, . - shrunk_rom_size - .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "ADHB" - .long shrunk_rom_size - .long 512 - .long 0 - .previous + .size extra_size, . - extra_size /* Temporary decompression area * diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds index 763b80d6..fb763656 100644 --- a/src/arch/i386/scripts/i386.lds +++ b/src/arch/i386/scripts/i386.lds @@ -1,4 +1,4 @@ -/* -*- sh -*- */ +/* -*- ld-script -*- */ /* * Linker script for i386 images @@ -121,6 +121,23 @@ SECTIONS { _textdata_filesz = ABSOLUTE ( _mtextdata ) - ABSOLUTE ( _textdata ); _textdata_memsz = ABSOLUTE ( _etextdata ) - ABSOLUTE ( _textdata ); + /* + * Payload prefix + * + * If present, this will be placed between .text16.early and .text16.late. + * + */ + .pprefix 0x0 : AT ( _pprefix_lma ) { + _pprefix = .; + KEEP(*(.pprefix)) + KEEP(*(.pprefix.*)) + _mpprefix = .; + } .bss.pprefix (NOLOAD) : AT ( _end_lma ) { + _epprefix = .; + } + _pprefix_filesz = ABSOLUTE ( _mpprefix ) - ABSOLUTE ( _pprefix ); + _pprefix_memsz = ABSOLUTE ( _epprefix ) - ABSOLUTE ( _pprefix ); + /* * Compressor information block * @@ -187,8 +204,14 @@ SECTIONS { _text16_early_lma = .; . += _text16_early_filesz; + . = ALIGN ( _max_align ); + . = ALIGN ( _payload_align ); + _pprefix_lma = .; + . += _pprefix_filesz; + . = ALIGN ( _max_align ); _payload_lma = .; + _pprefix_skip = ABSOLUTE ( _payload_lma ) - ABSOLUTE ( _pprefix_lma ); _text16_late_lma = .; . += _text16_late_filesz; diff --git a/src/util/zbin.c b/src/util/zbin.c index a9195164..0dabaf1e 100644 --- a/src/util/zbin.c +++ b/src/util/zbin.c @@ -237,15 +237,15 @@ static int process_zinfo_add ( struct input_file *input __attribute__ (( unused )), struct output_file *output, size_t len, - struct zinfo_add *add, + struct zinfo_add *add, size_t offset, size_t datasize ) { - size_t offset = add->offset; void *target; signed long addend; unsigned long size; signed long val; unsigned long mask; + offset += add->offset; if ( ( offset + datasize ) > output->len ) { fprintf ( stderr, "Add at %#zx outside output buffer\n", offset ); @@ -319,42 +319,90 @@ static int process_zinfo_addb ( struct input_file *input, struct output_file *output, union zinfo_record *zinfo ) { return process_zinfo_add ( input, output, output->len, - &zinfo->add, 1 ); + &zinfo->add, 0, 1 ); } static int process_zinfo_addw ( struct input_file *input, struct output_file *output, union zinfo_record *zinfo ) { return process_zinfo_add ( input, output, output->len, - &zinfo->add, 2 ); + &zinfo->add, 0, 2 ); } static int process_zinfo_addl ( struct input_file *input, struct output_file *output, union zinfo_record *zinfo ) { return process_zinfo_add ( input, output, output->len, - &zinfo->add, 4 ); + &zinfo->add, 0, 4 ); } static int process_zinfo_adhb ( struct input_file *input, struct output_file *output, union zinfo_record *zinfo ) { return process_zinfo_add ( input, output, output->hdr_len, - &zinfo->add, 1 ); + &zinfo->add, 0, 1 ); } static int process_zinfo_adhw ( struct input_file *input, struct output_file *output, union zinfo_record *zinfo ) { return process_zinfo_add ( input, output, output->hdr_len, - &zinfo->add, 2 ); + &zinfo->add, 0, 2 ); } static int process_zinfo_adhl ( struct input_file *input, struct output_file *output, union zinfo_record *zinfo ) { return process_zinfo_add ( input, output, output->hdr_len, - &zinfo->add, 4 ); + &zinfo->add, 0, 4 ); +} + +static int process_zinfo_adpb ( struct input_file *input, + struct output_file *output, + union zinfo_record *zinfo ) { + return process_zinfo_add ( input, output, + ( output->len - output->hdr_len ), + &zinfo->add, 0, 1 ); +} + +static int process_zinfo_adpw ( struct input_file *input, + struct output_file *output, + union zinfo_record *zinfo ) { + return process_zinfo_add ( input, output, + ( output->len - output->hdr_len ), + &zinfo->add, 0, 2 ); +} + +static int process_zinfo_adpl ( struct input_file *input, + struct output_file *output, + union zinfo_record *zinfo ) { + return process_zinfo_add ( input, output, + ( output->len - output->hdr_len ), + &zinfo->add, 0, 4 ); +} + +static int process_zinfo_appb ( struct input_file *input, + struct output_file *output, + union zinfo_record *zinfo ) { + return process_zinfo_add ( input, output, + ( output->len - output->hdr_len ), + &zinfo->add, output->hdr_len, 1 ); +} + +static int process_zinfo_appw ( struct input_file *input, + struct output_file *output, + union zinfo_record *zinfo ) { + return process_zinfo_add ( input, output, + ( output->len - output->hdr_len ), + &zinfo->add, output->hdr_len, 2 ); +} + +static int process_zinfo_appl ( struct input_file *input, + struct output_file *output, + union zinfo_record *zinfo ) { + return process_zinfo_add ( input, output, + ( output->len - output->hdr_len ), + &zinfo->add, output->hdr_len, 4 ); } struct zinfo_processor { @@ -374,6 +422,12 @@ static struct zinfo_processor zinfo_processors[] = { { "ADHB", process_zinfo_adhb }, { "ADHW", process_zinfo_adhw }, { "ADHL", process_zinfo_adhl }, + { "ADPB", process_zinfo_adpb }, + { "ADPW", process_zinfo_adpw }, + { "ADPL", process_zinfo_adpl }, + { "APPB", process_zinfo_appb }, + { "APPW", process_zinfo_appw }, + { "APPL", process_zinfo_appl }, }; static int process_zinfo ( struct input_file *input,