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
feat: add PmTimer
#83
feat: add PmTimer
#83
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! I've been wondering about how to approach ACPI's register blocks in a good way for a while - I think providing a good interface is going to be slightly tricky.
The problem with the approach in this PR is how it will scale to the entire register block - we'll end up mapping the FADT potentially many times, just to pull a few bytes out here and there each time.
My alternative suggestion is to expose this through the PlatformInfo
type - this already parses the FADT for various other things, and I think collecting all of this information in there creates a nice interface for when we parse the rest of the fixed hardware stuff. What do you think?
I've also highlighted a few problems implementation-wise.
acpi/src/fadt.rs
Outdated
/// Information about the ACPI Power Management Timer (ACPI PM Timer). | ||
pub struct PmTimer { | ||
/// An I/O space address to the register block of ACPI PM Timer. | ||
pub io_base: u32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From §4.8.3.3 of the spec, it looks like the PM timer doesn't have to be in I/O space, but can instead be in system memory. PM_TMR_BLK
should always be treated as an I/O address, but is superceded by the X_PM_TMR_BLK
field (if present and non-zero), which is a GenericAddress
. This should therefore probably be a GenericAddress
(which should be created from PM_TMR_BLK
in I/O space if that field is used.
Edit: currently GenericAddress
is pub(crate)
. We'll have to make it public, and should probably think about providing an enum-based representation for better user-consumption, while we can change it without breaking semver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean like this?
enum Addr{
Phys(usize),
Io(u32),
Pci(u32),
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort of, unfortunately we need to handle the rest of the address spaces off the bat as well as we'd break semver by adding the other variants later.
I've had a more careful look at how we should do this, and it turns out an enum doesn't really work as well as I thought it would. I basically ended up writing what I thought would work; hope that's okay. If you rebase your branch you should be able to switch to just using the new GenericAddress
.
acpi/src/fadt.rs
Outdated
} | ||
impl PmTimer { | ||
/// Creates a new instance of `PmTimer`. | ||
pub fn new<H>(tables: &AcpiTables<H>) -> Result<PmTimer, AcpiError> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PM timer is an optional feature (if both PM_TMR_BLK
and X_PM_TMR_BLK
are zero), so this should probably return Result<Option<PmTimer>, AcpiError>
.
acpi/src/fadt.rs
Outdated
.ok_or(AcpiError::TableMissing(crate::sdt::Signature::FADT))? | ||
}; | ||
|
||
Ok(PmTimer { io_base: fadt.pm_timer_block, supports_32bit: fadt.flags.get_bit(8) }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to handle two more things:
- If
X_PM_TMR_BLK
is present (check withExtendedField::access
), use that instead ofPM_TMR_BLK
. Actually, this logic is probably best implemented as apm_timer_block()
method onFadt
, like we currently do withdsdt_address
- If both fields are zero, there is no PM timer. This should then return
Ok(None)
.
acpi/src/fadt.rs
Outdated
@@ -128,3 +131,27 @@ impl Fadt { | |||
} | |||
} | |||
} | |||
|
|||
/// Information about the ACPI Power Management Timer (ACPI PM Timer). | |||
pub struct PmTimer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Context provided in the top-level review comment)
I think this might be better living in platform.rs
, stored as a Option<PmTimer
in PlatformInfo
, and extracted from the FADT in PlatformInfo::new
Done. By the way, I think the members should be private and instead, getters should be called not to wrongly edit the values. What do you think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, this is looking pretty good! Just two small questions, and then this can be merged.
Thanks!
acpi/src/fadt.rs
Outdated
self.x_pm_timer_block.access(self.header().revision).or_else(|| { | ||
if self.pm_timer_block != 0 { | ||
Some(RawGenericAddress { | ||
address_space: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the older pm_timer_block
is in I/O space (I think it is, as the spec says "system port address", but I wish that was clearer), shouldn't this be 1
?
acpi/src/fadt.rs
Outdated
} | ||
} | ||
|
||
pub fn flags(&self) -> u32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this will be public, could we call it raw_flags
, as we may want to provide a nicer view into the flags in the future, and it would be nice for that to be called flags
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(as mentioned below) as this is just a field access, I wouldn't be against just making the field pub
, and then we can add a flags
method later on for parsing the bitfield if we want?
Do you mean on |
OK, I made |
Thanks very much! |
This PR introduces a new struct called
PmTimer
, which contains the information of the ACPI Power Management Timer. It can be constructed fromAcpiTables
.