diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 6feab57bd80..b604f4f83c7 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Support for `rand_core` 0.9 (#3211) +- `ESP_HAL_CONFIG_STACK_GUARD_OFFSET` and `ESP_HAL_CONFIG_STACK_GUARD_VALUE` to configure Rust's [Stack smashing protection](https://doc.rust-lang.org/rustc/exploit-mitigations.html#stack-smashing-protection) (#3203) ### Changed @@ -21,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Detecting a UART overflow now clears the RX FIFO. (#3190) - ESP32-S2: Fixed PSRAM initialization (#3196) - ESP32: Fixed SPI3 QSPI signals (#3201) +- ESP32-C6/H2: The `flip_link` feature should no longer crash (#3203) ### Removed diff --git a/esp-hal/build.rs b/esp-hal/build.rs index 2ff56888566..6abb749c6de 100644 --- a/esp-hal/build.rs +++ b/esp-hal/build.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashMap, env, error::Error, fs::{self, File}, @@ -122,6 +123,19 @@ fn main() -> Result<(), Box> { Some(Validator::Enumeration( vec![String::from("quad"), String::from("octal")] )), + ), + // Rust's stack smashing protection configuration + ( + "stack-guard-offset", + "The stack guard variable will be placed this many bytes from the stack's end.", + Value::Integer(4096), + None + ), + ( + "stack-guard-value", + "The value to be written to the stack guard variable.", + Value::Integer(0xDEED_BAAD), + None ) ], true); @@ -166,10 +180,21 @@ fn main() -> Result<(), Box> { } else { // RISC-V devices: - preprocess_file(&config_symbols, "ld/riscv/asserts.x", out.join("asserts.x"))?; - preprocess_file(&config_symbols, "ld/riscv/debug.x", out.join("debug.x"))?; preprocess_file( &config_symbols, + &cfg, + "ld/riscv/asserts.x", + out.join("asserts.x"), + )?; + preprocess_file( + &config_symbols, + &cfg, + "ld/riscv/debug.x", + out.join("debug.x"), + )?; + preprocess_file( + &config_symbols, + &cfg, "ld/riscv/hal-defaults.x", out.join("hal-defaults.x"), )?; @@ -177,8 +202,8 @@ fn main() -> Result<(), Box> { // With the architecture-specific linker scripts taken care of, we can copy all // remaining linker scripts which are common to all devices: - copy_dir_all(&config_symbols, "ld/sections", &out)?; - copy_dir_all(&config_symbols, format!("ld/{device_name}"), &out)?; + copy_dir_all(&config_symbols, &cfg, "ld/sections", &out)?; + copy_dir_all(&config_symbols, &cfg, format!("ld/{device_name}"), &out)?; Ok(()) } @@ -188,6 +213,7 @@ fn main() -> Result<(), Box> { fn copy_dir_all( config_symbols: &[&str], + cfg: &HashMap, src: impl AsRef, dst: impl AsRef, ) -> std::io::Result<()> { @@ -198,12 +224,14 @@ fn copy_dir_all( if ty.is_dir() { copy_dir_all( config_symbols, + cfg, entry.path(), dst.as_ref().join(entry.file_name()), )?; } else { preprocess_file( config_symbols, + cfg, entry.path(), dst.as_ref().join(entry.file_name()), )?; @@ -215,9 +243,12 @@ fn copy_dir_all( /// A naive pre-processor for linker scripts fn preprocess_file( config: &[&str], + cfg: &HashMap, src: impl AsRef, dst: impl AsRef, ) -> std::io::Result<()> { + println!("cargo:rerun-if-changed={}", src.as_ref().display()); + let file = File::open(src)?; let mut out_file = File::create(dst)?; @@ -225,7 +256,7 @@ fn preprocess_file( take.push(true); for line in std::io::BufReader::new(file).lines() { - let line = line?; + let line = substitute_config(cfg, &line?); let trimmed = line.trim(); if let Some(condition) = trimmed.strip_prefix("#IF ") { @@ -252,6 +283,43 @@ fn preprocess_file( Ok(()) } +fn substitute_config(cfg: &HashMap, line: &str) -> String { + let mut result = String::new(); + let mut chars = line.chars().peekable(); + + while let Some(c) = chars.next() { + if c != '$' { + result.push(c); + continue; + } + + let Some('{') = chars.peek() else { + result.push(c); + continue; + }; + chars.next(); + + let mut key = String::new(); + for c in chars.by_ref() { + if c == '}' { + break; + } + key.push(c); + } + match cfg + .get(&key) + .unwrap_or_else(|| panic!("missing config key: {key}")) + { + Value::Bool(true) => result.push('1'), + Value::Bool(false) => result.push('0'), + Value::Integer(value) => result.push_str(&value.to_string()), + Value::String(value) => result.push_str(value), + } + } + + result +} + #[cfg(feature = "esp32")] fn generate_memory_extras() -> Vec { let reserve_dram = if cfg!(feature = "bluetooth") { diff --git a/esp-hal/ld/esp32/esp32.x b/esp-hal/ld/esp32/esp32.x index a61c7579408..cd20b332c68 100644 --- a/esp-hal/ld/esp32/esp32.x +++ b/esp-hal/ld/esp32/esp32.x @@ -19,9 +19,11 @@ INCLUDE "fixups/rtc_fast_rwdata_dummy.x" /* END ESP32 fixups */ /* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +SECTIONS { + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" +} INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "rtc_fast.x" INCLUDE "rtc_slow.x" diff --git a/esp-hal/ld/esp32c2/esp32c2.x b/esp-hal/ld/esp32c2/esp32c2.x index 76225573343..ab0e041ed17 100644 --- a/esp-hal/ld/esp32c2/esp32c2.x +++ b/esp-hal/ld/esp32c2/esp32c2.x @@ -80,9 +80,11 @@ PROVIDE(__global_pointer$ = _data_start + 0x800); /* end of esp32c2 fixups */ /* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +SECTIONS { + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" +} INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "stack.x" INCLUDE "dram2.x" diff --git a/esp-hal/ld/esp32c3/esp32c3.x b/esp-hal/ld/esp32c3/esp32c3.x index 4ed604f92a0..51fe0dfde10 100644 --- a/esp-hal/ld/esp32c3/esp32c3.x +++ b/esp-hal/ld/esp32c3/esp32c3.x @@ -80,9 +80,11 @@ PROVIDE(__global_pointer$ = _data_start + 0x800); /* end of esp32c3 fixups */ /* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +SECTIONS { + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" +} INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "rtc_fast.x" INCLUDE "stack.x" diff --git a/esp-hal/ld/esp32c6/esp32c6.x b/esp-hal/ld/esp32c6/esp32c6.x index ac3ea162d7e..abb1e11d269 100644 --- a/esp-hal/ld/esp32c6/esp32c6.x +++ b/esp-hal/ld/esp32c6/esp32c6.x @@ -55,8 +55,17 @@ SECTIONS { KEEP(*(.trap)); *(.trap.*); } > RWTEXT + + /* Shared sections - ordering matters */ + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" + /* End of Shared sections */ } -INSERT BEFORE .rwtext; +#IF ESP_HAL_CONFIG_FLIP_LINK +/* INSERT BEFORE does not seem to work for the .stack section. Instead, we place every RAM + section after .stack if `flip_link` is enabled. */ +INSERT AFTER .stack; +#ENDIF SECTIONS { /** @@ -71,15 +80,13 @@ SECTIONS { INSERT BEFORE .rodata; /* end of esp32c6 fixups */ -/* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +/* Shared sections #2 - ordering matters */ INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "rtc_fast.x" INCLUDE "stack.x" INCLUDE "dram2.x" -/* End of Shared sections */ +/* End of Shared sections #2 */ INCLUDE "debug.x" diff --git a/esp-hal/ld/esp32h2/esp32h2.x b/esp-hal/ld/esp32h2/esp32h2.x index d4ce0dbe33b..b00b8514586 100644 --- a/esp-hal/ld/esp32h2/esp32h2.x +++ b/esp-hal/ld/esp32h2/esp32h2.x @@ -43,14 +43,24 @@ PROVIDE(_start_trap = default_start_trap); /* Must be called __global_pointer$ for linker relaxations to work. */ PROVIDE(__global_pointer$ = _data_start + 0x800); + SECTIONS { .trap : ALIGN(4) { KEEP(*(.trap)); *(.trap.*); } > RWTEXT + + /* Shared sections - ordering matters */ + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" + /* End of Shared sections */ } -INSERT BEFORE .rwtext; +#IF ESP_HAL_CONFIG_FLIP_LINK +/* INSERT BEFORE does not seem to work for the .stack section. Instead, we place every RAM + section after .stack if `flip_link` is enabled. */ +INSERT AFTER .stack; +#ENDIF SECTIONS { /** @@ -64,15 +74,13 @@ SECTIONS { } INSERT BEFORE .rodata; -/* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +/* Shared sections #2 - ordering matters */ INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "rtc_fast.x" INCLUDE "stack.x" INCLUDE "dram2.x" -/* End of Shared sections */ +/* End of Shared sections #2 */ INCLUDE "debug.x" diff --git a/esp-hal/ld/esp32s2/esp32s2.x b/esp-hal/ld/esp32s2/esp32s2.x index 83869824ab6..4b0a7f6d24a 100644 --- a/esp-hal/ld/esp32s2/esp32s2.x +++ b/esp-hal/ld/esp32s2/esp32s2.x @@ -27,9 +27,11 @@ INCLUDE "fixups/rtc_fast_rwdata_dummy.x" /* End of fixups for esp32s2 */ /* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +SECTIONS { + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" +} INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "rtc_fast.x" INCLUDE "rtc_slow.x" diff --git a/esp-hal/ld/esp32s3/esp32s3.x b/esp-hal/ld/esp32s3/esp32s3.x index a9f130ee005..108a7ce655b 100644 --- a/esp-hal/ld/esp32s3/esp32s3.x +++ b/esp-hal/ld/esp32s3/esp32s3.x @@ -41,9 +41,11 @@ INCLUDE "fixups/rodata_dummy.x" /* End of ESP32S3 fixups */ /* Shared sections - ordering matters */ -INCLUDE "rwtext.x" +SECTIONS { + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" +} INCLUDE "text.x" -INCLUDE "rwdata.x" INCLUDE "rodata.x" INCLUDE "rtc_fast.x" INCLUDE "rtc_slow.x" diff --git a/esp-hal/ld/sections/rwdata.x b/esp-hal/ld/sections/rwdata.x index f6accabeede..1655a9fd3f7 100644 --- a/esp-hal/ld/sections/rwdata.x +++ b/esp-hal/ld/sections/rwdata.x @@ -1,63 +1,59 @@ - - -SECTIONS { - .data : ALIGN(4) - { - _data_start = ABSOLUTE(.); - . = ALIGN (4); - - #IF ESP_HAL_CONFIG_PLACE_SWITCH_TABLES_IN_RAM - *(.rodata.*_esp_hal_internal_handler*) - *(.rodata..Lswitch.table.*) - *(.rodata.cst*) - #ENDIF - - #IF ESP_HAL_CONFIG_PLACE_ANON_IN_RAM - *(.rodata..Lanon .rodata..Lanon.*) - #ENDIF - - *(.sdata .sdata.* .sdata2 .sdata2.*); - *(.data .data.*); - *(.data1) - _data_end = ABSOLUTE(.); - . = ALIGN(4); - } > RWDATA AT > RODATA - - /* LMA of .data */ - _sidata = LOADADDR(.data); - - .bss (NOLOAD) : ALIGN(4) - { - _bss_start = ABSOLUTE(.); - . = ALIGN (4); - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - *(.dynbss) - *(.sbss .sbss.* .bss .bss.*); - *(.share.mem) - *(.gnu.linkonce.b.*) - *(COMMON) - _bss_end = ABSOLUTE(.); - . = ALIGN(4); - } > RWDATA - - .noinit (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - *(.noinit .noinit.*) - . = ALIGN(4); - } > RWDATA - - .data.wifi : - { - . = ALIGN(4); - *( .dram1 .dram1.*) - . = ALIGN(4); - } > RWDATA AT > RODATA -} \ No newline at end of file +.data : ALIGN(4) +{ + _data_start = ABSOLUTE(.); + . = ALIGN (4); + + #IF ESP_HAL_CONFIG_PLACE_SWITCH_TABLES_IN_RAM + *(.rodata.*_esp_hal_internal_handler*) + *(.rodata..Lswitch.table.*) + *(.rodata.cst*) + #ENDIF + + #IF ESP_HAL_CONFIG_PLACE_ANON_IN_RAM + *(.rodata..Lanon .rodata..Lanon.*) + #ENDIF + + *(.sdata .sdata.* .sdata2 .sdata2.*); + *(.data .data.*); + *(.data1) + _data_end = ABSOLUTE(.); + . = ALIGN(4); +} > RWDATA AT > RODATA + +/* LMA of .data */ +_sidata = LOADADDR(.data); + +.bss (NOLOAD) : ALIGN(4) +{ + _bss_start = ABSOLUTE(.); + . = ALIGN (4); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.sbss .sbss.* .bss .bss.*); + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + _bss_end = ABSOLUTE(.); + . = ALIGN(4); +} > RWDATA + +.noinit (NOLOAD) : ALIGN(4) +{ + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); +} > RWDATA + +.data.wifi : +{ + . = ALIGN(4); + *( .dram1 .dram1.*) + . = ALIGN(4); +} > RWDATA AT > RODATA diff --git a/esp-hal/ld/sections/rwtext.x b/esp-hal/ld/sections/rwtext.x index aca9385b5b0..e1dbf589cf5 100644 --- a/esp-hal/ld/sections/rwtext.x +++ b/esp-hal/ld/sections/rwtext.x @@ -1,22 +1,20 @@ -SECTIONS { - .rwtext : ALIGN(4) - { - . = ALIGN (4); - *(.rwtext.literal .rwtext .rwtext.literal.* .rwtext.*) - . = ALIGN(4); - } > RWTEXT +.rwtext : ALIGN(4) +{ + . = ALIGN (4); + *(.rwtext.literal .rwtext .rwtext.literal.* .rwtext.*) + . = ALIGN(4); +} > RWTEXT - .rwtext.wifi : - { - . = ALIGN(4); - *( .wifi0iram .wifi0iram.*) - *( .wifirxiram .wifirxiram.*) - *( .wifislprxiram .wifislprxiram.*) - *( .wifislpiram .wifislpiram.*) - *( .phyiram .phyiram.*) - *( .iram1 .iram1.*) - *( .wifiextrairam.* ) - *( .coexiram.* ) - . = ALIGN(4); - } > RWTEXT AT > RODATA -} \ No newline at end of file +.rwtext.wifi : +{ + . = ALIGN(4); + *( .wifi0iram .wifi0iram.*) + *( .wifirxiram .wifirxiram.*) + *( .wifislprxiram .wifislprxiram.*) + *( .wifislpiram .wifislpiram.*) + *( .phyiram .phyiram.*) + *( .iram1 .iram1.*) + *( .wifiextrairam.* ) + *( .coexiram.* ) + . = ALIGN(4); +} > RWTEXT AT > RODATA diff --git a/esp-hal/ld/sections/stack.x b/esp-hal/ld/sections/stack.x index cfb3695c7a0..90050968dde 100644 --- a/esp-hal/ld/sections/stack.x +++ b/esp-hal/ld/sections/stack.x @@ -1,5 +1,3 @@ -#IF ESP_HAL_CONFIG_FLIP_LINK -/* no Xtensa chip is supported - so we can assume RISC-V */ SECTIONS { /* must be last segment using RWDATA */ .stack (NOLOAD) : ALIGN(4) @@ -7,37 +5,19 @@ SECTIONS { _stack_end = ABSOLUTE(.); _stack_end_cpu0 = ABSOLUTE(.); + /* The stack_guard for `stack-protector` mitigation - https://doc.rust-lang.org/rustc/exploit-mitigations.html#stack-smashing-protection */ + __stack_chk_guard = _stack_end + ${ESP_HAL_CONFIG_STACK_GUARD_OFFSET}; + +/* no Xtensa chip is supported - so we can assume RISC-V */ +#IF ESP_HAL_CONFIG_FLIP_LINK /* Since we cannot know how much the alignment padding of the sections will add we shrink the stack for "the worst case" */ . = . + LENGTH(RWDATA) - (SIZEOF(.trap) + SIZEOF(.rwtext) + SIZEOF(.rwtext.wifi) + SIZEOF(.data) + SIZEOF(.bss) + SIZEOF(.noinit) + SIZEOF(.data.wifi)) - 304; - +#ELSE + . = ORIGIN(RWDATA) + LENGTH(RWDATA); +#ENDIF . = ALIGN (4); _stack_start = ABSOLUTE(.); _stack_start_cpu0 = ABSOLUTE(.); } > RWDATA } -INSERT BEFORE .trap; - -#ELSE - -SECTIONS { - /* must be last segment using RWDATA */ - .stack (NOLOAD) : ALIGN(4) - { - . = ALIGN (4); - _stack_end = ABSOLUTE(.); - _stack_end_cpu0 = ABSOLUTE(.); - } > RWDATA -} - -PROVIDE(_stack_start = ORIGIN(RWDATA) + LENGTH(RWDATA)); -PROVIDE(_stack_start_cpu0 = ORIGIN(RWDATA) + LENGTH(RWDATA)); - -#ENDIF - -/* -Provide the stack_guard for `stack-protector` - -Ideally the offset should be configurable - should be done once we have https://github.com/esp-rs/esp-hal/issues/1111 -*/ -PROVIDE(__stack_chk_guard = _stack_end + 4096); diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 86700aa5810..0b1e02c93dc 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -418,7 +418,10 @@ fn hal_main(a0: usize, a1: usize, a2: usize) -> ! { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); // we _should_ use a random value but we don't have a good source for random // numbers here - stack_chk_guard.write_volatile(0xdeadbabe); + stack_chk_guard.write_volatile(esp_config::esp_config_int!( + u32, + "ESP_HAL_CONFIG_STACK_GUARD_VALUE" + )); main(a0, a1, a2); } diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 535e0f6384e..89f590f5ab1 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -114,7 +114,10 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); // we _should_ use a random value but we don't have a good source for random // numbers here - stack_chk_guard.write_volatile(0xdeadbabe); + stack_chk_guard.write_volatile(esp_config::esp_config_int!( + u32, + "ESP_HAL_CONFIG_STACK_GUARD_VALUE" + )); } crate::interrupt::setup_interrupts(); diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index 812645df24a..d9ac0097298 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -118,7 +118,10 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); // we _should_ use a random value but we don't have a good source for random // numbers here - stack_chk_guard.write_volatile(0xdeadbabe); + stack_chk_guard.write_volatile(esp_config::esp_config_int!( + u32, + "ESP_HAL_CONFIG_STACK_GUARD_VALUE" + )); } crate::interrupt::setup_interrupts(); diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index 8f602661e40..598b03cf8bb 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -157,7 +157,10 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); // we _should_ use a random value but we don't have a good source for random // numbers here - stack_chk_guard.write_volatile(0xdeadbabe); + stack_chk_guard.write_volatile(esp_config::esp_config_int!( + u32, + "ESP_HAL_CONFIG_STACK_GUARD_VALUE" + )); } crate::interrupt::setup_interrupts(); diff --git a/hil-test/.cargo/config.toml b/hil-test/.cargo/config.toml index 685528829db..7a54a18e524 100644 --- a/hil-test/.cargo/config.toml +++ b/hil-test/.cargo/config.toml @@ -1,9 +1,9 @@ [target.'cfg(target_arch = "riscv32")'] runner = "probe-rs run --preverify" rustflags = [ - "-C", "link-arg=-Tlinkall.x", "-C", "link-arg=-Tembedded-test.x", "-C", "link-arg=-Tdefmt.x", + "-C", "link-arg=-Tlinkall.x", "-C", "force-frame-pointers" ] @@ -11,9 +11,9 @@ rustflags = [ runner = "probe-rs run --preverify" rustflags = [ "-C", "link-arg=-nostartfiles", - "-C", "link-arg=-Wl,-Tlinkall.x", - "-C", "link-arg=-Tdefmt.x", "-C", "link-arg=-Tembedded-test.x", + "-C", "link-arg=-Tdefmt.x", + "-C", "link-arg=-Wl,-Tlinkall.x", ] [env] diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 6e4a843ff34..92ad00ae3df 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -56,6 +56,10 @@ harness = false name = "get_time" harness = false +[[test]] +name = "flip_link" +harness = false + [[test]] name = "gpio" harness = false diff --git a/hil-test/tests/flip_link.rs b/hil-test/tests/flip_link.rs new file mode 100644 index 00000000000..58a715c55f7 --- /dev/null +++ b/hil-test/tests/flip_link.rs @@ -0,0 +1,20 @@ +//! Tests flip_link + +//% CHIPS: esp32c6 esp32h2 +//% ENV: ESP_HAL_CONFIG_FLIP_LINK = true + +#![no_std] +#![no_main] + +use hil_test as _; + +#[cfg(test)] +#[embedded_test::tests(default_timeout = 3)] +mod tests { + #[test] + fn test() { + let _p = esp_hal::init(Default::default()); + defmt::info!("Hello, world!"); + defmt::assert_eq!(1 + 1, 2); + } +}