Skip to content
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

Add initial support for the ThinkPad T440p #1282

Merged
merged 19 commits into from Feb 28, 2023

Conversation

rbreslow
Copy link
Contributor

@rbreslow rbreslow commented Jan 17, 2023

Overview

I made the following changes to support the ThinkPad T440p:

  • Add script for obtaining Haswell mrc.bin blob.
  • Add script for extracting blobs from an original T440p ROM.
  • Add Coreboot and Linux configs for the T440p.
  • Add Heads configs for the T440p (maximized/hotp-maximized).
  • Add script for obtaining a T440p me.bin blob from Lenovo's website.
  • Add ifd.bin and gbe.bin blobs extracted from my T440p.
  • Build everything on CircleCI.

I did not perform any research into T440p support that doesn't involve external flashing. As such, I only created and tested maximized and hotp-maximized Heads configurations.

I'd like to split the following into follow-up issues/tasks:

  • Write a flashing guide for the T440p.
  • Add CI support for the T440p. This will involve figuring out how to provide CI generic ifd.bin, me.bin, and gbe.bin blobs.
  • Cache the mrc.bin, to avoid excess load on Google's servers, and ensure we can retrieve it from the Internet Archive if the original source ever disappears (e.g., Libreboot). Perhaps we contribute this as a script to Coreboot?
  • Investigate ~8 second selfboot jump Coreboot stage. About ~5 seconds longer than @tlaurion's X230. With no immediate difference in payload size.

Resolves #1133

Testing Instructions

Requirements

I assume you already have all the system dependencies (e.g., gnat, pkgconfig, etc.) required to build Heads.

I purchased the following to assemble an SPI flasher:

I set up an anti-static ESD mat/wristband at my workstation (connected to ground). And I wore nitrile gloves while performing all this work.

There are a bunch of warnings to avoid the CH341A programmer because the most commonly available one has a defect where it outputs 5.5V instead of 3.3V, which is unfortunate because it seemed like the most straight forward programmer to use.

However, I found a CH341A-variant with a physical jumper to change the voltage from 5.5V to 3.3V. So, I decided to purchase that and follow Chuck Nemeth's instructions to verify that it was outputting the correct voltage.

I tested GND to all the pins, got ~3.3V, so we're good to go.

testing_33v

I found the following resources helpful when assembling the SPI flasher:

Some miscellaneous notes:

  • /CS on the flash chip corresponds to CS0 on the CH341A.
  • You don't connect anything to the /WP or /HOLD pins.
  • flashrom source code describes how to connect the remaining pins: https://github.com/flashrom/flashrom/blob/9a152b8191c5bd3b0a88b29c6b267030da77b770/ch341a_spi.c#L277-L289.
  • I did the following when connecting to the flash chip:
    1. Make sure VCC (power supply) is disconnected from the SOIC-8 clip.
    2. Connect CH341A to USB.
    3. Connect SOIC-8 clip to flash chip.
    4. Now, attach VCC to the SOIC-8 clip.
    5. Follow in-reverse when disconnecting.

Building Heads and Flashing

To access the flash chips on the T440p, I followed the "1160 Base cover assembly" instructions on page 79 of the hardware maintenance manual. Not everything here is necessary, there's some nuance required in removing the assembly, and I broke the speaker cable when disassembling my machine. I will expand on this in a future flashing guide.

t440p_board

With everything opened up, the chips are exposed. I used flashrom to extract the firmware from both flash chips:

$ time sudo flashrom --programmer ch341a_spi -r backup_4096kb_1.bin
flashrom v1.2 on Linux 5.15.79 (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Winbond flash chip "W25Q32.V" (4096 kB, SPI) on ch341a_spi.
Reading flash... done.
sudo flashrom --programmer ch341a_spi -r backup_4096kb_1.bin  1.36s user 3.06s system 6% cpu 1:07.78 total
$ time sudo flashrom --programmer ch341a_spi -r backup_4096kb_2.bin
flashrom v1.2 on Linux 5.15.79 (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Winbond flash chip "W25Q32.V" (4096 kB, SPI) on ch341a_spi.
Reading flash... done.
sudo flashrom --programmer ch341a_spi -r backup_4096kb_2.bin  1.55s user 3.42s system 7% cpu 1:07.78 total
$ time sudo flashrom --programmer ch341a_spi -r backup_8192kb_1.bin
flashrom v1.2 on Linux 5.15.79 (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) on ch341a_spi.
Reading flash... done.
sudo flashrom --programmer ch341a_spi -r backup_8192kb_1.bin  2.68s user 5.82s system 6% cpu 2:15.38 total
$ time sudo flashrom --programmer ch341a_spi -r backup_8192kb_2.bin
flashrom v1.2 on Linux 5.15.79 (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) on ch341a_spi.
Reading flash... done.
sudo flashrom --programmer ch341a_spi -r backup_8192kb_2.bin  2.63s user 5.74s system 6% cpu 2:15.36 total
$ sha256sum *.bin
8321ff0d174ef00b8ae7dd2e026d2b4ec8a1cc61e1b8cf002818cba1eedc4fa2  backup_4096kb_1.bin
8321ff0d174ef00b8ae7dd2e026d2b4ec8a1cc61e1b8cf002818cba1eedc4fa2  backup_4096kb_2.bin
b791490eb03fc03dba8db28a619b170f4aca5dea77f7844b10e8a4d138847b2f  backup_8192kb_1.bin
b791490eb03fc03dba8db28a619b170f4aca5dea77f7844b10e8a4d138847b2f  backup_8192kb_2.bin

Then, I combined the contents of both chips to reproduce the original ROM:

$ cat backup_8192kb_1.bin backup_4096kb_1.bin > t440p_original.bin

Next, I built the project. This will fail, as we haven't supplied any binary blobs. However, we need it to install dependencies, like Coreboot:

$ make BOARD=t440p-hotp-maximized

Update: These steps were accurate when I created the pull request, but the scripts below have changed slightly after 9368404. Now, you only need to run make once if you want to use the Heads-supplied blobs.

Now, we can extract the binary blobs from the original ROM:

$ ./blobs/t440p/export-blobs ~/projects/t440p/t440p_original.bin
~/projects/heads/build/x86/coreboot-4.17 ~/projects/heads
Full image detected
The ME/TXE region goes from 0x3000 to 0x500000
Found FPT header at 0x3010
Found 28 partition(s)
Found FTPR header: FTPR partition spans from 0x160000 to 0x210000
ME/TXE firmware version 9.1.45.3000
Public key match: Intel ME, firmware versions 9.0.x.x, 9.1.x.x
The AltMeDisable bit is NOT SET
Reading partitions list...
 PSVN (0x00000bc0 - 0x000000c00, 0x00000040 total bytes): removed
 FOVD (0x00000c00 - 0x000001000, 0x00000400 total bytes): removed
 MDES (0x00001000 - 0x000002000, 0x00001000 total bytes): removed
 FCRS (0x00002000 - 0x000003000, 0x00001000 total bytes): removed
 EFFS (0x00003000 - 0x0000df000, 0x000dc000 total bytes): removed
 BIAL (NVRAM partition, no data, 0x0000add3 total bytes): nothing to remove
 BIEL (NVRAM partition, no data, 0x00003522 total bytes): nothing to remove
 BIIS (NVRAM partition, no data, 0x00036000 total bytes): nothing to remove
 NVCL (NVRAM partition, no data, 0x000069c9 total bytes): nothing to remove
 NVCM (NVRAM partition, no data, 0x0000439b total bytes): nothing to remove
 NVCP (NVRAM partition, no data, 0x0000a3c0 total bytes): nothing to remove
 NVHM (NVRAM partition, no data, 0x00000058 total bytes): nothing to remove
 NVJC (NVRAM partition, no data, 0x00003da0 total bytes): nothing to remove
 NVKR (NVRAM partition, no data, 0x00005fb3 total bytes): nothing to remove
 NVNF (NVRAM partition, no data, 0x0000175f total bytes): nothing to remove
 NVOS (NVRAM partition, no data, 0x0003a34b total bytes): nothing to remove
 NVSH (NVRAM partition, no data, 0x000022c0 total bytes): nothing to remove
 NVSM (NVRAM partition, no data, 0x00001de8 total bytes): nothing to remove
 NVTD (NVRAM partition, no data, 0x00001feb total bytes): nothing to remove
 NVUK (NVRAM partition, no data, 0x00008940 total bytes): nothing to remove
 PLDM (NVRAM partition, no data, 0x000043c5 total bytes): nothing to remove
 TMNN (NVRAM partition, no data, 0x000001a6 total bytes): nothing to remove
 GLUT (0x000df000 - 0x0000e8000, 0x00009000 total bytes): removed
 LOCL (0x000e8000 - 0x0000ec000, 0x00004000 total bytes): removed
 WCOD (0x000ec000 - 0x000160000, 0x00074000 total bytes): removed
 FTPR (0x00160000 - 0x000210000, 0x000b0000 total bytes): NOT removed
 NFTP (0x00210000 - 0x00048a000, 0x0027a000 total bytes): removed
 MDMV (0x0048a000 - 0x0004ca000, 0x00040000 total bytes): removed
Removing partition entries in FPT...
Removing EFFS presence flag...
Correcting checksum (0xda)...
Reading FTPR modules list...
 UPDATE           (LZMA   , 0x1c6487 - 0x1c66b1       ): removed
 ROMP             (Huffman, fragmented data, ~1 KiB   ): NOT removed, essential
 BUP              (Huffman, fragmented data, ~70 KiB  ): NOT removed, essential
 KERNEL           (Huffman, fragmented data, ~226 KiB ): removed
 POLICY           (Huffman, fragmented data, ~99 KiB  ): removed
 ClsPriv          (LZMA   , 0x1c66b1 - 0x1c6a8a       ): removed
 SESSMGR          (LZMA   , 0x1c6a8a - 0x1d2413       ): removed
 SESSMGR_PRIV     (LZMA   , 0x1d2413 - 0x1d7d03       ): removed
 HOSTCOMM         (LZMA   , 0x1d7d03 - 0x1e0035       ): removed
 TDT              (LZMA   , 0x1e0035 - 0x1e53fa       ): removed
 FPF              (LZMA   , 0x1e53fa - 0x1e6ef9       ): removed
Relocating FTPR from 0x160000 - 0x210000 to 0x1740 - 0xb1740...
 Adjusting FPT entry...
 Adjusting LUT start offset...
 Adjusting Huffman start offset...
 Adjusting chunks offsets...
 Moving data...
The ME minimum size should be 122880 bytes (0x1e000 bytes)
The ME region can be reduced up to:
 00003000:00020fff me
Setting the AltMeDisable bit in PCHSTRP10 to disable Intel ME...
Removing ME/TXE R/W access to the other flash regions...
Extracting the descriptor to "ifd_shrinked.bin"...
Modifying the regions of the extracted descriptor...
 00003000:004fffff me   --> 00003000:00020fff me
 00500000:00bfffff bios --> 00021000:00bfffff bios
Extracting and truncating the ME image to "me_shrinked.bin"...
Checking the FTPR RSA signature of the extracted ME image... VALID
Checking the FTPR RSA signature... VALID
Done! Good luck!
cc -O2 -g -Wall -Wextra -Wmissing-prototypes -Werror -I../../src/commonlib/include -I../../src/commonlib/bsd/include -I../../util/cbfstool/flashmap -include ../../src/commonlib/bsd/include/commonlib/bsd/compiler.h -D_DEFAULT_SOURCE   -c -o ../ifdtool/ifdtool.o ../../util/ifdtool/ifdtool.c
cc -O2 -g -Wall -Wextra -Wmissing-prototypes -Werror -I../../src/commonlib/include -I../../src/commonlib/bsd/include -I../../util/cbfstool/flashmap -include ../../src/commonlib/bsd/include/commonlib/bsd/compiler.h -D_DEFAULT_SOURCE   -c -o ../ifdtool/fmap.o ../../util/cbfstool/flashmap/fmap.c
cc -O2 -g -Wall -Wextra -Wmissing-prototypes -Werror -I../../src/commonlib/include -I../../src/commonlib/bsd/include -I../../util/cbfstool/flashmap -include ../../src/commonlib/bsd/include/commonlib/bsd/compiler.h -D_DEFAULT_SOURCE   -c -o ../ifdtool/kv_pair.o ../../util/cbfstool/flashmap/kv_pair.c
cc -O2 -g -Wall -Wextra -Wmissing-prototypes -Werror -I../../src/commonlib/include -I../../src/commonlib/bsd/include -I../../util/cbfstool/flashmap -include ../../src/commonlib/bsd/include/commonlib/bsd/compiler.h -D_DEFAULT_SOURCE   -c -o ../ifdtool/valstr.o ../../util/cbfstool/flashmap/valstr.c
printf "   IFDTOOL\n"
   IFDTOOL
cc ../ifdtool/ifdtool.o ../ifdtool/fmap.o ../ifdtool/kv_pair.o ../ifdtool/valstr.o -o ../ifdtool/ifdtool
File /home/user/projects/t440p/t440p_original.bin is 12582912 bytes
  Flash Region 0 (Flash Descriptor): 00000000 - 00000fff
  Flash Region 1 (BIOS): 00500000 - 00bfffff
  Flash Region 2 (Intel ME): 00003000 - 004fffff
  Flash Region 3 (GbE): 00001000 - 00002fff
  Flash Region 4 (Platform Data): 00fff000 - 00000fff (unused)
~/projects/heads

And obtain the Haswell mrc.bin blob:

$ ./blobs/haswell/obtain-mrc
~/projects/heads/build/x86/coreboot-4.17 ~/projects/heads
make: Entering directory '/home/user/projects/heads/build/x86/coreboot-4.17/util/cbfstool'
make: Leaving directory '/home/user/projects/heads/build/x86/coreboot-4.17/util/cbfstool'
Downloading recovery image inventory...
Processing board peppy
Downloading recovery image
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  617M  100  617M    0     0  2357k      0  0:04:28  0:04:28 --:--:-- 1915k
Decompressing recovery image
Extracting ROOT-A partition
Extracting chromeos-firmwareupdate
Extracting coreboot image
Extracted coreboot-Google_Peppy.4389.89.0.bin
Found file mrc.bin at 0x18ffc0, type spd, compressed 190180, size 190180
mrc.bin: OK
~/projects/heads

We can compile the project again:

$ make BOARD=t440p-hotp-maximized
. . .
# Use coreboot.rom, because custom output files might not be processed by cbfstool
"/home/user/projects/heads/build/x86/coreboot-4.17/t440p-hotp-maximized/cbfstool" "/home/user/projects/heads/build/x86/coreboot-4.17/t440p-hotp-maximized/coreboot.rom" print
FMAP REGION: COREBOOT
Name                           Offset     Type           Size   Comp
cbfs_master_header             0x0        cbfs header        32 none
fallback/romstage              0x80       stage           42568 none
cpu_microcode_blob.bin         0xa780     microcode       46080 none
intel_fit                      0x15bc0    intel_fit          80 none
fallback/ramstage              0x15c40    stage          120927 LZMA (263548 decompressed)
config                         0x33500    raw              1084 none
revision                       0x33980    raw               704 none
build_info                     0x33c80    raw               102 none
fallback/dsdt.aml              0x33d40    raw             13907 none
vbt.bin                        0x373c0    raw              1410 LZMA (4608 decompressed)
cmos_layout.bin                0x37980    cmos_layout      1296 none
fallback/postcar               0x37ec0    stage           27304 none
fallback/payload               0x3e9c0    simple elf    7190508 none
(empty)                        0x71a200   null           482212 none
mrc.bin                        0x78fdc0   mrc            190180 none
(empty)                        0x7be500   null           178212 none
bootblock                      0x7e9d40   bootblock       24704 none
2023-01-16 18:37:37-05:00 INSTALL   build/x86/coreboot-4.17/t440p-hotp-maximized/coreboot.rom => build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized-.rom
06de42bf69ed17fa4307fc859b50195dec8d888191720bb0488b139dc72d778d  build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized-.rom
2023-01-16 18:37:37-05:00 DD 8MB build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized--bottom.rom
86e60008cc8660f12fd0da220db8a164635c43ba28f947d4194980f66db8ae0b  /home/user/projects/heads/build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized--bottom.rom
2023-01-16 18:37:37-05:00 DD 4MB build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized--top.rom
bff7f82e7ddafce070e0e6b860d5bc962021c491d602c31da7615b7ee6628654  /home/user/projects/heads/build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized--top.rom
06de42bf69ed17fa4307fc859b50195dec8d888191720bb0488b139dc72d778d  /home/user/projects/heads/build/x86/t440p-hotp-maximized/heads-t440p-hotp-maximized-.rom

And finally, we can flash the T440p:

$ sudo flashrom --programmer ch341a_spi -w heads-t440p--top.rom
. . .
$ sudo flashrom --programmer ch341a_spi -w heads-t440p--bottom.rom
. . .

I tested both the htop-maximized and maximized variants:

t440p_hotp_maximized

librem_key

t440p_maximized

And verified both WiFi and Intel GbE networking work on a Qubes OS install:

tor_connection_check

Some thoughts to wrap up:

  • I was iterating quickly and could reflash many times via the Heads GUI. Super slick.
  • I had trouble after reflashing because it wasn't obvious how to reseal the disk encryption key in the TPM. For posterity: You have to navigate Options -->Boot Options -->Show OS boot menuQubes,_with_Xen_hypervisorMake default and then Heads will prompt Do you want to reseal a disk key to the TPM [y/N]:.
  • It's not obvious how to store your private keys on a YubiKey. OEM Factory Reset / Re-Ownership --> is NOT your friend. Instead, you want to go under GPG Options -->Add GPG key to running BIOS and reflash, which will prompt you to insert a USB drive containing your GPG public key. Then, the next time you select Update checksums and sign all files in /boot, Heads will prompt you to insert your GPG smartcard.

.gitattributes Outdated Show resolved Hide resolved
Comment on lines 5 to 10
function usage() {
echo -n \
"Usage: $(basename "$0") path_to_original_rom
Extract Intel firmware from the original ROM.
"
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided not to copy or iterate on the existing extract.sh script. Instead, I wanted to make something tailored for the T440p, focusing on improved readability.

Down the road, I think we should consolidate all the blob extraction tooling so that we don't need to replicate per board.

Comment on lines +1 to +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"
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 include directive.

Comment on lines 3 to 4
# TODO: Make a ThinkPad-common Linux config file.
CONFIG_LINUX_CONFIG=config/linux-librem_common.config
Copy link
Contributor Author

@rbreslow rbreslow Jan 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the linux-librem_common.config Linux config as it was the only one based on Linux 5.10.x. Unfortunately, the configs for the X230 didn't work.

Are you OK with merging this as-is? I don't like that it's pointing to a Librem config. But I also don't want to duplicate that file just for the T440p.

In the future, I think that we could benefit from a common Linux config with board-specific overrides.

Comment on lines +10 to +21
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These magic values were copied from the X230 config.

# CONFIG_USE_BLOBS is not set
CONFIG_VENDOR_LENOVO=y
CONFIG_NO_POST=y
CONFIG_CBFS_SIZE=0x800000
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 cbmem -t). And, an anecdote in https://groups.google.com/a/chromium.org/g/chromium-os-reviews/c/lUqRrGUoEBY/m/ka7L1f2BS8gJ suggested that this value needs to be a power of 2.

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?").

Copy link
Collaborator

@tlaurion tlaurion Jan 17, 2023

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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).

Ah, okay, this makes sense. I ran me_cleaner on my original ROM again and then used ifdtool to dump the IFD regions:

$ 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 gbe

Putting this into a notepad (using Soulver), I determined the size of each region and that there is 1 byte of padding between each region:

cbfs_size_math

So maybe 0xBDEFFF is the maximum CBFS size? I will recompile, flash, and see. It would be cool if we could automate this math.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: 0xBDEFFF did not work. RAM initialization times are back up. ☹️.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The 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

icon on coreboot channel answered. Excerpt:

icon:
it's not end - start but end - start + 1
but that's not why it's slowing down. I assume with the bigger size, not everything in CBFS can be cached
there's CAR (cache as RAM) at 0xff7c0000..0xff7effff. this is used to store data before the DRAM is up
the BIOS region is mapped directly below 4G (0x100000000). so making CBFS too big, it could even conflict with CAR
I don't think this can be changed without also changing the MRC blob
so the best option is really to set CBFS_SIZE to 8MiB
one could still make the rest of the BIOS region available with a custom FMAP. only not as part of CBFS

I replied:

Interesting. Has no impact on ivy/sandy which extends cbfs region to reuse all liberated space from ME (11.5mb for heads maximized boards). But yet again, native ram init there.
Misalignments increased boot time in the past, but those were linked to tpm measurements problems (increasing boot time by 50 seconds, but also on older versions of coreboot).

Then icon replied:

yes, CAR is in 0xfefe0000..0xfefeffff for SNB
that's DCACHE_RAM_BASE/_SIZE in Kconfig btw.
oh, actually it's bigger

nic3-14159 added:

Side note, IIRC the coreboot build system rounds CBFS_SIZE down to 64KiB boundaries


@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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tlaurion Here are my cbmem logs from the CBFS_SIZE set 0xBDEFFF: https://gist.github.com/rbreslow/50b45e538437dd10f9e2bf51abd260de. What size would you like me to try now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So maybe 0xBDEFFF is the maximum CBFS size? I will recompile, flash, and see. It would be cool if we could automate this math.

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_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"
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 intel_iommu=igfx_off in the CONFIG_BOOT_KERNEL_ADD board config option did nothing. And, the Qubes OS default boot option already contains intel_iommu=igfx_off.

See:

Copy link
Collaborator

Choose a reason for hiding this comment

The 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.

modules/hotp-verification Outdated Show resolved Hide resolved
modules/musl-cross Outdated Show resolved Hide resolved
@tlaurion
Copy link
Collaborator

@rbreslow First comment: awesome contribution!!!!

In the spirit of other maximimized boards, I would like to collaborate into making this board download ME and dump it under haswell blob dir like the other boards are doing it from Lenovo latest bios available prior of merge.

ifd can probably be borrowed from libreboot, while I also suppose nvramutil from libreboot is able to generate gbe.bin and also drop it under haswell blob as a default with DE:AD:C0:FF:EE, if not extracted by user from backups as part of a export/extract script. (Not sure how me and gbe are injected in ROM with first look from coreboot config but might have overlooked.

The idea there is to deliver all this working when adding a board if blobs are needed, otherwise turning this in a maintenance nightmare.

As for yournlinux config being based in Librem, this might work as of now, but the config is tailored for those boards with modules for nvme for example.

If you can take a look at x230 blob download script, this would need to be duplicated to download and extract ME from Lenovo. If we have that working with gbe.bin mrc.bin me.bin in place, we would be able to add the board into CircleCI. If you flash that ROM and it works for you, then merging it would be tested working and mergeable.

Makes sense?

Then next step would be to find magic number for CBFS, since 8mb seems really small to fit librem kernel and all the other stuff, which would probably fail really soon to build and without having it under CI we would just not notice.

After that, main benefit for that board would be to have TXT variants for each boards, so that ACM blobs are also included and enabling DRTM which a lot of people are waiting for, which would make the t440p as a first working DRTM enabled platform.

I'm interested into making those go forward sonic any help is needed, I will jump in.

Awesome work!
Will review in more details this week and might propose a PR against your branch to coauthor other needed part.

Note the ifd.bin cannot be generated as of today as opposed to gbe.bin, so normally those files come from "dead" boards. I can swear from memory that I have seen a t440p ifd over libreboot tree. And I'm pretty sure I documented how to modify that ifd to have its regions match moved me region to add frees space into BIOS region into PR that lead into first maximized boards being merged upstream. Will come back to you with that in next coming days as well.

We want to get away of legacy board requiring users to extract blobs from backups, while an extract script is always provided so users can choose for themselves.

Also note that t440p instructions should point to latest Lenovo bios update available to update EC prior of initial external flashing as well, currently missing.

Awesome pointer for disassembly and flashing. Have not checked which flash chips are in the t440p, where the ones present under xx20/xx30 are really resilient to higher voltage. Better warned then sorry, and LC ch341 variant are safer, I agree. But using personally a black ch341 and having flashed hundred of x230 laptops myself, if not external power source are connected, I only have 3 bricks resulting of flashing..... Because I forgot to disconnect battery/AC adapter, not because of a 5v flasher. Again, better safe then sorry.

Yes. Mrc trained memory is saved back to SPI.

Thanks again for this contribution!

@tlaurion
Copy link
Collaborator

tlaurion commented Jan 17, 2023

@rbreslow :

For ME downloader+cleaner:

So basically blobs/xx30/download_clean_me.sh could be adapted for blobs/haswell/download_clean_me.sh:

user@heads-tests:/tmp/t440p$ wget https://download.lenovo.com/pccbbs/mobiles/glrg22ww.exe
--2023-01-16 22:35:12--  https://download.lenovo.com/pccbbs/mobiles/glrg22ww.exe
Resolving download.lenovo.com (download.lenovo.com)... 23.202.200.85
Connecting to download.lenovo.com (download.lenovo.com)|23.202.200.85|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5388640 (5.1M) [application/octet-stream]
Saving to: ‘glrg22ww.exe’

glrg22ww.exe                          100%[=======================================================================>]   5.14M  3.68MB/s    in 1.4s    

2023-01-16 22:35:14 (3.68 MB/s) - ‘glrg22ww.exe’ saved [5388640/5388640]

user@heads-tests:/tmp/t440p$ innoextract glrg22ww.exe 
Extracting "Intel Management Engine 9.1 Firmware for Windows 7/8.1/10" - setup data version 5.4.2
 - "app/FwDetect.exe"
 - "app/FwUpdate.exe"
 - "app/FWUpdLcl.exe"
 - "app/FWUpdLcl64.exe"
 - "app/Idrvdll.dll"
 - "app/ME9.1_5M_Production.bin"
 - "app/MEInfoWin.exe"
 - "app/MEUpdate.CMD"
 - "app/Pmxdll.dll"
 - "app/SLA_TOOLS.pdf"
Done.
user@heads-tests:/tmp/t440p$ ~/heads/blobs/xx30/me_cleaner.py -r -t -O ./me.bin app/ME9.1_5M_Production.bin
ME/TXE image detected
Found FPT header at 0x10
Found 28 partition(s)
Found FTPR header: FTPR partition spans from 0x160000 to 0x210000
ME/TXE firmware version 9.1.45.3000 (generation 2)
Public key match: Intel ME, firmware versions 9.0.x.x, 9.1.x.x
Reading partitions list...
 PSVN (0x00000bc0 - 0x000000c00, 0x00000040 total bytes): removed
 FOVD (0x00000c00 - 0x000001000, 0x00000400 total bytes): removed
 MDES (0x00001000 - 0x000002000, 0x00001000 total bytes): removed
 FCRS (0x00002000 - 0x000003000, 0x00001000 total bytes): removed
 EFFS (0x00003000 - 0x0000df000, 0x000dc000 total bytes): removed
 BIAL (NVRAM partition, no data, 0x0000add3 total bytes): nothing to remove
 BIEL (NVRAM partition, no data, 0x00003522 total bytes): nothing to remove
 BIIS (NVRAM partition, no data, 0x00036000 total bytes): nothing to remove
 NVCL (NVRAM partition, no data, 0x000069c9 total bytes): nothing to remove
 NVCM (NVRAM partition, no data, 0x0000439b total bytes): nothing to remove
 NVCP (NVRAM partition, no data, 0x0000a445 total bytes): nothing to remove
 NVHM (NVRAM partition, no data, 0x00000058 total bytes): nothing to remove
 NVJC (NVRAM partition, no data, 0x00003da0 total bytes): nothing to remove
 NVKR (NVRAM partition, no data, 0x00005fb4 total bytes): nothing to remove
 NVNF (NVRAM partition, no data, 0x0000175f total bytes): nothing to remove
 NVOS (NVRAM partition, no data, 0x0003a34d total bytes): nothing to remove
 NVSH (NVRAM partition, no data, 0x000022c0 total bytes): nothing to remove
 NVSM (NVRAM partition, no data, 0x00001de8 total bytes): nothing to remove
 NVTD (NVRAM partition, no data, 0x00001feb total bytes): nothing to remove
 NVUK (NVRAM partition, no data, 0x00008940 total bytes): nothing to remove
 PLDM (NVRAM partition, no data, 0x000043c5 total bytes): nothing to remove
 TMNN (NVRAM partition, no data, 0x000001a6 total bytes): nothing to remove
 GLUT (0x000df000 - 0x0000e8000, 0x00009000 total bytes): removed
 LOCL (0x000e8000 - 0x0000ec000, 0x00004000 total bytes): removed
 WCOD (0x000ec000 - 0x000160000, 0x00074000 total bytes): removed
 FTPR (0x00160000 - 0x000210000, 0x000b0000 total bytes): NOT removed
 NFTP (0x00210000 - 0x00048a000, 0x0027a000 total bytes): removed
 MDMV (0x0048a000 - 0x0004ca000, 0x00040000 total bytes): removed
Removing partition entries in FPT...
Removing EFFS presence flag...
Correcting checksum (0xd9)...
Reading FTPR modules list...
 UPDATE           (LZMA   , 0x1c6487 - 0x1c66b1       ): removed
 ROMP             (Huffman, fragmented data, ~1 KiB   ): NOT removed, essential
 BUP              (Huffman, fragmented data, ~70 KiB  ): NOT removed, essential
 KERNEL           (Huffman, fragmented data, ~226 KiB ): removed
 POLICY           (Huffman, fragmented data, ~99 KiB  ): removed
 ClsPriv          (LZMA   , 0x1c66b1 - 0x1c6a8a       ): removed
 SESSMGR          (LZMA   , 0x1c6a8a - 0x1d2413       ): removed
 SESSMGR_PRIV     (LZMA   , 0x1d2413 - 0x1d7d03       ): removed
 HOSTCOMM         (LZMA   , 0x1d7d03 - 0x1e0035       ): removed
 TDT              (LZMA   , 0x1e0035 - 0x1e53fa       ): removed
 FPF              (LZMA   , 0x1e53fa - 0x1e6ef9       ): removed
Relocating FTPR from 0x160000 - 0x210000 to 0x1740 - 0xb1740...
 Adjusting FPT entry...
 Adjusting LUT start offset...
 Adjusting Huffman start offset...
 Adjusting chunks offsets...
 Moving data...
The ME minimum size should be 122880 bytes (0x1e000 bytes)
Truncating file at 0x1e000...
Checking the FTPR RSA signature... VALID
Done! Good luck! 

From blobs/xx30/README, applying the following on a fully stitched coreboot rom:
python ~/me_cleaner/me_cleaner.py -S -r -t -d -O /tmp/discarded.bin -D ~/heads/blobs/haswell/ifd.bin -M /tmp/temporary_me.bin dead_serving_a_purpose_t440p_bottom_spi_backup.rom

Would produce proper ifd.bin to be dropped under blobs/haswell for IFD matching latest available ME from present recipe, and dodging blob redistribution limitations.

@rbreslow
Copy link
Contributor Author

rbreslow commented Jan 18, 2023

In the spirit of other maximimized boards, I would like to collaborate into making this board download ME and dump it under haswell blob dir like the other boards are doing it from Lenovo latest bios available prior of merge.

[...]

The idea there is to deliver all this working when adding a board if blobs are needed, otherwise turning this in a maintenance nightmare.

I'm onboard 👍.

ifd can probably be borrowed from libreboot, while I also suppose nvramutil from libreboot is able to generate gbe.bin and also drop it under haswell blob as a default with DE:AD:C0:FF:EE, if not extracted by user from backups as part of a export/extract script. (Not sure how me and gbe are injected in ROM with first look from coreboot config but might have overlooked.

[...]

Note the ifd.bin cannot be generated as of today as opposed to gbe.bin, so normally those files come from "dead" boards. I can swear from memory that I have seen a t440p ifd over libreboot tree. And I'm pretty sure I documented how to modify that ifd to have its regions match moved me region to add frees space into BIOS region into PR that lead into first maximized boards being merged upstream. Will come back to you with that in next coming days as well.

Yes, Libreboot has an ifd.bin blob: https://notabug.org/libreboot/lbmk/src/master/blobs/t440p. Although, it's slightly different than the IFD from my laptop, and I'm not sure why. I updated to the latest BIOS before extracting my IFD.

$ strings my_laptop_ifd.bin
I!B`
E E 
E E 
E E  
% % 
% % 
% % 
GLRN11WW
9.1.10.1005
12MB
SIGNED
$ strings libreboot_ifd.bin
I!B`
E E 
E E 
E E  
% % 
% % 
% % 
GLRN12WW
9.1.20.1035
12MB
SIGNED

Any ideas? Also, is there anything sensitive about sharing an IFD? Is there something specific to my laptop that could identify me? I haven't dug too deep.

As for yournlinux config being based in Librem, this might work as of now, but the config is tailored for those boards with modules for nvme for example.

Good catch. And that's convinced me to apply more scrutiny to the kernel config. I'll split things out into a separate linux-t440p.config file and tune the parameters there.

If you can take a look at x230 blob download script, this would need to be duplicated to download and extract ME from Lenovo. If we have that working with gbe.bin mrc.bin me.bin in place, we would be able to add the board into CircleCI. If you flash that ROM and it works for you, then merging it would be tested working and mergeable.

Makes sense?

Yes, 👍.

Then next step would be to find magic number for CBFS, since 8mb seems really small to fit librem kernel and all the other stuff, which would probably fail really soon to build and without having it under CI we would just not notice.

Agreed. I left a comment with more thoughts here: #1282 (comment).

We want to get away of legacy board requiring users to extract blobs from backups, while an extract script is always provided so users can choose for themselves.

👍. This makes sense.

Also note that t440p instructions should point to latest Lenovo bios update available to update EC prior of initial external flashing as well, currently missing.

Ah, I should've included that in my testing instructions. I burned the latest BIOS update onto a CD and updated my laptop.

Thanks again for this contribution!

You're welcome! And thank you for your great feedback. Seriously, I appreciate it ❤️ .

Here's a list of things I'm going to do:

  • Move the modules/hotp-verification/modules/musl-cross changes into a separate PR.
  • Make a linux-t440p.config, based on linux-librem_common.config, tuning parameters and removing modules such as NVMe storage.
  • Find or borrow an IFD blob.
  • Generate a GbE blob with a generic MAC address (e.g., DE:AD:C0:FF:EE).
  • Download and extract the ME blob from Lenovo.
  • Add the board to CircleCI.

@rbreslow
Copy link
Contributor Author

rbreslow commented Jan 18, 2023

I expected that the ME blob downloaded from Lenovo's website would match the ME I extracted from my laptop. After all, I performed a BIOS update before extraction, and they have the same version number.

I ran me_cleaner on both files and compared the results. The SHAs were different, so I wanted to know why.

$ sha256sum *.bin                                       
b7cf4c0cf514bbf279d9fddb12c34fca5c1c23e94b000c26275369b924ab9c25  me_shrinked_lenovo.bin
18ee99989a16c82c66df639b0d3993a426a0e6400966e82824fc507ae2ae50a1  me_shrinked_my_laptop.bin

The me_cleaner output was slightly different:

$ diff -u <(python me_cleaner.py -r -t -O me_shrinked_my_laptop.bin ../ifdtool/flashregion_2_intel_me.bin) <(python me_cleaner.py -r -t -O me_shrinked_lenovo.bin ~/Downloads/ME9.1_5M_Production.bin)
--- /dev/fd/12	2023-01-17 17:42:05.000000000 -0500
+++ /dev/fd/13	2023-01-17 17:42:05.000000000 -0500
@@ -15,12 +15,12 @@
  BIIS (NVRAM partition, no data, 0x00036000 total bytes): nothing to remove
  NVCL (NVRAM partition, no data, 0x000069c9 total bytes): nothing to remove
  NVCM (NVRAM partition, no data, 0x0000439b total bytes): nothing to remove
- NVCP (NVRAM partition, no data, 0x0000a3c0 total bytes): nothing to remove
+ NVCP (NVRAM partition, no data, 0x0000a445 total bytes): nothing to remove
  NVHM (NVRAM partition, no data, 0x00000058 total bytes): nothing to remove
  NVJC (NVRAM partition, no data, 0x00003da0 total bytes): nothing to remove
- NVKR (NVRAM partition, no data, 0x00005fb3 total bytes): nothing to remove
+ NVKR (NVRAM partition, no data, 0x00005fb4 total bytes): nothing to remove
  NVNF (NVRAM partition, no data, 0x0000175f total bytes): nothing to remove
- NVOS (NVRAM partition, no data, 0x0003a34b total bytes): nothing to remove
+ NVOS (NVRAM partition, no data, 0x0003a34d total bytes): nothing to remove
  NVSH (NVRAM partition, no data, 0x000022c0 total bytes): nothing to remove
  NVSM (NVRAM partition, no data, 0x00001de8 total bytes): nothing to remove
  NVTD (NVRAM partition, no data, 0x00001feb total bytes): nothing to remove
@@ -35,7 +35,7 @@
  MDMV (0x0048a000 - 0x0004ca000, 0x00040000 total bytes): removed
 Removing partition entries in FPT...
 Removing EFFS presence flag...
-Correcting checksum (0xda)...
+Correcting checksum (0xd9)...
 Reading FTPR modules list...
  UPDATE           (LZMA   , 0x1c6487 - 0x1c66b1       ): removed
  ROMP             (Huffman, fragmented data, ~1 KiB   ): NOT removed, essential

Using xxd, I generated a diff between the hex dumps of both blobs:

$ diff <(xxd me_shrinked_my_laptop.bin) <(xxd me_shrinked_lenovo.bin) 
2,3c2,3
< 00000010: 2446 5054 0100 0000 2010 30da 0700 6400  $FPT.... .0...d.
< 00000020: 2000 0000 00fc ffff 0900 0100 0a00 e803   ...............
---
> 00000010: 2446 5054 0100 0000 2010 30d9 0700 6400  $FPT.... .0...d.
> 00000020: 2000 0000 00fc ffff 0000 0000 0000 0000   ...............

It only looks like 10 bytes are different. da is now d9. 0900 0100 0a00 e803 is now 0000 0000 0000 0000.

I wasn't sure what to make of this, but then stumbled upon and used ME Analyzer to compare the two dumps:

╔═══════════════════════════════════════════╗
║         ME Analyzer v1.283.3 r313         ║
╚═══════════════════════════════════════════╝

╔════════════════════════════════════════════════════╗
║          me_shrinked_my_laptop.bin (1/2)           ║
╟───────────────────────────────────┬────────────────╢
║               Family              │       ME       ║
╟───────────────────────────────────┼────────────────╢
║              Version              │  9.1.45.3000   ║
╟───────────────────────────────────┼────────────────╢
║              Release              │   Production   ║
╟───────────────────────────────────┼────────────────╢
║                Type               │   Extracted    ║
╟───────────────────────────────────┼────────────────╢
║                SKU                │      5MB       ║
╟───────────────────────────────────┼────────────────╢
║    TCB Security Version Number    │       1        ║
╟───────────────────────────────────┼────────────────╢
║       Version Control Number      │       17       ║
╟───────────────────────────────────┼────────────────╢
║          Production Ready         │      Yes       ║
╟───────────────────────────────────┼────────────────╢
║                Date               │   2018-06-13   ║
╟───────────────────────────────────┼────────────────╢
║                Size               │    0xB2000     ║
╟───────────────────────────────────┼────────────────╢
║          Flash Image Tool         │  9.1.10.1000   ║
╟───────────────────────────────────┼────────────────╢
║          Chipset Support          │    LPT/WPT     ║
╚═══════════════════════════════════╧════════════════╝

Warning: Firmware size exceeds File, possible data loss!

╔═════════════════════════════════════════════════╗
║           me_shrinked_lenovo.bin (2/2)          ║
╟─────────────────────────────────┬───────────────╢
║              Family             │       ME      ║
╟─────────────────────────────────┼───────────────╢
║             Version             │  9.1.45.3000  ║
╟─────────────────────────────────┼───────────────╢
║             Release             │   Production  ║
╟─────────────────────────────────┼───────────────╢
║               Type              │     Stock     ║
╟─────────────────────────────────┼───────────────╢
║               SKU               │      5MB      ║
╟─────────────────────────────────┼───────────────╢
║   TCB Security Version Number   │       1       ║
╟─────────────────────────────────┼───────────────╢
║      Version Control Number     │       17      ║
╟─────────────────────────────────┼───────────────╢
║         Production Ready        │      Yes      ║
╟─────────────────────────────────┼───────────────╢
║               Date              │   2018-06-13  ║
╟─────────────────────────────────┼───────────────╢
║               Size              │    0xB2000    ║
╟─────────────────────────────────┼───────────────╢
║         Chipset Support         │    LPT/WPT    ║
╚═════════════════════════════════╧═══════════════╝

Warning: Firmware size exceeds File, possible data loss!

ME Analyzer said the Lenovo ME was "stock," while the ME from my laptop was "extracted." And the Lenovo ME was missing a Flash Image Tool (FIT) version number.

Looking at the source code, I found that ME Analyzer determines whether the firmware is "stock" or "extracted," as well as the FIT version, when analyzing $FPT: https://github.com/platomav/MEAnalyzer/blob/3f161b7e4aa9931afb910e9f1ce4732fdf04ebc3/MEA.py#L12352-L12402.

I verified that the majority of the different bytes corresponded to the FIT version (9.1.10.1000):

>>> int.from_bytes(b'\x09\x00', byteorder='little')         
9
>>> int.from_bytes(b'\x01\x00', byteorder='little')         
1
>>> int.from_bytes(b'\x0A\x00', byteorder='little')         
10
>>> int.from_bytes(b'\xE8\x03', byteorder='little')         
1000

And, looking at the data structure for FPT_Header, the last byte (da) that's changed is the HeaderChecksum 11 bytes in, which makes sense since the FIT version has also changed.

So, now, we have a little more assurance that Lenovo hasn't injected any new backdoors since the last time I flashed my BIOS 😅. The only difference is that the ME firmware I extracted contains a "Flash Image Tool" version and a different checksum.

@tlaurion
Copy link
Collaborator

tlaurion commented Jan 18, 2023

Thanks for the ME analysis in previous post, makes sense.

@tlaurion
Copy link
Collaborator

tlaurion commented Jan 18, 2023

On IFD, it is known that some information, depending of makers (Lenovo) might fuse serial numbers and such, including Microsoft COA (never confirmed) inside of IFD.

IFD could be generated, but nobody really cared going that route. The idea here is more "safety in numbers" and the more people sharing the same IFD, the more anonymous one can gets outside of using an IFD coming from libreboot/heads/whatever.

Then, if using tails/qubesos or anything outside of corporate OSes known to leak through accepted but unread service agreement (Microsoft or others) are not supposed to be affected.

I am not aware of a research that digged into that, while if there was enough money, we could definitely go back to specs or feed an IA with enough ifd to generate an abstracted one. But as opposed to ME binary blob, once again, just like the GBE blob, ifd is considered a configuration blob, which interest for us is to define regions, used by flashrom to determine what regions to flash.

On maximized builds, those are neglected since we reflash the whole combined opaque spi, but it is still possible to call flashrom with --ifd and specify BIOS region to not touche GBE nor ifd, or ifd or GBE alone... Which depends of IFD define regions.

Once again, the ifd needs to be unlocked to be changed in the future, and its ME region unlocked to have ME flashable in the future as well. This is mainly why we care to provide an ifd, otherwise coreboot bakes one, but flashing whole spi opaque image will result in a brick. If no valid ifd is added into coreboot config, then coreboot bakes an invalid one, and flashrom needs to be instructed to flash --ifd bios region only, otherwise resulting in a brick.

I based this script on the Coreboot docs:
https://doc.coreboot.org/northbridge/intel/haswell/mrc.bin.html. While
adding an integrity check to ensure we're obtaining the correct blob.

Also, it's worth surfacing that the SHA-1 for the resulting binary is
the same SHA that Libreboot uses in their integrity check:
https://notabug.org/libreboot/lbmk/src/master/resources/scripts/download/mrc#L95.
However, I elected to use SHA-256 for extra paranoia.
I generated this config by walking through Coreboot's `make menuconfig`.
The plan is to pare down verbose defaults and tweak from here.
Remove options that haven't deviated from defaults in the Coreboot
Kconfig, despite being saved by `make savedefconfig`. Also, add
`CONFIG_BOARD_LENOVO_THINKPAD_T440P`, which was missing from the `make
savedefconfig` output, causing Heads builds to fail. And finally, bump
`CONFIG_CBFS_SIZE` to `0x800000` (8 MiB to bytes to hexadecimal).

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
`cbmem -t`). And, an anecdote in
https://groups.google.com/a/chromium.org/g/chromium-os-reviews/c/lUqRrGUoEBY/m/ka7L1f2BS8gJ
suggested that this value needs to be a power of 2.

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?").
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
`intel_iommu=igfx_off` in the `CONFIG_BOOT_KERNEL_ADD` board config
option did nothing. And, the Qubes OS default boot option already
contains `intel_iommu=igfx_off`.

See:
- https://www.qubes-os.org/doc/installation-troubleshooting/#not-asking-for-vnc-because-we-dont-have-a-network--x-startup-failed-aborting-installation--pane-is-dead-error-during-installation
- https://github.com/Qubes-Community/Contents/blob/master/docs/troubleshooting/intel-igfx-troubleshooting.md
- https://www.kernel.org/doc/html/v5.10/x86/intel-iommu.html?highlight=igfx_off#graphics-problems
@tlaurion
Copy link
Collaborator

tlaurion commented Jan 19, 2023

@rbreslow :
Going back to number comparison.

t440p:
t440p

  • Are those numbers consistents across multiple boot or only the first boot after flash?
  • Are those numbers lowering down when playing with CBFS size? Some input there?

X230:
x230


Also if you could provide current logs from boot (cbmem console of last boot dump) would help, where coreboot channel is really helping faster then I would ever have thought!

@rbreslow
Copy link
Contributor Author

Are those numbers consistents across multiple boot or only the first boot after flash?

They are consistent across multiple boots. I uploaded log files: #1282 (comment).

Are those numbers lowering down when playing with CBFS size? Some input there?

So, from 0xBDEFFF to 0x800000 (bzImage + initrd.cpio.xz ≈ 6.8 MiB, and 7.0/7.5 MiB caused build failures): https://gist.github.com/rbreslow/d14ba1a163b851f2e7fb675201749667.

As far as getting this pull request across the finish line, let's pick an arbitrary value but capture all of this context in a follow-up issue. Then, we can apply a smarter fix to all the boards.

@rbreslow
Copy link
Contributor Author

rbreslow commented Jan 23, 2023

I diff'd the IFD and GbE blobs that I extracted from my machine from the ones provided by Libreboot for the T440p.

Analysis of ifd.bin

Starting with the IFD, 4 bytes differed towards the beginning of the file. Then, 3 bytes were different in what appeared to be a version number.

$ diff -u <(xxd ./ifd_mine.bin) <(xxd ./ifd_libreboot.bin)
--- /dev/fd/11	2023-01-22 10:38:16.000000000 -0500
+++ /dev/fd/13	2023-01-22 10:38:16.000000000 -0500
@@ -4,7 +4,7 @@
 00000030: 3400 9049 2142 60ad b7b9 c4c7 ffff ffff  4..I!B`.........
 00000040: 0000 0000 2100 ff0b 0300 2000 0100 0200  ....!..... .....
 00000050: ff7f 0000 ff7f 0000 ff7f 0000 ffff ffff  ................
-00000060: 0000 0b0a 0000 0404 1801 0808 ffff ffff  ................
+00000060: 0000 ffff 0000 ffff 1801 0808 ffff ffff  ................
 00000070: ffff ffff ffff ffff ffff ffff ffff ffff  ................
 00000080: ffff ffff ffff ffff ffff ffff ffff ffff  ................
 00000090: ffff ffff ffff ffff ffff ffff ffff ffff  ................
@@ -238,8 +238,8 @@
 00000ed0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
 00000ee0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
 00000ef0: ffff ffff ffff ffff ffff ffff df16 0000  ................
-00000f00: 474c 524e 3131 5757 ff39 2e31 2e31 302e  GLRN11WW.9.1.10.
-00000f10: 3130 3035 ff31 324d 42ff 5349 474e 4544  1005.12MB.SIGNED
+00000f00: 474c 524e 3132 5757 ff39 2e31 2e32 302e  GLRN12WW.9.1.20.
+00000f10: 3130 3335 ff31 324d 42ff 5349 474e 4544  1035.12MB.SIGNED
 00000f20: ffff ffff ffff ffff ffff ffff ffff ffff  ................
 00000f30: ffff ffff ffff ffff ffff ffff ffff ffff  ................
 00000f40: ffff ffff ffff ffff ffff ffff ffff ffff  ................

This generated two questions:

  1. What do those bytes at the top represent?
  2. Why is the version number in Libreboot's IFD newer? I updated my BIOS before dumping my ROM's contents.

Luckily, Intel publishes a datasheet for the ICH8, containing detailed specifications which describe the data structure of the T440p's Flash Descriptor: Intel® I/O Controller Hub 8 (ICH8) Family. And, using ImHex and their pattern language, I was able to analyze the contents of both Flash Descriptors.

All of the patterns I developed for this analysis are available here: https://github.com/rbreslow/ImHex-Patterns/tree/rb/intel-ich8/patterns/intel.

The first difference occurs in the Flash Descriptor Master Section. The Flash Descriptor Master contains three instances of the same 32-bit data structure, which appear to control read and write access to different regions of the ROM:

bitfield flash_master {
  requester_id                                      : 16;
  flash_descriptor_master_region_read_access        : 1;
  host_cpu_slash_bios_master_region_read_access     : 1;
  me_master_region_read_access                      : 1;
  gbe_master_region_read_access                     : 1;
  reserved0                                         : 4;
  flash_descriptor_master_region_write_access       : 1;
  host_cpu_slash_bios_master_region_write_access    : 1;
  me_master_region_write_access                     : 1;
  gbe_master_region_write_access                    : 1;
  reserved1                                         : 4;
};

struct flash_descriptor_master {
  // FLMSTR1—Flash Master 1 (Host Processor/ BIOS)
  flash_master flmstr1;
  // FLMSTR2—Flash Master 2 (ME)
  flash_master flmstr2;
  // FLMSTR3—Flash Master 3 (GbE)
  flash_master flmstr3;
};

Specifically, the difference is in the first two Flash Masters. My instance of flmstr1 has Flash Descriptor, BIOS, and GbE read access with BIOS and GbE write access. Whereas Libreboot's flmstr1 has wildcard read and write, along with incorrect reserved bits (0xF instead of 0x0, per Intel's spec).

My instance of flmstr2 only has ME read and write access. Libreboot's flmstr2, again, has wildcard read and write access with incorrect reserved bits.

Strangely though, flmstr3 is identical in both ROMs: Only GbE read and write access and reserved bits set to 0x0.

flmstr1 struct from my ROM'sifd.bin blob.
flmstr2 struct from my ROM'sifd.bin blob.
flmstr3 struct from my ROM'sifd.bin blob.
flmstr1 struct from my Libreboot'sifd.bin blob.
flmstr2 struct from my Libreboot'sifd.bin blob.
flmstr3 struct from my Libreboot'sifd.bin blob.

We can see the same information by diffing the output of ifdtool -d:

$ diff -u <(ifdtool -d ifd_mine.bin) <(ifdtool -d ifd_libreboot.bin)
--- /dev/fd/12	2023-01-23 11:25:00.000000000 -0500
+++ /dev/fd/14	2023-01-23 11:25:00.000000000 -0500
@@ -1,4 +1,4 @@
-File ifd_mine.bin is 4096 bytes
+File ifd_libreboot.bin is 4096 bytes
 PCH Revision: 8 series Lynx Point
 FLMAP0:    0x03040103
   NR:      3
@@ -140,8 +140,8 @@
     Upper Block / Sector Erase Size:    4KB
 
 OEM Section:
-00: 47 4c 52 4e 31 31 57 57 ff 39 2e 31 2e 31 30 2e
-10: 31 30 30 35 ff 31 32 4d 42 ff 53 49 47 4e 45 44
+00: 47 4c 52 4e 31 32 57 57 ff 39 2e 31 2e 32 30 2e
+10: 31 30 33 35 ff 31 32 4d 42 ff 53 49 47 4e 45 44
 20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 
@@ -200,30 +200,30 @@
 AltMeDisable bit is set
 
 Found Master Section
-FLMSTR1:   0x0a0b0000 (Host CPU/BIOS)
-  Platform Data Region Write Access: disabled
+FLMSTR1:   0xffff0000 (Host CPU/BIOS)
+  Platform Data Region Write Access: enabled
   GbE Region Write Access:           enabled
-  Intel ME Region Write Access:      disabled
+  Intel ME Region Write Access:      enabled
   Host CPU/BIOS Region Write Access: enabled
-  Flash Descriptor Write Access:     disabled
-  Platform Data Region Read Access:  disabled
+  Flash Descriptor Write Access:     enabled
+  Platform Data Region Read Access:  enabled
   GbE Region Read Access:            enabled
-  Intel ME Region Read Access:       disabled
+  Intel ME Region Read Access:       enabled
   Host CPU/BIOS Region Read Access:  enabled
   Flash Descriptor Read Access:      enabled
   Requester ID:                      0x0000
 
-FLMSTR2:   0x04040000 (Intel ME)
-  Platform Data Region Write Access: disabled
-  GbE Region Write Access:           disabled
+FLMSTR2:   0xffff0000 (Intel ME)
+  Platform Data Region Write Access: enabled
+  GbE Region Write Access:           enabled
   Intel ME Region Write Access:      enabled
-  Host CPU/BIOS Region Write Access: disabled
-  Flash Descriptor Write Access:     disabled
-  Platform Data Region Read Access:  disabled
-  GbE Region Read Access:            disabled
+  Host CPU/BIOS Region Write Access: enabled
+  Flash Descriptor Write Access:     enabled
+  Platform Data Region Read Access:  enabled
+  GbE Region Read Access:            enabled
   Intel ME Region Read Access:       enabled
-  Host CPU/BIOS Region Read Access:  disabled
-  Flash Descriptor Read Access:      disabled
+  Host CPU/BIOS Region Read Access:  enabled
+  Flash Descriptor Read Access:      enabled
   Requester ID:                      0x0000
 
 FLMSTR3:   0x08080118 (GbE)

Some more questions:

  1. Who or what do these bits grant read/write access to?
  2. Assuming these bits are required for internal flashing with flashrom, my ifd.bin doesn't have Flash Descriptor write access enabled, so how is internal flashing succeeding?

The next difference is within the 256-byte "OEM Section." I don't know why the version number is more recent in Libreboot's IFD as I updated the BIOS on my T440p before extracting my ROM.

On IFD, it is known that some information, depending of makers (Lenovo) might fuse serial numbers and such, including Microsoft COA (never confirmed) inside of IFD.

At the very least, I'm pretty sure there aren't any serial numbers inside of the IFD, as the specification is open, and there are no undocumented bits that differ between our blob and Libreboot's.

Analysis of gbe.bin

The mystery continued with the GbE blob. I used Libreboot's nvmutil to perform a hex dump on each blob/checksum calculation. And please note that I redacted the last three bytes of my MAC address.

$ diff -u <(./nvm gbe_mine.bin dump) <(./nvm gbe_libreboot.bin dump)
WARNING: BAD checksum in part 0
--- /dev/fd/11	2023-01-22 11:35:16.000000000 -0500
+++ /dev/fd/13	2023-01-22 11:35:16.000000000 -0500
@@ -1,18 +1,18 @@
-MAC (part 0): 68:f7:28:ff:ff:ff
-0000000 f768 ff28 ffff 0801 ffff 00d3 0029 8000 
+MAC (part 0): 68:f7:28:7d:f1:74
+0000000 f768 7d28 74f1 0801 ffff 00d3 0029 8000 
 0000010 1000 ffff 10c3 220e 17aa 153a 0000 0000 
-0000020 0702 0000 0000 0005 3028 1900 0000 0c00 
+0000020 0702 0000 0000 a505 3028 1900 0000 0c00 
 0000030 2a64 0a40 0843 0113 153a baad 153a 153a 
 0000040 baad 153a baad 153a 0000 8080 4e00 0886 
 0000050 0000 0000 0007 2000 00a0 0000 0c00 ffff 
 0000060 0100 4000 1535 4007 ffff ffff ffff ffff 
-0000070 ffff ffff ffff ffff ffff 0100 ffff 1d9d 
-MAC (part 1): 68:f7:28:ff:ff:ff
-0000000 f768 ff28 ffff 0801 ffff 00d3 0029 8000 
+0000070 ffff ffff ffff ffff ffff 0100 ffff 6459 
+MAC (part 1): 68:f7:28:7d:f1:74
+0000000 f768 7d28 74f1 0801 ffff 00d3 0029 8000 
 0000010 1000 ffff 10c3 220e 17aa 153a 0000 0000 
 0000020 0702 0000 0000 a505 3028 1900 0000 0c00 
 0000030 2a64 0a40 0843 0113 153a baad 153a 153a 
 0000040 baad 153a baad 153a 0000 8080 4e00 0886 
 0000050 0000 0000 0007 2000 00a0 0000 0c00 ffff 
 0000060 0100 4000 1535 4007 ffff ffff ffff ffff 
-0000070 ffff ffff ffff ffff ffff 0100 ffff 1d9d 
+0000070 ffff ffff ffff ffff ffff 0100 ffff 6459

What immediately jumps out is that my gbe.bin blob has an invalid checksum in what nvmutil calls "part 0." Then, besides the MAC address, there's a single-byte difference at offset 0x26. Along with a four-byte difference at offset 0x7E. Then, in "part 1," the single-byte difference is missing, but the same four-byte difference occurs again.

Luckily, I was able to find more documentation from Intel, Intel® I/O Controller Hub 8/9 LAN NVM Map and Information Guide, which describes the data structure of the "LAN NVM," or, LAN Non-Volatile Memory. So, I was able to use ImHex to perform another analysis.

Some observations:

  • Intel doesn't mention multiple "parts"/copies of the LAN NVM data structure.
  • I didn't spend time codifying the "Extended Configuration Area" in my ImHex pattern because Intel's documentation seemed sparse. I may reevaluate in the future.

The single-byte difference I mentioned occurs within the shared_initialization_control structure:

bitfield shared_initialization_control_duplex1 {
  dynamic_clock_gating : 1;
  clk_cnt_1_4 : 1;
  clk_cnt_1_16 : 1;
  padding : 1;
  frcspd : 1;
  d_slash_ud_polarity : 1;
  phyt : 2;
  reserved0 : 1;
  phy_pd_enable : 1;
  reserved1 :  1;
  ext_pwr_polarity : 1;
  reserved2 : 2;
  sign : 2;
} [[inline]];

bitfield shared_initialization_control_duplex2 {
  padding : 3;
  fd : 2;
  padding : 11;
} [[inline]];

union shared_initialization_control {
    shared_initialization_control_duplex1;
    shared_initialization_control_duplex2;
};

My GbE blob has incorrect values for reserved2 and sign, which are supposed to be 0x1 and 0x2, respectively. However, In "part 1," the sign value in my GbE blob is correct and matches Libreboot. And it looks like both blobs have an incorrect value for reserved2.

shared_initialization_control struct from my ROM's gbe.bin blob (part 0).
shared_initialization_control struct from Libreboot's gbe.bin blob (part 0).
shared_initialization_control struct from my ROM'sgbe.bin blob (part 1).

The only other difference between the blobs is the checksum 0x7E, which makes sense since both blobs have a different MAC address.

Checksum from my ROM's gbe.bin (part 0).

Some more thoughts:

  • I'm concerned with how much data in the blob is unaccounted for by the datasheets I've found. However, at least it's the same as another T440p, so it's nothing specific to my machine.

Conclusion

At a high level, the only differences are:

  • IFD: read/write bits and "OEM Section" version number.
  • GbE: MAC address, shared_initialization_control bits, and checksums.

I feel safe sharing my personal IFD and GbE blobs. I don't see any personally identifiable information besides my MAC address (and this was a $50 eBay computer).

Before I commit things, I will use nvmutil to change the MAC address to DE:AD:C0:FF:EE and calculate a new checksum.

@tlaurion, what are your thoughts on the malformed bits of my GbE blob? Ethernet seems to work fine on my machine.

Same thing with my Flash Descriptor. It seems to work. I'm thinking we use both as-is but open an issue to investigate the discrepancies.

@tlaurion
Copy link
Collaborator

tlaurion commented Jan 23, 2023

@tlaurion, what are your thoughts on the malformed bits of my GbE blob? Ethernet seems to work fine on my machine.

@rbreslow from top of my head, I can only answer for GBE.bin

Spec file to generate those config blobs have been upstreamed to coreboot per @Thrilleratplay, and then sprung the idea of having those being generated at runtime inside of osboot through nvmramutil now part of libreboot.

Intel drivers are actually responsible to male sure that at least one of the two regions are valid.

You can see under blobs/xx30/README a recipe to produce a GBE region, where instructions are basically duplicating that valid region to recreate a valid GBE.bin dropped there.

I'm surprised that libreboot is not providing valid GBE.bin, being behind both spec file and GBE region generator (again blobs/xx30 or xx20/README) where more can be found checking the spec files used to generate those (and where DE:AD:C0:FF:EE comes from for credit and eye blink to creators... and anonymity in numbers)
This is documented here: https://github.com/osresearch/heads/blob/075284374b217addbc1d21c803182192d5c0a216/blobs/xx30/README#L46

Note that nvmutil is planned to be included in firmware where Mac generator is desired by many. This will generate two equal regions with randomized Mac on demand at first.

Same thing with my Flash Descriptor. It seems to work. I'm thinking we use both as-is but open an issue to investigate the discrepancies.

Your analysis here is precious, where prior work was not necessarily revalidated and used as is. For what is defined as smaller permissions groups for GBE/me regions, I remember having read those permissions are used by ME to access those regions.

On a flashrom perspective, ifd is used (if present. Aftetall this is Intel File descriptor and unique to Intel for those gen) ifd is used to specify regions to be flashed and to poke those regions prior of attempting erase/write functions. If ME region is locked for write (ifdtool not being called on ifd/rom to unlock ME region either by user or by coreboot stitching final firmware) flashrom will warn about protected regions (see https://osresearch.net/Prerequisites#legacy-vs-maximized-boards for legacy boards (where neither ifd nor ME were touched prior of maximized builds existence). This page gives flashrom output when regions are locked https://osresearch.net/Updating#locked-ifd-and-me

@rbreslow
Copy link
Contributor Author

rbreslow commented Jan 24, 2023

Spec file to generate those config blobs have been upstreamed to coreboot per @Thrilleratplay, and then sprung the idea of having those being generated at runtime inside of osboot through nvmramutil now part of libreboot.

There are some minor differences between the ICH9 and ICH8 flash descriptor. The flash descriptor @Thrilleratplay added to Coreboot (ifd-x200.spec) is for the ICH9. So, we'd need to contribute another spec for the ICH8.

I enjoyed using the "Hex patterns" DSL to analyze the flash descriptor/GbE blobs. There are data types, functions, conditionals, and even a standard library: https://imhex.werwolv.net/docs/. And now, we have the patterns I created during my analysis above.

However, after talking with @WerWolv in Discord (the ImHex developer), I learned it might take work to encode a new binary using the pattern language.

But in general, 100%, I agree it'd be cool to generate these blobs at build-time (or even runtime for gbe.bin, if that's possible).

Intel drivers are actually responsible to male sure that at least one of the two regions are valid.

You can see under blobs/xx30/README a recipe to produce a GBE region, where instructions are basically duplicating that valid region to recreate a valid GBE.bin dropped there.

Do you know of any official documentation on this? I haven't been able to find anything that explains why there are two regions.

And yeah, I see this in the xx30 README:

# duplicate binary as per spec
cat gbe1.bin gbe1.bin > ../../../../blobs/xx30/gbe.bin

And looking at my own gbe.bin blob, it looks like the second region starts at 0x1000 (4 KiB) and is exactly the same size as the first region.

I'm surprised that libreboot is not providing valid GBE.bin, being behind both spec file and GBE region generator (again blobs/xx30 or xx20/README) where more can be found checking the spec files used to generate those (and where DE:AD:C0:FF:EE comes from for credit and eye blink to creators... and anonymity in numbers) [...]

For clarification: Libreboot does provide a valid gbe.bin blob, even leaving in the original MAC address of the donor board. It's my blob that appears to have an invalid region/corrupted byte.

Note that nvmutil is planned to be included in firmware where Mac generator is desired by many. This will generate two equal regions with randomized Mac on demand at first.

Do you want to include nvmutil in the Heads initrd to randomize and then reflash GbE on boot?

Your analysis here is precious, where prior work was not necessarily revalidated and used as is. For what is defined as smaller permissions groups for GBE/me regions, I remember having read those permissions are used by ME to access those regions.

On a flashrom perspective, ifd is used (if present. Aftetall this is Intel File descriptor and unique to Intel for those gen) ifd is used to specify regions to be flashed and to poke those regions prior of attempting erase/write functions. If ME region is locked for write (ifdtool not being called on ifd/rom to unlock ME region either by user or by coreboot stitching final firmware) flashrom will warn about protected regions (see https://osresearch.net/Prerequisites#legacy-vs-maximized-boards for legacy boards (where neither ifd nor ME were touched prior of maximized builds existence). This page gives flashrom output when regions are locked https://osresearch.net/Updating#locked-ifd-and-me

Thank you so much.

Got it. Well, flashrom in the Heads payload is not giving any "read-only" or "locked" errors, so I'm inclined to leave the Flash Descriptor as-is. Later on, I will experiment by disabling bits to find the minimum permission set.

I went through all of the different options we copied from the Librem
config. The only thing that stood out as irrelevant was NVMe support.
However, I'm not a Linux kernel expert, and I didn't do a deep dive, so
I'm sure there is still room for improvement.
I performed an analysis of the differences between an me.bin blob I
extracted from my T440p and the me.bin blob from Lenovo's website:
linuxboot#1282 (comment).
blobs/haswell/obtain-mrc Outdated Show resolved Hide resolved
@srgrint
Copy link
Contributor

srgrint commented Feb 24, 2023

Great to have you back @rbreslow

Thanks in particular for the warning about the speaker cable on T440p disassembly - I think the hardware maintenance manual dosen't make it as clear as it could the importance of extreme care when unrouting it.

I have just tried the same configuration, but bumping the coreboot version to 4.19. Seems to work fine including suspend/resume

More aligned with the naming conventions of xx20 and xx30's extract.sh.
I extracted the ifd.bin blob from my T440p using the blobs/t440p/extract
script.
- I extracted the gbe.bin blob from my T440p's original ROM using the
  blobs/t440p/extract script.
- Using a hex editor, I corrected the sign bit in part 0 that I found
  was malformed in my analysis:
  linuxboot#1282 (comment).
- After correcting the sign bit, nvmutil showed that both parts of my
  gbe.bin blob had valid checksums.
- Finally, I used nvmutil to set the MAC address to 00:de:ad:c0:ff:ee.
Before, the T440p blob scripts would look for Coreboot using the find
command. Now, we require the user to specify the path to Coreboot in the
COREBOOT_DIR environment variable. Also, add an output directory
argument to each script.

These changes will make it easier to integrate with the Heads build
system and CI.
Now, when you run `make BOARD=any-t440p-variant`, the build system
automatically fetches mrc.bin and me.bin.
We need extra dependencies to support Coreboot's util/crosfirmware.sh to
extract the T440p's mrc.bin.
Comment on lines +38 to +48
# 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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make rule syntax is:

targets : prerequisites
        recipe
        …

Where a "target" is a path to a file that needs to exist. So, we create two targets for mrc.bin and me.bin with recipes that run the corresponding blob scripts. And we make the Coreboot build target (defined elsewhere) depend on these blob targets.

Since a target is a path to a file, if the blobs already exist (e.g., user-supplied blobs), make will skip these recipes.

See: https://www.gnu.org/software/make/manual/make.html#Rule-Syntax

blobs/haswell/obtain-mrc Show resolved Hide resolved
Comment on lines 23 to 24
if [[ ! -f "$1/mrc.bin" ]]; then
pushd "${COREBOOT_DIR}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a mrc.bin already exists, don't try and download it again. Instead, skip right to the integrity check.

@tlaurion
Copy link
Collaborator

Any reason why NO_GFX_INIT is not defined under coreboot config? (As for x230 for example)?

Since Linux provides i915+DRM, it seems unneeded?

@tlaurion
Copy link
Collaborator

tlaurion commented Feb 26, 2023

Is this board iGPU only?
EDIT: No it can be iGPU+dGPU, so there will be additional board variants with dGPU blobs later on.

https://support.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t440p/downloads/ds104325

I'm still personally confused with the presence of libgfx init in coreboot and iGPU+dGPU presence without dGPU blobs.

@tlaurion
Copy link
Collaborator

tlaurion commented Feb 26, 2023

@rbreslow

NO_GFX_INIT

Not an issue for this PR, would be a question for when times come to add dGPU blobs for nividia dual graphics board owners.

Edit: for reference #1057 (comment)

Because we're using pushd/popd to make the Coreboot util invocation
cleaner, we need to use realpath so that the scripts will work with any
user input.
@rbreslow
Copy link
Contributor Author

rbreslow commented Feb 28, 2023

I've verified that the latest CircleCI build works via an internal flash on my T440p. And I made sure that the modifications to the GbE blob worked:

Heads Main Menu

heads_main_menu

Heads System Info

heads_system_info

Qubes MAC Address

qubes_mac_address

I'm awaiting your review and 👍.

This change will improve build times by allowing the T440p to share the
Coreboot 4.17 cache with the Librem boards. Once we update the other
ThinkPad boards to use Coreboot 4.19, we'll make the T440p depend on the
X230 again.

Co-authored-by: Thierry Laurion <insurgo@riseup.net>
@tlaurion
Copy link
Collaborator

Nothing to say! Waiting for successful build with workspace passed from librem

@PerAstraAdDeum
Copy link

Hi there,

I'm following this endeavor closely ever since shmalebx9 came up with his proposal to integrate files from the osboot project.
From what I can tell you are close to an actual release, it that right? If so, will pre-compiled ROMs be available for T440p?
I'd offer my support for testing - corebooted T440p owner here - but I'm not that tech-savvy and I'd very much prefer a downloadable ROM or at least a somewhat beginner-friendly tutorial (like this excellent guide for example ).

Apart from that, I have some questions regarding Heads. Are their any wikis or manuals aside from osresearch?

@tlaurion
Copy link
Collaborator

tlaurion commented Mar 19, 2023

@PerAstraAdDeum ROMs are downloadable from CircleCI following https://osresearch.net/Downloading#downloading-heads-from-circleci

Heads is still in a rolling release, there is no planned release until Heads finds a new home inside of an organization (that is political issue) and not figured out yet. This is because @osresearch is a user account and would require Trammel to do the releases himself as opposed to an organisation under github which could assign permissions to me and others to delegate tasks, which otherwise is limited to assign permissions to collaborators. Its a maintainership problem for which I do not have solution today and is the first step to have releases and after which, firmware images, even if not completely reproducible (other problem to be resolved before/after) to have firmware images pushed/downloaded and out in LVFS so fwupd can download firmware images and have Heads verify them (third problem) directly and automatically as users download other software updates.

As of now there is another issue opened for no_gfx which seems to be a kernel config issue linked to using 5.x kernel as opposed to 4.x to boot platform and have final OS have console in framebuffer, common with librem platforms (kernel config for t440p was borrowed by librem_common).

Long story short, firmware images are downloadable as circleci artifacts, today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Integrate T440p Support from Osboot
4 participants