Skip to content

Commit 3a6246b

Browse files
committed
rust: Add allocator support
Create a config `CONFIG_RUST_ALLOC` that will hook Rust's allocation system into the `malloc`/`free` allocator provided on Zephyr. This will allow the `alloc` crate in rust to be used. Signed-off-by: David Brown <[email protected]>
1 parent 7725e34 commit 3a6246b

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,16 @@ config RUST
1919
help
2020
This option enables the use of applications written in Rust.
2121

22+
if RUST
23+
24+
config RUST_ALLOC
25+
bool "Support an allocator in Rust code"
26+
help
27+
If enabled, the Rust zephyr support library will include support for
28+
an allocator. This allocator will use the currently configured
29+
Zephyr allocator (malloc/free). This this enabled, Rust
30+
applications can use the `alloc` crate.
31+
32+
endif # RUST
33+
2234
endmenu

zephyr/src/alloc_impl.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! A Rust global allocator that uses the stdlib allocator in Zephyr
2+
//!
3+
//! The zephyr runtime is divided into three crates:
4+
//! - [core](https://doc.rust-lang.org/stable/core/) is the the "dependency-free" foundation of the
5+
//! standard library. It is all of the parts of the standard library that have no dependencies
6+
//! outside of the language and the architecture itself.
7+
//! - [alloc](https://doc.rust-lang.org/stable/alloc/) provides the parts of the standard library
8+
//! that depend on memory allocation. This includes various types of smart pointers, atomically
9+
//! referenced counted pointers, and various collections. This depends on the platform providing
10+
//! an allocator.
11+
//! - [std](https://doc.rust-lang.org/stable/std/) is the rest of the standard library. It include
12+
//! both core and alloc, and then everthing else, including filesystem access, networking, etc. It
13+
//! is notable, however, that the Rust standard library is fairly minimal. A lot of functionality
14+
//! that other languages might include will be relegated to other crates, and the ecosystem and
15+
//! tooling around cargo make it as easy to use these as the standard library.
16+
//!
17+
//! For running application code on Zephyr, the core library (mostly) just works (the a caveat of a
18+
//! little work needed to use atomics on platforms Zephyr supports but don't have atomic
19+
//! instructions). The std library is somewhat explicitly _not_ supported. Although the intent is
20+
//! to provide much of the functionality from std, Zephyr is different enough from the conventional
21+
//! operating system std was built around that just porting it doesn't really give practical
22+
//! results. The result is either to complicated to make work, or too different from what is
23+
//! typically done on Zephyr. Supporting std could be a future project.
24+
//!
25+
//! This leaves alloc, which is mostly independent but is required to know about an allocator to
26+
//! use. This module provides an allocator for Rust that uses the underlying memory allocator
27+
//! configured into Zephyr.
28+
//!
29+
//! Because a given embedded application may or may not want memory allocation, this is controlled
30+
//! by the `CONFIG_RUST_ALLOC` Kconfig. When this config is enabled, the alloc crate becomes
31+
//! available to applications.
32+
//!
33+
//! Since alloc is typically used on Rust as a part of the std library, building in a no-std
34+
//! environment requires that it be access explicitly. Generally, alloc must be explicitly added
35+
//! to every module that needs it.
36+
//!
37+
//! ```
38+
//! extern crate alloc;
39+
//!
40+
//! use alloc::boxed::Box;
41+
//!
42+
//! let item = Box::new(5);
43+
//! printkln!("box value {}", item);
44+
//! ```
45+
//!
46+
//! The box holding the value 5 will be allocated by `Box::new`, and freed when the `item` goes out
47+
//! of scope.
48+
49+
// This entire module is only used if CONFIG_RUST_ALLOC is enabled.
50+
extern crate alloc;
51+
52+
use core::alloc::{GlobalAlloc, Layout};
53+
54+
use alloc::alloc::handle_alloc_error;
55+
56+
/// Define size_t, as it isn't defined within the FFI.
57+
#[allow(non_camel_case_types)]
58+
type c_size_t = usize;
59+
60+
extern "C" {
61+
fn malloc(size: c_size_t) -> *mut u8;
62+
fn free(ptr: *mut u8);
63+
}
64+
65+
/// An allocator that uses Zephyr's allocation primitives.
66+
///
67+
/// This is exported for documentation purposes, this module does contain an instance of the
68+
/// allocator as well.
69+
pub struct ZephyrAllocator;
70+
71+
unsafe impl GlobalAlloc for ZephyrAllocator {
72+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
73+
let size = layout.size();
74+
let align = layout.align();
75+
76+
// The C allocation library assumes an alignment of 8. For now, just panic if this cannot
77+
// be satistifed.
78+
if align > 8 {
79+
handle_alloc_error(layout);
80+
}
81+
82+
malloc(size)
83+
}
84+
85+
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
86+
free(ptr)
87+
}
88+
}
89+
90+
/// The global allocator built around the Zephyr malloc/free.
91+
#[global_allocator]
92+
pub static ZEPHYR_ALLOCATOR: ZephyrAllocator = ZephyrAllocator;

zephyr/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,8 @@ pub mod raw {
129129
pub mod _export {
130130
pub use core::format_args;
131131
}
132+
133+
// Mark this as `pub` so the docs can be read.
134+
// If allocation has been requested, provide the allocator.
135+
#[cfg(CONFIG_RUST_ALLOC)]
136+
pub mod alloc_impl;

0 commit comments

Comments
 (0)