Browse Source

[efi] Ensure EFI ROM checksum is zero

The UEFI specification does not mention ROM checksums, and reassigns
the field typically used as a checksum byte.  The UEFI shell
"loadpcirom" utility does not verify ROM checksums, but it seems that
some UEFI BIOSes do.
tags/v0.9.7
Michael Brown 16 years ago
parent
commit
8fd81349b3
1 changed files with 60 additions and 101 deletions
  1. 60
    101
      src/util/efirom.c

+ 60
- 101
src/util/efirom.c View File

@@ -21,6 +21,7 @@
21 21
 #include <stdlib.h>
22 22
 #include <stdio.h>
23 23
 #include <string.h>
24
+#include <sys/stat.h>
24 25
 #include <unistd.h>
25 26
 #include <errno.h>
26 27
 #include <assert.h>
@@ -64,48 +65,9 @@ static void * xmalloc ( size_t len ) {
64 65
 static size_t file_size ( FILE *file ) {
65 66
 	ssize_t len;
66 67
 
67
-	if ( fseek ( file, 0, SEEK_END ) != 0 ) {
68
-		eprintf ( "Could not seek: %s\n", strerror ( errno ) );
69
-		exit ( 1 );
70
-	}
71
-	len = ftell ( file );
72
-	if ( len < 0 ) {
73
-		eprintf ( "Could not determine file size: %s\n",
74
-			  strerror ( errno ) );
75
-		exit ( 1 );
76
-	}
77 68
 	return len;
78 69
 }
79 70
 
80
-/**
81
- * Copy file
82
- *
83
- * @v in		Input file
84
- * @v out		Output file
85
- * @v len		Length to copy
86
- */
87
-static void file_copy ( FILE *in, FILE *out, size_t len ) {
88
-	char buf[4096];
89
-	size_t frag_len;
90
-
91
-	while ( len ) {
92
-		frag_len = len;
93
-		if ( frag_len > sizeof ( buf ) )
94
-			frag_len = sizeof ( buf );
95
-		if ( fread ( buf, frag_len, 1, in ) != 1 ) {
96
-			eprintf ( "Could not read: %s\n",
97
-				  strerror ( errno ) );
98
-			exit ( 1 );
99
-		}
100
-		if ( fwrite ( buf, frag_len, 1, out ) != 1 ) {
101
-			eprintf ( "Could not write: %s\n",
102
-				  strerror ( errno ) );
103
-			exit ( 1 );
104
-		}
105
-		len -= frag_len;
106
-	}
107
-}
108
-
109 71
 /**
110 72
  * Read information from PE headers
111 73
  *
@@ -113,42 +75,26 @@ static void file_copy ( FILE *in, FILE *out, size_t len ) {
113 75
  * @ret machine		Machine type
114 76
  * @ret subsystem	EFI subsystem
115 77
  */
116
-static void read_pe_info ( FILE *pe, uint16_t *machine,
78
+static void read_pe_info ( void *pe, uint16_t *machine,
117 79
 			   uint16_t *subsystem ) {
118
-	EFI_IMAGE_DOS_HEADER dos;
80
+	EFI_IMAGE_DOS_HEADER *dos;
119 81
 	union {
120 82
 		EFI_IMAGE_NT_HEADERS32 nt32;
121 83
 		EFI_IMAGE_NT_HEADERS64 nt64;
122
-	} nt;
123
-
124
-	/* Read DOS header */
125
-	if ( fseek ( pe, 0, SEEK_SET ) != 0 ) {
126
-		eprintf ( "Could not seek: %s\n", strerror ( errno ) );
127
-		exit ( 1 );
128
-	}
129
-	if ( fread ( &dos, sizeof ( dos ), 1, pe ) != 1 ) {
130
-		eprintf ( "Could not read: %s\n", strerror ( errno ) );
131
-		exit ( 1 );
132
-	}
133
-
134
-	/* Read NT header */
135
-	if ( fseek ( pe, dos.e_lfanew, SEEK_SET ) != 0 ) {
136
-		eprintf ( "Could not seek: %s\n", strerror ( errno ) );
137
-		exit ( 1 );
138
-	}
139
-	if ( fread ( &nt, sizeof ( nt ), 1, pe ) != 1 ) {
140
-		eprintf ( "Could not read: %s\n", strerror ( errno ) );
141
-		exit ( 1 );
142
-	}
84
+	} *nt;
143 85
 
144 86
 	/* Locate NT header */
145
-	*machine = nt.nt32.FileHeader.Machine;
87
+	dos = pe;
88
+	nt = ( pe + dos->e_lfanew );
89
+
90
+	/* Parse out PE information */
91
+	*machine = nt->nt32.FileHeader.Machine;
146 92
 	switch ( *machine ) {
147 93
 	case EFI_IMAGE_MACHINE_IA32:
148
-		*subsystem = nt.nt32.OptionalHeader.Subsystem;
94
+		*subsystem = nt->nt32.OptionalHeader.Subsystem;
149 95
 		break;
150 96
 	case EFI_IMAGE_MACHINE_X64:
151
-		*subsystem = nt.nt64.OptionalHeader.Subsystem;
97
+		*subsystem = nt->nt64.OptionalHeader.Subsystem;
152 98
 		break;
153 99
 	default:
154 100
 		eprintf ( "Unrecognised machine type %04x\n", *machine );
@@ -166,52 +112,65 @@ static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
166 112
 	struct {
167 113
 		EFI_PCI_EXPANSION_ROM_HEADER rom;
168 114
 		PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) ));
169
-	} headers;
115
+		uint8_t checksum;
116
+	} *headers;
117
+	struct stat pe_stat;
170 118
 	size_t pe_size;
171 119
 	size_t rom_size;
172
-	unsigned int rom_size_sectors;
173
-
174
-	/* Determine output file size */
175
-	pe_size = file_size ( pe );
176
-	rom_size = ( pe_size + sizeof ( headers ) );
177
-	rom_size_sectors = ( ( rom_size + 511 ) / 512 );
120
+	void *buf;
121
+	void *payload;
122
+	unsigned int i;
123
+	uint8_t checksum;
178 124
 
179
-	/* Construct ROM header */
180
-	memset ( &headers, 0, sizeof ( headers ) );
181
-	headers.rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
182
-	headers.rom.InitializationSize = rom_size_sectors;
183
-	headers.rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
184
-	read_pe_info ( pe, &headers.rom.EfiMachineType,
185
-		       &headers.rom.EfiSubsystem );
186
-	headers.rom.EfiImageHeaderOffset = sizeof ( headers );
187
-	headers.rom.PcirOffset =
188
-		offsetof ( typeof ( headers ), pci );
189
-	headers.pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
190
-	headers.pci.VendorId = opts->vendor;
191
-	headers.pci.DeviceId = opts->device;
192
-	headers.pci.Length = sizeof ( headers.pci );
193
-	headers.pci.ClassCode[0] = PCI_CLASS_NETWORK;
194
-	headers.pci.ImageLength = rom_size_sectors;
195
-	headers.pci.CodeType = 0x03; /* No constant in EFI headers? */
196
-	headers.pci.Indicator = 0x80; /* No constant in EFI headers? */
197
-
198
-	/* Write out ROM header */
199
-	if ( fwrite ( &headers, sizeof ( headers ), 1, rom ) != 1 ) {
200
-		eprintf ( "Could not write headers: %s\n",
125
+	/* Determine PE file size */
126
+	if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
127
+		eprintf ( "Could not stat PE file: %s\n",
201 128
 			  strerror ( errno ) );
202 129
 		exit ( 1 );
203 130
 	}
131
+	pe_size = pe_stat.st_size;
204 132
 
205
-	/* Write out payload */
206
-	if ( fseek ( pe, 0, SEEK_SET ) != 0 ) {
207
-		eprintf ( "Could not seek: %s\n", strerror ( errno ) );
133
+	/* Determine ROM file size */
134
+	rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
135
+
136
+	/* Allocate ROM buffer and read in PE file */
137
+	buf = xmalloc ( rom_size );
138
+	memset ( buf, 0, rom_size );
139
+	headers = buf;
140
+	payload = ( buf + sizeof ( *headers ) );
141
+	if ( fread ( payload, pe_size, 1, pe ) != 1 ) {
142
+		eprintf ( "Could not read PE file: %s\n",
143
+			  strerror ( errno ) );
208 144
 		exit ( 1 );
209 145
 	}
210
-	file_copy ( pe, rom, pe_size );
211 146
 
212
-	/* Round up to 512-byte boundary */
213
-	if ( ftruncate ( fileno ( rom ), ( rom_size_sectors * 512 ) ) != 0 ) {
214
-		eprintf ( "Could not set length: %s\n", strerror ( errno ) );
147
+	/* Construct ROM header */
148
+	headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
149
+	headers->rom.InitializationSize = ( rom_size / 512 );
150
+	headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
151
+	read_pe_info ( payload, &headers->rom.EfiMachineType,
152
+		       &headers->rom.EfiSubsystem );
153
+	headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
154
+	headers->rom.PcirOffset =
155
+		offsetof ( typeof ( *headers ), pci );
156
+	headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
157
+	headers->pci.VendorId = opts->vendor;
158
+	headers->pci.DeviceId = opts->device;
159
+	headers->pci.Length = sizeof ( headers->pci );
160
+	headers->pci.ClassCode[0] = PCI_CLASS_NETWORK;
161
+	headers->pci.ImageLength = ( rom_size / 512 );
162
+	headers->pci.CodeType = 0x03; /* No constant in EFI headers? */
163
+	headers->pci.Indicator = 0x80; /* No constant in EFI headers? */
164
+
165
+	/* Fix image checksum */
166
+	for ( i = 0, checksum = 0 ; i < rom_size ; i++ )
167
+		checksum += *( ( uint8_t * ) buf + i );
168
+	headers->checksum -= checksum;
169
+
170
+	/* Write out ROM */
171
+	if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) {
172
+		eprintf ( "Could not write ROM file: %s\n",
173
+			  strerror ( errno ) );
215 174
 		exit ( 1 );
216 175
 	}
217 176
 }

Loading…
Cancel
Save