On 2015-03-27 15:40, Laszlo Ersek wrote:
> On 03/27/15 16:07, Gordan Bobic wrote:
>> On 2015-03-27 12:58, Laszlo Ersek wrote:
>>> On 03/27/15 13:27, Gordan Bobic wrote:
>>>> On 2015-03-27 09:39, Laszlo Ersek wrote:
>>>>>>
>>>>>> Return (VROM)
>>>>>> }
>>>>>> }
>>>>>> }
>>>>>
>>>>> The end result is that the caller should call _ROM in a loop,
>>>>> updating
>>>>> the start offset, and stop when the returned buffer size is smaller
>>>>> (potentially: zero) than the requested read size. This _ROM loop
>>>>> will be
>>>>> served from the memory range starting at (0x9CF9C018 + 4), for the
>>>>> number of bytes that can be read from the UINT32 at 0x9CF9C018.
>>>>>
>>>>> If a copy of the actual ROM in question is available, then one
>>>>> might be
>>>>> able reimplement the _ROM method: define a Buffer of bytes, listing
>>>>> the
>>>>> actual bytes comprising the ROM image, and then serve the _ROM
>>>>> invocations from *that*, instead of the VBOR operation region's
>>>>> VBSx
>>>>> fields. And the RVBS references can be replaced with a known
>>>>> constant.
>>>>
>>>> Right. So what would be the correct way to embed a 103936 byte BIOS
>>>> payload inside the _ROM method?
>>>
>>> Please consult the ACPI spec. You should create a named Buffer object
>>> with open-coded byte contents (*), then rebase the existing _ROM
>>> logic
>>> on top of that object. Build the new SSDT with iasl, then pass it to
>>> qemu with the -acpitable switch, as Gerd recommended. QEMU should
>>> then
>>> expose that custom table too to OVMF, and OVMF should install it for
>>> the
>>> guest OS.
>>>
>>> ((*) As an example, refer to
>>>
>>> Name (VROM, Buffer (Local1)
>>> {
>>> 0x00
>>> })
>>>
>>> in the iasl output. See also "19.5.10 Buffer (Declare Buffer Object)"
>>> in
>>> the ACPI spec.)
>>>
>>> I'm not suggesting this is easy -- to the contrary. In particular
>>> because the SSDT that you decompiled has a bunch of other code in it,
>>> with many OperationRegions and Externals.
>>>
>>> In particular, there's a whole bunch of open-coded address constants
>>> in
>>> the SSDT. One of those is
>>>
>>> OperationRegion (VBOR, SystemMemory, 0x9CF9C018, 0x00019604)
>>
>> I was rather hoping, as a first pass, to simply statically encode the
>> payload into a binary string
>
> Yes, indeed, that is part of the idea. And, as I said below, the VBOR
> opregion would actually be obviated (removed) by implementing the idea.
> (But, there are other opregions with hard-coded addresses that would
> remain!)
>
>> and have the _ROM method simply return
>> that. Would that not work?
>
> No, this part would not. You can't return the *entire* expansion ROM in
> one _ROM method invocation. _ROM basically corresponds to pread(), in
> POSIX speak. You must take an offset to read from, and a target buffer
> size that the caller wants to get in return. (Obviously the analogy is
> very incomplete, but the point is that _ROM needs to take start offset
> and buffer size parameters.)
>
> What you could do is embed the full ROM as *another* named Buffer
> object
> in the SSDT, and then serve the _ROM invocations (which are basically
> pread() calls) from that buffer, instead of the VBSx arrays.
>
>>> itself, which you would replace with the explicit Buffer object.
>>> However, there are others, for example:
>>>
>>> OperationRegion (SGOP, SystemMemory, 0x9CFBBE98, 0x00000054)
>>>
>>> The hardcoded address constant in the AML code very strongly suggests
>>> that this AML payload was entirely composed, or partially patched, by
>>> the laptop vendor's firmware *dynamically* during boot, dependent on
>>> system RAM size, video card characteristics, PCI window
>>> characteristics,
>>> whatever. To replay that in the guest, you'd probably have to
>>> reimplement most of that logic in OVMF and/or qemu. '-acpitable' is
>>> good
>>> only if you have a static AML blob.
>>
>> I am 99% certain it is not being patched at runtime, because what
>> nouveau pulls out and makes available as
>> /sys/kernel/debug/dri/<id>/vbios.rom
>> is exactly identical to the firmware blob I pulled out of the
>> system firmware.
>
> I don't know how that tool that you used to pull the firmware blob out
> of the system firmware works. If it is reading live tables from system
> memory, then it doesn't prove anything. The patching could happen
> inside
> the system firmware before even grub is booted.
It operates on the firmware update blob provided by Lenovo as a BIOS
update. It doesn't go anywhere near a running system.
> The only way this method would prove anything is if you had the entire
> system firmware *as a file* on your host (from some reliable source),
> and the extractor fetched this exact ROM image from that static file.
That is exactly what I did - a whole system firmware rom file from
the manufacturer supplied BIOS update.
> (Alternatively, if the extractor fetched the embedded ROM image
> directly
> from read-only flash.)
>
>> Having said that, the system firmware does include no fewer than 3
>> Nvidia BIOS-es with different version numbers, so I suspect what is
>> happening there is the firmware figuring out which of the three it
>> should use for the card that is present.
>>
>>> So, I think your card is simply unusable for passthrough. It is
>>> strongly
>>> tied to your proprietary system firmware, instead of carrying its
>>> own,
>>> well-isolated option ROM.
>>
>> Which does kind of present another possibility. Nvidia cards,
>> according
>> to what nouveau driver does, offer 3 methods of getting the VBIOS out:
>> 1) PRAMIN (read it from the particular place in VRAM)
>
> If it can be just read from the video RAM, then why doesn't that work
> in
> a guest? It doesn't seem to be much different from reading the ROM
> image
> from the dedicated PCI ROM bar.
That is essentially what is supposed to happen.
The problem is that although I can verify with nvagetbios that the
BIOS stuck in VRAM appropriately, once I invoke it on the device
once the VM claimed it, I get back garbage, which implies either that
something happens that clobbers that area of VRAM or that the
register containing the pointer to the relevant VRAM block gets
clobbered.
>> It has been suggested that if I use a driver to initialize the RAM,
>> then use nvafakebios to load the BIOS blob into the PRAMIN, and then
>> start the VM.
>
> I have no clue what nvafakebios does. I found the source but none of it
> is documented.
It takes the BIOS blob and loads it into PRAMIN. It is generally
used for testing the nouveau driver without having to reboot the
machine or reflash the BIOS to reverse engineer the contents of
various data tables.
nvagetbios does the opposite, it dumps the BIOS, by default
from PRAMIN, but also knows how to get it from the PROM
(for some PROMs at least).
>> But it doesn't appear to have worked - seems something
>> seems to clobber the BIOS payload along the way.
>>
>> 2) PROM (read it from the supported PROM)
>> Short of writing a qemu emulation for one, I'm not sure there's a
>> way to make use of this.
>>
>> 3) ACPI
>>
>>> With a separate add-on card, the vendor simply can't put the option
>>> ROM
>>> anywhere else than on the card itself, but with an integrated card,
>>> they
>>> can apparently pull sh*t like this.
>>
>> See above - it isn't all that messed up, the output is completely
>> clean.
>
> Fine. Then you can start hacking the SSDT, as discussed before :)
Yup, need to go read up more on ACPI stuff, and work out what gets
presented by QEMU by default. If there are any data blobs already at
predefined addresses, I expect I'll have to make sure that I don't
clobber them with the BIOS payload.
Thanks for your help guys, most appreciated. :)
Gordan
------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel