blob: f917c4cdf4274f3cda4adea6ddb2a3cef4ed5b74 [file] [log] [blame]
Luc Verhaegen838fe242009-06-17 00:48:02 +02001/*
2 * Decompression utility for AMI BIOSes.
3 *
4 * Copyright 2009 Luc Verhaegen <libv@skynet.be>
5 * Copyright 2000-2006 Anthony Borisow
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
Lubomir Rintelc707d3e2017-06-25 23:39:52 +020022#define _GNU_SOURCE
23
Luc Verhaegen838fe242009-06-17 00:48:02 +020024#include <stdio.h>
25#include <inttypes.h>
26#include <errno.h>
27#include <string.h>
28#include <sys/mman.h>
Luc Verhaegen838fe242009-06-17 00:48:02 +020029#include <fcntl.h>
30#include <unistd.h>
Lubomir Rintelc707d3e2017-06-25 23:39:52 +020031#include <string.h>
Luc Verhaegen838fe242009-06-17 00:48:02 +020032
33#include "bios_extract.h"
Idwer Vollering0ab44552012-09-23 01:22:20 +020034#include "compat.h"
Luc Verhaegen838fe242009-06-17 00:48:02 +020035#include "lh5_extract.h"
36
Anton Kochkov8f9427f2013-04-07 13:20:30 +040037struct AMI95ModuleName {
38 uint8_t Id;
39 char *Name;
Luc Verhaegen838fe242009-06-17 00:48:02 +020040};
41
Anton Kochkov8f9427f2013-04-07 13:20:30 +040042static struct AMI95ModuleName AMI95ModuleNames[] = {
43 {0x00, "POST"},
44 {0x01, "Setup Server"},
45 {0x02, "RunTime"},
46 {0x03, "DIM"},
47 {0x04, "Setup Client"},
48 {0x05, "Remote Server"},
49 {0x06, "DMI Data"},
50 {0x07, "Green PC"},
51 {0x08, "Interface"},
52 {0x09, "MP"},
53 {0x0A, "Notebook"},
54 {0x0B, "Int-10"},
55 {0x0C, "ROM-ID"},
56 {0x0D, "Int-13"},
57 {0x0E, "OEM Logo"},
58 {0x0F, "ACPI Table"},
59 {0x10, "ACPI AML"},
60 {0x11, "P6 Microcode"},
61 {0x12, "Configuration"},
62 {0x13, "DMI Code"},
63 {0x14, "System Health"},
64 {0x15, "Memory Sizing"},
65 {0x16, "Memory Test"},
66 {0x17, "Debug"},
67 {0x18, "ADM (Display MGR)"},
68 {0x19, "ADM Font"},
69 {0x1A, "Small Logo"},
70 {0x1B, "SLAB"},
Lubomir Rintel64534e62017-06-25 23:58:10 +020071 {0x1C, "BCP Info"},
72 {0x1D, "Dual Logo"},
73 {0x1E, "Intel OSB"},
Anton Kochkov8f9427f2013-04-07 13:20:30 +040074 {0x20, "PCI AddOn ROM"},
75 {0x21, "Multilanguage"},
76 {0x22, "UserDefined"},
77 {0x23, "ASCII Font"},
78 {0x24, "BIG5 Font"},
79 {0x25, "OEM Logo"},
Lubomir Rintel64534e62017-06-25 23:58:10 +020080 {0x26, "Debugger"},
81 {0x27, "Debugger Port"},
82 {0x28, "BMC Output"},
83 {0x29, "MBI File"},
Anton Kochkov8f9427f2013-04-07 13:20:30 +040084 {0x2A, "User ROM"},
85 {0x2B, "PXE Code"},
86 {0x2C, "AMI Font"},
87 {0x2E, "User ROM"},
88 {0x2D, "Battery Refresh"},
Lubomir Rintel64534e62017-06-25 23:58:10 +020089 {0x2F, "Serial Redirection"},
Anton Kochkov8f9427f2013-04-07 13:20:30 +040090 {0x30, "Font Database"},
91 {0x31, "OEM Logo Data"},
92 {0x32, "Graphic Logo Code"},
93 {0x33, "Graphic Logo Data"},
94 {0x34, "Action Logo Code"},
95 {0x35, "Action Logo Data"},
96 {0x36, "Virus"},
97 {0x37, "Online Menu"},
98 {0x38, "Lang1 as ROM"},
99 {0x39, "Lang2 as ROM"},
100 {0x3A, "Lang3 as ROM"},
101 {0x40, "AMD CIM-X NB binary"},
102 {0x60, "AMD CIM-X SB binary"},
103 {0x70, "OSD Bitmaps"},
Lubomir Rintel64534e62017-06-25 23:58:10 +0200104 {0x80, "Image Info"},
105 {0xab, "CompuTrace backdoor"},
106 {0xf0, "Asrock Backup Util or Windows SLIC"},
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400107 {0xf9, "Asrock AMD AHCI DLL"},
108 {0xfa, "Asrock LOGO GIF"},
109 {0xfb, "Asrock LOGO JPG"},
110 {0xfc, "Asrock LOGO JPG"},
111 {0xfd, "Asrock LOGO PCX - Instant boot"},
112 {0, NULL}
Luc Verhaegen838fe242009-06-17 00:48:02 +0200113};
114
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400115static char *AMI95ModuleNameGet(uint8_t ID)
Luc Verhaegen838fe242009-06-17 00:48:02 +0200116{
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400117 int i;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200118
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400119 for (i = 0; AMI95ModuleNames[i].Name; i++)
120 if (AMI95ModuleNames[i].Id == ID)
121 return AMI95ModuleNames[i].Name;
122 return NULL;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200123}
124
125/*
126 *
127 */
128Bool
Luc Verhaegen15587352009-06-26 10:00:29 +0200129AMI95Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
Luc Verhaegen838fe242009-06-17 00:48:02 +0200130 uint32_t AMIBOffset, uint32_t ABCOffset)
131{
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400132 Bool Compressed;
133 uint32_t Offset;
134 char Date[9];
135 int i;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200136
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400137 struct abc {
138 const char AMIBIOSC[8];
139 const char Version[4];
140 const uint16_t CRCLen;
141 const uint32_t CRC32;
142 const uint16_t BeginLo;
143 const uint16_t BeginHi;
144 } *abc;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200145
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400146 struct bigpart {
147 const uint32_t CSize;
148 const uint32_t Unknown;
149 } *bigpart;
Rudolf Marekd6b4fbb2009-12-21 11:30:05 +0100150
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400151 struct part {
152 /* When Previous Part Address is 0xFFFFFFFF, then this is the last part. */
153 const uint16_t PrePartLo; /* Previous part low word */
154 const uint16_t PrePartHi; /* Previous part high word */
155 const uint16_t CSize; /* Header length */
156 const uint8_t PartID; /* ID for this header */
157 const uint8_t IsComprs; /* 0x80 -> compressed */
158 const uint32_t RealCS; /* Old BIOSes:
159 Real Address in RAM where to expand to
160 Now:
161 Type 0x20 PCI ID of device for this ROM
162 Type 0x21 Language ID (ascii) */
163 const uint32_t ROMSize; /* Compressed Length */
164 const uint32_t ExpSize; /* Expanded Length */
165 } *part;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200166
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400167 if (!ABCOffset) {
168 if ((BIOSImage[8] == '1') && (BIOSImage[9] == '0') &&
169 (BIOSImage[11] == '1') && (BIOSImage[12] == '0'))
170 fprintf(stderr,
171 "Error: This is an AMI '94 (1010) BIOS Image.\n");
172 else
173 fprintf(stderr,
174 "Error: This is an AMI '94 BIOS Image.\n");
175 return FALSE;
176 }
Luc Verhaegen838fe242009-06-17 00:48:02 +0200177
Lubomir Rintelc707d3e2017-06-25 23:39:52 +0200178 if (ABCOffset + sizeof (struct abc) < BIOSLength) {
179 abc = (struct abc *)(BIOSImage + ABCOffset);
180 if (memcmp (abc->Version, "AMIN", 4) == 0) {
181 /* Skip to next one if immediately followed by "AMINCBLK"
182 * header in place of a version number. */
183 abc = (struct abc *)memmem (BIOSImage + ABCOffset + 1,
184 BIOSLength - ABCOffset - 1 - sizeof (struct abc),
185 "AMIBIOSC", 8);
186 }
187 } else
188 abc = NULL;
189
190 if (!abc) {
191 fprintf(stderr,
192 "Error: short read after AMIBIOSC signature.\n");
193 return FALSE;
194 }
Luc Verhaegen15587352009-06-26 10:00:29 +0200195
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400196 /* Get Date */
197 memcpy(Date, BIOSImage + BIOSLength - 11, 8);
198 Date[8] = 0;
Luc Verhaegen15587352009-06-26 10:00:29 +0200199
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400200 printf("AMI95 Version\t: %.4s (%s)\n", abc->Version, Date);
Luc Verhaegen15587352009-06-26 10:00:29 +0200201
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400202 /* First, the boot rom */
Luc Verhaegen15587352009-06-26 10:00:29 +0200203 uint32_t BootOffset;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200204 int fd;
205
Luc Verhaegen15587352009-06-26 10:00:29 +0200206 BootOffset = AMIBOffset & 0xFFFF0000;
207
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400208 printf("0x%05X (%6d bytes) -> amiboot.rom\n", BootOffset,
209 BIOSLength - BootOffset);
Luc Verhaegen838fe242009-06-17 00:48:02 +0200210
211 fd = open("amiboot.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
212 if (fd < 0) {
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400213 fprintf(stderr, "Error: unable to open %s: %s\n\n",
214 "amiboot.rom", strerror(errno));
215 return FALSE;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200216 }
217
Luc Verhaegen15587352009-06-26 10:00:29 +0200218 write(fd, BIOSImage + BootOffset, BIOSLength - BootOffset);
Luc Verhaegen838fe242009-06-17 00:48:02 +0200219 close(fd);
Luc Verhaegen838fe242009-06-17 00:48:02 +0200220
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400221 /* now dump the individual modules */
222 if (BIOSLength > 0x100000)
223 Offset = (le16toh(abc->BeginHi) << 16) + le16toh(abc->BeginLo);
Luc Verhaegen838fe242009-06-17 00:48:02 +0200224 else
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400225 Offset = (le16toh(abc->BeginHi) << 4) + le16toh(abc->BeginLo);
Luc Verhaegen838fe242009-06-17 00:48:02 +0200226
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400227 for (i = 0; i < 0x80; i++) {
228 char filename[64], *ModuleName;
229 unsigned char *Buffer;
230 int BufferSize, ROMSize;
Rudolf Marekd6b4fbb2009-12-21 11:30:05 +0100231
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400232 part = (struct part *)(BIOSImage + (Offset - BIOSOffset));
Luc Verhaegen838fe242009-06-17 00:48:02 +0200233
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400234 if (part->IsComprs & 0x80)
235 Compressed = FALSE;
236 else
237 Compressed = TRUE;
238
239 /* even they claim they are compressed they arent */
240 if ((part->PartID == 0x40) || (part->PartID == 0x60))
241 Compressed = FALSE;
242
243 if (part->PartID == 0x20) {
244 uint16_t vid = le32toh(part->RealCS) & 0xFFFF;
245 uint16_t pid = le32toh(part->RealCS) >> 16;
246 sprintf(filename, "amipci_%04X_%04X.rom", vid, pid);
247 } else if (part->PartID == 0x21) {
248 sprintf(filename, "amilang_%c%c.rom",
249 (le32toh(part->RealCS) >> 8) & 0xFF,
250 le32toh(part->RealCS) & 0xFF);
251 } else
252 sprintf(filename, "amibody_%02x.rom", part->PartID);
253
254 if (Compressed) {
255 ROMSize = le32toh(part->ROMSize);
256 BufferSize = le32toh(part->ExpSize);
257 } else {
258 BufferSize = le16toh(part->CSize);
259 if (!BufferSize || (BufferSize == 0xFFFF)) {
260 bigpart =
261 (struct bigpart *)(BIOSImage +
262 (Offset - BIOSOffset) -
263 sizeof(struct bigpart));
264 BufferSize = le32toh(bigpart->CSize);
265 }
266 ROMSize = BufferSize;
267 }
268
269 if (Compressed)
270 printf("0x%05X (%6d bytes)", Offset - BIOSOffset + 0x14,
271 ROMSize);
272 else
273 printf("0x%05X (%6d bytes)", Offset - BIOSOffset + 0x0C,
274 ROMSize);
275
276 printf(" -> %-20s", filename);
277
278 if (Compressed)
279 printf(" (%6d bytes)", BufferSize);
280 else
281 printf(" ");
282
283 ModuleName = AMI95ModuleNameGet(part->PartID);
284 if (ModuleName)
285 printf(" \"%s\"\n", ModuleName);
286 else
287 printf("\n");
288
289 Buffer = MMapOutputFile(filename, BufferSize);
290 if (!Buffer)
291 return FALSE;
292
293 if (Compressed)
294 LH5Decode(BIOSImage + (Offset - BIOSOffset) + 0x14,
295 ROMSize, Buffer, BufferSize);
296 else
297 memcpy(Buffer, BIOSImage + (Offset - BIOSOffset) + 0x0C,
298 BufferSize);
299
300 munmap(Buffer, BufferSize);
301
302 if ((le16toh(part->PrePartHi) == 0xFFFF)
303 || (le16toh(part->PrePartLo) == 0xFFFF))
304 break;
305
306 if (BIOSLength > 0x100000)
307 Offset =
308 (le16toh(part->PrePartHi) << 16) +
309 le16toh(part->PrePartLo);
310 else
311 Offset =
312 (le16toh(part->PrePartHi) << 4) +
313 le16toh(part->PrePartLo);
Luc Verhaegenf5571312010-03-27 13:19:53 +0100314 }
315
Anton Kochkov8f9427f2013-04-07 13:20:30 +0400316 return TRUE;
Luc Verhaegen838fe242009-06-17 00:48:02 +0200317}