mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
feat(esp_hw_support): Add esp_cpu.h support for linux builds
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "soc/spi_periph.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/spi_common_internal.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
|
||||
@@ -3,9 +3,12 @@ idf_build_get_property(non_os_build NON_OS_BUILD)
|
||||
|
||||
# On Linux, we only support a few features, hence this simple component registration
|
||||
if(${target} STREQUAL "linux")
|
||||
# "include/linux" MUST come before "include" so that Linux-specific header
|
||||
# overrides (e.g. esp_cpu.h) take precedence over the generic versions.
|
||||
idf_component_register(SRCS "port/linux/esp_random.c"
|
||||
"port/linux/chip_info.c"
|
||||
INCLUDE_DIRS "include" "etm/include")
|
||||
"port/linux/cpu.c"
|
||||
INCLUDE_DIRS "include/linux" "include" "etm/include")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Linux/macOS host-only version of esp_cpu.h.
|
||||
*
|
||||
* This header provides stub/minimal implementations of the esp_cpu_*
|
||||
* API for host builds. It is placed in an include directory that takes
|
||||
* precedence over the generic esp_cpu.h for CONFIG_IDF_TARGET_LINUX.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief CPU cycle count type
|
||||
*/
|
||||
typedef uint32_t esp_cpu_cycle_count_t;
|
||||
|
||||
/**
|
||||
* @brief CPU interrupt type
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_CPU_INTR_TYPE_LEVEL = 0,
|
||||
ESP_CPU_INTR_TYPE_EDGE,
|
||||
ESP_CPU_INTR_TYPE_NA,
|
||||
} esp_cpu_intr_type_t;
|
||||
|
||||
/**
|
||||
* @brief CPU interrupt descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
int priority;
|
||||
esp_cpu_intr_type_t type;
|
||||
uint32_t flags;
|
||||
} esp_cpu_intr_desc_t;
|
||||
|
||||
#define ESP_CPU_INTR_DESC_FLAG_SPECIAL 0x01
|
||||
#define ESP_CPU_INTR_DESC_FLAG_RESVD 0x02
|
||||
|
||||
/**
|
||||
* @brief CPU interrupt handler type
|
||||
*/
|
||||
typedef void (*esp_cpu_intr_handler_t)(void *arg);
|
||||
|
||||
/**
|
||||
* @brief CPU watchpoint trigger type
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_CPU_WATCHPOINT_LOAD,
|
||||
ESP_CPU_WATCHPOINT_STORE,
|
||||
ESP_CPU_WATCHPOINT_ACCESS,
|
||||
} esp_cpu_watchpoint_trigger_t;
|
||||
|
||||
/* --------------------------------------------------- CPU Control ----------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Stall a CPU core
|
||||
*
|
||||
* @param core_id The core's ID
|
||||
*/
|
||||
void esp_cpu_stall(int core_id);
|
||||
|
||||
/**
|
||||
* @brief Resume a previously stalled CPU core
|
||||
*
|
||||
* @param core_id The core's ID
|
||||
*/
|
||||
void esp_cpu_unstall(int core_id);
|
||||
|
||||
/**
|
||||
* @brief Reset a CPU core
|
||||
*
|
||||
* @param core_id The core's ID
|
||||
*/
|
||||
void esp_cpu_reset(int core_id);
|
||||
|
||||
/**
|
||||
* @brief Wait for Interrupt
|
||||
*
|
||||
* This function causes the current CPU core to execute its Wait For Interrupt
|
||||
* (WFI or equivalent) instruction. After executing this function, the CPU core
|
||||
* will stop execution until an interrupt occurs.
|
||||
*/
|
||||
void esp_cpu_wait_for_intr(void);
|
||||
|
||||
/* -------------------------------------------------- CPU Registers ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Get the current core's ID
|
||||
*
|
||||
* @return Always 0 on Linux host (single core)
|
||||
*/
|
||||
FORCE_INLINE_ATTR __attribute__((pure)) int esp_cpu_get_core_id(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current CPU core's privilege level
|
||||
*
|
||||
* @return -1 (not applicable on host)
|
||||
*/
|
||||
FORCE_INLINE_ATTR __attribute__((always_inline)) int esp_cpu_get_curr_privilege_level(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the current stack pointer address
|
||||
*/
|
||||
FORCE_INLINE_ATTR void *esp_cpu_get_sp(void)
|
||||
{
|
||||
void *sp;
|
||||
#if defined(__x86_64__)
|
||||
__asm__ __volatile__ ("mov %%rsp, %0" : "=r"(sp));
|
||||
#elif defined(__aarch64__)
|
||||
__asm__ __volatile__ ("mov %0, sp" : "=r"(sp));
|
||||
#else
|
||||
sp = __builtin_frame_address(0);
|
||||
#endif
|
||||
return sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current CPU core's cycle count
|
||||
*
|
||||
* @return Always 0 (no hardware cycle counter on host)
|
||||
*/
|
||||
FORCE_INLINE_ATTR esp_cpu_cycle_count_t esp_cpu_get_cycle_count(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the current CPU core's cycle count (no-op on host)
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_set_cycle_count(esp_cpu_cycle_count_t cycle_count)
|
||||
{
|
||||
(void)cycle_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a program counter (PC) value to address
|
||||
*/
|
||||
FORCE_INLINE_ATTR __attribute__((pure)) void *esp_cpu_pc_to_addr(uint32_t pc)
|
||||
{
|
||||
return (void *)(uintptr_t)pc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the current CPU core's thread pointer (no-op on host)
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_set_threadptr(void *threadptr)
|
||||
{
|
||||
(void)threadptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current CPU core's thread pointer
|
||||
*
|
||||
* @return NULL on host
|
||||
*/
|
||||
FORCE_INLINE_ATTR void *esp_cpu_get_threadptr(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Get a CPU interrupt's descriptor
|
||||
*
|
||||
* Each CPU interrupt has a descriptor describing the interrupt's capabilities
|
||||
* and restrictions. This function gets the descriptor of a particular interrupt
|
||||
* on a particular CPU.
|
||||
*
|
||||
* @param[in] core_id The core's ID
|
||||
* @param[in] intr_num Interrupt number
|
||||
* @param[out] intr_desc_ret The interrupt's descriptor
|
||||
*/
|
||||
void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret);
|
||||
|
||||
/**
|
||||
* @brief Set the base address of the current CPU's Interrupt Vector Table (IVT)
|
||||
*
|
||||
* @param ivt_addr Interrupt Vector Table's base address
|
||||
*/
|
||||
|
||||
FORCE_INLINE_ATTR void esp_cpu_intr_set_ivt_addr(const void *ivt_addr)
|
||||
{
|
||||
(void)ivt_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a particular interrupt already has a handler function
|
||||
*
|
||||
* @note This function simply checks if the IVT of the current CPU already has
|
||||
* a handler assigned.
|
||||
* @param intr_num Interrupt number (from 0 to 31)
|
||||
* @return True if the interrupt has a handler function, false otherwise.
|
||||
*/
|
||||
FORCE_INLINE_ATTR bool esp_cpu_intr_has_handler(int intr_num)
|
||||
{
|
||||
(void)intr_num;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the handler function of a particular interrupt
|
||||
*
|
||||
* Assign a handler function (i.e., ISR) to a particular interrupt on the
|
||||
* current CPU.
|
||||
*
|
||||
* @note This function simply sets the handler function (in the IVT) and does
|
||||
* not actually enable the interrupt.
|
||||
* @param intr_num Interrupt number (from 0 to 31)
|
||||
* @param handler Handler function
|
||||
* @param handler_arg Argument passed to the handler function
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_intr_set_handler(int intr_num, esp_cpu_intr_handler_t handler, void *handler_arg)
|
||||
{
|
||||
(void)intr_num;
|
||||
(void)handler;
|
||||
(void)handler_arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a handler function's argument of
|
||||
*
|
||||
* Get the argument of a previously assigned handler function on the current CPU.
|
||||
*
|
||||
* @param intr_num Interrupt number (from 0 to 31)
|
||||
* @return The the argument passed to the handler function
|
||||
*/
|
||||
FORCE_INLINE_ATTR void *esp_cpu_intr_get_handler_arg(int intr_num)
|
||||
{
|
||||
(void)intr_num;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable particular interrupts on the current CPU
|
||||
*
|
||||
* @param intr_mask Bit mask of the interrupts to enable
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_intr_enable(uint32_t intr_mask)
|
||||
{
|
||||
(void)intr_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable particular interrupts on the current CPU
|
||||
*
|
||||
* @param intr_mask Bit mask of the interrupts to disable
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_intr_disable(uint32_t intr_mask)
|
||||
{
|
||||
(void)intr_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the enabled interrupts on the current CPU
|
||||
*
|
||||
* @return Bit mask of the enabled interrupts
|
||||
*/
|
||||
FORCE_INLINE_ATTR uint32_t esp_cpu_intr_get_enabled_mask(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acknowledge an edge interrupt
|
||||
*
|
||||
* @param intr_num Interrupt number (from 0 to 31)
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_intr_edge_ack(int intr_num)
|
||||
{
|
||||
(void)intr_num;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------- Memory Ports ----------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Configure the CPU to disable access to invalid memory regions
|
||||
*/
|
||||
void esp_cpu_configure_region_protection(void);
|
||||
|
||||
/* ---------------------------------------------------- Debugging ------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Set and enable a hardware watchpoint on the current CPU
|
||||
*
|
||||
* @param wp_num Hardware watchpoint number
|
||||
* @param wp_addr Watchpoint's base address
|
||||
* @param size Size of the region to watch
|
||||
* @param trigger Trigger type
|
||||
* @return ESP_ERR_NOT_SUPPORTED on host
|
||||
*/
|
||||
esp_err_t esp_cpu_set_watchpoint(int wp_num, const void *wp_addr, size_t size, esp_cpu_watchpoint_trigger_t trigger);
|
||||
|
||||
/**
|
||||
* @brief Clear a hardware watchpoint on the current CPU
|
||||
*
|
||||
* @param wp_num Hardware watchpoint number
|
||||
* @return ESP_ERR_NOT_SUPPORTED on host
|
||||
*/
|
||||
esp_err_t esp_cpu_clear_watchpoint(int wp_num);
|
||||
|
||||
/**
|
||||
* @brief Check if the current CPU has a debugger attached
|
||||
*
|
||||
* @return True if debugger is attached, false otherwise
|
||||
*/
|
||||
|
||||
FORCE_INLINE_ATTR bool esp_cpu_dbgr_is_attached(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Trigger a call to the current CPU's attached debugger
|
||||
*/
|
||||
FORCE_INLINE_ATTR void esp_cpu_dbgr_break(void)
|
||||
{
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Given the return address, calculate the address of the preceding call instruction
|
||||
* This is typically used to answer the question "where was the function called from?"
|
||||
* @param return_address The value of the return address register.
|
||||
* Typically set to the value of __builtin_return_address(0).
|
||||
* @return Address of the call instruction preceding the return address.
|
||||
*/
|
||||
FORCE_INLINE_ATTR intptr_t esp_cpu_get_call_addr(intptr_t return_address)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
return return_address - 5;
|
||||
#else
|
||||
return return_address - 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ Misc --------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Atomic compare-and-set operation
|
||||
*
|
||||
* @param addr Address of atomic variable
|
||||
* @param compare_value Value to compare the atomic variable to
|
||||
* @param new_value New value to set the atomic variable to
|
||||
* @return Whether the atomic variable was set or not
|
||||
*/
|
||||
bool esp_cpu_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stub implementations of non-inline esp_cpu_* functions for Linux/macOS
|
||||
* host builds. These provide no-op or minimal behaviour since hardware
|
||||
* CPU control, interrupt descriptors, breakpoints, watchpoints, and memory
|
||||
* region protection don't exist on the host.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
/* --------------------------------------------------- CPU Control ----------------------------------------------------- */
|
||||
|
||||
void esp_cpu_stall(int core_id)
|
||||
{
|
||||
(void)core_id;
|
||||
}
|
||||
|
||||
void esp_cpu_unstall(int core_id)
|
||||
{
|
||||
(void)core_id;
|
||||
}
|
||||
|
||||
void esp_cpu_reset(int core_id)
|
||||
{
|
||||
(void)core_id;
|
||||
}
|
||||
|
||||
void esp_cpu_wait_for_intr(void)
|
||||
{
|
||||
/* No WFI equivalent on host; just return */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- */
|
||||
|
||||
void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret)
|
||||
{
|
||||
(void)core_id;
|
||||
(void)intr_num;
|
||||
if (intr_desc_ret) {
|
||||
intr_desc_ret->priority = -1;
|
||||
intr_desc_ret->type = ESP_CPU_INTR_TYPE_NA;
|
||||
intr_desc_ret->flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------- Memory Ports ----------------------------------------------------- */
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* No memory protection unit on host */
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------- Debugging ------------------------------------------------------ */
|
||||
|
||||
esp_err_t esp_cpu_set_watchpoint(int wp_num, const void *wp_addr, size_t size, esp_cpu_watchpoint_trigger_t trigger)
|
||||
{
|
||||
(void)wp_num;
|
||||
(void)wp_addr;
|
||||
(void)size;
|
||||
(void)trigger;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t esp_cpu_clear_watchpoint(int wp_num)
|
||||
{
|
||||
(void)wp_num;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ Misc --------------------------------------------------------- */
|
||||
|
||||
bool esp_cpu_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value)
|
||||
{
|
||||
return atomic_compare_exchange_strong((_Atomic uint32_t *)addr, &compare_value, new_value);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -9,18 +9,8 @@
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_LINUX
|
||||
#include "esp_private/cache_utils.h"
|
||||
#include "esp_cpu.h"
|
||||
#else
|
||||
/* esp_cpu.h isn't available when building for Linux */
|
||||
static intptr_t esp_cpu_get_call_addr(intptr_t return_address)
|
||||
{
|
||||
/* on x86, there is no hope to get the address of the previous instruction */
|
||||
return return_address;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression, intptr_t addr)
|
||||
{
|
||||
|
||||
@@ -9,10 +9,7 @@
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#if !CONFIG_IDF_TARGET_LINUX
|
||||
#include "esp_cpu.h"
|
||||
#endif
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_memory_utils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
Reference in New Issue
Block a user