mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-09 19:07:30 +02:00
Updates for Rust 1.82 (#2449)
Rust 1.82 adds `&raw` expressions, and marks some attributes as unsafe.
This commit is contained in:
parent
2bba470415
commit
f8882190f3
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -55,6 +55,9 @@ jobs:
|
|||||||
- name: Setup Rust cache
|
- name: Setup Rust cache
|
||||||
uses: ./.github/workflows/setup-rust-cache
|
uses: ./.github/workflows/setup-rust-cache
|
||||||
|
|
||||||
|
- name: Update Rust
|
||||||
|
run: rustup update
|
||||||
|
|
||||||
- name: Build Rust code
|
- name: Build Rust code
|
||||||
run: cargo build
|
run: cargo build
|
||||||
|
|
||||||
@ -89,7 +92,9 @@ jobs:
|
|||||||
sudo apt install gcc-aarch64-linux-gnu
|
sudo apt install gcc-aarch64-linux-gnu
|
||||||
|
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
run: rustup target add ${{ matrix.target }}
|
run: |
|
||||||
|
rustup update
|
||||||
|
rustup target add ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Build Rust code
|
- name: Build Rust code
|
||||||
working-directory: ${{ matrix.directory }}
|
working-directory: ${{ matrix.directory }}
|
||||||
@ -140,6 +145,9 @@ jobs:
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install gettext
|
sudo apt install gettext
|
||||||
|
|
||||||
|
- name: Update Rust
|
||||||
|
run: rustup update
|
||||||
|
|
||||||
- name: Install mdbook
|
- name: Install mdbook
|
||||||
uses: ./.github/workflows/install-mdbook
|
uses: ./.github/workflows/install-mdbook
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@ use jni::sys::jstring;
|
|||||||
use jni::JNIEnv;
|
use jni::JNIEnv;
|
||||||
|
|
||||||
/// HelloWorld::hello method implementation.
|
/// HelloWorld::hello method implementation.
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
pub extern "system" fn Java_HelloWorld_hello(
|
pub extern "system" fn Java_HelloWorld_hello(
|
||||||
mut env: JNIEnv,
|
mut env: JNIEnv,
|
||||||
_class: JClass,
|
_class: JClass,
|
||||||
|
@ -6,14 +6,13 @@ Similarly, you can export Rust functions and call them from C.
|
|||||||
You can do it by hand if you want:
|
You can do it by hand if you want:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern "C" {
|
unsafe extern "C" {
|
||||||
fn abs(x: i32) -> i32;
|
safe fn abs(x: i32) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = -42;
|
let x = -42;
|
||||||
// SAFETY: `abs` doesn't have any safety requirements.
|
let abs_x = abs(x);
|
||||||
let abs_x = unsafe { abs(x) };
|
|
||||||
println!("{x}, {abs_x}");
|
println!("{x}, {abs_x}");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -3,14 +3,13 @@
|
|||||||
We can declare external functions by hand:
|
We can declare external functions by hand:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern "C" {
|
unsafe extern "C" {
|
||||||
fn abs(x: i32) -> i32;
|
safe fn abs(x: i32) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = -42;
|
let x = -42;
|
||||||
// SAFETY: `abs` doesn't have any safety requirements.
|
let abs_x = abs(x);
|
||||||
let abs_x = unsafe { abs(x) };
|
|
||||||
println!("{x}, {abs_x}");
|
println!("{x}, {abs_x}");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -42,8 +42,8 @@ Build, push, and run the binary on your device:
|
|||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
`#[no_mangle]` disables Rust's usual name mangling, so the exported symbol will
|
`#[unsafe(no_mangle)]` disables Rust's usual name mangling, so the exported
|
||||||
just be the name of the function. You can also use
|
symbol will just be the name of the function. You can also use
|
||||||
`#[export_name = "some_name"]` to specify whatever name you want.
|
`#[unsafe(export_name = "some_name")]` to specify whatever name you want.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
/// Analyze the numbers.
|
/// Analyze the numbers.
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn analyze_numbers(x: c_int, y: c_int) {
|
pub extern "C" fn analyze_numbers(x: c_int, y: c_int) {
|
||||||
if x < y {
|
if x < y {
|
||||||
println!("x ({x}) is smallest!");
|
println!("x ({x}) is smallest!");
|
||||||
|
@ -8,7 +8,7 @@ Now let's use the new `Registers` struct in our driver.
|
|||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
- Note the use of `addr_of!` / `addr_of_mut!` to get pointers to individual
|
- Note the use of `&raw const` / `&raw mut` to get pointers to individual fields
|
||||||
fields without creating an intermediate reference, which would be unsound.
|
without creating an intermediate reference, which would be unsound.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -17,49 +17,57 @@ use log::error;
|
|||||||
use smccc::psci::system_off;
|
use smccc::psci::system_off;
|
||||||
use smccc::Hvc;
|
use smccc::Hvc;
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
|
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
|
||||||
error!("sync_exception_current");
|
error!("sync_exception_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
|
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
|
||||||
error!("irq_current");
|
error!("irq_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
|
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
|
||||||
error!("fiq_current");
|
error!("fiq_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
|
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
|
||||||
error!("serr_current");
|
error!("serr_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("sync_lower");
|
error!("sync_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("irq_lower");
|
error!("irq_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("fiq_lower");
|
error!("fiq_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("serr_lower");
|
error!("serr_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
|
@ -29,7 +29,8 @@ use smccc::Hvc;
|
|||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
||||||
// nothing else accesses that address range.
|
// nothing else accesses that address range.
|
||||||
|
@ -29,7 +29,8 @@ use smccc::Hvc;
|
|||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
||||||
// nothing else accesses that address range.
|
// nothing else accesses that address range.
|
||||||
|
@ -29,7 +29,8 @@ use smccc::Hvc;
|
|||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
const PL011_BASE_ADDRESS: *mut u8 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u8 = 0x900_0000 as _;
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
||||||
// nothing else accesses that address range.
|
// nothing else accesses that address range.
|
||||||
|
@ -23,7 +23,8 @@ mod exceptions;
|
|||||||
|
|
||||||
const PSCI_SYSTEM_OFF: u32 = 0x84000008;
|
const PSCI_SYSTEM_OFF: u32 = 0x84000008;
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {
|
extern "C" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {
|
||||||
// SAFETY: this only uses the declared registers and doesn't do anything
|
// SAFETY: this only uses the declared registers and doesn't do anything
|
||||||
// with memory.
|
// with memory.
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
use core::ptr::{addr_of, addr_of_mut};
|
|
||||||
|
|
||||||
// ANCHOR: Flags
|
// ANCHOR: Flags
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
@ -124,7 +123,7 @@ impl Uart {
|
|||||||
// of a PL011 device which is appropriately mapped.
|
// of a PL011 device which is appropriately mapped.
|
||||||
unsafe {
|
unsafe {
|
||||||
// Write to the TX buffer.
|
// Write to the TX buffer.
|
||||||
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
|
(&raw mut (*self.registers).dr).write_volatile(byte.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until the UART is no longer busy.
|
// Wait until the UART is no longer busy.
|
||||||
@ -139,7 +138,7 @@ impl Uart {
|
|||||||
} else {
|
} else {
|
||||||
// SAFETY: We know that self.registers points to the control
|
// SAFETY: We know that self.registers points to the control
|
||||||
// registers of a PL011 device which is appropriately mapped.
|
// registers of a PL011 device which is appropriately mapped.
|
||||||
let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
|
let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
|
||||||
// TODO: Check for error conditions in bits 8-11.
|
// TODO: Check for error conditions in bits 8-11.
|
||||||
Some(data as u8)
|
Some(data as u8)
|
||||||
}
|
}
|
||||||
@ -148,7 +147,7 @@ impl Uart {
|
|||||||
fn read_flag_register(&self) -> Flags {
|
fn read_flag_register(&self) -> Flags {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL011 device which is appropriately mapped.
|
// of a PL011 device which is appropriately mapped.
|
||||||
unsafe { addr_of!((*self.registers).fr).read_volatile() }
|
unsafe { (&raw const (*self.registers).fr).read_volatile() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ANCHOR_END: Uart
|
// ANCHOR_END: Uart
|
||||||
|
@ -20,8 +20,8 @@ for all these functions.)
|
|||||||
inline assembly code, and ignore its contents afterwards. We need to use
|
inline assembly code, and ignore its contents afterwards. We need to use
|
||||||
`inout` rather than `in` because the call could potentially clobber the
|
`inout` rather than `in` because the call could potentially clobber the
|
||||||
contents of the registers.
|
contents of the registers.
|
||||||
- This `main` function needs to be `#[no_mangle]` and `extern "C"` because it is
|
- This `main` function needs to be `#[unsafe(no_mangle)]` and `extern "C"`
|
||||||
called from our entry point in `entry.S`.
|
because it is called from our entry point in `entry.S`.
|
||||||
- `_x0`–`_x3` are the values of registers `x0`–`x3`, which are conventionally
|
- `_x0`–`_x3` are the values of registers `x0`–`x3`, which are conventionally
|
||||||
used by the bootloader to pass things like a pointer to the device tree.
|
used by the bootloader to pass things like a pointer to the device tree.
|
||||||
According to the standard aarch64 calling convention (which is what
|
According to the standard aarch64 calling convention (which is what
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
- Use [`pointer::read_volatile`] and [`pointer::write_volatile`].
|
- Use [`pointer::read_volatile`] and [`pointer::write_volatile`].
|
||||||
- Never hold a reference.
|
- Never hold a reference.
|
||||||
- Use [`addr_of!`] to get fields of structs without creating an intermediate
|
- Use `&raw` to get fields of structs without creating an intermediate
|
||||||
reference.
|
reference.
|
||||||
|
|
||||||
[`pointer::read_volatile`]: https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.read_volatile
|
[`pointer::read_volatile`]: https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.read_volatile
|
||||||
@ -19,7 +19,8 @@
|
|||||||
- Some existing crates for volatile access to hardware do hold references, but
|
- Some existing crates for volatile access to hardware do hold references, but
|
||||||
this is unsound. Whenever a reference exist, the compiler may choose to
|
this is unsound. Whenever a reference exist, the compiler may choose to
|
||||||
dereference it.
|
dereference it.
|
||||||
- Use the `addr_of!` macro to get struct field pointers from a pointer to the
|
- Use `&raw` to get struct field pointers from a pointer to the struct.
|
||||||
struct.
|
- For compatibility with old versions of Rust you can use the [`addr_of!`] macro
|
||||||
|
instead.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#[link_section = ".vector_table.interrupts"]
|
#[unsafe(link_section = ".vector_table.interrupts")]
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global variable of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
pub static __INTERRUPTS: [usize; 1] = [0];
|
pub static __INTERRUPTS: [usize; 1] = [0];
|
||||||
|
@ -17,13 +17,15 @@ use log::{error, info, trace};
|
|||||||
use smccc::psci::system_off;
|
use smccc::psci::system_off;
|
||||||
use smccc::Hvc;
|
use smccc::Hvc;
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
|
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
|
||||||
error!("sync_exception_current");
|
error!("sync_exception_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
|
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
|
||||||
trace!("irq_current");
|
trace!("irq_current");
|
||||||
let intid =
|
let intid =
|
||||||
@ -31,37 +33,43 @@ extern "C" fn irq_current(_elr: u64, _spsr: u64) {
|
|||||||
info!("IRQ {intid:?}");
|
info!("IRQ {intid:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
|
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
|
||||||
error!("fiq_current");
|
error!("fiq_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
|
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
|
||||||
error!("serr_current");
|
error!("serr_current");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("sync_lower");
|
error!("sync_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("irq_lower");
|
error!("irq_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("fiq_lower");
|
error!("fiq_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
|
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
|
||||||
error!("serr_lower");
|
error!("serr_lower");
|
||||||
system_off::<Hvc>().unwrap();
|
system_off::<Hvc>().unwrap();
|
||||||
|
@ -50,7 +50,8 @@ const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
|
|||||||
const PL031_IRQ: IntId = IntId::spi(2);
|
const PL031_IRQ: IntId = IntId::spi(2);
|
||||||
|
|
||||||
// ANCHOR: main
|
// ANCHOR: main
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
// SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
|
||||||
// nothing else accesses that address range.
|
// nothing else accesses that address range.
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
use core::ptr::{addr_of, addr_of_mut};
|
|
||||||
|
|
||||||
// ANCHOR: Flags
|
// ANCHOR: Flags
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
@ -126,7 +125,7 @@ impl Uart {
|
|||||||
// of a PL011 device which is appropriately mapped.
|
// of a PL011 device which is appropriately mapped.
|
||||||
unsafe {
|
unsafe {
|
||||||
// Write to the TX buffer.
|
// Write to the TX buffer.
|
||||||
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
|
(&raw mut (*self.registers).dr).write_volatile(byte.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until the UART is no longer busy.
|
// Wait until the UART is no longer busy.
|
||||||
@ -141,7 +140,7 @@ impl Uart {
|
|||||||
} else {
|
} else {
|
||||||
// SAFETY: We know that self.registers points to the control
|
// SAFETY: We know that self.registers points to the control
|
||||||
// registers of a PL011 device which is appropriately mapped.
|
// registers of a PL011 device which is appropriately mapped.
|
||||||
let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
|
let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
|
||||||
// TODO: Check for error conditions in bits 8-11.
|
// TODO: Check for error conditions in bits 8-11.
|
||||||
Some(data as u8)
|
Some(data as u8)
|
||||||
}
|
}
|
||||||
@ -150,7 +149,7 @@ impl Uart {
|
|||||||
fn read_flag_register(&self) -> Flags {
|
fn read_flag_register(&self) -> Flags {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL011 device which is appropriately mapped.
|
// of a PL011 device which is appropriately mapped.
|
||||||
unsafe { addr_of!((*self.registers).fr).read_volatile() }
|
unsafe { (&raw const (*self.registers).fr).read_volatile() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ANCHOR_END: Uart
|
// ANCHOR_END: Uart
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// ANCHOR: solution
|
// ANCHOR: solution
|
||||||
use core::ptr::{addr_of, addr_of_mut};
|
|
||||||
|
|
||||||
#[repr(C, align(4))]
|
#[repr(C, align(4))]
|
||||||
struct Registers {
|
struct Registers {
|
||||||
/// Data register
|
/// Data register
|
||||||
@ -63,7 +61,7 @@ impl Rtc {
|
|||||||
pub fn read(&self) -> u32 {
|
pub fn read(&self) -> u32 {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL031 device which is appropriately mapped.
|
// of a PL031 device which is appropriately mapped.
|
||||||
unsafe { addr_of!((*self.registers).dr).read_volatile() }
|
unsafe { (&raw const (*self.registers).dr).read_volatile() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a match value. When the RTC value matches this then an interrupt
|
/// Writes a match value. When the RTC value matches this then an interrupt
|
||||||
@ -71,7 +69,7 @@ impl Rtc {
|
|||||||
pub fn set_match(&mut self, value: u32) {
|
pub fn set_match(&mut self, value: u32) {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL031 device which is appropriately mapped.
|
// of a PL031 device which is appropriately mapped.
|
||||||
unsafe { addr_of_mut!((*self.registers).mr).write_volatile(value) }
|
unsafe { (&raw mut (*self.registers).mr).write_volatile(value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the match register matches the RTC value, whether or not
|
/// Returns whether the match register matches the RTC value, whether or not
|
||||||
@ -79,7 +77,7 @@ impl Rtc {
|
|||||||
pub fn matched(&self) -> bool {
|
pub fn matched(&self) -> bool {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL031 device which is appropriately mapped.
|
// of a PL031 device which is appropriately mapped.
|
||||||
let ris = unsafe { addr_of!((*self.registers).ris).read_volatile() };
|
let ris = unsafe { (&raw const (*self.registers).ris).read_volatile() };
|
||||||
(ris & 0x01) != 0
|
(ris & 0x01) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +88,7 @@ impl Rtc {
|
|||||||
pub fn interrupt_pending(&self) -> bool {
|
pub fn interrupt_pending(&self) -> bool {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL031 device which is appropriately mapped.
|
// of a PL031 device which is appropriately mapped.
|
||||||
let ris = unsafe { addr_of!((*self.registers).mis).read_volatile() };
|
let ris = unsafe { (&raw const (*self.registers).mis).read_volatile() };
|
||||||
(ris & 0x01) != 0
|
(ris & 0x01) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,14 +100,14 @@ impl Rtc {
|
|||||||
let imsc = if mask { 0x01 } else { 0x00 };
|
let imsc = if mask { 0x01 } else { 0x00 };
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL031 device which is appropriately mapped.
|
// of a PL031 device which is appropriately mapped.
|
||||||
unsafe { addr_of_mut!((*self.registers).imsc).write_volatile(imsc) }
|
unsafe { (&raw mut (*self.registers).imsc).write_volatile(imsc) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears a pending interrupt, if any.
|
/// Clears a pending interrupt, if any.
|
||||||
pub fn clear_interrupt(&mut self) {
|
pub fn clear_interrupt(&mut self) {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
// SAFETY: We know that self.registers points to the control registers
|
||||||
// of a PL031 device which is appropriately mapped.
|
// of a PL031 device which is appropriately mapped.
|
||||||
unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) }
|
unsafe { (&raw mut (*self.registers).icr).write_volatile(0x01) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ In your Chromium build, add a new Rust target to `//ui/base/BUILD.gn`
|
|||||||
containing:
|
containing:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[no_mangle]
|
// SAFETY: There is no other global function of this name.
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn hello_from_rust() {
|
pub extern "C" fn hello_from_rust() {
|
||||||
println!("Hello from Rust!")
|
println!("Hello from Rust!")
|
||||||
}
|
}
|
||||||
@ -32,7 +33,7 @@ subsequent exercises. If you've succeeded, you will be able to use right-click
|
|||||||
## Where to find help
|
## Where to find help
|
||||||
|
|
||||||
- The options available to the [`rust_static_library` gn template][0]
|
- The options available to the [`rust_static_library` gn template][0]
|
||||||
- Information about [`#[no_mangle]`][1]
|
- Information about [`#[unsafe(no_mangle)]`][1]
|
||||||
- Information about [`extern "C"`][2]
|
- Information about [`extern "C"`][2]
|
||||||
- Information about gn's [`--export-rust-project`][3] switch
|
- Information about gn's [`--export-rust-project`][3] switch
|
||||||
- [How to install rust-analyzer in VSCode][4]
|
- [How to install rust-analyzer in VSCode][4]
|
||||||
@ -45,9 +46,9 @@ This example is unusual because it boils down to the lowest-common-denominator
|
|||||||
interop language, C. Both C++ and Rust can natively declare and call C ABI
|
interop language, C. Both C++ and Rust can natively declare and call C ABI
|
||||||
functions. Later in the course, we'll connect C++ directly to Rust.
|
functions. Later in the course, we'll connect C++ directly to Rust.
|
||||||
|
|
||||||
`allow_unsafe = true` is required here because `#[no_mangle]` might allow Rust
|
`allow_unsafe = true` is required here because `#[unsafe(no_mangle)]` might
|
||||||
to generate two functions with the same name, and Rust can no longer guarantee
|
allow Rust to generate two functions with the same name, and Rust can no longer
|
||||||
that the right one is called.
|
guarantee that the right one is called.
|
||||||
|
|
||||||
If you need a pure Rust executable, you can also do that using the
|
If you need a pure Rust executable, you can also do that using the
|
||||||
`rust_executable` gn template.
|
`rust_executable` gn template.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
specifies a single function, to be called from C++, called `hello_from_rust`,
|
specifies a single function, to be called from C++, called `hello_from_rust`,
|
||||||
taking no parameters and returning no value.
|
taking no parameters and returning no value.
|
||||||
- Modify your previous `hello_from_rust` function to remove `extern "C"` and
|
- Modify your previous `hello_from_rust` function to remove `extern "C"` and
|
||||||
`#[no_mangle]`. This is now just a standard Rust function.
|
`#[unsafe(no_mangle)]`. This is now just a standard Rust function.
|
||||||
- Modify your `gn` target to build these bindings.
|
- Modify your `gn` target to build these bindings.
|
||||||
- In your C++ code, remove the forward-declaration of `hello_from_rust`.
|
- In your C++ code, remove the forward-declaration of `hello_from_rust`.
|
||||||
Instead, include the generated header file.
|
Instead, include the generated header file.
|
||||||
|
@ -10,7 +10,7 @@ Creating pointers is safe, but dereferencing them requires `unsafe`:
|
|||||||
fn main() {
|
fn main() {
|
||||||
let mut s = String::from("careful!");
|
let mut s = String::from("careful!");
|
||||||
|
|
||||||
let r1 = &mut s as *mut String;
|
let r1 = &raw mut s;
|
||||||
let r2 = r1 as *const String;
|
let r2 = r1 as *const String;
|
||||||
|
|
||||||
// SAFETY: r1 and r2 were obtained from references and so are guaranteed to
|
// SAFETY: r1 and r2 were obtained from references and so are guaranteed to
|
||||||
|
@ -51,11 +51,11 @@ mod ffi {
|
|||||||
pub d_name: [c_char; 1024],
|
pub d_name: [c_char; 1024],
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
unsafe extern "C" {
|
||||||
pub fn opendir(s: *const c_char) -> *mut DIR;
|
pub unsafe fn opendir(s: *const c_char) -> *mut DIR;
|
||||||
|
|
||||||
#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
|
#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
|
||||||
pub fn readdir(s: *mut DIR) -> *const dirent;
|
pub unsafe fn readdir(s: *mut DIR) -> *const dirent;
|
||||||
|
|
||||||
// See https://github.com/rust-lang/libc/issues/414 and the section on
|
// See https://github.com/rust-lang/libc/issues/414 and the section on
|
||||||
// _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).
|
// _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).
|
||||||
@ -64,9 +64,9 @@ mod ffi {
|
|||||||
// to macOS (as opposed to iOS / wearOS / etc.) on Intel and PowerPC.
|
// to macOS (as opposed to iOS / wearOS / etc.) on Intel and PowerPC.
|
||||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||||
#[link_name = "readdir$INODE64"]
|
#[link_name = "readdir$INODE64"]
|
||||||
pub fn readdir(s: *mut DIR) -> *const dirent;
|
pub unsafe fn readdir(s: *mut DIR) -> *const dirent;
|
||||||
|
|
||||||
pub fn closedir(s: *mut DIR) -> c_int;
|
pub unsafe fn closedir(s: *mut DIR) -> c_int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user