-1

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] );
Adrien Chapelet
  • 386
  • 4
  • 24
  • Your code that "reads values" doesn't actually read anything, it just prints out an address. – cdhowie Mar 29 '23 at 15:07
  • How can I display the memory content of these addresses? – Adrien Chapelet Mar 29 '23 at 15:08
  • 6
    From the [duplicate](https://stackoverflow.com/a/55658380/5397009) that was given to [your previous question](https://stackoverflow.com/q/75878242/5397009), you only need to add `mut` to get write access: [playground](https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=669cc3cbf1339f1b953d4d8a8d4b82ba). – Jmb Mar 29 '23 at 15:10
  • I struggle in importing `use std::slice;` (compiler says use of undeclared crate or module `std`), any idea why? – Adrien Chapelet Mar 29 '23 at 15:29
  • @AdrienChapelet Are you using `no_std`? – cdhowie Mar 29 '23 at 15:32
  • yes :( any alternative to `std::slice::from_raw_parts_mut` ? – Adrien Chapelet Mar 29 '23 at 15:46
  • It's also in `core`, i.e. use `core::slice::from_raw_parts_mut` – Jmb Mar 29 '23 at 15:52

1 Answers1

0

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;
cafce25
  • 15,907
  • 4
  • 25
  • 31
  • Given that you've chosen to only mark `new` as `unsafe`, I would add an `assert_eq!(self.ptr as usize % mem::align_of::(), 0)` to each `as_*` method, just to be on the safe side. – Jmb Mar 30 '23 at 06:24