How to declare a static variable as a reference to a hard-coded memory address?

I am working on the built-in Rust code for the NXP LPC82X series controllers. The exact toolchain does not matter for the question.

These controllers contain peripheral drivers in the ROM. I want to use these drivers, which means that I need to use unsafe Rust and FFI without binding the actual code.

ROM APIs expose pointers to functions packaged in C structures at specific addresses. If anyone wants the details of this API, chapter 29 of the LPC82X manual describes the API in question.

My drawing of the My Rust mannequin is similar to this one, which will be hidden from the application code, but with an as yet unwritten abstraction of I2C. It compiles.

#![feature(naked_functions)] const I2C_ROM_API_ADDRESS: usize = 0x1fff_200c; static mut ROM_I2C_API: Option<&RomI2cApi> = None; #[repr(C)] struct RomI2cApi { // Dummy functions, real ones take arguments, and have different return // These won't be called directly, only through the struct implemented methods // value master_transmit_poll: extern "C" fn() -> bool, master_receive_poll: extern "C" fn() -> bool, } impl RomI2cApi { fn api_table() -> &'static RomI2cApi { unsafe { match ROM_I2C_API { None => RomI2cApi::new(), Some(table) => table, } } } unsafe fn new() -> &'static RomI2cApi { ROM_I2C_API = Some(&*(I2C_ROM_API_ADDRESS as *const RomI2cApi)); ROM_I2C_API.unwrap() } #[inline] fn master_transmit_poll(&self) -> bool { (self.master_transmit_poll)() } #[inline] fn master_receive_poll(&self) -> bool { (self.master_receive_poll)() } } impl From<usize> for &'static RomI2cApi { fn from(address: usize) -> &'static RomI2cApi { unsafe { &*(address as *const RomI2cApi) } } } fn main() { let rom_api = unsafe { RomI2cApi::api_table() }; println!("ROM I2C API address is: {:p}", rom_api); // Should be commented out when trying ! rom_api.master_transmit_poll(); } 

I cannot declare struct pointer struct as non-mutable static, since statics have many limitations, including not dereferencing pointers in assignment. Is there a better workaround than Option ? Using Option with the api_table function at least ensures that initialization happens.

+5
source share
1 answer

You can get around statics in general:

 const ROM_I2C_API: &RomI2cApi = &*(0x1fff_200c as *const RomI2cApi); 

It does not work, but it is planned to work in the future. Now use

 const ROM_I2C_API: *const RomI2cApi = 0x1fff_200c as *const RomI2cApi; fn api_table() -> &'static RomI2cApi { unsafe { &*(ROM_I2C_API) } } 

This creates &'static RomI2cApi and allows you to access functions everywhere directly by calling api_table().master_transmit_poll()

+4
source

Source: https://habr.com/ru/post/1275254/


All Articles