Hello,
This patch was developed through some guesswork and by examining the
debug output of "official" tools. Expected output looks like:
Using file "../882.bin" (1024kB)
Found Phoenix BIOS "PhoenixBIOS 4.0 Release 6.1 "
Version "DEVEL972", created on 07/07/08 at 15:37:46.
BCPSYS module offset is NULL.
FFV modules: 5
[ 0]: (00000000-00080000) FED91FBA-D37B-4EEA-8729-2EF29FB37A78
_R00 (00000000-0000819A) 0000819A 00 02 oprom_00.rom
_R01 (0000819A-0000FA31) 00007897 00 02 oprom_01.rom
_H00 (0000FA31-00014EC3) 00005492 00 02 tcpa_H_00.rom
_Q00 (00014EC3-000193B3) 000044F0 00 02 tcpa_Q_00.rom
_A00 (000193B3-0001B034) 00001C81 00 02 acpi_00.rom
_C00 (0001B038-0001C860) 00001828 02 01 update_00.rom
_B05 (0001C860-00027F12) 0000B6B2 00 02 bioscode_05.rom
_B02 (00027F12-00031351) 0000943F 00 02 bioscode_02.rom
_B03 (00031351-00039238) 00007EE7 00 02 bioscode_03.rom
_B00 (00039238-0003E135) 00004EFD 00 02 bioscode_00.rom
_K00 (0003E135-00042B33) 000049FE 00 02 tcpa_K_00.rom
_T00 (00042B33-000471A2) 0000466F 00 02 template_00.rom
_E00 (000471A2-0004B1F0) 0000404E 00 02 setup_00.rom
_S00 (0004B1F0-0004EE85) 00003C95 00 02 strings_00.rom
_L01 (0004EE85-0005212D) 000032A8 00 02 logo_01.rom
_B04 (0005212D-00054DDE) 00002CB1 00 02 bioscode_04.rom
_B06 (00054DDE-00057826) 00002A48 00 02 bioscode_06.rom
_B01 (00057826-000598EE) 000020C8 00 02 bioscode_01.rom
_M00 (000598EE-0005AC93) 000013A5 00 02 miser_00.rom
_D00 (0005AC93-0005B82E) 00000B9B 00 02 display_00.rom
_Y00 (0005B82E-0005C1E2) 000009B4 00 02 _Y00.rom
_L00 (0005C1E2-0005CAA3) 000008C1 00 02 logo_00.rom
_G00 (0005CAA3-0005CF07) 00000464 00 02 decompcode_00.rom
_A01 (0005CF07-0005CF7F) 00000078 00 02 acpi_01.rom
_A02 (0005CF7F-0005CFD1) 00000052 00 02 acpi_02.rom
volumeinfo.bin (0005CFD1-0005D031) 00000060 00 01 volumeinfo.bin
GAP (0005D031-00080000) 00022FCF 00 F0
[ 1]: (00080000-00082000) FD21E8FD-2525-4A95-BB90-47EC5763FF9E
ESCD
[ 2]: (00082000-00090000) F6AE0F63-5F8C-4316-A2EA-76B9AF762756
Hole (raw code)
[ 3]: (00090000-000F7000) FED91FBA-D37B-4EEA-8729-2EF29FB37A78
volumedir.bin2 (00090008-00090190) 00000188 42 01 volumedir.bin2
volumeinfo.bin (00090190-000901F0) 00000060 00 01 volumeinfo.bin
GAP (000901F0-000DFFE8) 0004FDF8 00 F0
_$00 (000DFFE8-000E0004) 0000001C 40 01 _$00.rom
_X01 (000E0008-000E9750) 00009748 40 01 romexec_01.rom
GAP (000E9750-000ED6E8) 00003F98 00 F0
_X00 (000ED6E8-000F6000) 00008918 40 01 romexec_00.rom
GAP (000F6000-000F7000) 00001000 00 F0
[ 4]: (000F7000-00100000) F6AE0F63-5F8C-4316-A2EA-76B9AF762756
Hole (raw code)
Note that many newer Phoenix BIOSes have a trailer containing flash
enable information, etc. which must be stripped off for this code to work.
ESCD seems to be "Extended System Configuration Data" (dumped to
ESCD.bin) and all holes are dumped to hole_%02x.bin.
Signed-off-by: Joshua Roys <roysj...@gmail.com>
>From 952b21e8da57938da65596a5aec047375b60dd87 Mon Sep 17 00:00:00 2001
From: Joshua Roys <roysj...@gmail.com>
Date: Wed, 26 Oct 2011 12:30:06 -0400
Subject: [PATCH] Add support for Phoenix FFV layouts
Signed-off-by: Joshua Roys <roysj...@gmail.com>
---
phoenix.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 268 insertions(+), 13 deletions(-)
diff --git a/phoenix.c b/phoenix.c
index 2da84b7..b1dedf1 100644
--- a/phoenix.c
+++ b/phoenix.c
@@ -66,6 +66,22 @@ PhoenixModuleNames[] = {
{'J', "SmartCardPAS"},
};
+struct PhoenixID {
+ char Name[6];
+ uint16_t Flags;
+ uint16_t Length;
+};
+
+struct PhoenixFFVModule {
+ uint8_t Signature;
+ uint8_t Flags;
+ uint16_t Checksum;
+ uint16_t LengthLo;
+ uint8_t LengthHi;
+ uint8_t Compression;
+ char Name[16];
+};
+
static char *
PhoenixModuleNameGet(char Id)
{
@@ -238,6 +254,244 @@ PhoenixModule(unsigned char *BIOSImage, int BIOSLength,
int Offset)
return le32toh(Module->Previous);
}
+static int
+PhoenixExtractFFV(unsigned char *BIOSImage, int BIOSLength, int Offset)
+{
+ struct PhoenixFFVCompressionHeader {
+ uint16_t TotalLengthLo;
+ uint8_t TotalLengthHi;
+ uint8_t Unk1;
+
+ uint16_t PackedLenLo;
+ uint8_t PackedLenHi;
+ uint8_t Unk2;
+
+ uint16_t RealLenLo;
+ uint8_t RealLenHi;
+ uint8_t Unk3;
+ } *CompHeader;
+ struct PhoenixFFVModule *Module;
+ char Name[16], filename[24];
+ char *ModuleName;
+ int fd;
+ uint32_t Length, PackedLen, RealLen;
+ unsigned char *RealData;
+
+ Module = (struct PhoenixFFVModule *) (BIOSImage + Offset);
+
+ if (Module->Signature != 0xF8) {
+ /* ignore and move on to the next byte... */
+ return 1;
+ }
+
+ Length = (le16toh(Module->LengthHi) << 16) | Module->LengthLo;
+ if ((Offset + ((le16toh(Module->LengthHi) << 16) | Module->LengthLo)) >
BIOSLength) {
+ fprintf(stderr, "Error: Module overruns buffer at 0x%05X\n",
+ Offset);
+ return 1;
+ }
+
+ if (Module->Compression == 0xF0) {
+ strcpy(Name, "GAP");
+ filename[0] = '\0';
+ }
+ else {
+ /* get rid of the pesky 0xFF in the middle of the name */
+ memcpy(Name, Module->Name, 8);
+ memcpy(Name + 8, Module->Name + 9, 7);
+ Name[15] = '\0';
+
+ if (Name[0] == '_') {
+ ModuleName = PhoenixModuleNameGet(Name[1]);
+ if (ModuleName) {
+ snprintf(filename, sizeof(filename), "%s_%c%c.rom", ModuleName,
Name[2], Name[3]);
+ }
+ else {
+ snprintf(filename, sizeof(filename), "%s.rom", Name);
+ }
+ }
+ else {
+ strncpy(filename, Name, sizeof(filename));
+ }
+ }
+
+ printf("\t%-15s (%08X-%08X) %08X %02X %02X %s\n",
+ Name, Offset, Offset + Length, Length, Module->Flags,
Module->Compression, filename
+ );
+
+ switch (Module->Compression) {
+ case 0xF0:
+ break;
+
+ case 0x02:
+ if (Name[1] == 'G') {
+ break;
+ }
+ else {
+ CompHeader = (struct PhoenixFFVCompressionHeader *) (BIOSImage +
Offset + 0x18);
+ }
+ /* some blocks have a (8 byte?) header we need to skip */
+ if (CompHeader->TotalLengthLo != Length - 0x18) {
+ CompHeader = (struct PhoenixFFVCompressionHeader *)
+ ((unsigned char *)CompHeader + CompHeader->TotalLengthLo);
+ }
+ PackedLen = (CompHeader->PackedLenHi << 16) | CompHeader->PackedLenLo;
+ RealLen = (CompHeader->RealLenHi << 16) | CompHeader->RealLenLo;
+ RealData = MMapOutputFile(filename, RealLen);
+ if (!RealData) {
+ fprintf(stderr, "Failed to mmap file for uncompressed data.\n");
+ break;
+ }
+ LH5Decode((unsigned char *)CompHeader + sizeof(struct
PhoenixFFVCompressionHeader),
+ PackedLen, RealData, RealLen);
+ munmap(RealData, RealLen);
+ break;
+
+ case 0x01:
+ fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "Error: unable to open %s: %s\n\n", filename,
strerror(errno));
+ break;
+ }
+ write(fd, BIOSImage + Offset + 0x18, Length - 0x18);
+ close(fd);
+ break;
+
+ default:
+ fprintf(stderr, "\t\tUnsupported compression type!\n");
+ break;
+ }
+
+ return Length;
+}
+
+void
+PhoenixFFVDirectory(unsigned char *BIOSImage, int BIOSLength, int Offset)
+{
+ struct PhoenixVolumeDirEntry {
+ /* these are stored little endian */
+ uint32_t guid1;
+ uint16_t guid2;
+ uint16_t guid3;
+ /* these are big endian */
+ uint16_t guid4;
+ /*uint48_t guid5;*/
+ uint16_t guid5;
+ uint32_t guid6;
+
+ uint32_t Base;
+ uint32_t Length;
+ };
+ struct PhoenixVolumeDir {
+ uint16_t Unk1;
+ uint16_t Unk2;
+ uint32_t Length;
+ struct PhoenixVolumeDirEntry Modules[];
+ } *Volume;
+ struct PhoenixFFVModule *Module;
+ char Name[16], guid[37];
+ int fd, HoleNum = 0;
+ uint32_t Base, Length, NumModules, ModNum;
+
+ Module = (struct PhoenixFFVModule *) (BIOSImage + Offset);
+ Volume = (struct PhoenixVolumeDir *) (BIOSImage + Offset + 0x18);
+
+ if (Module->Signature != 0xF8) {
+ fprintf(stderr, "Error: Invalid module signature at 0x%05X\n",
+ Offset);
+ return;
+ }
+
+ Length = (le16toh(Module->LengthHi) << 16) | Module->LengthLo;
+ if ((Offset + Length) > BIOSLength) {
+ fprintf(stderr, "Error: Module overruns buffer at 0x%05X\n",
+ Offset);
+ return;
+ }
+
+ /* get rid of the pesky 0xFF in the middle of the name */
+ memcpy(Name, Module->Name, 8);
+ memcpy(Name + 8, Module->Name + 9, 7);
+ Name[15] = '\0';
+ if (strcmp(Name, "volumedir.bin2")) {
+ fprintf(stderr, "FFV points to something other than volumedir.bin2:
%s\n", Name);
+ return;
+ }
+
+ NumModules = (Volume->Length - 8) / sizeof(struct PhoenixVolumeDirEntry);
+ printf("FFV modules: %u\n", NumModules);
+
+ for (ModNum = 0; ModNum < NumModules; ModNum++)
+ {
+ sprintf(guid, "%08X-%04X-%04X-%04X-%04X%08X",
+ le32toh(Volume->Modules[ModNum].guid1),
+ le16toh(Volume->Modules[ModNum].guid2),
+ le16toh(Volume->Modules[ModNum].guid3),
+ be16toh(Volume->Modules[ModNum].guid4),
+ be16toh(Volume->Modules[ModNum].guid5),
+ be32toh(Volume->Modules[ModNum].guid6)
+ );
+ Base = Volume->Modules[ModNum].Base & (BIOSLength - 1);
+ Length = Volume->Modules[ModNum].Length;
+ printf("[%2u]: (%08X-%08X) %s\n",
+ ModNum, Base, Base + Length, guid
+ );
+
+ if (!strcmp(guid, "FED91FBA-D37B-4EEA-8729-2EF29FB37A78")) {
+ /* FFV modules */
+ Offset = Base;
+ while (Offset < Base + Length) {
+ Offset += PhoenixExtractFFV(BIOSImage, BIOSLength, Offset);
+ }
+ }
+ else if (!strcmp(guid, "FD21E8FD-2525-4A95-BB90-47EC5763FF9E")) {
+ /* Extended System Configuration Data (and similar?) */
+ printf("\tESCD\n");
+ fd = open("ESCD.bin", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR |
S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "Error: unable to open ESCD.bin: %s\n\n",
strerror(errno));
+ continue;
+ }
+ write(fd, BIOSImage + Base, Length);
+ close(fd);
+ }
+ else if (!strcmp(guid, "F6AE0F63-5F8C-4316-A2EA-76B9AF762756")) {
+ /* Raw BIOS code */
+ printf("\tHole (raw code)\n");
+ snprintf(Name, sizeof(Name), "hole_%02x.bin", HoleNum++);
+ fd = open(Name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "Error: unable to open %s: %s\n\n", Name,
strerror(errno));
+ continue;
+ }
+ write(fd, BIOSImage + Base, Length);
+ close(fd);
+ }
+ else {
+ fprintf(stderr, "\tUnknown FFV module GUID!\n");
+ }
+ }
+
+ return;
+}
+
+Bool
+PhoenixFFV(unsigned char *BIOSImage, int BIOSLength, struct PhoenixID *FFV)
+{
+ uint32_t Offset;
+
+ Offset = le32toh(*((uint32_t *) (((char *) FFV) + 0xA))) & (BIOSLength -
1);
+
+ if (!Offset) {
+ fprintf(stderr, "BCPFFV module offset is NULL.\n");
+ return FALSE;
+ }
+
+ PhoenixFFVDirectory(BIOSImage, BIOSLength, Offset);
+
+ return TRUE;
+}
+
/*
*
*/
@@ -245,11 +499,7 @@ Bool
PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t BCPSegmentOffset)
{
- struct PhoenixID {
- char Name[6];
- uint16_t Flags;
- uint16_t Length;
- } *ID;
+ struct PhoenixID *ID, *SYS = NULL, *FFV = NULL;
uint32_t Offset;
printf("Found Phoenix BIOS \"%s\"\n", (char *) (BIOSImage + Offset1));
@@ -263,10 +513,12 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength,
int BIOSOffset,
ID->Name[4], ID->Name[5], le16toh(ID->Flags),
le16toh(ID->Length));
#endif
if (!strncmp(ID->Name, "BCPSYS", 6))
- break;
+ SYS = ID;
+ else if (!strncmp(ID->Name, "BCPFFV", 6))
+ FFV = ID;
}
- if (!ID->Name[0] || ((void *) ID >= (void *) (BIOSImage + BIOSLength))) {
+ if (!SYS) {
fprintf(stderr, "Error: Failed to locate BCPSYS offset.\n");
return FALSE;
}
@@ -275,21 +527,24 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength,
int BIOSOffset,
{
char Date[9], Time[9], Version[9];
- strncpy(Date, ((char *) ID) + 0x0F, 8);
+ strncpy(Date, ((char *) SYS) + 0x0F, 8);
Date[8] = 0;
- strncpy(Time, ((char *) ID) + 0x18, 8);
+ strncpy(Time, ((char *) SYS) + 0x18, 8);
Time[8] = 0;
- strncpy(Version, ((char *) ID) + 0x37, 8);
+ strncpy(Version, ((char *) SYS) + 0x37, 8);
Version[8] = 0;
printf("Version \"%s\", created on %s at %s.\n", Version, Date, Time);
}
- Offset = le32toh(*((uint32_t *) (((char *) ID) + 0x77)));
+ Offset = le32toh(*((uint32_t *) (((char *) SYS) + 0x77)));
Offset &= (BIOSLength - 1);
if (!Offset) {
- fprintf(stderr, "Error: retrieved invalid Modules offset.\n");
- return FALSE;
+ fprintf(stderr, "BCPSYS module offset is NULL.\n");
+ if (!FFV) {
+ return FALSE;
+ }
+ return PhoenixFFV(BIOSImage, BIOSLength, FFV);
}
while (Offset) {
--
1.7.1
_______________________________________________
flashrom mailing list
flashrom@flashrom.org
http://www.flashrom.org/mailman/listinfo/flashrom