Skip to content

mmio: use one VolatilePtr instead of many AtomicPtr #35

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
mkroening opened this issue Jul 12, 2024 · 5 comments
Open

mmio: use one VolatilePtr instead of many AtomicPtr #35

mkroening opened this issue Jul 12, 2024 · 5 comments

Comments

@mkroening
Copy link
Member

For MMIO the serial port is defined as:

pub struct MmioSerialPort {
    data: AtomicPtr<u8>,
    int_en: AtomicPtr<u8>,
    fifo_ctrl: AtomicPtr<u8>,
    line_ctrl: AtomicPtr<u8>,
    modem_ctrl: AtomicPtr<u8>,
    line_sts: AtomicPtr<u8>,
}

with

        Self {
            data: AtomicPtr::new(base_pointer),
            int_en: AtomicPtr::new(base_pointer.add(1)),
            fifo_ctrl: AtomicPtr::new(base_pointer.add(2)),
            line_ctrl: AtomicPtr::new(base_pointer.add(3)),
            modem_ctrl: AtomicPtr::new(base_pointer.add(4)),
            line_sts: AtomicPtr::new(base_pointer.add(5)),
        }

Instead, it should be only one pointer in size and using volatile operations instead of atomic ones via #[derive(VolatileFieldAccess).

I can take a look at this in the coming weeks.

@ChocolateLoverRaj
Copy link

I think besides being volatile, the only thing an atomic pointer would do is make sure that part of a byte isn't written before the other part of the byte (which Rust wouldn't do anyways, but it doesn't promise that it won't). So nothing should break with this change right? I was also confused why the code uses AtomicPtr and not volatile.

@ChocolateLoverRaj
Copy link

@mkroening how would this work with stride (for example with each register takes up 32 bits in MMIO).

@mkroening
Copy link
Member Author

We could make VolatileFieldAccess work with const generics and then do

#[derive(VolatileFieldAccess)]
pub struct MmioSerialPort<const PAD: usize = 0> {
    data: u8,
    __pad1: [u8; PAD],
    int_en: u8,
    __pad2: [u8; PAD],
    fifo_ctrl: u8,
    __pad3: [u8; PAD],
    line_ctrl: u8,
    __pad4: [u8; PAD],
    modem_ctrl: u8,
    __pad5: [u8; PAD],
    line_sts: u8,
    __pad6: [u8; PAD],
}

What do you think about this approach?

@ChocolateLoverRaj
Copy link

What do you think about this approach?

The PAD would have to be stride - 1, which I'm not sure if it's possible. And I have a use case where I don't know the stride in compile time. I only know the stride at run time, which I don't think would would work in this case.

I made #39, which still uses 6 different volatile pointers instead of a volatile struct, but I could adjust it to instead have functions like get_register_with_offset(offset: usize) so that only a single u16 (for ports) or pointer (for MMIO) will need to be stored. Then we could keep using volatile pointers but we could just add index * stride in run time instead of using VolatileFieldAccess.

@mkroening
Copy link
Member Author

I see. Having ptr_base(&self) -> VolatilePtr<'_, u8>, ptr_data(&self) -> VolatilePtr<'_, u8> while only having one VolatilePtr<'a, u8> and the stride inside the struct sounds sensible to me. 👍

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants