From a8b13d23f29a08026eaa308b8b09be7e9d1ff5a6 Mon Sep 17 00:00:00 2001 From: Francis Rowe Date: Thu, 25 Dec 2014 16:25:49 -0500 Subject: ich9deblob: moved src to src/, .o files to obj/ --- (limited to 'resources/utilities/ich9deblob/src') 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 0000000..fcb80d0 --- /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 + * Francis Rowe + * + * 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 . + */ + +#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 0000000..cc0cc42 --- /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 + * Francis Rowe + * + * 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 . + */ + +#ifndef COMMON_DESCRIPTOR_GBE_H +#define COMMON_DESCRIPTOR_GBE_H + +#include +#include + +#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 0000000..505a37d --- /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 + * Francis Rowe + * + * 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 . + */ + +#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 0000000..d9d5bdb --- /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 + * Francis Rowe + * + * 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 . + */ + +#ifndef X86COMPATIBILITY_H +#define X86COMPATIBILITY_H + +#include +#include + +#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 0000000..aa3d84e --- /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 + * Francis Rowe + * + * 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 . + */ + +/* + * 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) - 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) 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 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 0000000..863b894 --- /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 + * Francis Rowe + * + * 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 . + */ + +/* + * 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 +#include + +/* 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 0000000..9eee828 --- /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 + * Francis Rowe + * + * 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 . + */ + +/* + * 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 0000000..bfcc002 --- /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 + * Francis Rowe + * + * 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 . + */ + +/* + * 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 +#include + +/* 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 0000000..ee549d2 --- /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 + * Francis Rowe + * + * 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 . + */ + +/* 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 < + * Francis Rowe + * + * 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 . + */ + +#ifndef ICH9DEBLOB_H +#define ICH9DEBLOB_H + +#include +#include + +#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 -- cgit v0.9.1