|
| 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; |
0 commit comments