-
Notifications
You must be signed in to change notification settings - Fork 192
firmware_uefi: implement MOR (Memory Overwrite Request) bit support #3397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
89bb4b7
2eae1ec
b3563ab
be29d70
898680d
df6fd92
e589e34
693b4e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,6 +71,7 @@ use inspect::InspectMut; | |
| use local_clock::InspectableLocalClock; | ||
| use pal_async::local::block_on; | ||
| use platform::logger::UefiLogger; | ||
| use platform::nvram::MorConfig; | ||
| use platform::nvram::VsmConfig; | ||
| use service::diagnostics::DEFAULT_LOGS_PER_PERIOD; | ||
| use service::diagnostics::WATCHDOG_LOGS_PER_PERIOD; | ||
|
|
@@ -143,6 +144,7 @@ pub struct UefiRuntimeDeps<'a> { | |
| pub generation_id_deps: generation_id::GenerationIdRuntimeDeps, | ||
| pub vsm_config: Option<Box<dyn VsmConfig>>, | ||
| pub time_source: Box<dyn InspectableLocalClock>, | ||
| pub mor_config: Option<Box<dyn MorConfig>>, | ||
| } | ||
|
|
||
| /// The Hyper-V UEFI services chipset device. | ||
|
|
@@ -164,6 +166,11 @@ pub struct UefiDevice { | |
| #[inspect(hex)] | ||
| address: u32, | ||
|
|
||
| // MOR (Memory Overwrite Request) state | ||
| mor_bit_status: bool, | ||
| #[inspect(skip)] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe worth inspecting with an is_some? |
||
| mor_config: Option<Box<dyn MorConfig>>, | ||
|
|
||
| // Receiver for watchdog timeout events | ||
| #[inspect(skip)] | ||
| watchdog_recv: mesh::Receiver<()>, | ||
|
|
@@ -185,6 +192,7 @@ impl UefiDevice { | |
| generation_id_deps, | ||
| vsm_config, | ||
| time_source, | ||
| mor_config, | ||
| } = runtime_deps; | ||
|
|
||
| // Create the UEFI device with the rest of the services. | ||
|
|
@@ -194,6 +202,8 @@ impl UefiDevice { | |
| address: 0, | ||
| gm, | ||
| watchdog_recv, | ||
| mor_bit_status: true, // initialized to success, matching legacy behavior | ||
| mor_config, | ||
|
mebersol marked this conversation as resolved.
|
||
| service: UefiDeviceServices { | ||
| nvram: service::nvram::NvramServices::new( | ||
| nvram_storage, | ||
|
|
@@ -233,6 +243,10 @@ impl UefiDevice { | |
| self.handle_watchdog_read(reg) | ||
| } | ||
| UefiCommand::NFIT_SIZE => 0, // no NFIT | ||
| UefiCommand::MOR_SET_VARIABLE => { | ||
| // Return 1 if the last MOR SetVariable succeeded, 0 otherwise. | ||
| u32::from(self.mor_bit_status) | ||
| } | ||
| _ => { | ||
| tracelimit::warn_ratelimited!(?addr, "unknown uefi read"); | ||
| !0 | ||
|
|
@@ -285,10 +299,38 @@ impl UefiDevice { | |
| None, | ||
| ); | ||
| } | ||
| UefiCommand::MOR_SET_VARIABLE => block_on(self.handle_mor_set_variable(data as u8)), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can't be a block_on. If it really needs to be async then this device will have to do the whole PollDevice dance
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Namely store a future and poll it inside poll_device |
||
| _ => tracelimit::warn_ratelimited!(addr, data, "unknown uefi write"), | ||
| } | ||
| } | ||
|
|
||
| /// Handle the MOR_SET_VARIABLE command from the guest. | ||
| /// | ||
| /// Persists the MOR variable in NVRAM and notifies the platform so it can | ||
| /// arrange for memory to be scrubbed on the next reset. | ||
| async fn handle_mor_set_variable(&mut self, value: u8) { | ||
| use uefi_specs::uefi::nvram::EfiVariableAttributes; | ||
| use uefi_specs::uefi::nvram::vars; | ||
|
|
||
| let attr = EfiVariableAttributes::DEFAULT_ATTRIBUTES; | ||
|
|
||
| let result = self | ||
| .service | ||
| .nvram | ||
| .set_mor_variable(vars::MEMORY_OVERWRITE_REQUEST_CONTROL(), value, attr.into()) | ||
| .await; | ||
|
|
||
| self.mor_bit_status = result.is_ok(); | ||
|
|
||
| if self.mor_bit_status { | ||
| if let Some(mor_config) = &self.mor_config { | ||
| mor_config.notify_mor_set(value); | ||
| } | ||
| } else { | ||
| tracelimit::warn_ratelimited!("failed to set MOR variable in NVRAM"); | ||
|
mebersol marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
|
Comment on lines
+307
to
+339
|
||
|
|
||
| /// Extra inspection fields for the UEFI device. | ||
| fn inspect_extra(&mut self, resp: &mut inspect::Response<'_>) { | ||
| const USAGE: &str = | ||
|
|
@@ -580,6 +622,8 @@ mod save_restore { | |
| command_set: _, | ||
| gm: _, | ||
| watchdog_recv: _, | ||
| mor_bit_status: _, | ||
| mor_config: _, | ||
|
Comment on lines
633
to
+636
|
||
| service: | ||
| UefiDeviceServices { | ||
| nvram, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,3 +16,18 @@ pub use uefi_specs::uefi::time::EFI_TIME; | |
| pub trait VsmConfig: Send { | ||
| fn revoke_guest_vsm(&self); | ||
| } | ||
|
|
||
| /// Callbacks for MOR (Memory Overwrite Request) bit changes. | ||
| /// | ||
| /// When the guest sets the MOR bit via the UEFI device, the platform may need | ||
| /// to take action to ensure memory is scrubbed on the next reset. In Underhill, | ||
| /// this is done by setting the `zero_memory_on_reset` flag in | ||
| /// `HvRegisterVsmPartitionConfig`. | ||
| pub trait MorConfig: Send { | ||
| /// Called when the guest sets the MOR variable. | ||
| /// | ||
| /// `mor_value` is the raw byte written by the guest. Bit 0 | ||
| /// (`MOR_CLEAR_MEMORY_BIT_MASK`) indicates whether memory should be cleared | ||
| /// on the next reset. | ||
| fn notify_mor_set(&self, mor_value: u8); | ||
| } | ||
|
Comment on lines
+20
to
+33
|
||
Uh oh!
There was an error while loading. Please reload this page.