From 2f2ac22910102b56b6d773ca938f79a63ad6aa81 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Mon, 26 Jan 2026 17:43:27 +0800 Subject: [PATCH 01/53] minor --- kernel/src/boards/seeed_xiao_esp32c3/link.x | 18 ++++++++++++++++++ kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 13 +++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 kernel/src/boards/seeed_xiao_esp32c3/link.x create mode 100644 kernel/src/boards/seeed_xiao_esp32c3/mod.rs diff --git a/kernel/src/boards/seeed_xiao_esp32c3/link.x b/kernel/src/boards/seeed_xiao_esp32c3/link.x new file mode 100644 index 00000000..d8e0e38a --- /dev/null +++ b/kernel/src/boards/seeed_xiao_esp32c3/link.x @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 vivo Mobile Communication Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +OUTPUT_ARCH("riscv") +ENTRY(_start) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs new file mode 100644 index 00000000..f6b61c6d --- /dev/null +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -0,0 +1,13 @@ +// Copyright (c) 2025 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. From a4a5726ef6861d09ebe377a0d4ae9e16840ba2b2 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 27 Jan 2026 16:02:05 +0800 Subject: [PATCH 02/53] minor --- kconfig/config/seeed_xiao_esp32c3/Kconfig | 0 .../config/seeed_xiao_esp32c3/debug/defconfig | 34 +++++ kernel/src/boards/seeed_xiao_esp32c3/Kconfig | 20 +++ .../src/boards/seeed_xiao_esp32c3/config.rs | 22 ++++ kernel/src/boards/seeed_xiao_esp32c3/link.x | 98 ++++++++++++--- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 118 ++++++++++++++++++ 6 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 kconfig/config/seeed_xiao_esp32c3/Kconfig create mode 100644 kconfig/config/seeed_xiao_esp32c3/debug/defconfig create mode 100644 kernel/src/boards/seeed_xiao_esp32c3/Kconfig create mode 100644 kernel/src/boards/seeed_xiao_esp32c3/config.rs diff --git a/kconfig/config/seeed_xiao_esp32c3/Kconfig b/kconfig/config/seeed_xiao_esp32c3/Kconfig new file mode 100644 index 00000000..e69de29b diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig new file mode 100644 index 00000000..f8df3ade --- /dev/null +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -0,0 +1,34 @@ +# CONFIG_IRQ_PRIORITY_BITS_3 is not set +CONFIG_IRQ_PRIORITY_BITS_2=y +CONFIG_ALIGN_SIZE=8 +CONFIG_TICKS_PER_SECOND=100 +CONFIG_SMP=n +CONFIG_NUM_CORES=1 +CONFIG_ALLOCATOR_TLSF=y +CONFIG_ALLOCATOR="tlsf" +CONFIG_USE_KERNEL_BOOT=y +# +# Kernel Core Features +# +CONFIG_SOFT_TIMER=y +CONFIG_EVENT_FLAGS=y +CONFIG_ROBIN_SCHEDULER=y +CONFIG_ROBIN_SLICE=10 +CONFIG_OVERFLOW_CHECK=y +CONFIG_STACK_HIGHWATER_CHECK=y +CONFIG_MAIN_THREAD_STACK_SIZE=12288 +CONFIG_IDLE_THREAD_STACK_SIZE=2048 +CONFIG_TIMER_THREAD_STACK_SIZE=2048 +CONFIG_THREAD_PRIORITY=y +CONFIG_THREAD_PRIORITY_32=y +CONFIG_THREAD_PRIORITY_MAX=32 +CONFIG_MAIN_THREAD_PRIORITY=32 + +CONFIG_ENABLE_SYSCALL=y +# CONFIG_FDT is not set +# CONFIG_VIRTIO is not set +CONFIG_SERIAL_RX_FIFO_SIZE=256 +CONFIG_SERIAL_TX_FIFO_SIZE=256 +CONFIG_ENABLE_VFS=n +CONFIG_ENABLE_NET=n +CONFIG_PROCFS=n diff --git a/kernel/src/boards/seeed_xiao_esp32c3/Kconfig b/kernel/src/boards/seeed_xiao_esp32c3/Kconfig new file mode 100644 index 00000000..d0870647 --- /dev/null +++ b/kernel/src/boards/seeed_xiao_esp32c3/Kconfig @@ -0,0 +1,20 @@ +# Soc specific configuration +# cortex-m +choice + prompt "The cortex-m irq priority bits" + default IRQ_PRIORITY_BITS_2 + help + Choose between 2, 3 or 8 for the cortex-m irq priority bits. + config IRQ_PRIORITY_BITS_2 + bool "2" + help + Set irq priority bits to 2. + config IRQ_PRIORITY_BITS_3 + bool "3" + help + Set irq priority bits to 3. + config IRQ_PRIORITY_BITS_8 + bool "8" + help + Set irq priority bits to 8. +endchoice diff --git a/kernel/src/boards/seeed_xiao_esp32c3/config.rs b/kernel/src/boards/seeed_xiao_esp32c3/config.rs new file mode 100644 index 00000000..c6d963af --- /dev/null +++ b/kernel/src/boards/seeed_xiao_esp32c3/config.rs @@ -0,0 +1,22 @@ +// Copyright (c) 2025 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::arch::irq::IrqNumber; + +pub const PLIC_BASE: usize = 0x0c00_0000; + +pub const UART0: u32 = 0x1000_0000; +pub const UART0_IRQ: IrqNumber = IrqNumber::new(10); diff --git a/kernel/src/boards/seeed_xiao_esp32c3/link.x b/kernel/src/boards/seeed_xiao_esp32c3/link.x index d8e0e38a..72d23e01 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/link.x +++ b/kernel/src/boards/seeed_xiao_esp32c3/link.x @@ -1,18 +1,88 @@ -/* - * Copyright (c) 2025 vivo Mobile Communication Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* This code is derived from + * https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/link.lds + * Copyright (c) 2024 - present Microsoft Corporation + * SPDX-License-Identifier: MIT */ OUTPUT_ARCH("riscv") ENTRY(_start) + +SECTIONS +{ + /* + * ensure that entry.S / _entry is at 0x80000000, + * where qemu's -kernel jumps. + */ + . = 0x80000000; + + /* Ignore build information, like .hash, .gnu.hash and etc. */ + + .text : { + . = ALIGN(16); + *(.text._start) + *(.text .text.*) + . = ALIGN(0x1000); + PROVIDE(etext = .); + } + + .rodata : { + . = ALIGN(16); + *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */ + . = ALIGN(16); + *(.rodata .rodata.*) + } + + .data : { + . = ALIGN(16); + PROVIDE(__global_pointer$ = . + 0x800); + *(.sdata .sdata.*) /* do not need to distinguish this from .data */ + . = ALIGN(16); + *(.data .data.*) + } + + .bss : { + . = ALIGN(16); + __bss_start = .; + *(.sbss .sbss.*) /* do not need to distinguish this from .bss */ + . = ALIGN(16); + *(.bss .bss.*) + __bss_end = .; + } + + /* Initialize C runtime. */ + /* .ctors and .dtors should not appear since we don't have C++ code at present. */ + .init_array : { + . = ALIGN(16); + PROVIDE_HIDDEN(__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN(__init_array_end = .); + } + + .bk_app_array : { + . = ALIGN(16); + PROVIDE_HIDDEN(__bk_app_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.bk_app_array.*))) + KEEP (*(.bk_app_array)) + PROVIDE_HIDDEN(__bk_app_array_end = .); + } + + .heap : { + . = ALIGN(4096); + __heap_start = .; + . += 0x800000; + __heap_end = .; + } + + /* Ignore .fini_array since we are building a kernel which has no chance to + * execute code in .fini_array. */ + + .stack : { + . = ALIGN(16); + __sys_stack_start = .; + . += 0x80000; + __sys_stack_end = .; + } + + PROVIDE(_end = .); +} diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index f6b61c6d..f92aa26b 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -11,3 +11,121 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +// This code is based on +// https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/hwtimer.c +// https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/trap.c +// https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/uart.c +// Copyright (c) 2024 - present Microsoft Corporation +// SPDX-License-Identifier: MIT + +mod config; +use crate::{ + arch, + arch::riscv::{local_irq_enabled, trap_entry, Context}, + drivers::ic::plic::Plic, + scheduler, + support::SmpStagedInit, + time, +}; +use core::sync::atomic::Ordering; +pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); + +const CLOCK_ADDR: usize = 0x0200_0000; +const CLOCK_TIME: usize = CLOCK_ADDR + 0xBFF8; +const NUM_TICKS_PER_SECOND: usize = 10_000_000; +const NUM_TICKS_PER_TIMER: usize = NUM_TICKS_PER_SECOND / 10; +const NS_PER_TICK: usize = 1_000_000_000 / NUM_TICKS_PER_SECOND; + +#[inline] +fn clock_timecmp_ptr(hart: usize) -> *mut usize { + unsafe { (CLOCK_ADDR + 0x4000 + 8 * hart) as *mut usize } +} + +#[inline] +pub fn current_ticks() -> usize { + unsafe { (CLOCK_TIME as *const usize).read_volatile() } +} + +#[inline] +pub fn current_cycles() -> usize { + let x: usize; + unsafe { + core::arch::asm!("csrr {}, cycle", + out(reg) x, + options(nostack, nomem)) + } + x +} + +fn set_timecmp(tick: usize) { + let hart = arch::current_cpu_id(); + unsafe { clock_timecmp_ptr(hart).write_volatile(tick) }; +} + +#[inline] +fn init_vector_table() { + unsafe { + core::arch::asm!( + "la {x}, {entry}", + "csrw mtvec, {x}", + x = out(reg) _, + entry = sym trap_entry, + options(nostack), + ); + } +} + +pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { + let cpu_id = arch::current_cpu_id(); + PLIC.complete(cpu_id, PLIC.claim(cpu_id)) +} + +pub(crate) fn set_timeout_after(ns: usize) { + set_timecmp(current_ticks() + ns / NS_PER_TICK); +} + +pub(crate) fn ticks_to_duration(ticks: usize) -> core::time::Duration { + core::time::Duration::from_nanos((ticks * NS_PER_TICK) as u64) +} + +pub(crate) fn current_duration() -> core::time::Duration { + ticks_to_duration(current_ticks()) +} + +static STAGING: SmpStagedInit = SmpStagedInit::new(); + +pub(crate) fn init() { + assert!(!local_irq_enabled()); + STAGING.run(0, true, crate::boot::init_runtime); + STAGING.run(1, true, crate::boot::init_heap); + STAGING.run(2, false, init_vector_table); + STAGING.run(3, true, || { + time::systick_init(1_000_000_000); + }); + STAGING.run(4, false, time::reset_systick); + // From now on, all work will be done by core 0. + if arch::current_cpu_id() != 0 { + scheduler::wait_and_then_start_schedule(); + unreachable!("Secondary cores should have jumped to the scheduler"); + } + // Enable UART0 in PLIC. + PLIC.enable( + arch::current_cpu_id(), + u32::try_from(usize::from(config::UART0_IRQ)) + .expect("usize(64 bits) converts to u32 failed"), + ); + // Set UART0 priority in PLIC. + PLIC.set_priority( + u32::try_from(usize::from(config::UART0_IRQ)) + .expect("usize(64 bits) converts to u32 failed"), + 1, + ); +} + +crate::define_peripheral! { + (console_uart, blueos_driver::uart::dumb::DumbUart, + blueos_driver::uart::dumb::DumbUart), +} + +crate::define_pin_states!(None); From 229657dc62701d70e602611ece52bbde1281d388 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 30 Jan 2026 15:43:50 +0800 Subject: [PATCH 03/53] minor --- .../src/boards/seeed_xiao_esp32c3/config.rs | 71 +++++++++ kernel/src/boards/seeed_xiao_esp32c3/link.x | 137 +++++++++++------- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 7 +- 3 files changed, 161 insertions(+), 54 deletions(-) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/config.rs b/kernel/src/boards/seeed_xiao_esp32c3/config.rs index c6d963af..4cf0c1ea 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/config.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/config.rs @@ -20,3 +20,74 @@ pub const PLIC_BASE: usize = 0x0c00_0000; pub const UART0: u32 = 0x1000_0000; pub const UART0_IRQ: IrqNumber = IrqNumber::new(10); + +/// ESP-IDF compatible application descriptor +/// +/// This gets populated by the [esp_app_desc] macro. +#[repr(C)] +pub struct EspAppDesc { + /// Magic word ESP_APP_DESC_MAGIC_WORD + magic_word: u32, + /// Secure version + secure_version: u32, + /// Reserved + reserv1: [u32; 2], + /// Application version + version: [core::ffi::c_char; 32], + /// Project name + project_name: [core::ffi::c_char; 32], + /// Compile time + time: [core::ffi::c_char; 16], + /// Compile date + date: [core::ffi::c_char; 16], + /// Version IDF + idf_ver: [core::ffi::c_char; 32], + /// sha256 of elf file + app_elf_sha256: [u8; 32], + /// Minimal eFuse block revision supported by image, in format: major * 100 + /// + minor + min_efuse_blk_rev_full: u16, + /// Maximal eFuse block revision supported by image, in format: major * 100 + /// + minor + max_efuse_blk_rev_full: u16, + /// MMU page size in log base 2 format + mmu_page_size: u8, + /// Reserved + reserv3: [u8; 3], + /// Reserved + reserv2: [u32; 18], +} + +#[unsafe(export_name = "esp_app_desc")] +#[unsafe(link_section = ".rodata_desc.appdesc")] +/// Application metadata descriptor. +pub static ESP_APP_DESC: EspAppDesc = EspAppDesc { + magic_word: 0xABCD_5432, + secure_version: 0, + reserv1: [0; 2], + version: str_to_cstr_array("0.1.0"), + project_name: str_to_cstr_array("blueoskernel"), + time: str_to_cstr_array("none"), + date: str_to_cstr_array("none"), + idf_ver: str_to_cstr_array("none"), + app_elf_sha256: [0; 32], + min_efuse_blk_rev_full: 0, + max_efuse_blk_rev_full: 0xffff, + mmu_page_size: 0x10, + reserv3: [0; 3], + reserv2: [0; 18], +}; + +const fn str_to_cstr_array(s: &str) -> [::core::ffi::c_char; C] { + let bytes = s.as_bytes(); + let mut ret: [::core::ffi::c_char; C] = [0; C]; + let mut i = 0; + loop { + ret[i] = bytes[i] as _; + i += 1; + if i >= bytes.len() || i >= C { + break; + } + } + ret +} diff --git a/kernel/src/boards/seeed_xiao_esp32c3/link.x b/kernel/src/boards/seeed_xiao_esp32c3/link.x index 72d23e01..92e9af72 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/link.x +++ b/kernel/src/boards/seeed_xiao_esp32c3/link.x @@ -7,82 +7,119 @@ OUTPUT_ARCH("riscv") ENTRY(_start) -SECTIONS -{ - /* - * ensure that entry.S / _entry is at 0x80000000, - * where qemu's -kernel jumps. - */ - . = 0x80000000; +MEMORY { + /* External flash - /* Ignore build information, like .hash, .gnu.hash and etc. */ + The 0x20 offset is a convenience for the app binary image generation. + Flash cache has 64KB pages. The .bin file which is flashed to the chip + has a 0x18 byte file header, and each segment has a 0x08 byte segment + header. Setting this offset makes it simple to meet the flash cache MMU's + constraint that (paddr % 64KB == vaddr % 64KB).) + */ - .text : { - . = ALIGN(16); - *(.text._start) - *(.text .text.*) - . = ALIGN(0x1000); - PROVIDE(etext = .); - } + /* Instruction ROM */ + IROM : ORIGIN = 0x42000000 + 0x20, LENGTH = 0x400000 - 0x20 + /* Data ROM */ + DROM : ORIGIN = 0x3C000000 + 0x20, LENGTH = 0x400000 - 0x20 + + DRAM : ORIGIN = 0x3FC80000, LENGTH = 384K +} - .rodata : { +SECTIONS +{ + .rodata_desc : ALIGN(4) + { + KEEP(*(.rodata_desc)); + KEEP(*(.rodata_desc.*)); + } > DROM + + .rodata : ALIGN(4) + { . = ALIGN(16); *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */ . = ALIGN(16); *(.rodata .rodata.*) - } + } > DROM - .data : { - . = ALIGN(16); - PROVIDE(__global_pointer$ = . + 0x800); - *(.sdata .sdata.*) /* do not need to distinguish this from .data */ - . = ALIGN(16); - *(.data .data.*) - } - - .bss : { - . = ALIGN(16); - __bss_start = .; - *(.sbss .sbss.*) /* do not need to distinguish this from .bss */ - . = ALIGN(16); - *(.bss .bss.*) - __bss_end = .; - } + .rodata.wifi : ALIGN(4) + { + . = ALIGN(4); + *( .rodata_wlog_*.* ) + . = ALIGN(4); + } > DROM - /* Initialize C runtime. */ - /* .ctors and .dtors should not appear since we don't have C++ code at present. */ .init_array : { - . = ALIGN(16); + . = ALIGN(4); PROVIDE_HIDDEN(__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN(__init_array_end = .); - } + } > DROM .bk_app_array : { - . = ALIGN(16); + . = ALIGN(4); PROVIDE_HIDDEN(__bk_app_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.bk_app_array.*))) KEEP (*(.bk_app_array)) PROVIDE_HIDDEN(__bk_app_array_end = .); - } + } > DROM + + /* Put .bss to RAM */ + .zero.table : + { + . = ALIGN(4); + __zero_table_start = .; + LONG (__bss_start) + LONG ((__bss_end - __bss_start) / 4) + __zero_table_end = .; + } > DROM + + . = ALIGN(0x10000) + 0x20; + .text : ALIGN(4) + { + *(.literal .text .literal.* .text.*) + } > IROM + + .data (COPY) : { + *(.rdata) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE(__global_pointer$ = . + 0x800); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + KEEP(*(.test_data.*)); + } > DRAM + . = ALIGN(4); + PROVIDE(__data_end = .); + + .bss : { + . = ALIGN(4); + __bss_start = .; + *(.sbss .sbss.*) + *(.bss .bss.*) + . = ALIGN(4); + __bss_end = .; + } > DRAM .heap : { - . = ALIGN(4096); + . = ALIGN(8); __heap_start = .; - . += 0x800000; + . = ORIGIN(DRAM) + LENGTH(DRAM) - 0x1000; __heap_end = .; - } - - /* Ignore .fini_array since we are building a kernel which has no chance to - * execute code in .fini_array. */ + } > DRAM .stack : { . = ALIGN(16); __sys_stack_start = .; - . += 0x80000; + . += 0x1000; __sys_stack_end = .; - } - - PROVIDE(_end = .); -} + } > DRAM +} \ No newline at end of file diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index f92aa26b..49ab4108 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -13,9 +13,7 @@ // limitations under the License. // This code is based on -// https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/hwtimer.c -// https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/trap.c -// https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/uart.c +// https://github.com/esp-rs/esp-hal/blob/main/esp-bootloader-esp-idf/src/lib.rs // Copyright (c) 2024 - present Microsoft Corporation // SPDX-License-Identifier: MIT @@ -82,7 +80,7 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { } pub(crate) fn set_timeout_after(ns: usize) { - set_timecmp(current_ticks() + ns / NS_PER_TICK); + set_timecmp(0 + ns / NS_PER_TICK); } pub(crate) fn ticks_to_duration(ticks: usize) -> core::time::Duration { @@ -103,6 +101,7 @@ pub(crate) fn init() { STAGING.run(3, true, || { time::systick_init(1_000_000_000); }); + STAGING.run(4, false, time::reset_systick); // From now on, all work will be done by core 0. if arch::current_cpu_id() != 0 { From 8fdac14ca1abb59268c63e19bf45a360e99ea759 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Mon, 2 Feb 2026 17:14:30 +0800 Subject: [PATCH 04/53] minor --- driver/src/lib.rs | 1 + driver/src/systimer/mod.rs | 13 + driver/src/uart/esp32_uart.rs | 377 ++++++++++++++++++++ driver/src/uart/mod.rs | 2 + kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 83 ++--- 5 files changed, 414 insertions(+), 62 deletions(-) create mode 100644 driver/src/systimer/mod.rs create mode 100644 driver/src/uart/esp32_uart.rs diff --git a/driver/src/lib.rs b/driver/src/lib.rs index 26bc8b02..efccfe75 100644 --- a/driver/src/lib.rs +++ b/driver/src/lib.rs @@ -20,4 +20,5 @@ pub mod i2c; pub mod pinctrl; pub mod reset; pub mod static_ref; +pub mod systimer; pub mod uart; diff --git a/driver/src/systimer/mod.rs b/driver/src/systimer/mod.rs new file mode 100644 index 00000000..64b39d7e --- /dev/null +++ b/driver/src/systimer/mod.rs @@ -0,0 +1,13 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/driver/src/uart/esp32_uart.rs b/driver/src/uart/esp32_uart.rs new file mode 100644 index 00000000..ec414308 --- /dev/null +++ b/driver/src/uart/esp32_uart.rs @@ -0,0 +1,377 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use blueos_hal::{ + uart::Uart, Configuration, Has8bitDataReg, HasFifo, HasInterruptReg, HasLineStatusReg, +}; +use hal_espressif_rs::uart_hal_context_t; + +use crate::uart::{Parity, StopBits}; + +pub struct Esp32Uart { + inner: uart_hal_context_t, +} + +unsafe impl Send for Esp32Uart {} +unsafe impl Sync for Esp32Uart {} + +impl Esp32Uart { + unsafe fn get_inner_ref_mut(&self) -> &mut uart_hal_context_t { + &mut *(core::ptr::addr_of!(self.inner) as *mut uart_hal_context_t) + } + + pub const fn new(base_addr: u32) -> Self { + unsafe { + Esp32Uart { + inner: uart_hal_context_t { + dev: base_addr as *mut _, + }, + } + } + } +} + +impl Configuration for Esp32Uart { + type Target = (); + // This code snippet is modified from + // https://github.com/zephyrproject-rtos/zephyr/blob/4f3478391a3c5e555dcd629f9e829378c17b0d62/drivers/serial/uart_esp32.c#L277-L377 + fn configure(&self, param: &super::UartConfig) -> blueos_hal::err::Result { + let super::UartConfig { + baudrate, + parity, + stop_bits, + data_bits, + flow_ctrl, + } = param; + + unsafe { + hal_espressif_rs::uart_hal_set_sclk( + self.get_inner_ref_mut(), + hal_espressif_rs::soc_periph_uart_clk_src_legacy_t_UART_SCLK_DEFAULT, + ); + hal_espressif_rs::uart_hal_set_txfifo_empty_thr(self.get_inner_ref_mut(), 0x1); + hal_espressif_rs::uart_hal_set_rxfifo_full_thr(self.get_inner_ref_mut(), 0x16); + hal_espressif_rs::uart_hal_rxfifo_rst(self.get_inner_ref_mut()); + hal_espressif_rs::uart_hal_txfifo_rst(self.get_inner_ref_mut()); + } + + match parity { + Parity::None => unsafe { + hal_espressif_rs::uart_hal_set_parity( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_parity_t_UART_PARITY_DISABLE, + ); + }, + Parity::Even => unsafe { + hal_espressif_rs::uart_hal_set_parity( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_parity_t_UART_PARITY_EVEN, + ); + }, + Parity::Odd => unsafe { + hal_espressif_rs::uart_hal_set_parity( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_parity_t_UART_PARITY_ODD, + ); + }, + _ => { + return Err(blueos_hal::err::HalError::InvalidParam); + } + } + + match data_bits { + super::DataBits::DataBits5 => unsafe { + hal_espressif_rs::uart_hal_set_data_bit_num( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_word_length_t_UART_DATA_5_BITS, + ); + }, + super::DataBits::DataBits6 => unsafe { + hal_espressif_rs::uart_hal_set_data_bit_num( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_word_length_t_UART_DATA_6_BITS, + ); + }, + super::DataBits::DataBits7 => unsafe { + hal_espressif_rs::uart_hal_set_data_bit_num( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_word_length_t_UART_DATA_7_BITS, + ); + }, + super::DataBits::DataBits8 => unsafe { + hal_espressif_rs::uart_hal_set_data_bit_num( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_word_length_t_UART_DATA_8_BITS, + ); + }, + _ => { + return Err(blueos_hal::err::HalError::InvalidParam); + } + } + + match stop_bits { + StopBits::DataBits1 => unsafe { + hal_espressif_rs::uart_hal_set_stop_bits( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_stop_bits_t_UART_STOP_BITS_1, + ); + }, + StopBits::DataBits1_5 => unsafe { + hal_espressif_rs::uart_hal_set_stop_bits( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_stop_bits_t_UART_STOP_BITS_1_5, + ); + }, + StopBits::DataBits2 => unsafe { + hal_espressif_rs::uart_hal_set_stop_bits( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_stop_bits_t_UART_STOP_BITS_2, + ); + }, + _ => { + return Err(blueos_hal::err::HalError::InvalidParam); + } + } + + unsafe { + hal_espressif_rs::uart_hal_set_mode( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_mode_t_UART_MODE_UART, + ); + } + + match flow_ctrl { + super::FlowCtrl::None => unsafe { + hal_espressif_rs::uart_hal_set_hw_flow_ctrl( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_DISABLE, + 0, + ); + }, + super::FlowCtrl::RtsCts => unsafe { + hal_espressif_rs::uart_hal_set_hw_flow_ctrl( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_CTS_RTS, + 10, + ); + }, + super::FlowCtrl::Rs485 => unsafe { + hal_espressif_rs::uart_hal_set_mode( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_mode_t_UART_MODE_RS485_HALF_DUPLEX, + ); + }, + _ => { + return Err(blueos_hal::err::HalError::InvalidParam); + } + } + + let src_clk = unsafe { + let mut src_clk: hal_espressif_rs::uart_sclk_t = 0; + hal_espressif_rs::uart_hal_get_sclk(self.get_inner_ref_mut(), &mut src_clk); + if src_clk == 0 { + return Err(blueos_hal::err::HalError::Fail); + } + src_clk + }; + + let sclk_freq = unsafe { + let mut sclk_freq: u32 = 0; + hal_espressif_rs::esp_clk_tree_src_get_freq_hz( + src_clk as hal_espressif_rs::soc_module_clk_t, + hal_espressif_rs::esp_clk_tree_src_freq_precision_t_ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, + core::ptr::addr_of_mut!(sclk_freq), + ); + sclk_freq + }; + unsafe { + hal_espressif_rs::uart_hal_set_baudrate(self.get_inner_ref_mut(), *baudrate, sclk_freq); + hal_espressif_rs::uart_hal_set_rx_timeout(self.get_inner_ref_mut(), 0x16); + } + Ok(()) + } +} + +// impl Uart for Esp32Uart {} + +impl Has8bitDataReg for Esp32Uart { + fn read_data8(&self) -> blueos_hal::err::Result { + let mut len = 1; + let mut p_char = 0u8; + unsafe { + hal_espressif_rs::uart_hal_read_rxfifo( + self.get_inner_ref_mut(), + core::ptr::addr_of_mut!(p_char), + core::ptr::addr_of_mut!(len), + ) + }; + if len == 0 { + return Err(blueos_hal::err::HalError::IoError); + } + Ok(p_char) + } + + fn write_data8(&self, data: u8) { + let mut len = 1; + unsafe { + hal_espressif_rs::uart_hal_write_txfifo( + self.get_inner_ref_mut(), + core::ptr::addr_of!(data), + 1, + core::ptr::addr_of_mut!(len), + ) + }; + } + + fn is_data_ready(&self) -> bool { + unsafe { + hal_espressif_rs::rust_helper_uart_hal_get_rxfifo_len(self.get_inner_ref_mut()) > 0 + } + } +} + +impl HasLineStatusReg for Esp32Uart { + fn is_bus_busy(&self) -> bool { + unsafe { + hal_espressif_rs::rust_helper_uart_hal_get_txfifo_len(self.get_inner_ref_mut()) > 0 + } + } +} + +impl HasFifo for Esp32Uart { + fn enable_fifo(&self, _num: u8) -> blueos_hal::err::Result<()> { + // FIFO is always enabled in ESP32 UART + Ok(()) + } + + fn is_tx_fifo_full(&self) -> bool { + unsafe { + // FIXME + hal_espressif_rs::rust_helper_uart_hal_get_txfifo_len(self.get_inner_ref_mut()) != 0 + } + } + + fn is_rx_fifo_empty(&self) -> bool { + unsafe { + hal_espressif_rs::rust_helper_uart_hal_get_rxfifo_len(self.get_inner_ref_mut()) == 0 + } + } +} + +impl HasInterruptReg for Esp32Uart { + type InterruptType = super::InterruptType; + + fn enable_interrupt(&self, intr: Self::InterruptType) { + match intr { + super::InterruptType::Rx => unsafe { + hal_espressif_rs::rust_helper_uart_clr_intsts_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, + ); + hal_espressif_rs::rust_helper_uart_clr_intsts_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, + ); + hal_espressif_rs::uart_hal_ena_intr_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, + ); + hal_espressif_rs::uart_hal_ena_intr_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, + ); + }, + super::InterruptType::Tx => unsafe { + hal_espressif_rs::rust_helper_uart_clr_intsts_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, + ); + hal_espressif_rs::uart_hal_ena_intr_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, + ); + }, + _ => {} + } + } + + fn disable_interrupt(&self, intr: Self::InterruptType) { + match intr { + super::InterruptType::Rx => unsafe { + hal_espressif_rs::rust_helper_uart_hal_disable_intr_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, + ); + hal_espressif_rs::rust_helper_uart_hal_disable_intr_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, + ); + }, + super::InterruptType::Tx => unsafe { + hal_espressif_rs::rust_helper_uart_hal_disable_intr_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, + ); + }, + _ => {} + } + } + + fn clear_interrupt(&self, intr: Self::InterruptType) { + match intr { + super::InterruptType::Rx => unsafe { + hal_espressif_rs::rust_helper_uart_clr_intsts_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, + ); + hal_espressif_rs::rust_helper_uart_clr_intsts_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, + ); + }, + super::InterruptType::Tx => unsafe { + hal_espressif_rs::rust_helper_uart_clr_intsts_mask( + self.get_inner_ref_mut(), + hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, + ); + }, + _ => unsafe { + let mask = hal_espressif_rs::rust_helper_uart_hal_get_intsts_mask( + self.get_inner_ref_mut(), + ); + hal_espressif_rs::rust_helper_uart_clr_intsts_mask(self.get_inner_ref_mut(), mask); + }, + } + } + + fn get_interrupt(&self) -> Self::InterruptType { + unsafe { + let mask = + hal_espressif_rs::rust_helper_uart_hal_get_intsts_mask(self.get_inner_ref_mut()); + if mask & hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL != 0 { + super::InterruptType::Rx + } else if mask & hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY != 0 { + super::InterruptType::Tx + } else { + super::InterruptType::Unknown + } + } + } + + fn set_interrupt_handler(&self, handler: &'static dyn Fn()) {} + + fn get_irq_nums(&self) -> &[u32] { + &[] + } +} diff --git a/driver/src/uart/mod.rs b/driver/src/uart/mod.rs index 6a7e6b0a..48b87f67 100644 --- a/driver/src/uart/mod.rs +++ b/driver/src/uart/mod.rs @@ -15,6 +15,8 @@ pub mod arm_pl011; pub mod cmsdk; pub mod dumb; +#[cfg(target_chip = "esp32c3")] +pub mod esp32_uart; #[cfg(target_chip = "gd32e5x")] pub mod gd32e5x_uart; #[cfg(target_chip = "gd32vw55x")] diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 49ab4108..d14dbf57 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -28,38 +28,7 @@ use crate::{ }; use core::sync::atomic::Ordering; pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); - -const CLOCK_ADDR: usize = 0x0200_0000; -const CLOCK_TIME: usize = CLOCK_ADDR + 0xBFF8; -const NUM_TICKS_PER_SECOND: usize = 10_000_000; -const NUM_TICKS_PER_TIMER: usize = NUM_TICKS_PER_SECOND / 10; -const NS_PER_TICK: usize = 1_000_000_000 / NUM_TICKS_PER_SECOND; - -#[inline] -fn clock_timecmp_ptr(hart: usize) -> *mut usize { - unsafe { (CLOCK_ADDR + 0x4000 + 8 * hart) as *mut usize } -} - -#[inline] -pub fn current_ticks() -> usize { - unsafe { (CLOCK_TIME as *const usize).read_volatile() } -} - -#[inline] -pub fn current_cycles() -> usize { - let x: usize; - unsafe { - core::arch::asm!("csrr {}, cycle", - out(reg) x, - options(nostack, nomem)) - } - x -} - -fn set_timecmp(tick: usize) { - let hart = arch::current_cpu_id(); - unsafe { clock_timecmp_ptr(hart).write_volatile(tick) }; -} +pub type ClockImpl = crate::devices::clock::riscv_clock::RiscvClock<0x6002_3000, 0x1, 16_000_000>; #[inline] fn init_vector_table() { @@ -79,18 +48,6 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { PLIC.complete(cpu_id, PLIC.claim(cpu_id)) } -pub(crate) fn set_timeout_after(ns: usize) { - set_timecmp(0 + ns / NS_PER_TICK); -} - -pub(crate) fn ticks_to_duration(ticks: usize) -> core::time::Duration { - core::time::Duration::from_nanos((ticks * NS_PER_TICK) as u64) -} - -pub(crate) fn current_duration() -> core::time::Duration { - ticks_to_duration(current_ticks()) -} - static STAGING: SmpStagedInit = SmpStagedInit::new(); pub(crate) fn init() { @@ -98,28 +55,24 @@ pub(crate) fn init() { STAGING.run(0, true, crate::boot::init_runtime); STAGING.run(1, true, crate::boot::init_heap); STAGING.run(2, false, init_vector_table); - STAGING.run(3, true, || { - time::systick_init(1_000_000_000); - }); - STAGING.run(4, false, time::reset_systick); // From now on, all work will be done by core 0. - if arch::current_cpu_id() != 0 { - scheduler::wait_and_then_start_schedule(); - unreachable!("Secondary cores should have jumped to the scheduler"); - } + // if arch::current_cpu_id() != 0 { + // scheduler::wait_and_then_start_schedule(); + // unreachable!("Secondary cores should have jumped to the scheduler"); + // } // Enable UART0 in PLIC. - PLIC.enable( - arch::current_cpu_id(), - u32::try_from(usize::from(config::UART0_IRQ)) - .expect("usize(64 bits) converts to u32 failed"), - ); + // PLIC.enable( + // arch::current_cpu_id(), + // u32::try_from(usize::from(config::UART0_IRQ)) + // .expect("usize(64 bits) converts to u32 failed"), + // ); // Set UART0 priority in PLIC. - PLIC.set_priority( - u32::try_from(usize::from(config::UART0_IRQ)) - .expect("usize(64 bits) converts to u32 failed"), - 1, - ); + // PLIC.set_priority( + // u32::try_from(usize::from(config::UART0_IRQ)) + // .expect("usize(64 bits) converts to u32 failed"), + // 1, + // ); } crate::define_peripheral! { @@ -128,3 +81,9 @@ crate::define_peripheral! { } crate::define_pin_states!(None); + +#[inline(always)] +pub(crate) fn send_ipi(_hart: usize) {} + +#[inline(always)] +pub(crate) fn clear_ipi(_hart: usize) {} From 773b65f830ad24cc1458432526baf1596274cd9d Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 11 Feb 2026 11:53:16 +0800 Subject: [PATCH 05/53] laji --- driver/src/systimer/esp32_sys_timer.rs | 218 ++++++++++ driver/src/systimer/mod.rs | 3 + driver/src/uart/esp32_uart.rs | 377 ------------------ driver/src/uart/esp32_usb_serial.rs | 176 ++++++++ driver/src/uart/mod.rs | 2 +- hal/src/clock.rs | 27 ++ hal/src/lib.rs | 1 + .../config/seeed_xiao_esp32c3/debug/defconfig | 2 +- .../seeed_xiao_esp32c3/release/defconfig | 34 ++ kernel/src/arch/riscv/mod.rs | 4 +- kernel/src/arch/riscv/trap.rs | 9 +- kernel/src/boards/gd32e507_eval/mod.rs | 1 + kernel/src/boards/gd32vw553_eval/mod.rs | 3 +- kernel/src/boards/qemu_mps2_an385/mod.rs | 4 +- kernel/src/boards/qemu_mps3_an547/mod.rs | 4 +- kernel/src/boards/qemu_riscv32/mod.rs | 2 +- kernel/src/boards/qemu_riscv64/mod.rs | 2 +- .../src/boards/raspberry_pico2_cortexm/mod.rs | 2 +- kernel/src/boards/seeed_xiao_esp32c3/link.x | 297 +++++++++++--- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 127 +++++- kernel/src/boot.rs | 4 + kernel/src/devices/clock.rs | 14 - kernel/src/devices/clock/gic_generic_timer.rs | 4 +- kernel/src/devices/clock/riscv_clock.rs | 4 +- kernel/src/devices/clock/systick.rs | 3 +- kernel/src/devices/tty/serial/mod.rs | 6 +- kernel/src/scheduler/mod.rs | 4 +- kernel/src/sync/libatomic/atomic.c | 257 ++++++------ kernel/src/time.rs | 3 +- kernel/src/time/timer.rs | 3 +- 30 files changed, 985 insertions(+), 612 deletions(-) create mode 100644 driver/src/systimer/esp32_sys_timer.rs delete mode 100644 driver/src/uart/esp32_uart.rs create mode 100644 driver/src/uart/esp32_usb_serial.rs create mode 100644 hal/src/clock.rs create mode 100644 kconfig/config/seeed_xiao_esp32c3/release/defconfig diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs new file mode 100644 index 00000000..67c8712d --- /dev/null +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -0,0 +1,218 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use blueos_hal::clock::Clock; +use tock_registers::{ + interfaces::{ReadWriteable, Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +register_bitfields! [ + u32, + + pub CONF [ + CLK_EN OFFSET(31) NUMBITS(1) [], + UNIT0_WORK_EN OFFSET(30) NUMBITS(1) [], + UNIT1_WORK_EN OFFSET(29) NUMBITS(1) [], + UNIT0_CORE0_STALL_EN OFFSET(28) NUMBITS(1) [], + UNIT1_CORE0_STALL_EN OFFSET(26) NUMBITS(1) [], + TARGET0_WORK_EN OFFSET(24) NUMBITS(1) [], + TARGET1_WORK_EN OFFSET(23) NUMBITS(1) [], + TARGET2_WORK_EN OFFSET(22) NUMBITS(1) [] + ], + + pub UNIT_OP [ + UPDATE OFFSET(30) NUMBITS(1) [], + VALUE_VALID OFFSET(29) NUMBITS(1) [] + ], + + pub UNIT_LOAD_HI [ + LOAD_HI OFFSET(0) NUMBITS(20) [] + ], + + pub UNIT_LOAD_LO [ + LOAD_LO OFFSET(0) NUMBITS(32) [] + ], + + pub UNIT_VALUE_HI [ + VALUE_HI OFFSET(0) NUMBITS(20) [] + ], + + pub UNIT_VALUE_LO [ + VALUE_LO OFFSET(0) NUMBITS(32) [] + ], + + pub UNIT_LOAD [ + LOAD OFFSET(0) NUMBITS(1) [] + ], + + pub TARGET_HI [ + HI OFFSET(0) NUMBITS(20) [] + ], + + pub TARGET_LO [ + LO OFFSET(0) NUMBITS(32) [] + ], + + pub TARGET_CONF [ + PERIOD OFFSET(0) NUMBITS(26) [], + PERIOD_MODE OFFSET(30) NUMBITS(1) [], + TIMER_UNIT_SEL OFFSET(31) NUMBITS(1) [] + ], + + pub COMP_LOAD [ + LOAD OFFSET(0) NUMBITS(1) [] + ], + + pub INT_ENA [ + TARGET0 OFFSET(0) NUMBITS(1) [], + TARGET1 OFFSET(1) NUMBITS(1) [], + TARGET2 OFFSET(2) NUMBITS(1) [] + ], + + pub INT_RAW [ + TARGET0 OFFSET(0) NUMBITS(1) [], + TARGET1 OFFSET(1) NUMBITS(1) [], + TARGET2 OFFSET(2) NUMBITS(1) [] + ], + + pub INT_CLR [ + TARGET0 OFFSET(0) NUMBITS(1) [], + TARGET1 OFFSET(1) NUMBITS(1) [], + TARGET2 OFFSET(2) NUMBITS(1) [] + ], + + pub INT_ST [ + TARGET0 OFFSET(0) NUMBITS(1) [], + TARGET1 OFFSET(1) NUMBITS(1) [], + TARGET2 OFFSET(2) NUMBITS(1) [] + ] +]; + +register_structs! { + + Registers { + (0x00 => conf: ReadWrite), + (0x04 => unit0_op: ReadWrite), + (0x08 => _reserved0), + (0x0C => unit0_load_hi: ReadWrite), + (0x10 => unit0_load_lo: ReadWrite), + (0x14 => _reserved1), + (0x1C => target0_hi: ReadWrite), + (0x20 => target0_lo: ReadWrite), + (0x24 => _reserved2), + (0x34 => target0_conf: ReadWrite), + (0x38 => _reserved3), + (0x40 => unit0_value_hi: ReadWrite), + (0x44 => unit0_value_lo: ReadWrite), + (0x48 => _reserved4), + (0x50 => comp0_load: ReadWrite), + (0x54 => _reserved5), + (0x5C => unit0_load: ReadWrite), + (0x60 => _reserved6), + (0x64 => int_ena: ReadWrite), + (0x68 => int_raw: ReadWrite), + (0x6C => int_clr: ReadWrite), + (0x70 => int_st: ReadWrite), + (0x74 => @END), + } +} + +/// FIXME: Only Supports Timer Unit 0 for now +pub struct Esp32SysTimer; + +impl Esp32SysTimer { + fn registers() -> &'static Registers { + unsafe { &*(BASE_ADDR as *const Registers) } + } + + pub fn init() { + // enable unit 0 + Self::registers().conf.modify(CONF::UNIT0_WORK_EN::SET); + // select unit 0 vs comparator 0 + Self::set_unit(); + // enable comparator 0 + Self::set_comparator_enable(true); + // CLR interrupt + // Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); + // enable interrupt + Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); + // set TARGET mode + Self::registers() + .target0_conf + .modify(TARGET_CONF::PERIOD_MODE::CLEAR); + } + + fn set_unit() { + Self::registers() + .target0_conf + .modify(TARGET_CONF::TIMER_UNIT_SEL::CLEAR); + } + + fn set_comparator_enable(enable: bool) { + Self::registers().conf.modify(if enable { + CONF::TARGET0_WORK_EN::SET + } else { + CONF::TARGET0_WORK_EN::CLEAR + }); + } +} + +impl Clock for Esp32SysTimer { + // this code is modified from + // https://github.com/esp-rs/esp-hal/blob/6100b7d90973539cf73d51e72cc20e6e275a98c6/esp-hal/src/timer/systimer.rs#L371-L387 + // This can be a shared reference as long as this type isn't Sync. + // FIXME: A stress test should be added to verify whether this API is stalled in multi-task. + fn estimate_current_cycles() -> u64 { + Self::registers().unit0_op.modify(UNIT_OP::UPDATE::SET); + while !Self::registers().unit0_op.is_set(UNIT_OP::VALUE_VALID) {} + + let mut lo_prev = Self::registers() + .unit0_value_lo + .read(UNIT_VALUE_LO::VALUE_LO); + loop { + let lo = lo_prev; + let hi = Self::registers() + .unit0_value_hi + .read(UNIT_VALUE_HI::VALUE_HI); + lo_prev = Self::registers() + .unit0_value_lo + .read(UNIT_VALUE_LO::VALUE_LO); + + if lo == lo_prev { + return ((hi as u64) << 32) | lo as u64; + } + } + } + + fn hz() -> u64 { + HZ + } + + fn interrupt_at(moment: u64) { + Self::registers() + .target0_hi + .write(TARGET_HI::HI.val((moment >> 32) as u32)); + Self::registers() + .target0_lo + .write(TARGET_LO::LO.val(moment as u32)); + // load comparator + Self::registers().comp0_load.write(COMP_LOAD::LOAD::SET); + } + + fn stop() { + Self::set_comparator_enable(false); + } +} diff --git a/driver/src/systimer/mod.rs b/driver/src/systimer/mod.rs index 64b39d7e..c31d53cd 100644 --- a/driver/src/systimer/mod.rs +++ b/driver/src/systimer/mod.rs @@ -11,3 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +#[cfg(target_chip = "esp32c3")] +pub mod esp32_sys_timer; diff --git a/driver/src/uart/esp32_uart.rs b/driver/src/uart/esp32_uart.rs deleted file mode 100644 index ec414308..00000000 --- a/driver/src/uart/esp32_uart.rs +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use blueos_hal::{ - uart::Uart, Configuration, Has8bitDataReg, HasFifo, HasInterruptReg, HasLineStatusReg, -}; -use hal_espressif_rs::uart_hal_context_t; - -use crate::uart::{Parity, StopBits}; - -pub struct Esp32Uart { - inner: uart_hal_context_t, -} - -unsafe impl Send for Esp32Uart {} -unsafe impl Sync for Esp32Uart {} - -impl Esp32Uart { - unsafe fn get_inner_ref_mut(&self) -> &mut uart_hal_context_t { - &mut *(core::ptr::addr_of!(self.inner) as *mut uart_hal_context_t) - } - - pub const fn new(base_addr: u32) -> Self { - unsafe { - Esp32Uart { - inner: uart_hal_context_t { - dev: base_addr as *mut _, - }, - } - } - } -} - -impl Configuration for Esp32Uart { - type Target = (); - // This code snippet is modified from - // https://github.com/zephyrproject-rtos/zephyr/blob/4f3478391a3c5e555dcd629f9e829378c17b0d62/drivers/serial/uart_esp32.c#L277-L377 - fn configure(&self, param: &super::UartConfig) -> blueos_hal::err::Result { - let super::UartConfig { - baudrate, - parity, - stop_bits, - data_bits, - flow_ctrl, - } = param; - - unsafe { - hal_espressif_rs::uart_hal_set_sclk( - self.get_inner_ref_mut(), - hal_espressif_rs::soc_periph_uart_clk_src_legacy_t_UART_SCLK_DEFAULT, - ); - hal_espressif_rs::uart_hal_set_txfifo_empty_thr(self.get_inner_ref_mut(), 0x1); - hal_espressif_rs::uart_hal_set_rxfifo_full_thr(self.get_inner_ref_mut(), 0x16); - hal_espressif_rs::uart_hal_rxfifo_rst(self.get_inner_ref_mut()); - hal_espressif_rs::uart_hal_txfifo_rst(self.get_inner_ref_mut()); - } - - match parity { - Parity::None => unsafe { - hal_espressif_rs::uart_hal_set_parity( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_parity_t_UART_PARITY_DISABLE, - ); - }, - Parity::Even => unsafe { - hal_espressif_rs::uart_hal_set_parity( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_parity_t_UART_PARITY_EVEN, - ); - }, - Parity::Odd => unsafe { - hal_espressif_rs::uart_hal_set_parity( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_parity_t_UART_PARITY_ODD, - ); - }, - _ => { - return Err(blueos_hal::err::HalError::InvalidParam); - } - } - - match data_bits { - super::DataBits::DataBits5 => unsafe { - hal_espressif_rs::uart_hal_set_data_bit_num( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_word_length_t_UART_DATA_5_BITS, - ); - }, - super::DataBits::DataBits6 => unsafe { - hal_espressif_rs::uart_hal_set_data_bit_num( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_word_length_t_UART_DATA_6_BITS, - ); - }, - super::DataBits::DataBits7 => unsafe { - hal_espressif_rs::uart_hal_set_data_bit_num( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_word_length_t_UART_DATA_7_BITS, - ); - }, - super::DataBits::DataBits8 => unsafe { - hal_espressif_rs::uart_hal_set_data_bit_num( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_word_length_t_UART_DATA_8_BITS, - ); - }, - _ => { - return Err(blueos_hal::err::HalError::InvalidParam); - } - } - - match stop_bits { - StopBits::DataBits1 => unsafe { - hal_espressif_rs::uart_hal_set_stop_bits( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_stop_bits_t_UART_STOP_BITS_1, - ); - }, - StopBits::DataBits1_5 => unsafe { - hal_espressif_rs::uart_hal_set_stop_bits( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_stop_bits_t_UART_STOP_BITS_1_5, - ); - }, - StopBits::DataBits2 => unsafe { - hal_espressif_rs::uart_hal_set_stop_bits( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_stop_bits_t_UART_STOP_BITS_2, - ); - }, - _ => { - return Err(blueos_hal::err::HalError::InvalidParam); - } - } - - unsafe { - hal_espressif_rs::uart_hal_set_mode( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_mode_t_UART_MODE_UART, - ); - } - - match flow_ctrl { - super::FlowCtrl::None => unsafe { - hal_espressif_rs::uart_hal_set_hw_flow_ctrl( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_DISABLE, - 0, - ); - }, - super::FlowCtrl::RtsCts => unsafe { - hal_espressif_rs::uart_hal_set_hw_flow_ctrl( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_CTS_RTS, - 10, - ); - }, - super::FlowCtrl::Rs485 => unsafe { - hal_espressif_rs::uart_hal_set_mode( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_mode_t_UART_MODE_RS485_HALF_DUPLEX, - ); - }, - _ => { - return Err(blueos_hal::err::HalError::InvalidParam); - } - } - - let src_clk = unsafe { - let mut src_clk: hal_espressif_rs::uart_sclk_t = 0; - hal_espressif_rs::uart_hal_get_sclk(self.get_inner_ref_mut(), &mut src_clk); - if src_clk == 0 { - return Err(blueos_hal::err::HalError::Fail); - } - src_clk - }; - - let sclk_freq = unsafe { - let mut sclk_freq: u32 = 0; - hal_espressif_rs::esp_clk_tree_src_get_freq_hz( - src_clk as hal_espressif_rs::soc_module_clk_t, - hal_espressif_rs::esp_clk_tree_src_freq_precision_t_ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, - core::ptr::addr_of_mut!(sclk_freq), - ); - sclk_freq - }; - unsafe { - hal_espressif_rs::uart_hal_set_baudrate(self.get_inner_ref_mut(), *baudrate, sclk_freq); - hal_espressif_rs::uart_hal_set_rx_timeout(self.get_inner_ref_mut(), 0x16); - } - Ok(()) - } -} - -// impl Uart for Esp32Uart {} - -impl Has8bitDataReg for Esp32Uart { - fn read_data8(&self) -> blueos_hal::err::Result { - let mut len = 1; - let mut p_char = 0u8; - unsafe { - hal_espressif_rs::uart_hal_read_rxfifo( - self.get_inner_ref_mut(), - core::ptr::addr_of_mut!(p_char), - core::ptr::addr_of_mut!(len), - ) - }; - if len == 0 { - return Err(blueos_hal::err::HalError::IoError); - } - Ok(p_char) - } - - fn write_data8(&self, data: u8) { - let mut len = 1; - unsafe { - hal_espressif_rs::uart_hal_write_txfifo( - self.get_inner_ref_mut(), - core::ptr::addr_of!(data), - 1, - core::ptr::addr_of_mut!(len), - ) - }; - } - - fn is_data_ready(&self) -> bool { - unsafe { - hal_espressif_rs::rust_helper_uart_hal_get_rxfifo_len(self.get_inner_ref_mut()) > 0 - } - } -} - -impl HasLineStatusReg for Esp32Uart { - fn is_bus_busy(&self) -> bool { - unsafe { - hal_espressif_rs::rust_helper_uart_hal_get_txfifo_len(self.get_inner_ref_mut()) > 0 - } - } -} - -impl HasFifo for Esp32Uart { - fn enable_fifo(&self, _num: u8) -> blueos_hal::err::Result<()> { - // FIFO is always enabled in ESP32 UART - Ok(()) - } - - fn is_tx_fifo_full(&self) -> bool { - unsafe { - // FIXME - hal_espressif_rs::rust_helper_uart_hal_get_txfifo_len(self.get_inner_ref_mut()) != 0 - } - } - - fn is_rx_fifo_empty(&self) -> bool { - unsafe { - hal_espressif_rs::rust_helper_uart_hal_get_rxfifo_len(self.get_inner_ref_mut()) == 0 - } - } -} - -impl HasInterruptReg for Esp32Uart { - type InterruptType = super::InterruptType; - - fn enable_interrupt(&self, intr: Self::InterruptType) { - match intr { - super::InterruptType::Rx => unsafe { - hal_espressif_rs::rust_helper_uart_clr_intsts_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, - ); - hal_espressif_rs::rust_helper_uart_clr_intsts_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, - ); - hal_espressif_rs::uart_hal_ena_intr_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, - ); - hal_espressif_rs::uart_hal_ena_intr_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, - ); - }, - super::InterruptType::Tx => unsafe { - hal_espressif_rs::rust_helper_uart_clr_intsts_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, - ); - hal_espressif_rs::uart_hal_ena_intr_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, - ); - }, - _ => {} - } - } - - fn disable_interrupt(&self, intr: Self::InterruptType) { - match intr { - super::InterruptType::Rx => unsafe { - hal_espressif_rs::rust_helper_uart_hal_disable_intr_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, - ); - hal_espressif_rs::rust_helper_uart_hal_disable_intr_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, - ); - }, - super::InterruptType::Tx => unsafe { - hal_espressif_rs::rust_helper_uart_hal_disable_intr_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, - ); - }, - _ => {} - } - } - - fn clear_interrupt(&self, intr: Self::InterruptType) { - match intr { - super::InterruptType::Rx => unsafe { - hal_espressif_rs::rust_helper_uart_clr_intsts_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL, - ); - hal_espressif_rs::rust_helper_uart_clr_intsts_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_TOUT, - ); - }, - super::InterruptType::Tx => unsafe { - hal_espressif_rs::rust_helper_uart_clr_intsts_mask( - self.get_inner_ref_mut(), - hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY, - ); - }, - _ => unsafe { - let mask = hal_espressif_rs::rust_helper_uart_hal_get_intsts_mask( - self.get_inner_ref_mut(), - ); - hal_espressif_rs::rust_helper_uart_clr_intsts_mask(self.get_inner_ref_mut(), mask); - }, - } - } - - fn get_interrupt(&self) -> Self::InterruptType { - unsafe { - let mask = - hal_espressif_rs::rust_helper_uart_hal_get_intsts_mask(self.get_inner_ref_mut()); - if mask & hal_espressif_rs::uart_intr_t_UART_INTR_RXFIFO_FULL != 0 { - super::InterruptType::Rx - } else if mask & hal_espressif_rs::uart_intr_t_UART_INTR_TXFIFO_EMPTY != 0 { - super::InterruptType::Tx - } else { - super::InterruptType::Unknown - } - } - } - - fn set_interrupt_handler(&self, handler: &'static dyn Fn()) {} - - fn get_irq_nums(&self) -> &[u32] { - &[] - } -} diff --git a/driver/src/uart/esp32_usb_serial.rs b/driver/src/uart/esp32_usb_serial.rs new file mode 100644 index 00000000..b5476fe7 --- /dev/null +++ b/driver/src/uart/esp32_usb_serial.rs @@ -0,0 +1,176 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::static_ref::StaticRef; +use blueos_hal::{ + uart::Uart, Configuration, Has8bitDataReg, HasFifo, HasInterruptReg, HasLineStatusReg, PlatPeri, +}; +use tock_registers::{ + interfaces::{ReadWriteable, Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +register_bitfields! [ + u32, + + pub EP1_REG [ + RDWR_BYTE OFFSET(0) NUMBITS(8) [] + ], + + pub EP1_CONF_REG [ + WR_DONE OFFSET(0) NUMBITS(1) [], + IN_EP_DATA_FREE OFFSET(1) NUMBITS(1) [ + FREE = 1, + NOT_FREE = 0 + ], + OUT_EP_DATA_AVAIL OFFSET(2) NUMBITS(1) [ + AVAIL = 1, + NOT_AVAIL = 0 + ] + ], + + pub JFIFO_ST_REG [ + IN_FIFO_CNT OFFSET(0) NUMBITS(2) [], + IN_FIFO_EMPTY OFFSET(2) NUMBITS(1) [ + EMPTY = 1, + NOT_EMPTY = 0 + ], + IN_FIFO_FULL OFFSET(3) NUMBITS(1) [ + FULL = 1, + NOT_FULL = 0 + ], + OUT_FIFO_CNT OFFSET(4) NUMBITS(2) [], + OUT_FIFO_EMPTY OFFSET(6) NUMBITS(1) [ + EMPTY = 1, + NOT_EMPTY = 0 + ], + OUT_FIFO_FULL OFFSET(7) NUMBITS(1) [ + FULL = 1, + NOT_FULL = 0 + ], + IN_FIFO_RESET OFFSET(8) NUMBITS(1) [], + OUT_FIFO_RESET OFFSET(9) NUMBITS(1) [] + ] +]; + +register_structs! { + Registers { + (0x00 => ep1_reg: ReadWrite), + (0x04 => ep1_conf_reg: ReadWrite), + (0x08 => _reserved0), + (0x20 => jfifo_st_reg: ReadWrite), + (0x24 => @END), + } +} + +const USB_SERIAL_BASE: StaticRef = + unsafe { StaticRef::new(0x6004_3000 as *const Registers) }; + +pub struct Esp32UsbSerial; + +unsafe impl Send for Esp32UsbSerial {} +unsafe impl Sync for Esp32UsbSerial {} + +impl Configuration for Esp32UsbSerial { + type Target = (); + fn configure(&self, param: &super::UartConfig) -> blueos_hal::err::Result { + Ok(()) + } +} + +impl Has8bitDataReg for Esp32UsbSerial { + fn write_data8(&self, data: u8) { + USB_SERIAL_BASE + .ep1_reg + .write(EP1_REG::RDWR_BYTE.val(data as u32)); + USB_SERIAL_BASE + .ep1_conf_reg + .write(EP1_CONF_REG::WR_DONE.val(1)); + } + + fn is_data_ready(&self) -> bool { + USB_SERIAL_BASE + .ep1_conf_reg + .is_set(EP1_CONF_REG::OUT_EP_DATA_AVAIL) + } + + fn read_data8(&self) -> blueos_hal::err::Result { + Ok(USB_SERIAL_BASE.ep1_reg.read(EP1_REG::RDWR_BYTE) as u8) + } +} + +impl HasLineStatusReg for Esp32UsbSerial { + fn is_bus_busy(&self) -> bool { + USB_SERIAL_BASE + .ep1_conf_reg + .is_set(EP1_CONF_REG::IN_EP_DATA_FREE) + != true + } +} + +impl HasFifo for Esp32UsbSerial { + fn enable_fifo(&self, num: u8) -> blueos_hal::err::Result<()> { + Ok(()) + } + + fn is_tx_fifo_full(&self) -> bool { + // USB_SERIAL_BASE + // .jfifo_st_reg + // .is_set(JFIFO_ST_REG::IN_FIFO_FULL) + USB_SERIAL_BASE + .ep1_conf_reg + .is_set(EP1_CONF_REG::IN_EP_DATA_FREE) + != true + } + + fn is_rx_fifo_empty(&self) -> bool { + USB_SERIAL_BASE + .ep1_conf_reg + .is_set(EP1_CONF_REG::OUT_EP_DATA_AVAIL) + != true + } +} + +impl HasInterruptReg for Esp32UsbSerial { + type InterruptType = super::InterruptType; + + fn enable_interrupt(&self, intr: Self::InterruptType) { + // Not supported + } + + fn disable_interrupt(&self, intr: Self::InterruptType) { + // Not supported + } + + fn clear_interrupt(&self, intr: Self::InterruptType) { + // Not supported + } + + fn get_interrupt(&self) -> Self::InterruptType { + super::InterruptType::Unknown + } + + fn set_interrupt_handler(&self, handler: &'static dyn Fn()) { + // Not supported + } + + fn get_irq_nums(&self) -> &[u32] { + &[] + } +} + +impl PlatPeri for Esp32UsbSerial {} + +impl Uart for Esp32UsbSerial {} diff --git a/driver/src/uart/mod.rs b/driver/src/uart/mod.rs index 48b87f67..0eb9435d 100644 --- a/driver/src/uart/mod.rs +++ b/driver/src/uart/mod.rs @@ -16,7 +16,7 @@ pub mod arm_pl011; pub mod cmsdk; pub mod dumb; #[cfg(target_chip = "esp32c3")] -pub mod esp32_uart; +pub mod esp32_usb_serial; #[cfg(target_chip = "gd32e5x")] pub mod gd32e5x_uart; #[cfg(target_chip = "gd32vw55x")] diff --git a/hal/src/clock.rs b/hal/src/clock.rs new file mode 100644 index 00000000..6ab4f273 --- /dev/null +++ b/hal/src/clock.rs @@ -0,0 +1,27 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// We use the term `cycles` to refer to the internal counter of the Clock. We +// use the term `hz` to descripe how many cycles within a second. Tick is +// defined as a short period of time, which is atomic in the system, just like +// the Planck time in physical world. We use `TICKS_PER_SECOND` to measure it. +// A clock instance should be able to interrupt the system. +pub trait Clock { + fn hz() -> u64; + // Reading the current counter of the Clock requires some time(Time + // Drifting), we can only estimate it. + fn estimate_current_cycles() -> u64; + fn interrupt_at(moment: u64); + fn stop(); +} diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 8906fbb7..cf94fbb7 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -20,6 +20,7 @@ pub mod err; use core::num::NonZeroUsize; use err::Result; +pub mod clock; pub mod clock_control; pub mod i2c; pub mod pinctrl; diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index f8df3ade..60f7d914 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -12,7 +12,7 @@ CONFIG_USE_KERNEL_BOOT=y # CONFIG_SOFT_TIMER=y CONFIG_EVENT_FLAGS=y -CONFIG_ROBIN_SCHEDULER=y +CONFIG_ROBIN_SCHEDULER=n CONFIG_ROBIN_SLICE=10 CONFIG_OVERFLOW_CHECK=y CONFIG_STACK_HIGHWATER_CHECK=y diff --git a/kconfig/config/seeed_xiao_esp32c3/release/defconfig b/kconfig/config/seeed_xiao_esp32c3/release/defconfig new file mode 100644 index 00000000..f8df3ade --- /dev/null +++ b/kconfig/config/seeed_xiao_esp32c3/release/defconfig @@ -0,0 +1,34 @@ +# CONFIG_IRQ_PRIORITY_BITS_3 is not set +CONFIG_IRQ_PRIORITY_BITS_2=y +CONFIG_ALIGN_SIZE=8 +CONFIG_TICKS_PER_SECOND=100 +CONFIG_SMP=n +CONFIG_NUM_CORES=1 +CONFIG_ALLOCATOR_TLSF=y +CONFIG_ALLOCATOR="tlsf" +CONFIG_USE_KERNEL_BOOT=y +# +# Kernel Core Features +# +CONFIG_SOFT_TIMER=y +CONFIG_EVENT_FLAGS=y +CONFIG_ROBIN_SCHEDULER=y +CONFIG_ROBIN_SLICE=10 +CONFIG_OVERFLOW_CHECK=y +CONFIG_STACK_HIGHWATER_CHECK=y +CONFIG_MAIN_THREAD_STACK_SIZE=12288 +CONFIG_IDLE_THREAD_STACK_SIZE=2048 +CONFIG_TIMER_THREAD_STACK_SIZE=2048 +CONFIG_THREAD_PRIORITY=y +CONFIG_THREAD_PRIORITY_32=y +CONFIG_THREAD_PRIORITY_MAX=32 +CONFIG_MAIN_THREAD_PRIORITY=32 + +CONFIG_ENABLE_SYSCALL=y +# CONFIG_FDT is not set +# CONFIG_VIRTIO is not set +CONFIG_SERIAL_RX_FIFO_SIZE=256 +CONFIG_SERIAL_TX_FIFO_SIZE=256 +CONFIG_ENABLE_VFS=n +CONFIG_ENABLE_NET=n +CONFIG_PROCFS=n diff --git a/kernel/src/arch/riscv/mod.rs b/kernel/src/arch/riscv/mod.rs index f5c7e037..93c31991 100644 --- a/kernel/src/arch/riscv/mod.rs +++ b/kernel/src/arch/riscv/mod.rs @@ -485,9 +485,9 @@ pub(crate) extern "C" fn bootstrap() { unsafe { core::arch::asm!( "csrs mstatus, {mstatus}", - "csrs mie, {mie}", + // "csrs mie, {mie}", mstatus = in(reg) MSTATUS_MPP_M | MSTATUS_MPIE, - mie = in(reg) MIE_MTIE|MIE_MSIE|MIE_MEIE, + // mie = in(reg) MIE_MTIE|MIE_MSIE|MIE_MEIE, options(nostack), ) }; diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index fbff2910..41a96f9f 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -55,6 +55,8 @@ extern "C" fn switch_stack_with_hook( // trap_handler decides whether nested interrupt is allowed. #[repr(align(4))] +#[no_mangle] +#[link_section = ".trap.handler"] #[naked] pub(crate) unsafe extern "C" fn trap_entry() { core::arch::naked_asm!( @@ -231,6 +233,7 @@ fn might_switch_context(from: &Context, ra: usize) -> usize { extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: usize) -> usize { debug_assert!(!super::local_irq_enabled()); let sp = ctx as *const _ as usize; + crate::kprintln!("mcause: 0x{:x}, mepc: 0x{:x}", mcause, ctx.mepc); match mcause & (INTERRUPT_MASK | 0x3f) { EXTERN_INT => { handle_plic_irq(ctx, mcause, mtval); @@ -240,7 +243,11 @@ extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: crate::time::handle_clock_interrupt(); might_switch_context(ctx, cont) } - ECALL => handle_ecall(ctx, cont), + // ECALL => handle_ecall(ctx, cont), + ECALL => { + ctx.mepc += 4; + sp + } // For waking up from wfi. MSI => { clear_ipi(arch::current_cpu_id()); diff --git a/kernel/src/boards/gd32e507_eval/mod.rs b/kernel/src/boards/gd32e507_eval/mod.rs index f91bf41d..6cadb9f5 100644 --- a/kernel/src/boards/gd32e507_eval/mod.rs +++ b/kernel/src/boards/gd32e507_eval/mod.rs @@ -21,6 +21,7 @@ use crate::{ }; use alloc::sync::Arc; use blueos_driver::pinctrl::gd32_afio::*; +use blueos_hal::clock::Clock; use blueos_infra::tinyarc::TinyArc; use core::ptr::addr_of; use spin::Once; diff --git a/kernel/src/boards/gd32vw553_eval/mod.rs b/kernel/src/boards/gd32vw553_eval/mod.rs index 44b8325c..835aa98d 100644 --- a/kernel/src/boards/gd32vw553_eval/mod.rs +++ b/kernel/src/boards/gd32vw553_eval/mod.rs @@ -25,7 +25,7 @@ use crate::{ self, riscv::{local_irq_enabled, trap_entry, Context}, }, - devices::clock::{riscv_clock::RiscvClock, Clock}, + devices::clock::riscv_clock::RiscvClock, drivers::msip::Msip, scheduler, time, time::Tick, @@ -36,6 +36,7 @@ use alloc::{ string::String, }; use blueos_driver::pinctrl::gd32_af::{AfioMode, Gd32Alterfunc, OutputSpeed, OutputType, PullMode}; +use blueos_hal::clock::Clock; pub type ClockImpl = RiscvClock<0xD1000000, 0xD1000008, 40_000_000>; diff --git a/kernel/src/boards/qemu_mps2_an385/mod.rs b/kernel/src/boards/qemu_mps2_an385/mod.rs index bc047042..030a0f79 100644 --- a/kernel/src/boards/qemu_mps2_an385/mod.rs +++ b/kernel/src/boards/qemu_mps2_an385/mod.rs @@ -20,12 +20,12 @@ use crate::{ memory_map, UART0RX_IRQn, UART0TX_IRQn, SYSTEM_CORE_CLOCK, UART0RX_IRQ_N, UART0TX_IRQ_N, }, boot, - devices::clock::{systick, Clock}, + devices::clock::systick, error::Error, irq::IrqTrace, time, }; -use blueos_hal::HasInterruptReg; +use blueos_hal::{clock::Clock, HasInterruptReg}; use boot::INIT_BSS_DONE; #[repr(C)] diff --git a/kernel/src/boards/qemu_mps3_an547/mod.rs b/kernel/src/boards/qemu_mps3_an547/mod.rs index 8d741332..cd67498b 100644 --- a/kernel/src/boards/qemu_mps3_an547/mod.rs +++ b/kernel/src/boards/qemu_mps3_an547/mod.rs @@ -21,12 +21,12 @@ use crate::{ memory_map, UART0RX_IRQn, UART0TX_IRQn, SYSTEM_CORE_CLOCK, UART0RX_IRQ_N, UART0TX_IRQ_N, }, boot, - devices::clock::{systick, Clock}, + devices::clock::systick, error::Error, irq::IrqTrace, time, }; -use blueos_hal::HasInterruptReg; +use blueos_hal::{clock::Clock, HasInterruptReg}; use boot::INIT_BSS_DONE; use core::ptr::addr_of; diff --git a/kernel/src/boards/qemu_riscv32/mod.rs b/kernel/src/boards/qemu_riscv32/mod.rs index a023e40c..7f070a1a 100644 --- a/kernel/src/boards/qemu_riscv32/mod.rs +++ b/kernel/src/boards/qemu_riscv32/mod.rs @@ -23,12 +23,12 @@ mod config; use crate::{ arch, arch::riscv::{local_irq_enabled, trap_entry, Context}, - devices::clock::Clock, drivers::{ic::plic::Plic, msip::Msip}, scheduler, support::SmpStagedInit, time, }; +use blueos_hal::clock::Clock; use core::sync::atomic::Ordering; pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); pub use crate::devices::clock::riscv_clock::QemuRiscvClock as ClockImpl; diff --git a/kernel/src/boards/qemu_riscv64/mod.rs b/kernel/src/boards/qemu_riscv64/mod.rs index a023e40c..7f070a1a 100644 --- a/kernel/src/boards/qemu_riscv64/mod.rs +++ b/kernel/src/boards/qemu_riscv64/mod.rs @@ -23,12 +23,12 @@ mod config; use crate::{ arch, arch::riscv::{local_irq_enabled, trap_entry, Context}, - devices::clock::Clock, drivers::{ic::plic::Plic, msip::Msip}, scheduler, support::SmpStagedInit, time, }; +use blueos_hal::clock::Clock; use core::sync::atomic::Ordering; pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); pub use crate::devices::clock::riscv_clock::QemuRiscvClock as ClockImpl; diff --git a/kernel/src/boards/raspberry_pico2_cortexm/mod.rs b/kernel/src/boards/raspberry_pico2_cortexm/mod.rs index e33ba241..8ff5b899 100644 --- a/kernel/src/boards/raspberry_pico2_cortexm/mod.rs +++ b/kernel/src/boards/raspberry_pico2_cortexm/mod.rs @@ -23,7 +23,7 @@ use crate::{ irq::IrqTrace, time, }; -use blueos_hal::clock_control::ClockControl; +use blueos_hal::{clock::Clock, clock_control::ClockControl}; use core::ptr::addr_of; use spin::Once; diff --git a/kernel/src/boards/seeed_xiao_esp32c3/link.x b/kernel/src/boards/seeed_xiao_esp32c3/link.x index 92e9af72..436017e8 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/link.x +++ b/kernel/src/boards/seeed_xiao_esp32c3/link.x @@ -7,7 +7,32 @@ OUTPUT_ARCH("riscv") ENTRY(_start) -MEMORY { +MEMORY +{ + /* + https://github.com/espressif/esptool/blob/ed64d20b051d05f3f522bacc6a786098b562d4b8/esptool/targets/esp32c3.py#L78-L90 + MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"], + [0x3C000000, 0x3C800000, "DROM"], + [0x3FC80000, 0x3FCE0000, "DRAM"], + [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"], + [0x3FF00000, 0x3FF20000, "DROM_MASK"], + [0x40000000, 0x40060000, "IROM_MASK"], + [0x42000000, 0x42800000, "IROM"], + [0x4037C000, 0x403E0000, "IRAM"], + [0x50000000, 0x50002000, "RTC_IRAM"], + [0x50000000, 0x50002000, "RTC_DRAM"], + [0x600FE000, 0x60100000, "MEM_INTERNAL2"]] + */ + + ICACHE : ORIGIN = 0x4037C000, LENGTH = 0x4000 + /* Instruction RAM */ + IRAM : ORIGIN = 0x4037C000 + 0x4000, LENGTH = 313K - 0x4000 + /* Data RAM */ + DRAM : ORIGIN = 0x3FC80000, LENGTH = 313K + + /* memory available after the 2nd stage bootloader is finished */ + dram2_seg ( RW ) : ORIGIN = ORIGIN(DRAM) + LENGTH(DRAM), len = 0x3fcde710 - (ORIGIN(DRAM) + LENGTH(DRAM)) + /* External flash The 0x20 offset is a convenience for the app binary image generation. @@ -20,106 +45,246 @@ MEMORY { /* Instruction ROM */ IROM : ORIGIN = 0x42000000 + 0x20, LENGTH = 0x400000 - 0x20 /* Data ROM */ - DROM : ORIGIN = 0x3C000000 + 0x20, LENGTH = 0x400000 - 0x20 + DROM (rxai!w) : ORIGIN = 0x3C000000 + 0x20, LENGTH = 0x400000 - 0x20 - DRAM : ORIGIN = 0x3FC80000, LENGTH = 384K + /* RTC fast memory (executable). Persists over deep sleep. */ + RTC_FAST : ORIGIN = 0x50000000, LENGTH = 0x2000 /*- ESP_BOOTLOADER_RESERVE_RTC*/ } -SECTIONS -{ - .rodata_desc : ALIGN(4) +REGION_ALIAS("ROTEXT", IROM); +REGION_ALIAS("RODATA", DROM); + +REGION_ALIAS("RWDATA", DRAM); +REGION_ALIAS("RWTEXT", IRAM); + +REGION_ALIAS("RTC_FAST_RWTEXT", RTC_FAST); +REGION_ALIAS("RTC_FAST_RWDATA", RTC_FAST); + +SECTIONS { + .rotext_dummy (NOLOAD) : { - KEEP(*(.rodata_desc)); - KEEP(*(.rodata_desc.*)); - } > DROM + /* This dummy section represents the .rodata section within ROTEXT. + * Since the same physical memory is mapped to both DROM and IROM, + * we need to make sure the .rodata and .text sections don't overlap. + * We skip the amount of memory taken by .rodata* in .text + */ - .rodata : ALIGN(4) + /* Start at the same alignment constraint than .flash.text */ + + . = ALIGN(ALIGNOF(.rodata)); + + /* Create an empty gap as big as .text section */ + + . = . + SIZEOF(.rodata_desc); + . = . + SIZEOF(.rodata); + + /* Prepare the alignment of the section above. Few bytes (0x20) must be + * added for the mapping header. + */ + + . = ALIGN(0x10000) + 0x20; + _rotext_reserved_start = .; + } > ROTEXT +} +INSERT BEFORE .text; + +/* Similar to .rotext_dummy this represents .rwtext but in .data */ +SECTIONS { + .rwdata_dummy (NOLOAD) : ALIGN(4) { - . = ALIGN(16); - *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */ - . = ALIGN(16); - *(.rodata .rodata.*) - } > DROM + . = . + SIZEOF(.rwtext) + SIZEOF(.rwtext.wifi) + SIZEOF(.trap); + } > RWDATA +} +INSERT BEFORE .data; + +SECTIONS { + .trap : ALIGN(4) + { + _trap_section_origin = .; + KEEP(*(.trap)); + *(.trap.*); + } > RWTEXT + + .rwtext : ALIGN(4) + { + . = ALIGN (4); + *(.rwtext.literal .rwtext .rwtext.literal.* .rwtext.*) + /* unconditionally add patched SPI-flash ROM functions (from esp-rom-sys) - the linker is still happy if there are none */ + *:esp_rom_spiflash.*(.literal .literal.* .text .text.*) + . = ALIGN(4); + } > RWTEXT - .rodata.wifi : ALIGN(4) + .rwtext.wifi : { . = ALIGN(4); - *( .rodata_wlog_*.* ) + *( .wifi0iram .wifi0iram.*) + *( .wifirxiram .wifirxiram.*) + *( .wifislprxiram .wifislprxiram.*) + *( .wifislpiram .wifislpiram.*) + *( .phyiram .phyiram.*) + *( .iram1 .iram1.*) + *( .wifiextrairam.* ) + *( .coexiram.* ) . = ALIGN(4); - } > DROM - .init_array : { + _rwtext_len = . - ORIGIN(RWTEXT); + } > RWTEXT + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + . = ALIGN (4); + + *(.rodata.*_esp_hal_internal_handler*) + *(.rodata..Lswitch.table.*) + *(.rodata.cst*) + + + *(.sdata .sdata.* .sdata2 .sdata2.*); + *(.data .data.*); + *(.data1) + _data_end = ABSOLUTE(.); . = ALIGN(4); - PROVIDE_HIDDEN(__init_array_start = .); - KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN(__init_array_end = .); - } > DROM + } > RWDATA + + .data.wifi : + { + . = ALIGN(4); + *( .dram1 .dram1.*) + . = ALIGN(4); + } > RWDATA + + .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 - .bk_app_array : { + .noinit (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + *(.noinit .noinit.*) + *(.uninit .uninit.*) + . = ALIGN(4); + } > RWDATA +} + +SECTIONS { + /* For ESP App Description, must be placed first in image */ + .rodata_desc : ALIGN(0x10) + { + KEEP(*(.rodata_desc)); + KEEP(*(.rodata_desc.*)); + } > RODATA + + .rodata : ALIGN(0x10) + { + . = ALIGN (4); + _rodata_start = ABSOLUTE(.); + *(.rodata .rodata.*) + *(.srodata .srodata.*) . = ALIGN(4); + PROVIDE_HIDDEN(__bk_app_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.bk_app_array.*))) KEEP (*(.bk_app_array)) PROVIDE_HIDDEN(__bk_app_array_end = .); - } > DROM - /* Put .bss to RAM */ - .zero.table : - { . = ALIGN(4); - __zero_table_start = .; - LONG (__bss_start) - LONG ((__bss_end - __bss_start) / 4) - __zero_table_end = .; - } > DROM + PROVIDE(__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*))) + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) + PROVIDE(__init_array_end = .); + . = ALIGN(4); + _rodata_end = ABSOLUTE(.); + } > RODATA +} - . = ALIGN(0x10000) + 0x20; +SECTIONS { .text : ALIGN(4) { + KEEP(*(.init)); + KEEP(*(.init.rust)); + KEEP(*(.text.abort)); *(.literal .text .literal.* .text.*) - } > IROM + } > ROTEXT +} - .data (COPY) : { - *(.rdata) - *(.gnu.linkonce.r.*) - *(.data .data.*) - *(.gnu.linkonce.d.*) - . = ALIGN(8); - PROVIDE(__global_pointer$ = . + 0x800); - *(.sdata .sdata.*) - *(.gnu.linkonce.s.*) - . = ALIGN(8); - *(.srodata.cst16) - *(.srodata.cst8) - *(.srodata.cst4) - *(.srodata.cst2) - *(.srodata .srodata.*) - KEEP(*(.test_data.*)); - } > DRAM - . = ALIGN(4); - PROVIDE(__data_end = .); +SECTIONS { + .rtc_fast.text : { + . = ALIGN(4); + *(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*) + . = ALIGN(4); + } > RTC_FAST_RWTEXT AT > RODATA + + .rtc_fast.data : + { + . = ALIGN(4); + _rtc_fast_data_start = ABSOLUTE(.); + *(.rtc_fast.data .rtc_fast.data.*) + _rtc_fast_data_end = ABSOLUTE(.); + . = ALIGN(4); + } > RTC_FAST_RWDATA AT > RODATA - .bss : { + /* LMA of .data */ + _rtc_fast_sidata = LOADADDR(.rtc_fast.data); + + .rtc_fast.bss (NOLOAD) : + { . = ALIGN(4); - __bss_start = .; - *(.sbss .sbss.*) - *(.bss .bss.*) + _rtc_fast_bss_start = ABSOLUTE(.); + *(.rtc_fast.bss .rtc_fast.bss.*) + _rtc_fast_bss_end = ABSOLUTE(.); . = ALIGN(4); - __bss_end = .; - } > DRAM + } > RTC_FAST_RWDATA - .heap : { + .rtc_fast.persistent (NOLOAD) : + { + . = ALIGN(4); + _rtc_fast_persistent_start = ABSOLUTE(.); + *(.rtc_fast.persistent .rtc_fast.persistent.*) + _rtc_fast_persistent_end = ABSOLUTE(.); + . = ALIGN(4); + } > RTC_FAST_RWDATA +} + +SECTIONS +{ + .heap (NOLOAD) : { . = ALIGN(8); __heap_start = .; . = ORIGIN(DRAM) + LENGTH(DRAM) - 0x1000; __heap_end = .; - } > DRAM + } > RWDATA - .stack : { + .stack (NOLOAD) : { . = ALIGN(16); __sys_stack_start = .; . += 0x1000; __sys_stack_end = .; - } > DRAM -} \ No newline at end of file + } > RWDATA +} + +SECTIONS { + .espressif.metadata 0 (INFO) : + { + KEEP(*(.espressif.metadata)); + } +} + +PROVIDE(__global_pointer$ = ALIGN(_data_start, 4) + 0x800); diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index d14dbf57..91f28dd2 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -26,19 +26,71 @@ use crate::{ support::SmpStagedInit, time, }; +use blueos_hal::Has8bitDataReg; use core::sync::atomic::Ordering; pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); -pub type ClockImpl = crate::devices::clock::riscv_clock::RiscvClock<0x6002_3000, 0x1, 16_000_000>; +// FIXME: Only support unit0 for now +pub type ClockImpl = + blueos_driver::systimer::esp32_sys_timer::Esp32SysTimer<0x6002_3000, 16_000_000>; + +core::arch::global_asm!( + " +.section .trap +.type _vector_table, @function + +.option push +.balign 0x4 +.option norelax +.option norvc + +_vector_table: + j trap_entry // 0: Instruction address misaligned + j trap_entry // 1: Instruction access fault + j trap_entry // 2: Illegal instruction + j trap_entry // 3: Breakpoint + j trap_entry // 4: Load address misaligned + j trap_entry // 5: Load access fault + j trap_entry // 6: Store/AMO address misaligned + j trap_entry // 7: Store/AMO access fault + j trap_entry // 8: Environment call from U-mode + j trap_entry // 9: Environment call from S-mode + j trap_entry // 10: Reserved + j trap_entry // 11: Environment call from M-mode + j trap_entry // 12: Instruction page fault + j trap_entry // 13: Load page fault + j trap_entry // 14: Reserved + j trap_entry // 15: Store/AMO page fault + j trap_entry // 16: Reserved + j trap_entry // 17: Reserved + j trap_entry // 18: Reserved + j trap_entry // 19: Reserved + j trap_entry // 20: Reserved + j trap_entry // 21: Reserved + j trap_entry // 22: Reserved + j trap_entry // 23: Reserved + j trap_entry // 24: Reserved + j trap_entry // 25: Reserved + j trap_entry // 26: Reserved + j trap_entry // 27: Reserved + j trap_entry // 28: Reserved + j trap_entry // 29: Reserved + j trap_entry // 30: Reserved + j trap_entry // 31: Reserved + " +); #[inline] fn init_vector_table() { + unsafe extern "C" { + static _vector_table: u32; + } + let mut v = core::ptr::addr_of!(_vector_table) as usize; + v |= 0x3; // Set MODE to Vectored unsafe { core::arch::asm!( - "la {x}, {entry}", - "csrw mtvec, {x}", - x = out(reg) _, - entry = sym trap_entry, - options(nostack), + "csrw mtvec, {0}", + in(reg) v, + options(nostack, preserves_flags), ); } } @@ -50,34 +102,54 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { static STAGING: SmpStagedInit = SmpStagedInit::new(); +const INTR_BASE: usize = 0x600c_2000; +const TARGET0_INT_MAP_REG: usize = INTR_BASE + 0x94; +const INT_ENABLE_REG: usize = INTR_BASE + 0x104; +const INT_THRESH_REG: usize = INTR_BASE + 0x194; +const TARGET0_INT_NUM: usize = 1; // IRQ number 16 in target0 +const CLOCK_GATE_REG: usize = INTR_BASE + 0x100; + pub(crate) fn init() { assert!(!local_irq_enabled()); - STAGING.run(0, true, crate::boot::init_runtime); - STAGING.run(1, true, crate::boot::init_heap); - STAGING.run(2, false, init_vector_table); + unsafe { hal_espressif_rs::soc_init() }; + unsafe { + crate::boot::INIT_BSS_DONE = true; + } + crate::boot::init_runtime(); + crate::boot::init_heap(); + init_vector_table(); + + blueos_driver::systimer::esp32_sys_timer::Esp32SysTimer::<0x6002_3000, 16_000_000>::init(); + // map target0 interrupt to 16 interrupt + unsafe { + core::ptr::write_volatile(CLOCK_GATE_REG as *mut u32, 1); + core::ptr::write_volatile(TARGET0_INT_MAP_REG as *mut u32, TARGET0_INT_NUM as u32); + core::ptr::write_volatile(INT_ENABLE_REG as *mut u32, 0xFFFF_FFFF); + core::ptr::write_volatile(INT_THRESH_REG as *mut u32, 1); + // hal_espressif_rs::rust_helper_esp_cpu_inter_enable(1 << TARGET0_INT_NUM); + // hal_espressif_rs::rust_helper_esp_cpu_intr_set_priority(TARGET0_INT_NUM as i32, 1); + } // From now on, all work will be done by core 0. // if arch::current_cpu_id() != 0 { // scheduler::wait_and_then_start_schedule(); // unreachable!("Secondary cores should have jumped to the scheduler"); // } - // Enable UART0 in PLIC. + // Enable TARGET0 in PLIC. // PLIC.enable( // arch::current_cpu_id(), - // u32::try_from(usize::from(config::UART0_IRQ)) - // .expect("usize(64 bits) converts to u32 failed"), + // u32::try_from(16usize).expect("usize(64 bits) converts to u32 failed"), // ); - // Set UART0 priority in PLIC. + // Set TARGET0 priority in PLIC. // PLIC.set_priority( - // u32::try_from(usize::from(config::UART0_IRQ)) - // .expect("usize(64 bits) converts to u32 failed"), + // u32::try_from(16usize).expect("usize(64 bits) converts to u32 failed"), // 1, // ); } crate::define_peripheral! { - (console_uart, blueos_driver::uart::dumb::DumbUart, - blueos_driver::uart::dumb::DumbUart), + (console_uart, blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial, + blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial), } crate::define_pin_states!(None); @@ -87,3 +159,24 @@ pub(crate) fn send_ipi(_hart: usize) {} #[inline(always)] pub(crate) fn clear_ipi(_hart: usize) {} + +// #[no_mangle] +// pub unsafe extern "C" fn test_memory() { +// let mut v: u32 = 0; +// let addr_reg_0 = 0x3c000004usize as *const u32; +// let addr_reg_1 = 0x3c010004usize as *const u32; +// let addr_reg_3 = 0x3c018004usize as *const u32; +// let addr_reg_4 = 0x3c0182c0usize as *const u32; +// core::arch::asm!( +// "lw {out}, 0({addr_reg_0})", +// "lw {out}, 0({addr_reg_1})", +// "lw {out}, 0({addr_reg_3})", +// "lw {out}, 0({addr_reg_4})", +// out = out(reg) v, +// addr_reg_0 = in(reg) addr_reg_0, +// addr_reg_1 = in(reg) addr_reg_1, +// addr_reg_3 = in(reg) addr_reg_3, +// addr_reg_4 = in(reg) addr_reg_4, +// options(nostack, preserves_flags), +// ); +// } diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index b1c2479a..e170e04b 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -165,6 +165,10 @@ extern "C" fn init() { #[cfg(enable_vfs)] init_vfs(); init_apps(); + use crate::time::Tick; + let now = Tick::now(); + crate::kprintln!("Kernel initialized successfully! Uptime: {}", now.0); + Tick::interrupt_after(Tick::from_millis(100)); arch::start_schedule(scheduler::schedule); unreachable!("We should have jumped to the schedule loop!"); } diff --git a/kernel/src/devices/clock.rs b/kernel/src/devices/clock.rs index 02371270..82f6a56c 100644 --- a/kernel/src/devices/clock.rs +++ b/kernel/src/devices/clock.rs @@ -12,20 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// We use the term `cycles` to refer to the internal counter of the Clock. We -// use the term `hz` to descripe how many cycles within a second. Tick is -// defined as a short period of time, which is atomic in the system, just like -// the Planck time in physical world. We use `TICKS_PER_SECOND` to measure it. -// A clock instance should be able to interrupt the system. -pub trait Clock { - fn hz() -> u64; - // Reading the current counter of the Clock requires some time(Time - // Drifting), we can only estimate it. - fn estimate_current_cycles() -> u64; - fn interrupt_at(moment: u64); - fn stop(); -} - #[cfg(target_arch = "aarch64")] pub(crate) mod gic_generic_timer; #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] diff --git a/kernel/src/devices/clock/gic_generic_timer.rs b/kernel/src/devices/clock/gic_generic_timer.rs index 3202b7eb..42abfeda 100644 --- a/kernel/src/devices/clock/gic_generic_timer.rs +++ b/kernel/src/devices/clock/gic_generic_timer.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{devices::clock::Clock, drivers::timer::GenericTimer}; - +use crate::drivers::timer::GenericTimer; +use blueos_hal::clock::Clock; pub struct GenericClock; impl Clock for GenericClock { diff --git a/kernel/src/devices/clock/riscv_clock.rs b/kernel/src/devices/clock/riscv_clock.rs index 119ffc7c..fb11477d 100644 --- a/kernel/src/devices/clock/riscv_clock.rs +++ b/kernel/src/devices/clock/riscv_clock.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{arch, devices::clock::Clock, drivers::timer::RiscvTimer}; - +use crate::{arch, drivers::timer::RiscvTimer}; +use blueos_hal::clock::Clock; pub struct RiscvClock; impl RiscvTimer diff --git a/kernel/src/devices/clock/systick.rs b/kernel/src/devices/clock/systick.rs index 1d250411..f653b0c1 100644 --- a/kernel/src/devices/clock/systick.rs +++ b/kernel/src/devices/clock/systick.rs @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{arch, arch::irq::IRQ_PRIORITY_FOR_SCHEDULER, devices::clock::Clock}; +use crate::{arch, arch::irq::IRQ_PRIORITY_FOR_SCHEDULER}; +use blueos_hal::clock::Clock; use core::sync::atomic::{AtomicUsize, Ordering}; use cortex_m::peripheral::{scb::SystemHandler, syst::SystClkSource, SCB, SYST}; diff --git a/kernel/src/devices/tty/serial/mod.rs b/kernel/src/devices/tty/serial/mod.rs index 7a353f7f..58b493b7 100644 --- a/kernel/src/devices/tty/serial/mod.rs +++ b/kernel/src/devices/tty/serial/mod.rs @@ -534,7 +534,11 @@ impl Device for Serial { } fn write(&self, _pos: u64, buf: &[u8], is_nonblocking: bool) -> Result { - self.fifo_tx(buf, is_nonblocking).map_err(ErrorKind::from) + // self.fifo_tx(buf, is_nonblocking).map_err(ErrorKind::from) + self.uart_ops + .irqsave_lock() + .write(buf) + .map_err(ErrorKind::from) } fn ioctl(&self, request: u32, arg: usize) -> Result<(), ErrorKind> { diff --git a/kernel/src/scheduler/mod.rs b/kernel/src/scheduler/mod.rs index 31f14587..0d691445 100644 --- a/kernel/src/scheduler/mod.rs +++ b/kernel/src/scheduler/mod.rs @@ -440,7 +440,9 @@ pub extern "C" fn schedule() -> ! { debug_assert!(arch::local_irq_enabled()); loop { yield_me(); - idle::get_idle_hook()(); + crate::kprintln!("running idle hook"); + // idle::get_idle_hook()(); + crate::kprintln!("returned from idle hook"); } } diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index 3eb7a0bd..768f606c 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -41,7 +41,10 @@ typedef unsigned long uintptr_t; typedef long intptr_t; +#if __STDC_VERSION__ >= 202311L +#else typedef unsigned char bool; +#endif typedef unsigned long size_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; @@ -72,9 +75,9 @@ extern void enable_local_irq_restore(size_t); #pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load) #pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store) #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) -#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ +#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ __atomic_compare_exchange) -#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ +#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ __atomic_is_lock_free) #ifdef HAS_LOCK_FREE_CAS @@ -95,13 +98,15 @@ _Static_assert(__atomic_always_lock_free(sizeof(uintptr_t), 0), "Implementation assumes lock-free pointer-size cmpxchg"); typedef _Atomic(uintptr_t) Lock; /// Unlock a lock. This is a release operation. -__inline static void unlock(Lock *l, size_t irq_status) { +__inline static void unlock(Lock *l, size_t irq_status) +{ __c11_atomic_store(l, 0, __ATOMIC_RELEASE); enable_local_irq_restore(irq_status); } /// Locks a lock. In the current implementation, this is potentially /// unbounded in the contended case. -__inline static size_t lock(Lock *l) { +__inline static size_t lock(Lock *l) +{ size_t irq_status = disable_local_irq_save(); uintptr_t old = 0; while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE, @@ -113,7 +118,8 @@ __inline static size_t lock(Lock *l) { static Lock locks[SPINLOCK_COUNT]; /// Returns a lock to use for a given pointer. -static __inline Lock *lock_for_pointer(void *ptr) { +static __inline Lock *lock_for_pointer(void *ptr) +{ intptr_t hash = (intptr_t)ptr; // Disregard the lowest 4 bits. We want all values that may be part of the // same memory operation to hash to the same value and therefore use the same @@ -135,11 +141,13 @@ typedef int Lock; static __inline Lock *lock_for_pointer(void *ptr) { return 0; } -__inline static void unlock(Lock *l, size_t irq_status) { +__inline static void unlock(Lock *l, size_t irq_status) +{ enable_local_irq_restore(irq_status); } -__inline static size_t lock(Lock *l) { +__inline static size_t lock(Lock *l) +{ size_t irq_status = disable_local_irq_save(); return irq_status; } @@ -147,8 +155,8 @@ __inline static size_t lock(Lock *l) { #endif // HAS_LOCK_FREE_CAS /// Macros for determining whether a size is lock free. -#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p) \ - (__atomic_always_lock_free(size, p) || \ +#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p) \ + (__atomic_always_lock_free(size, p) || \ (__atomic_always_lock_free(size, 0) && ((uintptr_t)p % size) == 0)) #define IS_LOCK_FREE_1(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(1, p) #define IS_LOCK_FREE_2(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(2, p) @@ -158,11 +166,12 @@ __inline static size_t lock(Lock *l) { /// Macro that calls the compiler-generated lock-free versions of functions /// when they exist. -#define TRY_LOCK_FREE_CASE(n, type, ptr) \ - case n: \ - if (IS_LOCK_FREE_##n(ptr)) { \ - LOCK_FREE_ACTION(type); \ - } \ +#define TRY_LOCK_FREE_CASE(n, type, ptr) \ + case n: \ + if (IS_LOCK_FREE_##n(ptr)) \ + { \ + LOCK_FREE_ACTION(type); \ + } \ break; #ifdef __SIZEOF_INT128__ #define TRY_LOCK_FREE_CASE_16(p) TRY_LOCK_FREE_CASE(16, __uint128_t, p) @@ -170,21 +179,24 @@ __inline static size_t lock(Lock *l) { #define TRY_LOCK_FREE_CASE_16(p) /* __uint128_t not available */ #endif -#define LOCK_FREE_CASES(ptr) \ - do { \ - switch (size) { \ - TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \ - TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \ - TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \ - TRY_LOCK_FREE_CASE(8, uint64_t, ptr) \ - TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */ \ - default: \ - break; \ - } \ +#define LOCK_FREE_CASES(ptr) \ + do \ + { \ + switch (size) \ + { \ + TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \ + TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \ + TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \ + TRY_LOCK_FREE_CASE(8, uint64_t, ptr) \ + TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */ \ + default: \ + break; \ + } \ } while (0) /// Whether atomic operations for the given size (and alignment) are lock-free. -bool __atomic_is_lock_free_c(size_t size, void *ptr) { +bool __atomic_is_lock_free_c(size_t size, void *ptr) +{ #define LOCK_FREE_ACTION(type) return true; LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION @@ -193,9 +205,10 @@ bool __atomic_is_lock_free_c(size_t size, void *ptr) { /// An atomic load operation. This is atomic with respect to the source /// pointer only. -void __atomic_load_c(int size, void *src, void *dest, int model) { -#define LOCK_FREE_ACTION(type) \ - *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ +void __atomic_load_c(int size, void *src, void *dest, int model) +{ +#define LOCK_FREE_ACTION(type) \ + *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ return; LOCK_FREE_CASES(src); #undef LOCK_FREE_ACTION @@ -207,9 +220,10 @@ void __atomic_load_c(int size, void *src, void *dest, int model) { /// An atomic store operation. This is atomic with respect to the destination /// pointer only. -void __atomic_store_c(int size, void *dest, void *src, int model) { -#define LOCK_FREE_ACTION(type) \ - __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ +void __atomic_store_c(int size, void *dest, void *src, int model) +{ +#define LOCK_FREE_ACTION(type) \ + __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ return; LOCK_FREE_CASES(dest); #undef LOCK_FREE_ACTION @@ -225,16 +239,18 @@ void __atomic_store_c(int size, void *dest, void *src, int model) { /// /// This function returns 1 if the exchange takes place or 0 if it fails. int __atomic_compare_exchange_c(int size, void *ptr, void *expected, - void *desired, int success, int failure) { -#define LOCK_FREE_ACTION(type) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ + void *desired, int success, int failure) +{ +#define LOCK_FREE_ACTION(type) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ failure) LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(ptr); size_t irq = lock(l); - if (memcmp(ptr, expected, size) == 0) { + if (memcmp(ptr, expected, size) == 0) + { memcpy(ptr, desired, size); unlock(l, irq); return 1; @@ -246,10 +262,11 @@ int __atomic_compare_exchange_c(int size, void *ptr, void *expected, /// Performs an atomic exchange operation between two pointers. This is atomic /// with respect to the target address. -void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { -#define LOCK_FREE_ACTION(type) \ - *(type *)old = \ - __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \ +void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) +{ +#define LOCK_FREE_ACTION(type) \ + *(type *)old = \ + __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \ return; LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION @@ -265,78 +282,84 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { // specialised versions of the above functions. //////////////////////////////////////////////////////////////////////////////// #ifdef __SIZEOF_INT128__ -#define OPTIMISED_CASES \ - OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ - OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ - OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ - OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) \ +#define OPTIMISED_CASES \ + OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ + OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ + OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ + OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) \ OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t) #else -#define OPTIMISED_CASES \ - OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ - OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ - OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ +#define OPTIMISED_CASES \ + OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ + OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ + OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) #endif -#define OPTIMISED_CASE(n, lockfree, type) \ - type __atomic_load_##n(type *src, int model) { \ - if (lockfree(src)) \ - return __c11_atomic_load((_Atomic(type) *)src, model); \ - Lock *l = lock_for_pointer(src); \ - size_t irq = lock(l); \ - type val = *src; \ - unlock(l, irq); \ - return val; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + type __atomic_load_##n(type *src, int model) \ + { \ + if (lockfree(src)) \ + return __c11_atomic_load((_Atomic(type) *)src, model); \ + Lock *l = lock_for_pointer(src); \ + size_t irq = lock(l); \ + type val = *src; \ + unlock(l, irq); \ + return val; \ } OPTIMISED_CASES #undef OPTIMISED_CASE -#define OPTIMISED_CASE(n, lockfree, type) \ - void __atomic_store_##n(type *dest, type val, int model) { \ - if (lockfree(dest)) { \ - __c11_atomic_store((_Atomic(type) *)dest, val, model); \ - return; \ - } \ - Lock *l = lock_for_pointer(dest); \ - size_t irq = lock(l); \ - *dest = val; \ - unlock(l, irq); \ - return; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + void __atomic_store_##n(type *dest, type val, int model) \ + { \ + if (lockfree(dest)) \ + { \ + __c11_atomic_store((_Atomic(type) *)dest, val, model); \ + return; \ + } \ + Lock *l = lock_for_pointer(dest); \ + size_t irq = lock(l); \ + *dest = val; \ + unlock(l, irq); \ + return; \ } OPTIMISED_CASES #undef OPTIMISED_CASE -#define OPTIMISED_CASE(n, lockfree, type) \ - type __atomic_exchange_##n(type *dest, type val, int model) { \ - if (lockfree(dest)) \ - return __c11_atomic_exchange((_Atomic(type) *)dest, val, model); \ - Lock *l = lock_for_pointer(dest); \ - size_t irq = lock(l); \ - type tmp = *dest; \ - *dest = val; \ - unlock(l, irq); \ - return tmp; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + type __atomic_exchange_##n(type *dest, type val, int model) \ + { \ + if (lockfree(dest)) \ + return __c11_atomic_exchange((_Atomic(type) *)dest, val, model); \ + Lock *l = lock_for_pointer(dest); \ + size_t irq = lock(l); \ + type tmp = *dest; \ + *dest = val; \ + unlock(l, irq); \ + return tmp; \ } OPTIMISED_CASES #undef OPTIMISED_CASE -#define OPTIMISED_CASE(n, lockfree, type) \ - bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \ - int success, int failure) { \ - if (lockfree(ptr)) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, expected, desired, success, failure); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - if (*ptr == *expected) { \ - *ptr = desired; \ - unlock(l, irq); \ - return true; \ - } \ - *expected = *ptr; \ - unlock(l, irq); \ - return false; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \ + int success, int failure) \ + { \ + if (lockfree(ptr)) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, expected, desired, success, failure); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + if (*ptr == *expected) \ + { \ + *ptr = desired; \ + unlock(l, irq); \ + return true; \ + } \ + *expected = *ptr; \ + unlock(l, irq); \ + return false; \ } OPTIMISED_CASES #undef OPTIMISED_CASE @@ -344,28 +367,30 @@ OPTIMISED_CASES //////////////////////////////////////////////////////////////////////////////// // Atomic read-modify-write operations for integers of various sizes. //////////////////////////////////////////////////////////////////////////////// -#define ATOMIC_RMW(n, lockfree, type, opname, op) \ - type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) { \ - if (lockfree(ptr)) \ - return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - type tmp = *ptr; \ - *ptr = tmp op val; \ - unlock(l, irq); \ - return tmp; \ +#define ATOMIC_RMW(n, lockfree, type, opname, op) \ + type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) \ + { \ + if (lockfree(ptr)) \ + return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + type tmp = *ptr; \ + *ptr = tmp op val; \ + unlock(l, irq); \ + return tmp; \ } -#define ATOMIC_RMW_NAND(n, lockfree, type) \ - type __atomic_fetch_nand_##n(type *ptr, type val, int model) { \ - if (lockfree(ptr)) \ - return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - type tmp = *ptr; \ - *ptr = ~(tmp & val); \ - unlock(l, irq); \ - return tmp; \ +#define ATOMIC_RMW_NAND(n, lockfree, type) \ + type __atomic_fetch_nand_##n(type *ptr, type val, int model) \ + { \ + if (lockfree(ptr)) \ + return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + type tmp = *ptr; \ + *ptr = ~(tmp & val); \ + unlock(l, irq); \ + return tmp; \ } #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) diff --git a/kernel/src/time.rs b/kernel/src/time.rs index 929e49c2..a64b96df 100644 --- a/kernel/src/time.rs +++ b/kernel/src/time.rs @@ -20,7 +20,7 @@ use blueos_kconfig::CONFIG_TICKS_PER_SECOND as TICKS_PER_SECOND; use core::time::Duration; // ClockImpl should be provided by each board. pub use crate::boards::ClockImpl; -use crate::devices::clock::Clock; +use blueos_hal::clock::Clock; #[derive(Default, Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] pub struct Tick(pub usize); @@ -76,6 +76,7 @@ impl Tick { } pub fn interrupt_at(n: Tick) { + crate::kprintln!("Set clock interrupt at tick {:?}", n); let _guard = DisableInterruptGuard::new(); if n == Self::MAX { ClockImpl::stop(); diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 70a332ff..52d97223 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -590,7 +590,8 @@ mod tests { #[test] fn test_timer_accuracy() { - use crate::{boards::ClockImpl, devices::clock::Clock}; + use crate::boards::ClockImpl; + use blueos_hal::clock::Clock; let start = ClockImpl::estimate_current_cycles(); scheduler::suspend_me_for::<()>( Tick(blueos_kconfig::CONFIG_TICKS_PER_SECOND as usize), From bec8df540fef338fe42ddfc6dea43bb728b4fad5 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Thu, 12 Feb 2026 11:40:13 +0800 Subject: [PATCH 06/53] wip --- driver/src/systimer/esp32_sys_timer.rs | 53 +++++++++++++------------- kernel/src/arch/riscv/trap.rs | 6 +-- kernel/src/boot.rs | 4 -- kernel/src/scheduler/mod.rs | 4 +- kernel/src/thread/builder.rs | 13 ++++++- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index 67c8712d..1b1dbba5 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -140,19 +140,19 @@ impl Esp32SysTimer { pub fn init() { // enable unit 0 - Self::registers().conf.modify(CONF::UNIT0_WORK_EN::SET); + // Self::registers().conf.modify(CONF::UNIT0_WORK_EN::SET); // select unit 0 vs comparator 0 - Self::set_unit(); + // Self::set_unit(); // enable comparator 0 - Self::set_comparator_enable(true); + // Self::set_comparator_enable(true); // CLR interrupt // Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); // enable interrupt - Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); + // Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); // set TARGET mode - Self::registers() - .target0_conf - .modify(TARGET_CONF::PERIOD_MODE::CLEAR); + // Self::registers() + // .target0_conf + // .modify(TARGET_CONF::PERIOD_MODE::CLEAR); } fn set_unit() { @@ -176,25 +176,26 @@ impl Clock for Esp32SysTimer u64 { - Self::registers().unit0_op.modify(UNIT_OP::UPDATE::SET); - while !Self::registers().unit0_op.is_set(UNIT_OP::VALUE_VALID) {} - - let mut lo_prev = Self::registers() - .unit0_value_lo - .read(UNIT_VALUE_LO::VALUE_LO); - loop { - let lo = lo_prev; - let hi = Self::registers() - .unit0_value_hi - .read(UNIT_VALUE_HI::VALUE_HI); - lo_prev = Self::registers() - .unit0_value_lo - .read(UNIT_VALUE_LO::VALUE_LO); - - if lo == lo_prev { - return ((hi as u64) << 32) | lo as u64; - } - } + 0 + // Self::registers().unit0_op.modify(UNIT_OP::UPDATE::SET); + // while !Self::registers().unit0_op.is_set(UNIT_OP::VALUE_VALID) {} + + // let mut lo_prev = Self::registers() + // .unit0_value_lo + // .read(UNIT_VALUE_LO::VALUE_LO); + // loop { + // let lo = lo_prev; + // let hi = Self::registers() + // .unit0_value_hi + // .read(UNIT_VALUE_HI::VALUE_HI); + // lo_prev = Self::registers() + // .unit0_value_lo + // .read(UNIT_VALUE_LO::VALUE_LO); + + // if lo == lo_prev { + // return ((hi as u64) << 32) | lo as u64; + // } + // } } fn hz() -> u64 { diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index 41a96f9f..c0360aeb 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -243,11 +243,7 @@ extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: crate::time::handle_clock_interrupt(); might_switch_context(ctx, cont) } - // ECALL => handle_ecall(ctx, cont), - ECALL => { - ctx.mepc += 4; - sp - } + ECALL => handle_ecall(ctx, cont), // For waking up from wfi. MSI => { clear_ipi(arch::current_cpu_id()); diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index e170e04b..b1c2479a 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -165,10 +165,6 @@ extern "C" fn init() { #[cfg(enable_vfs)] init_vfs(); init_apps(); - use crate::time::Tick; - let now = Tick::now(); - crate::kprintln!("Kernel initialized successfully! Uptime: {}", now.0); - Tick::interrupt_after(Tick::from_millis(100)); arch::start_schedule(scheduler::schedule); unreachable!("We should have jumped to the schedule loop!"); } diff --git a/kernel/src/scheduler/mod.rs b/kernel/src/scheduler/mod.rs index 0d691445..711d4a32 100644 --- a/kernel/src/scheduler/mod.rs +++ b/kernel/src/scheduler/mod.rs @@ -291,6 +291,7 @@ fn inner_yield(next: ThreadNode) { old.disable_preempt(); if Thread::id(old) == Thread::id(idle::current_idle_thread_ref()) { let ok = old.transfer_state(thread::RUNNING, thread::READY); + crate::kprintln!("ok = {:?}", ok); debug_assert_eq!(ok, Ok(())); } else { let ok = queue_ready_thread(thread::RUNNING, unsafe { Arc::clone_from(old) }); @@ -440,9 +441,10 @@ pub extern "C" fn schedule() -> ! { debug_assert!(arch::local_irq_enabled()); loop { yield_me(); + // crate::arch::ecall_switch_context_with_hook(core::ptr::null_mut()); crate::kprintln!("running idle hook"); // idle::get_idle_hook()(); - crate::kprintln!("returned from idle hook"); + // crate::kprintln!("returned from idle hook"); } } diff --git a/kernel/src/thread/builder.rs b/kernel/src/thread/builder.rs index 9ce85cf1..bdeda2c2 100644 --- a/kernel/src/thread/builder.rs +++ b/kernel/src/thread/builder.rs @@ -193,10 +193,13 @@ pub(crate) fn build_static_thread( kind: ThreadKind, ) -> ThreadNode { let inner = &s.arc; + let stack_size = s.stack.rep.len(); + let stack_base = s.stack.rep.as_ptr() as usize; let stack = &mut s.stack; + let arc = unsafe { ThreadNode::from_static_inner_ref(inner) }; debug_assert_eq!(ThreadNode::strong_count(&arc), 1); - let _id = Thread::id(&arc); + let id = Thread::id(&arc); let mut w = arc.lock(); let Some(stack) = Stack::from_raw(stack.rep.as_mut_ptr(), stack.rep.len()) else { panic!("Invalid stack"); @@ -215,6 +218,14 @@ pub(crate) fn build_static_thread( stack.rep.len(), core::mem::size_of::(), ); + crate::kprintln!( + "System thread 0x{:x} created: sp: 0x{:x}, context size: {}, stack size: {}, stack base: 0x{:x}", + id, + w.saved_sp(), + core::mem::size_of::(), + stack_size, + stack_base + ); drop(w); t.write(arc.clone()); GlobalQueueVisitor::add(arc.clone()); From 79313eea826f1ac941cc699c6b801f3eec629107 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Thu, 12 Feb 2026 18:25:06 +0800 Subject: [PATCH 07/53] minor --- driver/src/systimer/esp32_sys_timer.rs | 60 ++++++++++--------- .../config/seeed_xiao_esp32c3/debug/defconfig | 2 +- .../seeed_xiao_esp32c3/release/defconfig | 2 +- kernel/src/arch/riscv/trap.rs | 6 +- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 19 +++++- kernel/src/boot.rs | 20 +++++++ kernel/src/scheduler/mod.rs | 6 +- kernel/src/thread/builder.rs | 10 +--- kernel/src/time.rs | 2 +- 9 files changed, 78 insertions(+), 49 deletions(-) diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index 1b1dbba5..5850496c 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -140,19 +140,24 @@ impl Esp32SysTimer { pub fn init() { // enable unit 0 - // Self::registers().conf.modify(CONF::UNIT0_WORK_EN::SET); + Self::registers().conf.modify(CONF::UNIT0_WORK_EN::SET); // select unit 0 vs comparator 0 - // Self::set_unit(); + Self::set_unit(); // enable comparator 0 - // Self::set_comparator_enable(true); + Self::set_comparator_enable(true); // CLR interrupt // Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); // enable interrupt - // Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); + Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); // set TARGET mode - // Self::registers() - // .target0_conf - // .modify(TARGET_CONF::PERIOD_MODE::CLEAR); + Self::registers() + .target0_conf + .modify(TARGET_CONF::PERIOD_MODE::CLEAR); + } + + #[inline] + pub fn clr_interrupt() { + Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); } fn set_unit() { @@ -176,26 +181,25 @@ impl Clock for Esp32SysTimer u64 { - 0 - // Self::registers().unit0_op.modify(UNIT_OP::UPDATE::SET); - // while !Self::registers().unit0_op.is_set(UNIT_OP::VALUE_VALID) {} - - // let mut lo_prev = Self::registers() - // .unit0_value_lo - // .read(UNIT_VALUE_LO::VALUE_LO); - // loop { - // let lo = lo_prev; - // let hi = Self::registers() - // .unit0_value_hi - // .read(UNIT_VALUE_HI::VALUE_HI); - // lo_prev = Self::registers() - // .unit0_value_lo - // .read(UNIT_VALUE_LO::VALUE_LO); - - // if lo == lo_prev { - // return ((hi as u64) << 32) | lo as u64; - // } - // } + Self::registers().unit0_op.modify(UNIT_OP::UPDATE::SET); + while !Self::registers().unit0_op.is_set(UNIT_OP::VALUE_VALID) {} + + let mut lo_prev = Self::registers() + .unit0_value_lo + .read(UNIT_VALUE_LO::VALUE_LO); + loop { + let lo = lo_prev; + let hi = Self::registers() + .unit0_value_hi + .read(UNIT_VALUE_HI::VALUE_HI); + lo_prev = Self::registers() + .unit0_value_lo + .read(UNIT_VALUE_LO::VALUE_LO); + + if lo == lo_prev { + return ((hi as u64) << 32) | lo as u64; + } + } } fn hz() -> u64 { @@ -208,7 +212,7 @@ impl Clock for Esp32SysTimer> 32) as u32)); Self::registers() .target0_lo - .write(TARGET_LO::LO.val(moment as u32)); + .write(TARGET_LO::LO.val((moment & 0xFFFF_FFFF) as u32)); // load comparator Self::registers().comp0_load.write(COMP_LOAD::LOAD::SET); } diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index 60f7d914..349fc421 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -29,6 +29,6 @@ CONFIG_ENABLE_SYSCALL=y # CONFIG_VIRTIO is not set CONFIG_SERIAL_RX_FIFO_SIZE=256 CONFIG_SERIAL_TX_FIFO_SIZE=256 -CONFIG_ENABLE_VFS=n +CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n diff --git a/kconfig/config/seeed_xiao_esp32c3/release/defconfig b/kconfig/config/seeed_xiao_esp32c3/release/defconfig index f8df3ade..f2d36a7e 100644 --- a/kconfig/config/seeed_xiao_esp32c3/release/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/release/defconfig @@ -29,6 +29,6 @@ CONFIG_ENABLE_SYSCALL=y # CONFIG_VIRTIO is not set CONFIG_SERIAL_RX_FIFO_SIZE=256 CONFIG_SERIAL_TX_FIFO_SIZE=256 -CONFIG_ENABLE_VFS=n +CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index c0360aeb..48fd4283 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -233,12 +233,16 @@ fn might_switch_context(from: &Context, ra: usize) -> usize { extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: usize) -> usize { debug_assert!(!super::local_irq_enabled()); let sp = ctx as *const _ as usize; - crate::kprintln!("mcause: 0x{:x}, mepc: 0x{:x}", mcause, ctx.mepc); match mcause & (INTERRUPT_MASK | 0x3f) { EXTERN_INT => { handle_plic_irq(ctx, mcause, mtval); might_switch_context(ctx, cont) } + _ if mcause & 0x8000_0000 != 0 => { + // esp32c3 has another external interrupt number + handle_plic_irq(ctx, mcause, mtval); + might_switch_context(ctx, cont) + } TIMER_INT => { crate::time::handle_clock_interrupt(); might_switch_context(ctx, cont) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 91f28dd2..0dc6dda4 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -97,7 +97,14 @@ fn init_vector_table() { pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { let cpu_id = arch::current_cpu_id(); - PLIC.complete(cpu_id, PLIC.claim(cpu_id)) + match mcause & 0xff { + TARGET0_INT_NUM => { + ClockImpl::clr_interrupt(); + crate::kprintln!("Handle TARGET0 interrupt"); + } + _ => {} + } + // PLIC.complete(cpu_id, PLIC.claim(cpu_id)) } static STAGING: SmpStagedInit = SmpStagedInit::new(); @@ -106,8 +113,10 @@ const INTR_BASE: usize = 0x600c_2000; const TARGET0_INT_MAP_REG: usize = INTR_BASE + 0x94; const INT_ENABLE_REG: usize = INTR_BASE + 0x104; const INT_THRESH_REG: usize = INTR_BASE + 0x194; -const TARGET0_INT_NUM: usize = 1; // IRQ number 16 in target0 +const TARGET0_INT_NUM: usize = 16; // IRQ number 16 in target0 const CLOCK_GATE_REG: usize = INTR_BASE + 0x100; +const INT_PRI_16_REG: usize = INTR_BASE + 0x154; +const INT_TYPE_REG: usize = INTR_BASE + 0x108; pub(crate) fn init() { assert!(!local_irq_enabled()); @@ -125,8 +134,12 @@ pub(crate) fn init() { unsafe { core::ptr::write_volatile(CLOCK_GATE_REG as *mut u32, 1); core::ptr::write_volatile(TARGET0_INT_MAP_REG as *mut u32, TARGET0_INT_NUM as u32); - core::ptr::write_volatile(INT_ENABLE_REG as *mut u32, 0xFFFF_FFFF); + core::ptr::write_volatile(INT_TYPE_REG as *mut u32, 1); // edge interrupt avoid for spurious interrupt core::ptr::write_volatile(INT_THRESH_REG as *mut u32, 1); + core::ptr::write_volatile(INT_PRI_16_REG as *mut u32, 15); + core::ptr::write_volatile((INT_PRI_16_REG + 0x4) as *mut u32, 15); + core::ptr::write_volatile((INT_PRI_16_REG - 0x4) as *mut u32, 15); + core::ptr::write_volatile(INT_ENABLE_REG as *mut u32, 0xFFFF_FFFF); // hal_espressif_rs::rust_helper_esp_cpu_inter_enable(1 << TARGET0_INT_NUM); // hal_espressif_rs::rust_helper_esp_cpu_intr_set_priority(TARGET0_INT_NUM as i32, 1); } diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index b1c2479a..e73d3ca0 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -165,10 +165,30 @@ extern "C" fn init() { #[cfg(enable_vfs)] init_vfs(); init_apps(); + use crate::time::Tick; + + enable_mie(); + Tick::interrupt_after(Tick::from_millis(100)); + for i in 0..100 { + let now = Tick::now(); + crate::kprintln!("System booted at tick {:?}", now); + } + Tick::interrupt_after(Tick::from_millis(100)); + loop {} arch::start_schedule(scheduler::schedule); unreachable!("We should have jumped to the schedule loop!"); } +pub fn enable_mie() { + unsafe { + core::arch::asm!( + "csrrs zero, mstatus, {mask}", + mask = const 1 << 3, // MIE 位是 bit 3 + options(nomem, preserves_flags), + ); + } +} + pub(crate) fn init_runtime() { init_bss(); run_init_array(); diff --git a/kernel/src/scheduler/mod.rs b/kernel/src/scheduler/mod.rs index 711d4a32..31f14587 100644 --- a/kernel/src/scheduler/mod.rs +++ b/kernel/src/scheduler/mod.rs @@ -291,7 +291,6 @@ fn inner_yield(next: ThreadNode) { old.disable_preempt(); if Thread::id(old) == Thread::id(idle::current_idle_thread_ref()) { let ok = old.transfer_state(thread::RUNNING, thread::READY); - crate::kprintln!("ok = {:?}", ok); debug_assert_eq!(ok, Ok(())); } else { let ok = queue_ready_thread(thread::RUNNING, unsafe { Arc::clone_from(old) }); @@ -441,10 +440,7 @@ pub extern "C" fn schedule() -> ! { debug_assert!(arch::local_irq_enabled()); loop { yield_me(); - // crate::arch::ecall_switch_context_with_hook(core::ptr::null_mut()); - crate::kprintln!("running idle hook"); - // idle::get_idle_hook()(); - // crate::kprintln!("returned from idle hook"); + idle::get_idle_hook()(); } } diff --git a/kernel/src/thread/builder.rs b/kernel/src/thread/builder.rs index bdeda2c2..5758202c 100644 --- a/kernel/src/thread/builder.rs +++ b/kernel/src/thread/builder.rs @@ -193,7 +193,7 @@ pub(crate) fn build_static_thread( kind: ThreadKind, ) -> ThreadNode { let inner = &s.arc; - let stack_size = s.stack.rep.len(); + let stack_size = s.stack.rep.len(); let stack_base = s.stack.rep.as_ptr() as usize; let stack = &mut s.stack; @@ -218,14 +218,6 @@ pub(crate) fn build_static_thread( stack.rep.len(), core::mem::size_of::(), ); - crate::kprintln!( - "System thread 0x{:x} created: sp: 0x{:x}, context size: {}, stack size: {}, stack base: 0x{:x}", - id, - w.saved_sp(), - core::mem::size_of::(), - stack_size, - stack_base - ); drop(w); t.write(arc.clone()); GlobalQueueVisitor::add(arc.clone()); diff --git a/kernel/src/time.rs b/kernel/src/time.rs index a64b96df..ca1fbafb 100644 --- a/kernel/src/time.rs +++ b/kernel/src/time.rs @@ -76,7 +76,7 @@ impl Tick { } pub fn interrupt_at(n: Tick) { - crate::kprintln!("Set clock interrupt at tick {:?}", n); + crate::kprintln!("Set interrupt at tick {:?}", n); let _guard = DisableInterruptGuard::new(); if n == Self::MAX { ClockImpl::stop(); From da54624b6a19e08af2262e45cf9a024c4e662c7a Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 24 Feb 2026 14:02:35 +0800 Subject: [PATCH 08/53] add intr --- driver/src/systimer/esp32_sys_timer.rs | 7 +- driver/src/uart/esp32_usb_serial.rs | 142 +++++++++++++++++++- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 71 +++++----- kernel/src/boot.rs | 19 --- 4 files changed, 178 insertions(+), 61 deletions(-) diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index 5850496c..fbfb16a9 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -140,13 +140,13 @@ impl Esp32SysTimer { pub fn init() { // enable unit 0 + Self::registers().conf.modify(CONF::CLK_EN::SET); Self::registers().conf.modify(CONF::UNIT0_WORK_EN::SET); + Self::registers().conf.modify(CONF::TARGET0_WORK_EN::CLEAR); // select unit 0 vs comparator 0 Self::set_unit(); - // enable comparator 0 - Self::set_comparator_enable(true); // CLR interrupt - // Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); + Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); // enable interrupt Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); // set TARGET mode @@ -215,6 +215,7 @@ impl Clock for Esp32SysTimer ep1_reg: ReadWrite), (0x04 => ep1_conf_reg: ReadWrite), - (0x08 => _reserved0), + (0x08 => int_raw_reg: ReadWrite), + (0x0c => int_st_reg: ReadWrite), + (0x10 => int_ena_reg: ReadWrite), + (0x14 => int_clr_reg: ReadWrite), + (0x18 => _reserved1), (0x20 => jfifo_st_reg: ReadWrite), (0x24 => @END), } @@ -78,11 +144,21 @@ register_structs! { const USB_SERIAL_BASE: StaticRef = unsafe { StaticRef::new(0x6004_3000 as *const Registers) }; -pub struct Esp32UsbSerial; +pub struct Esp32UsbSerial { + pub intr_handler: UnsafeCell>, +} unsafe impl Send for Esp32UsbSerial {} unsafe impl Sync for Esp32UsbSerial {} +impl Esp32UsbSerial { + pub const fn new() -> Self { + Self { + intr_handler: UnsafeCell::new(None), + } + } +} + impl Configuration for Esp32UsbSerial { type Target = (); fn configure(&self, param: &super::UartConfig) -> blueos_hal::err::Result { @@ -147,23 +223,75 @@ impl HasInterruptReg for Esp32UsbSerial { type InterruptType = super::InterruptType; fn enable_interrupt(&self, intr: Self::InterruptType) { - // Not supported + match intr { + super::InterruptType::Rx => { + USB_SERIAL_BASE + .int_ena_reg + .modify(INT_ENA_REG::SERIAL_OUT_RECV_PKT::SET); + } + super::InterruptType::Tx => { + USB_SERIAL_BASE + .int_ena_reg + .modify(INT_ENA_REG::SERIAL_IN_EMPTY::SET); + } + _ => {} + } } fn disable_interrupt(&self, intr: Self::InterruptType) { - // Not supported + match intr { + super::InterruptType::Tx => { + USB_SERIAL_BASE + .int_ena_reg + .modify(INT_ENA_REG::SERIAL_IN_EMPTY::CLEAR); + } + super::InterruptType::Rx => { + USB_SERIAL_BASE + .int_ena_reg + .modify(INT_ENA_REG::SERIAL_OUT_RECV_PKT::CLEAR); + } + _ => {} + } } fn clear_interrupt(&self, intr: Self::InterruptType) { - // Not supported + match intr { + super::InterruptType::Rx => { + USB_SERIAL_BASE + .int_clr_reg + .write(INT_CLR_REG::SERIAL_OUT_RECV_PKT::SET); + } + super::InterruptType::Tx => { + USB_SERIAL_BASE + .int_clr_reg + .write(INT_CLR_REG::SERIAL_IN_EMPTY::SET); + } + super::InterruptType::All => { + USB_SERIAL_BASE.int_clr_reg.write( + INT_CLR_REG::SERIAL_OUT_RECV_PKT::SET + INT_CLR_REG::SERIAL_IN_EMPTY::SET, + ); + } + _ => {} + } } fn get_interrupt(&self) -> Self::InterruptType { - super::InterruptType::Unknown + let status = &USB_SERIAL_BASE.int_st_reg; + let rx = status.is_set(INT_ST_REG::SERIAL_OUT_RECV_PKT); + let tx = status.is_set(INT_ST_REG::SERIAL_IN_EMPTY); + + match (rx, tx) { + (true, true) => super::InterruptType::All, + (true, false) => super::InterruptType::Rx, + (false, true) => super::InterruptType::Tx, + _ => super::InterruptType::Unknown, + } } fn set_interrupt_handler(&self, handler: &'static dyn Fn()) { - // Not supported + unsafe { + *self.intr_handler.get() = Some(handler); + } } fn get_irq_nums(&self) -> &[u32] { diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 0dc6dda4..47f96320 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -100,7 +100,10 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { match mcause & 0xff { TARGET0_INT_NUM => { ClockImpl::clr_interrupt(); - crate::kprintln!("Handle TARGET0 interrupt"); + crate::time::handle_clock_interrupt(); + } + USB_SERIAL_JTAG_INT_NUM => { + usb_serial_jtag_interrupt_handler(); } _ => {} } @@ -110,12 +113,19 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { static STAGING: SmpStagedInit = SmpStagedInit::new(); const INTR_BASE: usize = 0x600c_2000; + +const CLOCK_GATE_REG: usize = INTR_BASE + 0x100; + const TARGET0_INT_MAP_REG: usize = INTR_BASE + 0x94; +const TARGET0_INT_NUM: usize = 16; // IRQ number 16 in target0 +const INT_PRI16_REG: usize = INTR_BASE + 0x154; + +const USB_SERIAL_JTAG_INT_MAP_REG: usize = INTR_BASE + 0x68; +const USB_SERIAL_JTAG_INT_NUM: usize = 15; // IRQ number 15 in USB Serial JTAG +const INT_PRI15_REG: usize = INTR_BASE + 0x150; + const INT_ENABLE_REG: usize = INTR_BASE + 0x104; const INT_THRESH_REG: usize = INTR_BASE + 0x194; -const TARGET0_INT_NUM: usize = 16; // IRQ number 16 in target0 -const CLOCK_GATE_REG: usize = INTR_BASE + 0x100; -const INT_PRI_16_REG: usize = INTR_BASE + 0x154; const INT_TYPE_REG: usize = INTR_BASE + 0x108; pub(crate) fn init() { @@ -130,18 +140,22 @@ pub(crate) fn init() { init_vector_table(); blueos_driver::systimer::esp32_sys_timer::Esp32SysTimer::<0x6002_3000, 16_000_000>::init(); - // map target0 interrupt to 16 interrupt + unsafe { core::ptr::write_volatile(CLOCK_GATE_REG as *mut u32, 1); + // map target0 interrupt to 16 interrupt core::ptr::write_volatile(TARGET0_INT_MAP_REG as *mut u32, TARGET0_INT_NUM as u32); - core::ptr::write_volatile(INT_TYPE_REG as *mut u32, 1); // edge interrupt avoid for spurious interrupt + // map USB Serial JTAG interrupt to 15 interrupt + core::ptr::write_volatile( + USB_SERIAL_JTAG_INT_MAP_REG as *mut u32, + USB_SERIAL_JTAG_INT_NUM as u32, + ); + // Enable USB Serial JTAG interrupt + // core::ptr::write_volatile(INT_TYPE_REG as *mut u32, 1); // edge interrupt avoid for spurious interrupt core::ptr::write_volatile(INT_THRESH_REG as *mut u32, 1); - core::ptr::write_volatile(INT_PRI_16_REG as *mut u32, 15); - core::ptr::write_volatile((INT_PRI_16_REG + 0x4) as *mut u32, 15); - core::ptr::write_volatile((INT_PRI_16_REG - 0x4) as *mut u32, 15); + core::ptr::write_volatile(INT_PRI16_REG as *mut u32, 15); + core::ptr::write_volatile(INT_PRI15_REG as *mut u32, 15); core::ptr::write_volatile(INT_ENABLE_REG as *mut u32, 0xFFFF_FFFF); - // hal_espressif_rs::rust_helper_esp_cpu_inter_enable(1 << TARGET0_INT_NUM); - // hal_espressif_rs::rust_helper_esp_cpu_intr_set_priority(TARGET0_INT_NUM as i32, 1); } // From now on, all work will be done by core 0. // if arch::current_cpu_id() != 0 { @@ -162,7 +176,7 @@ pub(crate) fn init() { crate::define_peripheral! { (console_uart, blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial, - blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial), + blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial::new()), } crate::define_pin_states!(None); @@ -173,23 +187,16 @@ pub(crate) fn send_ipi(_hart: usize) {} #[inline(always)] pub(crate) fn clear_ipi(_hart: usize) {} -// #[no_mangle] -// pub unsafe extern "C" fn test_memory() { -// let mut v: u32 = 0; -// let addr_reg_0 = 0x3c000004usize as *const u32; -// let addr_reg_1 = 0x3c010004usize as *const u32; -// let addr_reg_3 = 0x3c018004usize as *const u32; -// let addr_reg_4 = 0x3c0182c0usize as *const u32; -// core::arch::asm!( -// "lw {out}, 0({addr_reg_0})", -// "lw {out}, 0({addr_reg_1})", -// "lw {out}, 0({addr_reg_3})", -// "lw {out}, 0({addr_reg_4})", -// out = out(reg) v, -// addr_reg_0 = in(reg) addr_reg_0, -// addr_reg_1 = in(reg) addr_reg_1, -// addr_reg_3 = in(reg) addr_reg_3, -// addr_reg_4 = in(reg) addr_reg_4, -// options(nostack, preserves_flags), -// ); -// } +pub fn usb_serial_jtag_interrupt_handler() { + use blueos_hal::HasInterruptReg; + let uart = get_device!(console_uart); + let intr = uart.get_interrupt(); + if let Some(handler) = unsafe { + let intr_handler_cell = &*uart.intr_handler.get(); + + intr_handler_cell.as_ref() + } { + handler(); + } + uart.clear_interrupt(intr); +} diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index e73d3ca0..34648da1 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -165,30 +165,11 @@ extern "C" fn init() { #[cfg(enable_vfs)] init_vfs(); init_apps(); - use crate::time::Tick; - enable_mie(); - Tick::interrupt_after(Tick::from_millis(100)); - for i in 0..100 { - let now = Tick::now(); - crate::kprintln!("System booted at tick {:?}", now); - } - Tick::interrupt_after(Tick::from_millis(100)); - loop {} arch::start_schedule(scheduler::schedule); unreachable!("We should have jumped to the schedule loop!"); } -pub fn enable_mie() { - unsafe { - core::arch::asm!( - "csrrs zero, mstatus, {mask}", - mask = const 1 << 3, // MIE 位是 bit 3 - options(nomem, preserves_flags), - ); - } -} - pub(crate) fn init_runtime() { init_bss(); run_init_array(); From 9dcba33f6d202c1d42316682948c307e3d94a5b0 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 24 Feb 2026 14:19:03 +0800 Subject: [PATCH 09/53] minor --- kernel/src/boot.rs | 1 - kernel/src/time.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index 34648da1..b1c2479a 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -165,7 +165,6 @@ extern "C" fn init() { #[cfg(enable_vfs)] init_vfs(); init_apps(); - arch::start_schedule(scheduler::schedule); unreachable!("We should have jumped to the schedule loop!"); } diff --git a/kernel/src/time.rs b/kernel/src/time.rs index ca1fbafb..8a8b6429 100644 --- a/kernel/src/time.rs +++ b/kernel/src/time.rs @@ -76,7 +76,6 @@ impl Tick { } pub fn interrupt_at(n: Tick) { - crate::kprintln!("Set interrupt at tick {:?}", n); let _guard = DisableInterruptGuard::new(); if n == Self::MAX { ClockImpl::stop(); From a35caa90ade93a4942c7a315f42cf42de4adb7c1 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 24 Feb 2026 14:21:16 +0800 Subject: [PATCH 10/53] minor --- kernel/src/time/timer.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 52d97223..70a332ff 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -590,8 +590,7 @@ mod tests { #[test] fn test_timer_accuracy() { - use crate::boards::ClockImpl; - use blueos_hal::clock::Clock; + use crate::{boards::ClockImpl, devices::clock::Clock}; let start = ClockImpl::estimate_current_cycles(); scheduler::suspend_me_for::<()>( Tick(blueos_kconfig::CONFIG_TICKS_PER_SECOND as usize), From 6b4a67b097051ce19e6f0f5922c6596ac12ec36a Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 24 Feb 2026 14:22:26 +0800 Subject: [PATCH 11/53] minor --- kernel/src/thread/builder.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/src/thread/builder.rs b/kernel/src/thread/builder.rs index 5758202c..49afc8e1 100644 --- a/kernel/src/thread/builder.rs +++ b/kernel/src/thread/builder.rs @@ -193,13 +193,11 @@ pub(crate) fn build_static_thread( kind: ThreadKind, ) -> ThreadNode { let inner = &s.arc; - let stack_size = s.stack.rep.len(); - let stack_base = s.stack.rep.as_ptr() as usize; let stack = &mut s.stack; let arc = unsafe { ThreadNode::from_static_inner_ref(inner) }; debug_assert_eq!(ThreadNode::strong_count(&arc), 1); - let id = Thread::id(&arc); + let _id = Thread::id(&arc); let mut w = arc.lock(); let Some(stack) = Stack::from_raw(stack.rep.as_mut_ptr(), stack.rep.len()) else { panic!("Invalid stack"); From ed725e2e4d9d8728acc8683d0b5946c5d43b823f Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 24 Feb 2026 14:23:03 +0800 Subject: [PATCH 12/53] minor --- kernel/src/thread/builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/src/thread/builder.rs b/kernel/src/thread/builder.rs index 49afc8e1..9ce85cf1 100644 --- a/kernel/src/thread/builder.rs +++ b/kernel/src/thread/builder.rs @@ -194,7 +194,6 @@ pub(crate) fn build_static_thread( ) -> ThreadNode { let inner = &s.arc; let stack = &mut s.stack; - let arc = unsafe { ThreadNode::from_static_inner_ref(inner) }; debug_assert_eq!(ThreadNode::strong_count(&arc), 1); let _id = Thread::id(&arc); From 11f8bb4ba6b30b0703a34900e44fd9669868c5d1 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Tue, 24 Feb 2026 14:40:27 +0800 Subject: [PATCH 13/53] del idf deps --- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 47f96320..6dec4118 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -130,11 +130,7 @@ const INT_TYPE_REG: usize = INTR_BASE + 0x108; pub(crate) fn init() { assert!(!local_irq_enabled()); - unsafe { hal_espressif_rs::soc_init() }; - unsafe { - crate::boot::INIT_BSS_DONE = true; - } crate::boot::init_runtime(); crate::boot::init_heap(); init_vector_table(); From 24072aca2660437fb5b521ed6c4dff040e9fd278 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 17:18:28 +0800 Subject: [PATCH 14/53] add riscv kconfig --- kernel/src/boards/seeed_xiao_esp32c3/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/Kconfig b/kernel/src/boards/seeed_xiao_esp32c3/Kconfig index d0870647..b329c525 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/Kconfig +++ b/kernel/src/boards/seeed_xiao_esp32c3/Kconfig @@ -18,3 +18,8 @@ choice help Set irq priority bits to 8. endchoice + +config SOC_ESP32C3 + bool "Esp32c3" + default y + select RISCV From 01be4fcdfa50e51c3e877628e81f98e04c0c4ad3 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 17:20:54 +0800 Subject: [PATCH 15/53] set mie --- kernel/src/arch/riscv/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/src/arch/riscv/mod.rs b/kernel/src/arch/riscv/mod.rs index 93c31991..f5c7e037 100644 --- a/kernel/src/arch/riscv/mod.rs +++ b/kernel/src/arch/riscv/mod.rs @@ -485,9 +485,9 @@ pub(crate) extern "C" fn bootstrap() { unsafe { core::arch::asm!( "csrs mstatus, {mstatus}", - // "csrs mie, {mie}", + "csrs mie, {mie}", mstatus = in(reg) MSTATUS_MPP_M | MSTATUS_MPIE, - // mie = in(reg) MIE_MTIE|MIE_MSIE|MIE_MEIE, + mie = in(reg) MIE_MTIE|MIE_MSIE|MIE_MEIE, options(nostack), ) }; From 6a4215bd40fbda8e34a68407a6d20261657aafa4 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 17:47:03 +0800 Subject: [PATCH 16/53] minor --- kernel/src/sync/libatomic/atomic.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index 768f606c..e7bac706 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -75,9 +75,9 @@ extern void enable_local_irq_restore(size_t); #pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load) #pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store) #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) -#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ +#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ __atomic_compare_exchange) -#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ +#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ __atomic_is_lock_free) #ifdef HAS_LOCK_FREE_CAS @@ -98,15 +98,13 @@ _Static_assert(__atomic_always_lock_free(sizeof(uintptr_t), 0), "Implementation assumes lock-free pointer-size cmpxchg"); typedef _Atomic(uintptr_t) Lock; /// Unlock a lock. This is a release operation. -__inline static void unlock(Lock *l, size_t irq_status) -{ +__inline static void unlock(Lock *l, size_t irq_status) { __c11_atomic_store(l, 0, __ATOMIC_RELEASE); enable_local_irq_restore(irq_status); } /// Locks a lock. In the current implementation, this is potentially /// unbounded in the contended case. -__inline static size_t lock(Lock *l) -{ +__inline static size_t lock(Lock *l) { size_t irq_status = disable_local_irq_save(); uintptr_t old = 0; while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE, From 1f96ce195d2f5b10932de8ecb1844dd7f22e560f Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 17:50:07 +0800 Subject: [PATCH 17/53] minor --- kernel/src/sync/libatomic/atomic.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index e7bac706..e2922f8a 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -77,7 +77,7 @@ extern void enable_local_irq_restore(size_t); #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) #pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ __atomic_compare_exchange) -#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ +#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ __atomic_is_lock_free) #ifdef HAS_LOCK_FREE_CAS @@ -116,8 +116,7 @@ __inline static size_t lock(Lock *l) { static Lock locks[SPINLOCK_COUNT]; /// Returns a lock to use for a given pointer. -static __inline Lock *lock_for_pointer(void *ptr) -{ +static __inline Lock *lock_for_pointer(void *ptr) { intptr_t hash = (intptr_t)ptr; // Disregard the lowest 4 bits. We want all values that may be part of the // same memory operation to hash to the same value and therefore use the same @@ -139,8 +138,7 @@ typedef int Lock; static __inline Lock *lock_for_pointer(void *ptr) { return 0; } -__inline static void unlock(Lock *l, size_t irq_status) -{ +__inline static void unlock(Lock *l, size_t irq_status) { enable_local_irq_restore(irq_status); } From 6f9e74f22ce96949a9b433dacd35645c2475599b Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:07:34 +0800 Subject: [PATCH 18/53] minor --- kernel/src/sync/libatomic/atomic.c | 63 ++++++++++++++---------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index e2922f8a..8ac9f34c 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -142,8 +142,7 @@ __inline static void unlock(Lock *l, size_t irq_status) { enable_local_irq_restore(irq_status); } -__inline static size_t lock(Lock *l) -{ +__inline static size_t lock(Lock *l) { size_t irq_status = disable_local_irq_save(); return irq_status; } @@ -151,8 +150,8 @@ __inline static size_t lock(Lock *l) #endif // HAS_LOCK_FREE_CAS /// Macros for determining whether a size is lock free. -#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p) \ - (__atomic_always_lock_free(size, p) || \ +#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p) \ + (__atomic_always_lock_free(size, p) || \ (__atomic_always_lock_free(size, 0) && ((uintptr_t)p % size) == 0)) #define IS_LOCK_FREE_1(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(1, p) #define IS_LOCK_FREE_2(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(2, p) @@ -162,12 +161,12 @@ __inline static size_t lock(Lock *l) /// Macro that calls the compiler-generated lock-free versions of functions /// when they exist. -#define TRY_LOCK_FREE_CASE(n, type, ptr) \ - case n: \ - if (IS_LOCK_FREE_##n(ptr)) \ - { \ - LOCK_FREE_ACTION(type); \ - } \ +#define TRY_LOCK_FREE_CASE(n, type, ptr) \ + case n: \ + if (IS_LOCK_FREE_##n(ptr)) \ + { \ + LOCK_FREE_ACTION(type); \ + } \ break; #ifdef __SIZEOF_INT128__ #define TRY_LOCK_FREE_CASE_16(p) TRY_LOCK_FREE_CASE(16, __uint128_t, p) @@ -175,24 +174,23 @@ __inline static size_t lock(Lock *l) #define TRY_LOCK_FREE_CASE_16(p) /* __uint128_t not available */ #endif -#define LOCK_FREE_CASES(ptr) \ - do \ - { \ - switch (size) \ - { \ - TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \ - TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \ - TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \ - TRY_LOCK_FREE_CASE(8, uint64_t, ptr) \ - TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */ \ - default: \ - break; \ - } \ +#define LOCK_FREE_CASES(ptr) \ + do \ + { \ + switch (size) \ + { \ + TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \ + TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \ + TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \ + TRY_LOCK_FREE_CASE(8, uint64_t, ptr) \ + TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */ \ + default: \ + break; \ + } \ } while (0) /// Whether atomic operations for the given size (and alignment) are lock-free. -bool __atomic_is_lock_free_c(size_t size, void *ptr) -{ +bool __atomic_is_lock_free_c(size_t size, void *ptr) { #define LOCK_FREE_ACTION(type) return true; LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION @@ -201,8 +199,7 @@ bool __atomic_is_lock_free_c(size_t size, void *ptr) /// An atomic load operation. This is atomic with respect to the source /// pointer only. -void __atomic_load_c(int size, void *src, void *dest, int model) -{ +void __atomic_load_c(int size, void *src, void *dest, int model) { #define LOCK_FREE_ACTION(type) \ *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ return; @@ -216,8 +213,7 @@ void __atomic_load_c(int size, void *src, void *dest, int model) /// An atomic store operation. This is atomic with respect to the destination /// pointer only. -void __atomic_store_c(int size, void *dest, void *src, int model) -{ +void __atomic_store_c(int size, void *dest, void *src, int model) { #define LOCK_FREE_ACTION(type) \ __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ return; @@ -235,11 +231,10 @@ void __atomic_store_c(int size, void *dest, void *src, int model) /// /// This function returns 1 if the exchange takes place or 0 if it fails. int __atomic_compare_exchange_c(int size, void *ptr, void *expected, - void *desired, int success, int failure) -{ -#define LOCK_FREE_ACTION(type) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ + void *desired, int success, int failure) { +#define LOCK_FREE_ACTION(type) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ failure) LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION From 6af199b73a698d502653d16b0f4afb4c7a52fd3a Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:10:02 +0800 Subject: [PATCH 19/53] minor --- kernel/src/sync/libatomic/atomic.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index 8ac9f34c..eadbdd17 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -163,8 +163,7 @@ __inline static size_t lock(Lock *l) { /// when they exist. #define TRY_LOCK_FREE_CASE(n, type, ptr) \ case n: \ - if (IS_LOCK_FREE_##n(ptr)) \ - { \ + if (IS_LOCK_FREE_##n(ptr)) { \ \ LOCK_FREE_ACTION(type); \ } \ break; @@ -175,10 +174,8 @@ __inline static size_t lock(Lock *l) { #endif #define LOCK_FREE_CASES(ptr) \ - do \ - { \ - switch (size) \ - { \ + do { \ + switch (size) { \ TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \ TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \ TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \ From 9a25aece0c4b0a6aaad1858e35029d4e5d96d8fa Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:13:20 +0800 Subject: [PATCH 20/53] minor --- kernel/src/sync/libatomic/atomic.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index eadbdd17..60f246e0 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -163,7 +163,7 @@ __inline static size_t lock(Lock *l) { /// when they exist. #define TRY_LOCK_FREE_CASE(n, type, ptr) \ case n: \ - if (IS_LOCK_FREE_##n(ptr)) { \ \ + if (IS_LOCK_FREE_##n(ptr)) { \ LOCK_FREE_ACTION(type); \ } \ break; @@ -197,8 +197,8 @@ bool __atomic_is_lock_free_c(size_t size, void *ptr) { /// An atomic load operation. This is atomic with respect to the source /// pointer only. void __atomic_load_c(int size, void *src, void *dest, int model) { -#define LOCK_FREE_ACTION(type) \ - *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ +#define LOCK_FREE_ACTION(type) \ + *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ return; LOCK_FREE_CASES(src); #undef LOCK_FREE_ACTION @@ -211,8 +211,8 @@ void __atomic_load_c(int size, void *src, void *dest, int model) { /// An atomic store operation. This is atomic with respect to the destination /// pointer only. void __atomic_store_c(int size, void *dest, void *src, int model) { -#define LOCK_FREE_ACTION(type) \ - __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ +#define LOCK_FREE_ACTION(type) \ + __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ return; LOCK_FREE_CASES(dest); #undef LOCK_FREE_ACTION @@ -229,16 +229,15 @@ void __atomic_store_c(int size, void *dest, void *src, int model) { /// This function returns 1 if the exchange takes place or 0 if it fails. int __atomic_compare_exchange_c(int size, void *ptr, void *expected, void *desired, int success, int failure) { -#define LOCK_FREE_ACTION(type) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ +#define LOCK_FREE_ACTION(type) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ failure) LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(ptr); size_t irq = lock(l); - if (memcmp(ptr, expected, size) == 0) - { + if (memcmp(ptr, expected, size) == 0) { memcpy(ptr, desired, size); unlock(l, irq); return 1; @@ -250,11 +249,10 @@ int __atomic_compare_exchange_c(int size, void *ptr, void *expected, /// Performs an atomic exchange operation between two pointers. This is atomic /// with respect to the target address. -void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) -{ -#define LOCK_FREE_ACTION(type) \ - *(type *)old = \ - __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \ +void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { +#define LOCK_FREE_ACTION(type) \ + *(type *)old = \ + __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \ return; LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION From 0ed38ff4d4e1f4330df80107241c48c2ab9cd033 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:16:30 +0800 Subject: [PATCH 21/53] minor --- kernel/src/sync/libatomic/atomic.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index 60f246e0..e9f4d117 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -211,8 +211,8 @@ void __atomic_load_c(int size, void *src, void *dest, int model) { /// An atomic store operation. This is atomic with respect to the destination /// pointer only. void __atomic_store_c(int size, void *dest, void *src, int model) { -#define LOCK_FREE_ACTION(type) \ - __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ +#define LOCK_FREE_ACTION(type) \ + __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ return; LOCK_FREE_CASES(dest); #undef LOCK_FREE_ACTION @@ -229,9 +229,9 @@ void __atomic_store_c(int size, void *dest, void *src, int model) { /// This function returns 1 if the exchange takes place or 0 if it fails. int __atomic_compare_exchange_c(int size, void *ptr, void *expected, void *desired, int success, int failure) { -#define LOCK_FREE_ACTION(type) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ +#define LOCK_FREE_ACTION(type) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ failure) LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION @@ -268,17 +268,17 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { // specialised versions of the above functions. //////////////////////////////////////////////////////////////////////////////// #ifdef __SIZEOF_INT128__ -#define OPTIMISED_CASES \ - OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ - OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ - OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ - OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) \ +#define OPTIMISED_CASES \ + OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ + OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ + OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ + OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) \ OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t) #else -#define OPTIMISED_CASES \ - OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ - OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ - OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ +#define OPTIMISED_CASES \ + OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \ + OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \ + OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \ OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) #endif From 8ed7d18428af4318bfc61f0d9b84326cb6ce6b0b Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:28:50 +0800 Subject: [PATCH 22/53] minor --- kernel/src/sync/libatomic/atomic.c | 70 ++++++++++++++---------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index e9f4d117..1c101462 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -229,9 +229,9 @@ void __atomic_store_c(int size, void *dest, void *src, int model) { /// This function returns 1 if the exchange takes place or 0 if it fails. int __atomic_compare_exchange_c(int size, void *ptr, void *expected, void *desired, int success, int failure) { -#define LOCK_FREE_ACTION(type) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ +#define LOCK_FREE_ACTION(type) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ failure) LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION @@ -282,48 +282,44 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) #endif -#define OPTIMISED_CASE(n, lockfree, type) \ - type __atomic_load_##n(type *src, int model) \ - { \ - if (lockfree(src)) \ - return __c11_atomic_load((_Atomic(type) *)src, model); \ - Lock *l = lock_for_pointer(src); \ - size_t irq = lock(l); \ - type val = *src; \ - unlock(l, irq); \ - return val; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + type __atomic_load_##n(type *src, int model) { \ + if (lockfree(src)) \ + return __c11_atomic_load((_Atomic(type) *)src, model); \ + Lock *l = lock_for_pointer(src); \ + size_t irq = lock(l); \ + type val = *src; \ + unlock(l, irq); \ + return val; \ } OPTIMISED_CASES #undef OPTIMISED_CASE -#define OPTIMISED_CASE(n, lockfree, type) \ - void __atomic_store_##n(type *dest, type val, int model) \ - { \ - if (lockfree(dest)) \ - { \ - __c11_atomic_store((_Atomic(type) *)dest, val, model); \ - return; \ - } \ - Lock *l = lock_for_pointer(dest); \ - size_t irq = lock(l); \ - *dest = val; \ - unlock(l, irq); \ - return; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + void __atomic_store_##n(type *dest, type val, int model) { \ + if (lockfree(dest)) { \ + __c11_atomic_store((_Atomic(type) *)dest, val, model); \ + return; \ + } \ + Lock *l = lock_for_pointer(dest); \ + size_t irq = lock(l); \ + *dest = val; \ + unlock(l, irq); \ + return; \ } OPTIMISED_CASES #undef OPTIMISED_CASE -#define OPTIMISED_CASE(n, lockfree, type) \ - type __atomic_exchange_##n(type *dest, type val, int model) \ - { \ - if (lockfree(dest)) \ - return __c11_atomic_exchange((_Atomic(type) *)dest, val, model); \ - Lock *l = lock_for_pointer(dest); \ - size_t irq = lock(l); \ - type tmp = *dest; \ - *dest = val; \ - unlock(l, irq); \ - return tmp; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + type __atomic_exchange_##n(type *dest, type val, int model) { \ + if (lockfree(dest)) \ + return __c11_atomic_exchange((_Atomic(type) *)dest, val, model); \ + Lock *l = lock_for_pointer(dest); \ + size_t irq = lock(l); \ + type tmp = *dest; \ + *dest = val; \ + unlock(l, irq); \ + return tmp; \ } OPTIMISED_CASES #undef OPTIMISED_CASE From e7bf35451eaba0a2fbc4ac57729900f03c97445d Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:33:49 +0800 Subject: [PATCH 23/53] minor --- kernel/src/sync/libatomic/atomic.c | 55 ++++++++++++++---------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index 1c101462..47e19270 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -324,24 +324,22 @@ OPTIMISED_CASES OPTIMISED_CASES #undef OPTIMISED_CASE -#define OPTIMISED_CASE(n, lockfree, type) \ - bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \ - int success, int failure) \ - { \ - if (lockfree(ptr)) \ - return __c11_atomic_compare_exchange_strong( \ - (_Atomic(type) *)ptr, expected, desired, success, failure); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - if (*ptr == *expected) \ - { \ - *ptr = desired; \ - unlock(l, irq); \ - return true; \ - } \ - *expected = *ptr; \ - unlock(l, irq); \ - return false; \ +#define OPTIMISED_CASE(n, lockfree, type) \ + bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \ + int success, int failure) { \ + if (lockfree(ptr)) \ + return __c11_atomic_compare_exchange_strong( \ + (_Atomic(type) *)ptr, expected, desired, success, failure); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + if (*ptr == *expected) { \ + *ptr = desired; \ + unlock(l, irq); \ + return true; \ + } \ + *expected = *ptr; \ + unlock(l, irq); \ + return false; \ } OPTIMISED_CASES #undef OPTIMISED_CASE @@ -362,17 +360,16 @@ OPTIMISED_CASES return tmp; \ } -#define ATOMIC_RMW_NAND(n, lockfree, type) \ - type __atomic_fetch_nand_##n(type *ptr, type val, int model) \ - { \ - if (lockfree(ptr)) \ - return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - type tmp = *ptr; \ - *ptr = ~(tmp & val); \ - unlock(l, irq); \ - return tmp; \ +#define ATOMIC_RMW_NAND(n, lockfree, type) \ + type __atomic_fetch_nand_##n(type *ptr, type val, int model) { \ + if (lockfree(ptr)) \ + return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + type tmp = *ptr; \ + *ptr = ~(tmp & val); \ + unlock(l, irq); \ + return tmp; \ } #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) From 872dae0fb5f45941167fb01140b77e2b0e6b6529 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:36:13 +0800 Subject: [PATCH 24/53] minor --- kernel/src/sync/libatomic/atomic.c | 41 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/kernel/src/sync/libatomic/atomic.c b/kernel/src/sync/libatomic/atomic.c index 47e19270..d1396d49 100644 --- a/kernel/src/sync/libatomic/atomic.c +++ b/kernel/src/sync/libatomic/atomic.c @@ -347,29 +347,28 @@ OPTIMISED_CASES //////////////////////////////////////////////////////////////////////////////// // Atomic read-modify-write operations for integers of various sizes. //////////////////////////////////////////////////////////////////////////////// -#define ATOMIC_RMW(n, lockfree, type, opname, op) \ - type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) \ - { \ - if (lockfree(ptr)) \ - return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - type tmp = *ptr; \ - *ptr = tmp op val; \ - unlock(l, irq); \ - return tmp; \ +#define ATOMIC_RMW(n, lockfree, type, opname, op) \ + type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) { \ + if (lockfree(ptr)) \ + return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + type tmp = *ptr; \ + *ptr = tmp op val; \ + unlock(l, irq); \ + return tmp; \ } -#define ATOMIC_RMW_NAND(n, lockfree, type) \ - type __atomic_fetch_nand_##n(type *ptr, type val, int model) { \ - if (lockfree(ptr)) \ - return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ - Lock *l = lock_for_pointer(ptr); \ - size_t irq = lock(l); \ - type tmp = *ptr; \ - *ptr = ~(tmp & val); \ - unlock(l, irq); \ - return tmp; \ +#define ATOMIC_RMW_NAND(n, lockfree, type) \ + type __atomic_fetch_nand_##n(type *ptr, type val, int model) { \ + if (lockfree(ptr)) \ + return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ + Lock *l = lock_for_pointer(ptr); \ + size_t irq = lock(l); \ + type tmp = *ptr; \ + *ptr = ~(tmp & val); \ + unlock(l, irq); \ + return tmp; \ } #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) From dbb6e7bfb30851b8c2f466a74b810e2667d27587 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 18:48:44 +0800 Subject: [PATCH 25/53] make fifo tx enable --- kernel/src/devices/tty/serial/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kernel/src/devices/tty/serial/mod.rs b/kernel/src/devices/tty/serial/mod.rs index 58b493b7..7a353f7f 100644 --- a/kernel/src/devices/tty/serial/mod.rs +++ b/kernel/src/devices/tty/serial/mod.rs @@ -534,11 +534,7 @@ impl Device for Serial { } fn write(&self, _pos: u64, buf: &[u8], is_nonblocking: bool) -> Result { - // self.fifo_tx(buf, is_nonblocking).map_err(ErrorKind::from) - self.uart_ops - .irqsave_lock() - .write(buf) - .map_err(ErrorKind::from) + self.fifo_tx(buf, is_nonblocking).map_err(ErrorKind::from) } fn ioctl(&self, request: u32, arg: usize) -> Result<(), ErrorKind> { From 759b5d89f556bf734390d422da725fd103a763ee Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 25 Feb 2026 19:41:02 +0800 Subject: [PATCH 26/53] disable wdt --- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 6dec4118..7ec63828 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -128,6 +128,10 @@ const INT_ENABLE_REG: usize = INTR_BASE + 0x104; const INT_THRESH_REG: usize = INTR_BASE + 0x194; const INT_TYPE_REG: usize = INTR_BASE + 0x108; +const RTC_CNTL_BASE: usize = 0x6000_8000; +const RTC_CNTL_WDTWRITECT_REG: usize = RTC_CNTL_BASE + 0xA8; +const RTC_CNTL_WDTCONFIG0_REG: usize = RTC_CNTL_BASE + 0x90; + pub(crate) fn init() { assert!(!local_irq_enabled()); @@ -138,6 +142,11 @@ pub(crate) fn init() { blueos_driver::systimer::esp32_sys_timer::Esp32SysTimer::<0x6002_3000, 16_000_000>::init(); unsafe { + // disable WDT to avoid unexpected reset + core::ptr::write_volatile(RTC_CNTL_WDTWRITECT_REG as *mut u32, 0x50D83AA1); + core::ptr::write_volatile(RTC_CNTL_WDTCONFIG0_REG as *mut u32, 0); + core::ptr::write_volatile(RTC_CNTL_WDTWRITECT_REG as *mut u32, 0); + core::ptr::write_volatile(CLOCK_GATE_REG as *mut u32, 1); // map target0 interrupt to 16 interrupt core::ptr::write_volatile(TARGET0_INT_MAP_REG as *mut u32, TARGET0_INT_NUM as u32); From c4e85a28bf8c4e46aefb21906ccc75804f764aa7 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Thu, 26 Feb 2026 16:33:30 +0800 Subject: [PATCH 27/53] add intc --- driver/src/interrupt_controller/esp32_intc.rs | 88 +++++++++++++++++++ driver/src/interrupt_controller/mod.rs | 27 ++++++ driver/src/lib.rs | 1 + driver/src/static_ref.rs | 4 + kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 64 ++++---------- 5 files changed, 138 insertions(+), 46 deletions(-) create mode 100644 driver/src/interrupt_controller/esp32_intc.rs create mode 100644 driver/src/interrupt_controller/mod.rs diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs new file mode 100644 index 00000000..d15104cf --- /dev/null +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -0,0 +1,88 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use tock_registers::{ + interfaces::{ReadWriteable, Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +use crate::{ + interrupt_controller::Interrupt, static_ref::StaticRef, + uart::esp32_usb_serial::JFIFO_ST_REG::OUT_FIFO_FULL, +}; + +register_structs! { + pub IntcRegisters { + (0x000 => _reserved0), + (0x068 => usb_intr_map_reg: ReadWrite), + (0x06c => _reserved1), + (0x094 => systimer_target0_int_map_reg: ReadWrite), + (0x098 => _reserved2), + (0x104 => cpu_int_enable_reg: ReadWrite), + (0x108 => _reserved3), + (0x118 => priority_reg: [ReadWrite; 31]), + (0x194 => thresh_reg: ReadWrite), + (0x198 => @END), + } +} + +register_bitfields! [ + u32, + + pub PRIORITY_REG [ + PRIORITY OFFSET(0) NUMBITS(4) [], + ], + + pub THRESH_REG [ + THRESH OFFSET(0) NUMBITS(4) [], + ], +]; + +pub struct Esp32Intc { + registers: StaticRef, +} + +impl Esp32Intc { + pub const fn new(base: usize) -> Self { + Self { + registers: unsafe { StaticRef::new(base as *const IntcRegisters) }, + } + } + + pub fn alloc_irq(&self, irq: Interrupt) { + let mut map_reg = + self.registers.inner() as *const IntcRegisters as usize + irq.source_no * 4; + unsafe { + core::ptr::write_volatile(map_reg as *mut u32, irq.irq_no as u32); + } + } + + pub fn enable_irq(&self, irq: Interrupt) { + let mut enable_reg = self.registers.cpu_int_enable_reg.get(); + enable_reg |= 1 << irq.irq_no; + self.registers.cpu_int_enable_reg.set(enable_reg); + } + + pub fn set_priority(&self, irq: Interrupt, priority: u8) { + self.registers.priority_reg[(irq.irq_no - 1) as usize] + .write(PRIORITY_REG::PRIORITY.val(priority as u32)); + } + + pub fn set_thresh(&self, thresh: u8) { + self.registers + .thresh_reg + .write(THRESH_REG::THRESH.val(thresh as u32)); + } +} diff --git a/driver/src/interrupt_controller/mod.rs b/driver/src/interrupt_controller/mod.rs new file mode 100644 index 00000000..90f487ea --- /dev/null +++ b/driver/src/interrupt_controller/mod.rs @@ -0,0 +1,27 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(target_chip = "esp32c3")] +pub mod esp32_intc; + +pub struct Interrupt { + pub(crate) source_no: usize, + pub(crate) irq_no: usize, +} + +impl Interrupt { + pub const fn new(source_no: usize, irq_no: usize) -> Self { + Self { source_no, irq_no } + } +} diff --git a/driver/src/lib.rs b/driver/src/lib.rs index efccfe75..ce49feb4 100644 --- a/driver/src/lib.rs +++ b/driver/src/lib.rs @@ -17,6 +17,7 @@ pub mod clock_control; pub mod i2c; +pub mod interrupt_controller; pub mod pinctrl; pub mod reset; pub mod static_ref; diff --git a/driver/src/static_ref.rs b/driver/src/static_ref.rs index d1c9cf1e..388d2aed 100644 --- a/driver/src/static_ref.rs +++ b/driver/src/static_ref.rs @@ -53,6 +53,10 @@ impl StaticRef { ptr: NonNull::new_unchecked(ptr.cast_mut()), } } + + pub fn inner(&self) -> *const T { + self.ptr.as_ptr() + } } impl Clone for StaticRef { diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 7ec63828..256d1641 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -26,6 +26,7 @@ use crate::{ support::SmpStagedInit, time, }; +use blueos_driver::interrupt_controller::Interrupt; use blueos_hal::Has8bitDataReg; use core::sync::atomic::Ordering; pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); @@ -110,28 +111,17 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { // PLIC.complete(cpu_id, PLIC.claim(cpu_id)) } -static STAGING: SmpStagedInit = SmpStagedInit::new(); +const TARGET0_INT_NUM: usize = 16; -const INTR_BASE: usize = 0x600c_2000; - -const CLOCK_GATE_REG: usize = INTR_BASE + 0x100; - -const TARGET0_INT_MAP_REG: usize = INTR_BASE + 0x94; -const TARGET0_INT_NUM: usize = 16; // IRQ number 16 in target0 -const INT_PRI16_REG: usize = INTR_BASE + 0x154; - -const USB_SERIAL_JTAG_INT_MAP_REG: usize = INTR_BASE + 0x68; -const USB_SERIAL_JTAG_INT_NUM: usize = 15; // IRQ number 15 in USB Serial JTAG -const INT_PRI15_REG: usize = INTR_BASE + 0x150; - -const INT_ENABLE_REG: usize = INTR_BASE + 0x104; -const INT_THRESH_REG: usize = INTR_BASE + 0x194; -const INT_TYPE_REG: usize = INTR_BASE + 0x108; +const USB_SERIAL_JTAG_INT_NUM: usize = 15; const RTC_CNTL_BASE: usize = 0x6000_8000; const RTC_CNTL_WDTWRITECT_REG: usize = RTC_CNTL_BASE + 0xA8; const RTC_CNTL_WDTCONFIG0_REG: usize = RTC_CNTL_BASE + 0x90; +const USB_SERIAL_JTAG_IRQ: Interrupt = Interrupt::new(26, 15); +const SYSTIMER_TARGET0_IRQ: Interrupt = Interrupt::new(37, 16); + pub(crate) fn init() { assert!(!local_irq_enabled()); @@ -146,42 +136,24 @@ pub(crate) fn init() { core::ptr::write_volatile(RTC_CNTL_WDTWRITECT_REG as *mut u32, 0x50D83AA1); core::ptr::write_volatile(RTC_CNTL_WDTCONFIG0_REG as *mut u32, 0); core::ptr::write_volatile(RTC_CNTL_WDTWRITECT_REG as *mut u32, 0); - - core::ptr::write_volatile(CLOCK_GATE_REG as *mut u32, 1); - // map target0 interrupt to 16 interrupt - core::ptr::write_volatile(TARGET0_INT_MAP_REG as *mut u32, TARGET0_INT_NUM as u32); - // map USB Serial JTAG interrupt to 15 interrupt - core::ptr::write_volatile( - USB_SERIAL_JTAG_INT_MAP_REG as *mut u32, - USB_SERIAL_JTAG_INT_NUM as u32, - ); - // Enable USB Serial JTAG interrupt - // core::ptr::write_volatile(INT_TYPE_REG as *mut u32, 1); // edge interrupt avoid for spurious interrupt - core::ptr::write_volatile(INT_THRESH_REG as *mut u32, 1); - core::ptr::write_volatile(INT_PRI16_REG as *mut u32, 15); - core::ptr::write_volatile(INT_PRI15_REG as *mut u32, 15); - core::ptr::write_volatile(INT_ENABLE_REG as *mut u32, 0xFFFF_FFFF); } - // From now on, all work will be done by core 0. - // if arch::current_cpu_id() != 0 { - // scheduler::wait_and_then_start_schedule(); - // unreachable!("Secondary cores should have jumped to the scheduler"); - // } - // Enable TARGET0 in PLIC. - // PLIC.enable( - // arch::current_cpu_id(), - // u32::try_from(16usize).expect("usize(64 bits) converts to u32 failed"), - // ); - // Set TARGET0 priority in PLIC. - // PLIC.set_priority( - // u32::try_from(16usize).expect("usize(64 bits) converts to u32 failed"), - // 1, - // ); + + get_device!(intc).alloc_irq(SYSTIMER_TARGET0_IRQ); + get_device!(intc).alloc_irq(USB_SERIAL_JTAG_IRQ); + + get_device!(intc).set_thresh(1); + + get_device!(intc).set_priority(USB_SERIAL_JTAG_IRQ, 15); + get_device!(intc).set_priority(SYSTIMER_TARGET0_IRQ, 15); + get_device!(intc).enable_irq(SYSTIMER_TARGET0_IRQ); + get_device!(intc).enable_irq(USB_SERIAL_JTAG_IRQ); } crate::define_peripheral! { (console_uart, blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial, blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial::new()), + (intc, blueos_driver::interrupt_controller::esp32_intc::Esp32Intc, + blueos_driver::interrupt_controller::esp32_intc::Esp32Intc::new(0x600c_2000)), } crate::define_pin_states!(None); From a4f4938a3ea9eab4643e684981520f0b5b0c4c15 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Thu, 26 Feb 2026 16:45:26 +0800 Subject: [PATCH 28/53] minor --- driver/src/interrupt_controller/esp32_intc.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index d15104cf..71603ce9 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -26,12 +26,8 @@ use crate::{ register_structs! { pub IntcRegisters { (0x000 => _reserved0), - (0x068 => usb_intr_map_reg: ReadWrite), - (0x06c => _reserved1), - (0x094 => systimer_target0_int_map_reg: ReadWrite), - (0x098 => _reserved2), (0x104 => cpu_int_enable_reg: ReadWrite), - (0x108 => _reserved3), + (0x108 => _reserved1), (0x118 => priority_reg: [ReadWrite; 31]), (0x194 => thresh_reg: ReadWrite), (0x198 => @END), From 38888e7931b172ca42736a725dc258c33ee3c913 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 27 Feb 2026 11:02:58 +0800 Subject: [PATCH 29/53] add copyright --- kernel/src/boards/seeed_xiao_esp32c3/config.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/config.rs b/kernel/src/boards/seeed_xiao_esp32c3/config.rs index 4cf0c1ea..d05da293 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/config.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/config.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2025 vivo Mobile Communication Co., Ltd. +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// SPDX-License-Identifier: MIT OR Apache-2.0 +// This code is copied from [esp-hal](https://github.com/esp-rs/esp-hal/blob/main/esp-bootloader-esp-idf/src/lib.rs) -use crate::arch::irq::IrqNumber; - -pub const PLIC_BASE: usize = 0x0c00_0000; - -pub const UART0: u32 = 0x1000_0000; -pub const UART0_IRQ: IrqNumber = IrqNumber::new(10); +// License: Apache-2.0 OR MIT +// Copyright 2021 esp-rs /// ESP-IDF compatible application descriptor /// @@ -61,6 +57,7 @@ pub struct EspAppDesc { #[unsafe(export_name = "esp_app_desc")] #[unsafe(link_section = ".rodata_desc.appdesc")] /// Application metadata descriptor. +/// FIXME: This is currently hardcoded, but we should generate it from build scripts. pub static ESP_APP_DESC: EspAppDesc = EspAppDesc { magic_word: 0xABCD_5432, secure_version: 0, From b5391ff92f70fd05c343af1149dff58b180a5666 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 27 Feb 2026 11:07:43 +0800 Subject: [PATCH 30/53] add link.x --- kernel/src/arch/riscv/trap.rs | 1 + kernel/src/boards/seeed_xiao_esp32c3/link.x | 80 ++++++++++----------- kernel/src/time/timer.rs | 3 +- 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index 48fd4283..257046fe 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -233,6 +233,7 @@ fn might_switch_context(from: &Context, ra: usize) -> usize { extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: usize) -> usize { debug_assert!(!super::local_irq_enabled()); let sp = ctx as *const _ as usize; + // #[cfg(has_plic)] match mcause & (INTERRUPT_MASK | 0x3f) { EXTERN_INT => { handle_plic_irq(ctx, mcause, mtval); diff --git a/kernel/src/boards/seeed_xiao_esp32c3/link.x b/kernel/src/boards/seeed_xiao_esp32c3/link.x index 436017e8..caf34196 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/link.x +++ b/kernel/src/boards/seeed_xiao_esp32c3/link.x @@ -1,7 +1,7 @@ /* This code is derived from - * https://github.com/eclipse-threadx/threadx/blob/master/ports/risc-v64/gnu/example_build/qemu_virt/link.lds - * Copyright (c) 2024 - present Microsoft Corporation - * SPDX-License-Identifier: MIT + * https://github.com/esp-rs/esp-hal/tree/main/esp-hal/ld/esp32c3 + * Copyright 2021 esp-rs + * License: Apache-2.0 OR MIT */ OUTPUT_ARCH("riscv") @@ -60,43 +60,6 @@ REGION_ALIAS("RWTEXT", IRAM); REGION_ALIAS("RTC_FAST_RWTEXT", RTC_FAST); REGION_ALIAS("RTC_FAST_RWDATA", RTC_FAST); -SECTIONS { - .rotext_dummy (NOLOAD) : - { - /* This dummy section represents the .rodata section within ROTEXT. - * Since the same physical memory is mapped to both DROM and IROM, - * we need to make sure the .rodata and .text sections don't overlap. - * We skip the amount of memory taken by .rodata* in .text - */ - - /* Start at the same alignment constraint than .flash.text */ - - . = ALIGN(ALIGNOF(.rodata)); - - /* Create an empty gap as big as .text section */ - - . = . + SIZEOF(.rodata_desc); - . = . + SIZEOF(.rodata); - - /* Prepare the alignment of the section above. Few bytes (0x20) must be - * added for the mapping header. - */ - - . = ALIGN(0x10000) + 0x20; - _rotext_reserved_start = .; - } > ROTEXT -} -INSERT BEFORE .text; - -/* Similar to .rotext_dummy this represents .rwtext but in .data */ -SECTIONS { - .rwdata_dummy (NOLOAD) : ALIGN(4) - { - . = . + SIZEOF(.rwtext) + SIZEOF(.rwtext.wifi) + SIZEOF(.trap); - } > RWDATA -} -INSERT BEFORE .data; - SECTIONS { .trap : ALIGN(4) { @@ -130,6 +93,11 @@ SECTIONS { _rwtext_len = . - ORIGIN(RWTEXT); } > RWTEXT + .rwdata_dummy (NOLOAD) : ALIGN(4) + { + . = . + SIZEOF(.rwtext) + SIZEOF(.rwtext.wifi) + SIZEOF(.trap); + } > RWDATA + .data : ALIGN(4) { _data_start = ABSOLUTE(.); @@ -216,6 +184,31 @@ SECTIONS { } SECTIONS { + .rotext_dummy (NOLOAD) : + { + /* This dummy section represents the .rodata section within ROTEXT. + * Since the same physical memory is mapped to both DROM and IROM, + * we need to make sure the .rodata and .text sections don't overlap. + * We skip the amount of memory taken by .rodata* in .text + */ + + /* Start at the same alignment constraint than .flash.text */ + + . = ALIGN(ALIGNOF(.rodata)); + + /* Create an empty gap as big as .text section */ + + . = . + SIZEOF(.rodata_desc); + . = . + SIZEOF(.rodata); + + /* Prepare the alignment of the section above. Few bytes (0x20) must be + * added for the mapping header. + */ + + . = ALIGN(0x10000) + 0x20; + _rotext_reserved_start = .; + } > ROTEXT + .text : ALIGN(4) { KEEP(*(.init)); @@ -287,4 +280,11 @@ SECTIONS { } } +SECTIONS { + .eh_frame 0 (INFO) : + { + KEEP(*(.eh_frame)); + } +} + PROVIDE(__global_pointer$ = ALIGN(_data_start, 4) + 0x800); diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 70a332ff..52d97223 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -590,7 +590,8 @@ mod tests { #[test] fn test_timer_accuracy() { - use crate::{boards::ClockImpl, devices::clock::Clock}; + use crate::boards::ClockImpl; + use blueos_hal::clock::Clock; let start = ClockImpl::estimate_current_cycles(); scheduler::suspend_me_for::<()>( Tick(blueos_kconfig::CONFIG_TICKS_PER_SECOND as usize), From 072f41d04b650f240d49ad5e3a4a5e3f38d5f178 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 27 Feb 2026 12:04:55 +0800 Subject: [PATCH 31/53] make mtime optional --- arch/riscv/Kconfig | 8 +++++++- kernel/src/boards/gd32vw553_eval/Kconfig | 1 + kernel/src/boards/qemu_riscv32/Kconfig | 1 + kernel/src/boards/qemu_riscv64/Kconfig | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 2f9161d6..200b0097 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -19,5 +19,11 @@ config HAS_MIE default n help Whether the platform supports the MIE. - + +config HAS_MTIME + bool "MTIME supports" + default n + help + Whether the platform supports the MTIME. + endmenu diff --git a/kernel/src/boards/gd32vw553_eval/Kconfig b/kernel/src/boards/gd32vw553_eval/Kconfig index 2ed3b3a4..fa7ec211 100644 --- a/kernel/src/boards/gd32vw553_eval/Kconfig +++ b/kernel/src/boards/gd32vw553_eval/Kconfig @@ -3,4 +3,5 @@ config SOC_GD32VW553 default y select RISCV select HAS_MIE + select HAS_MTIME select HAS_PLIC diff --git a/kernel/src/boards/qemu_riscv32/Kconfig b/kernel/src/boards/qemu_riscv32/Kconfig index bf8d6157..9c7e1f95 100644 --- a/kernel/src/boards/qemu_riscv32/Kconfig +++ b/kernel/src/boards/qemu_riscv32/Kconfig @@ -24,4 +24,5 @@ config SOC_QEMU_VIRT_RISCV32 default y select RISCV select HAS_MIE + select HAS_MTIME select HAS_PLIC diff --git a/kernel/src/boards/qemu_riscv64/Kconfig b/kernel/src/boards/qemu_riscv64/Kconfig index a34d6753..fa6db182 100644 --- a/kernel/src/boards/qemu_riscv64/Kconfig +++ b/kernel/src/boards/qemu_riscv64/Kconfig @@ -24,4 +24,5 @@ config SOC_QEMU_VIRT_RISCV64 default y select RISCV select HAS_MIE + select HAS_MTIME select HAS_PLIC From 6baeadaa4e5081895922133f8c7998b83c43c805 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 27 Feb 2026 12:07:22 +0800 Subject: [PATCH 32/53] minor --- kernel/src/arch/riscv/trap.rs | 19 +++-- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 82 +++++++++------------ 2 files changed, 47 insertions(+), 54 deletions(-) diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index 257046fe..30dc8725 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -17,7 +17,7 @@ use super::{ }; use crate::{ arch, - boards::{clear_ipi, handle_plic_irq}, + boards::clear_ipi, debug, irq::{enter_irq, leave_irq}, rv_restore_context, rv_restore_context_epilogue, rv_save_context, rv_save_context_prologue, @@ -55,7 +55,6 @@ extern "C" fn switch_stack_with_hook( // trap_handler decides whether nested interrupt is allowed. #[repr(align(4))] -#[no_mangle] #[link_section = ".trap.handler"] #[naked] pub(crate) unsafe extern "C" fn trap_entry() { @@ -233,17 +232,14 @@ fn might_switch_context(from: &Context, ra: usize) -> usize { extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: usize) -> usize { debug_assert!(!super::local_irq_enabled()); let sp = ctx as *const _ as usize; - // #[cfg(has_plic)] match mcause & (INTERRUPT_MASK | 0x3f) { + #[cfg(has_plic)] EXTERN_INT => { + use crate::boards::handle_plic_irq; handle_plic_irq(ctx, mcause, mtval); might_switch_context(ctx, cont) } - _ if mcause & 0x8000_0000 != 0 => { - // esp32c3 has another external interrupt number - handle_plic_irq(ctx, mcause, mtval); - might_switch_context(ctx, cont) - } + #[cfg(has_mtime)] TIMER_INT => { crate::time::handle_clock_interrupt(); might_switch_context(ctx, cont) @@ -254,6 +250,13 @@ extern "C" fn handle_trap(ctx: &mut Context, mcause: usize, mtval: usize, cont: clear_ipi(arch::current_cpu_id()); sp } + #[cfg(not(has_plic))] + _ if mcause & 0x8000_0000 != 0 => { + use crate::boards::handle_intc_irq; + // esp32c3 has another external interrupt number + handle_intc_irq(ctx, mcause, mtval); + might_switch_context(ctx, cont) + } _ => { let t = scheduler::current_thread_ref(); panic!( diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 256d1641..470f8053 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -12,24 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -// This code is based on -// https://github.com/esp-rs/esp-hal/blob/main/esp-bootloader-esp-idf/src/lib.rs -// Copyright (c) 2024 - present Microsoft Corporation -// SPDX-License-Identifier: MIT - mod config; use crate::{ arch, arch::riscv::{local_irq_enabled, trap_entry, Context}, - drivers::ic::plic::Plic, - scheduler, - support::SmpStagedInit, - time, + scheduler, time, }; use blueos_driver::interrupt_controller::Interrupt; use blueos_hal::Has8bitDataReg; -use core::sync::atomic::Ordering; -pub(crate) static PLIC: Plic = Plic::new(config::PLIC_BASE); // FIXME: Only support unit0 for now pub type ClockImpl = blueos_driver::systimer::esp32_sys_timer::Esp32SysTimer<0x6002_3000, 16_000_000>; @@ -45,39 +35,40 @@ core::arch::global_asm!( .option norvc _vector_table: - j trap_entry // 0: Instruction address misaligned - j trap_entry // 1: Instruction access fault - j trap_entry // 2: Illegal instruction - j trap_entry // 3: Breakpoint - j trap_entry // 4: Load address misaligned - j trap_entry // 5: Load access fault - j trap_entry // 6: Store/AMO address misaligned - j trap_entry // 7: Store/AMO access fault - j trap_entry // 8: Environment call from U-mode - j trap_entry // 9: Environment call from S-mode - j trap_entry // 10: Reserved - j trap_entry // 11: Environment call from M-mode - j trap_entry // 12: Instruction page fault - j trap_entry // 13: Load page fault - j trap_entry // 14: Reserved - j trap_entry // 15: Store/AMO page fault - j trap_entry // 16: Reserved - j trap_entry // 17: Reserved - j trap_entry // 18: Reserved - j trap_entry // 19: Reserved - j trap_entry // 20: Reserved - j trap_entry // 21: Reserved - j trap_entry // 22: Reserved - j trap_entry // 23: Reserved - j trap_entry // 24: Reserved - j trap_entry // 25: Reserved - j trap_entry // 26: Reserved - j trap_entry // 27: Reserved - j trap_entry // 28: Reserved - j trap_entry // 29: Reserved - j trap_entry // 30: Reserved - j trap_entry // 31: Reserved - " + j {trap_entry} // 0: Exception + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + j {trap_entry} + ", + trap_entry = sym trap_entry, ); #[inline] @@ -96,7 +87,7 @@ fn init_vector_table() { } } -pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { +pub(crate) fn handle_intc_irq(ctx: &Context, mcause: usize, mtval: usize) { let cpu_id = arch::current_cpu_id(); match mcause & 0xff { TARGET0_INT_NUM => { @@ -108,7 +99,6 @@ pub(crate) fn handle_plic_irq(ctx: &Context, mcause: usize, mtval: usize) { } _ => {} } - // PLIC.complete(cpu_id, PLIC.claim(cpu_id)) } const TARGET0_INT_NUM: usize = 16; From 81d96ff90222cb04d4e8d024c69a05e26f54d1f7 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Fri, 27 Feb 2026 17:30:07 +0800 Subject: [PATCH 33/53] Apply suggestion from @lawkai-vivo --- kconfig/config/seeed_xiao_esp32c3/release/defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kconfig/config/seeed_xiao_esp32c3/release/defconfig b/kconfig/config/seeed_xiao_esp32c3/release/defconfig index f2d36a7e..173b34e6 100644 --- a/kconfig/config/seeed_xiao_esp32c3/release/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/release/defconfig @@ -12,7 +12,7 @@ CONFIG_USE_KERNEL_BOOT=y # CONFIG_SOFT_TIMER=y CONFIG_EVENT_FLAGS=y -CONFIG_ROBIN_SCHEDULER=y +CONFIG_ROUND_ROBIN=y CONFIG_ROBIN_SLICE=10 CONFIG_OVERFLOW_CHECK=y CONFIG_STACK_HIGHWATER_CHECK=y From f738d1900c14b27009bc562072a99c09efec6247 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Fri, 27 Feb 2026 17:31:04 +0800 Subject: [PATCH 34/53] Update kconfig/config/seeed_xiao_esp32c3/debug/defconfig --- kconfig/config/seeed_xiao_esp32c3/debug/defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index 349fc421..ab851bda 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -12,7 +12,7 @@ CONFIG_USE_KERNEL_BOOT=y # CONFIG_SOFT_TIMER=y CONFIG_EVENT_FLAGS=y -CONFIG_ROBIN_SCHEDULER=n +CONFIG_ROUND_ROBIN=n CONFIG_ROBIN_SLICE=10 CONFIG_OVERFLOW_CHECK=y CONFIG_STACK_HIGHWATER_CHECK=y From 6f561e8ed20dbdb1893201bf49b0ff52c600297d Mon Sep 17 00:00:00 2001 From: xu chang Date: Sat, 28 Feb 2026 15:08:56 +0800 Subject: [PATCH 35/53] Update driver/src/systimer/esp32_sys_timer.rs Co-authored-by: Kai Law --- driver/src/systimer/esp32_sys_timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index fbfb16a9..8ea8bcf4 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -156,7 +156,7 @@ impl Esp32SysTimer { } #[inline] - pub fn clr_interrupt() { + pub fn clear_interrupt() { Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); } From 44b2583563ca2e81be02a6aab3b3fa611da40aa0 Mon Sep 17 00:00:00 2001 From: xu chang Date: Sat, 28 Feb 2026 15:09:11 +0800 Subject: [PATCH 36/53] Update driver/src/systimer/esp32_sys_timer.rs Co-authored-by: Kai Law --- driver/src/systimer/esp32_sys_timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index 8ea8bcf4..239da988 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -166,7 +166,7 @@ impl Esp32SysTimer { .modify(TARGET_CONF::TIMER_UNIT_SEL::CLEAR); } - fn set_comparator_enable(enable: bool) { + fn set_comparator(enable: bool) { Self::registers().conf.modify(if enable { CONF::TARGET0_WORK_EN::SET } else { From c9c20a20464b5de7ec90a77de148ab3ea9a8be44 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Sat, 28 Feb 2026 17:45:35 +0800 Subject: [PATCH 37/53] add unittest_kernel --- kernel/BUILD.gn | 21 +++++++++++++++++++++ kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/kernel/BUILD.gn b/kernel/BUILD.gn index 3925e58e..a4f4ecd2 100644 --- a/kernel/BUILD.gn +++ b/kernel/BUILD.gn @@ -195,6 +195,27 @@ if (defined(use_defmt) && use_defmt) { img = ":kernel_unittest" chip = "$chip" } +} else if (defined(qemu_use_esp32_loader) && qemu_use_esp32_loader) { + gen_esp32_image("kernel_unittest_image") { + testonly = true + elf = ":kernel_unittest" + chip = "${chip}" + bootloader = qemu_esp32_bootloader_bin + partition_table = qemu_esp32_partition_table_bin + } + + gen_qemu_runner("unittest_runner") { + testonly = true + img = ":kernel_unittest_image" + qemu = "$qemu_exe" + machine = "$machine" + qemu_args = qemu_extra_args + block_img = "unittest_block.img" + block_args = qemu_block_args + block_interface = qemu_block_interface + use_esp32_loader = qemu_use_esp32_loader + semihosting = true + } } else { gen_qemu_runner("unittest_runner") { testonly = true diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 470f8053..144471be 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -77,7 +77,7 @@ fn init_vector_table() { static _vector_table: u32; } let mut v = core::ptr::addr_of!(_vector_table) as usize; - v |= 0x3; // Set MODE to Vectored + // v |= 0x3; // Set MODE to Vectored unsafe { core::arch::asm!( "csrw mtvec, {0}", From 85fce7b4802d97e7a6436f30e48ebcc2d7d49ee4 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Sat, 28 Feb 2026 17:59:31 +0800 Subject: [PATCH 38/53] fix bug --- driver/src/systimer/esp32_sys_timer.rs | 2 +- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index 239da988..8ea8bcf4 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -166,7 +166,7 @@ impl Esp32SysTimer { .modify(TARGET_CONF::TIMER_UNIT_SEL::CLEAR); } - fn set_comparator(enable: bool) { + fn set_comparator_enable(enable: bool) { Self::registers().conf.modify(if enable { CONF::TARGET0_WORK_EN::SET } else { diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 144471be..7b5eb6af 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -91,7 +91,7 @@ pub(crate) fn handle_intc_irq(ctx: &Context, mcause: usize, mtval: usize) { let cpu_id = arch::current_cpu_id(); match mcause & 0xff { TARGET0_INT_NUM => { - ClockImpl::clr_interrupt(); + ClockImpl::clear_interrupt(); crate::time::handle_clock_interrupt(); } USB_SERIAL_JTAG_INT_NUM => { From feda84882f3ee04a2e1b18962e27d6d6f613cb31 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Mon, 2 Mar 2026 11:12:31 +0800 Subject: [PATCH 39/53] set unittest thread num options --- kconfig/BUILD.gn | 1 + kconfig/config/Kconfig | 3 ++- kconfig/config/Kconfig.test | 12 ++++++++++++ kconfig/config/seeed_xiao_esp32c3/debug/defconfig | 1 + kconfig/config/seeed_xiao_esp32c3/release/defconfig | 1 + kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 1 - kernel/src/sync/barrier.rs | 7 ++++--- 7 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 kconfig/config/Kconfig.test diff --git a/kconfig/BUILD.gn b/kconfig/BUILD.gn index 86f085b2..c365cfb5 100644 --- a/kconfig/BUILD.gn +++ b/kconfig/BUILD.gn @@ -25,6 +25,7 @@ _kconfig_files = [ "//kernel/kernel/src/vfs/Kconfig", "//kernel/kernel/src/net/Kconfig", "//kernel/arch/riscv/Kconfig", + "config/Kconfig.test", ] _config_file = rebase_path("${root_gen_dir}/.config") diff --git a/kconfig/config/Kconfig b/kconfig/config/Kconfig index 28c6f248..d127b4be 100644 --- a/kconfig/config/Kconfig +++ b/kconfig/config/Kconfig @@ -9,4 +9,5 @@ rsource "../../kernel/src/Kconfig" rsource "../../kernel/src/allocator/Kconfig" rsource "../../kernel/src/scheduler/Kconfig" rsource "../../kernel/src/vfs/Kconfig" -rsource "../../kernel/src/net/Kconfig" \ No newline at end of file +rsource "../../kernel/src/net/Kconfig" +rsource "Kconfig.test" diff --git a/kconfig/config/Kconfig.test b/kconfig/config/Kconfig.test new file mode 100644 index 00000000..e4219b46 --- /dev/null +++ b/kconfig/config/Kconfig.test @@ -0,0 +1,12 @@ +# Kconfig.test +# +# This Kconfig file is used to configure options for tests, including: +# - Unit tests +# - Integration tests +# - Other test-related cases and infrastructure +# +config UNITTEST_THREAD_NUM + int "The num of thread used by uniitest." + default 64 + help + Set the number of thread used by unittest. diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index ab851bda..6e5739bf 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -32,3 +32,4 @@ CONFIG_SERIAL_TX_FIFO_SIZE=256 CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n +CONFIG_UNITTEST_THREAD_NUM=16 diff --git a/kconfig/config/seeed_xiao_esp32c3/release/defconfig b/kconfig/config/seeed_xiao_esp32c3/release/defconfig index 173b34e6..c29c801c 100644 --- a/kconfig/config/seeed_xiao_esp32c3/release/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/release/defconfig @@ -32,3 +32,4 @@ CONFIG_SERIAL_TX_FIFO_SIZE=256 CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n +CONFIG_UNITTEST_THREAD_NUM=16 diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 7b5eb6af..dc0e93d1 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -77,7 +77,6 @@ fn init_vector_table() { static _vector_table: u32; } let mut v = core::ptr::addr_of!(_vector_table) as usize; - // v |= 0x3; // Set MODE to Vectored unsafe { core::arch::asm!( "csrw mtvec, {0}", diff --git a/kernel/src/sync/barrier.rs b/kernel/src/sync/barrier.rs index 4a27f86e..49272c6c 100644 --- a/kernel/src/sync/barrier.rs +++ b/kernel/src/sync/barrier.rs @@ -55,13 +55,14 @@ mod tests { use crate::{static_arc, types::Arc}; use alloc::vec::Vec; use blueos_test_macro::test; + const UNITTEST_THREAD_NUM: usize = blueos_kconfig::CONFIG_UNITTEST_THREAD_NUM as usize; static_arc! { BARRIER(ConstBarrier<2>, ConstBarrier::<{ 2 }>::new()), } static_arc! { - BARRIER_MANY(ConstBarrier<64>, ConstBarrier::<{ 64 }>::new()), + BARRIER_MANY(ConstBarrier<{UNITTEST_THREAD_NUM}>, ConstBarrier::<{UNITTEST_THREAD_NUM}>::new()), } #[test] @@ -75,7 +76,7 @@ mod tests { // Should not hang. #[test] fn stress_barrier() { - for i in 0..63 { + for i in 0..UNITTEST_THREAD_NUM - 1 { crate::thread::spawn(|| { BARRIER_MANY.wait(); }); @@ -85,7 +86,7 @@ mod tests { #[test] fn join_thread() { - let n = 64; + let n = UNITTEST_THREAD_NUM; let mut vt = Vec::new(); let counter = Arc::new(AtomicUsize::new(n)); for i in 0..n { From 809776bf98c5beecbe1899b0dcc514d631fed97b Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 4 Mar 2026 11:18:59 +0800 Subject: [PATCH 40/53] fix --- driver/src/interrupt_controller/esp32_intc.rs | 2 +- driver/src/systimer/esp32_sys_timer.rs | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index 71603ce9..bfe9f4b8 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -72,7 +72,7 @@ impl Esp32Intc { } pub fn set_priority(&self, irq: Interrupt, priority: u8) { - self.registers.priority_reg[(irq.irq_no - 1) as usize] + self.registers.priority_reg[irq.irq_no as usize] .write(PRIORITY_REG::PRIORITY.val(priority as u32)); } diff --git a/driver/src/systimer/esp32_sys_timer.rs b/driver/src/systimer/esp32_sys_timer.rs index 8ea8bcf4..5309eb76 100644 --- a/driver/src/systimer/esp32_sys_timer.rs +++ b/driver/src/systimer/esp32_sys_timer.rs @@ -138,6 +138,14 @@ impl Esp32SysTimer { unsafe { &*(BASE_ADDR as *const Registers) } } + fn enable_interrupt(enable: bool) { + Self::registers().int_ena.modify(if enable { + INT_ENA::TARGET0::SET + } else { + INT_ENA::TARGET0::CLEAR + }); + } + pub fn init() { // enable unit 0 Self::registers().conf.modify(CONF::CLK_EN::SET); @@ -147,8 +155,10 @@ impl Esp32SysTimer { Self::set_unit(); // CLR interrupt Self::registers().int_clr.modify(INT_CLR::TARGET0::SET); + // disable comparator + Self::set_comparator_enable(false); // enable interrupt - Self::registers().int_ena.modify(INT_ENA::TARGET0::SET); + Self::enable_interrupt(true); // set TARGET mode Self::registers() .target0_conf @@ -166,7 +176,7 @@ impl Esp32SysTimer { .modify(TARGET_CONF::TIMER_UNIT_SEL::CLEAR); } - fn set_comparator_enable(enable: bool) { + pub fn set_comparator_enable(enable: bool) { Self::registers().conf.modify(if enable { CONF::TARGET0_WORK_EN::SET } else { @@ -207,12 +217,18 @@ impl Clock for Esp32SysTimer> 32) as u32)); Self::registers() .target0_lo .write(TARGET_LO::LO.val((moment & 0xFFFF_FFFF) as u32)); + // load comparator Self::registers().comp0_load.write(COMP_LOAD::LOAD::SET); Self::set_comparator_enable(true); From 9275715f03f7ce1f43fc9240424d28df5b70a115 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 4 Mar 2026 11:19:48 +0800 Subject: [PATCH 41/53] del unncessary logic --- kernel/src/time.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/src/time.rs b/kernel/src/time.rs index 8a8b6429..9d83982b 100644 --- a/kernel/src/time.rs +++ b/kernel/src/time.rs @@ -44,7 +44,6 @@ impl Tick { if n == Self::MAX { return Self::MAX; } - let now = Self::now(); Self(Self::now().0 + n.0) } From 9f468852a23541350fdbc4fd515639e5349e1f5d Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Wed, 4 Mar 2026 11:46:47 +0800 Subject: [PATCH 42/53] minor --- kernel/BUILD.gn | 6 ++++++ kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 1 + kernel/src/lib.rs | 6 +++--- kernel/src/sync/mutex.rs | 4 ++-- kernel/src/time/timer.rs | 4 +++- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/kernel/BUILD.gn b/kernel/BUILD.gn index a4f4ecd2..4cbd58d6 100644 --- a/kernel/BUILD.gn +++ b/kernel/BUILD.gn @@ -98,6 +98,12 @@ build_rust("kernel_unittest") { "--test", "-Zpanic-abort-tests", ] + if (defined(chip)) { + rustflags += [ + "--cfg", + "target_chip=\"${chip}\"", + ] + } } run_clippy("kernel_unittest_clippy") { diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index dc0e93d1..92094b74 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -77,6 +77,7 @@ fn init_vector_table() { static _vector_table: u32; } let mut v = core::ptr::addr_of!(_vector_table) as usize; + v |= 1; // set the least significant bit to enable vectored mode unsafe { core::arch::asm!( "csrw mtvec, {0}", diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index de2877f0..bad4f29f 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -509,7 +509,7 @@ mod tests { #[test] fn stress_build_threads() { #[cfg(target_pointer_width = "32")] - let n = 32; + let n = blueos_kconfig::CONFIG_UNITTEST_THREAD_NUM as usize / 2; #[cfg(all(debug_assertions, target_pointer_width = "64"))] let n = 32; #[cfg(all(not(debug_assertions), target_pointer_width = "64"))] @@ -532,7 +532,7 @@ mod tests { #[test] fn stress_spawn_threads() { #[cfg(target_pointer_width = "32")] - let n = 32; + let n = blueos_kconfig::CONFIG_UNITTEST_THREAD_NUM as usize / 2; #[cfg(all(debug_assertions, target_pointer_width = "64"))] let n = 32; #[cfg(all(not(debug_assertions), target_pointer_width = "64"))] @@ -711,7 +711,7 @@ mod tests { } static SCHED_TIMERS_CLEANUP: CleanupCounter = CleanupCounter::new(); - #[test] + fn stress_sched_timers() { reset_and_queue_test_threads(test_sched_timers, Some(test_sched_timers_cleanup)); let l = unsafe { TEST_THREADS.len() }; diff --git a/kernel/src/sync/mutex.rs b/kernel/src/sync/mutex.rs index 9d57403d..2a50e782 100644 --- a/kernel/src/sync/mutex.rs +++ b/kernel/src/sync/mutex.rs @@ -744,7 +744,7 @@ mod tests { fn test_acquire_many_mutexes() { use crate::config::MAX_THREAD_PRIORITY; #[cfg(target_pointer_width = "32")] - const N: usize = 64; + const N: usize = blueos_kconfig::CONFIG_UNITTEST_THREAD_NUM as usize; #[cfg(target_pointer_width = "32")] const M: usize = N / 8; #[cfg(target_pointer_width = "64")] @@ -835,7 +835,7 @@ mod tests { // Thread group1 acquires MG1, MG2, MG4 use crate::config::MAX_THREAD_PRIORITY; #[cfg(target_pointer_width = "32")] - const N: usize = 16; + const N: usize = (blueos_kconfig::CONFIG_UNITTEST_THREAD_NUM / 4) as usize; #[cfg(target_pointer_width = "32")] const M: usize = N / 4; #[cfg(target_pointer_width = "64")] diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 52d97223..6adf0e01 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -421,7 +421,9 @@ mod tests { assert_eq!(counter3.load(Ordering::Relaxed), 1); } - #[test] + // Alarm cannot be triggered on esp32c3 when the target is too old. + // See https://github.com/espressif/qemu/issues/69 + #[cfg_attr(not(target_chip = "esp32c3"), test)] fn test_timer_edge_cases() { // Test with zero interval. let counter = Arc::new(AtomicUsize::new(0)); From 773d0a9d1e6f61025906a2bcefe110a7f424fad4 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 10:04:50 +0800 Subject: [PATCH 43/53] add check_all --- driver/src/interrupt_controller/esp32_intc.rs | 2 +- driver/src/uart/esp32_usb_serial.rs | 6 +++ hal/src/lib.rs | 13 ++--- kernel/BUILD.gn | 54 ++++++++++++++----- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 4 +- kernel/src/devices/tty/serial/uart.rs | 2 +- kernel/tests/test_vfs.rs | 10 +++- 7 files changed, 64 insertions(+), 27 deletions(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index bfe9f4b8..71603ce9 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -72,7 +72,7 @@ impl Esp32Intc { } pub fn set_priority(&self, irq: Interrupt, priority: u8) { - self.registers.priority_reg[irq.irq_no as usize] + self.registers.priority_reg[(irq.irq_no - 1) as usize] .write(PRIORITY_REG::PRIORITY.val(priority as u32)); } diff --git a/driver/src/uart/esp32_usb_serial.rs b/driver/src/uart/esp32_usb_serial.rs index 247ae40e..5248c7cc 100644 --- a/driver/src/uart/esp32_usb_serial.rs +++ b/driver/src/uart/esp32_usb_serial.rs @@ -217,6 +217,12 @@ impl HasFifo for Esp32UsbSerial { .is_set(EP1_CONF_REG::OUT_EP_DATA_AVAIL) != true } + + fn flush(&self) { + USB_SERIAL_BASE + .ep1_conf_reg + .write(EP1_CONF_REG::WR_DONE.val(1)); + } } impl HasInterruptReg for Esp32UsbSerial { diff --git a/hal/src/lib.rs b/hal/src/lib.rs index cf94fbb7..d1d8b7bc 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -147,15 +147,10 @@ pub trait HasInterruptReg { /// such as UART, SPI, I2C, and other communication interfaces. /// pub trait HasFifo { - fn enable_fifo(&self, num: u8) -> Result<()> { - Ok(()) - } - fn is_tx_fifo_full(&self) -> bool { - false - } - fn is_rx_fifo_empty(&self) -> bool { - false - } + fn enable_fifo(&self, num: u8) -> Result<()>; + fn is_tx_fifo_full(&self) -> bool; + fn is_rx_fifo_empty(&self) -> bool; + fn flush(&self) {} } /// Status register operations trait diff --git a/kernel/BUILD.gn b/kernel/BUILD.gn index 4cbd58d6..0dab3748 100644 --- a/kernel/BUILD.gn +++ b/kernel/BUILD.gn @@ -133,6 +133,12 @@ build_rust("kernel_integration_test") { "--test", "-Zpanic-abort-tests", ] + if (defined(chip)) { + rustflags += [ + "--cfg", + "target_chip=\"${chip}\"", + ] + } } run_clippy("kernel_integration_test_clippy") { @@ -172,16 +178,40 @@ cbindgen("rust_wrapper") { rebase_path([ "." ], root_build_dir) } -gen_qemu_runner("integration_test_runner") { - testonly = true - semihosting = true - img = ":kernel_integration_test" - qemu = qemu_exe - machine = machine - qemu_args = qemu_extra_args - net_args = qemu_net_args - block_img = "integration_test_block.img" - block_args = qemu_block_args +if (defined(qemu_use_esp32_loader) && qemu_use_esp32_loader) { + gen_esp32_image("kernel_integration_test_esp32_image") { + testonly = true + elf = ":kernel_integration_test" + chip = "${chip}" + bootloader = qemu_esp32_bootloader_bin + partition_table = qemu_esp32_partition_table_bin + } + + gen_qemu_runner("integration_test_runner") { + testonly = true + img = ":kernel_integration_test_esp32_image" + qemu = qemu_exe + machine = machine + qemu_args = qemu_extra_args + net_args = qemu_net_args + block_img = "integration_test_block.img" + block_args = qemu_block_args + block_interface = qemu_block_interface + use_esp32_loader = qemu_use_esp32_loader + semihosting = true + } +} else { + gen_qemu_runner("integration_test_runner") { + testonly = true + semihosting = true + img = ":kernel_integration_test" + qemu = qemu_exe + machine = machine + qemu_args = qemu_extra_args + net_args = qemu_net_args + block_img = "integration_test_block.img" + block_args = qemu_block_args + } } run_qemu_check("run_integration_test") { @@ -202,7 +232,7 @@ if (defined(use_defmt) && use_defmt) { chip = "$chip" } } else if (defined(qemu_use_esp32_loader) && qemu_use_esp32_loader) { - gen_esp32_image("kernel_unittest_image") { + gen_esp32_image("kernel_unittest_esp32_image") { testonly = true elf = ":kernel_unittest" chip = "${chip}" @@ -212,7 +242,7 @@ if (defined(use_defmt) && use_defmt) { gen_qemu_runner("unittest_runner") { testonly = true - img = ":kernel_unittest_image" + img = ":kernel_unittest_esp32_image" qemu = "$qemu_exe" machine = "$machine" qemu_args = qemu_extra_args diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 92094b74..828dab9e 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -109,8 +109,8 @@ const RTC_CNTL_BASE: usize = 0x6000_8000; const RTC_CNTL_WDTWRITECT_REG: usize = RTC_CNTL_BASE + 0xA8; const RTC_CNTL_WDTCONFIG0_REG: usize = RTC_CNTL_BASE + 0x90; -const USB_SERIAL_JTAG_IRQ: Interrupt = Interrupt::new(26, 15); -const SYSTIMER_TARGET0_IRQ: Interrupt = Interrupt::new(37, 16); +const USB_SERIAL_JTAG_IRQ: Interrupt = Interrupt::new(26, USB_SERIAL_JTAG_INT_NUM); +const SYSTIMER_TARGET0_IRQ: Interrupt = Interrupt::new(37, TARGET0_INT_NUM); pub(crate) fn init() { assert!(!local_irq_enabled()); diff --git a/kernel/src/devices/tty/serial/uart.rs b/kernel/src/devices/tty/serial/uart.rs index dd814b39..1eb4f72d 100644 --- a/kernel/src/devices/tty/serial/uart.rs +++ b/kernel/src/devices/tty/serial/uart.rs @@ -113,7 +113,7 @@ where } fn flush(&mut self) -> Result<(), Self::Error> { - while self.uart.is_bus_busy() {} + self.uart.flush(); Ok(()) } } diff --git a/kernel/tests/test_vfs.rs b/kernel/tests/test_vfs.rs index a07c3bf6..08ac3c65 100644 --- a/kernel/tests/test_vfs.rs +++ b/kernel/tests/test_vfs.rs @@ -46,7 +46,10 @@ use core::{ use libc::{AF_INET, ENOSYS, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, SEEK_SET}; use semihosting::println; -#[test] +// In esp32c3, we use usb-serial as the console output, +// which does not support on qemu yet, so we skip this test on esp32c3 for now. +// See https://github.com/espressif/esp-toolchain-docs/blob/main/qemu/README.md +#[cfg_attr(not(target_chip = "esp32c3"), test)] fn test_uart() { // Test UART device path let uart_path = c"/dev/ttyS0"; @@ -417,7 +420,10 @@ fn verify_directory(path: *const c_char) -> Result<(), c_int> { Ok(()) } -#[test] +// In esp32c3, we use usb-serial as the console output, +// which does not support on qemu yet, so we skip this test on esp32c3 for now. +// See https://github.com/espressif/esp-toolchain-docs/blob/main/qemu/README.md +#[cfg_attr(not(target_chip = "esp32c3"), test)] fn test_std_fds() { // Test writing to stdout (fd 1) let test_data = b"Hello, this is a test message to stdout!\n"; From 2e1f230acbf64c5eb6299cb0e3e7c68387b042ed Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 10:31:54 +0800 Subject: [PATCH 44/53] del kconfig.test --- kconfig/BUILD.gn | 1 - kconfig/config/Kconfig | 7 ++++++- kconfig/config/Kconfig.test | 12 ------------ 3 files changed, 6 insertions(+), 14 deletions(-) delete mode 100644 kconfig/config/Kconfig.test diff --git a/kconfig/BUILD.gn b/kconfig/BUILD.gn index c365cfb5..86f085b2 100644 --- a/kconfig/BUILD.gn +++ b/kconfig/BUILD.gn @@ -25,7 +25,6 @@ _kconfig_files = [ "//kernel/kernel/src/vfs/Kconfig", "//kernel/kernel/src/net/Kconfig", "//kernel/arch/riscv/Kconfig", - "config/Kconfig.test", ] _config_file = rebase_path("${root_gen_dir}/.config") diff --git a/kconfig/config/Kconfig b/kconfig/config/Kconfig index d127b4be..f2962065 100644 --- a/kconfig/config/Kconfig +++ b/kconfig/config/Kconfig @@ -10,4 +10,9 @@ rsource "../../kernel/src/allocator/Kconfig" rsource "../../kernel/src/scheduler/Kconfig" rsource "../../kernel/src/vfs/Kconfig" rsource "../../kernel/src/net/Kconfig" -rsource "Kconfig.test" + +config UNITTEST_THREAD_NUM + int "The num of thread used by uniitest." + default 64 + help + Set the number of thread used by unittest. diff --git a/kconfig/config/Kconfig.test b/kconfig/config/Kconfig.test deleted file mode 100644 index e4219b46..00000000 --- a/kconfig/config/Kconfig.test +++ /dev/null @@ -1,12 +0,0 @@ -# Kconfig.test -# -# This Kconfig file is used to configure options for tests, including: -# - Unit tests -# - Integration tests -# - Other test-related cases and infrastructure -# -config UNITTEST_THREAD_NUM - int "The num of thread used by uniitest." - default 64 - help - Set the number of thread used by unittest. From d9108ea4360795d6bf7c9d75a4b1a9887ba2477a Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 13:47:44 +0800 Subject: [PATCH 45/53] fix compile error --- kernel/src/boards/raspberry_pico2_cortexm/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/boards/raspberry_pico2_cortexm/mod.rs b/kernel/src/boards/raspberry_pico2_cortexm/mod.rs index 8ff5b899..60b7c0f3 100644 --- a/kernel/src/boards/raspberry_pico2_cortexm/mod.rs +++ b/kernel/src/boards/raspberry_pico2_cortexm/mod.rs @@ -19,7 +19,7 @@ use crate::{ arch::{self, irq::IrqNumber}, boot, boot::INIT_BSS_DONE, - devices::clock::{systick, Clock}, + devices::clock::systick, irq::IrqTrace, time, }; From 6b35776487cf8ee4f49ac6b0e5715bc6b35714cb Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 18:07:10 +0800 Subject: [PATCH 46/53] minor --- driver/src/uart/ns16550a.rs | 14 +++++++++++++- hal/src/lib.rs | 1 - kernel/src/devices/tty/serial/uart.rs | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/driver/src/uart/ns16550a.rs b/driver/src/uart/ns16550a.rs index 75c9d440..dec3b340 100644 --- a/driver/src/uart/ns16550a.rs +++ b/driver/src/uart/ns16550a.rs @@ -86,7 +86,19 @@ impl Has8bitDataReg for Ns16550a<'static> { impl HasLineStatusReg for Ns16550a<'static> {} -impl HasFifo for Ns16550a<'static> {} +impl HasFifo for Ns16550a<'static> { + fn enable_fifo(&self, num: u8) -> blueos_hal::err::Result<()> { + todo!() + } + + fn is_tx_fifo_full(&self) -> bool { + false + } + + fn is_rx_fifo_empty(&self) -> bool { + false + } +} impl HasInterruptReg for Ns16550a<'static> { type InterruptType = super::InterruptType; diff --git a/hal/src/lib.rs b/hal/src/lib.rs index d1d8b7bc..9ad0056d 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -150,7 +150,6 @@ pub trait HasFifo { fn enable_fifo(&self, num: u8) -> Result<()>; fn is_tx_fifo_full(&self) -> bool; fn is_rx_fifo_empty(&self) -> bool; - fn flush(&self) {} } /// Status register operations trait diff --git a/kernel/src/devices/tty/serial/uart.rs b/kernel/src/devices/tty/serial/uart.rs index 1eb4f72d..dd814b39 100644 --- a/kernel/src/devices/tty/serial/uart.rs +++ b/kernel/src/devices/tty/serial/uart.rs @@ -113,7 +113,7 @@ where } fn flush(&mut self) -> Result<(), Self::Error> { - self.uart.flush(); + while self.uart.is_bus_busy() {} Ok(()) } } From bddf29a163dd61b80893eb2892279e76d4d3d170 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 18:08:49 +0800 Subject: [PATCH 47/53] minor --- driver/src/uart/esp32_usb_serial.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/driver/src/uart/esp32_usb_serial.rs b/driver/src/uart/esp32_usb_serial.rs index 5248c7cc..247ae40e 100644 --- a/driver/src/uart/esp32_usb_serial.rs +++ b/driver/src/uart/esp32_usb_serial.rs @@ -217,12 +217,6 @@ impl HasFifo for Esp32UsbSerial { .is_set(EP1_CONF_REG::OUT_EP_DATA_AVAIL) != true } - - fn flush(&self) { - USB_SERIAL_BASE - .ep1_conf_reg - .write(EP1_CONF_REG::WR_DONE.val(1)); - } } impl HasInterruptReg for Esp32UsbSerial { From 09522fa6b28b2065f7f625b04cdb695e03381c41 Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 18:09:44 +0800 Subject: [PATCH 48/53] minor --- driver/src/uart/ns16550a.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/driver/src/uart/ns16550a.rs b/driver/src/uart/ns16550a.rs index dec3b340..b4de9b62 100644 --- a/driver/src/uart/ns16550a.rs +++ b/driver/src/uart/ns16550a.rs @@ -91,6 +91,8 @@ impl HasFifo for Ns16550a<'static> { todo!() } + // FIXME: the current implementation is just a placeholder, + // we need to read the actual register to determine the status of the FIFO. fn is_tx_fifo_full(&self) -> bool { false } From e81d05f7cd1531401ebf85e195624f8a6895ab1b Mon Sep 17 00:00:00 2001 From: xu chang Date: Fri, 6 Mar 2026 18:21:49 +0800 Subject: [PATCH 49/53] Update driver/src/interrupt_controller/esp32_intc.rs Co-authored-by: Kai Law --- driver/src/interrupt_controller/esp32_intc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index 71603ce9..47ce0057 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -57,7 +57,7 @@ impl Esp32Intc { } } - pub fn alloc_irq(&self, irq: Interrupt) { + pub fn allocate_irq(&self, irq: Interrupt) { let mut map_reg = self.registers.inner() as *const IntcRegisters as usize + irq.source_no * 4; unsafe { From 66d42f2edb71d52438fb0464bfe44a2d9ed288a9 Mon Sep 17 00:00:00 2001 From: xu chang Date: Fri, 6 Mar 2026 18:22:01 +0800 Subject: [PATCH 50/53] Update driver/src/interrupt_controller/esp32_intc.rs Co-authored-by: Kai Law --- driver/src/interrupt_controller/esp32_intc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index 47ce0057..1f60d104 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -41,7 +41,7 @@ register_bitfields! [ PRIORITY OFFSET(0) NUMBITS(4) [], ], - pub THRESH_REG [ + pub THRESHOLD_REG [ THRESH OFFSET(0) NUMBITS(4) [], ], ]; From 8012b8c8e8fc9a6fc05e143083fe5d22d693834a Mon Sep 17 00:00:00 2001 From: xu chang Date: Fri, 6 Mar 2026 18:22:14 +0800 Subject: [PATCH 51/53] Update driver/src/interrupt_controller/esp32_intc.rs Co-authored-by: Kai Law --- driver/src/interrupt_controller/esp32_intc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index 1f60d104..f41fbe3c 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -76,7 +76,7 @@ impl Esp32Intc { .write(PRIORITY_REG::PRIORITY.val(priority as u32)); } - pub fn set_thresh(&self, thresh: u8) { + pub fn set_threshold(&self, threshold: u8) { self.registers .thresh_reg .write(THRESH_REG::THRESH.val(thresh as u32)); From b97453654c532cb5a8442fc1c014da9f33d2589c Mon Sep 17 00:00:00 2001 From: xu chang Date: Fri, 6 Mar 2026 18:22:25 +0800 Subject: [PATCH 52/53] Update driver/src/interrupt_controller/esp32_intc.rs Co-authored-by: Kai Law --- driver/src/interrupt_controller/esp32_intc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index f41fbe3c..30f776ef 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -42,7 +42,7 @@ register_bitfields! [ ], pub THRESHOLD_REG [ - THRESH OFFSET(0) NUMBITS(4) [], + THRESHOLD OFFSET(0) NUMBITS(4) [], ], ]; From 20170b7b7a13d78be3b75b101ba87bac6ed388cb Mon Sep 17 00:00:00 2001 From: xuchang-vivo Date: Fri, 6 Mar 2026 18:25:42 +0800 Subject: [PATCH 53/53] fix --- driver/src/interrupt_controller/esp32_intc.rs | 6 +++--- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/driver/src/interrupt_controller/esp32_intc.rs b/driver/src/interrupt_controller/esp32_intc.rs index 30f776ef..251d8df7 100644 --- a/driver/src/interrupt_controller/esp32_intc.rs +++ b/driver/src/interrupt_controller/esp32_intc.rs @@ -29,7 +29,7 @@ register_structs! { (0x104 => cpu_int_enable_reg: ReadWrite), (0x108 => _reserved1), (0x118 => priority_reg: [ReadWrite; 31]), - (0x194 => thresh_reg: ReadWrite), + (0x194 => threshold_reg: ReadWrite), (0x198 => @END), } } @@ -78,7 +78,7 @@ impl Esp32Intc { pub fn set_threshold(&self, threshold: u8) { self.registers - .thresh_reg - .write(THRESH_REG::THRESH.val(thresh as u32)); + .threshold_reg + .write(THRESHOLD_REG::THRESHOLD.val(threshold as u32)); } } diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 828dab9e..606f0879 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -128,10 +128,10 @@ pub(crate) fn init() { core::ptr::write_volatile(RTC_CNTL_WDTWRITECT_REG as *mut u32, 0); } - get_device!(intc).alloc_irq(SYSTIMER_TARGET0_IRQ); - get_device!(intc).alloc_irq(USB_SERIAL_JTAG_IRQ); + get_device!(intc).allocate_irq(SYSTIMER_TARGET0_IRQ); + get_device!(intc).allocate_irq(USB_SERIAL_JTAG_IRQ); - get_device!(intc).set_thresh(1); + get_device!(intc).set_threshold(1); get_device!(intc).set_priority(USB_SERIAL_JTAG_IRQ, 15); get_device!(intc).set_priority(SYSTIMER_TARGET0_IRQ, 15);