Move the esp-alloc package into the repository (#1449)

This commit is contained in:
Jesse Braham 2024-04-16 15:11:05 +00:00 committed by GitHub
parent 2a750dfedc
commit 3c2dccd51c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 258 additions and 2 deletions

View File

@ -2,6 +2,7 @@
resolver = "2"
members = ["xtask"]
exclude = [
"esp-alloc",
"esp-build",
"esp-hal",
"esp-hal-procmacros",

View File

@ -56,7 +56,6 @@ There are a number of other crates within the [esp-rs organization] which can be
| Crate | Description |
| :--------------: | :----------------------------------------------------------------------------: |
| [esp-alloc] | A simple `no_std` heap allocator |
| [esp-backtrace] | Backtrace support for bare-metal applications |
| [esp-ieee802154] | Low-level IEEE802.15.4 driver for the ESP32-C6 and ESP32-H2 |
| [esp-openthread] | A bare-metal Thread implementation using `esp-ieee802154` |

29
esp-alloc/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
name = "esp-alloc"
version = "0.3.0"
edition = "2021"
rust-version = "1.68"
description = "A heap allocator for Espressif devices"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"
keywords = [
"allocator",
"esp32",
"riscv",
"xtensa",
]
categories = [
"memory-management",
"no-std",
]
[package.metadata.docs.rs]
default-target = "riscv32imc-unknown-none-elf"
[dependencies]
critical-section = "1.1.1"
linked_list_allocator = { version = "0.10.5", default-features = false, features = ["const_mut_refs"] }
[features]
nightly = []

26
esp-alloc/README.md Normal file
View File

@ -0,0 +1,26 @@
# esp-alloc
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/esp-rs/esp-alloc/ci.yml?label=CI&logo=github&style=flat-square)
[![Crates.io](https://img.shields.io/crates/v/esp-alloc?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-alloc)
[![docs.rs](https://img.shields.io/docsrs/esp-alloc?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-alloc)
![MSRV](https://img.shields.io/badge/MSRV-1.68-blue?style=flat-square)
![Crates.io](https://img.shields.io/crates/l/esp-alloc?style=flat-square)
A simple `no_std` heap allocator for RISC-V and Xtensa processors from Espressif. Supports all currently available ESP32 devices.
**NOTE:** using this as your global allocator requires using Rust 1.68 or greater, or the `nightly` release channel.
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
any additional terms or conditions.

160
esp-alloc/src/lib.rs Normal file
View File

@ -0,0 +1,160 @@
//! A simple `no_std` heap allocator for RISC-V and Xtensa processors from
//! Espressif. Supports all currently available ESP32 devices.
//!
//! **NOTE:** using this as your global allocator requires using Rust 1.68 or
//! greater, or the `nightly` release channel.
//!
//! # Using this as your Global Allocator
//! To use EspHeap as your global allocator, you need at least Rust 1.68 or
//! nightly.
//!
//! ```rust
//! #[global_allocator]
//! static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
//!
//! fn init_heap() {
//! const HEAP_SIZE: usize = 32 * 1024;
//! static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
//!
//! unsafe {
//! ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, HEAP_SIZE);
//! }
//! }
//! ```
//!
//! # Using this with the nightly `allocator_api`-feature
//! Sometimes you want to have single allocations in PSRAM, instead of an esp's
//! DRAM. For that, it's convenient to use the nightly `allocator_api`-feature,
//! which allows you to specify an allocator for single allocations.
//!
//! **NOTE:** To use this, you have to enable the create's `nightly` feature
//! flag.
//!
//! Create and initialize an allocator to use in single allocations:
//! ```rust
//! static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
//!
//! fn init_psram_heap() {
//! unsafe {
//! PSRAM_ALLOCATOR.init(psram::psram_vaddr_start() as *mut u8, psram::PSRAM_BYTES);
//! }
//! }
//! ```
//!
//! And then use it in an allocation:
//! ```rust
//! let large_buffer: Vec<u8, _> = Vec::with_capacity_in(1048576, &PSRAM_ALLOCATOR);
//! ```
#![no_std]
#![cfg_attr(feature = "nightly", feature(allocator_api))]
pub mod macros;
#[cfg(feature = "nightly")]
use core::alloc::{AllocError, Allocator};
use core::{
alloc::{GlobalAlloc, Layout},
cell::RefCell,
ptr::{self, NonNull},
};
use critical_section::Mutex;
use linked_list_allocator::Heap;
pub struct EspHeap {
heap: Mutex<RefCell<Heap>>,
}
impl EspHeap {
/// Crate a new UNINITIALIZED heap allocator
///
/// You must initialize this heap using the
/// [`init`](struct.EspHeap.html#method.init) method before using the
/// allocator.
pub const fn empty() -> EspHeap {
EspHeap {
heap: Mutex::new(RefCell::new(Heap::empty())),
}
}
/// Initializes the heap
///
/// This function must be called BEFORE you run any code that makes use of
/// the allocator.
///
/// `heap_bottom` is a pointer to the location of the bottom of the heap.
///
/// `size` is the size of the heap in bytes.
///
/// Note that:
///
/// - The heap grows "upwards", towards larger addresses. Thus `end_addr`
/// must be larger than `start_addr`
///
/// - The size of the heap is `(end_addr as usize) - (start_addr as usize)`.
/// The allocator won't use the byte at `end_addr`.
///
/// # Safety
///
/// Obey these or Bad Stuff will happen.
///
/// - This function must be called exactly ONCE.
/// - `size > 0`
pub unsafe fn init(&self, heap_bottom: *mut u8, size: usize) {
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().init(heap_bottom, size));
}
/// Returns an estimate of the amount of bytes in use.
pub fn used(&self) -> usize {
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().used())
}
/// Returns an estimate of the amount of bytes available.
pub fn free(&self) -> usize {
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().free())
}
}
unsafe impl GlobalAlloc for EspHeap {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
critical_section::with(|cs| {
self.heap
.borrow(cs)
.borrow_mut()
.allocate_first_fit(layout)
.ok()
.map_or(ptr::null_mut(), |allocation| allocation.as_ptr())
})
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
critical_section::with(|cs| {
self.heap
.borrow(cs)
.borrow_mut()
.deallocate(NonNull::new_unchecked(ptr), layout)
});
}
}
#[cfg(feature = "nightly")]
unsafe impl Allocator for EspHeap {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
critical_section::with(|cs| {
let raw_ptr = self
.heap
.borrow(cs)
.borrow_mut()
.allocate_first_fit(layout)
.map_err(|_| AllocError)?
.as_ptr();
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
})
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
self.dealloc(ptr.as_ptr(), layout);
}
}

41
esp-alloc/src/macros.rs Normal file
View File

@ -0,0 +1,41 @@
//! Macros provided for convenience
/// Create a heap allocator providing a heap of the given size in bytes
///
/// You can only have ONE allocator at most
#[macro_export]
macro_rules! heap_allocator {
($size:expr) => {{
#[global_allocator]
static ALLOCATOR: $crate::EspHeap = $crate::EspHeap::empty();
static mut HEAP: core::mem::MaybeUninit<[u8; $size]> = core::mem::MaybeUninit::uninit();
unsafe {
ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, $size);
}
}};
}
/// Create a heap allocator backed by PSRAM
///
/// You can only have ONE allocator at most. You need a SoC which supports PSRAM
/// and activate the feature to enable it. You need to pass the PSRAM peripheral
/// and the psram module path.
///
/// # Usage
/// ```no_run
/// esp_alloc::psram_allocator!(peripherals.PSRAM, hal::psram);
/// ```
#[macro_export]
macro_rules! psram_allocator {
($peripheral:expr,$psram_module:path) => {{
#[global_allocator]
static ALLOCATOR: $crate::EspHeap = $crate::EspHeap::empty();
use $psram_module as _psram;
_psram::init_psram($peripheral);
unsafe {
ALLOCATOR.init(_psram::psram_vaddr_start() as *mut u8, _psram::PSRAM_BYTES);
}
}};
}

View File

@ -22,7 +22,7 @@ embedded-hal-async = "1.0.0"
embedded-hal-bus = "0.1.0"
embedded-io-async = "0.6.1"
embedded-can = "0.4.1"
esp-alloc = "0.3.0"
esp-alloc = { version = "0.3.0", path = "../esp-alloc" }
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
esp-hal = { version = "0.16.0", path = "../esp-hal", features = ["log"] }
esp-hal-smartled = { version = "0.9.0", path = "../esp-hal-smartled", optional = true }