← Alemar Labs

Finding the hidden VT-d switch on a Lenovo M700


The Lenovo ThinkCentre M700 is a tidy little Skylake box, and like a lot of OEM machines it ships with VT-d switched off and — more annoyingly — with no menu entry to switch it back on. VT-d is the IOMMU: without it there is no clean PCI passthrough, no device isolation for a hypervisor. The silicon supports it. The firmware just refuses to show you the toggle.

The option is still in there. OEMs suppress setup questions in the UEFI forms rather than compiling them out, so the switch, its variable, and its storage offset are all sitting in the firmware image waiting to be read. Here is how I found it.

Dump the flash

Everything starts with the SPI flash. This is an 8 MB image pulled off the board:

imageM05.bin   8388608 bytes   md5 77363a049243db742960057eacf1584f

flash.fd is a byte-identical copy of the same dump — same MD5 — so there is one source of truth and a working copy.

Carve it into regions

A raw SPI image is a stack of regions described by the Intel Flash Descriptor. Running it through a UEFI firmware parser splits it apart:

Flash Descriptor (Intel PCH)
Firmware Volume: FFS2
NVAR Variable Store

That produces a regions/ tree — a 6 MB BIOS region (region-bios.fd), a 2 MB Management Engine region (region-me.fd), and empty GbE/PDR regions — plus the carved FFS files underneath. The BIOS region is where the setup form lives.

Extract the setup forms (IFR)

UEFI menus are stored as IFR — Internal Form Representation — a bytecode describing every question, its variable, and the conditions under which it shows. IFRExtractor RS turns that bytecode back into readable text:

IFRExtractor RS v1.6.1 - extracts HII string and form packages in UEFI
Internal Form Representation (IFR) from a binary file into human-readable text

The main Setup formset comes out as roughly 18,000 lines. Somewhere in there is VT-d.

Find the variable

Every setup question writes into a named variable store. The one that matters:

VarStore Guid: EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9, VarStoreId: 0x1, Size: 0xE42, Name: "Setup"

And the VT-d question itself:

OneOf Prompt: "VT-d", Help: "VT-d support on Intel platforms provides the capability
to ensure improved isolation of I/O resources...",
QuestionId: 0x19, VarStoreId: 0x1, VarOffset: 0x481, Size: 8, Min: 0x0, Max: 0x1
    OneOfOption Option: "Disabled" Value: 0, Default, MfgDefault
    OneOfOption Option: "Enabled" Value: 1

That is the whole answer. VT-d is one byte in the Setup store, GUID EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9, at offset 0x481: 0 disabled, 1 enabled. It appears twice in the forms (QuestionId 0x19 and 0x9A9) but both instances point at the same offset, so there is one bit of state to change.

VT-x, if you want it too, is right next door:

OneOf Prompt: "Intel(R) Virtualization Technology",
QuestionId: 0x9A8, VarStoreId: 0x1, VarOffset: 0x18D

Why the menu never shows it

The option is not missing — it is deliberately hidden, in two different forms. In the CPU Configuration menu it is wrapped in an unconditional suppress:

SuppressIf
    True
    OneOf Prompt: "VT-d", QuestionId: 0x9A9, VarStoreId: 0x1, VarOffset: 0x481

SuppressIf True means “always hide this.” In the System Agent Configuration form it is gated on other questions instead:

SuppressIf
    EqIdVal QuestionId: 0xAA8, Value: 0x0
    GrayOutIf
        EqIdVal QuestionId: 0xA10, Value: 0x1
        OneOf Prompt: "VT-d", QuestionId: 0x19, VarStoreId: 0x1, VarOffset: 0x481

Hidden when 0xAA8 is 0, grayed out when 0xA10 is 1. Either way, the UI will not let you reach the byte. But the byte does not care about the UI.

Flipping it

Since the question is only hidden at the presentation layer, the fix is to write the variable directly and skip the menu entirely. With the GUID and offset in hand it is a one-liner in a setup_var-style grub shell: set Setup offset 0x481 to 1, save, reboot. The firmware reads the same byte the hidden menu would have written, and VT-d comes up enabled.

What this dump captures is the discovery half — image pulled, regions carved, IFR extracted, the exact variable pinpointed. The write is the easy part once you know precisely which byte to touch, which is the entire point of reading the firmware instead of guessing at it.