From b95c1b1217c972cdd444146b259f53b502b44fdc Mon Sep 17 00:00:00 2001 From: bzt Date: Mon, 24 Oct 2022 15:21:19 +0200 Subject: [PATCH] Added utils --- utils/Makefile | 11 + utils/OLVASSEL.md | 9 + utils/README.md | 9 + utils/efiffs.c | 269 ++++++++++ utils/efirom.c | 1258 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1556 insertions(+) create mode 100644 utils/Makefile create mode 100644 utils/OLVASSEL.md create mode 100644 utils/README.md create mode 100644 utils/efiffs.c create mode 100644 utils/efirom.c diff --git a/utils/Makefile b/utils/Makefile new file mode 100644 index 0000000..8f13856 --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,11 @@ +SRCS=$(wildcard *.c) +TARGETS=$(SRCS:.c=) +CFLAGS= -Wall -fshort-wchar + +all: $(TARGETS) + +%: %.c + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm $(TARGETS) diff --git a/utils/OLVASSEL.md b/utils/OLVASSEL.md new file mode 100644 index 0000000..7685f72 --- /dev/null +++ b/utils/OLVASSEL.md @@ -0,0 +1,9 @@ +POSIX-UEFI Segédeszközök +======================== + +Ezek kis parancsok, amik besegítenek az UEFI toolchain-edbe. A POSIX-UEFI által lefordított .efi kimeneti fájlokat konvertálják +olyan különböző formátumú fájlokká, amiket az UEFI firmware használ. + +* __efirom__ - ez PCI Option ROM képet készít + +* __efiffs__ - ez DXE UEFI eszközmeghajtó képet (bővebb infó [ebben a wikiben](https://github.com/pbatard/efifs/wiki/Adding-a-driver-to-a-UEFI-firmware) található arról, hogy kell a firmwarehez adni). diff --git a/utils/README.md b/utils/README.md new file mode 100644 index 0000000..83407ab --- /dev/null +++ b/utils/README.md @@ -0,0 +1,9 @@ +POSIX-UEFI Utilities +==================== + +These are small portable commands to help you with the UEFI toolchain. They convert the .efi output that you've compiled +with POSIX-UEFI into different file formats required by the UEFI firmware. + +* __efirom__ - creates a PCI Option ROM image + +* __efiffs__ - creates a DXE UEFI driver image (see [this wiki](https://github.com/pbatard/efifs/wiki/Adding-a-driver-to-a-UEFI-firmware) on how to add it to a firmaware). diff --git a/utils/efiffs.c b/utils/efiffs.c new file mode 100644 index 0000000..d006f70 --- /dev/null +++ b/utils/efiffs.c @@ -0,0 +1,269 @@ +/* + * utils/efiffs.c + * + * Copyright (C) 2022 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the POSIX-UEFI package. + * @brief small tool to convert an .efi file to an .ffs file + * + */ + +#include +#include +#include +#include +#include + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} __attribute__((packed)) guid_t; + +/** + * Print usage + */ +void usage(char *cmd) +{ + printf("POSIX-UEFI utils - efiffs by bztsrc@gitlab MIT\r\n\r\n"); + printf("%s [-g ] [-n ] [-v ] [-t ] [-p ] infile [outfile]\r\n\r\n", cmd); + printf(" -g specify the GUID (defaults to random)\r\n"); + printf(" -n specify the driver's name (eg 'FAT')\r\n"); + printf(" -v specify the driver's version (eg '1.0')\r\n"); + printf(" -t specify the ffs type (defaults to 7, EFI_FV_FILETYPE_DRIVER)\r\n"); + printf(" -p specify the pe section type (defaults to 16, EFI_SECTION_PE32)\r\n"); + printf(" infile input .efi file\r\n"); + printf(" outfile output file name (default generated from infile)\r\n"); + exit(1); +} + +/** + * Convert hex string into integer + */ +unsigned int gethex(char *ptr, int len) +{ + unsigned int ret = 0; + for(;len--;ptr++) { + if(*ptr>='0' && *ptr<='9') { ret <<= 4; ret += (unsigned int)(*ptr-'0'); } + else if(*ptr >= 'a' && *ptr <= 'f') { ret <<= 4; ret += (unsigned int)(*ptr-'a'+10); } + else if(*ptr >= 'A' && *ptr <= 'F') { ret <<= 4; ret += (unsigned int)(*ptr-'A'+10); } + else break; + } + return ret; +} + +/** + * Parse a GUID in string into binary representation + */ +void getguid(char *ptr, guid_t *guid) +{ + int i; + + if(!ptr || !*ptr || ptr[8] != '-' || ptr[13] != '-' || ptr[18] != '-') { + fprintf(stderr, "efiffs: bad GUID format\r\n"); + return; + } + guid->Data1 = gethex(ptr, 8); ptr += 9; + guid->Data2 = gethex(ptr, 4); ptr += 5; + guid->Data3 = gethex(ptr, 4); ptr += 5; + guid->Data4[0] = gethex(ptr, 2); ptr += 2; + guid->Data4[1] = gethex(ptr, 2); ptr += 2; if(*ptr == '-') ptr++; + for(i = 2; i < 8; i++, ptr += 2) guid->Data4[i] = gethex(ptr, 2); +} + +/** + * Parse fss type + */ +int gettype(char *str) +{ + static const char *types[] = { + NULL, "RAW", "FREEFORM", "SECURITY_CORE", "PEI_CORE", "DXE_CORE", "PEIM", "DRIVER", "COMBINED_PEIM_DRIVER", + "APPLICATION", "SMM", "FIRMWARE_VOLUME_IMAGE", "COMBINED_SMM_DXE", "SMM_CORE", NULL }; + int i; + + i = atoi(str); + if(i > 0 && i < (int)(sizeof(types)/sizeof(types[0]))) return i; + + if(!memcmp(str, "EFI_FV_FILETYPE_", 16)) str += 16; + for(i = 1; types[i] && strcmp(str, types[i]); i++); + if(!types[i]) { + fprintf(stderr, "efiffs: invalid fss type, available values:\r\n"); + for(i = 1; types[i]; i++) + fprintf(stderr, " EFI_FV_FILETYPE_%s\r\n", types[i]); + return 7; /* EFI_FV_FILETYPE_DRIVER */ + } + return i; +} + +/** + * Parse section type + */ +int getsec(char *str) +{ + static const char *types[] = { + "PE32", "PIC", "TE", "DXE_DEPEX", "VERSION", "USER_INTERFACE", "COMPATIBILITY16", + "FIRMWARE_VOLUME_IMAGE", "FREEFORM_SUBTYPE_GUID", "RAW", "RESERVED", "PEI_DEPEX", "SMM_DEPEX", NULL }; + int i; + + i = atoi(str); + if(i == 1 || i == 2 || i >= 16) return i; + + if(!memcmp(str, "EFI_SECTION_", 12)) str += 12; + if(!strcmp(str, "COMPRESSION")) return 1; + if(!strcmp(str, "GUID_DEFINED")) return 2; + for(i = 0; types[i] && strcmp(str, types[i]); i++); + if(!types[i]) { + fprintf(stderr, "efiffs: invalid section type, available values:\r\n"); + fprintf(stderr, " EFI_SECTION_COMPRESSION\r\n EFI_SECTION_GUID_DEFINED\r\n"); + for(i = 0; types[i]; i++) + fprintf(stderr, " EFI_SECTION_%s\r\n", types[i]); + return 16; /* EFI_SECTION_PE32 */ + } + return i + 16; +} + +/** + * Calculate checksum + */ +uint8_t checksum8(uint8_t *buff, int len) +{ + uint8_t ret = 0; + int i; + + for(i = 0; i < len; i++) + ret = (uint8_t)(ret + buff[i]); + return (uint8_t)(0x100 - ret); +} + +/** + * Main function + */ +int main(int argc, char **argv) +{ + FILE *f; + int i, size, len; + int filetype = 7; /* EFI_FV_FILETYPE_DRIVER */ + int sectype = 16; /* EFI_SECTION_PE32 */ + char *in = NULL, *out = NULL, *name = NULL, *ver = NULL; + uint8_t *buff = NULL, *sec = NULL; + guid_t guid; + + /* get a random GUID */ + srand(time(NULL)); + i = rand(); memcpy(&((uint8_t*)&guid)[0], &i, 4); + i = rand(); memcpy(&((uint8_t*)&guid)[4], &i, 4); + i = rand(); memcpy(&((uint8_t*)&guid)[8], &i, 4); + i = rand(); memcpy(&((uint8_t*)&guid)[12], &i, 4); + + /* parse command line */ + for(i = 1; i < argc && argv[i]; i++) + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case 'g': getguid(argv[++i], &guid); break; + case 'n': name = argv[++i]; break; + case 'v': ver = argv[++i]; break; + case 't': filetype = gettype(argv[++i]); break; + case 'p': sectype = getsec(argv[++i]); break; + default: usage(argv[0]); break; + } + } else + if(!in) in = argv[i]; else + if(!out) out = argv[i]; else + usage(argv[0]); + if(!in) usage(argv[0]); + + /* get input data */ + f = fopen(in, "rb"); + if(!f) { + fprintf(stderr, "efiffs: unable to read '%s'\r\n", in); + return 2; + } + fseek(f, 0L, SEEK_END); + size = (int)ftell(f); + fseek(f, 0L, SEEK_SET); + len = 24 + 12 + 4 + size + (name ? 6 + 2 * strlen(name) : 0) + (ver ? 6 + 2 * strlen(ver) : 0); + buff = (uint8_t*)malloc(len); + if(!buff) { fprintf(stderr, "efiffs: unable to allocate memory\r\n"); return 2; } + memset(buff, 0, len); + sec = buff + 24; + /* add the PE section */ + sec[0] = size & 0xff; + sec[1] = (size >> 8) & 0xff; + sec[2] = (size >> 16) & 0xff; + sec[3] = sectype; + fread(sec + 4, 1, size, f); + fclose(f); + sec += 4 + ((size + 3) & ~3); + /* add the name section */ + if(name) { + size = 6 + 2 * strlen(name); + sec[0] = size & 0xff; + sec[1] = (size >> 8) & 0xff; + sec[2] = (size >> 16) & 0xff; + sec[3] = 0x15; /* EFI_SECTION_USER_INTERFACE */ + for(i = 0; name[i]; i++) + sec[4 + 2 * i] = name[i]; + sec += ((size + 3) & ~3); + } + /* add the version section */ + if(ver) { + size = 6 + 2 * strlen(ver); + sec[0] = size & 0xff; + sec[1] = (size >> 8) & 0xff; + sec[2] = (size >> 16) & 0xff; + sec[3] = 0x14; /* EFI_SECTION_VERSION */ + for(i = 0; ver[i]; i++) + sec[4 + 2 * i] = ver[i]; + sec += ((size + 3) & ~3); + } + + /* calculate ffs header fields */ + len = (int)((uintptr_t)sec - (uintptr_t)buff); + memcpy(buff, &guid, 16); + buff[0x12] = filetype; + buff[0x14] = len & 0xff; + buff[0x15] = (len >> 8) & 0xff; + buff[0x16] = (len >> 16) & 0xff; + buff[0x11] = 0xAA; + buff[0x10] = checksum8(buff, 24); + + /* write out image */ + if(!out) { + i = strlen(in); + out = (char*)malloc(i + 5); + if(!out) { fprintf(stderr, "efiffs: unable to allocate memory\r\n"); return 2; } + strcpy(out, in); + strcpy(strcmp(out + i + 4, ".efi") ? out + i - 4 : out + i, ".ffs"); + } + f = fopen(out, "wb"); + if(!f) { + fprintf(stderr, "efiffs: unable to write '%s'\r\n", out); + return 2; + } + fwrite(buff, 1, len, f); + fclose(f); + + free(buff); + return 0; +} diff --git a/utils/efirom.c b/utils/efirom.c new file mode 100644 index 0000000..499a5d1 --- /dev/null +++ b/utils/efirom.c @@ -0,0 +1,1258 @@ +/* + * utils/efirom.c + * + * Copyright (C) 2009 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * modifications for gnuefi by bzt (bztsrc@gitlab) + * + * This file is part of the POSIX-UEFI package. + * @brief small tool to convert an .efi file to a .rom file + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) +typedef uint64_t UINTN; +typedef UINTN EFI_TPL; + +typedef struct _EFI_DEVICE_PATH_PROTOCOL { + uint8_t Type; + uint8_t SubType; + uint8_t Length[2]; +} EFI_DEVICE_PATH_PROTOCOL; + +typedef struct _EFI_DEVICE_PATH_PROTOCOL _EFI_DEVICE_PATH; +typedef EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH; + +#ifndef _EFI_LINK_H +#define _EFI_LINK_H + +/*++ + +Copyright (c) 1998 Intel Corporation + +Module Name: + + link.h (renamed efilink.h to avoid conflicts) + +Abstract: + + EFI link list macro's + + + +Revision History + +--*/ + +#ifndef EFI_NT_EMUL + +// +// List entry - doubly linked list +// + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY; + +#endif + + +// +// VOID +// InitializeListHead( +// LIST_ENTRY *ListHead +// ); +// + +#define InitializeListHead(ListHead) \ + (ListHead)->Flink = ListHead; \ + (ListHead)->Blink = ListHead; + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define _RemoveEntryList(Entry) { \ + LIST_ENTRY *_Blink, *_Flink; \ + _Flink = (Entry)->Flink; \ + _Blink = (Entry)->Blink; \ + _Blink->Flink = _Flink; \ + _Flink->Blink = _Blink; \ + } + +#if EFI_DEBUG + #define RemoveEntryList(Entry) \ + _RemoveEntryList(Entry); \ + (Entry)->Flink = (LIST_ENTRY *) BAD_POINTER; \ + (Entry)->Blink = (LIST_ENTRY *) BAD_POINTER; +#else + #define RemoveEntryList(Entry) \ + _RemoveEntryList(Entry); +#endif + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + LIST_ENTRY *_ListHead, *_Blink; \ + _ListHead = (ListHead); \ + _Blink = _ListHead->Blink; \ + (Entry)->Flink = _ListHead; \ + (Entry)->Blink = _Blink; \ + _Blink->Flink = (Entry); \ + _ListHead->Blink = (Entry); \ + } + +// +// VOID +// InsertHeadList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertHeadList(ListHead,Entry) {\ + LIST_ENTRY *_ListHead, *_Flink; \ + _ListHead = (ListHead); \ + _Flink = _ListHead->Flink; \ + (Entry)->Flink = _Flink; \ + (Entry)->Blink = _ListHead; \ + _Flink->Blink = (Entry); \ + _ListHead->Flink = (Entry); \ + } + +// VOID +// SwapListEntries( +// PLIST_ENTRY Entry1, +// PLIST_ENTRY Entry2 +// ); +// +// Put Entry2 before Entry1 +// +#define SwapListEntries(Entry1,Entry2) {\ + LIST_ENTRY *Entry1Flink, *Entry1Blink; \ + LIST_ENTRY *Entry2Flink, *Entry2Blink; \ + Entry2Flink = (Entry2)->Flink; \ + Entry2Blink = (Entry2)->Blink; \ + Entry1Flink = (Entry1)->Flink; \ + Entry1Blink = (Entry1)->Blink; \ + Entry2Blink->Flink = Entry2Flink; \ + Entry2Flink->Blink = Entry2Blink; \ + (Entry2)->Flink = Entry1; \ + (Entry2)->Blink = Entry1Blink; \ + Entry1Blink->Flink = (Entry2); \ + (Entry1)->Blink = (Entry2); \ + } + +// +// EFI_FIELD_OFFSET - returns the byte offset to a field within a structure +// + +#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field))) + +// +// CONTAINING_RECORD - returns a pointer to the structure +// from one of it's elements. +// + +#define _CR(Record, TYPE, Field) \ + ((TYPE *) ( (CHAR8 *)(Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) + +#if EFI_DEBUG + #define CR(Record, TYPE, Field, Sig) \ + _CR(Record, TYPE, Field)->Signature != Sig ? \ + (TYPE *) ASSERT_STRUCT(_CR(Record, TYPE, Field), Record) : \ + _CR(Record, TYPE, Field) +#else + #define CR(Record, TYPE, Field, Signature) \ + _CR(Record, TYPE, Field) +#endif + + +// +// A lock structure +// + +typedef struct _FLOCK { + EFI_TPL Tpl; + EFI_TPL OwnerTpl; + UINTN Lock; +} FLOCK; + +#endif + +/* + PE32+ header file + */ +#ifndef _PE_H +#define _PE_H + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 +#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED + + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + uint16_t e_magic; // Magic number + uint16_t e_cblp; // Bytes on last page of file + uint16_t e_cp; // Pages in file + uint16_t e_crlc; // Relocations + uint16_t e_cparhdr; // Size of header in paragraphs + uint16_t e_minalloc; // Minimum extra paragraphs needed + uint16_t e_maxalloc; // Maximum extra paragraphs needed + uint16_t e_ss; // Initial (relative) SS value + uint16_t e_sp; // Initial SP value + uint16_t e_csum; // Checksum + uint16_t e_ip; // Initial IP value + uint16_t e_cs; // Initial (relative) CS value + uint16_t e_lfarlc; // File address of relocation table + uint16_t e_ovno; // Overlay number + uint16_t e_res[4]; // Reserved words + uint16_t e_oemid; // OEM identifier (for e_oeminfo) + uint16_t e_oeminfo; // OEM information; e_oemid specific + uint16_t e_res2[10]; // Reserved words + uint32_t e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header + uint16_t ne_magic; // Magic number + uint8_t ne_ver; // Version number + uint8_t ne_rev; // Revision number + uint16_t ne_enttab; // Offset of Entry Table + uint16_t ne_cbenttab; // Number of bytes in Entry Table + uint32_t ne_crc; // Checksum of whole file + uint16_t ne_flags; // Flag uint16_t + uint16_t ne_autodata; // Automatic data segment number + uint16_t ne_heap; // Initial heap allocation + uint16_t ne_stack; // Initial stack allocation + uint32_t ne_csip; // Initial CS:IP setting + uint32_t ne_sssp; // Initial SS:SP setting + uint16_t ne_cseg; // Count of file segments + uint16_t ne_cmod; // Entries in Module Reference Table + uint16_t ne_cbnrestab; // Size of non-resident name table + uint16_t ne_segtab; // Offset of Segment Table + uint16_t ne_rsrctab; // Offset of Resource Table + uint16_t ne_restab; // Offset of resident name table + uint16_t ne_modtab; // Offset of Module Reference Table + uint16_t ne_imptab; // Offset of Imported Names Table + uint32_t ne_nrestab; // Offset of Non-resident Names Table + uint16_t ne_cmovent; // Count of movable entries + uint16_t ne_align; // Segment alignment shift count + uint16_t ne_cres; // Count of resource segments + uint8_t ne_exetyp; // Target Operating system + uint8_t ne_flagsothers; // Other .EXE flags + uint16_t ne_pretthunks; // offset to return thunks + uint16_t ne_psegrefbytes; // offset to segment ref. bytes + uint16_t ne_swaparea; // Minimum code swap area size + uint16_t ne_expver; // Expected Windows version number + } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; + +// +// File header format. +// + +typedef struct _IMAGE_FILE_HEADER { + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. +#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian +#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian +#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x1c2 // Arm/Thumb +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_IA64 0x200 // IA-64 +#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine +#define IMAGE_FILE_MACHINE_EBC 0xebc // EFI Byte Code +#define IMAGE_FILE_MACHINE_X64 0x8664 // x86_64 +// +// Directory format. +// + +typedef struct _IMAGE_DATA_DIRECTORY { + uint32_t VirtualAddress; + uint32_t Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +// +// Optional header format. +// + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + + // + // NT additional fields. + // + + uint32_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Reserved1; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + uint32_t SizeOfStackReserve; + uint32_t SizeOfStackCommit; + uint32_t SizeOfHeapReserve; + uint32_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + uint32_t BaseOfBss; + uint32_t GprMask; + uint32_t CprMask[4]; + uint32_t GpValue; +} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 + +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct _IMAGE_NT_HEADERS { + uint32_t Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; + +#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((uint32_t)ntheader + \ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ + )) + + +// Subsystem Values + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. +#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. +#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. + + +// Directory Entries + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory + +// +// Section header format. +// + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + uint32_t PhysicalAddress; + uint32_t VirtualSize; + } Misc; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. + +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. + +#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. +#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. +#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +// +// Symbol format. +// + + +#define IMAGE_SIZEOF_SYMBOL 18 + +// +// Section values. +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// + +#define IMAGE_SYM_UNDEFINED (uint16_t)0 // Symbol is undefined or is common. +#define IMAGE_SYM_ABSOLUTE (uint16_t)-1 // Symbol is an absolute value. +#define IMAGE_SYM_DEBUG (uint16_t)-2 // Symbol is a special debug item. + +// +// Type (fundamental) values. +// + +#define IMAGE_SYM_TYPE_NULL 0 // no type. +#define IMAGE_SYM_TYPE_VOID 1 // +#define IMAGE_SYM_TYPE_CHAR 2 // type character. +#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. +#define IMAGE_SYM_TYPE_INT 4 // +#define IMAGE_SYM_TYPE_LONG 5 // +#define IMAGE_SYM_TYPE_FLOAT 6 // +#define IMAGE_SYM_TYPE_DOUBLE 7 // +#define IMAGE_SYM_TYPE_STRUCT 8 // +#define IMAGE_SYM_TYPE_UNION 9 // +#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. +#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. +#define IMAGE_SYM_TYPE_BYTE 12 // +#define IMAGE_SYM_TYPE_WORD 13 // +#define IMAGE_SYM_TYPE_UINT 14 // +#define IMAGE_SYM_TYPE_DWORD 15 // + +// +// Type (derived) values. +// + +#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. +#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. +#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. +#define IMAGE_SYM_DTYPE_ARRAY 3 // array. + +// +// Storage classes. +// + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +// new +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// type packing constants + +#define N_BTMASK 017 +#define N_TMASK 060 +#define N_TMASK1 0300 +#define N_TMASK2 0360 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +// MACROS + +// +// Communal selection types. +// + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + +// +// Relocation format. +// + +typedef struct _IMAGE_RELOCATION { + uint32_t VirtualAddress; + uint32_t SymbolTableIndex; + uint16_t Type; +} IMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// + +#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included +#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define IMAGE_REL_I386_SECTION 012 +#define IMAGE_REL_I386_SECREL 013 +#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address + +// +// MIPS relocation types. +// + +#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_MIPS_REFHALF 01 +#define IMAGE_REL_MIPS_REFWORD 02 +#define IMAGE_REL_MIPS_JMPADDR 03 +#define IMAGE_REL_MIPS_REFHI 04 +#define IMAGE_REL_MIPS_REFLO 05 +#define IMAGE_REL_MIPS_GPREL 06 +#define IMAGE_REL_MIPS_LITERAL 07 +#define IMAGE_REL_MIPS_SECTION 012 +#define IMAGE_REL_MIPS_SECREL 013 +#define IMAGE_REL_MIPS_REFWORDNB 042 +#define IMAGE_REL_MIPS_PAIR 045 + +// +// Alpha Relocation types. +// + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 +#define IMAGE_REL_ALPHA_REFLONG 0x1 +#define IMAGE_REL_ALPHA_REFQUAD 0x2 +#define IMAGE_REL_ALPHA_GPREL32 0x3 +#define IMAGE_REL_ALPHA_LITERAL 0x4 +#define IMAGE_REL_ALPHA_LITUSE 0x5 +#define IMAGE_REL_ALPHA_GPDISP 0x6 +#define IMAGE_REL_ALPHA_BRADDR 0x7 +#define IMAGE_REL_ALPHA_HINT 0x8 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 +#define IMAGE_REL_ALPHA_REFHI 0xA +#define IMAGE_REL_ALPHA_REFLO 0xB +#define IMAGE_REL_ALPHA_PAIR 0xC +#define IMAGE_REL_ALPHA_MATCH 0xD +#define IMAGE_REL_ALPHA_SECTION 0xE +#define IMAGE_REL_ALPHA_SECREL 0xF +#define IMAGE_REL_ALPHA_REFLONGNB 0x10 + +// +// IBM PowerPC relocation types. +// + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP +#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address +#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address +#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) +#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address +#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) +#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) +#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) +#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base +#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) + +#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base +#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) +#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number +#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code +#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction + +#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type + +// Flag bits in IMAGE_RELOCATION.TYPE + +#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it +#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken +#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) + +// +// Based relocation format. +// + +typedef struct _IMAGE_BASE_RELOCATION { + uint32_t VirtualAddress; + uint32_t SizeOfBlock; +// uint16_t TypeOffset[1]; +} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 + +// +// Line number format. +// + +typedef struct _IMAGE_LINENUMBER { + union { + uint32_t SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + uint32_t VirtualAddress; // Virtual address of line number. + } Type; + uint16_t Linenumber; // Line number. +} IMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + uint8_t Name[16]; // File member name - `/' terminated. + uint8_t Date[12]; // File member date - decimal. + uint8_t UserID[6]; // File member user id - decimal. + uint8_t GroupID[6]; // File member group id - decimal. + uint8_t Mode[8]; // File member mode - octal. + uint8_t Size[10]; // File member size - decimal. + uint8_t EndHeader[2]; // String to end header. +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL support. +// + +// +// Export Format +// + +typedef struct _IMAGE_EXPORT_DIRECTORY { + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Name; + uint32_t Base; + uint32_t NumberOfFunctions; + uint32_t NumberOfNames; + uint32_t *AddressOfFunctions; + uint32_t *AddressOfNames; + uint32_t *AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// +// Import Format +// + +typedef struct _IMAGE_IMPORT_BY_NAME { + uint16_t Hint; + uint8_t Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA { + union { + uint32_t Function; + uint32_t Ordinal; + PIMAGE_IMPORT_BY_NAME AddressOfData; + } u1; +} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint32_t ForwarderChain; + uint32_t Name; + PIMAGE_THUNK_DATA FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#endif + +#ifndef _PCI22_H +#define _PCI22_H + +/*++ + +Copyright (c) 1999 Intel Corporation + +Module Name: + + pci22.h + +Abstract: + Support for PCI 2.2 standard. + + + + +Revision History + +--*/ + +#ifdef SOFT_SDV +#define PCI_MAX_BUS 1 +#else +#define PCI_MAX_BUS 255 +#endif + +#define PCI_MAX_DEVICE 31 +#define PCI_MAX_FUNC 7 + +// +// Command +// +#define PCI_VGA_PALETTE_SNOOP_DISABLED 0x20 + +#pragma pack(1) +typedef struct { + uint16_t VendorId; + uint16_t DeviceId; + uint16_t Command; + uint16_t Status; + uint8_t RevisionID; + uint8_t ClassCode[3]; + uint8_t CacheLineSize; + uint8_t LaytencyTimer; + uint8_t HeaderType; + uint8_t BIST; +} PCI_DEVICE_INDEPENDENT_REGION; + +typedef struct { + uint32_t Bar[6]; + uint32_t CISPtr; + uint16_t SubsystemVendorID; + uint16_t SubsystemID; + uint32_t ExpansionRomBar; + uint32_t Reserved[2]; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint8_t MinGnt; + uint8_t MaxLat; +} PCI_DEVICE_HEADER_TYPE_REGION; + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_DEVICE_HEADER_TYPE_REGION Device; +} PCI_TYPE00; + +typedef struct { + uint32_t Bar[2]; + uint8_t PrimaryBus; + uint8_t SecondaryBus; + uint8_t SubordinateBus; + uint8_t SecondaryLatencyTimer; + uint8_t IoBase; + uint8_t IoLimit; + uint16_t SecondaryStatus; + uint16_t MemoryBase; + uint16_t MemoryLimit; + uint16_t PrefetchableMemoryBase; + uint16_t PrefetchableMemoryLimit; + uint32_t PrefetchableBaseUpper32; + uint32_t PrefetchableLimitUpper32; + uint16_t IoBaseUpper16; + uint16_t IoLimitUpper16; + uint32_t Reserved; + uint32_t ExpansionRomBAR; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint16_t BridgeControl; +} PCI_BRIDGE_CONTROL_REGISTER; + +#define PCI_CLASS_DISPLAY_CTRL 0x03 +#define PCI_CLASS_VGA 0x00 + +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_ISA 0x01 +#define PCI_CLASS_ISA_POSITIVE_DECODE 0x80 + +#define PCI_CLASS_NETWORK 0x02 +#define PCI_CLASS_ETHERNET 0x00 + +#define HEADER_TYPE_DEVICE 0x00 +#define HEADER_TYPE_PCI_TO_PCI_BRIDGE 0x01 +#define HEADER_TYPE_MULTI_FUNCTION 0x80 +#define HEADER_LAYOUT_CODE 0x7f + +#define IS_PCI_BRIDGE(_p) ((((_p)->Hdr.HeaderType) & HEADER_LAYOUT_CODE) == HEADER_TYPE_PCI_TO_PCI_BRIDGE) +#define IS_PCI_MULTI_FUNC(_p) (((_p)->Hdr.HeaderType) & HEADER_TYPE_MULTI_FUNCTION) + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_BRIDGE_CONTROL_REGISTER Bridge; +} PCI_TYPE01; + +typedef struct { + uint8_t Register; + uint8_t Function; + uint8_t Device; + uint8_t Bus; + uint8_t Reserved[4]; +} DEFIO_PCI_ADDR; + +typedef struct { + uint32_t Reg : 8; + uint32_t Func : 3; + uint32_t Dev : 5; + uint32_t Bus : 8; + uint32_t Reserved: 7; + uint32_t Enable : 1; +} PCI_CONFIG_ACCESS_CF8; + +#pragma pack() + +#define EFI_ROOT_BRIDGE_LIST 'eprb' +typedef struct { + UINTN Signature; + + uint16_t BridgeNumber; + uint16_t PrimaryBus; + uint16_t SubordinateBus; + + EFI_DEVICE_PATH *DevicePath; + + LIST_ENTRY Link; +} PCI_ROOT_BRIDGE_ENTRY; + + +#define PCI_EXPANSION_ROM_HEADER_SIGNATURE 0xaa55 +#define EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE 0x0EF1 +#define PCI_DATA_STRUCTURE_SIGNATURE EFI_SIGNATURE_32('P','C','I','R') + +#pragma pack(1) +typedef struct { + uint16_t Signature; // 0xaa55 + uint8_t Reserved[0x16]; + uint16_t PcirOffset; +} PCI_EXPANSION_ROM_HEADER; + + +typedef struct { + uint16_t Signature; // 0xaa55 + uint16_t InitializationSize; + uint16_t EfiSignature; // 0x0EF1 + uint16_t EfiSubsystem; + uint16_t EfiMachineType; + uint8_t Reserved[0x0A]; + uint16_t EfiImageHeaderOffset; + uint16_t PcirOffset; +} EFI_PCI_EXPANSION_ROM_HEADER; + +typedef struct { + uint32_t Signature; // "PCIR" + uint16_t VendorId; + uint16_t DeviceId; + uint16_t Reserved0; + uint16_t Length; + uint8_t Revision; + uint8_t ClassCode[3]; + uint16_t ImageLength; + uint16_t CodeRevision; + uint8_t CodeType; + uint8_t Indicator; + uint16_t Reserved1; +} PCI_DATA_STRUCTURE; +#pragma pack() + +#endif + + +/** Command-line options */ +struct options { + uint16_t vendor; + uint16_t device; +}; + +/** + * Allocate memory + * + * @v len Length of memory to allocate + * @ret ptr Pointer to allocated memory + */ +static void * xmalloc ( size_t len ) { + void *ptr; + + ptr = malloc ( len ); + if ( ! ptr ) { + eprintf ( "Could not allocate %zd bytes\n", len ); + exit ( 1 ); + } + + return ptr; +} + +/** + * Get file size + * + * @v file File + * @v len File size + */ +/* +static size_t file_size ( FILE *file ) { + ssize_t len; + + return len; +} +*/ +/** + * Read information from PE headers + * + * @v pe PE file + * @ret machine Machine type + * @ret subsystem EFI subsystem + */ +static void read_pe_info ( void *pe, uint16_t *machine, + uint16_t *subsystem ) { + IMAGE_DOS_HEADER *dos; + union { + IMAGE_NT_HEADERS nt64; + } *nt; + + /* Locate NT header */ + dos = pe; + nt = ( pe + dos->e_lfanew ); + + /* issue 4: TianoCore demands subsystem 10, so we must use EFI_APPLICATION + * in the PE header. Therefore we force EFI_ROM subsystem in this code here. */ + if(nt->nt64.OptionalHeader.Subsystem == 10) + nt->nt64.OptionalHeader.Subsystem = 13; + + /* Parse out PE information */ + *machine = nt->nt64.FileHeader.Machine; + *subsystem = nt->nt64.OptionalHeader.Subsystem; +} + +/** + * Convert EFI image to ROM image + * + * @v pe EFI file + * @v rom ROM file + */ +static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) { + struct { + EFI_PCI_EXPANSION_ROM_HEADER rom; + PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) )); + uint8_t checksum; + } *headers; + struct stat pe_stat; + size_t pe_size; + size_t rom_size; + void *buf; + void *payload; + unsigned int i; + uint8_t checksum; + + /* Determine PE file size */ + if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) { + eprintf ( "Could not stat PE file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } + pe_size = pe_stat.st_size; + + /* Determine ROM file size */ + rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 ); + + /* Allocate ROM buffer and read in PE file */ + buf = xmalloc ( rom_size ); + memset ( buf, 0, rom_size ); + headers = buf; + payload = ( buf + sizeof ( *headers ) ); + if ( fread ( payload, pe_size, 1, pe ) != 1 ) { + eprintf ( "Could not read PE file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } + + /* Construct ROM header */ + headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE; + headers->rom.InitializationSize = ( rom_size / 512 ); + headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE; + read_pe_info ( payload, &headers->rom.EfiMachineType, + &headers->rom.EfiSubsystem ); + headers->rom.EfiImageHeaderOffset = sizeof ( *headers ); + headers->rom.PcirOffset = + offsetof ( typeof ( *headers ), pci ); + headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE; + headers->pci.VendorId = opts->vendor ? opts->vendor : 0x8086; + headers->pci.DeviceId = opts->device ? opts->device : 0x100E; + headers->pci.Length = sizeof ( headers->pci ); + headers->pci.ClassCode[0] = PCI_CLASS_NETWORK; + headers->pci.ImageLength = ( rom_size / 512 ); + headers->pci.CodeType = 0x03; /* No constant in EFI headers? */ + headers->pci.Indicator = 0x80; /* No constant in EFI headers? */ + + /* Fix image checksum */ + for ( i = 0, checksum = 0 ; i < rom_size ; i++ ) + checksum += *( ( uint8_t * ) buf + i ); + headers->checksum -= checksum; + + /* Write out ROM */ + if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) { + eprintf ( "Could not write ROM file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } +} + +/** + * Print help + * + * @v program_name Program name + */ +static void print_help ( const char *program_name ) { + eprintf ( "POSIX-UEFI utils - efirom by Michael Brown GPL\r\n\r\n" ); + eprintf ( "%s [--vendor=VVVV] [--device=DDDD] " + "infile outfile\n", program_name ); +} + +/** + * Parse command-line options + * + * @v argc Argument count + * @v argv Argument list + * @v opts Options structure to populate + */ +static int parse_options ( const int argc, char **argv, + struct options *opts ) { + char *end; + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "vendor", required_argument, NULL, 'v' }, + { "device", required_argument, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + if ( ( c = getopt_long ( argc, argv, "v:d:h", + long_options, + &option_index ) ) == -1 ) { + break; + } + + switch ( c ) { + case 'v': + opts->vendor = strtoul ( optarg, &end, 16 ); + if ( *end ) { + eprintf ( "Invalid vendor \"%s\"\n", optarg ); + exit ( 2 ); + } + break; + case 'd': + opts->device = strtoul ( optarg, &end, 16 ); + if ( *end ) { + eprintf ( "Invalid device \"%s\"\n", optarg ); + exit ( 2 ); + } + break; + case 'h': + print_help ( argv[0] ); + exit ( 0 ); + case '?': + default: + exit ( 2 ); + } + } + return optind; +} + +int main ( int argc, char **argv ) { + struct options opts = { + }; + unsigned int infile_index; + const char *infile_name; + const char *outfile_name; + FILE *infile; + FILE *outfile; + + /* Parse command-line arguments */ + infile_index = parse_options ( argc, argv, &opts ); + if ( argc != ( infile_index + 2 ) ) { + print_help ( argv[0] ); + exit ( 2 ); + } + infile_name = argv[infile_index]; + outfile_name = argv[infile_index + 1]; + + /* Open input and output files */ + infile = fopen ( infile_name, "r" ); + if ( ! infile ) { + eprintf ( "Could not open %s for reading: %s\n", + infile_name, strerror ( errno ) ); + exit ( 1 ); + } + outfile = fopen ( outfile_name, "w" ); + if ( ! outfile ) { + eprintf ( "Could not open %s for writing: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + + /* Convert file */ + make_efi_rom ( infile, outfile, &opts ); + + fclose ( outfile ); + fclose ( infile ); + + return 0; +}