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

Have qemu boards support writeable pflash and internal flashing #1203

Open
tlaurion opened this issue Aug 24, 2022 · 15 comments
Open

Have qemu boards support writeable pflash and internal flashing #1203

tlaurion opened this issue Aug 24, 2022 · 15 comments

Comments

@tlaurion
Copy link
Collaborator

tlaurion commented Aug 24, 2022

Seems like both qemu and flashrom will need to be patched. Meanwhile, injecting key is made from separate qemu board build statement, and "reflashing" is rebooting qemu/kvm with newer built rom.


Current limitations stated under OP under #1188, where the following traces are what needs to be resolved:

@JonathonHall-Purism : would like to know what is the issue with nvram you were talking about earlier, and also what avenues possible with pflash since from what I've read from libvirt XML and qemu doc, the flash is not writable. Any input you have there would be useful in other open issues

Looks like the size limit is just a matter of changing this default for max_fw_size: https://gitlab.com/qemu-project/qemu/-/blob/master/hw/i386/pc.c#L1833

Re: writable flash, it seems to exist but the only discussion I can find is about people using it incorrectly: https://bugs.launchpad.net/qemu/+bug/1818367/comments/4

The element, with @type='pflash', no other attributes, and then
no sibling element either, happens to be valid, but it is an
extremely niche use case. It is used when you have a unified, writeable,
OVMF.fd file that contains both the firmware executable and the live
variable store.

This does sound like what we want, I have no idea right now how this works with plain qemu, whether flashrom supports it, or what it would take to add.

Originally posted by @JonathonHall-Purism in #1188 (comment)

@tlaurion
Copy link
Collaborator Author

Leaving traces of pertinent mailing list sub threads

@tlaurion
Copy link
Collaborator Author

Track Dasharo/dasharo-issues#828

@tlaurion
Copy link
Collaborator Author

@tlaurion
Copy link
Collaborator Author

tlaurion commented Nov 21, 2024

Question asked under Dasharo OSFV matrix channel at https://matrix.to/#/!MwWOJhMJzlxIdAQxae:matrix.3mdeb.com/$-G0q4GBkLoQwCk7d1geSf-U74XuqTNwtSb6HT072K-s?via=matrix.org&via=nitro.chat&via=matrix.3mdeb.com:

@krystian-hebel @miczyg1 @macpijan @pietrushnic : as of today, Heads only missing feature for unattended testing, simulating real hardware workflow, is SPI/pflash RW to passed rom image: being able to flashrom/flashprog read/write referred rom image passed to qemu/kvm to get persistence of firmware changes made to cbfs for config store for persistence between reboot and measured boot/part of sealed secrets (TPMTOTP, TPM DUK, config setting changes, boot device etc etc etc).

Can omebody ELI5/TLDR if it would be possible/how complicated it would be to provide qemu R/W access to passed rom image so there is no differences between real hardware operations vs emulated ops?

Ie, from master's

  • ./docker_repro.sh make BOARD=qemu-coreboot-whiptail-tpm2-hotp USB_TOKEN=Nitrokey3NFC
  • ./docker_repro.sh make BOARD=qemu-coreboot-whiptail-tpm2-hotp USB_TOKEN=Nitrokey3NFC run

commands, expending to

!!!!!! Build starts !!!!!!
Makefile:270: warning: overriding recipe for target 'all'
Makefile:251: warning: ignoring old recipe for target 'all'
swtpm socket \
	--tpm2 \
	--tpmstate dir="/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/vtpm" \
	--flags "startup-clear" \
	--terminate \
	--ctrl type=unixio,path="/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/vtpm/sock" &
sleep 0.5
qemu-system-x86_64 -drive file="/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/root.qcow2",if=virtio \
	--machine q35,accel=kvm:tcg \
	-rtc base=utc \
	-smp 1 \
	-vga std \
	-m "$(cat "/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/memory")" \
	-serial stdio \
	--bios "/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/heads-qemu-coreboot-whiptail-tpm2-hotp-v0.2.0-2440-gff307d4.rom" \
	-object rng-random,filename=/dev/urandom,id=rng0 \
	-device virtio-rng-pci,rng=rng0 \
	-netdev user,id=u1 -device e1000,netdev=u1 \
	-chardev socket,id=chrtpm,path="/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/vtpm/sock" \
	-tpmdev emulator,id=tpm0,chardev=chrtpm \
	-device tpm-tis,tpmdev=tpm0 \
	-device qemu-xhci,id=usb \
	-device usb-tablet \
	-drive file="/home/user/heads/build/x86/qemu-coreboot-whiptail-tpm2-hotp/usb_fd.raw",if=none,id=usb-fd-drive,format=raw \
	-device usb-storage,bus=usb.0,drive=usb-fd-drive \
	-device usb-host,vendorid=8352,productid=17074 \

automated testing still requires following targets/qemu.md workarounds because no SPI flash from within Heads to inject generated keyring, trustdb and config.user which normally would be injected into cbfs. Therefore, qemu.md instructs to

  • mount qemu's emulated thumb drive usb_fd.raw to get pubkey, and as opposed to real hardware which keeps trustdb/keyring persistently, asks dev/automated testing to inject the key manually (which injection creates unique trustdb/keyring per pubkey injection)
  • asks dev to ./docker_repro.sh make BOARD=qemu-coreboot-whiptail-tpm2-hotp PUBKEY_ASC=exported_emulated_thumbdrive_pubkey.asc inject_gpg which creates a rom with host created trustdb/keyring (and no config.user persistence of config)
  • asks dev to finally run ./docker_repro.sh make BOARD=qemu-coreboot-whiptail-tpm2-hotp PUBKEY_ASC=exported_emulated_thumbdrive_pubkey.asc run

To simulate a whole real hardware workflow... If there was support for pflash rw, then emulated vs real hardware workflow would be exactly the same.

Thoughts? That would resolve #1203

@tlaurion
Copy link
Collaborator Author

tlaurion commented Nov 21, 2024

Of course, changes to qemu would need to be merged inside of nix, and then flake.lock under Heads using this new built qemu, included under nix based created docker images under Heads.

When Heads needed canokey support built it under nix by default:

Leading to PR merging collaboration work, changing flake.lock and flake.nix to point to new qemu_full on which Heads docker image build atop of nix under #1687

@mkopec
Copy link
Contributor

mkopec commented Dec 10, 2024

This would definitely unblock some tests for us.

We planned to use qemu for automating part of Dasharo tests but we found that many features (OEM factory reset and GPG most notably) depend on being able to write to the flash. Without this ability a lot of our testing has to be done manually on hardware instead

@pietrushnic
Copy link

I achieved writes in QEMU and Dasharo (coreboot+SeaBIOS) with sortbootorder as a secondary payload. Someone would have to build that with Heads for QEMU, but I need to see how it would work out of the box if coreboot contains @krystian-hebel driver.

How I tested it? I used:

@tlaurion
Copy link
Collaborator Author

if coreboot contains @krystian-hebel driver.

Eli5?

@pietrushnic
Copy link

@mkopec
Copy link
Contributor

mkopec commented Dec 12, 2024

That patch enables Qemu flash writes in coreboot, we would need someone to port this code to flashrom, that's what Heads uses to write to flash

@krystian-hebel
Copy link
Contributor

I'm not sure if pflash is something that can be easily added to flashrom, there is no way of probing for it, other than trying to write, which may fail miserably for any real flash device. Would it be good enough to add a dedicated app/script (I've been testing it with busybox devmem) just for QEMU instead?

@tlaurion
Copy link
Collaborator Author

tlaurion commented Dec 12, 2024

I'm not sure if pflash is something that can be easily added to flashrom, there is no way of probing for it, other than trying to write, which may fail miserably for any real flash device. Would it be good enough to add a dedicated app/script (I've been testing it with busybox devmem) just for QEMU instead?

Since #1769, Heads is not hardcoding use of flashrom/flashprog, but instead requires each board to describe what is used to flash internally, now flashprog because of --progress output (and because @i-c-o-n responded and fixes everything that was needed for Heads tht flashrom took years to).

The ideal, of course, would be to have internal flashing of qemu pflash from flashprog/flashrom with same minimal arguments so that Heads do not have to implement another set of workarounds just for qemu, while keeping the same output that is existing for all other boards for automated testing.

If we take a look at a random #1769 board config change:

So as log as the internal flasher used permits similar flashrom/flashprog arugments (-r/-w/-v + filename), then Heads will prepend any internal flashing call with the content of CONFIG_FLASH_OPTIONS="flashprog --progress --programmer internal"

Note that flash.sh script currently uses BOARD name to exclude qemu boards as of today and print a warning on console pointing to qemu.md docs.

The ideal, in my opinion, would be the addition or a qemu programmer to flashrom/flashprog, ie flashprog --progress --programmer qemu which would know what to do, and exclude probing from internal programmer. Thoughts?

Would it be good enough to add a dedicated app/script (I've been testing it with busybox devmem) just for QEMU instead?

It would be enough. But would do things in the dark, without flashrom/flashprog progress bar, unified in all other boards and if failing because of WP regions or whatnot, would diverge in automated testings as opposed to where we want to go forward with flashprog, not leaving users/dev in the dark when reading/erasing/writing to a big flash chip.

@i-c-o-n
Copy link

i-c-o-n commented Dec 14, 2024

Wrt. flashprog, adding another "programmer" would be possible, but not sure if worth it. I see a few options with the internal programmer as well:

  1. Run qemu with some specific flash ID. Just tested -global driver=cfi.pflash01,property=id0,value=0xab -global driver=cfi.pflash01,property=id1,value=0xcd and could at least see the 0xcd in a log from flashprog -p internal:laptop=this_is_not_a_laptop. This would require to add some QEMU-compatible, bigger parallel flash chips to the database (virtually nothing above 512KiB was used for BIOS's, so such chips were never added). Not sure if it's fun to dig into parallel flash in 2024, though.
  2. Add CFI support to flashprog. CFI seems to be for automatic probing of flash parameters and similar to SFDP for SPI flash. Probably more fun than 1., but it's a 25 year old standard, so no use beyond QEMU probably.
  3. Actually emulate a "modern" controller: https://github.com/9elements/qemu/commits/qemu_ich9_spi I never had a close look and don't know why it didn't go upstream. But the idea seems right and we could test code paths that are much closer to those used on current hardware. IMO, getting this upstream would benefit the ecosystem the most and is what I would pursue. What I don't know: does the SPI flash emulation in QEMU have all the wanted features? i.e. anything that the pflash driver has and is missing?

@tlaurion
Copy link
Collaborator Author

@pietrushnic @mkopec @krystian-hebel thoughts on prior comment?

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

No branches or pull requests

5 participants