aboutsummaryrefslogtreecommitdiff
path: root/resources/utilities/ich9deblob/src
diff options
context:
space:
mode:
authorFrancis Rowe <info@gluglug.org.uk>2014-12-25 21:25:49 +0000
committerFrancis Rowe <info@gluglug.org.uk>2014-12-25 21:25:49 +0000
commita8b13d23f29a08026eaa308b8b09be7e9d1ff5a6 (patch)
tree0cdc767b9b44b94ca4fbec16bf88496bc4656dd4 /resources/utilities/ich9deblob/src
parent655ac91c5db8818c7cef7e9e44febaf36459d394 (diff)
downloadlibrebootfr-a8b13d23f29a08026eaa308b8b09be7e9d1ff5a6.tar.gz
librebootfr-a8b13d23f29a08026eaa308b8b09be7e9d1ff5a6.zip
ich9deblob: moved src to src/, .o files to obj/
Diffstat (limited to 'resources/utilities/ich9deblob/src')
-rw-r--r--resources/utilities/ich9deblob/src/common/descriptor_gbe.c68
-rw-r--r--resources/utilities/ich9deblob/src/common/descriptor_gbe.h35
-rw-r--r--resources/utilities/ich9deblob/src/common/x86compatibility.c171
-rw-r--r--resources/utilities/ich9deblob/src/common/x86compatibility.h39
-rw-r--r--resources/utilities/ich9deblob/src/descriptor/descriptor.c170
-rw-r--r--resources/utilities/ich9deblob/src/descriptor/descriptor.h265
-rw-r--r--resources/utilities/ich9deblob/src/gbe/gbe.c124
-rw-r--r--resources/utilities/ich9deblob/src/gbe/gbe.h101
-rw-r--r--resources/utilities/ich9deblob/src/ich9deblob.c223
-rw-r--r--resources/utilities/ich9deblob/src/ich9deblob.h37
10 files changed, 1233 insertions, 0 deletions
diff --git a/resources/utilities/ich9deblob/src/common/descriptor_gbe.c b/resources/utilities/ich9deblob/src/common/descriptor_gbe.c
new file mode 100644
index 00000000..fcb80d01
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/common/descriptor_gbe.c
@@ -0,0 +1,68 @@
+/*
+ * descriptor_gbe.c
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Purpose: common descriptor/gbe functions used by ich9deblob
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "descriptor_gbe.h"
+
+/*
+ * create 12KiB file with descriptor, and then gbe immediately after.
+ */
+int notCreatedDescriptorGbeFile(struct DESCRIPTORREGIONRECORD descriptorStruct, struct GBEREGIONRECORD_8K gbeStruct8k, char* fileName)
+{
+ FILE* fileStream = NULL;
+
+ /* These will have the structs copied to them */
+ char descriptorBuffer[DESCRIPTORREGIONSIZE];
+ char gbeBuffer8k[GBEREGIONSIZE_8K];
+
+ /* Copy the structs to buffers, to make writing them as files easier */
+ memcpy(&descriptorBuffer, &descriptorStruct, DESCRIPTORREGIONSIZE); /* descriptor */
+ memcpy(&gbeBuffer8k, &gbeStruct8k, GBEREGIONSIZE_8K); /* gbe */
+
+ /* delete old file before continuing */
+ remove(fileName);
+
+ /* open new file for writing the descriptor+gbe */
+ fileStream = fopen(fileName, "ab");
+
+ /* write the descriptor region into the first part */
+ if (DESCRIPTORREGIONSIZE != fwrite(descriptorBuffer, sizeof(char), DESCRIPTORREGIONSIZE, fileStream))
+ {
+ printf("\nerror: writing descriptor region failed\n");
+ return 1;
+ }
+
+ /* add gbe to the end of the file */
+ if (GBEREGIONSIZE_8K != fwrite(gbeBuffer8k, sizeof(char), GBEREGIONSIZE_8K, fileStream))
+ {
+ printf("\nerror: writing GBe region failed\n");
+ return 1;
+ }
+
+ fclose(fileStream);
+
+ printf("descriptor and gbe successfully written to the file: %s\n", fileName);
+ printf("Now do: dd if=deblobbed_descriptor.bin of=libreboot.rom bs=1 count=12k conv=notrunc\n");
+ printf("(in other words, add the modified descriptor+gbe to your ROM image)\n\n");
+
+ return 0;
+}
diff --git a/resources/utilities/ich9deblob/src/common/descriptor_gbe.h b/resources/utilities/ich9deblob/src/common/descriptor_gbe.h
new file mode 100644
index 00000000..cc0cc42f
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/common/descriptor_gbe.h
@@ -0,0 +1,35 @@
+/*
+ * gbe_descriptor.h
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Purpose: header file for descriptor_gbe.c
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMMON_DESCRIPTOR_GBE_H
+#define COMMON_DESCRIPTOR_GBE_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../descriptor/descriptor.h" /* structs describing what's in the descriptor region */
+#include "../gbe/gbe.h" /* structs describing what's in the gbe region */
+
+int notCreatedDescriptorGbeFile(struct DESCRIPTORREGIONRECORD descriptorStruct, struct GBEREGIONRECORD_8K gbeStruct8k, char* fileName);
+
+#endif
diff --git a/resources/utilities/ich9deblob/src/common/x86compatibility.c b/resources/utilities/ich9deblob/src/common/x86compatibility.c
new file mode 100644
index 00000000..505a37d9
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/common/x86compatibility.c
@@ -0,0 +1,171 @@
+/*
+ * x86compatibility.c
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Purpose: compiler/cpu compatibility checks. ich9deblob is not portable, yet.
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "x86compatibility.h"
+
+/*
+ * ---------------------------------------------------------------------
+ * x86 compatibility checking:
+ * ---------------------------------------------------------------------
+ */
+
+/* fail if struct size is incorrect */
+int structSizesIncorrect(struct DESCRIPTORREGIONRECORD descriptorDummy, struct GBEREGIONRECORD_8K gbe8kDummy)
+{
+ unsigned int descriptorRegionStructSize = sizeof(descriptorDummy);
+ unsigned int gbeRegion8kStructSize = sizeof(gbe8kDummy);
+
+ /* check compiler bit-packs in a compatible way. basically, it is expected that this code will be used on x86 */
+ if (DESCRIPTORREGIONSIZE != descriptorRegionStructSize){
+ printf("\nerror: compiler incompatibility: descriptor struct length is %i bytes (should be %i)\n", descriptorRegionStructSize, DESCRIPTORREGIONSIZE);
+ return 1;
+ }
+ if (GBEREGIONSIZE_8K != gbeRegion8kStructSize){
+ printf("\nerror: compiler incompatibility: gbe struct length is %i bytes (should be %i)\n", gbeRegion8kStructSize, GBEREGIONSIZE_8K);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* endianness check. big endian forced to fail */
+int systemIsBigEndian()
+{
+ unsigned short steak = 0xBEEF;
+ unsigned char *grill = (unsigned char*)&steak;
+
+ if (*grill==0xBE) {
+ printf("\nunsigned short 0xBEEF: first byte should be EF, but it's BE. Your system is big endian, and unsupported (only little endian is tested)\n");
+ return 1;
+ }
+ return 0; /* you got the good half of the steak */
+}
+
+/* fail if members are presented in the wrong order */
+int structMembersWrongOrder()
+{
+ int i;
+ struct DESCRIPTORREGIONRECORD descriptorDummy;
+ unsigned char *meVsccTablePtr = (unsigned char*)&descriptorDummy.meVsccTable;
+
+ /* These do not use bitfields. */
+ descriptorDummy.meVsccTable.jid0 = 0x01020304; /* unsigned int 32-bit */
+ descriptorDummy.meVsccTable.vscc0 = 0x10203040; /* unsigned int 32-bit */
+ descriptorDummy.meVsccTable.jid1 = 0x11223344; /* unsigned int 32-bit */
+ descriptorDummy.meVsccTable.vscc1 = 0x05060708; /* unsigned int 32-bit */
+ descriptorDummy.meVsccTable.jid2 = 0x50607080; /* unsigned int 32-bit */
+ descriptorDummy.meVsccTable.vscc2 = 0x55667788; /* unsigned int 32-bit */
+ descriptorDummy.meVsccTable.padding[0] = 0xAA; /* unsigned char 8-bit */
+ descriptorDummy.meVsccTable.padding[1] = 0xBB; /* unsigned char 8-bit */
+ descriptorDummy.meVsccTable.padding[2] = 0xCC; /* unsigned char 8-bit */
+ descriptorDummy.meVsccTable.padding[3] = 0xDD; /* unsigned char 8-bit */
+
+ /*
+ * Look from the top down, and concatenate the unsigned ints but
+ * with each unsigned in little endian order.
+ * Then, concatenate the unsigned chars in big endian order. (in the padding array)
+ *
+ * combined, these should become:
+ * 01020304 10203040 11223344 05060708 50607080 55667788 AA BB CC DD (ignore this. big endian. just working it out manually:)
+ * 04030201 40302010 44332211 08070605 80706050 88776655 AA BB CC DD (ignore this. not byte-separated, just working it out:)
+ * 04 03 02 01 40 30 20 10 44 33 22 11 08 07 06 05 80 70 60 50 88 77 66 55 AA BB CC DD <-- it should match this
+ */
+
+ if (
+ !
+ (
+ *meVsccTablePtr == 0x04 && *(meVsccTablePtr+1) == 0x03 && *(meVsccTablePtr+2) == 0x02 && *(meVsccTablePtr+3) == 0x01
+ && *(meVsccTablePtr+4) == 0x40 && *(meVsccTablePtr+5) == 0x30 && *(meVsccTablePtr+6) == 0x20 && *(meVsccTablePtr+7) == 0x10
+ && *(meVsccTablePtr+8) == 0x44 && *(meVsccTablePtr+9) == 0x33 && *(meVsccTablePtr+10) == 0x22 && *(meVsccTablePtr+11) == 0x11
+ && *(meVsccTablePtr+12) == 0x08 && *(meVsccTablePtr+13) == 0x07 && *(meVsccTablePtr+14) == 0x06 && *(meVsccTablePtr+15) == 0x05
+ && *(meVsccTablePtr+16) == 0x80 && *(meVsccTablePtr+17) == 0x70 && *(meVsccTablePtr+18) == 0x60 && *(meVsccTablePtr+19) == 0x50
+ && *(meVsccTablePtr+20) == 0x88 && *(meVsccTablePtr+21) == 0x77 && *(meVsccTablePtr+22) == 0x66 && *(meVsccTablePtr+23) == 0x55
+ && *(meVsccTablePtr+24) == 0xAA && *(meVsccTablePtr+25) == 0xBB && *(meVsccTablePtr+26) == 0xCC && *(meVsccTablePtr+27) == 0xDD
+ )
+ ) {
+
+ printf("\nStruct member order check (descriptorDummy.meVsccTable) with junk/dummy data:");
+ printf("\nShould be: 04 03 02 01 40 30 20 10 44 33 22 11 08 07 06 05 80 70 60 50 88 77 66 55 aa bb cc dd ");
+ printf("\nAnd it is: ");
+
+ for (i = 0; i < 28; i++) {
+ printf("%02x ", *(meVsccTablePtr + i));
+ }
+ printf("\nIncorrect order.\n");
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* fail if bit fields are presented in the wrong order */
+int structBitfieldWrongOrder()
+{
+ int i;
+ struct DESCRIPTORREGIONRECORD descriptorDummy;
+ unsigned char *flMap0Ptr = (unsigned char*)&descriptorDummy.flMaps.flMap0;
+
+ descriptorDummy.flMaps.flMap0.FCBA = 0xA2; /* :8 --> 10100010 */
+ descriptorDummy.flMaps.flMap0.NC = 0x02; /* :2 --> 10 */
+ descriptorDummy.flMaps.flMap0.reserved1 = 0x38; /* :6 --> 111000 */
+ descriptorDummy.flMaps.flMap0.FRBA = 0xD2; /* :8 --> 11010010 */
+ descriptorDummy.flMaps.flMap0.NR = 0x05; /* :3 --> 101 */
+ descriptorDummy.flMaps.flMap0.reserved2 = 0x1C; /* :5 --> 11100 */
+
+ /*
+ * Look from the top bottom up, and concatenate the binary strings.
+ * Then, convert the 8-bit groups to hex and reverse the (8-bit)byte order
+ *
+ * combined, these should become (in memory), in binary:
+ * 10100010 11100010 11010010 11100101
+ * or in hex:
+ * A2 E2 D2 E5
+ */
+
+ if (!(*flMap0Ptr == 0xA2 && *(flMap0Ptr+1) == 0xE2 && *(flMap0Ptr+2) == 0xD2 && *(flMap0Ptr+3) == 0xE5))
+ {
+ printf("\nBitfield order check (descriptorDummy.flMaps.flMaps0) with junk/dummy data:");
+ printf("\nShould be: a2 e2 d2 e5 ");
+ printf("\nAnd it is: ");
+
+ for (i = 0; i < 4; i++) {
+ printf("%02x ", *(flMap0Ptr + i));
+ }
+ printf("\nIncorrect order.\n");
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Compatibility checks. This version of ich9deblob is not yet porable. */
+int systemOrCompilerIncompatible(struct DESCRIPTORREGIONRECORD descriptorStruct, struct GBEREGIONRECORD_8K gbeStruct8k)
+{
+ if (structSizesIncorrect(descriptorStruct, gbeStruct8k)) return 1;
+ if (systemIsBigEndian()) return 1;
+ if (structBitfieldWrongOrder()) return 1;
+ if (structMembersWrongOrder()) return 1;
+ return 0;
+}
diff --git a/resources/utilities/ich9deblob/src/common/x86compatibility.h b/resources/utilities/ich9deblob/src/common/x86compatibility.h
new file mode 100644
index 00000000..d9d5bdb3
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/common/x86compatibility.h
@@ -0,0 +1,39 @@
+/*
+ * x86compatibility.h
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Purpose: keep gcc/make happy. no actual code here, just function definitions.
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef X86COMPATIBILITY_H
+#define X86COMPATIBILITY_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../descriptor/descriptor.h" /* structs describing what's in the descriptor region */
+#include "../gbe/gbe.h" /* structs describing what's in the gbe region */
+
+int structSizesIncorrect(struct DESCRIPTORREGIONRECORD descriptorDummy, struct GBEREGIONRECORD_8K gbe8kDummy);
+int systemIsBigEndian();
+int structMembersWrongOrder();
+int structBitfieldWrongOrder();
+int systemOrCompilerIncompatible(struct DESCRIPTORREGIONRECORD descriptorStruct, struct GBEREGIONRECORD_8K gbeStruct8k);
+
+#endif
diff --git a/resources/utilities/ich9deblob/src/descriptor/descriptor.c b/resources/utilities/ich9deblob/src/descriptor/descriptor.c
new file mode 100644
index 00000000..aa3d84e5
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/descriptor/descriptor.c
@@ -0,0 +1,170 @@
+/*
+ * descriptor/descriptor.c
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Provide descriptor related functions.
+ */
+
+/* structs describing the data in descriptor region */
+#include "descriptor.h"
+
+/*
+ * ---------------------------------------------------------------------
+ * Descriptor functions
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * Modify the flash descriptor, to remove the ME/AMT, and disable all other regions
+ * Only Flash Descriptor, Gbe and BIOS regions (BIOS region fills factoryRomSize-12k) are left.
+ * Tested on ThinkPad X200 and X200S. X200T and other GM45 targets may also work.
+ * Also described in docs/hcl/x200_remove_me.html
+ */
+struct DESCRIPTORREGIONRECORD deblobbedDescriptorStructFromFactory(struct DESCRIPTORREGIONRECORD factoryDescriptorStruct, unsigned int factoryRomSize)
+{
+ struct DESCRIPTORREGIONRECORD deblobbedDescriptorStruct;
+ memcpy(&deblobbedDescriptorStruct, &factoryDescriptorStruct, DESCRIPTORREGIONSIZE);
+
+ /*
+ * set number of regions from 4 -> 2 (0 based, so 4 means 5 and 2
+ * means 3. We want 3 regions: descriptor, gbe and bios, in that order)
+ */
+ deblobbedDescriptorStruct.flMaps.flMap0.NR = 2;
+
+ /*
+ * make descriptor writable from OS. This is that the user can run:
+ * sudo ./flashrom -p internal:laptop=force_I_want_a_brick
+ * from the OS, without relying an an external SPI flasher, while
+ * being able to write to the descriptor region (locked by default,
+ * until making the change below):
+ */
+ deblobbedDescriptorStruct.masterAccessSection.flMstr1.fdRegionWriteAccess = 1;
+
+ /* relocate BIOS region and increase size to fill image */
+ deblobbedDescriptorStruct.regionSection.flReg1.BASE = 3; // 3<<FLREGIONBITSHIFT is 12KiB, which is where BIOS region is to begin (after descriptor and gbe)
+ deblobbedDescriptorStruct.regionSection.flReg1.LIMIT = ((factoryRomSize >> FLREGIONBITSHIFT) - 1);
+ /*
+ * ^ for example, 8MB ROM, that's 8388608 bytes.
+ * ^ 8388608>>FLREGIONBITSHIFT (or 8388608/4096) = 2048 bytes
+ * 2048 - 1 = 2047 bytes.
+ * This defines where the final 0x1000 (4KiB) page starts in the flash chip, because the hardware does:
+ * 2047<<FLREGIONBITSHIFT (or 2047*4096) = 8384512 bytes, or 7FF000 bytes
+ * (it can't be 0x7FFFFF because of limited number of bits)
+ */
+
+ /* set ME region size to 0 - the ME is a blob, we don't want it in libreboot */
+ deblobbedDescriptorStruct.regionSection.flReg2.BASE = 0x1FFF; // setting 1FFF means setting size to 0. 1FFF<<FLREGIONBITSHIFT is outside of the ROM image (8MB) size?
+ /* ^ datasheet says to set this to 1FFF, but FFF was previously used and also worked. */
+ deblobbedDescriptorStruct.regionSection.flReg2.LIMIT = 0;
+ /*
+ * ^ 0<<FLREGIONBITSHIFT=0, so basically, the size is 0,
+ * ^ and the base (1FFF>>FLREGIONBITSHIFT) is well outside the higher 8MB range.
+ */
+
+ /* relocate Gbe region to begin at 4KiB (immediately after the flash descriptor) */
+ deblobbedDescriptorStruct.regionSection.flReg3.BASE = 1; // 1<<FLREGIONBITSHIFT is 4096, which is where the Gbe region is to begin (after the descriptor)
+ deblobbedDescriptorStruct.regionSection.flReg3.LIMIT = 2;
+ /*
+ * ^ 2<<FLREGIONBITSHIFT=8192 bytes. So we are set it to size 8KiB after the first 4KiB in the flash chip.
+ */
+
+ /* set Platform region size to 0 - another blob that we don't want */
+ deblobbedDescriptorStruct.regionSection.flReg4.BASE = 0x1FFF; // setting 1FFF means setting size to 0. 1FFF<<FLREGIONBITSHIFT is outside of the ROM image (8MB) size?
+ /* ^ datasheet says to set this to 1FFF, but FFF was previously used and also worked. */
+ deblobbedDescriptorStruct.regionSection.flReg4.LIMIT = 0;
+ /*
+ * ^ 0<<FLREGIONBITSHIFT=0, so basically, the size is 0,
+ * and the base (1FFF>>FLREGIONBITSHIFT) is well outside the higher 8MB range.
+ */
+
+ /* disable ME in ICHSTRAP0 - the ME is a blob, we don't want it in libreboot */
+ deblobbedDescriptorStruct.ichStraps.ichStrap0.meDisable = 1;
+
+ /* disable ME and TPM in MCHSTRAP0 */
+ deblobbedDescriptorStruct.mchStraps.mchStrap0.meDisable = 1; // ME is a blob. not wanted in libreboot.
+ deblobbedDescriptorStruct.mchStraps.mchStrap0.tpmDisable = 1; // not wanted in libreboot
+
+ /*
+ * disable ME, apart from chipset bugfixes (ME region should first be re-enabled above)
+ * This is sort of like the CPU microcode updates, but for the chipset
+ * (commented out below here, since blobs go against libreboot's purpose,
+ * but may be interesting for others)
+ * deblobbedDescriptorStruct.mchStraps.mchStrap0.meAlternateDisable = 1;
+ */
+
+ return deblobbedDescriptorStruct;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * Debugging functions:
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * show debugging info: descriptor region boundaries, in a 4KB struct.
+ */
+void printDescriptorRegionLocations(struct DESCRIPTORREGIONRECORD descriptorStruct, char* romName)
+{
+ printf("\n");
+
+ /* Descriptor region */
+ printf(
+ "%s: Descriptor start block: %08x ; Descriptor end block: %08x\n",
+ romName,
+ descriptorStruct.regionSection.flReg0.BASE << FLREGIONBITSHIFT,
+ descriptorStruct.regionSection.flReg0.LIMIT << FLREGIONBITSHIFT
+ );
+
+ /* BIOS region */
+ printf(
+ "%s: BIOS start block: %08x ; BIOS end block: %08x\n",
+ romName,
+ descriptorStruct.regionSection.flReg1.BASE << FLREGIONBITSHIFT,
+ descriptorStruct.regionSection.flReg1.LIMIT << FLREGIONBITSHIFT
+ );
+
+ /* ME region */
+ printf(
+ "%s: ME start block: %08x ; ME end block: %08x\n",
+ romName,
+ descriptorStruct.regionSection.flReg2.BASE << FLREGIONBITSHIFT,
+ descriptorStruct.regionSection.flReg2.LIMIT << FLREGIONBITSHIFT
+ );
+
+ /* GBe region */
+ printf(
+ "%s: GBe start block: %08x ; GBe end block: %08x\n",
+ romName,
+ descriptorStruct.regionSection.flReg3.BASE << FLREGIONBITSHIFT,
+ descriptorStruct.regionSection.flReg3.LIMIT << FLREGIONBITSHIFT
+ );
+
+ /* Platform region */
+ printf(
+ "%s: Platform start block: %08x ; GBe end block: %08x\n",
+ romName,
+ descriptorStruct.regionSection.flReg4.BASE << FLREGIONBITSHIFT,
+ descriptorStruct.regionSection.flReg4.LIMIT << FLREGIONBITSHIFT
+ );
+
+ return;
+}
diff --git a/resources/utilities/ich9deblob/src/descriptor/descriptor.h b/resources/utilities/ich9deblob/src/descriptor/descriptor.h
new file mode 100644
index 00000000..863b8945
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/descriptor/descriptor.h
@@ -0,0 +1,265 @@
+/*
+ * descriptor/descriptor.h
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Purpose: provide struct representing descriptor region.
+ * Map actual buffers of this regions, directly to instances of these
+ * structs. This makes working with descriptor really easy.
+ *
+ * bit fields used, corresponding to datasheet. See links to datasheets
+ * and documentation in ich9deblob.c
+ */
+
+#ifndef DESCRIPTORSTRUCT_H
+#define DESCRIPTORSTRUCT_H
+
+#include <stdio.h>
+#include <string.h>
+
+/* size of the descriptor in bytes */
+#define DESCRIPTORREGIONSIZE 0x1000
+
+/*
+ * Related to the flash descriptor
+ * bits 12(0xC)-24(0x18) are represented for words found in the flash descriptor
+ * To manipulate these easily in C, we shift them by FLREGIONBITSHIFT and then shift them back when done
+ * (because this is how data is stored in the flash descriptor)
+ */
+#define FLREGIONBITSHIFT 0xC
+
+/*
+ * ---------------------------------------------------------------------
+ * Descriptor struct representing the data
+ * ---------------------------------------------------------------------
+ */
+
+struct FLVALSIG
+{
+ unsigned int signature;
+};
+
+struct FLMAP0
+{
+ /* least signicant bits */
+ unsigned char FCBA : 8;
+ unsigned char NC : 2;
+ unsigned char reserved1 : 6;
+ /*
+ * ^^^^ unnamed members like these represent unused bits (per datasheet).
+ * the same applies for all structs in this file.
+ */
+ unsigned char FRBA : 8;
+ unsigned char NR : 3;
+ unsigned char reserved2 : 5;
+ /* most significant bits. */
+
+ /*
+ * the datasheet lists msb's first and lsb's last, in each table.
+ * meanwhile, x86 gcc treats the members at the top of the struct as lsb's
+ * and at the bottom of the struct, the members there are msb's. The same
+ * fact applies to all the other structs below.
+ *
+ * non-x86 (and/or non-gcc) is untested. little endian assumed.
+ */
+};
+
+struct FLMAP1
+{
+ unsigned char FMBA : 8;
+ unsigned char NM : 3;
+ unsigned char reserved : 5;
+ unsigned char FISBA : 8;
+ unsigned char ISL : 8;
+};
+
+struct FLMAP2
+{
+ unsigned char FMSBA : 8;
+ unsigned char MSL : 8;
+ unsigned short reserved : 16;
+};
+
+struct FLMAPS
+{
+ struct FLMAP0 flMap0;
+ struct FLMAP1 flMap1;
+ struct FLMAP2 flMap2;
+};
+
+struct FLCOMP
+{
+ unsigned char component1Density : 3;
+ unsigned char component2Density : 3;
+ unsigned char reserved1 : 2;
+ unsigned char reserved2 : 8;
+ unsigned char reserved3 : 1;
+ unsigned char readClockFrequency : 3;
+ unsigned char fastReadSupport : 1;
+ unsigned char fastreadClockFrequency : 3;
+ unsigned char writeEraseClockFrequency : 3;
+ unsigned char readStatusClockFrequency : 3;
+ unsigned char reserved4 : 2;
+};
+
+struct COMPONENTSECTIONRECORD
+{
+ struct FLCOMP flcomp;
+ unsigned int flill;
+ unsigned int flpb;
+ unsigned char padding[36];
+};
+
+struct FLREG
+{
+ unsigned short BASE : 13;
+ unsigned short reserved1 : 3;
+ unsigned short LIMIT : 13;
+ unsigned short reserved2 : 3;
+};
+
+struct REGIONSECTIONRECORD
+{
+ struct FLREG flReg0; /* Descriptor */
+ struct FLREG flReg1; /* BIOS */
+ struct FLREG flReg2; /* ME */
+ struct FLREG flReg3; /* Gbe */
+ struct FLREG flReg4; /* Platform */
+ unsigned char padding[12];
+};
+
+struct FLMSTR {
+ unsigned short requesterId : 16;
+ unsigned char fdRegionReadAccess : 1;
+ unsigned char biosRegionReadAccess : 1;
+ unsigned char meRegionReadAccess : 1;
+ unsigned char gbeRegionReadAccess : 1;
+ unsigned char pdRegionReadAccess : 1;
+ unsigned char reserved1 : 3;
+ unsigned char fdRegionWriteAccess : 1;
+ unsigned char biosRegionWriteAccess : 1;
+ unsigned char meRegionWriteAccess : 1;
+ unsigned char gbeRegionWriteAccess : 1;
+ unsigned char pdRegionWriteAccess : 1;
+ unsigned char reserved2 : 3;
+};
+
+
+struct MASTERACCESSSECTIONRECORD {
+ struct FLMSTR flMstr1;
+ struct FLMSTR flMstr2;
+ struct FLMSTR flMstr3;
+ unsigned char padding[148];
+};
+
+struct ICHSTRAP0 {
+ /* todo: add MeSmBus2Sel (boring setting) */
+ unsigned char meDisable : 1; /* If true, ME is disabled. */
+ unsigned char reserved1 : 6;
+ unsigned char tcoMode : 1; /* TCO Mode: (Legacy,TCO Mode) The TCO Mode, along with the BMCMODE strap, determines the behavior of the IAMT SmBus controller. */
+ unsigned char smBusAddress : 7; /* The ME SmBus 7-bit address. */
+ unsigned char bmcMode : 1; /* BMC mode: If true, device is in BMC mode. If Intel(R) AMT or ASF using Intel integrated LAN then this should be false. */
+ unsigned char tripPointSelect : 1; /* Trip Point Select: false the NJCLK input buffer is matched to 3.3v signal from the external PHY device, true is matched to 1.8v. */
+ unsigned char reserved2 : 2;
+ unsigned char integratedGbe : 1; /* Integrated GbE or PCI Express select: (PCI Express,,Integrated GbE) Defines what PCIe Port 6 is used for. */
+ unsigned char lanPhy : 1; /* LANPHYPC_GP12_SEL: Set to 0 for GP12 to be used as GPIO (General Purpose Input/Output), or 1 for GP12 to be used for native mode as LAN_PHYPC for 82566 LCD device */
+ unsigned char reserved3 : 3;
+ unsigned char dmiRequesterId : 1; /* DMI requestor ID security check disable: The primary purpose of this strap is to support server environments with multiple CPUs that each have a different RequesterID that can access the Flash. */
+ unsigned char smBus2Address : 7; /* The ME SmBus 2 7-bit address. */
+};
+
+struct ICHSTRAP1 {
+ unsigned char northMlink : 1; /* North MLink Dynamic Clock Gate Disable : Sets the default value for the South MLink Dynamic Clock Gate Enable registers. */
+ unsigned char southMlink : 1; /* South MLink Dynamic Clock Gate Enable : Sets the default value for the South MLink Dynamic Clock Gate Enable registers. */
+ unsigned char meSmbus : 1; /* ME SmBus Dynamic Clock Gate Enable : Sets the default value for the ME SMBus Dynamic Clock Gate Enable for both the ME SmBus controllers. */
+ unsigned char sstDynamic : 1; /* SST Dynamic Clock Gate Enable : Sets the default value for the SST Clock Gate Enable registers. */
+ unsigned char reserved1 : 4;
+ unsigned char northMlink2 : 1; /* North MLink 2 Non-Posted Enable : 'true':North MLink supports two downstream non-posted requests. 'false':North MLink supports one downstream non-posted requests. */
+ unsigned char reserved2 : 7;
+ unsigned short reserved3 : 16;
+};
+
+
+struct ICHSTRAPSRECORD {
+ struct ICHSTRAP0 ichStrap0;
+ struct ICHSTRAP1 ichStrap1;
+ unsigned char padding[248];
+};
+
+struct MCHSTRAP0 {
+ unsigned char meDisable : 1; /* If true, ME is disabled. */
+ unsigned char meBootFromFlash : 1; /* ME boot from Flash - guessed location */
+ unsigned char tpmDisable : 1; /* iTPM Disable : When set true, iTPM Host Interface is disabled. When set false (default), iTPM is enabled. */
+ unsigned char reserved1 : 3;
+ unsigned char spiFingerprint : 1; /* SPI Fingerprint Sensor Present: Indicates if an SPI Fingerprint sensor is present at CS#1. */
+ unsigned char meAlternateDisable : 1; /* ME Alternate Disable: Setting this bit allows ME to perform critical chipset functions but prevents loading of any ME FW applications. */
+ unsigned char reserved2 : 8;
+ unsigned short reserved3 : 16;
+};
+
+struct MCHSTRAPSRECORD {
+ struct MCHSTRAP0 mchStrap0;
+ unsigned char padding[3292];
+};
+
+struct MEVSCCTABLERECORD {
+ unsigned int jid0;
+ unsigned int vscc0;
+ unsigned int jid1;
+ unsigned int vscc1;
+ unsigned int jid2;
+ unsigned int vscc2;
+ unsigned char padding[4];
+};
+
+struct DESCRIPTORMAP2RECORD {
+ unsigned char meVsccTableBaseAddress : 8;
+ unsigned char meVsccTableLength : 8;
+ unsigned short reserved : 16;
+};
+
+struct OEMSECTIONRECORD {
+ unsigned char magicString[8];
+ unsigned char padding[248];
+};
+
+struct DESCRIPTORREGIONRECORD {
+ struct FLVALSIG flValSig;
+ struct FLMAPS flMaps;
+ struct COMPONENTSECTIONRECORD componentSection;
+ struct REGIONSECTIONRECORD regionSection;
+ struct MASTERACCESSSECTIONRECORD masterAccessSection;
+ struct ICHSTRAPSRECORD ichStraps;
+ struct MCHSTRAPSRECORD mchStraps;
+ struct MEVSCCTABLERECORD meVsccTable;
+ struct DESCRIPTORMAP2RECORD descriptor2Map;
+ struct OEMSECTIONRECORD oemSection;
+};
+
+/*
+ * ---------------------------------------------------------------------
+ * Function declarations (keep gcc/make happy. check them in descriptor.c)
+ * ---------------------------------------------------------------------
+ */
+
+struct DESCRIPTORREGIONRECORD deblobbedDescriptorStructFromFactory(struct DESCRIPTORREGIONRECORD factoryDescriptorStruct, unsigned int factoryRomSize);
+void printDescriptorRegionLocations(struct DESCRIPTORREGIONRECORD descriptorStruct, char* romName);
+
+#endif
diff --git a/resources/utilities/ich9deblob/src/gbe/gbe.c b/resources/utilities/ich9deblob/src/gbe/gbe.c
new file mode 100644
index 00000000..9eee8284
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/gbe/gbe.c
@@ -0,0 +1,124 @@
+/*
+ * gbe/gbe.c
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Provide gbe related functions.
+ */
+
+/* structs describing the data from gbe region */
+#include "gbe.h"
+
+/*
+ * ---------------------------------------------------------------------
+ * Gbe functions:
+ * ---------------------------------------------------------------------
+ */
+
+/* Read a 16-bit unsigned int from a supplied region buffer */
+unsigned short gbeGetRegionWordFrom8kBuffer(int index, char* regionData)
+{
+ return *((unsigned short*)(regionData + (index * 2)));
+}
+
+/*
+ * gbe checksum calculation (algorithm based on datasheet)
+ */
+unsigned short gbeGetChecksumFrom8kBuffer(char* regionData, unsigned short desiredValue, int byteOffset)
+{
+ int i;
+
+ /*
+ * byteOffset defines the byte address where the gbe begins in the buffer "regionData".
+ * However, this function works with 16-bit words. Shift the byte offset to the right for the word (16-bit) offset.
+ */
+ int wordOffset = byteOffset >> 1;
+
+ unsigned short regionWord; /* store words here for adding to checksum */
+ unsigned short checksum = 0; /* this gbe's checksum */
+
+ for (i = 0; i < 0x3F; i++) {
+ regionWord = gbeGetRegionWordFrom8kBuffer(i+wordOffset, regionData);
+ checksum += regionWord;
+ }
+ checksum = desiredValue - checksum;
+ return checksum;
+}
+
+/* checksum calculation for 4k gbe struct (algorithm based on datasheet) */
+unsigned short gbeGetChecksumFrom4kStruct(struct GBEREGIONRECORD_4K gbeStruct4k, unsigned short desiredValue)
+{
+ char gbeBuffer4k[GBEREGIONSIZE_4K];
+ memcpy(&gbeBuffer4k, &gbeStruct4k, GBEREGIONSIZE_4K);
+ return gbeGetChecksumFrom8kBuffer(gbeBuffer4k, desiredValue, 0);
+}
+
+/* modify the gbe region extracted from a factory.rom dump */
+struct GBEREGIONRECORD_8K deblobbedGbeStructFromFactory(struct GBEREGIONRECORD_8K factoryGbeStruct8k)
+{
+ /*
+ * Correct the main gbe region. By default, the X200 (as shipped from Lenovo) comes
+ * with a broken main gbe region, where the backup gbe region is used instead. Modify
+ * it so that the main region is usable.
+ */
+
+ struct GBEREGIONRECORD_8K deblobbedGbeStruct8k;
+ memcpy(&deblobbedGbeStruct8k, &factoryGbeStruct8k, GBEREGIONSIZE_8K);
+
+ deblobbedGbeStruct8k.backup.checkSum = gbeGetChecksumFrom4kStruct(deblobbedGbeStruct8k.backup, GBECHECKSUMTOTAL);
+ memcpy(&deblobbedGbeStruct8k.main, &deblobbedGbeStruct8k.backup, GBEREGIONSIZE_4K);
+
+ return deblobbedGbeStruct8k;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * Debugging functions:
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * show debugging info: show calculated (correct) gbe checksum and what
+ * is actually stored, in a 4K gbe struct. Only for a single region.
+ */
+void printGbeChecksumDataFromStruct4k(struct GBEREGIONRECORD_4K gbeStruct4k, char* romName, char* regionName)
+{
+ printf(
+ "%s Gbe (%s): calculated Gbe checksum: 0x%hx and actual GBe checksum: 0x%hx\n",
+ romName,
+ regionName,
+ gbeGetChecksumFrom4kStruct(gbeStruct4k, GBECHECKSUMTOTAL),
+ gbeStruct4k.checkSum
+ );
+
+ return;
+}
+
+/*
+ * show debugging info: show calculated (correct) gbe checksum and what
+ * is actually stored, in a 8K gbe struct. Do so for main and backup regions.
+ */
+void printGbeChecksumDataFromStruct8k(struct GBEREGIONRECORD_8K gbeStruct8k, char* romName)
+{
+ printGbeChecksumDataFromStruct4k(gbeStruct8k.main, romName, "main");
+ printGbeChecksumDataFromStruct4k(gbeStruct8k.backup, romName, "backup");
+
+ return;
+}
diff --git a/resources/utilities/ich9deblob/src/gbe/gbe.h b/resources/utilities/ich9deblob/src/gbe/gbe.h
new file mode 100644
index 00000000..bfcc0024
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/gbe/gbe.h
@@ -0,0 +1,101 @@
+/*
+ * gbe/gbe.h
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Purpose: provide struct representing gbe region.
+ * Map actual buffers of this regions, directly to instances of these
+ * structs. This makes working with gbe really easy.
+ */
+
+/*
+ * bit fields used, corresponding to datasheet. See links to datasheets
+ * and documentation in ich9deblob.c
+ */
+
+#ifndef GBESTRUCT_H
+#define GBESTRUCT_H
+
+#include <stdio.h>
+#include <string.h>
+
+/* Size of the full gbe region in bytes */
+#define GBEREGIONSIZE_8K 0x2000
+/*
+ * Size of each sub-region in gbe.
+ * gbe contains two regions which
+ * can be identical: main and backup.
+ * These are each half the size of the full region
+ */
+#define GBEREGIONSIZE_4K 0x1000
+
+/*
+ * When adding up the first 0x3F 16-bit words
+ * in a 4KiB GBE region, it should be equal
+ * to 0xBABA
+ */
+#define GBECHECKSUMTOTAL 0xBABA
+
+/*
+ * These will have a modified descriptor+gbe based on what's in the factory.rom
+ * These will be joined into a single 12KiB buffer (descriptor, then gbe) and saved to a file
+ * NOTE: The GBE region of 8K is actually 2x 4K regions in a single region; both 4K blocks can be identical (and by default, are)
+ * The 2nd one is a "backup", but we don't know when it's used. perhaps it's used when the checksum on the first one does not match?
+ */
+
+/*
+ * ---------------------------------------------------------------------
+ * Gbe struct representing the data:
+ * ---------------------------------------------------------------------
+ */
+
+struct GBEREGIONRECORD_4K {
+ unsigned char macAddress[6]; /* 0x03 words, or 0x06 bytes */
+ unsigned char otherStuff[120]; /* 0x3c words, or 0x7E bytes */
+ unsigned short checkSum; /* when added to the sum of all words above, this should match GBECHECKSUMTOTAL */
+ unsigned char padding1[3968];
+};
+
+/* main and backup region in gbe */
+struct GBEREGIONRECORD_8K {
+ struct GBEREGIONRECORD_4K main;
+ struct GBEREGIONRECORD_4K backup;
+ /*
+ * Backup region:
+ * This is actually "main" on X200, since the real main has a bad checksum
+ * and other errors. You should do what you need on this one (if modifying
+ * lenovobios's gbe region) and then copy to main
+ */
+};
+
+/*
+ * ---------------------------------------------------------------------
+ * Function declarations (keep gcc/make happy. check them in gbe.c)
+ * ---------------------------------------------------------------------
+ */
+
+unsigned short gbeGetRegionWordFrom8kBuffer(int index, char* regionData);
+unsigned short gbeGetChecksumFrom8kBuffer(char* regionData, unsigned short desiredValue, int byteOffset);
+unsigned short gbeGetChecksumFrom4kStruct(struct GBEREGIONRECORD_4K gbeStruct4k, unsigned short desiredValue);
+struct GBEREGIONRECORD_8K deblobbedGbeStructFromFactory(struct GBEREGIONRECORD_8K factoryGbeStruct8k);
+void printGbeChecksumDataFromStruct4k(struct GBEREGIONRECORD_4K gbeStruct4k, char* romName, char* regionName);
+void printGbeChecksumDataFromStruct8k(struct GBEREGIONRECORD_8K gbeStruct8k, char* romName);
+
+#endif
diff --git a/resources/utilities/ich9deblob/src/ich9deblob.c b/resources/utilities/ich9deblob/src/ich9deblob.c
new file mode 100644
index 00000000..ee549d2d
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/ich9deblob.c
@@ -0,0 +1,223 @@
+/*
+ * ich9deblob.c
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Purpose: disable and remove the ME from ich9m/gm45 machines in coreboot.
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Initially based on proof of concept by Steve Shenton. */
+
+/*
+ * Read a factory.rom dump (ich9m/gm45 machines) and
+ * modify the flash descriptor to remove all regions except descriptor,
+ * Gbe and BIOS. Set BIOS region to full size of the ROM image (after
+ * the flash descriptor and gbe). Basically, deblob the descriptor.
+ *
+ * This will will generate a concatenated descriptor+gbe dump suitable
+ * for use in libreboot. Currently tested: ThinkPad X200 (coreboot/libreboot)
+ */
+
+/*
+ * See docs/hcl/x200_remove_me.html for info plus links to datasheet (also linked below)
+ *
+ * Info about flash descriptor (read page 850 onwards):
+ * http://www.intel.co.uk/content/dam/doc/datasheet/io-controller-hub-9-datasheet.pdf
+ *
+ * Info about Gbe region (read whole datasheet):
+ * http://www.intel.co.uk/content/dam/doc/application-note/i-o-controller-hub-9m-82567lf-lm-v-nvm-map-appl-note.pdf
+ * https://communities.intel.com/community/wired/blog/2010/10/14/how-to-basic-eeprom-checksums
+ */
+
+#include "ich9deblob.h"
+
+int main(int argc, char *argv[])
+{
+ /*
+ * descriptor region. Will have an actual descriptor struct mapped to it (from the factory.rom dump)
+ * and then it will be modified (deblobbed) to remove the ME/AMT
+ */
+ char factoryDescriptorBuffer[DESCRIPTORREGIONSIZE];
+ struct DESCRIPTORREGIONRECORD factoryDescriptorStruct;
+ struct DESCRIPTORREGIONRECORD deblobbedDescriptorStruct;
+
+ /*
+ * gbe region. Well have actual gbe buffer mapped to it (from the factory.rom dump)
+ * and then it will be modified to correct the main region
+ */
+ char factoryGbeBuffer8k[GBEREGIONSIZE_8K];
+ struct GBEREGIONRECORD_8K factoryGbeStruct8k;
+ struct GBEREGIONRECORD_8K deblobbedGbeStruct8k;
+
+ /*
+ * Used to store the location of the Gbe
+ * region inside the factory.rom image.
+ */
+ unsigned int factoryGbeRegionStart;
+
+ /* names of the files that this utility will handle */
+ char* factoryRomFilename = "factory.rom"; /* user-supplied factory.bin dump (original firmware) */
+ char* deblobbedDescriptorFilename = "deblobbed_descriptor.bin"; /* descriptor+gbe: to be dd'd to beginning of a libreboot image */
+
+ /* Used when reading the factory.rom to extract descriptor/gbe regions */
+ unsigned int bufferLength;
+
+ /* For storing the size of the factory.rom dump in bytes */
+ unsigned int factoryRomSize;
+
+ /*
+ * ------------------------------------------------------------------
+ * Compatibility checks. This version of ich9deblob is not yet portable.
+ * ------------------------------------------------------------------
+ */
+
+ if (systemOrCompilerIncompatible(factoryDescriptorStruct, factoryGbeStruct8k)) return 1;
+ /* If true, fail with error message */
+
+ /*
+ * ------------------------------------------------------------------
+ * Extract the descriptor and gbe regions from the factory.rom dump
+ * ------------------------------------------------------------------
+ */
+ FILE* fileStream = NULL;
+ fileStream = fopen(factoryRomFilename, "rb"); /* open factory.rom */
+ if (NULL == fileStream)
+ {
+ printf("\nerror: could not open factory.rom\n");
+ return 1;
+ }
+ printf("\nfactory.rom opened successfully\n");
+
+ /*
+ * Get the descriptor region dump from the factory.rom
+ * (goes in factoryDescriptorBuffer variable)
+ */
+ bufferLength = fread(factoryDescriptorBuffer, sizeof(char), DESCRIPTORREGIONSIZE, fileStream);
+ if (DESCRIPTORREGIONSIZE != bufferLength) //
+ {
+ printf("\nerror: could not read descriptor from factory.rom (%i) bytes read\n", bufferLength);
+ return 1;
+ }
+ printf("\ndescriptor region read successfully\n");
+ /*
+ * copy descriptor buffer into descriptor struct memory
+ * factoryDescriptorStruct is an instance of a struct that actually
+ * defines the locations of all these variables in the descriptor,
+ * as defined in the datasheets. This allows us to map the extracted
+ * descriptor over the struct so that it can then be modified
+ * for libreboot's purpose
+ */
+ memcpy(&factoryDescriptorStruct, &factoryDescriptorBuffer, DESCRIPTORREGIONSIZE);
+ /*
+ * ^ the above is just for reference if needed. The modifications will be made here:
+ */
+ memcpy(&deblobbedDescriptorStruct, &factoryDescriptorBuffer, DESCRIPTORREGIONSIZE);
+
+ /*
+ * Get the gbe region dump from the factory.rom
+ */
+
+ /*
+ * get original GBe region location
+ * (it will be moved to the beginning of the flash, after the descriptor region)
+ * note for example, factoryGbeRegionStart is set to <<FLREGIONBITSHIFT of actual address (in C). this is how the addresses
+ * are stored in the descriptor.
+ */
+ factoryGbeRegionStart = factoryDescriptorStruct.regionSection.flReg3.BASE << FLREGIONBITSHIFT;
+
+ /*
+ * Set offset so that we can read the data from
+ * the gbe region
+ */
+ fseek(fileStream, factoryGbeRegionStart, SEEK_SET);
+ /* Read the gbe data from the factory.rom and put it in factoryGbeBuffer8k */
+ bufferLength = fread(factoryGbeBuffer8k, sizeof(char), GBEREGIONSIZE_8K, fileStream);
+ if (GBEREGIONSIZE_8K != bufferLength)
+ {
+ printf("\nerror: could not read GBe region from factory.rom (%i) bytes read\n", bufferLength);
+ return 1;
+ }
+ printf("\ngbe (8KiB) region read successfully\n");
+ /*
+ * copy gbe buffer into gbe struct memory
+ * factoryGbeStruct8k is an instance of a struct that actually
+ * defines the locations of all these variables in the gbe,
+ * as defined in the datasheets. This allows us to map the extracted
+ * gbe over the struct so that it can then be modified
+ * for libreboot's purpose
+ */
+ memcpy(&factoryGbeStruct8k, &factoryGbeBuffer8k, GBEREGIONSIZE_8K);
+ /*
+ * the original factoryGbeStruct8k is only reference. Changes go here:
+ */
+ memcpy(&deblobbedGbeStruct8k, &factoryGbeBuffer8k, GBEREGIONSIZE_8K);
+
+ /*
+ * Get size of ROM image
+ * This is needed for relocating the BIOS region (per descriptor)
+ */
+ fseek(fileStream, 0L, SEEK_END);
+ factoryRomSize = ftell(fileStream);
+
+ printf("\nfactory.rom size: [%i] bytes\n", factoryRomSize);
+
+ fclose(fileStream);
+
+ /*
+ * ------------------------------------------------------------------
+ * Modify the descriptor and gbe regions, ready to go in libreboot.rom
+ * ------------------------------------------------------------------
+ */
+
+ /*
+ * Disable the ME and Platform regions. Put Gbe at the beginning (after descriptor).
+ * Also, extend the BIOS region to fill the ROM image (after descriptor+gbe).
+ */
+ deblobbedDescriptorStruct = deblobbedDescriptorStructFromFactory(factoryDescriptorStruct, factoryRomSize);
+ /*
+ * Debugging: show region locations in the
+ * original descriptor and the modified one
+ */
+ printDescriptorRegionLocations(factoryDescriptorStruct, "Original");
+ printDescriptorRegionLocations(deblobbedDescriptorStruct, "Modified");
+
+ /*
+ * Modify the Gbe region (see function for details)
+ */
+ deblobbedGbeStruct8k = deblobbedGbeStructFromFactory(factoryGbeStruct8k);
+ /*
+ * Debugging: show difference between Gbe checksums in the
+ * original gbe and the modified one
+ */
+ printf("\n");
+ printGbeChecksumDataFromStruct8k(factoryGbeStruct8k, "Original");
+ printGbeChecksumDataFromStruct8k(deblobbedGbeStruct8k, "Modified");
+
+ /*
+ * ------------------------------------------------------------------
+ * Create the file with the modified descriptor and gbe inside
+ * ------------------------------------------------------------------
+ */
+
+ printf("\n");
+ if (notCreatedDescriptorGbeFile(deblobbedDescriptorStruct, deblobbedGbeStruct8k, deblobbedDescriptorFilename)) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/resources/utilities/ich9deblob/src/ich9deblob.h b/resources/utilities/ich9deblob/src/ich9deblob.h
new file mode 100644
index 00000000..a765bb5f
--- /dev/null
+++ b/resources/utilities/ich9deblob/src/ich9deblob.h
@@ -0,0 +1,37 @@
+/*
+ * ich9deblob.h
+ * This file is part of the ich9deblob utility from the libreboot project
+ *
+ * Purpose: header file for ich9deblob.c
+ *
+ * Copyright (C) 2014 Steve Shenton <sgsit@libreboot.org>
+ * Francis Rowe <info@gluglug.org.uk>
+ *
+ * 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 3 of the License, or
+ * (at your option) 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ICH9DEBLOB_H
+#define ICH9DEBLOB_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include "common/descriptor_gbe.h" /* common descriptor/gbe functions used by ich9deblob */
+#include "common/x86compatibility.h" /* system/compiler compatibility checks. This code is not portable. */
+#include "descriptor/descriptor.h" /* structs describing what's in the descriptor region */
+#include "gbe/gbe.h" /* structs describing what's in the gbe region */
+
+int main(int argc, char *argv[]);
+
+#endif