mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00
Backtrace tweaks (#4012)
* Disallow multiple halt methods * Warn for nonsense config * Use DRAM range from metadata
This commit is contained in:
parent
af1956d477
commit
55d8228987
@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- `exception-handler` now panics. (#3838)
|
- `exception-handler` now panics. (#3838)
|
||||||
- Only halt cores in panics when `halt-cores` feature is enabled. (#4010)
|
- Only halt cores in panics when `halt-cores` feature is enabled. (#4010)
|
||||||
|
- It is no longer possible to select multiple halt method features (`halt-cores`, `custom-halt`, `semihosting`) (#4012)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ cfg-if = "1.0.0"
|
|||||||
critical-section = "1.1.2"
|
critical-section = "1.1.2"
|
||||||
defmt = { version = "1", optional = true }
|
defmt = { version = "1", optional = true }
|
||||||
esp-config = { version = "0.5.0", path = "../esp-config" }
|
esp-config = { version = "0.5.0", path = "../esp-config" }
|
||||||
|
esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated" }
|
||||||
esp-println = { version = "0.15.0", optional = true, default-features = false, path = "../esp-println" }
|
esp-println = { version = "0.15.0", optional = true, default-features = false, path = "../esp-println" }
|
||||||
heapless = "0.8"
|
heapless = "0.8"
|
||||||
semihosting = { version = "0.1.20", optional = true }
|
semihosting = { version = "0.1.20", optional = true }
|
||||||
@ -34,13 +35,13 @@ esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"]
|
|||||||
[features]
|
[features]
|
||||||
default = ["colors"]
|
default = ["colors"]
|
||||||
|
|
||||||
esp32 = ["esp-println?/esp32", "semihosting?/openocd-semihosting", "print-float-registers"]
|
esp32 = ["esp-println?/esp32", "esp-metadata-generated/esp32", "semihosting?/openocd-semihosting", "print-float-registers"]
|
||||||
esp32c2 = ["esp-println?/esp32c2"]
|
esp32c2 = ["esp-println?/esp32c2", "esp-metadata-generated/esp32c2"]
|
||||||
esp32c3 = ["esp-println?/esp32c3"]
|
esp32c3 = ["esp-println?/esp32c3", "esp-metadata-generated/esp32c3"]
|
||||||
esp32c6 = ["esp-println?/esp32c6"]
|
esp32c6 = ["esp-println?/esp32c6", "esp-metadata-generated/esp32c6"]
|
||||||
esp32h2 = ["esp-println?/esp32h2"]
|
esp32h2 = ["esp-println?/esp32h2", "esp-metadata-generated/esp32h2"]
|
||||||
esp32s2 = ["esp-println?/esp32s2", "semihosting?/openocd-semihosting"]
|
esp32s2 = ["esp-println?/esp32s2", "esp-metadata-generated/esp32s2", "semihosting?/openocd-semihosting"]
|
||||||
esp32s3 = ["esp-println?/esp32s3", "semihosting?/openocd-semihosting", "print-float-registers"]
|
esp32s3 = ["esp-println?/esp32s3", "esp-metadata-generated/esp32s3", "semihosting?/openocd-semihosting", "print-float-registers"]
|
||||||
|
|
||||||
## Use `esp-println`
|
## Use `esp-println`
|
||||||
println = ["dep:esp-println"]
|
println = ["dep:esp-println"]
|
||||||
@ -60,6 +61,8 @@ custom-halt = []
|
|||||||
custom-pre-backtrace = []
|
custom-pre-backtrace = []
|
||||||
## Halt both CPUs on ESP32 / ESP32-S3 instead of doing a `loop {}` in case of a panic
|
## Halt both CPUs on ESP32 / ESP32-S3 instead of doing a `loop {}` in case of a panic
|
||||||
halt-cores = []
|
halt-cores = []
|
||||||
|
## Exit with a semihosting call in case of a panic
|
||||||
|
semihosting = ["dep:semihosting"]
|
||||||
## Include a panic handler
|
## Include a panic handler
|
||||||
panic-handler = []
|
panic-handler = []
|
||||||
|
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
use esp_config::generate_config_from_yaml_definition;
|
use esp_config::generate_config_from_yaml_definition;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_unique_features {
|
||||||
|
($($feature:literal),+ $(,)?) => {
|
||||||
|
assert!(
|
||||||
|
(0 $(+ cfg!(feature = $feature) as usize)+ ) <= 1,
|
||||||
|
"At most one of the following features must be enabled: {}",
|
||||||
|
[$($feature),+].join(", ")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_unique_used_features {
|
macro_rules! assert_unique_used_features {
|
||||||
($($feature:literal),+ $(,)?) => {
|
($($feature:literal),+ $(,)?) => {
|
||||||
@ -15,8 +26,17 @@ fn main() {
|
|||||||
// Ensure that exactly a backend is selected:
|
// Ensure that exactly a backend is selected:
|
||||||
assert_unique_used_features!("defmt", "println");
|
assert_unique_used_features!("defmt", "println");
|
||||||
|
|
||||||
if cfg!(feature = "custom-halt") && cfg!(feature = "halt-cores") {
|
// Ensure that there aren't multiple halt methods selected:
|
||||||
panic!("Only one of `custom-halt` and `halt-cores` can be enabled");
|
assert_unique_features!("custom-halt", "halt-cores", "semihosting");
|
||||||
|
|
||||||
|
if !cfg!(feature = "panic-handler")
|
||||||
|
&& cfg!(any(
|
||||||
|
feature = "custom-halt",
|
||||||
|
feature = "halt-cores",
|
||||||
|
feature = "semihosting"
|
||||||
|
))
|
||||||
|
{
|
||||||
|
print_warning("A halt method is selected, but esp-backtrace is not the panic handler.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit config
|
// emit config
|
||||||
@ -25,3 +45,7 @@ fn main() {
|
|||||||
.expect("Failed to read esp_config.yml for esp-backtrace");
|
.expect("Failed to read esp_config.yml for esp-backtrace");
|
||||||
generate_config_from_yaml_definition(&cfg_yaml, true, true, None).unwrap();
|
generate_config_from_yaml_definition(&cfg_yaml, true, true, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_warning(message: impl core::fmt::Display) {
|
||||||
|
println!("cargo:warning={message}");
|
||||||
|
}
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
|
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate esp_metadata_generated;
|
||||||
|
|
||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
use defmt as _;
|
use defmt as _;
|
||||||
#[cfg(feature = "println")]
|
#[cfg(feature = "println")]
|
||||||
@ -120,101 +123,48 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the address is in DRAM and that it is 16-byte aligned.
|
// Ensure that the address is in DRAM.
|
||||||
//
|
//
|
||||||
// Based loosely on the `esp_stack_ptr_in_dram` function from
|
// Address ranges can be found in `esp-metadata/devices/$CHIP.toml` in the `device` table.
|
||||||
// `components/esp_hw_support/include/esp_memory_utils.h` in ESP-IDF.
|
|
||||||
//
|
|
||||||
// Address ranges can be found in `components/soc/$CHIP/include/soc/soc.h` as
|
|
||||||
// `SOC_DRAM_LOW` and `SOC_DRAM_HIGH`.
|
|
||||||
fn is_valid_ram_address(address: u32) -> bool {
|
fn is_valid_ram_address(address: u32) -> bool {
|
||||||
if (address & 0xF) != 0 {
|
memory_range!("DRAM").contains(&address)
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32")]
|
|
||||||
if !(0x3FFA_E000..=0x4000_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32c2")]
|
|
||||||
if !(0x3FCA_0000..=0x3FCE_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32c3")]
|
|
||||||
if !(0x3FC8_0000..=0x3FCE_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32c6")]
|
|
||||||
if !(0x4080_0000..=0x4088_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32h2")]
|
|
||||||
if !(0x4080_0000..=0x4085_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32s2")]
|
|
||||||
if !(0x3FFB_0000..=0x4000_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32s3")]
|
|
||||||
if !(0x3FC8_8000..=0x3FD0_0000).contains(&address) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "halt-cores")]
|
#[cfg(feature = "halt-cores")]
|
||||||
fn halt() -> ! {
|
fn halt() {
|
||||||
cfg_if::cfg_if! {
|
#[cfg(any(feature = "esp32", feature = "esp32s3"))]
|
||||||
if #[cfg(feature = "custom-halt")] {
|
{
|
||||||
// call custom code
|
#[cfg(feature = "esp32")]
|
||||||
unsafe extern "Rust" {
|
mod registers {
|
||||||
fn custom_halt() -> !;
|
pub(crate) const OPTIONS0: u32 = 0x3ff48000;
|
||||||
}
|
pub(crate) const SW_CPU_STALL: u32 = 0x3ff480ac;
|
||||||
unsafe { custom_halt() }
|
}
|
||||||
} else if #[cfg(any(feature = "esp32", feature = "esp32s3"))] {
|
|
||||||
// multi-core
|
|
||||||
#[cfg(feature = "esp32")]
|
|
||||||
mod registers {
|
|
||||||
pub(crate) const OPTIONS0: u32 = 0x3ff48000;
|
|
||||||
pub(crate) const SW_CPU_STALL: u32 = 0x3ff480ac;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "esp32s3")]
|
#[cfg(feature = "esp32s3")]
|
||||||
mod registers {
|
mod registers {
|
||||||
pub(crate) const OPTIONS0: u32 = 0x60008000;
|
pub(crate) const OPTIONS0: u32 = 0x60008000;
|
||||||
pub(crate) const SW_CPU_STALL: u32 = 0x600080bc;
|
pub(crate) const SW_CPU_STALL: u32 = 0x600080bc;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sw_cpu_stall = registers::SW_CPU_STALL as *mut u32;
|
let sw_cpu_stall = registers::SW_CPU_STALL as *mut u32;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// We need to write the value "0x86" to stall a particular core. The write
|
// We need to write the value "0x86" to stall a particular core. The write
|
||||||
// location is split into two separate bit fields named "c0" and "c1", and the
|
// location is split into two separate bit fields named "c0" and "c1", and the
|
||||||
// two fields are located in different registers. Each core has its own pair of
|
// two fields are located in different registers. Each core has its own pair of
|
||||||
// "c0" and "c1" bit fields.
|
// "c0" and "c1" bit fields.
|
||||||
|
|
||||||
let options0 = registers::OPTIONS0 as *mut u32;
|
let options0 = registers::OPTIONS0 as *mut u32;
|
||||||
|
|
||||||
options0.write_volatile(options0.read_volatile() & !(0b1111) | 0b1010);
|
options0.write_volatile(options0.read_volatile() & !(0b1111) | 0b1010);
|
||||||
|
|
||||||
sw_cpu_stall.write_volatile(
|
sw_cpu_stall.write_volatile(
|
||||||
sw_cpu_stall.read_volatile() & !(0b111111 << 20) & !(0b111111 << 26)
|
sw_cpu_stall.read_volatile() & !(0b111111 << 20) & !(0b111111 << 26)
|
||||||
| (0x21 << 20)
|
| (0x21 << 20)
|
||||||
| (0x21 << 26),
|
| (0x21 << 26),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "panic-handler")]
|
#[cfg(feature = "panic-handler")]
|
||||||
@ -236,13 +186,20 @@ fn abort() -> ! {
|
|||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(feature = "semihosting")] {
|
if #[cfg(feature = "semihosting")] {
|
||||||
semihosting::process::abort();
|
critical_section::with(|_| {
|
||||||
|
semihosting::process::abort();
|
||||||
|
});
|
||||||
} else if #[cfg(feature = "halt-cores")] {
|
} else if #[cfg(feature = "halt-cores")] {
|
||||||
halt();
|
halt();
|
||||||
} else {
|
} else if #[cfg(feature = "custom-halt")] {
|
||||||
critical_section::with(|_| {
|
// call custom code
|
||||||
loop {}
|
unsafe extern "Rust" {
|
||||||
})
|
fn custom_halt() -> !;
|
||||||
|
}
|
||||||
|
unsafe { custom_halt() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
critical_section::with(|_| loop {})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user