0

I declared pointers (memory addresses) and I am able to read values like that in Rust:

let psram = 0x60000000 as *const u32;
let psramh = 0x60000000 as *const u16;
let psramb = 0x60000000 as *const u8;

let psram0 = unsafe {psram.offset(0)};
rprintln!( "RAM[0]: 0x{:X?} (Uninitialized)\r\n", psram0 );
    

But how can I set and display values to these memory addresses, I would do it like that in C (and rust to display):

psram[0] = 0x01234567;
psram[1] = 0x89ABCDEF;
rprintln!( "RAM[0]: 0x{:#02x} (Byte)\r\n", psramb[0] );
rprintln!( "RAM[0]: 0x{:#04x}(Halfword)\r\n", psramh[0] );
rprintln!( "RAM[0]: 0x{:X?} (Word)\r\n", psram[0] );
rprintln!( "RAM[4]: 0x{:X?}\r\n", psram[1] );
7
  • Your code that "reads values" doesn't actually read anything, it just prints out an address. Commented Mar 29, 2023 at 15:07
  • How can I display the memory content of these addresses? Commented Mar 29, 2023 at 15:08
  • 7
    From the duplicate that was given to your previous question, you only need to add mut to get write access: playground. Commented Mar 29, 2023 at 15:10
  • I struggle in importing use std::slice; (compiler says use of undeclared crate or module std), any idea why? Commented Mar 29, 2023 at 15:29
  • @AdrienChapelet Are you using no_std? Commented Mar 29, 2023 at 15:32

1 Answer 1

1

Immutable access in this case is way easier to accomplish safely and soundly, because you don't have to think about mutable aliasing and lifetimes as much, for mutable access with different types I would probably implement an abstraction that handles all the conversion and makes sure no aliasing occurs with mutable references involved:

#![no_std]
pub struct PsRam {
    ptr: *mut u32,
    words: usize,
}
impl PsRam {
    /// This function is `unsafe` because the caller has to make sure it's only called
    /// once for every address and that it actually points to `len` contiguous words we
    /// are allowed to read and write, for slice access later the pointer must further
    /// be properly aligned at a word boundary.
    pub const unsafe fn new(ptr: *mut u32, words: usize) -> Self {
        Self { ptr, words }
    }

    pub fn as_bytes(&self) -> &[u8] {
        unsafe { core::slice::from_raw_parts(self.ptr as *mut u8, 4 * self.words) }
    }

    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        unsafe { core::slice::from_raw_parts_mut(self.ptr as *mut u8, 4 * self.words) }
    }

    pub fn as_half_words(&self) -> &[u16] {
        unsafe { core::slice::from_raw_parts(self.ptr as *mut u16, 2 * self.words) }
    }

    pub fn as_half_words_mut(&mut self) -> &mut [u16] {
        unsafe { core::slice::from_raw_parts_mut(self.ptr as *mut u16, 2 * self.words) }
    }

    pub fn as_words(&self) -> &[u32] {
        unsafe { core::slice::from_raw_parts(self.ptr as *mut u32, self.words) }
    }

    pub fn as_words_mut(&mut self) -> &mut [u32] {
        unsafe { core::slice::from_raw_parts_mut(self.ptr as *mut u32, self.words) }
    }
}

This way we can safely write code like this:

const PS_RAM_WORDS: usize = 4; // how ever many words psram contains

let mut psram = unsafe { PsRam::new(0x60000000 as *mut u32, PS_RAM_WORDS) };

// all this works
rprintln!("address of second byte: {:p}", &psram.as_bytes()[1]);
rprintln!("psram as half words: {:?}", psram.as_half_words());
rprintln!("first word of psram: {:#010x}", psram.as_words()[0]);
psram.as_words_mut()[0] = 0x12345678;
rprintln!("first word of psram after edit: {:#010x}", psram.as_words()[0]);

output assuming the memory is 0 initialized:

address of second byte: 0x60000001
psram as half words: [0, 0, 0, 0, 0, 0, 0, 0]
first word of psram: 0x00000000
first word of psram after edit: 0x12345678

While the compiler helps rejecting code containing undefined behavior like this (two aliasing mutable references are not allowed):

let psramb = psram.as_bytes_mut();
let psramw = psram.as_words_mut();
psramb[0] = 13;
psramw[1] = 99;
Sign up to request clarification or add additional context in comments.

1 Comment

Given that you've chosen to only mark new as unsafe, I would add an assert_eq!(self.ptr as usize % mem::align_of::<T>(), 0) to each as_* method, just to be on the safe side.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.