-
-
Notifications
You must be signed in to change notification settings - Fork 206
Add initial support for the ThinkPad T440p #1282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5cce937
e325976
96f0c5b
f079211
65be2c5
24d23ff
c23ed54
7a29db1
ed8c74e
9368404
7c32d4e
e6c34bd
144f9c1
1dc5d4e
5083ba3
3efec15
63eab71
e4a09e8
1dd9c26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -e | ||
|
|
||
| function usage() { | ||
| echo -n \ | ||
| "Usage: $(basename "$0") path_to_output_directory | ||
| Obtain mrc.bin from a Haswell Chromebook firmware image. | ||
| " | ||
| } | ||
|
|
||
| MRC_BIN_HASH="d368ba45096a3b5490ed27014e1f9004bc363434ffdce0c368c08a89c4746722" | ||
|
|
||
| if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then | ||
| if [[ "${1:-}" == "--help" ]]; then | ||
| usage | ||
| else | ||
| if [[ -z "${COREBOOT_DIR}" ]]; then | ||
| echo "ERROR: No COREBOOT_DIR variable defined." | ||
| exit 1 | ||
| fi | ||
|
|
||
| output_dir="$(realpath "${1:-./}")" | ||
|
|
||
| # Obtain mrc.bin from a Haswell Chromebook firmware image. | ||
| # https://doc.coreboot.org/northbridge/intel/haswell/mrc.bin.html#obtaining-mrc-bin | ||
| if [[ ! -f "${output_dir}/mrc.bin" ]]; then | ||
| pushd "${COREBOOT_DIR}" | ||
|
|
||
| make -C util/cbfstool | ||
| cd util/chromeos | ||
| ./crosfirmware.sh peppy | ||
| ../cbfstool/cbfstool coreboot-*.bin extract -f mrc.bin -n mrc.bin -r RO_SECTION | ||
|
|
||
| mv mrc.bin "${output_dir}/mrc.bin" | ||
|
|
||
| popd | ||
| fi | ||
|
|
||
| if ! echo "${MRC_BIN_HASH} ${output_dir}/mrc.bin" | sha256sum --check; then | ||
| echo "ERROR: SHA256 checksum for mrc.bin doesn't match." | ||
| exit 1 | ||
| fi | ||
| fi | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # T440p Blobs | ||
|
|
||
| - [Overview](#overview) | ||
| - [Using Your Own Blobs](#using-your-own-blobs) | ||
|
|
||
| ## Overview | ||
|
|
||
| Coreboot on the T440p requires the following binary blobs: | ||
|
|
||
| - `mrc.bin` - Consists of Intel’s Memory Reference Code (MRC) and [is used to initialize the DRAM](https://doc.coreboot.org/northbridge/intel/haswell/mrc.bin.html). | ||
| - `me.bin` - Consists of Intel’s Management Engine (ME), which we modify using [me_cleaner](https://github.com/corna/me_cleaner) to remove all but the modules which are necessary for the CPU to function. | ||
| - `gbe.bin` - Consists of hardware/software configuration data for the Gigabit Ethernet (GbE) controller. Intel publishes the data structure [here](https://web.archive.org/web/20230122164346/https://www.intel.com/content/dam/www/public/us/en/documents/design-guides/i-o-controller-hub-8-9-nvm-map-guide.pdf), and an [ImHex](https://github.com/WerWolv/ImHex) hex editor pattern is available [here](https://github.com/rbreslow/ImHex-Patterns/blob/rb/intel-ich8/patterns/intel/ich8_lan_nvm.hexpat). | ||
| - `ifd.bin` - Consists of the Intel Flash Descriptor (IFD). Intel publishes the data structure [here](https://web.archive.org/web/20221208011432/https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/io-controller-hub-8-datasheet.pdf), and an ImHex hex editor pattern is available [here](https://github.com/rbreslow/ImHex-Patterns/blob/rb/intel-ich8/patterns/intel/ich8_flash_descriptor.hexpat). | ||
|
|
||
| Heads supplies an IFD and GbE blob, which we extracted from a donor board. We changed the MAC address of the GbE blob to `00:de:ad:c0:ff:ee` using [nvmutil](https://libreboot.org/docs/install/nvmutil.html), to support anonymity and build reproducibility. | ||
|
|
||
| When building any T440p board variant with `make`, the build system will download a copy of the MRC and Intel ME. We extract `mrc.bin` from a Chromebook firmware image and `me.bin` from a Lenovo firmware update. | ||
|
|
||
| ## Using Your Own Blobs | ||
|
|
||
| You can compile Heads using the Intel ME, GbE, and and IFD blobs from your original ROM. | ||
|
|
||
| However, it's worth noting that our analysis showed [no tangible difference](https://github.com/osresearch/heads/pull/1282#issuecomment-1386292403) between the Intel ME from a donor board and Lenovo's website. Also, we found [no meaningful difference](https://github.com/osresearch/heads/pull/1282#issuecomment-1400634600) between the IFD and and GbE blobs extracted from two T440ps, asides from the LAN MAC address. | ||
|
|
||
| First, make sure you've built Heads at least once in order to download the Coreboot sources: | ||
|
|
||
| ```console | ||
| $ make BOARD=t440p-hotp-maximized | ||
| ``` | ||
|
|
||
| Then, supply the path to the Coreboot sources via the `COREBOOT_DIR` environment variable, and run the blob-extraction script: | ||
|
|
||
| ```console | ||
| $ export COREBOOT_DIR="./build/x86/coreboot-4.17/" | ||
| $ ./blobs/t440p/extract /path/to/original_rom.bin ./blobs/t440p | ||
| ``` | ||
|
|
||
| Now, you can rebuild Heads: | ||
|
|
||
| ```console | ||
| $ make BOARD=t440p-hotp-maximized | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -e | ||
|
|
||
| function usage() { | ||
| echo -n \ | ||
| "Usage: $(basename "$0") path_to_output_directory | ||
| Download Intel ME firmware from Lenovo, neutralize, and shrink. | ||
| " | ||
| } | ||
|
|
||
| ME_BIN_HASH="b7cf4c0cf514bbf279d9fddb12c34fca5c1c23e94b000c26275369b924ab9c25" | ||
|
|
||
| if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then | ||
| if [[ "${1:-}" == "--help" ]]; then | ||
| usage | ||
| else | ||
| if [[ -z "${COREBOOT_DIR}" ]]; then | ||
| echo "ERROR: No COREBOOT_DIR variable defined." | ||
| exit 1 | ||
| fi | ||
|
|
||
| output_dir="$(realpath "${1:-./}")" | ||
|
|
||
| if [[ ! -f "${output_dir}/me.bin" ]]; then | ||
| # Unpack Lenovo's Windows installer into a temporary directory and | ||
| # extract the Intel ME blob. | ||
| pushd "$(mktemp -d)" | ||
|
|
||
| curl -O https://download.lenovo.com/pccbbs/mobiles/glrg22ww.exe | ||
| innoextract glrg22ww.exe | ||
|
|
||
| mv app/ME9.1_5M_Production.bin "${COREBOOT_DIR}/util/me_cleaner" | ||
|
|
||
| popd | ||
|
|
||
| # Neutralize and shrink Intel ME. Note that this doesn't include | ||
| # --soft-disable to set the "ME Disable" or "ME Disable B" (e.g., | ||
| # High Assurance Program) bits, as they are defined within the Flash | ||
| # Descriptor. | ||
| # https://github.com/corna/me_cleaner/wiki/External-flashing#neutralize-and-shrink-intel-me-useful-only-for-coreboot | ||
| pushd "${COREBOOT_DIR}/util/me_cleaner" | ||
|
|
||
| python me_cleaner.py -r -t -O me_shrinked.bin ME9.1_5M_Production.bin | ||
|
|
||
| mv me_shrinked.bin "${output_dir}/me.bin" | ||
| rm ./*.bin | ||
|
|
||
| popd | ||
| fi | ||
|
|
||
| if ! echo "${ME_BIN_HASH} ${output_dir}/me.bin" | sha256sum --check; then | ||
| echo "ERROR: SHA256 checksum for me.bin doesn't match." | ||
| exit 1 | ||
| fi | ||
| fi | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -e | ||
|
|
||
| function usage() { | ||
| echo -n \ | ||
| "Usage: $(basename "$0") path_to_original_rom path_to_output_directory | ||
| Extract Intel firmware from the original ROM. | ||
| " | ||
| } | ||
|
|
||
| if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then | ||
| if [[ "${1:-}" == "--help" ]]; then | ||
| usage | ||
| else | ||
| if [[ -z "${COREBOOT_DIR}" ]]; then | ||
| echo "ERROR: No COREBOOT_DIR variable defined." | ||
| exit 1 | ||
| fi | ||
|
|
||
| original_rom="$(realpath "$1")" | ||
| output_dir="$(realpath "${2:-./}")" | ||
|
|
||
| # Neutralize Intel ME and resize the Intel Flash Descriptor (IFD) | ||
| # layout. | ||
| # https://github.com/corna/me_cleaner/wiki/External-flashing#neutralize-and-shrink-intel-me-useful-only-for-coreboot | ||
| pushd "${COREBOOT_DIR}/util/me_cleaner" | ||
|
|
||
| python me_cleaner.py -S -r -t -d -O out.bin -D ifd_shrinked.bin -M me_shrinked.bin "${original_rom}" | ||
|
|
||
| mv ifd_shrinked.bin "${output_dir}/ifd.bin" | ||
| mv me_shrinked.bin "${output_dir}/me.bin" | ||
| rm ./*.bin | ||
|
|
||
| popd | ||
|
|
||
| # Extract the Intel Gigabit Ethernet (GbE) firmware. | ||
| pushd "${COREBOOT_DIR}/util/ifdtool" | ||
|
|
||
| make | ||
| ./ifdtool -x "${original_rom}" | ||
|
|
||
| mv flashregion_3_gbe.bin "${output_dir}/gbe.bin" | ||
| rm ./*.bin | ||
|
|
||
| popd | ||
| fi | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Inherit the rest from the base T440p config. | ||
| include $(pwd)/boards/t440p-maximized/t440p-maximized.config | ||
|
|
||
| CONFIG_HOTPKEY=y | ||
|
|
||
| export CONFIG_BOARD_NAME="ThinkPad T440p-hotp-maximized" | ||
|
Comment on lines
+1
to
+6
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I took a novel approach here. I didn't want to duplicate any config. I realized since this is just a Makefile, we can use the |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # Configuration for a ThinkPad T440p. | ||
| CONFIG_COREBOOT_CONFIG=config/coreboot-t440p.config | ||
| # TODO: Make a ThinkPad-common Linux config file. | ||
| CONFIG_LINUX_CONFIG=config/linux-t440p.config | ||
|
|
||
| export CONFIG_COREBOOT=y | ||
| export CONFIG_COREBOOT_VERSION=4.17 | ||
| export CONFIG_LINUX_VERSION=5.10.5 | ||
|
|
||
| CONFIG_CRYPTSETUP2=y | ||
| CONFIG_FLASHROM=y | ||
| CONFIG_FLASHTOOLS=y | ||
| CONFIG_GPG2=y | ||
| CONFIG_KEXEC=y | ||
| CONFIG_UTIL_LINUX=y | ||
| CONFIG_LVM2=y | ||
| CONFIG_MBEDTLS=y | ||
| CONFIG_PCIUTILS=y | ||
| CONFIG_POPT=y | ||
| CONFIG_QRENCODE=y | ||
| CONFIG_TPMTOTP=y | ||
|
Comment on lines
+10
to
+21
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These magic values were copied from the X230 config. |
||
|
|
||
| # Dependencies for a graphical menu. Enable CONFIG_SLANG and CONFIG_NEWT instead | ||
| # for a console-based menu. | ||
| CONFIG_CAIRO=y | ||
| CONFIG_FBWHIPTAIL=y | ||
|
|
||
| CONFIG_LINUX_USB=y | ||
|
|
||
| export CONFIG_TPM=y | ||
| export CONFIG_BOOTSCRIPT=/bin/gui-init | ||
| export CONFIG_BOOT_REQ_HASH=n | ||
| export CONFIG_BOOT_REQ_ROLLBACK=n | ||
| export CONFIG_BOOT_DEV="/dev/sda1" | ||
| export CONFIG_BOARD_NAME="ThinkPad T440p-maximized" | ||
| export CONFIG_FLASHROM_OPTIONS="-p internal" | ||
|
|
||
| # Make the Coreboot build depend on the following 3rd party blobs: | ||
| $(build)/coreboot-$(CONFIG_COREBOOT_VERSION)/$(BOARD)/.build: \ | ||
| $(pwd)/blobs/haswell/mrc.bin $(pwd)/blobs/t440p/me.bin | ||
|
|
||
| $(pwd)/blobs/haswell/mrc.bin: | ||
| COREBOOT_DIR="$(build)/$(coreboot_base_dir)" \ | ||
| $(pwd)/blobs/haswell/obtain-mrc $(pwd)/blobs/haswell | ||
|
|
||
| $(pwd)/blobs/t440p/me.bin: | ||
| COREBOOT_DIR="$(build)/$(coreboot_base_dir)" \ | ||
| $(pwd)/blobs/t440p/download-clean-me $(pwd)/blobs/t440p | ||
|
Comment on lines
+38
to
+48
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
targets : prerequisites
recipe
…Where a "target" is a path to a file that needs to exist. So, we create two targets for Since a target is a path to a file, if the blobs already exist (e.g., user-supplied blobs), See: https://www.gnu.org/software/make/manual/make.html#Rule-Syntax |
||
|
|
||
| # Haswell boards have an 8 MiB and 4 MiB SPI flash chip. So, we split the | ||
| # Coreboot ROM into two files to flash one on each chip. | ||
| all: $(board_build)/heads-$(BOARD)-$(HEADS_GIT_VERSION)-bottom.rom | ||
| $(board_build)/heads-$(BOARD)-$(HEADS_GIT_VERSION)-bottom.rom: $(board_build)/$(CB_OUTPUT_FILE) | ||
| $(call do,DD 8MB,$@,dd of=$@ if=$< bs=65536 count=128 skip=0 status=none) | ||
| @sha256sum $@ | tee -a "$(HASHES)" | ||
|
|
||
| all: $(board_build)/heads-$(BOARD)-$(HEADS_GIT_VERSION)-top.rom | ||
| $(board_build)/heads-$(BOARD)-$(HEADS_GIT_VERSION)-top.rom: $(board_build)/$(CB_OUTPUT_FILE) | ||
| $(call do,DD 4MB,$@,dd of=$@ if=$< bs=65536 count=64 skip=128 status=none) | ||
| @sha256sum $@ | tee -a "$(HASHES)" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # CONFIG_USE_BLOBS is not set | ||
| CONFIG_VENDOR_LENOVO=y | ||
| CONFIG_NO_POST=y | ||
| CONFIG_CBFS_SIZE=0x800000 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This value for the CBFS size is arbitrary. Originally, I had totaled the size of all binary blobs, subtracted that from the T440p's ROM size (12 MiB), and used the remaining space as the CBFS size (~11.68 MiB). However, this caused very long RAM initialization times (courtesy of So, I picked a size I expected our Linux payload to fit into that was a power of 2 that I also expected would leave enough space in the ROM for the IFD, ME, GbE, and Coreboot. Now, it takes less than a second for RAM initialization after flashing/first boot (anecdotally, it seems the MRC needs to be "trained?").
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have the impression that your initial CBFS_SIZE value might have been good, but not matching ifd defined region). Ifd needs to be modified to take output of neutered ME size while ME region needs to be reduced under ifd, and the freed space added to BIOS region there. That BIOS size would become the size of cbfs region under coreboot config from memory, but will have to find traces again which I was unsuccessful finding last time. Will try to find that information back since it needs to be part of the porting guide as well.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ah, okay, this makes sense. I ran me_cleaner on my original ROM again and then used $ python me_cleaner.py -S -r -t -d -O out.bin -D ifd_shrinked.bin -M me_shrinked.bin ~/projects/t440p/t440p_original.bin
. . .
$ ./ifdtool -f layout.txt ifd_shrinked.bin && cat layout.txt
00000000:00000fff fd
00021000:00bfffff bios
00003000:00020fff me
00001000:00002fff gbePutting this into a notepad (using Soulver), I determined the size of each region and that there is 1 byte of padding between each region: So maybe
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rbreslow I finally joined coreboot channel and posted my question directly to them here: https://matrix.to/#/!BZxDFuoBnMKnzVZwEp:libera.chat/$N_Nh4qJeU9gquoE9tzjeERYzsxgYB6j79uB6uvnoPdM?via=libera.chat&via=matrix.org&via=foss.wtf
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
icon on coreboot channel answered. Excerpt:
I replied:
Then icon replied:
nic3-14159 added:
@rbreslow Can you adjust the calculations and test with new CBFS? Might be a limitation of the MRC blob on which we might need to accept caching time (and document properly under board config as current limitation)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tlaurion Here are my
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Basically, the right calculation is taking output of ifdtool -f layout.txt path/to/ifd_output_from_me_cleaner_on_fullrom_backup.rom and parsing the BIOS region, substracting end address to begin address. @rbreslow Seems like xx30 and xx20 might have been off all along. Redoing. |
||
| CONFIG_IFD_BIN_PATH="@BLOB_DIR@/t440p/ifd.bin" | ||
| CONFIG_ME_BIN_PATH="@BLOB_DIR@/t440p/me.bin" | ||
| CONFIG_GBE_BIN_PATH="@BLOB_DIR@/t440p/gbe.bin" | ||
| CONFIG_HAVE_IFD_BIN=y | ||
| CONFIG_BOARD_LENOVO_THINKPAD_T440P=y | ||
| CONFIG_LINUX_COMMAND_LINE="intel_iommu=igfx_off" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without this, neither Qubes OS nor the Qubes OS installer would start. Presumably, because we're "kexecing" from an already running kernel, we need this set at the Coreboot level? Testing revealed that including See:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly. Otherwise the iommu is configured incorrectly since first kernel boot would try to isolate Intel iommu and the kexec'ed kernel would not be able set differently. Coreboot defined kernel option defines Heads behavior. |
||
| CONFIG_TPM_MEASURED_BOOT=y | ||
| CONFIG_HAVE_MRC=y | ||
| CONFIG_MRC_FILE="@BLOB_DIR@/haswell/mrc.bin" | ||
| CONFIG_HAVE_ME_BIN=y | ||
| CONFIG_HAVE_GBE_BIN=y | ||
| CONFIG_PAYLOAD_LINUX=y | ||
| CONFIG_PAYLOAD_FILE="@BOARD_BUILD_DIR@/bzImage" | ||
| CONFIG_LINUX_INITRD="@BOARD_BUILD_DIR@/initrd.cpio.xz" | ||

Uh oh!
There was an error while loading. Please reload this page.