Post by Heyi GuoHi Laszlo and Ard,
As you two are the new maintainers for ArmVirtPkg, I suppose you are the
right persons to ask this question :)
I'm running UEFI SCT aganst QEMU aarch64, and I got error for functional
test against HII_CONFIG_ACCESS_PROTOCOL installed in PlatformDxe module.
The test case is BBTestRouteConfigFunctionTestCheckpoint1 in
TestCase/UEFI/EFI/Protocol/HIIConfigAccess/BlackBoxTest/HIIConfigAccessBBTestFunction.c;
it will construct the configuration in some way (sorry I'm not familiar
with HII and not understand the process clearly), and then call
RouteConfig of HII_CONFIG_ACCESS_PROTOCOL.
Well, "some way" is certainly the key question here.
Post by Heyi GuoGUID=1cc53572800cab4c87ac3b084a6304b1&
NAME=004d00610069006e0046006f0072006d00530074006100740065&
PATH=01041400dfc5dcd907405e4390988970935504b27fff0400&
OFFSET=0000&
WIDTH=0020&
VALUE=00000000000000000000000000000000000000000000007400650073006e0055
Okay, it's been a very long time since I've last looked at HII config
strings. In any case, if you play with PlatformDxe (go to Device Manager
| OVMF Platform Configuration, play with the preferred resolution),
*and* you have build OVMF / ArmVirtPkg with sufficiently long debug
messages enabled, then you will see debug messages like:
ExtractConfig: Request="GUID=1cc53572800cab4c87ac3b084a6304b1&
NAME=004d00610069006e0046006f0072006d00530074006100740065&
PATH=01041400dfc5dcd907405e4390988970935504b27fff0400&
OFFSET=0&
WIDTH=0024"
ExtractConfig: Results="GUID=1cc53572800cab4c87ac3b084a6304b1&
NAME=004d00610069006e0046006f0072006d00530074006100740065&
PATH=01041400dfc5dcd907405e4390988970935504b27fff0400&
OFFSET=0&
WIDTH=0024&VALUE=000000000000000000000000000000000000000000000030003800340078003000340036"
The GUID that you can see is gOvmfPlatformConfigGuid, and it is used in
"OvmfPkg/PlatformDxe/Platform.c" as the formset GUID. So basically the
GUID just identifies the formset for which the HII message is for.
The NAME entry is hexadecimal encoding for the CHAR16 string
"MainFormState". "MainFormState" is the name of the object that stores
the state of the form / widget in binary representation. The type is
MAIN_FORM_STATE, declared in "OvmfPkg/PlatformDxe/Platform.h". The form
definition in "OvmfPkg/PlatformDxe/PlatformForms.vfr" defines the object
with name "MainFormState", with type MAIN_FORM_STATE, as the state of
the form.
(You can see some -- hopefully -- enlightening messages in the commit log:
git log -- OvmfPkg/PlatformDxe/ | less
)
I'm unsure about PATH, it probably partakes in identifying the form
within the formset, or some such.
In any case, OFFSET, WIDTH, and VALUE describe the contents of
MainFormState, in binary representation (well, a subset thereof). You
can see in "OvmfPkg/PlatformDxe/Platform.h" that the size of
MAIN_FORM_STATE is (2 * 16 + 4) == 30 == 0x24. That means that the above
OFFSET, WIDTH and VALUE fields define the complete contents of
MAIN_FORM_STATE.
//
// This structure describes the form state. Its fields relate strictly
// to the visual widgets on the form.
//
typedef struct {
UINT16 CurrentPreferredResolution[MAXSIZE_RES_CUR];
UINT32 NextPreferredResolution;
} MAIN_FORM_STATE;
The "CurrentPreferredResolution" field is a CHAR16 string; it
corresponds to the (read only) text field that you see on the form to
the right of the "Preferred Resolution at Next Boot" label. Its maximum
size is MAXSIZE_RES_CUR==16 UCS2 characters, including the terminating
L'\0'.
The "NextPreferredResolution" field is an index into the dynamically
gathered list of resolutions that the firstly registered GOP supports.
You can see this selection to the right of the "Change Preferred
Resolution for Next Boot" label.
(These two fields are separate on the form because
CurrentPreferredResolution is parsed from non-volatile variable data: it
can be unset to begin with, plus it can be a resolution that is not even
*found* in the GOP's list. This might happen eg. if you change the model
of the emulated video card, or change its video RAM size. Whereas the
drop-down list offers the currently available GOP modes. So you pick
your preferred resolution, select "Commit Changes and Exit", and
(ultimately) reboot the VM.)
Above I quoted the ExtractConfig messages; such messages relate to the
form engine / display browser extracting configuration from drivers, so
that the form state can be updated for display. (Refer to SVN r15374.)
The other direction is called "RouteConfig" (see SVN r15375), when the
form engine updates *part* of the form state (thereby updating part of
the preexistent driver configuration). This is triggered when you hit
Enter on "Commit Changes and Exit" (see how the QUESTION_SAVE_EXIT entry
is hooked up to EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT, in the VFR
file and in Callback()) *and* the state actually changed.
For example, if you change the NextPreferredResolution dropdown list
index from 0 to 1, the form engine will send down the following config
string:
RouteConfig: Configuration="GUID=1cc53572800cab4c87ac3b084a6304b1&
NAME=004d00610069006e0046006f0072006d00530074006100740065&
PATH=01041400dfc5dcd907405e4390988970935504b27fff0400&
(the usual stuff)
OFFSET=0000&
WIDTH=0020&VALUE=0000000000000000000000000000000000000030003800340078003000340036&OFFSET=0020&
WIDTH=0004&
VALUE=00000001"
Aha! So it sends the first 32 bytes (the CurrentPreferredResolution UCS2
string) first, then the value of the UINT32 NextPreferredResolution
index second.
Our RouteConfig() handler performs a read-modify-write cycle in response
-- that's necessary because the config update can be partial in general.
See again r15375.
Alright, now we understand what's what.
Apparently, the test case is trying to send down the following config
Post by Heyi GuoOFFSET=0000&
WIDTH=0020&
VALUE=00000000000000000000000000000000000000000000007400650073006e0055
wich means
set the 'CurrentPreferredResolution' string of the form state to
'<bunch of zeroes>tesnU'
Obviously, our RouteConfig() handler ignores any "changes" to this
string -- the string is marked READ_ONLY on the form to begin with, it
only serves display purposes. So we have:
RouteConfig()
// READ
PlatformConfigToFormState()
PlatformConfigLoad()
GetVariable2()
gRT->GetVariable()
// MODIFY (may be partial)
gHiiConfigRouting->ConfigToBlock()
// WRITE
FormStateToPlatformConfig()
PlatformConfigSave()
gRT->SetVariable()
Post by Heyi GuoI traced the code and found it failed in FormStateToPlatformConfig in
Platform.c, due to mNumGopModes being 0.
if (MainFormState->NextPreferredResolution >= mNumGopModes) {
return EFI_INVALID_PARAMETER;
}
Yes. Near the end of this RMW cycle, the NextPreferredResolution field
is 0. That's because no GOP has been installed yet, so the READ part --
regardless of the existence of the non-volatile variable that stores the
preferred resolution -- leaves NextPreferredResolution at zero. After
all there is no list of resolutions to search, and determine the index
of the current preference.
In addition, in the MODIFY part, the config string that the tester app
sends down doesn't cover NextPreferredResolution at all (that would be
OFFSET=0020, WIDTH=0004).
This is not a problem per se. For example, if the non-volatile variable
states 2048*2048 as your current (last) preference, but your new video
ram setting (from the QEMU side) only allows a max resolution of
1024x768 (just making up the numbers now), there's no way 2048*2048 will
be found in the list. In this case, the list index will be left at zero,
as initial choice.
Now, since we're *routing* the config, that means the user has actually
selected "Commit". In this case the resolution at index zero (which is
usually 640x480) will be looked up from the list of resolutions that the
GOP advertised, and written to the non-volatile variable.
Post by Heyi GuoI suppose GOP related data will be initialized when
gEfiGraphicsOutputProtocolGuid is installed,
Yes. Routing *any* config (ie. committing any selection made on the
form) makes no sense if the resolution list is empty. You cannot select
an element in that empty list at any subscript. You cannot derive the
preferred next resolution, and you cannot write it to the non-volatile
variable.
This is why FormStateToPlatformConfig() returns EFI_INVALID_PARAMETER:
the form state is untranslateable to platform configuration.
In normal operation, this can never happen, because using the form, you
can never trigger a RouteConfig unless at least one resolution has been
collected.
Basically, the tester utility is sending a RouteConfig message with
invalid, nonsensical configuration. It says "leave
NextPreferredResolution at its current value, *and* make that
configuration permanent". Well, the configuration corresponding to the
current value of NextPreferredResolution *cannot* be made permanent,
because it makes no sense. It's an index into something that has not
been initialized yet.
Post by Heyi Guo1. Shall I enable vga on qemu to pass this test?
Yes.
Post by Heyi GuoHow to enable vga? I
tried -display sdl -vga std, but nothing changed.
Build ArmVirtQemu with -D INTEL_BDS, and then pass the following options
to QEMU:
-M virt -cpu cortex-a57 -display sdl -device VGA
Post by Heyi Guo2. Can we modify the code to make it not depend on GOP?
No.
I don't know how the tester utility composes the config string, but it
can't just send down (a seemingly random) one, and expect the driver to
bend over backwards and make it permanent.
We could probably hack it around, by postponing the installation of the
EFI_HII_CONFIG_ACCESS_PROTOCOL instance from the entry point of the
driver (PlatformInit()) to the GOP installation callback
(GopInstalled()). This would simply prevent the tester utility from
finding the RouteConfig() function, because until after GOP installation
PlatformDxe would simply not expose itself as HII-accessible.
However, until someone provides evidence that OvmfPkg/PlatformDxe/,
as-is, breaks an HII rule, I'm not willing to write such a patch. I'll
have to be shown why the tester utility is in its right to do what it
does, and why PlatformDxe is wrong to reject it.
Post by Heyi GuoPlease kindly help with this issue and correct me if there is anything
wrong in my understanding.
I hope the above helps.
Thanks
Laszlo
------------------------------------------------------------------------------