Skip to content

ci: fix the toolchain check and the secboot firmware build on current runners - #29

Draft
xaionaro wants to merge 56 commits into
mainfrom
ci-fixes
Draft

xaionaro wants to merge 56 commits into
mainfrom
ci-fixes

Conversation

@xaionaro

Copy link
Copy Markdown
Member

Draft for a CI run
before main moves. Two fixes on top of the current local stack: scripts/check-toolchain.sh compares cargo --version instead of file identity (macOS/Windows jobs), and build-secboot-firmware.sh
builds edk2's BaseTools with gcc 15 by taking EfiRom.c as edk2 9af06ef3 left it (test-e2e-qemu on i686/aarch64; run 43072118590).

`hii keyword set` refused every STRING before its VALUE. It now takes
one as `set` takes its text.

SetData() writes a VALUE as given: edk2-stable202608
ConfigKeywordHandler.c takes a STRING as wide as its MaxSize CHAR16s
(GetWidth :1643-1644) and appends the VALUE (:2248), and ConfigRouting.c
HiiConfigToBlock reads its digits last first (GetValueOfNumber :518) and
copies that many bytes (:6353). So a STRING's VALUE holds all MaxSize
CHAR16s, last byte first, as `hii keyword get` prints them: "AB" of
MaxSize 4 is 0000000000420041. That is edk2's order, which keyword get
and set already take for the other kinds, and the reverse of UEFI 2.11
§35.2.1.5, which lists a <Number>'s bytes in memory order; the README
names it.

check_set takes the text that the VALUE holds up to its first NULL, as
get reads it, and refuses a UTF-16 surrogate there. It writes that text
with set's StringInput::write and string_own_write, so set's refusals
apply: MinSize, MaxSize, whose last CHAR16 holds the NULL, a line break
in a single-line STRING, the Private Use Area. A VALUE that is not the
bytes that set writes for the text, NULL-padded (UEFI 2.11 §33.2.5.4.9),
such as one with a character after the NULL, fails check_set's existing
comparison, and one of another width its GetWidth check. UEFI 2.11
§33.2.5.4.9 represents a STRING's result as its characters and the
terminating NULL, but a VALUE of fewer bytes than MaxSize CHAR16s is
refused: ConfigRouting.c HiiConfigToBlock copies the question's width
(:6353) from a buffer of half the VALUE's digits (GetValueOfNumber
:508-509), which the firmware would read past; the README says so. The
refusals that the other kinds share apply too: EFI_IFR_FLAG_CALLBACK, a
WRITE expression, storage that no variable holds, &READONLY, a read-only
question, the bytes of a password; a declared setup password needs
--i-am-fine-to-brick-this-system.

The internal-inconsistency refusal of an ORDERED_LIST whose description
holds another TextInput now serves a STRING too, and names both
TextInputs by a TextInputKind.

Test Plan:
- RED: these tests on the parent's code, 6 failed (1479 passed), each on
  "uefisettings does not yet implement keyword set of EFI_IFR_STRING":
  check_set_takes_a_string_value_as_set_takes_its_text,
  check_set_refuses_a_string_value_that_set_refuses_or_would_not_write,
  check_set_refuses_a_string_over_the_bytes_of_a_password,
  check_get_takes_string_date_time_and_ordered_list_but_not_password,
  set_of_a_string_with_a_declared_password_needs_the_flag and
  set_refuses_a_string_beside_a_password_of_var_store_id_0.
- strings_set_by_keyword_as_by_prompt is a characterization test, which
  passes on the parent too: `set --keyword` of a STRING already writes
  its text as `set` by prompt does, NULL-padded, and nothing for a text
  that set refuses.
- keywords.rs: check_set_takes_a_string_value_as_set_takes_its_text
  takes no character, "AB", MaxSize - 1 characters, a line feed in a
  multi-line STRING, a Common Control Code and " A ", its spaces kept.
  check_set_refuses_a_string_value_that_set_refuses_or_would_not_write:
  refused are 4 characters, fewer than MinSize, a line feed in a
  single-line STRING, U+E000, a surrogate, a character after the NULL,
  fewer bytes than MaxSize CHAR16s, a read-only STRING,
  EFI_IFR_FLAG_CALLBACK, &READONLY, a WRITE expression and name/value
  storage; the last 4 pin refusals that the parent makes before the kind
  as well.
  check_set_refuses_a_string_over_the_bytes_of_a_password: refused where
  its last CHAR16 overlaps a password, taken beside it.
  check_get_takes_string_date_time_and_ordered_list_but_not_password:
  set of a STRING's one-byte VALUE is now refused as not as wide as its
  question.
- keyword_access.rs:
  set_of_a_string_with_a_declared_password_needs_the_flag replaces
  set_refuses_a_string_before_the_setup_password: refused without the
  flag, before any call; U+E000 refused with set's error with and
  without it, before the setup password's refusal; with it, one
  SetData() of the VALUE, a GetData() that reads it back, and the setup
  password lifted.
  set_refuses_a_string_beside_a_password_of_var_store_id_0: beside a
  PASSWORD of VarStoreId 0, EFI_IFR_FLAG_CALLBACK or not, set of a
  STRING with the flag is refused with that PASSWORD's record through
  variables of either reach, with no variable read and no call, as the
  parent refuses it; beside a PASSWORD on Store that ends before it, one
  SetData() writes the VALUE, which the parent refuses. Its PASSWORDs
  come from flagged_password_on, a new fixture of ifr_fixtures.rs:
  password_on with question Flags.
- cargo test --lib: 1485 passed.
- 15 mutants, at the next commit's tree, whose src/ is this commit's; 14
  fail named tests: the VALUE's bytes written as given, the text
  dropped, a surrogate taken as no text, the width check or the
  comparison skipped for a STRING, GetWidth one CHAR16 wider, &READONLY
  or EFI_IFR_FLAG_CALLBACK taken for a STRING, EFI_IFR_FLAG_CALLBACK
  taken on every set, U+2028 taken in a single-line STRING, the text
  trimmed, or trimmed at its end, the setup password refused before the
  keywords' checks, and check_question's refusal of a WRITE expression
  skipped for a STRING, which string_own_write then refuses with its own
  error. The 15th has string_write pass VariableReach::Runtime, which
  only a question without a VarStore reads (QuestionDescriptor::store),
  and check_question refuses VarStoreId 0 first: it changes nothing.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
publish-hiidb's keyword-kinds-forms gains KindString, a STRING of
MaxSize 4 at VarOffset 34 of KindStore, and KindText, a multi-line
STRING (EFI_IFR_STRING_MULTI_LINE) of MaxSize 4 at 42, each with an
x-UEFI-ns keyword. KindStore's VarStore, and the variable that the
driver creates, grow to 50 bytes, the STRINGs empty.

In the UEFI Shell, shell-keyword-kinds now:
- sets KindString to "AB" with VALUE=0000000000420041, which dmpstore
  shows as 41 00 42 00 00 00 00 00 at offset 34 and `hii keyword get`
  reads back as the same VALUE;
- sets KindText to "A", LF, "B" with VALUE=00000042000a0041;
- refuses before any call VALUEs of KindString of 4 characters, of a
  character after the NULL, of U+E000, of a UTF-16 surrogate, of a line
  feed, of 2 CHAR16s and with &READONLY, each with its error, and
  dmpstore shows KindStore unchanged after each.
dmpstore-before checks the new DataSize and the empty STRINGs.

Test Plan:
- make -k test-e2e-qemu-shell-x86_64 SCENARIOS=shell-keyword-kinds
  passes every check of its 38 steps.
- QEMU carries over from runs before a conflict-free rebase onto the
  current main and before the previous commit's test-only and README
  changes: shell-keyword-kinds passed every check on x86_64, i686 and
  aarch64.
- Before an earlier conflict-free rebase, onto 5 later commits of main,
  and before the previous commit gained a unit test and a doc comment:
  the whole make -k test-e2e-qemu-x86_64 and test-e2e-qemu-shell-x86_64
  sets passed, in 6 runs of their scenarios: 108 boot, and 4 that only
  i686 boots skip. With this commit alone on the previous commit's
  parent then, x86_64 failed 13 checks, where the steps assert keyword
  set of a STRING: set-string (status and line), dmpstore-string,
  get-string, which reads VALUE=0000000000000000, set-text (status and
  line), dmpstore-text, and the errors of set-string-too-long,
  set-string-unwritten, set-string-private-use, set-string-surrogate,
  set-string-line-break and set-string-width, each "uefisettings does
  not yet implement keyword set of EFI_IFR_STRING".
  set-string-read-only-resp passed there, as &READONLY is refused before
  the kind.
- make -k lint passes; make -k test: 1579 passed; make test-i686: 1576
  passed; cargo test --lib: 1485 passed.
- The Windows emulation of the tests: 884 passed, where the previous
  commit's parent passes 879; the one test that it passes and this tree
  lacks is the one that the previous commit replaces.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
…d VarStoreId

A PASSWORD's VarStoreId names "a previously declared variable store"
(UEFI 2.11 §33.3.8.2.2), and VarStores are declared within a form set
(§33.2.5.1). For an id that no VarStore of its form package declares,
edk2-stable202608 finds no storage: the Forms Browser looks only in its
FormSet's storage list, then ASSERTs and dereferences what it found
(SetupBrowserDxe/IfrParse.c:136-153), and the Config Keyword Handler
walks only its form package (HiiDatabaseDxe/ConfigKeywordHandler.c
FindStorageFromVarId, :1520-1569) and ASSERTs on the NULL that it
returns (:2108-2109). Until now such a PASSWORD was unresolved but kept
by its IFR (Keeper::Ifr): through BootServices its HiiDB was refused,
but through Runtime get, set, list-questions, show-ifr and dump-efivars
read and wrote every variable of its HiiDB, with a warning only, and
keyword get and set called GetData() and SetData().

It is now driver-held, as one of VarStoreId 0 is: VarStoreIds::keeper
gives Keeper::OwnDriver to an id that no VarStore of its form package
that decodes declares (FirstVarStores::declared), so check_bounded
refuses every variable through Runtime too; through BootServices the
HiiDB stays refused as before.

- So is one in a disabled form, outside any FormSet, in IFR that
  uefisettings ignores, whose record names the VarStoreId, or whose
  question header past its op names such an id, and one whose id only
  another form package or another package list declares.
- FindStorageFromVarId reads the VarStoreId field of a VarStore op
  whatever the op's Length (:1538-1555), and so does the Forms Browser
  for one of the question's FormSet outside an unknown opcode's scope
  (IfrParse.c:1873-1918), so either would take one that does not
  decode; an id of only such an op is refused too, which fails closed.
- An id that another FormSet of its form package, or a VarStore outside
  any FormSet, declares stays bounded by the first VarStore of that id,
  which the Config Keyword Handler takes, as does one that its own
  FormSet declares after it.
- Variables that read nothing are not refused, so list-questions and
  show-ifr with --no-efivars still read such a HiiDB.
- --i-am-fine-to-brick-this-system lifts none of it, as it lifts no
  confidentiality refusal.
- README.md says so, and the docs that list the driver-held cases name
  it.
- The test helper of the driver-held refusals checks show-ifr through
  Runtime too, so it does for PASSWORDs of VarStoreId 0 and for those
  that edk2 may route to a VARSTORE_NAME_VALUE as well.

Test Plan:
- With this commit's tests on the product code of its parent, cargo test
  --locked --lib fails 6 tests and passes 1479:
  passwords_of_undeclared_var_store_ids_close_every_variable,
  a_password_of_an_id_that_only_another_form_package_declares_closes_every_variable,
  a_headless_password_in_a_disabled_form_closes_every_variable,
  dump_refuses_a_hiidb_with_a_password_of_an_undeclared_var_store_id,
  get_and_set_refuse_beside_a_password_of_an_undeclared_var_store_id and
  password_without_a_known_var_store_is_unresolved; there get reads a
  question beside such a PASSWORD, dump-efivars copies its VarStore,
  keyword get calls GetData() and its record is not driver-held. Run
  alone there, the case of an id of only a VarStore op of its FormSet
  that does not decode fails too: get reads B.
- At this commit, cargo check --locked --all-targets passes, and cargo
  test --locked --lib passes 1485, both with RUSTFLAGS=-D warnings.
- 17 mutants each fail named tests: keeper's form-package check off, its
  package-list fallback taking every id, a form package without a
  VarStore that decodes counted as declaring every id, the ids of
  VarStores outside any FormSet left out of FirstVarStores::declared,
  the ids of the other form packages of the list counted, for any
  PASSWORD, for one whose question header lies past its op, or for one
  outside any FormSet, a VarStore op that does not decode counted as
  declaring, in the PASSWORD's FormSet or anywhere, an undeclared id
  outside any FormSet kept bounded, an id that another FormSet declares
  counted as undeclared, add_outside's record of one in IFR that
  uefisettings ignores, a BootServices read beside a driver-held
  PASSWORD, variables that read nothing refused, dump-efivars without
  check_bounded, and show-ifr or list-questions falling back to
  variables that read nothing where a read through Runtime is refused.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
publish-hiidb's undeclared-password-forms registers two package lists
for one handle with a device path, as storageless-password-forms does.
The first list's form set declares the buffer VARSTORE UdBacking,
VarStoreId 1, with a UINT32 NUMERIC over its bytes 0..4, of the
x-UEFI-ns keyword UndeclaredSetting, and a PASSWORD of VarStoreId 9,
which no VarStore of its form package declares, so it names no
VarStore (UEFI 2.11 §33.3.8.2.2 asks for "a previously declared
variable store"); the second list's form set has a UINT16 NUMERIC over
the buffer VARSTORE Other. vars/undeclared-password.json creates
UdBacking, whose bytes 0..4 hold 0x7A4C19E3, standing for a password
that the PASSWORD's driver keeps there, and Other.
rt-data-undeclared-password-forms publishes the database for Linux
too, and export-config-undeclared-password installs ExportConfig()'s
results, as export-config does, with a <ConfigResp> of UdBacking
holding 0x7A4C19E3. The PASSWORD's prompt has no x-UEFI-ns keyword,
and UdBacking is a buffer VARSTORE, so edk2 resolves the PASSWORD's
storage neither when it registers the forms
(edk2-stable202608 HiiDatabaseDxe/Database.c:887-1013) nor when it
exports their configuration (ConfigRouting.c:5485-5537), where it
would ASSERT (SetupBrowserDxe/IfrParse.c:148,
ConfigKeywordHandler.c:2109).

hii-undeclared-password checks that Linux refuses get of each NUMERIC,
list-questions, show-ifr, set, also with
--i-am-fine-to-brick-this-system, which warns of nothing, and
dump-efivars with the refusal of a HiiDB whose PASSWORD may keep its
password in any variable, naming the PASSWORD, writing neither
UdBacking nor Other and creating no dump directory, that
list-questions --no-efivars lists the questions of both lists, that no
output shows 0x7A4C19E3, and that the debug log says that the firmware
lists no ExportConfig snapshot; hii-undeclared-password-snapshot
checks the same with the snapshot, which the debug log then does not
say, and that no output shows a value of it. shell-undeclared-password
checks that uefisettings.efi in the UEFI Shell refuses hii get of
either list's NUMERIC, keyword get of UndeclaredSetting,
list-questions, and keyword set of UndeclaredSetting and set with
--i-am-fine-to-brick-this-system, naming the PASSWORD and warning of
nothing, that UdBacking stays as it was, and that no output shows
0x7A4C19E3. All three boot on x86_64, i686 and aarch64.

Test Plan:
- With this commit alone on its parent before main's history was
  rebased, on x86_64 hii-undeclared-password and
  hii-undeclared-password-snapshot fail 4 of their 5 tests each: get and
  list-questions show 2051807715, the value of UdBacking's bytes 0..4,
  and set and dump-efivars succeed; shell-undeclared-password passes
  there, as the UEFI Shell build already refuses a HiiDB with a PASSWORD
  whose VarStore is unknown, so it guards against a regression and shows
  that the firmware boots this IFR.
- With this series on that parent, hii-undeclared-password,
  hii-undeclared-password-snapshot and shell-undeclared-password pass on
  x86_64, i686 and aarch64, and every row of tests/qemu/scenarios.tsv
  passes on x86_64: 116, and 4 that their architecture rule skips, in
  130 boots. Those runs carry over: since then the series rebased onto
  its current parent without conflicts, and "fix(hii): read no variable
  of a HiiDB with a PASSWORD of an undeclared VarStoreId" changed only
  doc comments, README.md and unit tests.
- At this commit, cargo check --locked --all-targets passes and cargo
  test --locked --lib passes 1485; make -k lint passes; make -k test:
  1579 passed; make test-i686: 1576 passed; the tests of the Windows
  build, run on Linux under its cfgs: 883 pass, 4 more than the 879 on
  the parent of "fix(hii): read no variable of a HiiDB with a PASSWORD
  of an undeclared VarStoreId", and none that passes there fails here;
  the one that runs only there is the test that it renames.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
UEFI 2.11 §33.2.5.4.9 gives the results of a string question as a hex
dump of the string, and a <NvConfig> holds a <String> of 4 hex digits
per <Char> (§35.2.1.2, §35.2.1.4). The ExportConfig() snapshot kept the
settings of name/value storage as numbers only, so a STRING there showed
no value.

The snapshot now keeps each <NvConfig> as given, and a question reads it
as a number or, for a STRING, as CHAR16s, most significant digit first,
as edk2-stable202608 SetupBrowserDxe/Setup.c BufferToValue reads them
(:1564-1579): up to a NULL or MaxSize characters, NULLs past them
dropped, an empty setting an empty string. Digits that are no <String>,
whose last CHAR16 BufferToValue would take from fewer than 4 digits
(:1571-1573), or characters other than NULL past MaxSize, which it would
cut (:1557-1561), give no value; the decoder of those digits is the one
that reads NAME, OPTIONSTRING and DISPLAYNAME. A numeric question of an
empty setting gives none either, as BufferToValue writes no number for
it (:1580-1590). A PASSWORD that edk2 may route to a
VARSTORE_NAME_VALUE, one of VarStoreId 0, or one whose VarStore is
unknown keeps the snapshot off as before, so no STRING of any
VARSTORE_NAME_VALUE shows beside it.

Test Plan:
- cargo check --locked --all-targets and cargo test --locked --lib,
  RUSTFLAGS='-D warnings': 1492 passed, 3 of them new or changed:
  - nv_config_reads_its_digits_as_a_string;
  - name_value_strings_take_their_characters_from_the_snapshot, which
    replaces name_value_strings_take_no_snapshot_value, with a CHECKBOX
    of an empty setting and an ORDERED_LIST, which reads its setting as
    a number;
  - name_value_strings_keep_to_the_password_refusals: STRINGs beside no
    PASSWORD, one on Backing, one routed to a VARSTORE_NAME_VALUE (on
    that store, on a second one, on the PASSWORD's own name, and from
    another package list of the driver), one of VarStoreId 0 in its
    form and one outside any FormSet, and one of an undeclared
    VarStoreId, which refuses the HiiDB through variables that read
    anything too, through get, list-questions and show-ifr, through
    Runtime and through variables that read nothing.
- With the parent's product code, both exports tests fail on the
  numbers-only reason: 1489 passed, 2 failed. With this product code on
  the parent of d48dfd4, which refused PASSWORDs of VarStoreId 0, each
  VarStoreId 0 case shows "AB <snapshot>" through Runtime.
- Mutants of this commit's product code, each killed by a named failing
  test (22): CHAR16s stored big-endian; characters past MaxSize taken,
  and NULLs past it refused; MaxSize taken in bytes; one character past
  MaxSize taken; the last character within MaxSize dropped; digits that
  fill no <Char> skipped; the digits of each <Char> swapped; the <Char>s
  read in reverse order; digits that are no <String> read as an empty
  string; an empty setting dropped; a missing setting read as zeros; an
  empty numeric setting read as 0; the first setting of a name taken;
  padding with spaces; a setting longer than MaxSize tagged as a read
  error; an ORDERED_LIST read as a string; the snapshot read beside a
  PASSWORD whose VarStore is unknown; a PASSWORD that edk2 may route to
  a VARSTORE_NAME_VALUE kept by its IFR, and leaving the snapshot on; a
  PASSWORD of VarStoreId 0 in a FormSet, and one outside any, kept by
  its IFR.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
publish-hiidb's rt-data-name-value-string-forms registers, for a handle
with a device path, a package list whose VARSTORE_NAME_VALUE has STRINGs
of MaxSize 4 on the names Text, Nul, Full, Padded, Long, Odd and Empty,
a CHECKBOX on Flag and no PASSWORD, then publishes the database as
rt-data does. export-config-name-value-string registers it before it
installs ExportConfig()'s results as export-config does, followed by a
<ConfigResp> of the VARSTORE_NAME_VALUE with Text=00410042,
Nul=004100420000, Full=0041004200430044, Padded=00410042004300440000,
Long=00410042004300440045, Odd=004100, Empty= and Flag=01.
hii_package.rs gains builders of the STRING and VARSTORE_NAME_VALUE
ops, which name_value_password_forms.rs uses too, and that file's first
list gains a STRING on "Pin", the name that its PASSWORD is on.

The scenario hii-name-value-string-snapshot checks that get, with and
without the hii prefix, and hii list-questions give Text and Nul
"AB <snapshot>", Full and Padded "ABCD <snapshot>", Long and Odd their
reasons, Empty " <snapshot>" and Flag "1 <snapshot>", that hii show-ifr
shows those answers, and that with --no-efivars each question says why
it has no value. hii-name-value-string, whose firmware lists no
snapshot, checks that each command gives every question that reason
and that the debug log says the firmware lists none. In
hii-name-value-password and hii-name-value-password-snapshot, get
refuses the STRING on "Pin" too, hii list-questions --no-efivars gives
it the name/value reason, and no output shows U+7A5B or U+C3E1, the
characters that it would read from the snapshot's 7a5bc3e1. All four
boot on x86_64, i686 and aarch64.

Test Plan:
- cargo check --locked --all-targets and cargo test --locked --lib,
  RUSTFLAGS='-D warnings': 1492 passed; cargo check --locked -p
  uefisettings-qemu-guest --features test-vm --tests: exit 0.
- The 8 checks of make -k lint, whose clippy covers the guest tests and
  publish-hiidb: exit 0; make -k test: 1586 passed; make test-i686:
  1583 passed; the Windows emulation of the tests: 890 passed, every
  one of the 888 that pass on the base of this series but
  name_value_strings_take_no_snapshot_value, which the previous commit
  replaces.
- make test-e2e-qemu-x86_64 with SCENARIOS=hii-name-value-string
  hii-name-value-string-snapshot hii-undeclared-password, and
  test-e2e-qemu-shell-x86_64 with SCENARIOS=shell-name-value-password
  shell-undeclared-password: each passes. On main before its
  system-table rewrite, each of the 113 scenarios of both targets
  passed, and on i686 and aarch64 hii-name-value-password,
  hii-name-value-password-snapshot, hii-name-value-string,
  hii-name-value-string-snapshot and shell-name-value-password passed.
- With main's product code, these tests fail on x86_64 in
  hii-name-value-string-snapshot: get, list-questions and show-ifr, on
  the numbers-only reason; the other rows pass there.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The UEFI Shell build exported the whole HII database with one
ExportPackageLists() of a NULL Handle (UEFI 2.11 §34.8.6), so its HiiDB
tells no package list's EFI_HII_HANDLE, which GetPackageListHandle()
(§34.8.12) takes to name the driver handle that registered the list.

List the handles with ListPackageLists() of EFI_HII_PACKAGE_TYPE_ALL
(§34.8.5), then export each list by its own handle, through
EFI_HII_DATABASE_PROTOCOL as uefi-raw defines it, since uefi's
HiiDatabase wraps only the NULL-Handle export. The HiiDB keeps its
format, the lists one after the other, now in ListPackageLists() order,
so the i-th package list is that of the i-th handle. PackageLists keeps
the handles beside the lists, and driver_handle() asks
GetPackageListHandle() for a list's driver handle, None when the list
has none: the Callback() sequences of questions without a VarStore
call that driver's EFI_HII_CONFIG_ACCESS_PROTOCOL.

Test Plan:
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1492 lib unit tests.
- make test-e2e-qemu-shell-x86_64 SCENARIOS='shell-parity
  shell-driver-sample': every check passes, and list-questions of the
  UEFI Shell build matches the Linux build's on all 29 questions that
  Linux reads.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
A question without a VarStore keeps its value in its driver, which only
EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack() reaches. A forms browser runs
those Callback()s over its edit buffer, which a Callback() reaches
through EFI_FORM_BROWSER2_PROTOCOL.BrowserCallback(); outside a browser
no edit buffer exists, and a driver may write the FormSet's stores
directly instead. Before uefisettings runs such Callback()s, it needs to
read every store of the FormSet, find what the Callback()s changed, and
put it back.

store_declarations() lists the stores that a FormSet declares
(VARSTORE, VARSTORE_NAME_VALUE, VARSTORE_EFI) with the settings that its
questions request, as edk2-stable202608 SetupBrowserDxe builds a store's
<ConfigRequest>: a Buffer store's blocks by VarOffset and the
StorageWidth of IfrParse.c, a Name/Value store's VarNames. A PASSWORD
question's bytes (MaxSize CHAR16s) or VarName are withheld: no setting
that overlaps them is requested, and the store is marked as holding a
password. A VARSTORE_EFI before UEFI 2.3.1 names no variable: in its
place, store_declarations() lists the EFI variable of its GUID that
the VarName of each of its questions names, as edk2-stable202608
SetupBrowserDxe IfrParse.c CreateQuestion takes it through GetToken;
for a VarName that the strings packages differ on, the variable of
each of their strings (ShortVarStoreEfi::candidate_variables). Each
is listed once, marked as holding a password if a PASSWORD question
names it.

ConfigRouting is EFI_HII_CONFIG_ROUTING_PROTOCOL.ExtractConfig() (UEFI
2.11 §35.4.2) and RouteConfig() (UEFI 2.11 §35.4.4) of that protocol,
which "is the only one that outside callers should invoke" (UEFI 2.11
§35.1.2). RoutingProtocol calls it as uefi-raw defines it, since uefi
wraps only ExportConfig(). ExtractConfig()'s Results are zeroed before
FreePool(), and parsed settings live in Zeroizing buffers.

FormSetStore reads a store: a Buffer or Name/Value store by
ExtractConfig() of its <ConfigRequest>, whose PATH is the device path
package of the store's package list (a list without one is refused),
an EFI variable store by GetVariable(). The answer must hold exactly the
requested settings, each block at the same OFFSET and WIDTH and each
name once: a missing, extra or repeated setting refuses. Baseline reads
every store twice; settings that differ between the two change on their
own and are left out of the comparison. check() reads them again, and
for each changed store:
- a Buffer or Name/Value store gets one RouteConfig() of a whole-store
  <ConfigResp>: every requested setting, the changed ones as before,
  the others as read now. A partial <ConfigResp> would clear the other
  settings of a driver that zeroes its copy before ConfigToBlock(), as
  edk2 NetworkPkg HttpBootConfig.c HttpBootFormRouteConfig does;
- a store that holds a password is not restored, and the change is
  refused: a RouteConfig() without the password bytes may clear them,
  and SetVariable() of an EFI variable store would write its password's
  bytes too, which uefisettings never writes;
- an EFI variable store gets SetVariable() of its old contents, after
  deleting the variable when its attributes changed, or is deleted when
  it was absent (UEFI 2.11 §8.2.3). These restores write whole
  variables: set's DataPatch writes (FirmwareVariables::write_patches)
  keep a variable's attributes and neither create nor delete one.
Each restore is read back to verify it. Since no snapshot of a Buffer
or Name/Value store requests a password's bytes, a Callback() that
changes only those goes unnoticed.

VariableData::delete_variable deletes a variable on every backend:
efivarfs by unlinking its file (Linux efivarfs_unlink()), Windows by a
zero-size SetFirmwareEnvironmentVariableExW, the UEFI Shell build by
SetVariable() without data. publish-hiidb gains the vendor device path
and install helper for the fixtures that register forms with a driver.

Nothing calls these yet; the Callback() sequences of the next changes
do, and drop the interim allow(dead_code) attributes.

Test Plan:
- 21 new tests of the stores: requests per question width and name,
  a store without a device path refused, unchanged stores, a changed
  Buffer store routed back whole and verified, a changed name, an EFI
  variable set back, deleted then set on changed attributes, deleted
  when created, restore failures and restores that write nothing,
  settings that change on their own, a changed setting beside them, an
  unreadable store, a store or setting missing from the answer, an
  extra or repeated setting, a changed Buffer store and a changed EFI
  variable store holding a password left unrestored, an unreadable
  store after the Callback()s, a failed deletion and a failed
  SetVariable() of a restore reported with their errors.
- 3 new tests of store_declarations: PASSWORD bytes and VarNames
  withheld; the variables of a VARSTORE_EFI before UEFI 2.3.1, each
  once, the one that a PASSWORD names holding a password whatever
  question names it after, and each string of a VarName that the
  strings packages differ on. 1 new test of EfiStatus' names.
- 8 mutants, each failing a new test: the matcher accepting an extra,
  repeated or missing setting, a partial restore, settings that change
  on their own taken from the baseline, a store holding a password
  restored, PASSWORD bytes requested, and overlap found only at the
  same offset.
- 1 mutant run at the end of this series, failing the new test: an EFI
  variable store holding a password set back.
- 1 mutant run at the end of this series, failing the new test of
  failed restores: a failed deletion of a variable that the Callback()s
  created counted as restored.
- 3 mutants run at the end of this series, each failing the new test
  of a VARSTORE_EFI before UEFI 2.3.1: its variables left out, the
  password mark of a variable dropped, or overwritten by a question
  after the PASSWORD.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1517 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
A question without a VarStore that has EFI_IFR_FLAG_CALLBACK keeps its
value in its driver (UEFI 2.11 §33.2.5.6), and get only said why it
showed none. In the UEFI Shell, get now calls that driver's
EFI_HII_CONFIG_ACCESS_PROTOCOL.Callback() for the one question with the
browser actions a forms browser sends (UEFI 2.11 §35.5.4): FORM_OPEN,
RETRIEVE and FORM_CLOSE, FORM_CLOSE once FORM_OPEN was sent, unless
RETRIEVE failed with an error other than EFI_UNSUPPORTED. FORM_CLOSE
follows a form's submit actions (UEFI 2.11 §35.5.4), which such a form
never reaches: edk2-stable202608 SetupBrowserDxe Presentation.c goes to
Done past FORM_CLOSE after such a RETRIEVE, and counts EFI_UNSUPPORTED
as success. It shows RETRIEVE's value as it shows a stored one. The
question starts at its standard default, else 0, as edk2-stable202608
SetupBrowserDxe starts a question without storage.

The driver is the one that GetPackageListHandle() names for the
question's package list, with the protocol opened GetProtocol, as a
forms browser finds it; a list without one is refused. The HII database
is exported again first: if it changed since get read it, the list's
index may name another handle, and get refuses. driver_held.rs finds a
question's FormSet with conditions.rs's enclosing_form_set.

The sequence runs between the reads of the FormSet's stores of the
previous change. A store that cannot be read refuses before the first
Callback(), settings that change between the two reads before it are
listed and not compared, and a store that the Callback()s changed is
restored, and get shows no value. A Callback() that asks the forms
browser to save the FormSet's modified values, which only a forms
browser's edit buffer holds, or returns an ActionRequest that UEFI 2.11
does not define refuses too; a reset or discard request is noted. A
question with a READ expression shows RETRIEVE's value, which
overrides READ in a forms browser. When RETRIEVE fails, a forms browser
keeps READ's value, but uefisettings does not evaluate READ beside a
driver's Callback()s, so get refuses and says so. This is current
behaviour, kept in one refusal, ExpressionBesideCallback, which
evaluating READ and WRITE inside the sequence would replace. The
sequence reads EFI variables through WithholdingVariables, whose new
VariableData gives the bytes of PASSWORD questions as zero and refuses
SetVariable() and deletion of a variable that holds such bytes, as
both would write them. Those bytes are PasswordQuestions::of_lists's,
also those of a VarStore outside any FormSet of a PASSWORD's
VarStoreId, which the Config Keyword Handler may take for it.

A question whose FormSet has a form that read_db disables, as UEFI
2.11 §33.2.5.10.1 disables the form of a malformed op, is refused
before any Callback() if that form holds a PASSWORD or VarStore op:
read_db drops the form from its FormSet's tree, so the declarations
of the FormSet's stores see neither, and uefisettings cannot tell
which stores a restore through RouteConfig() would change. The
refusal gives the form's DisabledForm reason, which names its FormId,
its FormSet and why read_db disables it, and the form's first PASSWORD
or VarStore op. A disabled form of another FormSet of the same GUID
in the package list, or of no FormSet whose GUID is known, counts as
one of the question's FormSet. read_db's record_disabled_var_stores,
which walks each disabled form once to record the VarStoreIds that it
declares in its FormSet, now also returns that op, which DisabledForm
keeps as store_op, so get walks no disabled form again.

Only get with this firmware's variables in the UEFI Shell calls a
driver: list-questions, show-ifr, the dumps and get --no-efivars keep
the refusal, and so do Linux, Windows and macOS, where no Callback()
may run after ExitBootServices(). In the UEFI Shell that refusal now
says that only get without --no-efivars calls the driver, no longer
that uefisettings.efi does not call it yet. set still refuses such a
question.

uefisettings exchanges a value with Callback() only for a ONE_OF,
NUMERIC or CHECKBOX question. An ORDERED_LIST or STRING, or a DATE or
TIME outside EFI Date/Time Storage, without a VarStore and with
EFI_IFR_FLAG_CALLBACK, with or without a READ or WRITE expression, is
refused through either reach with its op named
(StoragelessRefusal::CallbackUndecoded), as the README now says. Its
default, of an EFI_IFR_DEFAULT or a flagged option, still shows beside
that refusal, as get shows a default beside any value it lacks.

A Callback() names its question by QuestionId alone, "The unique value
that identifies the particular question" (UEFI 2.11 §33.3.8.2.2). So a
question with EFI_IFR_FLAG_CALLBACK whose QuestionId another question
of its FormSet also has, such as a PASSWORD, is refused through either
reach with that op named (StoragelessRefusal::CallbackSharedQuestionId)
and gets no DriverHeldQuestion, so no Callback() goes to its driver,
which could take it for the other. A PASSWORD itself is never driver
held: only a ONE_OF, NUMERIC or CHECKBOX is. The README says so, and
beside its Unsafe operations table that get of a question that its
driver holds takes no --i-am-fine-to-brick-this-system: it restores
any store that RETRIEVE changed, which undoes only the driver's own
change, and its ExtractConfig() reads reach the driver unflagged too.

In a HiiDB with a PASSWORD whose driver may keep the password in any
variable, one of VarStoreId 0, which names no VarStore, or one that
edk2 may route to a VARSTORE_NAME_VALUE, get asks a driver nothing and
reads no variable, as for any question: get's reader is
PasswordQuestions::reader (read_db_withholding), which refuses such a
HiiDB through variables that read anything (AnyVariablePasswords),
and through variables that reach BootServices as the password is
unresolved; DriverCallbacks::reach checks the HiiDB again
(PasswordQuestions::withholding) before it finds the driver and
snapshots the FormSet's stores.

StoragelessRefusal::SnapshotFailed and StoresChanged, StoreRestore and
QuestionDescriptor::storageless_route were kept, unused, for this
sequence. It reports a store that cannot be read or that changed with
form_set_stores' own errors, and driver_held.rs decides a question's
route as it parses it, so they go, with their tests. ChangingRefused
waits for set's sequence, as its expect(dead_code) now says.

publish-hiidb callback-forms registers generic FormSets whose
questions without a VarStore take each of these paths, each package list
but the last by a handle of its own with a vendor device path and
EFI_HII_CONFIG_ACCESS_PROTOCOL; the UEFI Shell scenario
shell-callback-forms runs get on them.

Windows: exports/windows.rs gains driver_held_values(), which returns
None, only so that the shared get compiles; Windows keeps the refusal.

Test Plan:
- 9 new tests of the sequence with a scripted driver: the calls and
  their values, RETRIEVE's EFI_UNSUPPORTED with and without a READ
  expression and its other errors, with FORM_CLOSE after EFI_UNSUPPORTED
  only, a RETRIEVE that writes the Buffer or the EFI variable store
  (refused, both restored), save and undefined requests refused, a save
  without stores allowed, reset and discard requests noted, an
  unreadable store refused before any Callback(), settings that change
  on their own listed; and the widths of the Callback() Value.
- 5 new tests of driver-held questions (their FormSet's stores and
  standard default, which questions are driver-held, a NUMERIC and a
  CHECKBOX one, their READ and WRITE expressions, how get shows their
  values), 1 of get going to a driver only where one is reached while
  set refuses before any write, and 1 of WithholdingVariables'
  VariableData: the bytes of a password read as zero, and its variable
  neither set nor deleted; 1 of a Callback() restore refused over a
  VarStore outside any FormSet of a PASSWORD's VarStoreId, the
  password kept.
- 1 new test: a DATE, TIME, ORDERED_LIST or STRING without a VarStore,
  with EFI_IFR_FLAG_CALLBACK, with and without READ and WRITE, refused
  by its op through either reach; and CallbackUndecoded's text.
- 1 mutant run at the end of this series, which takes each of them as
  a ONE_OF, NUMERIC or CHECKBOX, fails it.
- 1 new test: such a DATE and TIME, whose options flagged DEFAULT give
  2004-01-02 and 15:33:34, show that default beside the refusal
  through either reach, and set refuses them. That mutant fails it,
  and so does one run at the end of this series in which a DATE's or
  TIME's flagged option gives no default.
- 3 new tests: a CALLBACK question that shares its QuestionId with a
  PASSWORD, or another question, refused by that op, and one that
  shares none not; no PASSWORD driver-held, and a storageless ONE_OF
  driver-held only while no PASSWORD has its QuestionId; get and set
  of such a question never reaching its driver.
- 2 mutants run at the end of this series, each failing those tests:
  the shared QuestionId never found; driver_held ignoring it.
- 1 new test: get of a question that its driver holds, beside a
  PASSWORD of VarStoreId 0 or one that edk2 may route to a
  VARSTORE_NAME_VALUE, refused through either reach with no Callback()
  and no read, the refusal naming VarStoreId 0 for the first; beside
  one on a buffer VarStore, or without the PASSWORD, get asks the
  driver.
- 1 mutant run at the end of this series, get's reader over the
  PasswordQuestions of no package list, fails it, at the PASSWORD of
  VarStoreId 0.
- 1 new test: get's answer and set's refusal of a question that its
  driver holds, with control and Bidi_Control characters in its prompt
  and in an EFI variable name of the answer, print as every answer and
  error does: as Debug text or as JSON with those characters escaped,
  and through a console that renders ASCII only, every other character
  escaped too.
- 2 mutants run at the end of this series fail it: the JSON printed
  without JsonText; a line printed whatever the console renders.
- 1 new test: get of a STRING beside a question that its driver holds,
  through either reach, asks no driver and answers as without one:
  one without a VarStore and with EFI_IFR_FLAG_CALLBACK shows
  CallbackUndecoded, two on Setup their characters; get of the
  CHECKBOX asks the driver.
- 2 mutants run at the end of this series fail it: a STRING taken as
  a ONE_OF, NUMERIC or CHECKBOX, refused as one that its driver holds;
  get under a driver answering nothing for a question it does not
  hold.
- 15 mutants, each failing a new test: get's dispatch off, FORM_CLOSE
  only after a successful RETRIEVE, RETRIEVE's value ignored, the
  stores' check ignored, the request refusal ignored, the settings that
  change on their own unlisted, a save refused without stores, the
  request notes dropped, the Value unmasked, the standard default
  ignored, READ ignored, READ and WRITE unrecorded, and a CHECKBOX,
  ONE_OF or NUMERIC without its driver-held description.
- 4 mutants run at the end of this series, each failing a test that
  this commit adds: FORM_CLOSE sent after a RETRIEVE error other than
  EFI_UNSUPPORTED; a password's bytes read; a variable that holds them
  set, or deleted.
- 1 mutant run at the end of this series fails the new restore test,
  with 8 tests of the PASSWORDs outside any FormSet: a VarStore outside
  any FormSet of a PASSWORD's VarStoreId not withheld.
- 1 new test of the refusal beside a disabled form: one that holds a
  PASSWORD or a VARSTORE refuses, with its DisabledForm reason, which
  names the form, its FormSet and why it is disabled; one that holds
  neither, or is of another FormSet, does not; one of no FormSet whose
  GUID is known does.
- 7 mutants run at the end of this series, each failing it: the
  refusal never given; VarStore ops not counted; a disabled form of no
  known FormSet not counted; every FormSet's disabled forms counted;
  the reason dropped from the refusal; the text after it dropped; the
  form's first PASSWORD or VarStore op not recorded.
- 1 QEMU mutant run at the end of this series, DriverCallbacks::reach
  checking no disabled form, fails the get-disabled step of
  shell-callback-forms-password, which the next commit adds.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1541 lib unit tests; cargo test --locked --bins passes: 73
  tests.
- make test-e2e-qemu-shell-x86_64 SCENARIOS=shell-callback-forms: every
  check passes; get shows RETRIEVE's value with the setting that changes
  at every ExtractConfig() listed, and refuses when RETRIEVE returns
  EFI_UNSUPPORTED, when a store's ExtractConfig() fails (no Callback()),
  and for a package list that no driver handle registered.
- make test-e2e-qemu-shell-x86_64 SCENARIOS=shell-readwrite at the end
  of this series: get of a question that its driver holds, in a
  package list without a driver handle, names the missing
  EFI_HII_CONFIG_ACCESS_PROTOCOL, and list-questions shows the
  refusal; with the earlier rows of that scenario it fails.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
In the UEFI Shell, set now changes a question without a VarStore whose
driver holds its value as a forms browser does, through that driver's
EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack() (UEFI 2.11 §35.5.4):
FORM_OPEN, RETRIEVE, CHANGING with the new value, CHANGED unless
CHANGING failed, and FORM_CLOSE. A RETRIEVE that fails with an error
other than EFI_UNSUPPORTED ends the form before it takes a value, so set
sends neither CHANGING nor FORM_CLOSE then, as get does. CHANGING's
EFI_SUCCESS passes the value it returns on to CHANGED, its
EFI_UNSUPPORTED the new value, and any other error refuses the value. A
forms browser ignores CHANGED's errors, but without storage CHANGED is
where the driver applies the value, so an error there is not applied. A
forms browser never sends SUBMITTED for a question without storage, and
neither does set. A forms browser evaluates a WRITE expression between
CHANGING and CHANGED, but uefisettings does not evaluate WRITE beside a
driver's Callback()s, so set refuses a question with one before any
write. This is current behaviour, kept in get's ExpressionBesideCallback
refusal.

Then set reads the value back with FORM_OPEN, RETRIEVE and FORM_CLOSE,
and answers "applied", "applied; the driver now reports <value>" for a
driver that resets a transient value, or "applied; the driver offers no
read-back".

As for get, the sequence runs between reads of the FormSet's stores,
through variables that give the bytes of PASSWORD questions as zero, so
set writes none of them: a changed store that holds one is not
restored, and the value is not applied.
Once a Callback() ran, a refusal says "not applied: <reason>; the
driver's Callback(<action>) had already run, and any effect outside the
FormSet's stores stays", and a failure after the Callback()s still
restores the stores and yields an outcome. A save request in a FormSet
with stores and an undefined request are not applied, a reset or
discard request is noted, and a RECONNECT request after an applied
change disconnects and connects the driver's handle, as a forms browser
does.

set takes the new value as for a stored question, an option's text or a
number in range. A question that EFI_IFR_FLAG_READ_ONLY makes
read-only, which its driver holds, is an unsafe operation, as a stored
one is (UnsafeOperation::ReadOnlyQuestion): set's selection takes it
to forms::read_only_choice, the read-only part of choice_for_set,
which choice_for_set now calls after its efivar check, through
Selection::written_or_likely. set refuses --item, which gives the
items of an ORDERED_LIST, as for any question that takes VALUE.
No driver holds a STRING or an ORDERED_LIST: set refuses one without
a VarStore and with EFI_IFR_FLAG_CALLBACK by its op, read-only or
not, with the flag too, and sets a STRING on a VarStore as without a
driver.
It refuses questions of more than one kind among all
those selected, driver-held ones too (check_one_kind), checks every
selected value before the first write, and asks each driver-held match's
build, through DriverHeldValues::check_set, whether it can set that
question: the UEFI Shell build checks that it reaches the driver. Then
set_questions writes the stored questions' variables and sends the
others to their drivers: each driver is a store of its batch, after the
writes of EFI Date/Time Storage and the variables (DriverStore). As at
a failed variable write, set stops at the
first store that fails: the refusal of the only store is set's error
unchanged, and of one of several, NotSetEverywhere names the stores
written or applied, the one that failed and those not attempted, a
driver as its question's package list and "(its driver)"
(DriverStore::label, which names the store as DriverHeldValues'
store_name gives it). The drivers come after the variables because no
browser answers a driver's BrowserCallback(), so the variables written
first are the only view its Callback()s have of the values of this
set. set checks its unsafe operations once, right before its first
write, which for a question that its driver holds is its first
Callback(): set_questions takes set's PendingOperations with the
drivers and returns the operations that it lifted, which set_in and
set_using return with the answers. In a HiiDB that declares a setup
password question, set through a driver in the UEFI Shell is
UnsafeOperation::SetupPassword, so without
--i-am-fine-to-brick-this-system no Callback() runs; the README says
so. In a HiiDB with a PASSWORD of VarStoreId 0 or one that edk2 may
route to a VARSTORE_NAME_VALUE, set refuses before any Callback(),
read or write, with the flag too, as get does: its reader and writes
are PasswordQuestions::reader and withholding. Only the UEFI
Shell build reaches a driver: Linux, Windows and macOS still refuse such
a question before any write. In the UEFI Shell, the refusal of
list-questions, show-ifr, the dumps and get --no-efivars now says that
only get and set call the driver. set_selected passes set's
VolatileWrites policy (--allow-volatile) on to set_questions; a value
that a driver keeps, in no variable, is never volatile.

publish-hiidb's callback-forms questions now get set too, and the UEFI
Shell scenario shell-callback-forms-password registers a FormSet whose
Buffer store holds a PASSWORD question beside a setting that a CHANGED
overwrites, and a FormSet whose PASSWORD question is in a second form,
which a CHECKBOX op of 3 bytes disables, beside a question that its
driver holds. Its set without --i-am-fine-to-brick-this-system is
refused before any Callback(); with the flag, set warns of the setup
password.

Windows: the doc comment of exports/windows.rs's driver_held_values()
names set too.

Test Plan:
- 23 new tests of set's sequence with a scripted driver: the calls in
  order with their values and the read-back, CHANGING's EFI_SUCCESS and
  EFI_UNSUPPORTED values, a CHANGING error (no CHANGED, FORM_CLOSE
  still), a CHANGED error and its EFI_UNSUPPORTED, a failed RETRIEVE (no
  CHANGING, no FORM_CLOSE), save requests with and without stores, reset
  and discard notes, RECONNECT only after an applied change and its
  failure, an undefined request, a changed store restored, an unreadable
  store and a WRITE expression refused before any Callback(), a failure
  after the Callback()s still restoring, the read-back's other value,
  EFI_UNSUPPORTED and error, settings that change on their own, a
  CHANGED that writes an EFI variable store holding a password not
  applied and the store not set back; set's
  value of an option's text; set going to a driver only where one is
  reached, beside a stored question; set refusing a WRITE expression
  before it writes a stored question of the same name; a driver-held
  question that EFI_IFR_FLAG_READ_ONLY makes read-only refused without
  --i-am-fine-to-brick-this-system, and with it set, its lift
  returned, through either reach; a driver-held question beside a
  setup password question
  refused without the flag before any Callback(), and with it set,
  lifting SetupPassword, with no write of the password's store; set
  stopping at the
  first driver that refuses, with the stores written and applied, the
  refusal and the stores not attempted named; the refusal of the only
  driver unchanged; every driver-held match's check_set run before the
  first write; each driver-held answer with its own driver's
  annotation, among the stored ones, in
  each_driver_held_answer_carries_its_own_driver_s_annotation; and, in
  set_questions' tests, a failed variable write leaving the driver
  after it not attempted and unapplied, in
  a_failed_variable_write_leaves_the_drivers_after_it_unapplied.
- 1 new test: list-questions, get and set show a question whose driver
  holds its value with its QuestionId, its FormSet's GUID and its
  keyword, and its prompt and help in the language of --language; get
  and set select it by QuestionId, keyword or prompt, and take it to
  its driver.
- 1 new test: a CHECKBOX that its driver holds and a DATE on Setup of
  its prompt refused as two kinds, and --item for that CHECKBOX
  refused, each before its driver applies a value and before any
  write.
- 2 mutants run at the end of this series, each failing it: the check
  of one kind skipped; --item for a driver-held question refused as an
  invalid option.
- 14 mutants, each failing a test: CHANGING's EFI_UNSUPPORTED passing
  the returned value, a CHANGING error taken, a CHANGED error applied,
  no FORM_CLOSE, the read-back ignored, a reconnection after a refused
  change, the stores' check and the request refusal ignored, the first
  action named instead of the last, driver-held questions written as
  stored ones, an option's text parsed as a number, set's dispatch off,
  WRITE ignored in the sequence and before set's first write. A mutant
  that decides set's dispatch by the question alone, whatever driver is
  reached, fails no test: without a driver, set_questions refuses the
  question with the same text, before any write.
- 1 mutant run at the end of this series fails the test of what
  list-questions, get and set show: get's answer of a driver-held
  question without its QuestionId.
- 7 mutants run at the end of this series, each failing a new test:
  FORM_CLOSE sent after a failed RETRIEVE; check_set skipped; a
  driver's refusal skipped and the stores after it attempted; the
  drivers sent the value before the variables are written; the
  one-store rule counting the variables only; a set of driver-held
  questions only refused as not found.
- 2 mutants run at the end of this series, each failing a test that
  this commit adds: the driver branch of set's selection skipping
  read_only_choice; the drivers' Callback()s run before the unsafe
  operations are checked.
- 2 mutants run at the end of this series, each failing a new test: a
  failed variable write skipped when drivers follow it; the drivers'
  annotations returned in reverse order.
- 1 new test: set of a question that its driver holds, beside a
  PASSWORD of VarStoreId 0 or one that edk2 may route to a
  VARSTORE_NAME_VALUE, refused through either reach, with
  --i-am-fine-to-brick-this-system too, which the refusal does not
  name, with no Callback(), read or write, the refusal naming
  VarStoreId 0 for the first; without the PASSWORD, set through the
  driver, lifting nothing.
- 1 mutant run at the end of this series, set's reader and writes
  over the PasswordQuestions of no package list, fails it, at the
  PASSWORD of VarStoreId 0.
- 1 new test: set of a STRING beside a question that its driver holds,
  through either reach and with either grant, asks no driver and does
  as without one: one without a VarStore and with
  EFI_IFR_FLAG_CALLBACK refused by its op before any write, one on
  Setup written, one that EFI_IFR_FLAG_READ_ONLY makes read-only
  refused unless the flag lifts it; an ORDERED_LIST of the first
  STRING's flags, read-only too, refused by its op with either grant.
- 3 mutants run at the end of this series fail it: a STRING, or an
  ORDERED_LIST, taken as a ONE_OF, NUMERIC or CHECKBOX; set under a
  driver writing no question that it does not hold.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1569 lib unit tests.
- make test-e2e-qemu-shell-x86_64 SCENARIOS='shell-callback-forms
  shell-callback-forms-password': every check passes. set applies a
  value and reads it back; a CHANGED that overwrites the EFI variable
  store or the Buffer store is not applied, and the store reads as
  before (the Buffer store by one RouteConfig() of its whole
  <ConfigResp>); a CHANGING error, a CHANGED error and a save request
  are not applied; RECONNECT restarts the fixture's driver binding; the
  read-back tells a transient value and a missing RETRIEVE; a reset
  request is noted; a store that ExtractConfig() does not answer and a
  package list without a driver handle refuse before any Callback(); a
  changed store that holds a PASSWORD question is refused unrestored,
  and no read requests the password's bytes; set there without
  --i-am-fine-to-brick-this-system is refused before any Callback(),
  and with it prints the setup password's warning. get of the question
  beside a disabled form that holds a PASSWORD refuses with that form's
  reason, and calls no Callback().
- make test-e2e-qemu-shell-x86_64 SCENARIOS=shell-readwrite at the end
  of this series: set of a question that its driver holds, in a
  package list without a driver handle, names the missing
  EFI_HII_CONFIG_ACCESS_PROTOCOL before any write.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
A Callback() may write outside the FormSet's stores: a driver keeps the
value of a question without a VarStore where it likes, and one that
ignores a failed BrowserCallback() may act on zeros, which nothing
outside a forms browser can see.

get and set now read every EFI variable that GetNextVariableName()
lists before the sequence and again after it, but those of
uefisettings' own vendor GUID, and note each one that was created,
deleted or changed, in data or attributes, as "EFI variables changed:
<name>-<guid> (created)". The list only informs and never refuses: the
change may be the driver's own business. The bytes of PASSWORD
questions read as zero both times, so a change of only those goes
unlisted; a change of the other bytes of their variable lists it.

publish-hiidb's password FormSet gains a question whose CHANGED
overwrites only the password's bytes.

Test Plan:
- 3 new tests of the listing (created, deleted and changed variables
  without uefisettings' own, none when unchanged, attributes alone) and
  1 of a variable that set's CHANGED creates, listed while set applies;
  the tests of get's notes and of WithholdingVariables now also check a
  variable that RETRIEVE creates and the names listed.
- 6 mutants, each failing a test: uefisettings' own variables listed,
  changed or deleted variables unlisted, get's or set's note dropped,
  the names of WithholdingVariables dropped.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1573 lib unit tests.
- make test-e2e-qemu-shell-x86_64 SCENARIOS='shell-callback-forms
  shell-callback-forms-password': every check passes; set lists the
  variable in which a question's driver keeps its value, also when a
  save request refuses the change; a CHANGED beside a password lists
  the password's variable, and a CHANGED that overwrites only the
  password's bytes is applied with no variable listed, each with
  --i-am-fine-to-brick-this-system and its warning.
- 1 QEMU mutant run at the end of this series, on x86_64: the UEFI
  Shell build's Callback() sequences through variables that withhold
  no password byte; the step of the new question fails, as set lists
  the password's variable.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
A question that only its driver's Callback() reaches cannot be set
from an OS: boot services, and with them every Callback(), end at
ExitBootServices(). The next changes stage such a set for the next
boot instead: a Boot#### load option starts uefisettings.efi from the
EFI system partition once, through BootNext, and that image applies
the set before the OS starts. They need to write that load option and
to read the device path of the option that started the running OS.

LoadOption encodes and decodes an EFI_LOAD_OPTION (UEFI 2.11 §3.1.3):
its Attributes, reserved bits kept, its Description, its FilePathList
and its OptionalData. FilePathList holds packed device paths and checks
that each node lies within them and that the last is an End Entire
Device Path node (§10.3.1). Its image_path() is the first instance of
the first device path, which locates the image, and hard_drive() its
Hard Drive node. DevicePathNode decodes and encodes the Hard Drive node
(§10.3.5.1), its GPT and MBR signatures and any other Partition Format
and Signature Type byte for byte, and the File Path node (§10.3.5.4);
any other node passes through as its Type, Sub-Type and data.
Descriptions and Path Names are UCS-2 without Null; one read with a
surrogate decodes it as U+FFFD.

Nothing calls these yet; the staging change does, and drops the interim
allow(dead_code).

Test Plan:
- 8 new tests: a load option encoded byte for byte as §3.1.3 and Tables
  10.54 and 10.57 lay it out and decoded back; the image path of a full
  device path stopping at End This Instance, and its Hard Drive node;
  MBR signature bytes, and other formats and signature types kept;
  reserved attribute bits kept; each malformed load option refused
  (short, no Null, FilePathListLength beyond the end, no device path,
  a node Length below 4 or beyond the list, no End node); malformed
  Hard Drive and File Path nodes refused; UCS-2 checks and lossy
  decoding; nodes and lists too long for their Length.
- 6 mutants, each failing a new test: no End node check, a node
  Length below 4 accepted, the image path past End This Instance, the
  MBR signature shifted, FilePathListLength clamped to the bytes left,
  reserved attribute bits masked. from_bits_truncate for
  from_bits_retain fails none, and changes nothing: the flags declare
  every bit (const _ = !0).
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1581 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
Staging a set for the next boot copies uefisettings.efi to the EFI
system partition and starts it through a Boot#### option whose device
path is HD()+File: a Hard Drive node, then a File Path node. Firmware
finds the partition by that Hard Drive node, so the node must carry the
partition table's own numbers, which an OS's partition numbers need not
match. The staging changes on Linux and Windows read them from the disk
here.

PartitionTable::read reads a disk's partition table through
BlockDevice, in whole logical blocks. LBA 0 must hold an MBR, with
Signature 0xAA55 (UEFI 2.11 Table 5.1). A GPT Protective record that
starts at LBA 1 makes it a protective MBR (§5.2.3), as edk2-stable202608
PartitionDxe tells them apart; then the primary GPT is read, refused
unless it passes the tests of §5.3.2: Signature, HeaderCRC32 over
HeaderSize bytes, MyLBA 1, and the entry array's CRC32. The header must
also be revision 1.0 with HeaderSize from 92 to the block size, and
SizeOfPartitionEntry 128 x 2^n; arithmetic is checked, and an entry
array over 1 MiB is refused. The backup GPT is not read.

esp_hard_drive() takes the volume's offset and length in bytes, as the
OS reports them. Both must be whole logical blocks, and exactly one
entry in use must start there, be an ESP, span the volume and overlap
no other entry. A GPT entry must also lie within the usable LBAs and
lack Attributes bit 1 (No Block IO Protocol), or firmware makes no
partition of it. The node then holds:
- GPT: Partition Number = the entry's index + 1, as edk2 numbers it;
  Start = StartingLBA; Size = EndingLBA - StartingLBA + 1; the
  UniquePartitionGUID as the signature;
- MBR: the slot, 1-4, of a record of OSType 0xEF; its StartingLBA and
  SizeInLBA; the 32-bit disk signature at 0x1B8 (Signature Type 1).
GUIDs go through Guid's one byte conversion. crc32fast, which Cargo.lock
already holds for the QEMU guest, computes the CRC32s; it builds for
Linux and Windows only, as the module does.

Nothing calls this yet; the staging change on Linux does, and drops the
interim allow(dead_code).

Test Plan:
- 9 new tests. 3 read images that sfdisk (util-linux 2.41.6)
  partitioned, whose CRC32s are sfdisk's: a GPT of 512-byte blocks
  whose ESP is entry 3, after an unused entry 2 and first by offset; a
  GPT of 4096-byte blocks; an MBR whose ESP is in slot 2. The ESP type
  GUID from sfdisk's entry bytes. Each failing GPT header check:
  Signature, Revision, HeaderSize below 92 and past the block (the
  whole block accepted), MyLBA, SizeOfPartitionEntry 136 and 64, an
  entry array over the limit and at it; changed header and entry bytes
  against the stored CRC32s, a reserved byte past HeaderSize accepted.
  256-byte entries, bytes after the array in its last block ignored.
  The ESP entry refused for No Block IO Protocol, LBAs outside the
  usable ones or reversed, overlaps, a second entry at its start, only
  an unused entry there, and a size or offset off the volume's; other
  attribute bits, adjacent partitions and unused entries accepted. MBR
  records that overlap, are too small, or have OSType or SizeInLBA 0
  refused; a GPT Protective record not at LBA 1 skipped, one at LBA 1
  read as a GPT. Block sizes 0, 256 and 511, LBA 0 without 0xAA55 and
  short reads refused.
- 25 mutants, each failing a new test: no HeaderCRC32 check; no entry
  array CRC32 check; the header's CRC32 over the whole block; the
  array's over whole blocks; no MyLBA, Revision or ESP type (GPT, MBR)
  check; no HeaderSize floor; SizeOfPartitionEntry any multiple of 8;
  no entry array limit; GPT numbers by offset rank or from 0; MBR slots
  from 0; the MBR disk signature shifted; no size or overlap check; a
  second entry at the start accepted; a GPT Protective record at any
  LBA, or in use; 512-byte blocks assumed; whole blocks unchecked; No
  Block IO Protocol ignored; usable LBAs unchecked; reversed LBAs
  accepted.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1590 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
On Linux and Windows, set cannot reach a question whose value only its
driver's Callback() holds: boot services end at ExitBootServices(). The
next changes stage such a set instead. uefisettings.efi starts once,
before the OS, from a Boot#### option that BootNext names (UEFI 2.11
§3.1.2), applies the staged requests, and records what it did. This
change holds the records and what the OS side makes of them.

Two NV, BS, RT variables of uefisettings' own vendor GUID hold JSON:
- UefisettingsStagedSet, the staged set: its nonce, 128 random bits; the
  number of its Boot####; its image's path on the EFI system partition
  and SHA-256; its requests, in order. A request names the question by
  its FormSet GUID and QuestionId, with its value and EFI_IFR_TYPE_x,
  and the states and access level that set selected it with, as
  --include and --access-level name them, and set's grant of unsafe
  operations, "refuse" or "allow" as --i-am-fine-to-brick-this-system
  was given, which apply-staged checks the unsafe operations of
  applying it against.
- UefisettingsStagedOutcome, the outcome of the last staged set's boot,
  which echoes the set's nonce: started, which uefisettings.efi records
  before the first Callback(); finished, with each request's result;
  interrupted; not started.
A record of other attributes, of other fields or of no JSON is refused.
The Boot####'s OptionalData, which the boot manager passes to the image
as its LoadOptions, is only the command line
"uefisettings.efi apply-staged <nonce>" in CHAR16s.

StagedState::read tells the state from the records and BootNext. An
outcome of another nonce is ignored. With no outcome of the set's own
nonce, the set is pending while BootNext names its Boot####, as the
boot manager deletes BootNext before it starts that option (§3.1.2);
otherwise its boot is over, and the set was interrupted if
uefisettings.efi recorded that it started, and else never started.

settle() settles a set whose boot is over. It records the outcome, then
deletes the Boot#### and BootNext if it names that Boot####, the image,
and last the record. A Boot#### that no longer holds the set's command
line and an image whose SHA-256 changed are kept, with a warning. A
pending set stays. plan_stage() settles, then appends a request to the
pending set, which keeps its Boot####, or plans a new set. It refuses
while BootNext names another option, which staging would replace, and
while OsIndications holds BOOT_TO_FW_UI, START_OS_RECOVERY or
START_PLATFORM_RECOVERY, which keep the next boot from starting
BootNext's option unattended (§8.5.4). It refuses while OsIndications
holds FILE_CAPSULE_DELIVERY_SUPPORTED and \EFI\UpdateCapsule on the EFI
system partition holds a file, as processing that capsule on disk clears
BootNext without starting its option (§8.5.5). It also refuses while
\EFI\uefisettings there holds a file that the pending set does not name.
StagedFiles is how the OS reaches those files.

For these, globals.rs reads BootNext and OsIndications, and IfrValueType
reads its EFI_IFR_TYPE_x name back. The vendor GUID and IfrValueType
build wherever variable data does.

Nothing calls this yet; the staging change on Linux does, and drops the
interim allow(dead_code).

Test Plan:
- 11 new tests: the JSON of each record, byte for byte, read back; a
  nonce or digest not in lowercase hexadecimal digits, a record with an
  unknown field, value type, state, --include state, access level or
  grant, or with the --include state read-only, which is none now,
  states repeated or out of order, and one missing a field refused; each
  EFI_IFR_TYPE_x name read back; the command line in CHAR16s; the state
  of no record, an outcome only, BootNext naming the set's Boot#### or
  another or none, an outcome started, finished or settled, of the set's
  nonce or another's; records of other attributes or of no JSON refused;
  settling a finished, interrupted and never-started set and settling
  again; a Boot#### of another command line and a changed image kept; a
  pending set and no set left alone; a request appended to the pending
  set; staging a new set, appending, and each refusal; staging held
  while FILE_CAPSULE_DELIVERY_SUPPORTED and a capsule on disk are both
  there, and only then.
- 18 mutants, each failing a new test: no nonce check; started read as
  never started; never pending, or pending on any BootNext; a pending
  set settled; no outcome recorded; any Boot#### deleted; BootNext kept,
  or deleted when it names another option; a changed image deleted; no
  BootNext, OsIndications or file refusal, or no START_OS_RECOVERY in
  it; paths compared case-sensitively; record attributes unchecked; an
  outcome's unknown fields accepted; uppercase hexadecimal accepted.
- 1 mutant run at the end of this series, failing a new test: the
  capsule refusal off.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1601 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
On Linux, set of a question whose value only its driver holds refused
with the reason, as no Callback() is reachable once the OS runs. Now it
stages the request: the next boot starts uefisettings.efi from the EFI
system partition before the OS, which is to apply it. get is unchanged.

MountedEsp::locate finds that partition. It takes the vfat volumes that
mountinfo shows mounted from their root, one mount point per device. For
each, sysfs under /sys/dev/block/<major:minor> gives the partition's
start and size and its disk's logical block size and DEVNAME. esp.rs
then reads the disk's partition table for the partition's Hard Drive
node, refused unless the partition is an ESP. A volume counts only if
stat(2) of its mount point gives the major:minor that mountinfo names
(proc_pid_mountinfo(5)): a later mount on the mount point or on a
directory above it shadows it, and writes through it would reach that
mount's file system. The ESP is the volume whose partition the Hard
Drive node of BootCurrent's Boot#### names: a GPT partition by its
UniquePartitionGUID, an MBR one by its disk signature and partition
number. If that device path holds no Hard Drive node, it is the only
mounted ESP. Staging refuses when no volume or several match, naming
each mounted volume and why it is no match.

set then plans the staging. A pending set gets the request appended and
keeps its Boot####. A new set needs the uefisettings.efi to stage, named
with --image; without it, set refuses, and under Secure Boot says that
the image must be signed for db, as the firmware does not start an image
whose signature db lacks (UEFI 2.11 §32.4.2). stage_new() copies the
image to \EFI\uefisettings\uefisettings.efi, only as a new file, and
reads it back to compare its SHA-256: a file there already, which a set
staged at the same time may have placed, fails it before any write, and
stays. Then it records the set and writes the lowest Boot#### that no
variable holds and that neither BootOrder lists, so that no boot starts
it unattended, nor BootNext names, as edk2-stable202608
UefiBootManagerLib BmGetFreeOptionNumber() skips both: ACTIVE and
HIDDEN, of LOAD_OPTION_CATEGORY_APP if BootOptionSupport has
EFI_BOOT_OPTION_SUPPORT_APP (§3.1.4), else of LOAD_OPTION_CATEGORY_BOOT
(§3.1.5), and in no BootOrder. Its FilePathList is the ESP's Hard Drive
node and the image's File Path node, never a short-form path. Last it
writes BootNext. A step that fails undoes the ones before it. The paths
that records name reach only files of \EFI\uefisettings, and deleting
the last one deletes the directory. The capsules on disk that plan_stage
looks for are the files of \EFI\UpdateCapsule, which vfat finds in any
letter case (mount(8) check=normal).

The --image flag of set reaches SetOptions::staging_image; each build
picks what set does with a question that its driver holds through
driver_held_setter(). On Linux that stages the request with set's
--include, --access-level and grant of unsafe operations:
NextBootStaging::of() takes them and the image from SetOptions, and
the PASSWORD questions from the HiiDB's
package lists (PasswordQuestions::of_lists, which also counts a
VarStore outside any FormSet of a PASSWORD's VarStoreId), and
request() builds each request from the selected
question and value. stage() writes through this machine's variables
without the bytes of those questions: a write over them fails, and
staging undoes the steps before it. Those variables come from
PasswordQuestions::withholding_of, which gives variables of a stated
reach that need not be FirmwareVariables what withholding gives:
withheld's two refusals, a PASSWORD whose VarStore is unknown through
BootServices and IFR past an op where the walk for FormSets ends
through either reach, move into withheld_reaching, which both share,
and withheld alone still gives the bytes despite the second to
variables that read nothing. So in a HiiDB whose IFR past the walk's
end may hold a PASSWORD in any variable, or with a PASSWORD of
VarStoreId 0 or one that edk2 may route to a VARSTORE_NAME_VALUE,
whose driver may keep it in any variable
(PasswordQuestions::check_bounded), staging refuses before any read or
write, as get and set do, with --i-am-fine-to-brick-this-system too.
It writes whole variables, the
record, the Boot#### and BootNext, which set's DataPatch writes into a
VarStore cannot. set stages each request as a store of its batch, after
its variable writes (DriverStore), which its errors name as the
question's package list and "(staged for the next boot)". Its
check_set runs the staging's
refusals, the ESP, plan_stage and --image, before set writes any
question. The Ilo backend refuses --image. StagingArgs sits beside
VolatileArgs in each build's set: set_options puts its --image into
SetOptions, and every auto_set takes it beside SelectionArgs, for the
Linux build's refusal on the Ilo backend.
globals.rs
reads BootOrder for the free Boot####.

Windows: auto_set changes, and exports/windows.rs gains a
driver_held_setter() that returns Ok(None), only so that the shared set
compiles; Windows keeps the refusal.

In the QEMU hii-readwrite test, set of the question that its driver
holds now stages it, and fails because no boot there mounts the ESP.

Test Plan:
- 20 new tests. A fake Linux in a directory (mountinfo, sysfs block
  devices and the sfdisk images as device files): the ESP that
  BootCurrent names, without a Hard Drive node and without BootCurrent;
  a directory of it, also when mounted first, another type and a second
  mount point ignored; an escaped mount point; another partition named,
  two ESPs with and without one named, nothing, the ESP only as ext4 and
  a whole disk mounted refused, with the mounted volumes; an MBR ESP
  named by disk signature and partition number; a mount point that a
  later mount shadows refused, one mounted over another mount taken;
  DEVNAME "", "../sda", "a/./b" and "a//b" refused, "sda" and "mapper/x"
  taken. The ESP's files: placed only once, listed, hashed, deleted with
  the empty directory only, and paths outside \EFI\uefisettings refused.
  Malformed mountinfo lines refused. A new set's image, record, Boot####
  (byte for byte, for each BootOptionSupport) and BootNext, in that
  order; a failing write or read-back leaving nothing; the lowest
  Boot#### that neither exists nor BootOrder or BootNext holds; an
  existing image file failing a new set and staying. set staging what it
  selected, with its --include, --access-level, image and either
  grant; its store
  named "(staged for the next boot)"; a new set on
  the fake Linux, then appending without --image; --image missing, with
  and without Secure Boot; no ESP; in a HiiDB whose PASSWORD question
  keeps its password in BootNext, as its VarStore or as a VarStore
  outside any FormSet of its VarStoreId, nothing staged and BootNext
  never written. --image parsed into SetOptions, and refused by the Ilo
  backend. In a HiiDB whose IFR past the walk's end may hold a
  PASSWORD, staging refused, nothing written.
- 1 new test: beside a PASSWORD of VarStoreId 0 or one that edk2 may
  route to a VARSTORE_NAME_VALUE, staging refused with the grant
  "allow", the refusal naming VarStoreId 0 for the first, nothing
  read or written and no image placed; beside one on a buffer
  VarStore, staged.
- 31 mutants, each failing a new test: any GPT partition taken as the
  named one, or an MBR one of another number; no fallback without a Hard
  Drive node; several ESPs accepted; a directory of a volume, a volume
  of another type or a later mount point taken; mount points unescaped;
  a whole disk taken; 4096-byte sysfs sectors; the image overwritten;
  the directory deleted with other files; no path check, or ".", ".." or
  "/" accepted in a name; the read-back unchecked; no record, Boot####
  or BootNext written, or no undo; the category always or never
  LOAD_OPTION_CATEGORY_APP; no HIDDEN; Boot0000 taken though it exists;
  no Hard Drive node; a new set without --image staged; no Secure Boot
  text; an append unrecorded; --image accepted by the Ilo backend, or
  not passed on to SetOptions.
- 6 mutants run at the end of this series, each failing
  set_stages_what_it_selected: the image, --include or --access-level
  not taken from SetOptions, the request's include or access level
  dropped, or its value type changed.
- 2 mutants run at the end of this series, each failing
  set_stages_what_it_selected: the grant not taken from SetOptions;
  the request's grant not recorded.
- 4 mutants run at the end of this series, each failing a new test:
  BootOrder and BootNext not skipped for the free Boot####; ".."
  accepted in DEVNAME; the mount point's device unchecked; the undo run
  when placing the image fails.
- 1 mutant run at the end of this series, failing
  staging_writes_no_password_byte: staging through variables that
  withhold no password byte.
- 3 mutants run at the end of this series: a driver-held store named
  "(its driver)" whatever holds its value fails the new test of its
  name; staging that withholds the PASSWORD questions of the FormSets
  only, and a VarStore outside any FormSet of a PASSWORD's VarStoreId
  not withheld, each fail staging_writes_no_password_byte.
- 1 mutant run at the end of this series, withholding_of without
  withheld_reaching's refusals, fails the new test of IFR past the
  walk's end.
- 1 mutant run at the end of this series, staging's variables over the
  PasswordQuestions of no package list, fails the new test of a
  PASSWORD that its driver may keep in any variable, at VarStoreId 0,
  that of IFR past the walk's end and staging_writes_no_password_byte.
- 1 mutant run at the end of this series, staging reading BootNext
  before its check, fails the new test of a PASSWORD that its driver
  may keep in any variable.
- make test-e2e-qemu-x86_64, test-e2e-qemu-i686 and
  test-e2e-qemu-aarch64 at the end of this series: hii-readwrite
  passes; with the old expectation it fails on x86_64.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1620 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The Boot#### of a staged set starts uefisettings.efi with the command
line "uefisettings.efi apply-staged <nonce>". Until now that command did
not exist. Now uefisettings.efi applies the staged set of that nonce:
- It records the outcome "started" before the first Callback(), and
  applies no request unless that record is written. A nonce that has an
  outcome already applies no request again, as when its Boot#### starts
  a second time after a crash, a hang or a failed deletion: a recorded
  start becomes "interrupted", as the OS would read it, any other
  outcome stays, and the deletions below still run, so that no boot
  loops on the set.
- It sets each request's question through its driver's Callback()s, as
  set in the UEFI Shell does. The question is the one whose driver
  holds its value as the request's QuestionId of the request's FormSet,
  in the HII database exported again for each request, as a request
  before may have changed it. It is refused unless exactly one question
  matches, the states that set included cover each state it may be in
  now, with set's access level, and it takes the request's value type.
  It checks whether the question is read-only now, as set did: one
  that EFI_IFR_FLAG_READ_ONLY makes read-only is
  UnsafeOperation::ReadOnlyQuestion, which the grant that set recorded
  with the request must allow, checked after every refusal that it
  cannot lift and before the first Callback(); one that an
  EFI_IFR_VALUE gives its value has no driver that holds it then, and
  is refused as gone.
  Its texts are those of the platform language (PlatformLang), as set
  in the UEFI Shell shows them without --language.
- Every refusal or error becomes that request's result: the outcome
  "finished" records each request, applied or not, with the text set
  answers and the warning of each unsafe operation that applying it
  lifted, also before it failed.
- It deletes the set's Boot#### if it still holds the set's command
  line, with a BootNext that names it, and a BootNext that names
  BootCurrent only if BootCurrent's Boot#### holds the command line of
  the nonce, so that another tool's BootNext stays. The boot manager
  deletes BootNext before it starts that option (UEFI 2.11 §3.1.2), so
  one that names it now was written since.
- It prints each request's result, after a "warning:" line for each
  operation lifted, each variable it deleted and each failure, each
  line as TerminalText after "apply-staged: ", so that no HiiDB string
  rewrites the console; a result names its question as it is, as the
  warning of a read-only question does, which TerminalText escapes
  once. Then it resets the platform cold, as UiApp does after a change
  that needs a reset (edk2-stable202608
  MdeModulePkg/Application/UiApp/FrontPage.c SetupResetReminder). So the
  OS starts in a boot whose boot path holds no uefisettings.efi.
A step that fails is listed, and the steps after it still run. Without
a staged set of the nonce, it applies and records nothing, and deletes
BootCurrent's Boot#### only if that holds the command line of the
nonce. The set's record and image stay: the OS settles them.

In a HiiDB that declares a setup password question, set in the UEFI
Shell writes only with --i-am-fine-to-brick-this-system, as no setup
browser runs there to ask for the password. Before the OS, none runs
either. So apply-staged applies no request in such a HiiDB, and set
from an OS stages no question that its driver holds in one, before it
writes anything, with the flag too; the next change lets the flag lift
both.

apply-staged reads and writes this firmware's variables without the
bytes of the PASSWORD questions of its HII database: a step that would
write over them fails, so where one keeps its password in the outcome
record, no start is recorded and no request is applied. Its writes
record or delete whole variables, not DataPatch writes into a VarStore,
so they fail on any variable that holds such bytes. Where a
PASSWORD question's VarStore is unknown, as in IFR that uefisettings
skips, for VarStoreId 0, which names none, or beside a
VARSTORE_NAME_VALUE that edk2 may route it to, its bytes could be in
any variable, so apply-staged applies, records and
deletes nothing, also for a request recorded with the grant "allow".
set from an OS refuses to stage such a set, with that refusal: staging
writes at Runtime, and its check refuses up front what apply-staged's
BootServices check refuses (PasswordQuestions::check_withholding),
before anything is staged.
The setup password question that apply-staged and staging look for
may be in a FormSet or outside any (PasswordQuestions::of_lists).

There is no path that returns EFI_ABORTED: ResetSystem() does not
return (UEFI 2.11 §8.5.1.1), and the uefi crate types it so.

Test Plan:
- 14 new tests:
  - the start recorded before each request is applied, each result
    recorded and printed after its warnings, the Boot#### deleted and
    printed, the record
    kept; BootNext of the set's Boot####, or of a BootCurrent whose
    Boot#### holds the nonce's command line, deleted, and of another
    option or of a BootCurrent of another command line or absent kept;
  - a nonce whose outcome is started, finished or interrupted: no
    request applied, a start turned interrupted, the others kept, and
    the Boot#### and BootNext deleted all the same;
  - no request applied when recording the start fails, with the
    cleanup all the same;
  - another nonce's set, no set, BootCurrent of another command line
    and a malformed nonce: nothing applied or recorded, and only a
    Boot#### of the nonce's command line deleted;
  - the question of a request found by FormSet GUID and QuestionId
    among those held by their driver; a grayed-out one only when set
    included it; one gone, in two package lists, of another value type,
    or with an access level and no AMI VarStore refused, and none
    beside a setup password question, in a FormSet or outside any; its
    texts in the language requested;
  - set from an OS refused beside a setup password question when it
    would stage, with --i-am-fine-to-brick-this-system too, before any
    write; set of a stored question from an OS, and in the UEFI Shell
    with the flag, as before;
  - a request's question that EFI_IFR_FLAG_READ_ONLY makes read-only
    refused under a recorded "refuse" and lifted under "allow", one
    that an EFI_IFR_VALUE gives its value refused under either, and a
    writable one lifting nothing;
  - a request of a STRING or an ORDERED_LIST without a VarStore and
    with EFI_IFR_FLAG_CALLBACK, which no driver holds, refused as
    gone under either grant, before any Callback(); that of a
    CHECKBOX that its driver holds found;
  - a request that fails after its driver lifted an unsafe operation
    keeping that operation's warning and its error after them;
  - a result line naming its question as it is, `\` and control
    characters too, for TerminalText to escape once;
  - a PASSWORD question that keeps its password in the outcome record:
    no start recorded, no request applied, the record never written,
    the Boot#### deleted all the same;
  - IFR that uefisettings skips: nothing applied, written or deleted;
  - a PASSWORD of VarStoreId 0 or one that edk2 may route to a
    VARSTORE_NAME_VALUE: nothing read, applied, written or deleted, a
    request of the grant "allow" too, the refusal naming VarStoreId 0
    for the first; beside one on a buffer VarStore, the requests
    applied;
  - staging refused up front with apply-staged's refusal where IFR
    that uefisettings skips may hold a PASSWORD question: nothing
    written or staged, no image on the ESP.
- 1 new test of uefisettings.efi's lines: a line with control,
  Bidi_Control and line-break characters and `\` in a question's
  prompt prints as TerminalText after "apply-staged: ", and through a
  console that renders ASCII only, every other character escaped too.
- 12 mutants run at the end of this series, each failing a new test:
  a request applied though recording the start failed; the start,
  the finished outcome or the Boot####'s deletion skipped; BootNext
  of BootCurrent kept, or of another option deleted; the nonce
  unchecked; BootCurrent's Boot#### kept without a set; the first of
  several matching questions taken; the included states, the value
  type or the QuestionId ignored.
- 2 mutants run at the end of this series, each failing a test that this
  commit adds or extends: a nonce with an outcome applied again;
  BootNext of BootCurrent deleted whatever command line its Boot####
  holds.
- 1 mutant run at the end of this series fails the extended test of
  the question found: its texts not in the language requested.
- 3 mutants run at the end of this series, each failing a new test:
  the variables withholding no password byte; the PASSWORD questions
  of skipped IFR uncounted; the Runtime reach of an OS taken, which
  withholds the known passwords only.
- 1 mutant run at the end of this series, apply-staged's variables
  over the PasswordQuestions of no package list, fails the new test of
  a PASSWORD that its driver may keep in any variable, at VarStoreId
  0, and those of the outcome record's password and of skipped IFR.
- 1 mutant run at the end of this series, apply-staged reading
  BootNext before its check, fails the new test of a PASSWORD that its
  driver may keep in any variable.
- 1 mutant run at the end of this series: staging that stages what
  apply-staged refuses fails the new staging test.
- 5 mutants run at the end of this series, each failing a test that
  this commit adds or extends: the recorded grant ignored; the
  read-only check off; the outcome's warnings dropped; the printed
  warnings dropped; a failed request's lifted operations dropped.
- 1 mutant run at the end of this series, apply-staged taking a
  request's question by its QuestionId alone, fails the new test of
  a STRING and an ORDERED_LIST, and those of a read-only question and
  of the question found.
- 3 mutants run at the end of this series, each failing a new test of
  the lines: a result naming its question as Debug spells it; a line
  printed without TerminalText; a line printed whatever the console
  renders.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1634 lib unit tests; cargo test --locked --bins passes: 76
  tests; cargo clippy -D warnings of the x86_64 UEFI build passes.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
In a HiiDB that declares a setup password question, set in the UEFI
Shell writes only with --i-am-fine-to-brick-this-system, as no setup
browser runs there to ask for the password. A set staged for the next
boot is applied by uefisettings.efi before the OS, so it follows that
rule. Until now staging and apply-staged refused such a HiiDB outright,
so staging was unusable in any HiiDB that declares a PASSWORD question.

Staging and applying there are now an unsafe operation of their own,
UnsafeOperation::StagedSetupPassword, under the one
--i-am-fine-to-brick-this-system flag; there is no new flag. Its
refusal keeps the text of the old one and names the flag: "this HiiDB
declares a setup password question, and a set staged for the next boot
is applied before the OS, where no setup browser asks for or checks the
password; pass --i-am-fine-to-brick-this-system to stage it".
PasswordQuestions::staged_setup_password(), beside
setup_password_bypass(), gives it where the HiiDB declares a PASSWORD
question, in a FormSet or outside any; check_staging goes.

From an OS, set takes it in when a question that it selects stages,
and checks it with its other unsafe operations before its first write;
a set that stages nothing lifts nothing for it. apply-staged takes it
in for every request in such a HiiDB and checks it against the grant
that set recorded with the request, before the first Callback(). With
the flag, set and apply-staged warn of it, and the outcome record keeps
the warning. No byte of a PASSWORD question is shown or written, with
the flag or without, and staging still refuses what apply-staged would
refuse whatever the grant, such as a set beside a PASSWORD outside any
FormSet whose VarStore is unknown. The Linux build's long help of
--i-am-fine-to-brick-this-system on set and hii set lists the
operation, and the README's Unsafe operations table gives it a row.

Test Plan:
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1635 lib unit tests.
- 1 new test: a HiiDB that declares a password question makes a staged
  set unsafe, and one without makes it safe.
- set from an OS in a HiiDB with a setup password question: staging
  refused without the flag, before any write, also with every other
  option of set; staged with it, lifting
  StagedSetupPassword; a stored question written with and without the
  flag, lifting nothing; in the UEFI Shell with the flag, lifting
  SetupPassword.
- apply-staged refuses a request in such a HiiDB recorded without the
  flag, with that refusal's text, and finds the question of one
  recorded with it, lifting StagedSetupPassword.
- Staging refused up front, with apply-staged's refusal, beside a
  PASSWORD outside any FormSet whose VarStore is unknown, with the
  flag.
- 5 mutants run at the end of this series, each failing a test that
  this commit adds or extends: staging that adds no
  StagedSetupPassword; staging that adds it though nothing stages;
  apply-staged adding none; staged_setup_password() never giving it;
  apply-staged's check over the PASSWORDs of the FormSets only.
- 1 mutant run at the end of this series, an --include taken as the
  grant of StagedSetupPassword, fails the refusal with every other
  option.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
From Linux, get of a question whose value only its driver holds shows
why it has no value, as no Callback() is reachable once the OS runs.
Now it also shows what the records of staged sets tell of that
question, read from this machine's EFI variables, without writing any:
- while a set waits for its boot, the question's last request in it:
  "<value> is staged for the next boot, as Boot####: restart to apply";
- once the boot is over, the question's last result in its outcome:
  "the last staged boot applied <value>: <result>", or "did not apply
  <value>: <result>", each followed by "; warning: <text>" for each
  warning that the result keeps; for an interrupted boot, that it
  "stopped while it
  applied <value>, which may be partly applied"; for a boot that did
  not start uefisettings.efi, that "<value> is not applied".
The outcome stays after set settles the set, so get keeps showing the
last one. A value shows as get shows a stored one: the option's text,
the number, or 0 or 1. An outcome of "started" whose set is gone, and a
question that no request names, add nothing. get of --efivars or
--no-efivars reads no records.

No ExportConfig snapshot holds such a question: its <ConfigResp>s give
the bytes of VarStores only. So beside the snapshot, as without it, get
shows the question's refusal, its IFR default and the note, with no
<snapshot> mark. NextBootStaging::answer reads the records through any
VariableData, so a host test reaches it.

Test Plan:
- 1 new test: the note of a pending request, of an applied and a not
  applied result, of an applied result with two warnings, of an
  interrupted and a never-started boot, and none
  for no records, for a start whose set is gone and for another
  question.
- 1 new test of get on Linux beside the ExportConfig snapshot and
  without it: the driver-held question shows its refusal, its IFR
  default and the note of a pending set, never a snapshot value, while
  a stored question of the same prompt reads the snapshot only beside
  it.
- 5 mutants run at the end of this series, each failing the new test:
  the first request shown instead of the last; applied and not
  applied swapped; a pending request or an interrupted boot not
  shown; the note of another question shown.
- 1 mutant run at the end of this series fails it: the warnings
  dropped from the note.
- 1 mutant run at the end of this series, failing the new test of get:
  the note dropped from the answer.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1637 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
Fedora's kernel-core-6.17.1-300.fc43, the kernel of the x86_64 and
aarch64 guests, builds FAT and VFAT as modules (CONFIG_FAT_FS=m,
CONFIG_VFAT_FS=m) but ships no module: kernel-modules-core of the same
build holds them, as kernel/fs/fat/fat.ko.xz and vfat.ko.xz.
guest-packages-x86_64 and guest-packages-aarch64 now pin it, as
guest-packages-aarch64-unfixed pins its kernel's, so that a guest can
mount a FAT file system. Each sha256 is the one that the Fedora 43
release's primary.xml lists. CI's cache key hashes guest-packages-*,
so it changes by itself.

Test Plan:
- Each row's sha256 and size match primary.xml, whose sha256
  repomd.xml lists, and each package holds kernel/fs/fat/fat.ko.xz and
  vfat.ko.xz.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1637 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
init loaded run.sh's modules without checking insmod, so a module that
did not load, such as one loaded before a module that it depends on,
showed only later, as a test failing for want of what it provides.
init now notes each module that insmod refuses and, once it knows the
test terminal, prints "cannot load:" there with their names and fails
the setup, as for efivarfs. A pattern that matches no module still
loads nothing.

Test Plan:
- make test-e2e-qemu-x86_64 SCENARIOS=staged-set at the end of this
  series, with x86_64's esp_disk_modules reversed so that vfat.ko loads
  before fat.ko: the boot prints "cannot load: 01-vfat.ko" and fails
  its setup.
- The QEMU rows of every architecture pass, and with them every guest
  that loads modules.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The new scenario staged-set runs a staged set end to end: Linux stages
questions whose driver holds their value, the firmware starts the
staged uefisettings.efi from BootNext, and Linux reads the outcome,
on x86_64, i686 and aarch64.

devices=esp-disk attaches a writable 64 MiB disk that the boots share.
sfdisk partitions it as tests/qemu/esp-disk.sfdisk. The EFI system
partition is GPT entry 2 but the first partition on the disk, so a
Hard Drive node numbered by place would not start the image (UEFI 2.11
§10.3.5.1). run.sh also puts the UEFI Shell's uefisettings.efi in the
initramfs, and the modules that Linux needs to mount the ESP: on i686,
the virtio, FAT and NLS modules of Debian's kernel package; on x86_64
and aarch64, only FAT and VFAT, from kernel-modules-core, as Fedora's
kernel-core builds them as modules (CONFIG_FAT_FS=m, CONFIG_VFAT_FS=m)
and builds in the rest. It numbers the module files, so that init
loads each after those it depends on. CI gets sfdisk from the fdisk
package.

A rebooting-shell: boot runs QEMU without -no-reboot. A reset before
the UEFI Shell then restarts the firmware instead of ending QEMU.
check-shell-log.sh reads the console before the script's start as the
step "firmware", which has no status. A new check, count, matches the
number of lines.

The boots of staged-set:
1. Linux formats the ESP and stages two questions with two sets, which
   append to one staged set, the second with
   --i-am-fine-to-brick-this-system, which lifts nothing there; the
   record keeps each request's grant, "refuse" and "allow".
2. The firmware starts its Boot####, by HD(2,GPT,...). uefisettings.efi
   applies one request, records the driver's refusal of the other,
   prints that it deleted its Boot####, and resets the platform. The
   firmware loads its drivers twice.
3. Linux reads both results through get and the outcome record,
   neither of which keeps a warning. It checks the driver's variable,
   stages another set and deletes that set's image.
4. The firmware fails to load the image and boots on, once.
5. Linux reads that uefisettings.efi never started. The next set
   settles the old one, which deletes its Boot####, and stages a
   question of callback-forms whose Callback(CHANGED) resets the
   platform.
6. That reset comes before uefisettings.efi records any result.
7. Linux reads that the boot stopped while it applied the set, which
   the driver's variable confirms. The next set records the outcome as
   interrupted.

Once BootNext is gone, nothing references a staged Boot####, and the
firmware may remove it (UEFI 2.11 §3.1.1). The guest's OVMF does so
after the interrupted boot. It writes its Grub option at the lowest
number that neither BootOrder nor BootNext holds, then removes that
option as stale (edk2-stable202402 BmGetFreeOptionNumber,
PlatformBootManagerAfterConsole). The aarch64 guest's AAVMF keeps it,
so the test takes either. The tests count the Boot#### that hold a
staged command line, so they expect no particular number.
src/lib/esp/sfdisk_images.rs gains sfdisk's GPT of the disk, which the
codec must name as partition 2.

Test Plan:
- make test-e2e-qemu-x86_64, test-e2e-qemu-i686 and
  test-e2e-qemu-aarch64 SCENARIOS=staged-set: all 7 boots pass on each.
- RED: without x86_64's esp_disk_modules, stage_two_sets fails with
  "No such device" from mount.
- Two QEMU mutants, run on this change before a rebase, fail staged-set
  on x86_64: apply-staged skipping its reset (boot 2 fails), and settle
  keeping the image (after_the_applied_boot fails).
- Two more QEMU mutants fail staged-set on x86_64: the Hard Drive node
  numbered by the ESP's rank on the disk, not its GPT entry
  (stage_two_sets fails, and the firmware fails to load the staged
  Boot#### from HD(1,GPT,...): Not Found), and apply-staged keeping its
  Boot#### (boot 2 prints no "deleted Boot####" line).
- With x86_64's esp_disk_modules reversed, so that vfat.ko loads
  before fat.ko, the boot fails its setup with "cannot load:
  01-vfat.ko".
- The sfdisk test gains the QEMU disk's ESP: partition 2, start 2048,
  size 81920.
- scenario-options-test.sh: 3 new cases for devices=esp-disk; all 72
  cases pass.
- check-shell-log.sh on an earlier shell-callback-forms console:
  firmware checks pass and fail as expected, and a status check of
  firmware fails.
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1637 lib unit tests.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
Windows mounts the EFI system partition without a drive letter, so
staging from Windows must find it among the volumes. esp::windows lists
them with FindFirstVolumeW and FindNextVolumeW and maps each to its
disk with IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS. A volume is an ESP
only if it spans exactly one disk extent and the codec finds an ESP
entry in that disk's partition table with the same start and size. The
codec reads the table through \\.\PhysicalDriveN in the logical blocks
of IOCTL_DISK_GET_DRIVE_GEOMETRY.

The choice is the one Linux makes: the volume whose partition
BootCurrent's Hard Drive node names, else, if it names none, the only
ESP. Two volumes or none refuse, with every volume and why it is no
ESP. Only ERROR_NO_MORE_FILES ends the list. A volume or disk that
Windows denies with ERROR_ACCESS_DENIED refuses the search and says
that uefisettings needs Administrator. Every other failed call is named
with its code next to its volume.

The Win32 calls sit behind the EspCalls trait. esp::win32_calls makes
them on Windows, and fakes stand in for them in the tests of every
host. Placing a file on the ESP flushes no directory on Windows: the
file's sync_all, FlushFileBuffers, already writes its directory entry,
those of its parent directories and the FAT (FatCommonFlushBuffers in
filesys/fastfat/flush.c of Microsoft's Windows-driver-samples).

MountedEsp, its staged files, and the BootCurrent rule move from
esp::linux to esp, which both locators share. Both implement the new
EspLocator trait, which staging calls.

Test Plan:
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1645 lib unit tests.
- esp::windows tests: a mirrored pair of ESPs resolved by BootCurrent,
  a BootCurrent ESP that no volume is, 0/1/2 ESPs without BootCurrent,
  512- and 4096-byte blocks, an MBR ESP by its slot, a GPT entry whose
  index differs from its place on the disk, 0 or 2 extents, negative
  or partial extents, each failed Win32 call, a short read, and a
  denied disk or volume.
- One fixture gives the same Hard Drive node through the Linux and
  the Windows locators.
- 7 mutants run at the end of this series, each failing a new test:
  the first of several ESP volumes taken; a denied volume skipped
  unnamed; any error ending the volume list; the first of two
  extents taken; the extent's offset ignored; a short read taken;
  ERROR_ACCESS_DENIED not asking for administrator.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
On Windows, set now stages a question whose value only its driver
holds as it does on Linux. It records the staged set in the firmware
environment variables, copies --image to \EFI\uefisettings on the ESP
through the ESP's volume GUID path, and reads the copy back to check
its SHA-256. The ESP is the volume that esp::windows finds. Records,
the foreign-file refusal and cleanup are the shared code that Linux
runs. get shows what the records tell of such a question, as on Linux.
As on Linux, Windows set stages such a question in a HiiDB that
declares a setup password question only with
--i-am-fine-to-brick-this-system, whose grant each request records;
the long help of the flag on set lists that operation.

staged_set::linux becomes staged_set::next_boot, built for Linux and
Windows. Only system_variables and system_esp differ: efivarfs and
the mounted vfat volumes on Linux, the firmware environment calls and
the volumes on Windows. NextBootStaging::answer takes the Result of
system_variables(). stage_request and NextBootStaging's check take
any EspLocator. rand, for
the nonce, is now a Windows dependency too.

Windows: set stages a question that its driver holds, which it refused
before: driver_held_setter() builds a NextBootStaging from the HiiDB's
package lists, as on Linux, which stages without the bytes of their
PASSWORD questions and refuses up front what apply-staged would
refuse. set takes --image for it, and get shows what the records
tell. BootCurrent, SecureBoot, BootOrder, the load option codec,
set_refusal, and PasswordQuestions::check_withholding
and withholding_of now serve the Windows build too, and their
allow(dead_code) reasons say so.

Test Plan:
- cargo check --locked --all-targets and cargo test --locked --lib
  pass: 1647 lib unit tests.
- One test stages a new set and appends to it through each locator:
  the mounted ESP on Linux, and on every host a volume whose GUID path
  a directory stands for.
- On every host: the image refusal under Secure Boot, and the refusal
  when no volume is the ESP.
- set --image parses on Windows too.
- [UNVERIFIED] Firmware booting a copy that Windows staged, and std::fs
  over a real volume GUID path: no Windows machine here.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
Windows set writes the staged files through the ESP's volume GUID path.
Where Windows does not let it, the user can mount the ESP with
`mountvol S: /s` and pass `set --esp S:`. set still finds the ESP among
the volumes, as BootCurrent's Hard Drive node names it, and refuses
unless the volume mounted there is that ESP. It asks Windows with
GetVolumeNameForVolumeMountPointW, which takes a drive letter, a
mounted folder or a volume GUID path (Microsoft Learn,
GetVolumeNameForVolumeMountPointW). Then it copies, reads back and
cleans up through S:\ as it does through the GUID path.

SetOptions gains staging_esp. EspLocator gains mounted_at: Linux, which
writes through the mount point where it finds the ESP mounted, refuses
any mount point.

Windows: set takes --esp, and stages through the mount point that it
names once the volume there is the ESP; without --esp it stages through
the volume GUID path as before.

Test Plan:
- make -k RUST_TOOLCHAIN= lint test passes: 1650 lib unit tests, 1748
  tests in all, including clippy-windows for x86_64- and
  aarch64-pc-windows-msvc.
- A set staged and appended through a mount point lands its files
  there, though Windows names the mounted volume's GUID in another
  case; a mount point of another volume and one that Windows does not
  know are refused, with the volume or the failed call named.
- Linux refuses an ESP mount point.
- 5 mutants run at the end of this series, each failing a test that
  this commit adds or extends: any volume's mount point taken; volume
  GUID paths compared by case; a mount point without its trailing
  backslash; Linux taking --esp; --esp not taken from SetOptions.
- set --esp parses on Windows (runs in the Windows emulation).
- [UNVERIFIED] Writing through a real `mountvol` mount point: no Windows
  machine here.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
set on Linux and Windows stages a question whose value only its driver
holds, and apply-staged applies it before the OS, but the README still
said that set refuses such a question there. A new appendix section,
"Sets staged for the next boot", says what set --image writes and in
which order, which Boot#### it takes, how set finds the EFI system
partition on Linux and on Windows, with --esp, when it refuses to stage,
a capsule on disk among the cases, what apply-staged does before the OS,
also when its Boot#### starts again, what get shows afterwards, and when
set settles the old set. The UEFI Shell and Windows sections point to
it. The setup password text and the Unsafe operations row of a set
staged beside a setup password cover Windows too, and say what a
db-trusted uefisettings.efi then lets an OS administrator do with
--i-am-fine-to-brick-this-system; apply-staged's paragraph says that it
checks each request against the recorded flag, prints its warnings and
keeps them, which get shows; and the text after the table of questions
without a VarStore says that from an OS get refuses such a question and
set stages it. A paragraph says that staging and apply-staged write no
byte of a password question, and that set refuses to stage a set whose
password bytes apply-staged cannot tell; another that set stages after
the EFI variables of the other matches and that its errors name a staged
question
"(staged for the next boot)".

Test Plan:
- Each statement matches the staged-set commits' code and tests: the
  staging order and undo, the free Boot####, the ESP choice and its
  mount point check, the refusals, apply-staged's steps and its second
  start, get's texts and settling, the password bytes that neither
  writes, the refusal to stage where apply-staged writes nothing, and
  the name of a staged question in set's errors.
- [UNVERIFIED] Firmware booting a copy that Windows staged, and --esp
  through a real mountvol mount point: no Windows machine here, as the
  README says.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The UEFI Shell, Windows and macOS builds took --hii-source and
--efivar-memory and ignored them, as each reads the HiiDB in one way
only, so a source that the user named was silently not the one read.

Only the Linux build now defines the flags, in its platform module.
The other builds flatten an empty HiiSourceArgs, so clap refuses either
flag as an unexpected argument, before or after the command, and the
UEFI Shell build exits with EFI_ABORTED: main returns clap's exit code
2, and std 1.93.1 library/std/src/sys/process/uefi.rs:298-304 maps
every nonzero u8 to ExitCode::FAILURE. Their usage line loses
[OPTIONS]: clap_builder 4.5.27 src/output/usage.rs:204-250
(needs_options_tag) counts no help, version, hidden, required or
required-group option (:209-243), and --help and --version are all
that is left; shell-driver-sample's help row takes that line.

The Linux HiiSourceArgs derives no Default, so no Linux code can hand a
command the default source in place of the flags'. handle_cmds reads
the HiiDB of get, show-ifr, list-questions and list-strings through
HiiDbReader, which a test replaces to check that each reads from the
source of the flags, given before hii, between it and the command or
after the command.

Test Plan:
- At this commit (tree 39be217): cargo check --locked --workspace
  --all-targets with RUSTFLAGS='-D warnings' passes; cargo test
  --locked --lib: 1650 passed; --bins: 78 passed, among them the new
  hii_commands_read_the_hiidb_from_the_flags_source and
  hii_source_flags_exist_on_linux_only. The tests of the Windows build,
  run on Linux under its cfgs: 996 pass, as on the parent, 079ef57
  (tree 9eb606a), and each that passes there passes here but
  hii_source_flags_default_and_follow_the_command, now in the Linux
  build's platform tests.
- On the parent, hii_source_flags_exist_on_linux_only alone fails
  under the Windows build's cfgs: uefisettings --hii-source efivar
  show-translations parses.
- At the tip of the series (tree 9964186), which changes only
  tests/qemu: make -k lint passes.
- Mutants, on the series before its rebase onto 079ef57 (tree
  a2029fe3): get, show-ifr, list-questions or list-strings reading
  from a source parsed from an argv without the flags fails
  hii_commands_read_the_hiidb_from_the_flags_source, also with only
  the flags between hii and the command; each of the 11 sites that
  pass the source on fails to build given HiiSourceArgs::default()
  instead; --hii-source or --efivar-memory without global fails 5
  tests; --hii-source acpi naming systab fails
  hii_source_options_follow_the_flags; the Windows build taking
  --hii-source again fails hii_source_flags_exist_on_linux_only.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
shell-driver-sample checks that the UEFI Shell build's help names
neither --hii-source nor --efivar-memory, and that it refuses
--hii-source before the command and --efivar-memory after it as
unexpected arguments, with clap's text (clap_builder 4.5.27
src/error/format.rs:352-358) and EFI_ABORTED.

hii-systab names the vendor ACPI table method, which finds no table
there, before and after hii show-ifr, get, list-questions and
list-strings, and checks that each reports that source absent and
tried no other: a command that dropped the flags would read the
configuration table by the automatic order and succeed.

Test Plan:
- At this commit (tree 9964186): cargo check --locked -p
  uefisettings-qemu-guest --features test-vm --all-targets, with
  RUSTFLAGS='-D warnings', and make -k lint pass; make test: 1750
  passed; make test-i686: 1747 passed; the tests of the Windows build,
  run on Linux under its cfgs: 996 pass, as at its parent.
- At this commit: every scenario of make test-e2e-qemu that runs on
  x86_64 passes there (122), among them shell-driver-sample and
  hii-systab; shell-driver-sample, hii-systab and the other scenarios
  whose tests pass --hii-source pass on i686 (11) and aarch64 (13,
  with hii-systab-vamap and the hii-no-memory-map scenarios).
- With the series' tests/qemu files alone on 079ef57 (tree 0dac5584):
  shell-driver-sample fails 6 checks on x86_64, the help's usage line
  and its naming of the flags, and the status and error line of both
  refusals, as that build takes and ignores the flags; hii-systab
  passes.
- hii-systab fails the_other_methods_report_their_sources_absent on
  x86_64 when PlatformHiiDb::read, its list-strings read or the Linux
  HiiDbArgs::read reads with the source of an argv without the flags:
  the command reads the configuration table and exits with 0.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
`variable write-signed` with enhanced-authenticated-access signed its
EFI_VARIABLE_AUTHENTICATION_3 without reading the variable that it
writes. It now reads it first, and refuses, before it seeds or writes,
what UEFI 2.11 has the firmware refuse against the stored variable:
- attributes other than the variable's but APPEND_WRITE: "If a
  preexisting variable is rewritten with different attributes,
  SetVariable() shall not modify the variable and shall return
  EFI_INVALID_PARAMETER" (§8.2.3);
- metadata that uefisettings does not take, as it then has nothing to
  check against;
- another Type: "verify that the incoming type matches the existing
  type" (§8.2.5);
- a TimeStamp that is not "chronologically greater" than the
  variable's (§8.2.5), with APPEND_WRITE too, which §8.2.5 does not
  exempt as §8.2.6 does for an EFI_VARIABLE_AUTHENTICATION_2; the
  order is that of edk2-stable202608
  SecurityPkg/Library/AuthVariableLib/AuthService.c
  AuthServiceInternalCompareTimeStamp (:1251-1269): Year, Month, Day,
  Hour, Minute, then Second;
- the variable's own nonce, unless all zero, which asks the firmware
  for one: "If nonce is specified and variable already exists, verify
  that incoming nonce does not match existing nonce. If identical,
  return EFI_INVALID_PARAMETER" (§8.2.5);
- a --current-nonce other than the variable's, and one for a variable
  that does not exist, over which the signature would not verify.

A nonce update without --current-nonce now signs the variable's nonce,
which the caller serializes after the data (§8.2.5 step 3c: "The
current nonce is the one currently associated with this variable") and
which only the metadata that GetVariable() returns gives (§8.2.1), also
where the firmware made it.

A variable that it cannot read, or whose metadata it does not take, it
does not write. --i-am-fine-to-brick-this-system lifts none of these
refusals: none is an unsafe operation, and the flag supplies no input
that is missing. --payload-file stays unchecked against the variable,
and Linux still refuses every such write before the read, as efivarfs
lacks the attribute. edk2-stable202608 implements no
EFI_VARIABLE_AUTHENTICATION_3: its EFI_VARIABLE_ATTRIBUTES_MASK lacks
the attribute (MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
:44-49), so its SetVariable() returns EFI_INVALID_PARAMETER for every
such write (Variable.c:2648-2649).

The metadata decoder now returns the Secondary Descriptor beside the
size, and TimeStamp orders chronologically.

Test Plan:
- RED: this commit's authenticated.rs tests on the parent's code, main
  079ef57: 4 failed (1649 passed):
  sign_and_write_enhanced_checks_the_stored_variable_before_seeding at
  "other attributes", which got the seed error;
  sign_and_write_enhanced_signs_the_stored_nonce_by_default at "signed
  over the current nonce";
  sign_and_write_enhanced_refuses_a_variable_that_it_cannot_read, which
  wrote; and
  sign_and_write_enhanced_refuses_devdb_in_setup_mode_unless_allowed,
  which now expects devdb read.
- time_stamps_order_chronologically and
  authentication_3_metadata_gives_the_secondary_descriptor test this
  commit's API; the mutants below fail them.
- checks_the_stored_variable_before_seeding takes a create, a later
  TimeStamp, another nonce with the current one given or by default,
  another nonce of the current one's size, the start of the variable's
  nonce, an all-zero nonce, also where the variable's is all zero, and
  APPEND_WRITE besides the variable's attributes, each failing at the
  seed after the checks; and refuses, with nothing written, each of the
  refusals above, among them an APPEND_WRITE with the variable's
  TimeStamp, the variable's nonce of zero and nonzero bytes, a current
  nonce that is the start of the variable's, and fewer attributes than
  the variable's.
- writes_what_the_key_signs: its nonce updates now update a variable
  that holds the current nonce. The test double of the
  unreadable-SetupMode test fails the SetupMode read only, as the
  enhanced write now reads the target first.
- cargo check --all-targets passes; cargo test --lib: 1655 passed.
- 19 mutants, run with the last commit's code on an earlier main, where
  the next commit moves TimeStamp's fields into GmtTime, each fail a
  named test, which this tree keeps, as it keeps the lines that each
  mutant changes: the attribute check skipped, APPEND_WRITE kept in the
  comparison, a TimeStamp equal to the variable's taken, one not later
  taken with APPEND_WRITE, the TimeStamp order by bytes or with Month
  and Day swapped, no default current nonce, the incoming nonce as the
  default, the all-zero exception dropped, the held-nonce test inverted,
  a current nonce taken for a create, any current nonce taken, either
  Type mismatch taken, the stored nonce sliced a byte late, an
  unreadable variable taken as missing, the seed before the read, an
  unreadable SetupMode taken, or lifted for the enhanced path.
- 5 more, at the last commit, each fail
  checks_the_stored_variable_before_seeding at a named case: another
  nonce of the variable's size refused, the variable's nonce taken when
  any of its bytes is zero, a nonce refused as the start of the
  variable's, a current nonce taken as the start of the variable's, and
  fewer attributes than the variable's taken.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
`variable info` showed the attributes and the size of a variable. Of a
variable with EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS it now also
shows `metadata`, the headers that GetVariable() returns before the
data, which "must be interpreted according to the metadata headers"
(UEFI 2.11 §8.2.1): Version, Type, MetadataSize, Flags, the TimeStamp
or the nonce, and the Type and Id of the
EFI_VARIABLE_AUTHENTICATION_3_CERT_ID, for every such variable. The
current nonce is what an update signs after the data (§8.2.5 step 3c),
and this is how a user of --payload-file or of another signer learns
it, also where the firmware made it. Metadata that uefisettings does
not take shows as its refusal, never as bytes, and no data is shown.

Linux and Windows read the data already; the UEFI Shell build now reads
that of a variable with the attribute, and of no other. GmtTime gives
TimeStamp its text and its order, which the metadata's TimeStamp
shares.

Test Plan:
- RED: efivar_info_shows_the_metadata_of_enhanced_authenticated_access
  on the parent's code fails at its first case, TimeStamp, which shows
  no metadata.
- efivar_info_shows_the_metadata_of_enhanced_authenticated_access: of a
  variable with the attribute, the metadata of either Type, Version 2's
  refusal, the refusal of data that ends inside the metadata, and that
  of EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS beside it;
  without the attribute, no `metadata`; and never the data.
- variable_info_shows_the_metadata_of_enhanced_authenticated_access:
  the same through the Windows calls, with fakes.
- The QEMU guest test hii_auth87 variable_info_shows_the_metadata: the
  metadata of EnhancedAuthData and the refusal of EnhancedAuthRefused's
  from efivarfs. shell/auth87.tsv's variable-info now expects
  EnhancedAuthData's metadata, from the UEFI Shell build's
  GetVariable(). Both pass in the next commit's runs of hii-auth87 and
  shell-auth87 on x86_64, on an earlier main.
- cargo check --all-targets passes; cargo test --lib: 1657 passed.
- 7 mutants, with the next commit's code, whose src/ is this commit's,
  on an earlier main, each fail a named test, which this tree keeps, as
  it keeps the lines that each mutant changes: no metadata shown, the
  attribute refusal or the decoder's refusal shown as none, a nonce
  shown as Type 1, the Id read from IdSize on, `"metadata": null`
  without the attribute, and GmtTime's text with Day before Month.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
shell-auth3-checks boots the User Mode Secure Boot firmware with
virtio-rng and seeds vars/enhanced-auth-87.json, which now also holds
EnhancedAuthNonce, whose metadata holds a nonce of 8 bytes of 0xA5,
beside EnhancedAuthData, of TimeStamp 2026-11-06T12:00:00Z, and
EnhancedAuthRefused, whose metadata has Version 2, each with the
attributes 0x87. With run.sh's KEK key, `uefisettings.efi variable
write-signed` refuses before it seeds or writes: an equal and an
earlier TimeStamp, other attributes, a nonce for the TimeStamp
variable, Version 2's metadata, the variable's own nonce, a
--current-nonce other than its own, and one for EnhancedProbe, which
does not exist. A later TimeStamp, and another nonce without
--current-nonce, which signs the variable's own, reach SetVariable(),
which edk2-stable202608 refuses with EFI_INVALID_PARAMETER for the
attribute (MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
:2648-2649). Every variable stays as seeded, and EnhancedProbe absent.
`variable info` shows EnhancedAuthNonce's metadata and the refusal of
EnhancedAuthRefused's, from what the firmware's GetVariable() returns.

Test Plan:
- make -k test-e2e-qemu-shell-x86_64, -i686 and -aarch64 with
  SCENARIOS=shell-auth3-checks, on an earlier main: every check of its
  19 steps passed on each.
- RED: this commit alone on an earlier main, x86_64: 10 checks failed:
  info-nonce and info-refused, which show no metadata, and ts-equal,
  ts-earlier, other-attributes, nonce-on-timestamp, refused-metadata,
  nonce-held, nonce-other-current and current-nonce-create, which reach
  SetVariable(). ts-later and nonce-default passed there too, as they
  reach it either way.
- The whole make -k test-e2e-qemu-x86_64 and test-e2e-qemu-shell-x86_64
  sets passed with this code on an earlier main, in 10 runs of their
  scenarios: 115 boot, 125 boots in all, and 8 that only other
  architectures boot skip; each of the 44 Shell boots passed every
  check, and each of the 81 Linux boots printed "test result: ok".
- make -k lint passes; make -k test: 1755 passed; make test-i686: 1752
  passed; cargo test --lib: 1657 passed.
- The Windows emulation of the tests: 1002 passed, where the parent of
  the first commit passes 996, and none that it passes is lost.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
UEFI 2.11 §33.3.8.3.14 has a Forms Processor not process what a
DISABLE_IF whose condition is TRUE holds, and edk2-stable202608
SetupBrowserDxe/IfrParse.c ParseOpCodes skips a FORM under one outside
forms to the DISABLE_IF's END (:1390-1413). get, set and list-questions
offered its questions with --include disabled and wrote them, and
conditions read their values, where Expression.c IdToQuestion finds no
such question, and EQ_ID_VAL gives UNDEFINED (:2659-2663).

The question walks, QuestionIndex and the walk of the stores of a
FormSet, which get and set read and restore around a driver's
Callback(), now skip such a DISABLE_IF. question_state decides a
DISABLE_IF outside forms from the walk of the form-set-list that
VarStore lookups use, which ParseOpCodes evaluates once, before it reads
any value: one that relies on a question, or a true or non-constant
SUPPRESS_IF or GRAY_OUT_IF, or another op whose expression ParseOpCodes
evaluates there, such as a VALUE, before the form in its scope with no
DISABLE_IF ending between them (:2654-2655, :3007-3014), which
ParseOpCodes takes for the DISABLE_IF's, leaves the questions there
undetermined, and a reference to one from another form not known. Each
DISABLE_IF starts from such an op around it, as ParseOpCodes skips to
the END of the innermost one (:1395-1410). The walk runs once per
FormSet.

--keyword still finds those questions, as the edk2 keyword handler
evaluates no condition, so dump-efivars keeps their bytes. PASSWORD
detection walks every op, and the store walk keeps the PASSWORDs there,
so their bytes stay withheld.

Test Plan:
- With this commit's tests on the product code of its parent, 079ef57
  (tree 9eb606a): 8 fail and 1654 pass. Of the 8,
  questions_under_a_true_form_set_disable_if_are_none_of_its_questions
  gets Hidden refused as disabled instead of no response,
  a_reference_to_a_question_under_a_true_form_set_disable_if_is_undefined
  lists no Shown, as Hidden's 1 suppresses it,
  a_form_set_disable_if_that_is_not_constant_leaves_its_questions_undetermined
  and
  a_suppress_if_in_a_form_set_disable_if_leaves_the_forms_after_it_undetermined
  write After, and
  a_true_form_set_disable_if_requests_no_setting_and_declares_no_store_in_it
  requests a setting of a question in it and declares its VarStore;
  a_condition_in_an_undetermined_form_reads_a_question_of_that_form,
  a_question_that_edk2_may_not_parse_has_no_known_value and
  question_index_leaves_out_questions_that_edk2_does_not_parse fail too.
  The tests of the password, the keyword, the dump and the number of
  evaluations pass there, as this commit keeps what they check.
- With them on the product code of an earlier version of this commit, on
  02319dd (tree 355ebf6d), case by case: 5 of the 15 cases of
  a_suppress_if_in_a_form_set_disable_if_leaves_the_forms_after_it_undetermined
  fail. After a DISABLE_IF that ends before a true SUPPRESS_IF, in the
  form-set-list, in First's form or with a TRUE condition, set refuses
  After, and after a VALUE of TRUE outside forms, in a question or not,
  it writes After.
- At this commit on 079ef57 (tree ef8d5853): cargo check --locked
  --all-targets with RUSTFLAGS='-D warnings' passes; cargo test --locked
  --lib: 1662 passed.
- At the tip of the series on 079ef57 (tree dac2727a): make -k lint
  passes; make -k test: 1760 passed; make test-i686: 1757 passed; the
  tests of the Windows build, run on Linux under its cfgs: 1003 pass, 7
  more than the 996 on 079ef57, and none that passes there fails here.
- With the same two commits on 079ef57 (tree dac2727a): of 37 mutants
  of the question walks, the dump walk, the store walk, the PASSWORD and
  keyword walks, the form-set-list walk, its hiding and its reuse, and
  the same-form check, 35 fail a named test. Of the other two, one names
  the last op that may hide instead of the first, which changes only the
  text of a refusal, and one lets the form-set-list's own scope hide,
  which no DISABLE_IF opens.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
publish-hiidb.efi form-set-disable-if-forms registers a form set on
UefisettingsFormSetDisableIf whose forms but the first are in
DISABLE_IFs outside forms: a true one holds Hidden and a PASSWORD,
which O in the first form overlaps; one on Gate, an EFI_IFR_EQ_ID_VAL,
holds After; and a false one holds a true SUPPRESS_IF, then Later.
Shown, in the first form, is in a SUPPRESS_IF on Hidden, which holds 1.

hii-form-set-disable-if checks from Linux that no --include lists, gets
or sets Hidden, that Shown is not suppressed, that O shows and set
writes no byte of the password, also with
--i-am-fine-to-brick-this-system, that get shows After and Later with
both states and why and set writes them only with disabled questions
included, that the keyword HiddenKeyword selects Hidden as disabled,
and that dump-efivars keeps Hidden's byte for that keyword but no byte
of the password. shell-form-set-disable-if checks the same in the UEFI
Shell, where every set needs --i-am-fine-to-brick-this-system, as the
form set declares a PASSWORD.

Test Plan:
- With this commit alone on 079ef57 (tree 33e70c3c):
  hii-form-set-disable-if fails 4 of its 6 tests on x86_64: get refuses
  Hidden as disabled instead of giving no response, list-questions and
  get --keyword ShownKeyword take Shown as suppressed, and get shows
  After without its states. Its tests of the password and of the dump
  pass there.
- With it on a first version of the previous commit, on dfb21b82 (tree
  78e70fca): the dump test fails on x86_64, the dump holding 0 for
  Hidden's 1.
- At this commit on 079ef57 (tree dac2727a): hii-form-set-disable-if
  and shell-form-set-disable-if pass on x86_64, i686 and aarch64. So do
  hii-readwrite, staged-set, shell-readwrite, shell-time-storage,
  shell-auth27, shell-callback-forms and shell-callback-forms-password
  on x86_64, whose HiiDBs hold questions that only their driver holds,
  for which get and set walk the stores of the FormSet.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The Linux build took --hii-source and --efivar-memory and ignored them
where it reads no HiiDB of this machine: in show-translations, variable,
capsule and ilo, in get and set where they take the Ilo backend, and
where -f or the efivars dump of --efivars gives the HiiDB. It also
ignored --efivar-memory in identify, which only checks that the HiiDB
variable exists, and with --hii-source acpi or systab, as only the
efivar method reads that memory.

Both Linux flags are now None unless given, their defaults stated in
their help. Those commands, and HiiDbArgs::read when the file or the
dump gives a HiiDB, refuse either flag given, naming it and why it reads
nothing there; HiiBackend::read_given_hiidb, now public, tells the
latter before any read of this machine. hii_source_options refuses
--efivar-memory with acpi or systab, before anything is read.

The commands reach this machine's HII backend through MachineHii, which
handle_cmds_with takes, in place of main.rs's HiiDbReader: each site
that reads or writes the machine's HiiDB or identifies its backends
hands it the options of the flags, so a test that replaces it checks
the source of hii get, show-ifr, list-questions, list-strings, set,
extract-db and dump-efivars, and of get, set and identify. The other
builds define an empty MachineHii and a refuse_given that refuses
nothing, as they have neither flag.

Test Plan:
- At this commit (tree 54e560e): cargo check --locked --all-targets
  with RUSTFLAGS='-D warnings' passes; cargo test --locked --bins: 81
  passed, among them the new
  machine_commands_read_from_the_flags_source,
  machine_hiidb_flags_are_refused_where_no_machine_hiidb_is_read,
  efivar_memory_is_refused_with_a_method_that_never_reads_it and
  the_flags_are_refused_where_only_identify_would_see_them.
- At the tip of the series (tree 609ba11), which changes only
  tests/qemu: make -k lint passes; make test: 1772 passed, 1769 on the
  parent; make test-i686: 1769 passed, 1766 on the parent.
- Mutants, at that tip: dropping identify's refusal of
  --efivar-memory, or the refusal of get or set where they take the Ilo
  backend, fails
  the_flags_are_refused_where_only_identify_would_see_them;
  identify given the source of an argv without the flags fails
  machine_commands_read_from_the_flags_source and
  efivar_memory_is_refused_with_a_method_that_never_reads_it.
- On the series before its rebase onto 74ad762 and before the
  refusals in identify and on the Ilo backend, which change only
  src/platform/linux.rs (tip tree e2c6a864): the tests of the Windows
  build, run on Linux under its cfgs, 996 pass there, the same 996 as
  on its parent, 32aad68.
- On 32aad68, with the tests adapted to its HiiSourceArgs
  fields, its hii_source_options and its HiiDbReader, and run only
  through commands that read through HiiDbReader:
  hii_source_flags_are_none_unless_given_and_follow_the_command fails,
  as no flag parses to auto and runtime;
  hii_source_options_follow_the_flags fails for acpi and systab with
  --efivar-memory, which give options;
  machine_hiidb_flags_are_refused_where_no_machine_hiidb_is_read
  fails all 42 refusals, as show-translations succeeds, variable and
  capsule reach their payload file, and -f and the dump give their
  HiiDB; efivar_memory_is_refused_with_a_method_that_never_reads_it
  fails all 4, as the read goes ahead.
- Mutants, at that tip (tree e2c6a864): each of the 15 sites that hands
  the source on or turns it into HiiSourceOptions, given the source of
  an argv without the flags, fails
  machine_commands_read_from_the_flags_source; dropping the refusal of
  show-translations, variable or capsule, or of a HiiDB that -f or the
  dump gives, fails
  machine_hiidb_flags_are_refused_where_no_machine_hiidb_is_read;
  keeping --efivar-memory with acpi or systab fails
  hii_source_options_follow_the_flags and
  efivar_memory_is_refused_with_a_method_that_never_reads_it.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
hii-systab checks that the Linux build refuses --hii-source, given
before or after the command, in show-translations and ilo, and in
hii list-strings with -f, a file that extract-db wrote, while both run
without it; and that it refuses --efivar-memory with --hii-source
systab in hii get, with the text of each refusal. In the guest, no
ilorest_chif.so exists, so an ilo command that ignored the flag would
fail with another error, as would list-strings and show-translations
succeed.

Test Plan:
- At this commit (tree 609ba11): make -k lint passes, whose clippy
  checks the QEMU guest crate's tests with --all-features; hii-systab,
  hii-reserved and hii pass on x86_64.
- On the series before its rebase onto 74ad762 (tree e2c6a864):
  cargo check --locked -p uefisettings-qemu-guest --features test-vm
  --all-targets, with RUSTFLAGS='-D warnings', passes; hii-systab passes
  on x86_64, i686 and aarch64, also as hii-systab-vamap; so do the
  other Linux scenarios whose tests pass --hii-source or
  --efivar-memory, on x86_64: hii-devmem-guard, hii-none, hii-reserved,
  hii-acpi-nvs, hii-lockdown-acpi, hii-lockdown-efivar, hii-acpi,
  hii-acpi-hiid and hii-acpi-two-tables.
- With src/ of 32aad68 under the series' tests/qemu, before its rebase
  onto 74ad762: hii-systab fails
  the_flags_are_refused_where_nothing_reads_them on x86_64, as
  uefisettings --hii-source systab show-translations exits with 0.
- With ilo's refusal dropped, on the series before a change to the
  unit tests of the previous commit alone (tree e014819f): hii-systab
  fails the_flags_are_refused_where_nothing_reads_them on x86_64, as
  ilo show-attributes fails with "Unable to find location of
  ilorest_chif.so" instead.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
A QUESTION_REF1, EQ_ID_VAL, EQ_ID_ID or EQ_ID_VAL_LIST in the READ or
WRITE expression of a question took that question's value as retrieved
from its VarStore. In a WRITE, that is the value before the write, so a
SET of it planned the old value. In a READ, retrieving it re-entered
the same READ, a cycle, so the READ was refused.

edk2-stable202608 SetupBrowserDxe/Expression.c IdToQuestion finds the
question in the form first (:853), so these ops push the HiiValue that
THIS pushes (:2733-2741), and UEFI 2.11 sets THIS to the question's
value before a READ (§33.3.8.3.58) or a WRITE (§33.3.8.3.94). They now
push THIS: the stored value in a READ, the new value in a WRITE.
Role::Read and Role::Write carry the QuestionId of their question for
it. A reference to another question is unchanged.

A question of QuestionId 0, which UEFI 2.11 reserves (§33.3.8.2.2),
gets no QuestionId in its role, as Expression.c IdToQuestion2 finds no
question of it (:808-813): QUESTION_REF1 0 in its own READ or WRITE
still refers to no question.

Test Plan:
- RED: the test on the parent's code fails: the question whose READ is
  QUESTION_REF1 of itself plus 1 has no value, a ReadCycle.
- Unit test, conditions.rs (1 new):
  a_reference_to_the_question_that_is_read_or_written_pushes_this: that
  question through VarStoreValues; a READ of QUESTION_REF1, EQ_ID_VAL,
  EQ_ID_ID and EQ_ID_VAL_LIST of the read question and of another; a
  WRITE of a SET of QUESTION_REF1 of the written question and of
  another; a READ and a WRITE of QUESTION_REF1 0 in a question of
  QuestionId 0.
- make -k test on 74ad762: 1770 passed (1769 + 1 new); make
  test-i686: 1767.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
EFI_IFR_QUESTION_REF2 pops a question id and pushes the value of that
question (UEFI 2.11 §33.3.8.3.56). It was not evaluated, so every
condition, READ, WRITE and VALUE holding one was undetermined.

It now takes the question as QUESTION_REF1 does, with what both the
spec and edk2-stable202608 SetupBrowserDxe/Expression.c:3029-3053 give
for the other ids: an id that is no unsigned integer, i.e. a BOOLEAN,
DATE, TIME, STRING, buffer or UNDEFINED, or one above 0xFFFF, or the id
of no question gives UNDEFINED. An id that cannot be read leaves the
question unknown, so the op is not evaluated, as CONDITIONAL and MAP
are on such a value. The id of the question whose READ or WRITE is
evaluated gives THIS, as for QUESTION_REF1.

A DISABLE_IF outside forms that holds one relies on a question, which
UEFI 2.11 §33.3.8.3.14 does not allow there, so its condition is not
known, as with QUESTION_REF1.

Test Plan:
- RED: the tests on the parent's code fail, as QUESTION_REF2 is not
  evaluated there.
- Unit tests, conditions.rs (2 new, 1 extended):
  question_ref2_pushes_the_value_of_the_question_of_the_popped_id: the
  ids of a UINT, a BOOLEAN and a DATE question, of one that cannot be
  read and of one of another type, of no question, 0, 0x10001 from a
  constant and from a question, a BOOLEAN, a DATE, UNDEFINED, and an id
  that cannot be read.
  a_disable_if_outside_forms_is_not_known_where_it_relies_on_a_question.
  a_reference_to_the_question_that_is_read_or_written_pushes_this:
  QUESTION_REF2 of the read or written question and of another, in a
  READ and a WRITE.
- make -k test on 74ad762: 1772 passed (1770 + 2 new); make
  test-i686: 1769.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
edk2-stable202608 SetupBrowserDxe/Expression.c evaluates EFI_IFR_THIS as
QUESTION_REF1 of the question that holds it, and both fail with
EFI_NOT_FOUND where no question has that id (Expression.c:2733-2738).
In a condition, THIS took that as UNDEFINED, i.e. FALSE; it is now
malformed, as QUESTION_REF1 is, e.g. in a question of the reserved
QuestionId 0.

THIS keeps pushing each kind of value that a question gives (UEFI 2.11
§33.3.8.3.77): a UINT, a BOOLEAN, a DATE or a TIME, one that cannot be
read as unknown, and one of another kind as not evaluated.

Test Plan:
- RED: the test on the parent's code fails at "no question", which
  gave UNDEFINED.
- Unit test, conditions.rs (1 new):
  this_pushes_each_kind_of_question_value, in
  the EFI_IFR_VALUE of a question: a UINT, a BOOLEAN, a DATE, a TIME, a
  UINT that cannot be read, a value of another kind, and no question.
- make -k test on 74ad762: 1773 passed (1772 + 1 new); make
  test-i686: 1770.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
EFI_IFR_QUESTION_REF3 pops a question id and pushes the value of that
question in the FormSet that its DevicePath and Guid name (UEFI 2.11
§33.3.8.3.57). It was not evaluated.

It now pops the id as QUESTION_REF2 does, and takes the question where
the spec and edk2-stable202608 SetupBrowserDxe/Expression.c:2881-2937
take the same one:
- without a Guid, the spec takes the current FormSet, while edk2's
  GetQuestionValueFromForm takes the first FormSet of the package list,
  as Setup.c GetIfrBinaryData finds a Nil GUID (:6075): in a FormSet
  that the list starts with, both take the current one, where edk2
  finds the question in FormSet order (Expression.c:2524), as UEFI 2.11
  gives each question of a FormSet its own QuestionId (§33.2.5.4);
- with the Guid of the current FormSet, both take that one, from the
  form first, as QUESTION_REF1 does, so the question whose READ or
  WRITE is evaluated gives THIS;
- with the Guid of another FormSet, the spec takes that FormSet, while
  edk2 takes the current one (Expression.c:2924-2934);
- without a Guid, in the WRITE of the question of the popped id, edk2
  retrieves the question anew (:2561-2567) before Setup.c
  SetQuestionValue writes it (:1995-1998), while the spec takes THIS,
  which a WRITE sets (§33.3.8.3.94).
Where they differ, the result is undetermined and names both: the
value of the current FormSet's question, or the two values in the
WRITE. No effect is then known to both: a condition is unknown, a READ
is refused whatever is stored, a WRITE is refused before any SET, and
an EFI_IFR_VALUE gives no value. The divergences of conditions.rs gain
this kind, an op that the two evaluate apart, next to an UNDEFINED that
a CONDITIONAL drops. Past where edk2 ends the expression at an
UNDEFINED, the result is the spec's: the current FormSet's question,
or, for another FormSet, which is not looked up here, a value that is
not evaluated. The summary and the table of conditions.rs's module
doc gain a row for each of the three.

read_package_list marks each FormSet with the FORM_SET op that its
package list starts with, which parse_form_sets notes per form
package, whether that FormSet parses or not. A FormSet nested in
another's scope has no mark, so QUESTION_REF3 without a Guid there is
not evaluated, naming the nesting.

A DevicePath is not evaluated: it needs a device path converted from
text, which the reason names. A DISABLE_IF outside forms that holds
QUESTION_REF3 relies on a question, so its condition is not known.

Test Plan:
- RED: on the parent's code with this commit's forms.rs and package.rs
  changes,
  question_ref3_takes_the_question_from_the_form_set_that_it_names,
  question_ref3_without_a_guid_takes_the_question_in_form_set_order and
  a_disable_if_outside_forms_is_not_known_where_it_relies_on_a_question
  fail; read_db_marks_the_form_set_that_each_package_list_starts_with
  fails where read_package_list marks no FormSet.
- Unit tests (3 new, 3 changed):
  - conditions.rs
    question_ref3_takes_the_question_from_the_form_set_that_it_names:
    without a DevicePath, with DevicePath 0, and with a Nil Guid, in
    the first FormSet; the Guid of the current FormSet in another one;
    without a Guid in another FormSet, also after a FORM_SET op too
    short for a GUID and of no question; the Guid of another FormSet,
    of a question, of none and of one that cannot be read; a DevicePath,
    also with id 0x10001; no question; a BOOLEAN id; an id that cannot
    be read; a FormSet of an unknown package list, and one nested in
    another FormSet; both disagreements past an UNDEFINED that a
    CONDITIONAL drops; a READ and a condition of the Guid of another
    FormSet; a WRITE of a SET, then the Guid of another FormSet, or of
    the current one; a WRITE of a SET, then no Guid and the written
    question, in the first FormSet and in another, or another question;
    no Guid and the written question past an UNDEFINED that a
    CONDITIONAL drops.
  - conditions.rs
    question_ref3_without_a_guid_takes_the_question_in_form_set_order:
    one QuestionId in two forms, without a Guid, with the current
    FormSet's Guid, and QUESTION_REF1.
  - conditions.rs
    a_reference_to_the_question_that_is_read_or_written_pushes_this
    gains QUESTION_REF3 of the current FormSet's Guid, of the read or
    written question and of another, in a READ and a WRITE.
  - conditions.rs
    a_disable_if_outside_forms_is_not_known_where_it_relies_on_a_question
    gains QUESTION_REF3;
    strings_and_buffers_that_the_spec_gives_take_the_effect_of_undefined
    builds its divergences as the new kind of an UNDEFINED dropped.
  - package.rs
    read_db_marks_the_form_set_that_each_package_list_starts_with: two
    FormSets of one form package, FormSets of two form packages, and a
    first FormSet that does not parse.
- make -k test on 74ad762: 1776 passed (1773 + 3 new); make
  test-i686: 1773.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
EFI_IFR_RULE_REF pushes the value of the rule of its RuleId, an
expression that an EFI_IFR_RULE attaches to the form (UEFI 2.11
§33.3.8.3.63, §33.3.8.3.64). It was not evaluated.

It now finds the RULEs of the FORM or FORM_MAP that holds it, as
edk2-stable202608 SetupBrowserDxe/IfrParse.c ParseOpCodes attaches them
(:2712-2724), but none in the scope of an opcode above
EFI_IFR_MATCH2_OP, which ParseOpCodes skips (:1374-1381). It evaluates
the rule's expression on a stack of its own, as Expression.c
EvaluateExpression does (:2939-2959), with the heap stack of pending
ops that MAPs use, then the ops in the RULE_REF's scope:
- without the rule, also outside forms, it gives UNDEFINED, as both
  the spec and edk2 say;
- a rule that gives UNDEFINED, or whose expression is malformed, e.g.
  leaves two values or pops an empty stack, also in a MAP or past the
  rule's own UNDEFINED, gives UNDEFINED, as edk2 gives for a rule that
  fails (:2952-2956), in the spec's reading too;
- QUESTION_REF1 of a missing question in a rule, which edk2 fails
  (:2733-2738), so that its RULE_REF gives UNDEFINED, gives UNDEFINED,
  as UEFI 2.11 pushes without the question (§33.3.8.3.55), so a
  CONDITIONAL may drop it; outside rules it stays malformed; in a
  match expression of a MAP in the rule, also in a return expression
  of a MAP there, where edk2 fails the MAP too (:3656-3658) while the
  spec's MAP goes on to its next pair, it is undetermined, and past
  where edk2 ends the expression, not evaluated; in a rule that a
  match expression holds, the RULE_REF gives UNDEFINED either way;
- an op that is not evaluated and a value that cannot be read are as
  elsewhere: not UNDEFINED, which a condition would take as FALSE;
- a RULE_REF within the evaluation of its own rule, where edk2
  recurses without end, is malformed, also inside a rule and past
  where edk2 ends the expression: a condition is unknown, a READ and a
  WRITE are refused;
- where a CONDITIONAL drops the UNDEFINED that ends a rule's
  expression in edk2, the RULE_REF's UNDEFINED ends the expression
  that holds it there, while the spec's value goes on, as past a
  return expression of a MAP: the whole expression decides by its
  effect; a spec's value that cannot be read leaves it undetermined;
- a SET, an op not evaluated or a malformed op that the spec reaches
  past the end of a rule's expression, or of an expression of a MAP in
  it, goes out with the RULE_REF's UNDEFINED, as out of a return
  expression of a MAP, and so do those of the expressions that a
  malformed op leaves as it ends the rule: where a CONDITIONAL drops
  that UNDEFINED, a WRITE is refused before any SET, naming the first
  op skipped; else edk2's SETs stay;
- two RULEs of the RuleId, where the spec marks the form invalid and
  edk2's RuleIdToExpression takes the first (:907-916), are
  undetermined, naming both, and a READ of them is refused; past where
  edk2 ends the expression, the spec's result is not evaluated;
- as each RULE_REF evaluates its rule anew, rules that each refer
  twice to the one before double the work per rule: past
  MAX_RULE_EVALUATIONS (4096) rules in one expression, the RULE_REF is
  not evaluated; each READ that a value is retrieved through is an
  expression of its own, so one chain of them, up to MAX_READ_DEPTH
  deep, starts at most (MAX_READ_DEPTH + 1) x 4096.

An expression walks its form for RULEs once, into an index by RuleId
that each RULE_REF takes its rule from, so the work of RULE_REFs grows
with the rules that they start, not with the size of the form.

THIS in a rule has two readings: ParseOpCodes binds it, as it parses
the rule, to the innermost statement whose scope holds the THIS op
(IfrParse.c:1154-1176, :3082-3090), and ASSERTs where none does
(:1461-1466). That statement may have no QuestionId: a SUBTITLE, TEXT,
RESET_BUTTON or GUID op (but not the GUID op of an EDKII bit varstore
field, whose Scope ParseOpCodes clears, :2934-2937), or a question of
QuestionId 0; THIS then fails (Expression.c:808-813, :2733-2738).
UEFI 2.11 takes the current question (§33.3.8.3.77), that of the
expression that holds the outermost RULE_REF, as rules are
sub-expressions of the form's expressions (§33.2.5.7.3). Where no
statement holds the THIS op, it is not evaluated; where the statement
that holds it is the current question, it is that question's value,
THIS of its READ or WRITE; else it is undetermined, naming both, and
past where edk2 ends the expression, not evaluated.

A RULE_REF that no FORM holds, in a SUPPRESS_IF around FORMs, is
evaluated for the FORM of the question or option: edk2 makes that
SUPPRESS_IF each FORM's SuppressExpression (IfrParse.c:2592,
:1758-1774) and evaluates it with that FORM (Presentation.c:1522-1523,
:2511-2512), so RuleIdToExpression takes that FORM's rule, while
UEFI 2.11 keeps rules to the expressions within a form's scope
(§33.2.5.7.3) and pushes UNDEFINED without the rule (§33.3.8.3.64).
Where that FORM has a RULE of the RuleId, the result is undetermined,
naming both, and not evaluated past where edk2 ends the expression;
without one, both give UNDEFINED. A GRAY_OUT_IF outside forms is no
FORM's expression (IfrParse.c:2619).

The summary and the table of conditions.rs's module doc gain the rows
of two RULEs of one RuleId, of THIS in a rule and of a RULE_REF in a
SUPPRESS_IF around FORMs.

Test Plan:
- RED: these tests on the parent's code fail, as RULE_REF is not
  evaluated there: rule_ref_pushes_the_value_of_its_rule,
  this_in_a_rule_is_of_the_current_question_where_edk2_binds_the_same,
  a_rule_that_drops_an_undefined_hands_its_value_on,
  a_set_skipped_in_a_rule_goes_out_with_its_rule_ref,
  a_rule_ref_in_a_suppress_if_around_forms_is_undetermined_where_the_form_has_the_rule,
  question_ref1_of_a_missing_question_in_a_rule_gives_undefined,
  question_ref1_of_a_missing_question_in_a_match_expression_in_a_rule_is_undetermined
  and references_in_a_question_of_question_id_0_find_no_question.
  The fourth also fails on this code without the carry out of a rule
  and out of the expressions that a malformed op leaves, and
  an_expression_starts_at_most_max_rule_evaluations_rules on this code
  without the cap. a_reference_to_question_id_0_finds_no_question
  passes on the parent's code: it uses this commit's test helpers to
  pin how "refer to the question of a READ or WRITE as THIS" treats
  QuestionId 0, and fails where that commit's role takes QuestionId 0.
- Unit tests, conditions.rs (10 new):
  rule_ref_pushes_the_value_of_its_rule: a rule, also in the scope of
  the expression's first op; a rule of a rule; no rule; a rule in the
  scope of opcode 0x70, and one in that of 0x00; rules of UNDEFINED,
  of two values, of an op on an empty stack, of a MAP with a malformed
  match expression, of THIS in no statement; a rule of itself, also
  past an UNDEFINED that a CONDITIONAL may drop, and rules of each
  other; rules of an op not evaluated and of a value that cannot be
  read; a rule whose CONDITIONAL drops an UNDEFINED; two rules of one
  RuleId, also past such an UNDEFINED, and a READ of them; a
  CONDITIONAL that drops a rule's UNDEFINED, also of a rule malformed
  past it; a rule malformed past an UNDEFINED that its CONDITIONAL
  drops; rules past an UNDEFINED that a CONDITIONAL drops; an op not
  evaluated past an UNDEFINED that a CONDITIONAL in the scope of a
  later RULE_REF may drop; a READ, a WRITE and a SUPPRESS_IF of a rule
  of itself; outside forms.
  this_in_a_rule_is_of_the_current_question_where_edk2_binds_the_same:
  for a READ, a WRITE and a SUPPRESS_IF, THIS in a rule, and in a MAP
  in it, that no statement holds, and that the current question holds;
  QUESTION_REF1, QUESTION_REF2 and QUESTION_REF3 of the current
  FormSet's Guid of the current question in a rule; QUESTION_REF2 of
  another question in a rule; THIS in a rule that another question
  holds, and in a SUBTITLE scope, a GUID op scope and the scope of the
  GUID op of an EDKII bit varstore field of the current question; a
  READ whose THIS cannot be read, THIS in a rule that the current
  question holds, named as THIS; for an EFI_IFR_VALUE, THIS in a rule
  that no statement holds, that its question holds, also through a
  rule that no statement holds, and that another question holds, also
  past an UNDEFINED that a CONDITIONAL may drop, and an EFI_IFR_VALUE
  in no question.
  a_rule_that_drops_an_undefined_hands_its_value_on: its FALSE is
  FALSE as a condition, and unknown before a NOT; its 3 keeps a stored
  3, and is refused over 0 and over a stored value that cannot be
  read; a value that cannot be read is refused; a WRITE with SETs only
  before the RULE_REF plans them, and one with a SET after it, or with
  a value that cannot be read, is refused.
  question_ref1_of_a_missing_question_in_a_rule_gives_undefined: a
  SUPPRESS_IF of a rule of TRUE QUESTION_REF1 of a missing question
  TRUE CONDITIONAL, of a rule of that QUESTION_REF1 alone, and of that
  CONDITIONAL without the rule; a READ and a WRITE of such a rule.
  question_ref1_of_a_missing_question_in_a_match_expression_in_a_rule_is_undetermined:
  a READ of a rule of a MAP whose match expression is QUESTION_REF1
  of a missing question, also within a return expression of a MAP
  there, and past an UNDEFINED that a CONDITIONAL may drop; a READ of
  a rule of a MAP whose return expression drops such an UNDEFINED; a
  READ of a MAP whose match expression is a RULE_REF of a rule of that
  QUESTION_REF1; a SUPPRESS_IF of a rule of a MAP whose match
  expression is that QUESTION_REF1.
  a_set_skipped_in_a_rule_goes_out_with_its_rule_ref: a SET past the
  end of a rule, and past the end of a match expression of a MAP in a
  rule that a malformed op ends, is refused where a CONDITIONAL drops
  the RULE_REF's UNDEFINED, also where an op skipped later in a match
  or return expression that a malformed op ends is not the one named;
  without the CONDITIONAL, edk2's SETs stay.
  a_rule_ref_in_a_suppress_if_around_forms_is_undetermined_where_the_form_has_the_rule:
  a SUPPRESS_IF around a FORM with RULE 1 of TRUE, also past an
  UNDEFINED that a CONDITIONAL may drop, and around a FORM with only
  RULE 2; a GRAY_OUT_IF around a FORM with RULE 1; a SUPPRESS_IF in
  the FORM.
  a_reference_to_question_id_0_finds_no_question: QUESTION_REF2,
  QUESTION_REF3 of the current FormSet's Guid and QUESTION_REF1 of 0
  in a WRITE and a READ of a question of QuestionId 0.
  references_in_a_question_of_question_id_0_find_no_question: in
  questions of QuestionId 0 and 1, a WRITE of QUESTION_REF1 and of
  QUESTION_REF2 of the id, and of THIS in a rule that the question
  holds; a READ of QUESTION_REF1 and of EQ_ID_VAL of the id.
  an_expression_starts_at_most_max_rule_evaluations_rules: chains of
  12, 13 and 256 rules that each refer twice to the one before; two
  RULE_REFs of no rule after a chain of 12.
- make -k test on 74ad762: 1786 passed (1776 + 10 new); make
  test-i686: 1783.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
EFI_IFR_VERSION pushes the version of UEFI that the Forms Processor
conforms to, which UEFI 2.11 §33.3.8.3.93 derives from the revision of
the EFI System Table; edk2-stable202608 SetupBrowserDxe takes
EFI_SYSTEM_TABLE_REVISION (Setup.h:71). uefisettings does not read that
revision here yet, so VERSION stays not evaluated, but its reason now
names what it needs: "EFI_IFR_VERSION (the revision of the EFI System
Table) not evaluated", and a READ or WRITE that holds it "uses
EFI_IFR_VERSION (the revision of the EFI System Table), which
uefisettings does not evaluate".

Test Plan:
- RED: the test on the parent's code fails, as VERSION's reason named
  nothing it needs.
- Unit test, conditions.rs (1 new):
  version_is_not_evaluated_naming_what_it_needs.
- make -k test on 74ad762: 1787 passed (1786 + 1 new); make
  test-i686: 1784.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The UEFI Shell build runs driver code: get and set send a driver's
Callback()s for a question without a VarStore, between the reads of its
FormSet's stores, set reconnects the driver's controller when a
Callback() asks for it, and get and set by keyword call GetData() and
SetData() of EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL, which reach drivers.
Reads give the bytes of PASSWORD questions as zero, so a change of
those bytes alone went unseen: set reported the value applied, as
callback-forms-password's set-over row showed.

Each of these now runs between two reads of every withheld byte, which
compare a copy of those bytes that zeroes on drop and shows none: of
each variable that the bytes were recorded for, read by key whether
GetNextVariableName() lists it or not, uefisettings' own too, and of
each listed variable that withholds any. A change, or withheld bytes
that cannot be read or listed, refuses, as uefisettings never writes a
password byte, so it never restores one: get fails, set reports the
change not applied, and get and set by keyword fail. After an applied
change, the variables are compared again across the reconnection,
against the same first read: a changed password reports "applied; then
the reconnection that EFI_BROWSER_ACTION_REQUEST_RECONNECT asks for
changed the password bytes of EFI variable ...", and the listing of
changed variables holds the reconnection's writes too, as it did
before.

The reads of the FormSet's stores before the first Callback() run
driver code too, ExtractConfig(): where one fails, so that no
Callback() runs, the withheld bytes are compared across the reads that
ran, and the refusal names a change. Once a request of a staged set is
so refused, apply-staged applies none of the later ones, which would
run driver code after the change is seen, and records each as not
applied.

Each read of withheld bytes reads the variable once, into a buffer
that zeroes on drop, from which both the zeroed data and the copy come;
VariableData reads through WithholdingVariables do the same. In the
UEFI Shell, GetVariable() reads into such a buffer too, sized by a
first call and replaced while a call asks for more, never reallocated:
uefi 0.41's get_variable_boxed shrinks its buffer with realloc, which
frees the block that held the data unzeroed when the variable shrinks
between its two GetVariable() calls. So in the UEFI Shell, no buffer of
uefisettings that held a password's bytes in these reads is freed
unzeroed.

Test Plan:
- At this commit (tree dff8d96), on 321d568 (tree bfd39b4): cargo
  check --locked --all-targets with RUSTFLAGS='-D warnings' and make -k
  lint pass; make test: 1824 passed, 1790 on the base, of which cargo
  test --lib: 1721, 1687 on the base; make test-i686, linked against a
  user-space i686 glibc, as this host has none: 1821 passed, 1787 on
  the base; the tests of the Windows build, run on Linux under its
  cfgs: 1016 pass, the base's 1010 and 6 new.
- At this commit, on x86_64: staged-set and the 45 shell-* scenarios
  that boot there pass, among them shell-callback-forms-password, its
  set-over row refused with EFI_ABORTED.
- On the base, with this commit's tests/qemu files:
  shell-callback-forms-password fails 2 checks on x86_64, set-over's
  status (0x0) and its JSON error line, as the value is applied; of the
  new tests, these fail there: the 6 of question_callbacks
  (a_reconnection_is_compared_again_and_listed,
  set_refuses_an_extract_config_that_overwrites_withheld_bytes, and
  those where a Callback() overwrites or creates withheld bytes, or
  where they cannot be read),
  keyword_set_fails_where_set_data_changes_withheld_bytes and
  keyword_get_fails_where_get_data_changes_withheld_bytes, given the
  base's set_keywords and get_keywords, and
  freed_bytes::a_withheld_read_frees_no_withheld_byte.
- Without the compare where a store's first read fails, and without
  apply-staged's stop,
  set_names_a_password_change_when_the_baseline_fails,
  get_names_a_password_change_when_the_baseline_fails and
  apply_requests_applies_nothing_after_driver_code_changed_password_bytes
  fail.
- 54 mutants of the new code each fail a named test, among them: no
  compare after the reconnection; no witness across SetData() or
  GetData(); a refusal only from two changes on; the variables read
  after the stores' first ExtractConfig(); no compare where one fails;
  apply-staged's stop negated; set's refusal for changed password bytes
  of another type; get's failure shown as its answer; the first
  withheld range copied alone; the inner read copied into the zeroing
  buffer, which frees it unzeroed; GetVariable()'s buffer shrunk to its
  data; a withheld variable read twice; no witness of the variables
  that the listing skips, or of uefisettings' own; every listed
  variable witnessed, so that one without withheld bytes that cannot be
  read refuses.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
Conditions that read bytes the OS cannot read, such as those of a
buffer VarStore that only its driver's EFI_HII_CONFIG_ACCESS_PROTOCOL
holds, are undetermined, and set refuses the questions they may gray
out or hide. --access-level covered one such VarStore, AMI's
SystemAccess, with code that knew its name, GUID and meaning.
--assume-var-store NAME-GUID[+OFFSET]=HEX states the bytes of any
VarStore instead, on get, set, hii get, hii set and hii list-questions,
repeatable.

NAME-GUID is the name of the variable's efivar file, compared as
efivarfs names it, '!' for '/'. OFFSET is decimal, or hexadecimal after
0x. The values that conditions, the defaults and options they pick, and
the EFI_IFR_VALUE, READ and WRITE expressions read through
VarStoreValues come from the stated bytes, patched over those that the
variable holds; a value of which only some bytes are stated, and whose
variable cannot give the others, is unreadable, naming the bytes stated
and those not. EFI_IFR_GET reads them too. A question on stated bytes
answers with what its variable holds, and writes never take stated
bytes.

check_assumed refuses, naming each, a statement of a VarStore that no
FormSet declares as EFI_IFR_VARSTORE or EFI_IFR_VARSTORE_EFI where edk2
creates it, one past the greatest Size declared, and two that state the
same bytes; only the statements it takes reach what reads them. The
reason of a condition that cannot read a buffer or EFI variable VarStore
ends with the --assume-var-store that would state it, for a bit field
its StorageWidth bytes; it names none for bytes that hold a password,
nor for a VARSTORE_EFI before UEFI 2.3.1, whose variable holds one
question's value. On the Ilo backend the flag is refused as --include
is.

--access-level now states its byte through the same statements, until
the next commit removes it.

The CLI and the library API change: the flag;
GetOptions::assume_var_stores, SetOptions::assume_var_stores and
ListQuestionsOptions::assume_var_stores; exports::AssumedVarStore and
the #[non_exhaustive] exports::AssumedVarStoreError. --access-level is
published on main since 9c63f96 but unreleased: crates.io 0.1.6 is
c1939c4, an ancestor of 9c63f96.

A staged request records the statements in "assume_var_stores" in place
of "access_level", and apply-staged selects with them. A request that an
older uefisettings staged names "access_level", which
deny_unknown_fields refuses by that name, null too, so it is never read
as one that states nothing.

Windows: the Windows CLI takes --assume-var-store with the selection
flags that it shares, as it took --access-level.

Test Plan:
- cargo check --all-targets with -D warnings and clippy pass; 1703 lib
  unit tests (main: 1687) and 83 bin tests (main: 81) pass.
- The new tests pin: the parse and efivarfs name of a statement; each
  refusal of check_assumed, all named; stated bytes over a CHECKBOX, a
  NUMERIC, a bit field and a value that straddles them, with the
  variable's other bytes or why it has none; a GET of them; answers as
  stored; the reason's flag, for an enhanced authenticated variable
  too; set's selection and WRITE expressions, get,
  list-questions, staging and apply-staged with statements; an older
  staged request refused; the CLI's mapping and its Ilo refusal.
- 44 mutants run at the end of this series; 43 fail a named test, among
  them: statements off, their offset, GUID or name ignored, an answer
  reading them, a GET ignoring them or not patching them, a bit field
  read as whole bytes, a straddling value read with zeros, adjacent
  stated bytes named apart, each refusal of check_assumed off, the flag
  named for password bytes or not for an enhanced authenticated
  variable, statements dropped by staging or by apply-staged. The one
  left, the last of two statements of a byte winning, changes nothing:
  only statements that check_assumed takes reach a value, and it
  refuses such statements.
- QEMU x86_64, hii: with DriverSample's SuppressGrayOutSomething byte
  stated as 00, list-questions lists the ordered list that a DISABLE_IF
  disables as stored and not the one that a SUPPRESS_IF hides on 0, and
  leaves the one-of on that byte and the variable as stored; the BIT
  numeric on MyEfiBitVar names +4=<HEX of 1 byte> and follows e0 and 01
  stated; set refuses bytes of an undeclared VarStore. staged-set and
  hii-no-runtime-access, whose reasons now end with the flag, pass.
- [UNVERIFIED] AMI firmware itself: no such machine here. On two AMI
  HiiDBs, the CLI A/B in the next commit's Test Plan covers it.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
--access-level evaluated the conditions on AMI firmware's SystemAccess
VarStore at a stated level, with code that knew that VarStore's name,
GUID and meaning. --assume-var-store states the bytes of any VarStore,
that one included, so --access-level goes, with no alias; the README's
section on stated VarStore bytes shows the statement for SystemAccess.

The CLI and the library API change: get, set, hii get, hii set and
hii list-questions no longer take --access-level; exports::AccessLevel
and the access_level field of GetOptions, SetOptions and
ListQuestionsOptions are gone. The reason of a condition that cannot
read SystemAccess no longer names --access-level: it ends with the
--assume-var-store that would state the byte, as for any other VarStore.
--access-level is published on main since 9c63f96 but unreleased:
crates.io 0.1.6 is c1939c4, an ancestor of 9c63f96.

Windows: the Windows CLI no longer takes --access-level either.

Test Plan:
- make -k RUST_TOOLCHAIN= lint test passes: 1696 lib unit tests, 1799
  tests in all (main: 1687, 1790). test-i686 passes 1796 (main: 1787).
  The Windows emulation (win-all) passes 1015 tests (main: 1010), none
  failing; the 5 of main that it lacks are the removed tests.
- grep -i 'e770bb69\|SystemAccess\|AccessLevel' finds nothing in src/.
- CLI A/B on two AMI HiiDBs, list-questions (default and every state)
  and get: --assume-var-store SystemAccess-e770bb69-...=00 or =01 here
  gives main's output of --access-level administrator or user, once
  the reasons' suffixes are stripped (15 of 15), and each differs from
  stating nothing. Stating nothing, the 169 and 67 SystemAccess reasons
  that named --access-level name
  --assume-var-store SystemAccess-...+0=<HEX of 1 byte> instead.
- QEMU x86_64: hii, hii-readwrite, staged-set, hii-form-set-disable-if,
  shell-driver-sample, shell-readwrite and shell-form-set-disable-if
  pass.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
README still said that a Callback() that changes only the bytes of a
PASSWORD question goes unnoticed, which cbd138a ("fix(hii): refuse
where driver code changes a password's bytes") made false, and it
described keyword get and set, and apply-staged, as if no such change
stopped them. It now says what cbd138a does, at main:
- Callback()s: the withheld bytes are read before the stores' first
  reads, which refuses where they cannot be read or listed
  (question_callbacks.rs:628, variable_changes.rs:103-105), and
  compared after the sequence (question_callbacks.rs:503-504,
  :568-569), across the reads that ran where a store cannot be read
  (:634, :637), and after a reconnection against the same first read
  (:586-590), in every variable that they were recorded for, listed or
  not, and every listed one that withholds any
  (variable_changes.rs:17-19), without showing them
  (variables.rs:1566-1569; the refusals name the variable,
  variable_changes.rs:229, :233). A change, or bytes that
  cannot be compared, fails get (question_callbacks.rs:431-432) and
  set (:461), whose text is "not applied: ..." (:400, :759) or, after
  the reconnection, "applied...; then ..." (:393, :590). The store
  that holds one is still not restored (form_set_stores.rs:442-443).
- keyword get and set fail where GetData(), or SetData() and its
  read-back, changed those bytes or they cannot be compared across
  them (keyword_access.rs:421, :438, :449, :453, :704-705, :722, :733;
  exports/uefi.rs:174-175, :198-199).
- apply-staged applies no request after one so refused, and records
  the later ones as not applied (staged_set/apply.rs:125-126, :232-233,
  :241-243), as its requests go through set's refusal
  (exports/uefi.rs:395, :410, :361).
The other lines are unchanged.

Test Plan:
- README feeds no rustdoc or doctest: git grep include_str finds only
  thrift/lib.rs's two .thrift files, so make -k lint is the check and
  make test is not needed; make -k lint passes.
- Each changed sentence was read against the code lines above at
  cbd138a.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
variable get refused the load options, hot keys and console device
paths of UEFI 2.11 Table 3.1, and pointed at variable info, which shows
only their size. It now decodes them too:

- Boot####, Driver####, SysPrep####, PlatformRecovery#### and, of the
  vendor GUID given, OsRecovery#### (§3.1.3, §3.4.1): Attributes as
  names, each undefined bit in hex, the LOAD_OPTION_CATEGORY field as
  boot, app or its reserved value, the Description, each device path
  of the FilePathList as text and OptionalData in hex;
- Key#### (§3.1.6): the shift states by name, Reserved bits in hex,
  each key by its SCAN_ name or character, the Boot#### that it starts
  and whether BootOptionCrc is the CRC-32 of that Boot####, without
  which the boot manager ignores the key;
- ConIn, ConOut, ErrOut and their *Dev variables (§3.3): their device
  path as text.

Of a variable with EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS, each
decodes the bytes after the EFI_VARIABLE_AUTHENTICATION_3 metadata, as
get decodes the other variables (§8.2.1).

device_path.rs writes a device path as text (§10.6): each node in the
form that edk2-stable202608's ConvertDevicePathToText() writes with
AllowShortcuts TRUE, for every Type/Sub-Type row and named form of
Table 10.67, the USB class shortcuts, AcpiExp, Virtual* and
Persistent* included; NvdimmAcpiAdr, NVDIMM, RestService and NVMEoF,
which edk2 lacks, take the forms of Table 10.67. A form is written
only if it reads back to the node's bytes, else the form without the
shortcut if that does, else the generic form of Table 10.67, which
always does; instances are separated by ",/". It reads each of those
texts back as edk2's ConvertTextToDevicePath() does. Where edk2 reads
another text than Tables 10.66 and 10.67 say, it follows the tables,
such as an omitted BaudRate, DataBits, Protocol, Authentication or HD
Type read as the tables' default and a BMC Address without "0x" as
decimal; the module documentation lists each. It refuses what edk2
reads to another node or drops: an unknown node name, text after a
form's ")", a value that does not fit its field, a Path() of Type
0x7F, Uart DEFAULT, a Parity keyword next to a StopBits integer or the
reverse ("Mixing formats is prohibited"), an empty instance. A device
path holding an instance of no node has no text; get shows its bytes
and why.

Where edk2's form would not read back, the text differs from it, as
the module documentation lists:
- Uart(0,0,...) for a BaudRate or DataBits of 0, where edk2's
  DevPathToTextUart() writes DEFAULT;
- the EISA ID letters of a non-PNP ACPI _HID, where edk2 writes
  Acpi(0x%08x,...);
- AcpiEx() for an ACPI Expanded node of UIDSTR alone and a UID other
  than 0, where edk2 writes AcpiExp(), which has no UID;
- VenMsg(GUID,data) for a Messaging Vendor node of a GUID that edk2
  names, such as VenPcAnsi(), with data that the name drops;
- a Hard Drive partition number from 2^31 unsigned, where edk2 writes
  it negative;
- the generic form for every other node whose form would not read
  back, each class with a row in the tests: a value whose keyword maps
  back to another, a field that the form does not show, data past or
  short of the fields, a string holding a separator, a byte outside
  ASCII or no Null, a File Path holding "/", mixed partition formats,
  an NVMe-oF NID other than a UUID.

Nothing writes a device path from its text yet; the next changes do.
The CRC-32 is crc32fast's, the CRC that edk2's CalculateCrc32() takes.
The Windows build compiles, untested.

Test Plan:
- On main cbd138a, cargo test --locked --lib --bins: 1744 lib tests
  pass and 1 is ignored (cbd138a: 1721 and 0), and 81 bins tests
  pass (cbd138a: 81).
- At the series tip, mutants that decode a variable or match a Key####
  with the metadata of an enhanced Boot#### each fail a named test.
- cargo test --locked --lib --bins; cargo clippy --workspace
  --all-targets --all-features and, for x86_64-pc-windows-msvc,
  -p uefisettings --lib --bins --all-targets, with -D warnings.
- QEMU x86_64, scenarios variable-get, global-variables, boot-manager
  and shell-variable-get: from Linux, get shows each load option of
  BootOrder as its efivarfs bytes tell, OVMF's Key0000 and Key0001,
  and ConOut as text; the UEFI Shell shows Boot0001 and Boot0002 with
  the device path that the firmware's boot manager logged for each,
  Key0000 and ConOut; the Shell boot of boot-manager gets the same JSON
  as Linux for the seeded Boot0099 and Key0099.
- edk2-stable202608 BaseTools' DevicePath tool, its
  ConvertTextToDevicePath(), reads each of the 142 texts that to_text
  writes for the tests' nodes, at least one per form, keyword and USB
  class shortcut of Table 10.67 that edk2 has, and for OVMF's
  variables back to their bytes, and the 3 separator texts to the
  bytes of from_text. The 5 texts of the forms that edk2 lacks read
  back by from_text to the bytes of Table 10.67's node layouts.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
variable set-attributes changes the Attributes (UEFI 2.11 §3.1.3) of a
Boot####, Driver#### or SysPrep#### of EFI_GLOBAL_VARIABLE: --set and
--clear take the flags active, force-reconnect and hidden, and
--category boot or app gives the LOAD_OPTION_CATEGORY field a value,
clearing the whole field first, a reserved value too; no flag names
the bit of LOAD_OPTION_CATEGORY_APP. It patches the Attributes in
place: "When updating a load option, all undefined attribute bits must
be preserved", and every other byte stays as read, which a decode and
encode would not keep for a Description holding a surrogate. The
variable keeps its attributes. It prints the load option as variable
get shows it.

A Key#### starts its Boot#### only while its BootOptionCrc is the
CRC-32 of that Boot#### (§3.1.6), so a change would leave it ignored.
After writing a Boot####, set-attributes sets the BootOptionCrc of each
Key#### whose BootOption names it and whose BootOptionCrc was the
CRC-32 of its old bytes to that of the new ones, every other byte kept,
and prints each Key#### updated on stderr. A Key#### that is malformed,
names another Boot#### or was already stale stays as it was. A Key####
write that fails names the Boot#### as written, the Key#### updated
and each one left with the old BootOptionCrc. Windows,
whose calls cannot list variables, finds none, and set-attributes warns
that the Key#### that name the Boot#### are now ignored there; the
Windows build compiles, untested.

It refuses, before any write, PlatformRecovery####, which "are only
modified by firmware and are read-only to the OS" (§3.3),
OsRecovery####, a Secure Boot Policy Variable that needs
EFI_VARIABLE_AUTHENTICATION_2 (§3.3), any other variable, an absent
load option, a change of nothing and a flag both to set and to clear.
It refuses too a load option, or a Key#### following it, whose
attributes hold EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS or
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, which only an
EFI_VARIABLE_AUTHENTICATION_3 or _2 descriptor writes (§8.2.3).

Test Plan:
- On main cbd138a, cargo test --locked --lib --bins: 1753 lib tests
  pass and 1 is ignored (cbd138a: 1721 and 0), and 84 bins tests
  pass (cbd138a: 81).
- cargo test --locked --lib --bins; cargo clippy --workspace
  --all-targets --all-features and, for x86_64-pc-windows-msvc,
  -p uefisettings --lib --bins --all-targets, with -D warnings.
- QEMU x86_64 boot-manager: from Linux, then from the UEFI Shell,
  set-attributes clears and sets Boot0099's LOAD_OPTION_ACTIVE, its
  undefined bit kept, and Key0099's BootOptionCrc follows; it sets and
  clears Driver0000's LOAD_OPTION_FORCE_RECONNECT; each refusal leaves
  efivarfs, and the Shell's dmpstore, unchanged.
- At the series tip, mutants that re-encode the load option, update a
  stale Key####, keep the category field, write the Boot#### with
  NV+BS+RT instead of its attributes, decode a following Key#### with
  its metadata, or drop or narrow a refusal of authenticated attributes
  each fail a named test.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
variable create-load-option creates a Boot####, Driver#### or
SysPrep#### of EFI_GLOBAL_VARIABLE that does not exist, with NV+BS+RT
(UEFI 2.11 Table 3.1):
- --description takes its Description, UCS-2 text without Null;
- --device-path takes a device path as variable get shows it, read back
  to bytes, once per device path of its FilePathList, the first of
  which locates the image; --device-path-file takes instead a file of
  the bytes of one, an EFI_DEVICE_PATH_PROTOCOL, which the
  FilePathList decoder checks and nothing changes;
- --optional-data-file takes its OptionalData, bytes never decoded,
  none if not given;
- --flags and --category take its Attributes, active and boot if not
  given, and --flags none no flag, so that an app that is not active,
  Attributes 0x100, takes one write: "When creating a new load option,
  all undefined attribute bits must be written as zero" (§3.1.3).
It refuses an existing load option: set-attributes changes one, and
variable set BootOrder its place in BootOrder, which a new one stays
out of. A SysPrep#### while BootOptionSupport lacks
EFI_BOOT_OPTION_SUPPORT_SYSPREP, and an app Boot#### while it lacks
EFI_BOOT_OPTION_SUPPORT_APP, get a warning on stderr and are written
all the same (§3.1.4); an absent BootOptionSupport supports neither.
The category "is ignored for variables of the form Driver####,
SysPrep####, or OsRecovery####" (§3.1.3), so theirs gets none.

variable set-device-path sets ConIn, ConOut or ErrOut to one device
path, from text or a file of its bytes, keeping the variable's
attributes, or with NV+BS+RT if it is missing. ConIn, ConOut and ErrOut
"are always proper subsets of ConInDev, ConOutDev, and ErrOutDev"
(§3.3), so each instance that the *Dev variable lacks gets a warning
on stderr, but one holding a USB Class or USB WWID node, which the
firmware matches to the devices of that class or WWID
(edk2-stable202608 ConPlatformDxe MatchUsbShortformDevicePath()); the
write still proceeds. It refuses ConInDev, ConOutDev and
ErrOutDev, which "are volatile, and are set dynamically on every
boot".

Both print what they wrote as variable get shows it, and refuse, before
any write, a path that does not read or decode. set-device-path refuses
a console variable with those attributes alike. The Windows build
compiles, untested.

Test Plan:
- On main cbd138a, cargo test --locked --lib --bins: 1761 lib tests
  pass and 1 is ignored (cbd138a: 1721 and 0), and 86 bins tests
  pass (cbd138a: 81).
- cargo test --locked --lib --bins; cargo clippy --workspace
  --all-targets --all-features and, for x86_64-pc-windows-msvc,
  -p uefisettings --lib --bins --all-targets, with -D warnings.
- create-load-option rebuilds OVMF's Boot0000, Boot0001 and Boot0002
  byte for byte, and Boot0000 as an app of no flag, Attributes 0x100.
- QEMU x86_64 boot-manager, 4 boots: Linux creates Boot009A, to the
  UEFI Shell, and names it in BootNext, and the firmware logs "loading
  Boot009A" from the text that get shows; the Shell creates Boot009B
  of the short-form File Path \uefisettings.efi and names it in
  BootNext, and the firmware loads it; ConOut set to its own text keeps
  its bytes; the refusals leave the variables unchanged.
- At the series tip, mutants that overwrite an existing load option,
  write an undefined attribute bit, take the instances of a *Dev
  variable with its metadata or drop the refusal of an authenticated
  console each fail a named test.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
variable create-key creates a Key#### of EFI_GLOBAL_VARIABLE that does
not exist, with NV+BS+RT, a hot key that starts a Boot#### (UEFI 2.11
§3.1.6):
- --boot takes the Boot####, which must exist; BootOptionCrc gets the
  CRC-32 of its EFI_LOAD_OPTION, the bytes after any
  EFI_VARIABLE_AUTHENTICATION_3 metadata (§8.2.1), without which the
  boot manager ignores the key;
- --modifiers takes the shift states to hold, of shift, control, alt,
  logo, menu and sys-req, none if not given;
- --key takes each key, 0 to 3, as InputKeyCount counts them, by the
  name after SCAN_ of its scan code in edk2's SimpleTextIn.h and
  SimpleTextInEx.h, such as F2, ESC or EJECT, else by its one UCS-2
  character, else as ScanCode=0x####,UnicodeChar=0x####, which variable
  get shows for any other key.
KeyData gets Revision 0 and no Reserved bits, as the spec's examples.
It prints the key as variable get shows it.

It refuses, before any write, an existing Key####, a missing Boot####,
a BootOptionSupport without EFI_BOOT_OPTION_SUPPORT_KEY or with an
EFI_BOOT_OPTION_SUPPORT_COUNT below the keys (§3.1.4), an absent one
supporting none, and the shift states and keys of a Key#### that the
boot manager takes, as its Boot#### exists and its BootOptionCrc
matches: edk2-stable202608 EfiBootManagerAddKeyOptionVariable()
(BmHotkey.c) refuses those too. Windows, whose calls cannot list
variables, cannot check the last; create-key warns there and writes the
key all the same. The Windows build compiles, untested.

Test Plan:
- On main cbd138a, cargo test --locked --lib --bins: 1769 lib tests
  pass and 1 is ignored (cbd138a: 1721 and 0), and 88 bins tests pass
  (cbd138a: 81); make test passes 1879 tests (cbd138a: 1824),
  test-i686 1876 (1821), and the Windows emulation of win-all 1071
  (1016).
- make -k RUST_TOOLCHAIN= with each target of lint, then test and
  test-i686.
- make test-e2e-qemu on x86_64, i686 and aarch64: every scenario boots,
  or is skipped where scenarios.tsv says. In boot-manager Linux creates
  Key009A, ALT-F11 to Boot0099, after refusing Key0099, an absent
  Boot#### and Key0099's own keys; the UEFI Shell refuses Key0099 and
  ALT-F11, creates Key009B, SHIFT-F12 to Boot009B, and Key009A follows
  Boot0099's toggles; the last boot finds both keys' CRC matching.
- Mutants that accept more keys than BootOptionSupport counts, a key
  option longer than InputKeyCount gives, or a Boot#### or Key#### read
  with its metadata each fail a named test.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
scripts/check-toolchain.sh took the cargo on PATH for the cargo of
rustup only when it was the same file as rustup, as rustup-init
installs it: a link to rustup. Other installs put another file there
that runs rustup all the same. Homebrew's rustup formula
(Homebrew/homebrew-core Formula/r/rustup.rb at
398ea85abeeee2c92fc8ab9025410be152e50a5b, lines 46-57) links cargo
to rustup, then moves every file of bin to libexec/bin and leaves an
env script in its place, as Homebrew/brew
Library/Homebrew/extend/pathname.rb at
cbdfb03ce7e7d8c2f82a17c8bfccfeeabafee8ba, lines 335-346
(Pathname#env_script_all_files) does, so the cargo and the rustup on
PATH are two scripts. On Windows CI rustup installs its proxies as
hard links (rust-lang/rustup src/cli/self_update.rs at
9acde698f9680db8fe26865e70f4dd8d4172155a, lines 803-807).

In CI run 43072118590 of 2c84492, test-macos on macos-latest, whose
cargo is Homebrew's /opt/homebrew/opt/rustup/bin/cargo, and
test-windows, whose cargo is /c/Users/runneradmin/.cargo/bin/cargo,
failed in this check, right after make setup had installed the
toolchain through that rustup. test-macos on macos-15-intel and
lint-and-test passed, as the run's jobs list shows.

The check now asks what the cargo does: with RUSTUP_TOOLCHAIN set to
the toolchain, its --version must equal that of the toolchain's own
cargo, which rustup run runs. That holds for a link, a hard link, a
copy or a script that runs rustup, and fails for a cargo that ignores
RUSTUP_TOOLCHAIN; the message names that cargo and prints both
versions. rustup run, not the path that rustup which prints: the
script then runs no path that rustup prints, a Win32 one on Windows.
The check runs once rustup has the toolchain for its default host, so
a missing or custom toolchain keeps its own message, and it installs
nothing, as RUSTUP_AUTO_INSTALL=0 is exported.

Test Plan:
- scripts/check-toolchain.sh with the Makefile's TARGETS, run as the
  toolchain recipe runs it, PATH led by a dir of each layout, before
  and after this change, for toolchain stable (here 1.93.1 with every
  target; the 1.93.1 toolchain here has only x86_64-unknown-linux-gnu):
  - cargo a symlink to rustup (~/.cargo/bin): exit 0 before and after;
  - Homebrew-like env scripts for rustup and cargo: exit 1 with the CI
    message before, 0 after;
  - cargo a hard link to a copy of rustup: 0 before and after;
  - cargo and rustup two copies of rustup: 1 before, 0 after;
  - a cargo printing "cargo 1.80.0 (0000000 2024-01-01)": 1 before
    and after, now naming it and printing both versions;
  - toolchain 1.80.0, not installed: "rustup has no Rust toolchain
    1.80.0" before and after;
  - an empty toolchain name: 0 before and after;
  - after: a rustup whose run fails, and a cargo that fails, each
    exit 1 with its message.
  No run changed ~/.rustup or ~/.cargo/bin.
- make RUST_TOOLCHAIN=stable toolchain: exit 0, also with the
  Homebrew-like scripts first on PATH; with the foreign cargo first,
  exit 2 with the new message.
- make -k RUST_TOOLCHAIN= lint test: exit 0, 1586 passed; make
  test-i686: 1583 passed; make -k RUST_TOOLCHAIN=stable lint test:
  exit 0, 1586 passed.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
On ubuntu-26.04 (gcc 15, glibc 2.43), CI run 43072118590 failed
test-e2e-qemu on i686 and aarch64: build-secboot-firmware.sh's BaseTools
build stopped at EfiRom.c:78 with -Werror=discarded-qualifiers. There,
strstr of a const string is a const char *, which the edk2-stable202508
EfiRom.c assigns to an unused CHAR8 *. The QEMU-inputs cache missed, so
CI built the firmware from source.

Take EfiRom.c as edk2 9af06ef3cbb0 ("BaseTools/EfiRom: fix compiler
warning") left it: the script edits the tag's file and checks the result
against that commit's blob, so the pin and the firmware sources stay as
they are. The QEMU-inputs cache key hashes this script, so the next CI
run builds the firmware again.

Link: tianocore/edk2@9af06ef
Link: https://github.com/linuxboot/uefisettings/actions/runs/43072118590

Test Plan:
- CI run 43072118590 itself: with the same gcc command,
  edk2-stable202608's EfiRom.c (blob 6e903b35) compiled in
  build-driver-sample.sh's BaseTools build, and in the tag's BaseTools
  build every tool but EfiRom linked.
- The tag's EfiRom.c with CI's gcc flags on a host with gcc 15.3 and
  glibc 2.42: compiles. With a forced-in stand-in for a strstr that
  keeps the const of its argument under -std=gnu23: CI's error at
  EfiRom.c:78:17. The edited file compiles with and without the
  stand-in, and is byte-identical to 9af06ef3's (blob 6e903b35).
- All of BaseTools/Source/C with the stand-in: EfiRom is the only tool
  that fails at the tag, and none fails after the edit.
- The i686 and aarch64 secboot firmware, built from a clean edk2
  d46aa46c through make test-e2e-qemu-{i686,aarch64}: the 21 secboot
  scenarios pass on both, 46 boots, and all 24 Shell boots print
  "every check passed".
- make -k lint test: 1586 passed; make test-i686: 1583 passed.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
A UCS-2 string decoded as UTF-16: it paired surrogates into characters
beyond UCS-2, read a lone one as U+FFFD, and kept private use
characters and those between 0xF000 and 0xFCFF. UEFI 2.11 rules all of
them out of strings: "UEFI does not support surrogate characters"
(§33.2.6.2.2 Surrogate Area), "UEFI prohibits use of this area"
(§33.2.6.2.1 Private Use Area), and "Characters between 0xF000 and
0xFCFF should be rejected" (§33.3.6.3.2 Unicode 2-Byte Encoding
(UCS-2)).

Each CHAR16 of a UCS-2 string, and each character that the SCSU
decoder yields, now reads as its own character, or as U+FFFD where
UEFI rules it out, with one warning per string that names the first
such character, the rule, and the string's id and Language. The
common control codes of Table 33.3, 0xF620-0xF62B, 0xF7zz and 0xF8zz,
lie in the private use area and between 0xF000 and 0xFCFF, yet strings
may hold them (§33.2.6.2.4 Common Control Codes), so they are kept. A
FontName reads by the same rule, for the debug log that shows it. The
private use area is defined once, PRIVATE_USE_AREA, which the checks
of a STRING value and of a password file share.

A QUESTION or VALUE matches a text with a replaced character only
where no text as stored matches it, in any FormSet; texts equal after
the replacement are equal prompts, which select resolves to the first
selectable match in IFR order. A STRING default and a KeywordInfo
string keep the CHAR16s of their string, as edk2-stable202608
SetupBrowserDxe/Setup.c GetQuestionDefault copies them. An SCSU string
that held a replaced character has no CHAR16s to copy, so both refuse
it.

Test Plan:
- At this commit (tree 5755be7a), on cbd138a: cargo check --locked
  --all-targets with RUSTFLAGS='-D warnings' and cargo fmt --check
  pass; cargo test --locked --lib: 1731 passed, 1721 on cbd138a,
  among them the new
  characters_that_uefi_rules_out_read_as_replacement_characters,
  rule_bounds, character_rules_out_each_range_up_to_its_bounds,
  font_names_read_ruled_out_characters_as_replacement_characters,
  set_of_a_stored_replacement_character_writes_its_question,
  set_of_a_stored_replacement_character_writes_its_option,
  get_of_a_stored_replacement_character_answers_its_question,
  a_stored_prompt_is_unambiguous_beside_a_replaced_one_of_another_language,
  string_bytes_are_the_char16s_that_strings_held and
  info_takes_the_char16s_that_strings_held. The new
  list_strings_warns_once_per_string_of_its_first_ruled_out_character
  and list_strings_keeps_control_codes_without_a_warning of
  tests/ruled_out_character_warning.rs pass at the series' tip.
- With these tests on the product code of cbd138a:
  characters_that_uefi_rules_out_read_as_replacement_characters,
  rule_bounds,
  font_names_read_ruled_out_characters_as_replacement_characters,
  set_of_a_stored_replacement_character_writes_its_question,
  set_of_a_stored_replacement_character_writes_its_option,
  list_strings_warns_once_per_string_of_its_first_ruled_out_character
  and strings_without_a_variable_show_their_string_default fail;
  get_of_a_stored_replacement_character_answers_its_question,
  a_stored_prompt_is_unambiguous_beside_a_replaced_one_of_another_language
  and list_strings_keeps_control_codes_without_a_warning pass, as
  cbd138a matched QUESTION against texts as stored and warned of no
  character.
- Mutants, at the series' tip (tree 377b007e) or before it added
  get_of_a_stored_replacement_character_answers_its_question (tree
  bb54f835): dropping the exemption of the control codes for a CHAR16,
  or moving any bound of 0xF620-0xF62B or 0xF700-0xF8FF inward, fails
  character_rules_out_each_range_up_to_its_bounds, and rule_bounds or
  characters_that_uefi_rules_out_read_as_replacement_characters;
  moving a bound of PRIVATE_USE_AREA to 0xE001 or 0xF97F fails it and
  ucs2_encoder_refuses_the_private_use_area; moving one of
  0xF900-0xFCFF to 0xF901 or 0xFCFE fails
  character_rules_out_each_range_up_to_its_bounds; a surrogate read as
  U+FFFD without its rule fails it and
  list_strings_warns_once_per_string_of_its_first_ruled_out_character,
  which also fails without the warning or when it names the last
  ruled-out character; UCS-2 strings decoded as before fail
  characters_that_uefi_rules_out_read_as_replacement_characters; a
  FontName read by String::from_utf16_lossy fails
  font_names_read_ruled_out_characters_as_replacement_characters.
- Mutants of the match, likewise: the prompts always matched as
  displayed fails
  set_of_a_stored_replacement_character_writes_its_question and
  a_stored_prompt_is_unambiguous_beside_a_replaced_one_of_another_language,
  and always as stored fails
  set_of_a_stored_replacement_character_writes_its_question; get's
  prompts always matched as displayed fails
  get_of_a_stored_replacement_character_answers_its_question, and
  check_unambiguous's fails
  a_stored_prompt_is_unambiguous_beside_a_replaced_one_of_another_language;
  matching that keeps a text with a replaced character fails it,
  set_of_a_stored_replacement_character_writes_its_question and
  set_of_a_stored_replacement_character_writes_its_option, and
  matching_displayed that leaves such a text out fails the last two;
  select_option without its stored texts, without its displayed texts,
  or with the displayed texts in place of the stored ones fails
  set_of_a_stored_replacement_character_writes_its_option, and trying
  the trimmed texts first fails
  options_are_selected_by_the_text_that_get_shows.
- Mutants of what a string held, likewise: keeping no replaced string
  fails string_bytes_are_the_char16s_that_strings_held,
  info_takes_the_char16s_that_strings_held and the tests of the match
  above; shown_units that ignores what a string held fails the first
  two, and a DUPLICATE that copies none of it fails
  string_bytes_are_the_char16s_that_strings_held.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
get, set, list-questions and show-ifr showed a prompt, help, title or
option text with the common control codes of UEFI 2.11 Table 33.3 that
its string holds, 0xF620-0xF62B, 0xF7zz and 0xF8zz: font display hints
that "different platforms may ignore" (§33.2.6.2.4 Common Control
Codes). A QUESTION or VALUE matched only the text with them.

ListTexts::display and ListTexts::matching_displayed now take them out
of each text. A keyword, the text of a strings package of a
configuration language, which display shows for --language x-UEFI-ns,
keeps them, as keywords gives it, and so does list-strings. A QUESTION
or VALUE matches the stripped texts only where no text as stored
matches it, in any FormSet, so an input that selected a question or
option before selects the same one; texts equal only after the
stripping are equal prompts, which select resolves to the first
selectable match in IFR order. The check of a STRING value takes the
control codes from the same definition, is_control_character.

The names that must match the firmware's own keep the codes: a
name/value storage's VarName, and the labels by which an ExportConfig
snapshot names its settings, now come from ListTexts::stored, the
stored text of the string that display shows. shown_text, which gives
the text of a STRING default, a KeywordInfo string and a REF's
DevicePath, keeps giving it as stored.

Test Plan:
- At this commit (tree 7d9cf689), on cbd138a: cargo check --locked
  --all-targets with RUSTFLAGS='-D warnings' and cargo fmt --check
  pass; cargo test --locked --lib: 1740 passed, 1721 on cbd138a,
  among them the new
  texts_show_and_match_without_their_control_codes,
  prompts_that_differ_only_in_ruled_out_characters_collide,
  set_q_writes_the_question_whose_stored_prompt_is_q,
  set_enabled_writes_the_option_whose_stored_text_is_enabled,
  set_q_writes_no_form_set_whose_prompt_only_reads_alike,
  option_and_help_texts_without_control_codes,
  texts_show_and_match_without_control_codes_and_keywords_with_them,
  name_value_names_keep_their_control_codes and
  lookup_labels_settings_by_their_stored_texts.
- With these tests on the product code of cbd138a:
  texts_show_and_match_without_their_control_codes,
  prompts_that_differ_only_in_ruled_out_characters_collide and
  option_and_help_texts_without_control_codes fail;
  set_q_writes_the_question_whose_stored_prompt_is_q,
  set_enabled_writes_the_option_whose_stored_text_is_enabled,
  set_q_writes_no_form_set_whose_prompt_only_reads_alike and
  lookup_labels_settings_by_their_stored_texts pass, as there a
  QUESTION or VALUE and a snapshot label matched texts as stored.
- Mutants, at the series' tip before it added
  get_of_a_stored_replacement_character_answers_its_question (tree
  bb54f835): displayed stripping nothing fails
  texts_show_and_match_without_their_control_codes,
  prompts_that_differ_only_in_ruled_out_characters_collide,
  option_and_help_texts_without_control_codes,
  texts_show_and_match_without_control_codes_and_keywords_with_them
  and, as the check of a STRING value shares is_control_character,
  write_null_pads_the_text_to_max_size; displayed stripping only a
  text that starts with a control code, display keeping the codes of
  a text that it falls back on for --language x-UEFI, or display
  stripping a keyword fails
  texts_show_and_match_without_control_codes_and_keywords_with_them;
  matching_displayed keeping the codes fails
  texts_show_and_match_without_their_control_codes and
  option_and_help_texts_without_control_codes; a VarName taken from
  display fails name_value_names_keep_their_control_codes, and
  snapshot labels taken from display fail
  lookup_labels_settings_by_their_stored_texts.
- Mutants of the match at the series' tip, in the Test Plan of the
  previous commit, also fail
  set_q_writes_the_question_whose_stored_prompt_is_q and
  set_q_writes_no_form_set_whose_prompt_only_reads_alike (prompts
  always matched as displayed), and
  set_enabled_writes_the_option_whose_stored_text_is_enabled
  (select_option without its stored texts, or with the displayed
  texts in place of the stored ones).

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The SCSU decoder refused a surrogate, a character between 0xF000 and
0xFCFF and one beyond UCS-2, which fails the whole HiiDB, while a UCS-2
string reads each of them as U+FFFD, as it does a private use character
in either encoding. UEFI 2.11 rules all of them out of strings alike:
"Characters between 0xF000 and 0xFCFF should be rejected" (§33.3.6.3.1
Standard Compression Scheme for Unicode (SCSU)), "UEFI does not support
surrogate characters" and "The UEFI specification uses UCS-2"
(§33.2.6.2.2 Surrogate Area).

The decoder now yields the characters of the string, as code points,
and its control codes, and the strings reader passes them through the
rule that it applies to UCS-2 strings: each character that UEFI rules
out reads as U+FFFD, a character beyond UCS-2 as one, with one warning
per string, which names a character beyond UCS-2 as outside UCS-2. A
control code through 0x7F stays a control code; SCSU encodes control
codes through 0x7F alone (§33.2.6.2.4 Common Control Codes), so a
character between 0xF000 and 0xFCFF, a control code's 0xFxyy form
among them, is ruled out (§33.3.6.3.1 Standard Compression Scheme for
Unicode (SCSU)).

Test Plan:
- At this commit (tree 377b007e), on cbd138a: cargo check --locked
  --all-targets with RUSTFLAGS='-D warnings' and cargo fmt --check
  pass; make -k lint, in 4 runs, passes; make test: 1847 passed, 1824
  on cbd138a, 1742 of them of cargo test --lib, 1721 on cbd138a;
  make test-i686: 1844 passed, 1821 on cbd138a; the Windows emulation
  (win-all) of cargo test --tests: 1035 passed, 1016 on cbd138a, each
  of which passes here but
  decode_refuses_the_uts_6_example_of_all_features_at_u_f000, which
  this commit renames decode_reads_the_uts_6_example_of_all_features.
- New tests:
  scsu_characters_that_uefi_rules_out_read_as_replacement_characters
  and decode_yields_the_characters_that_uefi_rules_out; the first fails
  on the product code of cbd138a, where read_db refuses the package.
- On x86_64, these rows of make test-e2e-qemu-x86_64 and
  test-e2e-qemu-shell-x86_64 pass, no log of them holding a warning of
  a ruled-out character: each row of a set or get of DriverSample,
  hii, hii-platform-lang, hii-no-runtime-access, hii-reserved,
  hii-snapshot, hii-readwrite, hii-time-storage, hii-acpi,
  hii-acpi-hiid, hii-acpi-two-tables, hii-systab, the 26 crash-guard-*
  rows of x86_64, shell-driver-sample, shell-parity, shell-password,
  shell-readwrite, shell-time-storage and shell-auth27; and those of
  the string fixtures, hii-global-variables, hii-name-value-string,
  hii-name-value-string-snapshot, hii-control-text, shell-control-text
  and shell-keyword-kinds: 49 rows.
- Mutants, at the series' tip or before it added
  get_of_a_stored_replacement_character_answers_its_question (tree
  bb54f835): characters up to U+10FFFF taken as UCS-2 fail
  scsu_characters_that_uefi_rules_out_read_as_replacement_characters
  and character_rules_out_each_range_up_to_its_bounds; SCSU units
  turned into characters without the rule fail
  scsu_characters_that_uefi_rules_out_read_as_replacement_characters
  and characters_that_uefi_rules_out_read_as_replacement_characters;
  an SCSU character that takes the exemption of the control codes of
  a CHAR16 fails
  scsu_characters_that_uefi_rules_out_read_as_replacement_characters
  and character_rules_out_each_range_up_to_its_bounds; a decoder that
  yields a control code as a character fails decode_reads_every_tag and
  scsu_characters_that_uefi_rules_out_read_as_replacement_characters.

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
lint-and-test ran lint and the unit tests of x86_64 and i686 Linux as
one check, and test-e2e-qemu the QEMU tests of Linux and of the UEFI
Shell on all 3 architectures as another, while test-macos showed a check
per runner and test-windows one, and no check ran the unit tests of
Linux and Windows on aarch64. Each kind of check now has one job, and
each system one entry of it, named after its operating system and
architecture, which runs make -k <check>:

- lint: make -k lint
- test (linux-x86_64), test (linux-aarch64), test (macos-aarch64),
  test (macos-x86_64), test (windows-x86_64) and test (windows-aarch64):
  make -k test; test (linux-i686):
  make -k test-i686
- test-e2e-qemu (linux-<arch>): make -k test-e2e-qemu-<arch>, and
  test-e2e-qemu (uefi-shell-<arch>): make -k test-e2e-qemu-shell-<arch>,
  for x86_64, i686 and aarch64

The aarch64 entries run on the ubuntu-26.04-arm and windows-11-arm
runners, and macos-aarch64 on macos-26, the image that macos-latest
names today, pinned like the other runners.

The test entries share one list of steps: gcc's 32-bit libraries only
for linux-i686, GNU make 4 on macOS through Homebrew's gnubin
directory on PATH, so that every entry runs make, and Chocolatey's
make on Windows. The Makefile now stops under a make older than 3.82,
such as macOS's 3.81, which would ignore its .SHELLFLAGS, so a missing
gnubin directory fails the macOS entries instead of falling back to it.
Every entry runs bash, which Windows needed already.
rust-cache keys each entry by its system, as linux-x86_64 and
linux-i686 share a job and a runner image. The QEMU inputs cache is
per system, as the Linux entries also fetch the -unfixed guests,
which a cache that the UEFI Shell entry of the architecture saved
first would lack. Each entry uploads its failure logs as
qemu-test-logs-<system>, as upload-artifact v4 and later refuse one
name in two entries.

The make targets, and what each runs, are unchanged.

Test Plan:
- make -n of test, test-i686, lint and the 6 QEMU targets prints the
  same commands as on main
- the workflow runs main's 19 runner and check pairs, with macos-26
  for macos-latest, plus test on ubuntu-26.04-arm and windows-11-arm
- yaml.safe_load parses it: 3 jobs, of 1, 7 and 6 entries
- make stops with the 3.82 message where .FEATURES lacks oneshell,
  and GNU make 4.4.1 runs every check
- make lint, make test and make test-i686 pass
- only a CI run shows the macOS, Windows and aarch64 entries, the
  caches, the check names and the whole QEMU sets on GitHub's runners

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
CI now names each check that it runs, so a check that joins the
Makefile would no longer reach CI by joining a group. The lint
ci-jobs fails unless .github/workflows/checks.yml names each check of
CI_CHECKS, as a "run: make -k <check>" line or a matrix entry's
"check: <check>", and no other. CI_CHECKS holds lint, the checks of
CHECKS outside LINTS and test-e2e-qemu, and each QEMU target. Which
systems run a check, and whether a job runs its entries' checks, stay
the workflow's alone. ci-jobs needs no toolchain.

Test Plan:
- make ci-jobs passes on this workflow
- it fails, naming each check, on main's workflow (8 checks missing,
  test-e2e-qemu unknown), without the linux-i686 entry, without the
  uefi-shell-aarch64 entry, with check test-i686 renamed test-i868,
  with an entry of an unknown test-e2e-qemu-riscv64, with
  "make -k lint test" in place of "make -k lint", with test-foo added
  to CHECKS and with test-e2e-qemu-riscv64 added to QEMU_LINUX_TESTS
- make lint passes

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
The comment that keeps rust-cache out of the QEMU job said that the
builds take about a minute without it. In run 43204183069
(https://github.com/linuxboot/uefisettings/actions/runs/43204183069),
run.sh's cargo builds took 147.5 s on x86_64, 137.8 s on i686 and
142.6 s on aarch64, from "run.sh: start" to the fourth "Finished",
and every QEMU entry now pays them.

Test Plan:
- comment only; make -n of every target is unchanged

Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
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.

1 participant