-
-
Notifications
You must be signed in to change notification settings - Fork 2
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
Lifetimed indexing for array accessors #44
base: main
Are you sure you want to change the base?
Conversation
Here is some quick self-review. I'm currently working on these issues.
Random thoughts:
|
Hinted from A pitfall of this solution is that
For now, I believe that the closest-to-best solution is to map the entire array region once, unmap it when dropped, and add another set of marker types into single-entry accessor type definition, if it doesn't complicate things too much. |
Thanks for the PR, and sorry for the delay. I'm riviewing the code. Meanwhile, could you apply |
Converted to draft since this PR is incomplete and has a double-unmapping problem mentioned above. |
Resolved double mapping issue w/o creating any new marker structs. The (wrapped) set of single-elem accessors returned from Removed draft status of the PR. Please notify me if anything is unclear. (Edit) Just followed up rust-osdev/xhci#142 . |
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.
Sorry, but I'm still trying to understand the code. It'd be great if you provide some sample code that works with your patch. Meanwhile, I think this crate needs test codes, so I'll add them in another PR.
Also, is it correct that the fundamental idea is, instead of having an accessor covering the whole range of a struct or an array, to let such an accessor generate an accessor for its element with a lifetime bound?
Roughly correct. To sum up:
I have documented the use cases of new structs. You can refer to them when you make test codes. |
src/array.rs
Outdated
/// | ||
/// // Below are the equivalent examples using `.at()` method. | ||
/// | ||
/// // Read the 3rd element of the array. | ||
/// a.at(3).read_volatile(); | ||
/// | ||
/// // Write 42 as the 5th element of the array. | ||
/// a.at(5).write_volatile(42); | ||
/// | ||
/// // Update the 0th element. | ||
/// a.at(0).update_volatile(|v| { | ||
/// *v *= 2; | ||
/// }) | ||
/// |
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 is an example of indexing using .at(i)
methods. Unlike .set_at(i)
, this doesn't require to refer any traits.
Basically, .at(i)
method is introduced to replace .***_volatile_at(i)
with .at(i).***_volatile()
so most use cases are limited to these situations.
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 applying my suggestions.
src/mapper.rs
Outdated
|
||
/// an identity mapper which maps a physical address into itself. | ||
#[derive(Clone)] | ||
pub struct Identity; | ||
impl Mapper for Identity { | ||
#[allow(unused_variables)] | ||
unsafe fn map(&mut self, phys_base: usize, bytes: usize) -> NonZeroUsize { | ||
NonZeroUsize::new_unchecked(phys_base) | ||
} | ||
#[allow(unused_variables)] | ||
fn unmap(&mut self, virt_base: usize, bytes: usize) {} | ||
} |
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.
Could you create another PR for this change?
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 identity mapper is actually coupled with the rest of the changes and can't be separated. A bounded accessor internally uses identity as its mapper in order to preserve already-mapped vaddr space.
Say we reserve 0x1000..0x1010 physical address range for [u32;4]
array accessor a
, and our mapper maps 0x1000 page into 0x3000 frame. Then a.at(1)
should hold virtual address range 0x3004..0x3008.
However if we use the same mapper again when creating this bounded accessor, the mapper recognizes 0x3000 as another physical page and will map it into (e.g.) 0x5000 frame, and the bounded accessor will get the wrong range 0x5004..0x5008. (This is what I referred to as 'double mapping issue'.)
The solution I brought for this is to use identity mapper for element accessor, which prevents 0x3000 to be mapped to anywhere except 0x3000 itself.
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.
Sorry for the late response.
This identity mapper is actually coupled with the rest of the changes and can't be separated.
Does it mean you'll change this mapper in later commits? If not, sorry for not being clear enough, but I thought this identify mapper itself was useful as many people use identify mapping, and I can merge the PR before #44 if you separate this change.
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.
Oops. I'd misunderstood that you have meant "This Identity mapper is irrelevant to the rest of the changes so it should be in a separated PR".
For convenience's sake, identity mapper could be included in advance to this PR. Please wait for a couple of days.
Thanks for the response. I renamed some structs.
Clippy now complains that there are no |
Is it possible to implement |
I added a few tests for the existing accessor types. Could you add additional tests for this PR too? |
Sorry for delay. For some register arrays, it is more concise to design each register entry be moved entirely into another data structures. So although unsafe, I added an unbounded indexing method (I might got something wrong here. I don't have any test OS or any experience writing a driver, so correct me if anything is misunderstood.) (Edit) |
This PR is the generic design of
xhci
cratexhci::registers::runtime::{InterrupterRegisterSet, Interrupter}
pair.Main changes are:
a.read_volatile_at(i)
could be rewritten toa.at(i).access.read_volatile()
.T
of the accessor is a field struct, instead ofa.at(i).read_volatile().x
to use one big accessor, we can have a struct of accessors, each field of which represents the accessor to the field of same name, i.e.a.set_at(i).x.read_volatile()
.To use this, the definition of struct
T
should be decorated with#[derive(accessor::array::LifetimedSetGenericOf)]
. This will generate a struct-of-accessors typeLifetimedSetGenericOfT
, and implementaccessor::array::LifetimedSetGeneric<T>
with it the as associated type.Additionally, this PR includes:
Add built-in
accessor::mapper::Identity
mapper. TheIdentity
mapper either repeats already-mapped virtual addresses, or assumes that we are using physical addresses all along.((Edit) not necessarily.)accessor::mapper::Mapper
should implement [Clone
] fora.at(i)
anda.set_at(i)
methods. (Alternatively we could revert this change and implementa.at(i)
anda.set_at(i)
method only forM: Mapper + Clone
.)accessor::marker::AccessorTypeSpecifier
should implement [Copy
], which is done by default. ((Edit) pointless change now, but a new commit to just revert this seems too much.)Crate
memoffset
is re-exported asaccessor::memoffset
so that macro expansion can resolve it corretly.I'm new to proc-macros, so I'm not sure if it's a right way to refer 3rd-party crates in proc-macro code generation.
Disclaimer: not tested in runtime.
Any suggestions (and testing) are welcomed.