Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64e98eb527 | ||
|
|
4d44e3280b | ||
|
|
6da1cbcb06 | ||
|
|
1e5f5af4eb | ||
|
|
ee29ea2a20 | ||
|
|
3d4204036a | ||
|
|
c60a870b1c | ||
|
|
d26b221f53 | ||
|
|
9cb7b9e4ec | ||
|
|
e395a9a649 | ||
|
|
9526404c65 | ||
|
|
116c4a9e40 | ||
|
|
46292d748d | ||
|
|
51e1f38026 | ||
|
|
87b06394e6 | ||
|
|
9800d46c69 | ||
|
|
ac91402f71 | ||
|
|
e58bca83de | ||
|
|
91d1416460 | ||
|
|
cbb43bee3d | ||
|
|
989499c8f4 | ||
|
|
6eebe0acf0 | ||
|
|
1ea8bb2e0f | ||
|
|
4217df505a | ||
|
|
d1a9ef6b0b | ||
|
|
bf9345a1ec | ||
|
|
7f89472f14 | ||
|
|
e3a55c96ef | ||
|
|
663da2302b | ||
|
|
4670cb27c7 | ||
|
|
a55b5444c6 | ||
|
|
c1adc507d7 | ||
|
|
e918bdac38 | ||
|
|
8b5e0388cf | ||
|
|
3b7610ec5f | ||
|
|
2b0f179079 | ||
|
|
ff9fb454c6 | ||
|
|
5282c9fdc8 | ||
|
|
ee0aecc953 | ||
|
|
21c942f18c | ||
|
|
f017af445e | ||
|
|
01949d478d | ||
|
|
0dbc00a63b | ||
|
|
94b74dbd89 | ||
|
|
4c362f1aec | ||
|
|
bafc9f2a66 | ||
|
|
30de5e8a2c | ||
|
|
ff6295f930 | ||
|
|
738e159ede | ||
|
|
183444eed4 | ||
|
|
e2efcf7cb6 | ||
|
|
a494c09fcb | ||
|
|
fb8687a492 | ||
|
|
7abcf05115 | ||
|
|
2ff7f15e5f | ||
|
|
d1f998909d | ||
|
|
a9f222b9a7 | ||
|
|
58be950216 | ||
|
|
02f511bb93 |
2
.github/workflows/bsim-tests.yaml
vendored
2
.github/workflows/bsim-tests.yaml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
runs-on:
|
||||
group: zephyr-runner-v2-linux-x64-4xlarge
|
||||
container:
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.1.20250624
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.4.20250818
|
||||
options: '--entrypoint /bin/bash'
|
||||
env:
|
||||
ZEPHYR_TOOLCHAIN_VARIANT: zephyr
|
||||
|
||||
2
.github/workflows/clang.yaml
vendored
2
.github/workflows/clang.yaml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on:
|
||||
group: zephyr-runner-v2-linux-x64-4xlarge
|
||||
container:
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.1.20250624
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.4.20250818
|
||||
options: '--entrypoint /bin/bash'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
2
.github/workflows/codecov.yaml
vendored
2
.github/workflows/codecov.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on:
|
||||
group: zephyr-runner-v2-linux-x64-4xlarge
|
||||
container:
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.1.20250624
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.4.20250818
|
||||
options: '--entrypoint /bin/bash'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
2
.github/workflows/errno.yml
vendored
2
.github/workflows/errno.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
check-errno:
|
||||
runs-on: ubuntu-24.04
|
||||
container:
|
||||
image: ghcr.io/zephyrproject-rtos/ci:v0.28.0
|
||||
image: ghcr.io/zephyrproject-rtos/ci:v0.28.4
|
||||
|
||||
steps:
|
||||
- name: Apply container owner mismatch workaround
|
||||
|
||||
2
.github/workflows/footprint-tracking.yml
vendored
2
.github/workflows/footprint-tracking.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
group: zephyr-runner-v2-linux-x64-4xlarge
|
||||
if: github.repository_owner == 'zephyrproject-rtos'
|
||||
container:
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.1.20250624
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.4.20250818
|
||||
options: '--entrypoint /bin/bash'
|
||||
defaults:
|
||||
run:
|
||||
|
||||
2
.github/workflows/twister.yaml
vendored
2
.github/workflows/twister.yaml
vendored
@@ -127,7 +127,7 @@ jobs:
|
||||
needs: twister-build-prep
|
||||
if: needs.twister-build-prep.outputs.size != 0
|
||||
container:
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.1.20250624
|
||||
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.4.20250818
|
||||
options: '--entrypoint /bin/bash'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -214,24 +214,53 @@ endif()
|
||||
# 1) Using EXTRA_CFLAGS which is applied regardless of kconfig choice, or
|
||||
# 2) Rely on override support being implemented by your toolchain_cc_optimize_*()
|
||||
#
|
||||
get_property(OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG TARGET compiler PROPERTY no_optimization)
|
||||
get_property(OPTIMIZE_FOR_DEBUG_FLAG TARGET compiler PROPERTY optimization_debug)
|
||||
get_property(OPTIMIZE_FOR_SPEED_FLAG TARGET compiler PROPERTY optimization_speed)
|
||||
get_property(OPTIMIZE_FOR_SIZE_FLAG TARGET compiler PROPERTY optimization_size)
|
||||
get_property(OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG TARGET compiler PROPERTY optimization_size_aggressive)
|
||||
get_property(COMPILER_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG TARGET compiler PROPERTY no_optimization)
|
||||
get_property(COMPILER_OPTIMIZE_FOR_DEBUG_FLAG TARGET compiler PROPERTY optimization_debug)
|
||||
get_property(COMPILER_OPTIMIZE_FOR_SPEED_FLAG TARGET compiler PROPERTY optimization_speed)
|
||||
get_property(COMPILER_OPTIMIZE_FOR_SIZE_FLAG TARGET compiler PROPERTY optimization_size)
|
||||
get_property(COMPILER_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG TARGET compiler PROPERTY optimization_size_aggressive)
|
||||
|
||||
get_property(ASM_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG TARGET asm PROPERTY no_optimization)
|
||||
get_property(ASM_OPTIMIZE_FOR_DEBUG_FLAG TARGET asm PROPERTY optimization_debug)
|
||||
get_property(ASM_OPTIMIZE_FOR_SPEED_FLAG TARGET asm PROPERTY optimization_speed)
|
||||
get_property(ASM_OPTIMIZE_FOR_SIZE_FLAG TARGET asm PROPERTY optimization_size)
|
||||
get_property(ASM_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG TARGET asm PROPERTY optimization_size_aggressive)
|
||||
|
||||
# Let the assembler inherit the optimization flags of the compiler if it is
|
||||
# not set explicitly.
|
||||
if(NOT ASM_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG)
|
||||
set(ASM_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG ${COMPILER_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG})
|
||||
endif()
|
||||
if(NOT ASM_OPTIMIZE_FOR_DEBUG_FLAG)
|
||||
set(ASM_OPTIMIZE_FOR_DEBUG_FLAG ${COMPILER_OPTIMIZE_FOR_DEBUG_FLAG})
|
||||
endif()
|
||||
if(NOT ASM_OPTIMIZE_FOR_SPEED_FLAG)
|
||||
set(ASM_OPTIMIZE_FOR_SPEED_FLAG ${COMPILER_OPTIMIZE_FOR_SPEED_FLAG})
|
||||
endif()
|
||||
if(NOT ASM_OPTIMIZE_FOR_SIZE_FLAG)
|
||||
set(ASM_OPTIMIZE_FOR_SIZE_FLAG ${COMPILER_OPTIMIZE_FOR_SIZE_FLAG})
|
||||
endif()
|
||||
if(NOT ASM_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG)
|
||||
set(ASM_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG ${COMPILER_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG})
|
||||
endif()
|
||||
|
||||
# From kconfig choice, pick the actual OPTIMIZATION_FLAG to use.
|
||||
# Kconfig choice ensures only one of these CONFIG_*_OPTIMIZATIONS is set.
|
||||
if(CONFIG_NO_OPTIMIZATIONS)
|
||||
set(OPTIMIZATION_FLAG ${OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG})
|
||||
set(COMPILER_OPTIMIZATION_FLAG ${COMPILER_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG})
|
||||
set(ASM_OPTIMIZATION_FLAG ${ASM_OPTIMIZE_FOR_NO_OPTIMIZATIONS_FLAG})
|
||||
elseif(CONFIG_DEBUG_OPTIMIZATIONS)
|
||||
set(OPTIMIZATION_FLAG ${OPTIMIZE_FOR_DEBUG_FLAG})
|
||||
set(COMPILER_OPTIMIZATION_FLAG ${COMPILER_OPTIMIZE_FOR_DEBUG_FLAG})
|
||||
set(ASM_OPTIMIZATION_FLAG ${ASM_OPTIMIZE_FOR_DEBUG_FLAG})
|
||||
elseif(CONFIG_SPEED_OPTIMIZATIONS)
|
||||
set(OPTIMIZATION_FLAG ${OPTIMIZE_FOR_SPEED_FLAG})
|
||||
set(COMPILER_OPTIMIZATION_FLAG ${COMPILER_OPTIMIZE_FOR_SPEED_FLAG})
|
||||
set(ASM_OPTIMIZATION_FLAG ${ASM_OPTIMIZE_FOR_SPEED_FLAG})
|
||||
elseif(CONFIG_SIZE_OPTIMIZATIONS)
|
||||
set(OPTIMIZATION_FLAG ${OPTIMIZE_FOR_SIZE_FLAG}) # Default in kconfig
|
||||
set(COMPILER_OPTIMIZATION_FLAG ${COMPILER_OPTIMIZE_FOR_SIZE_FLAG}) # Default in kconfig
|
||||
set(ASM_OPTIMIZATION_FLAG ${ASM_OPTIMIZE_FOR_SIZE_FLAG})
|
||||
elseif(CONFIG_SIZE_OPTIMIZATIONS_AGGRESSIVE)
|
||||
set(OPTIMIZATION_FLAG ${OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG})
|
||||
set(COMPILER_OPTIMIZATION_FLAG ${COMPILER_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG})
|
||||
set(ASM_OPTIMIZATION_FLAG ${ASM_OPTIMIZE_FOR_SIZE_AGGRESSIVE_FLAG})
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Unreachable code. Expected optimization level to have been chosen. See Kconfig.zephyr")
|
||||
@@ -245,9 +274,9 @@ SOC_* symbol.")
|
||||
endif()
|
||||
|
||||
# Apply the final optimization flag(s)
|
||||
zephyr_compile_options($<$<COMPILE_LANGUAGE:ASM>:${OPTIMIZATION_FLAG}>)
|
||||
zephyr_compile_options($<$<COMPILE_LANGUAGE:C>:${OPTIMIZATION_FLAG}>)
|
||||
zephyr_compile_options($<$<COMPILE_LANGUAGE:CXX>:${OPTIMIZATION_FLAG}>)
|
||||
zephyr_compile_options($<$<COMPILE_LANGUAGE:ASM>:${ASM_OPTIMIZATION_FLAG}>)
|
||||
zephyr_compile_options($<$<COMPILE_LANGUAGE:C>:${COMPILER_OPTIMIZATION_FLAG}>)
|
||||
zephyr_compile_options($<$<COMPILE_LANGUAGE:CXX>:${COMPILER_OPTIMIZATION_FLAG}>)
|
||||
|
||||
if(CONFIG_LTO)
|
||||
zephyr_compile_options($<TARGET_PROPERTY:compiler,optimization_lto>)
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.17.2
|
||||
0.17.4
|
||||
|
||||
2
VERSION
2
VERSION
@@ -1,5 +1,5 @@
|
||||
VERSION_MAJOR = 4
|
||||
VERSION_MINOR = 2
|
||||
PATCHLEVEL = 0
|
||||
PATCHLEVEL = 1
|
||||
VERSION_TWEAK = 0
|
||||
EXTRAVERSION =
|
||||
|
||||
@@ -489,20 +489,219 @@ SECTION_FUNC(TEXT, z_arm_svc)
|
||||
* r8 - saved link register
|
||||
*/
|
||||
.L_do_syscall:
|
||||
/*
|
||||
* Build a privilege stack frame from the user stack frame, then switch PSP
|
||||
* to it. This ensures return from SVC does not rely on the user stack.
|
||||
*
|
||||
* Layout of privilege stack created from user stack:
|
||||
*
|
||||
* +------+-------------------------+------+-------------------------+--------------------------+
|
||||
* | User stack | Privilege stack | Notes |
|
||||
* +------+-------------------------+------+-------------------------+--------------------------+
|
||||
* |Offset| contents |Offset| contents | |
|
||||
* +------+-------------------------+------+-------------------------+--------------------------+
|
||||
* | 0 | R0 -> | 0 | R0 | PSP switches from 0th |
|
||||
* | | | | | offset of user stack to |
|
||||
* | | | | | 0th offset of priv stack |
|
||||
* | 4 | R1 -> | 4 | R1 | |
|
||||
* | 8 | R2 -> | 8 | R2 | |
|
||||
* | 12 | R3 -> |12 | R3 | |
|
||||
* | 16 | R12 -> |16 | R12 | |
|
||||
* | 20 | LR -> |20 | LR | |
|
||||
* | 24 | Return Address -x> |24 | z_arm_do_syscall |return address from user |
|
||||
* | | | | |sf is not copied. Instead,|
|
||||
* | | | | |it is replaced so that |
|
||||
* | | | | |z_arm_svc returns to |
|
||||
* | | | | |z_arm_do_syscall. |
|
||||
* | | | | | |
|
||||
* | 28 | xPSR (w/ or w/o pad) -> |28 | xPSR (pad bit cleared) |This completes the basic |
|
||||
* | | | | |exception sf w/ or w/o pad|
|
||||
* | | | | | |
|
||||
* | -- | FP regs + FPSCR -> |-- | FP regs + FPSCR |For arch supporting fp |
|
||||
* | | (w/ or w/o pad) | | |context an additional |
|
||||
* | | | | |extended sf is copied. |
|
||||
* |________________________________|______|_________________________|__________________________|
|
||||
* | | | | |On returning to |
|
||||
* | | | | |z_arm_do_syscall, the |
|
||||
* | | | | |above sf has already been |
|
||||
* | | | | |unstacked and 8B from the |
|
||||
* | | | | |then sf are used to pass |
|
||||
* | | | | |original pre-svc sp & the |
|
||||
* | | | | |return address. |
|
||||
* | | | | |Note: at the moment |
|
||||
* | | | | |z_arm_do_syscall also |
|
||||
* | | | | |expects the return address|
|
||||
* | | | | |to be set in r8. |
|
||||
* | | | | | |
|
||||
* | | | 0 | address that |z_arm_do_syscall expects |
|
||||
* | | | | z_arm_do_syscall should |the original pre-svc sp at|
|
||||
* | | | | set as PSP before |0th offset i.e. new sp[0] |
|
||||
* | | | | returning from svc. |and, |
|
||||
* | | | | | |
|
||||
* | | | 4 | Address that |the return address at |
|
||||
* | | | | z_arm_do_syscall should |sp[4]. Note that this is |
|
||||
* | | | | return to after handling|the return address copied |
|
||||
* | | | | svc |from user exception sf[24]|
|
||||
* | | | | |which was not copied in |
|
||||
* | | | | |the previous sf. |
|
||||
* +------+-------------------------+------+-------------------------+--------------------------+
|
||||
* "sf" in this function is used as abbreviation for "stack frame".
|
||||
* Note that the "FP regs + FPSCR" are only present if CONFIG_FPU_SHARING=y, and the optional pad
|
||||
* is only present if PSP was not 8-byte aligned when SVC was executed.
|
||||
* Also note that FPU cannot be present in ARMv6-M or ARMv8-M Baseline implementations
|
||||
* (i.e., it may only be present when CONFIG_ARMV7_M_ARMV8_M_MAINLINE is enabled).
|
||||
*/
|
||||
/* Start by fetching the top of privileged stack */
|
||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
|
||||
movs r3, #24
|
||||
ldr r1, [r0, r3] /* grab address of PC from stack frame */
|
||||
mov r8, r1
|
||||
ldr r1, =_kernel
|
||||
ldr r1, [r1, #_kernel_offset_to_current]
|
||||
adds r1, r1, #_thread_offset_to_priv_stack_start
|
||||
ldr r1, [r1] /* bottom of priv stack */
|
||||
ldr r3, =CONFIG_PRIVILEGED_STACK_SIZE
|
||||
subs r3, #(_EXC_HW_SAVED_BASIC_SF_SIZE+8) /* 8 for original sp and pc */
|
||||
add r1, r3
|
||||
mov ip, r1
|
||||
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
||||
ldr r8, [r0, #24] /* grab address of PC from stack frame */
|
||||
ldr ip, =_kernel
|
||||
ldr ip, [ip, #_kernel_offset_to_current]
|
||||
ldr ip, [ip, #_thread_offset_to_priv_stack_start] /* bottom of priv stack */
|
||||
add ip, #CONFIG_PRIVILEGED_STACK_SIZE
|
||||
#ifdef CONFIG_FPU_SHARING
|
||||
/* Assess whether svc calling thread had been using the FP registers. */
|
||||
tst lr, #_EXC_RETURN_FTYPE_Msk
|
||||
ite eq
|
||||
moveq r8, #_EXC_HW_SAVED_EXTENDED_SF_SIZE
|
||||
movne r8, #_EXC_HW_SAVED_BASIC_SF_SIZE
|
||||
#else
|
||||
mov r8, #_EXC_HW_SAVED_BASIC_SF_SIZE
|
||||
#endif
|
||||
sub ip, #8 /* z_arm_do_syscall will use this to get original sp and pc */
|
||||
sub ip, r8 /* 32 for basic sf + 72 for the optional esf */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
* r0 has PSP i.e. top of user stack
|
||||
* ip has top of privilege stack
|
||||
* r8 has hardware-saved stack frame size (only in case of mainline)
|
||||
*/
|
||||
push {r4-r7}
|
||||
push {r2}
|
||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
|
||||
mov r2, r0 /* safe to use r2 since it is saved on MSP */
|
||||
|
||||
/* Check for padding in the sf */
|
||||
ldr r1, [r0, #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET] /* grab xPSR from sf which has the pad bit */
|
||||
movs r3, #1
|
||||
/* Check if pad bit 9 is set */
|
||||
lsls r3, r3, #9
|
||||
tst r1, r3
|
||||
beq .L_no_padding
|
||||
/* special handling for padded sf */
|
||||
bics r1, r3 /* clear the pad bit (priv stack is aligned and doesn't need it) */
|
||||
adds r2, #4
|
||||
.L_no_padding:
|
||||
/* Calculate original pre-svc user sp which is psp + sf size (+4B if pad bit was set) */
|
||||
adds r2, #_EXC_HW_SAVED_BASIC_SF_SIZE
|
||||
mov r3, ip
|
||||
str r2,[r3, #0]
|
||||
|
||||
/* Store the pre-SVC user SP at the offset expected by z_arm_do_syscall,
|
||||
* as detailed in the table above.
|
||||
*/
|
||||
str r2,[r3, #_EXC_HW_SAVED_BASIC_SF_SIZE]
|
||||
/* sf of priv stack has the same xPSR as user stack but with 9th bit reset */
|
||||
str r1,[r3, #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET]
|
||||
|
||||
/* r0-r3, r12, LR from user stack sf are copied to sf of priv stack */
|
||||
mov r1, r0
|
||||
mov r2, r3
|
||||
ldmia r1!, {r4-r7}
|
||||
stmia r2!, {r4-r7}
|
||||
ldmia r1!, {r4-r5}
|
||||
stmia r2!, {r4-r5}
|
||||
|
||||
/* Store the svc return address at the offset expected by z_arm_do_syscall,
|
||||
* as detailed in the table above.
|
||||
*/
|
||||
str r5, [r3, #(_EXC_HW_SAVED_BASIC_SF_SIZE+4)]
|
||||
|
||||
ldr r1, =z_arm_do_syscall
|
||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
|
||||
str r1, [r0, r3] /* overwrite the PC to point to z_arm_do_syscall */
|
||||
str r1, [r3, #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET] /* Execution return to z_arm_do_syscall */
|
||||
ldr r1, [r0, #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET] /* grab address of PC from stack frame */
|
||||
/* Store the svc return address (i.e. next instr to svc) in r8 as expected by z_arm_do_syscall.
|
||||
*/
|
||||
mov r8, r1
|
||||
|
||||
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
||||
str r1, [r0, #24] /* overwrite the PC to point to z_arm_do_syscall */
|
||||
mov r2, r0 /* safe to use r2 since it is saved on MSP */
|
||||
|
||||
/* Calculate original pre-svc user sp without pad which is psp + sf size */
|
||||
add r2, r8
|
||||
|
||||
/* Also, check for padding in the sf */
|
||||
ldr r1, [r0, #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET] /* grab xPSR from sf which has the pad bit */
|
||||
tst r1, #(1<<9) /* Check if pad bit 9 is set */
|
||||
beq .L_no_padding
|
||||
bics r1, #(1<<9) /* clear the pad bit (priv stack is aligned and doesn't need it) */
|
||||
/* Calculate original pre-svc user sp with pad */
|
||||
add r2, #4
|
||||
.L_no_padding:
|
||||
str r2,[ip, #0]
|
||||
/* Store the pre-SVC user SP at the offset expected by z_arm_do_syscall,
|
||||
* as detailed in the table above.
|
||||
*/
|
||||
str r2,[ip, r8]
|
||||
str r1,[ip, #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET] /* priv sf get user sf xPSR with bit9 reset */
|
||||
|
||||
/* r0-r3, r12, LR from user stack sf are copied to sf of priv stack */
|
||||
mov r1, r0
|
||||
mov r2, ip
|
||||
ldmia r1!, {r4-r7}
|
||||
stmia r2!, {r4-r7}
|
||||
ldmia r1!, {r4-r5}
|
||||
stmia r2!, {r4-r5}
|
||||
|
||||
/* Store the svc return address at the offset expected by z_arm_do_syscall,
|
||||
* as detailed in the table above.
|
||||
*/
|
||||
add r8, #4
|
||||
str r5, [ip, r8]
|
||||
|
||||
ldr r1, =z_arm_do_syscall
|
||||
str r1, [ip, #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET] /* Execution return to z_arm_do_syscall */
|
||||
ldr r1, [r0, #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET] /* grab address of PC from stack frame */
|
||||
/* Store the svc return address (i.e. next instr to svc) in r8 as expected by z_arm_do_syscall.
|
||||
*/
|
||||
mov r8, r1
|
||||
|
||||
/* basic stack frame is copied at this point to privilege stack,
|
||||
* now time to copy the fp context
|
||||
*/
|
||||
#ifdef CONFIG_FPU_SHARING
|
||||
tst lr, #_EXC_RETURN_FTYPE_Msk
|
||||
bne .L_skip_fp_copy
|
||||
add r1, r0, #32
|
||||
add r2, ip, #32
|
||||
|
||||
vldmia r1!, {s0-s15}
|
||||
vstmia r2!, {s0-s15}
|
||||
|
||||
/* copy FPSCR + reserved (8 bytes) */
|
||||
ldmia r1!, {r4, r5}
|
||||
stmia r2!, {r4, r5}
|
||||
.L_skip_fp_copy:
|
||||
#endif
|
||||
|
||||
#endif
|
||||
pop {r2} /* restore CONTROL value */
|
||||
pop {r4-r7}
|
||||
|
||||
/* Point PSP to privilege stack,
|
||||
* note that r0 still has the old PSP
|
||||
*/
|
||||
msr PSP, ip
|
||||
|
||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
|
||||
ldr r3, =K_SYSCALL_LIMIT
|
||||
cmp r6, r3
|
||||
@@ -556,14 +755,12 @@ SECTION_FUNC(TEXT, z_arm_svc)
|
||||
isb
|
||||
|
||||
#if defined(CONFIG_BUILTIN_STACK_GUARD)
|
||||
/* Thread is now in privileged mode; after returning from SCVall it
|
||||
* will use the default (user) stack before switching to the privileged
|
||||
* stack to execute the system call. We need to protect the user stack
|
||||
* against stack overflows until this stack transition.
|
||||
*/
|
||||
ldr r1, [r0, #_thread_offset_to_stack_info_start] /* stack_info.start */
|
||||
msr PSPLIM, r1
|
||||
#endif /* CONFIG_BUILTIN_STACK_GUARD */
|
||||
/* Set stack pointer limit (needed in privileged mode) */
|
||||
ldr ip, =_kernel
|
||||
ldr ip, [ip, #_kernel_offset_to_current]
|
||||
ldr ip, [ip, #_thread_offset_to_priv_stack_start] /* priv stack ptr */
|
||||
msr PSPLIM, ip
|
||||
#endif
|
||||
|
||||
/* return from SVC to the modified LR - z_arm_do_syscall */
|
||||
bx lr
|
||||
|
||||
@@ -560,7 +560,9 @@ void arch_switch_to_main_thread(struct k_thread *main_thread, char *stack_ptr,
|
||||
/* We don’t intend to return, so there is no need to link. */
|
||||
"bx r4\n"
|
||||
/* Force a literal pool placement for the addresses referenced above */
|
||||
#ifndef __IAR_SYSTEMS_ICC__
|
||||
".ltorg\n"
|
||||
#endif
|
||||
:
|
||||
: "r"(_main), "r"(stack_ptr)
|
||||
: "r0", "r1", "r2", "r3", "r4", "ip", "lr", "memory");
|
||||
@@ -628,7 +630,9 @@ FUNC_NORETURN void z_arm_switch_to_main_no_multithreading(k_thread_entry_t main_
|
||||
"blx r0\n"
|
||||
"loop: b loop\n\t" /* while (true); */
|
||||
/* Force a literal pool placement for the addresses referenced above */
|
||||
#ifndef __IAR_SYSTEMS_ICC__
|
||||
".ltorg\n"
|
||||
#endif
|
||||
:
|
||||
: [_p1] "r"(p1), [_p2] "r"(p2), [_p3] "r"(p3), [_psp] "r"(psp),
|
||||
[_main_entry] "r"(main_entry)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Userspace and service handler hooks
|
||||
*
|
||||
* Copyright (c) 2017 Linaro Limited
|
||||
* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -308,9 +309,8 @@ SECTION_FUNC(TEXT,z_arm_userspace_enter)
|
||||
* This function is used to do system calls from unprivileged code. This
|
||||
* function is responsible for the following:
|
||||
* 1) Fixing up bad syscalls
|
||||
* 2) Configuring privileged stack and loading up stack arguments
|
||||
* 3) Dispatching the system call
|
||||
* 4) Restoring stack and calling back to the caller of the SVC
|
||||
* 2) Dispatching the system call
|
||||
* 3) Restoring stack and calling back to the caller of the SVC
|
||||
*
|
||||
*/
|
||||
SECTION_FUNC(TEXT, z_arm_do_syscall)
|
||||
@@ -328,41 +328,7 @@ SECTION_FUNC(TEXT, z_arm_do_syscall)
|
||||
* At this point PSPLIM is already configured to guard the default (user)
|
||||
* stack, so pushing to the default thread's stack is safe.
|
||||
*/
|
||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
|
||||
/* save current stack pointer (user stack) */
|
||||
mov ip, sp
|
||||
/* temporarily push to user stack */
|
||||
push {r0,r1}
|
||||
/* setup privileged stack */
|
||||
ldr r0, =_kernel
|
||||
ldr r0, [r0, #_kernel_offset_to_current]
|
||||
adds r0, r0, #_thread_offset_to_priv_stack_start
|
||||
ldr r0, [r0] /* priv stack ptr */
|
||||
ldr r1, =CONFIG_PRIVILEGED_STACK_SIZE
|
||||
add r0, r1
|
||||
|
||||
/* Store current SP and LR at the beginning of the priv stack */
|
||||
subs r0, #8
|
||||
mov r1, ip
|
||||
str r1, [r0, #0]
|
||||
mov r1, lr
|
||||
str r1, [r0, #4]
|
||||
mov ip, r0
|
||||
/* Restore user stack and original r0, r1 */
|
||||
pop {r0, r1}
|
||||
|
||||
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
||||
/* setup privileged stack */
|
||||
ldr ip, =_kernel
|
||||
ldr ip, [ip, #_kernel_offset_to_current]
|
||||
ldr ip, [ip, #_thread_offset_to_priv_stack_start] /* priv stack ptr */
|
||||
add ip, #CONFIG_PRIVILEGED_STACK_SIZE
|
||||
|
||||
/* Store current SP and LR at the beginning of the priv stack */
|
||||
subs ip, #8
|
||||
str sp, [ip, #0]
|
||||
str lr, [ip, #4]
|
||||
#elif defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||
#if defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||
/*
|
||||
* The SVC handler has already switched to the privileged stack.
|
||||
* Store the user SP and LR at the beginning of the priv stack.
|
||||
@@ -373,11 +339,6 @@ SECTION_FUNC(TEXT, z_arm_do_syscall)
|
||||
push {ip, lr}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||
/* switch to privileged stack */
|
||||
msr PSP, ip
|
||||
#endif
|
||||
|
||||
/* Note (applies when using stack limit checking):
|
||||
* We do not need to lock IRQs after switching PSP to the privileged stack;
|
||||
* PSPLIM is guarding the default (user) stack, which, by design, is
|
||||
@@ -386,14 +347,6 @@ SECTION_FUNC(TEXT, z_arm_do_syscall)
|
||||
* the maximum exception stack frame.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BUILTIN_STACK_GUARD)
|
||||
/* Set stack pointer limit (needed in privileged mode) */
|
||||
ldr ip, =_kernel
|
||||
ldr ip, [ip, #_kernel_offset_to_current]
|
||||
ldr ip, [ip, #_thread_offset_to_priv_stack_start] /* priv stack ptr */
|
||||
msr PSPLIM, ip
|
||||
#endif
|
||||
|
||||
/*
|
||||
* r0-r5 contain arguments
|
||||
* r6 contains call_id
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
* Copyright (c) 2025 Basalte bv
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,7 +9,7 @@
|
||||
/* Copied from linker.ld */
|
||||
|
||||
/* Non-cached region of RAM */
|
||||
SECTION_DATA_PROLOGUE(_NOCACHE_SECTION_NAME,,)
|
||||
SECTION_DATA_PROLOGUE(_NOCACHE_SECTION_NAME,(NOLOAD),)
|
||||
{
|
||||
#if defined(CONFIG_MMU)
|
||||
MMU_ALIGN;
|
||||
@@ -16,17 +17,31 @@ SECTION_DATA_PROLOGUE(_NOCACHE_SECTION_NAME,,)
|
||||
MPU_ALIGN(_nocache_ram_size);
|
||||
#endif
|
||||
_nocache_ram_start = .;
|
||||
_nocache_noload_ram_start = .;
|
||||
*(.nocache)
|
||||
*(".nocache.*")
|
||||
|
||||
#include <snippets-nocache-section.ld>
|
||||
|
||||
_nocache_noload_ram_end = .;
|
||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION)
|
||||
_nocache_noload_ram_size = _nocache_noload_ram_end - _nocache_noload_ram_start;
|
||||
|
||||
/* Non-cached loadable region of RAM and ROM */
|
||||
SECTION_DATA_PROLOGUE(_NOCACHE_LOAD_SECTION_NAME,,)
|
||||
{
|
||||
_nocache_load_ram_start = .;
|
||||
*(.nocache_load)
|
||||
*(".nocache_load.*")
|
||||
|
||||
#if defined(CONFIG_MMU)
|
||||
MMU_ALIGN;
|
||||
#else
|
||||
MPU_ALIGN(_nocache_ram_size);
|
||||
#endif
|
||||
_nocache_load_ram_end = .;
|
||||
_nocache_ram_end = .;
|
||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||
_nocache_load_ram_size = _nocache_load_ram_end - _nocache_load_ram_start;
|
||||
_nocache_load_rom_start = LOADADDR(_NOCACHE_LOAD_SECTION_NAME);
|
||||
_nocache_ram_size = _nocache_ram_end - _nocache_ram_start;
|
||||
_nocache_load_start = LOADADDR(_NOCACHE_SECTION_NAME);
|
||||
|
||||
@@ -311,7 +311,7 @@ You can debug an application in the usual way. Here is an example for the
|
||||
:goals: debug
|
||||
|
||||
.. _pyOCD:
|
||||
https://github.com/mbedmicro/pyOCD
|
||||
https://github.com/pyocd/pyOCD
|
||||
|
||||
.. _CMSIS DAP:
|
||||
https://developer.mbed.org/handbook/CMSIS-DAP
|
||||
@@ -323,7 +323,7 @@ You can debug an application in the usual way. Here is an example for the
|
||||
http://wiki.seeed.cc/BLE_Nitrogen/
|
||||
|
||||
.. _pyOCD issue 259:
|
||||
https://github.com/mbedmicro/pyOCD/issues/259
|
||||
https://github.com/pyocd/pyOCD/issues/259
|
||||
|
||||
.. _96Boards IE Specification:
|
||||
https://linaro.co/ie-specification
|
||||
|
||||
@@ -108,9 +108,9 @@ zephyr_i2c: &i2c1 {
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <I2C_BITRATE_FAST>;
|
||||
|
||||
vl53l1x: vl53l1x@52 {
|
||||
vl53l1x: vl53l1x@29 {
|
||||
compatible = "st,vl53l1x";
|
||||
reg = <0x52>;
|
||||
reg = <0x29>;
|
||||
status = "okay";
|
||||
xshut-gpios = <&gpiog 10 GPIO_ACTIVE_HIGH>;
|
||||
int-gpios = <&gpiod 8 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
@@ -17,4 +17,5 @@ if(CONFIG_BOARD_MPS2_AN521_CPU1 AND NOT CONFIG_OPENAMP)
|
||||
BUILD_BYPRODUCTS "${CPU0_BINARY_DIR}/${KERNEL_BIN_NAME}"
|
||||
BUILD_ALWAYS True
|
||||
)
|
||||
add_dependencies(app empty_cpu0)
|
||||
endif()
|
||||
|
||||
@@ -110,6 +110,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&clk_msik {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&clk_msis {
|
||||
status = "okay";
|
||||
msi-pll-mode;
|
||||
@@ -160,6 +164,8 @@
|
||||
};
|
||||
|
||||
&rng {
|
||||
clocks = <&rcc STM32_CLOCK(AHB2, 18)>,
|
||||
<&rcc STM32_SRC_MSIK RNG_SEL(1)>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -8,17 +8,20 @@
|
||||
# This section covers flags related to optimization #
|
||||
#####################################################
|
||||
set_compiler_property(PROPERTY no_optimization -On)
|
||||
|
||||
set_compiler_property(PROPERTY optimization_debug -Ol)
|
||||
|
||||
set_compiler_property(PROPERTY optimization_speed -Ohs)
|
||||
|
||||
set_compiler_property(PROPERTY optimization_size -Ohz)
|
||||
|
||||
set_compiler_property(PROPERTY optimization_size_aggressive -Ohz)
|
||||
|
||||
set_compiler_property(PROPERTY optimization_fast --no_size_constraints)
|
||||
|
||||
# IAR uses the GNU assembler so the options differ from the compiler
|
||||
set_property(TARGET asm PROPERTY no_optimization -O0)
|
||||
set_property(TARGET asm PROPERTY optimization_debug -Og)
|
||||
set_property(TARGET asm PROPERTY optimization_speed -O2)
|
||||
set_property(TARGET asm PROPERTY optimization_size -Os)
|
||||
set_property(TARGET asm PROPERTY optimization_size_aggressive -Oz)
|
||||
set_property(TARGET asm PROPERTY optimization_fast -Ofast)
|
||||
|
||||
#######################################################
|
||||
# This section covers flags related to warning levels #
|
||||
#######################################################
|
||||
|
||||
@@ -73,6 +73,9 @@ function(zephyr_mcuboot_tasks)
|
||||
"APPLICATION_CONFIG_DIR=\"${APPLICATION_CONFIG_DIR}\" "
|
||||
"and WEST_TOPDIR=\"${WEST_TOPDIR}\")")
|
||||
endif()
|
||||
|
||||
# Add key file as CMake dependency so a file change will rerun the build
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${${file}})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
include(${ZEPHYR_BASE}/cmake/toolchain/xcc/common.cmake)
|
||||
|
||||
set(COMPILER xcc)
|
||||
set(OPTIMIZE_FOR_DEBUG_FLAG "-O0")
|
||||
set(COMPILER_OPTIMIZE_FOR_DEBUG_FLAG "-O0")
|
||||
set(CC xcc)
|
||||
set(C++ xc++)
|
||||
set(LINKER xt-ld)
|
||||
|
||||
@@ -360,14 +360,14 @@ def get_catalog(generate_hw_features=False, hw_features_vendor_filter=None):
|
||||
# Grab all the twister files for this board and use them to figure out all the archs it
|
||||
# supports.
|
||||
board_archs = set()
|
||||
pattern = f"{board.name}*.yaml"
|
||||
for twister_file in board.dir.glob(pattern):
|
||||
try:
|
||||
with open(twister_file) as f:
|
||||
board_data = yaml.safe_load(f)
|
||||
board_archs.add(board_data.get("arch"))
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing twister file {twister_file}: {e}")
|
||||
for pattern in (f"{board.name}*.yaml", "twister.yaml"):
|
||||
for twister_file in board.dir.glob(pattern):
|
||||
try:
|
||||
with open(twister_file) as f:
|
||||
board_data = yaml.safe_load(f)
|
||||
board_archs.add(board_data.get("arch"))
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing twister file {twister_file}: {e}")
|
||||
|
||||
if doc_page and doc_page.is_relative_to(ZEPHYR_BASE):
|
||||
doc_page_path = doc_page.relative_to(ZEPHYR_BASE).as_posix()
|
||||
|
||||
@@ -4,7 +4,7 @@ TFTP
|
||||
####
|
||||
|
||||
Zephyr provides a simple TFTP client library that can enabled with
|
||||
:kconfig:option:`CONFIG_MQTT_SN_LIB` Kconfig option.
|
||||
:kconfig:option:`CONFIG_TFTP_LIB` Kconfig option.
|
||||
|
||||
See :zephyr:code-sample:`TFTP client sample application <tftp-client>` for
|
||||
more information about the library usage.
|
||||
|
||||
@@ -363,4 +363,4 @@ in the log.
|
||||
|
||||
.. _Eclipse IDE for C/C++ Developers: https://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/oxygen2
|
||||
.. _GNU MCU Eclipse plug-ins: https://gnu-mcu-eclipse.github.io/plugins/install/
|
||||
.. _pyOCD v0.11.0: https://github.com/mbedmicro/pyOCD/releases/tag/v0.11.0
|
||||
.. _pyOCD v0.11.0: https://github.com/pyocd/pyOCD/releases/tag/v0.11.0
|
||||
|
||||
@@ -26,6 +26,57 @@
|
||||
|
||||
.. _zephyr_4.2:
|
||||
|
||||
.. _zephyr_4.2.1:
|
||||
|
||||
Zephyr 4.2.1
|
||||
############
|
||||
|
||||
This is a bugfix release for Zephyr 4.2.0. The following issues are addressed by this release:
|
||||
|
||||
* :github:`96197` gPTP sample does not boot with NUCLEO-H563ZI
|
||||
* :github:`92393` LIS2DUX12 setting incorrect ODR configuration
|
||||
* :github:`93011` stm32u0: interrupt vectors for lpuart1 and lpuart2 are wrong in device tree
|
||||
* :github:`93220` Twister tests with coverage enabled crash during startup
|
||||
* :github:`93265` Stm32u5x: clock disable in sleep mode fix causing USB HS device initialization stalls
|
||||
* :github:`93342` doc: Documentation issue in 'connectivity/networking/api/tftp'
|
||||
* :github:`93350` net: tcp: keep-alive "pings" are no longer acknowledged with v4.2.0
|
||||
* :github:`93364` tests/subsys/llext fails after tagging 4.2
|
||||
* :github:`93424` Missing break after IPV6_MULTICAST_IF option processing
|
||||
* :github:`93445` STM32U535/545: dtc error for node wkup-pin@8 referencing non-existent port gpiof
|
||||
* :github:`93519` drivers: nxp_lpspi: Large performance degradation
|
||||
* :github:`93594` Nicla Vision has bad I2C address for VL53L1X sensor
|
||||
* :github:`93611` doc: Documentation issue in 'releases/release-notes-4.2'
|
||||
* :github:`93790` drivers: console: posix_arch_console: build warning with ``CONFIG_PRINTK=n``
|
||||
* :github:`93792` USB samples not working on ``max32690evkit``
|
||||
* :github:`93831` drivers: can: nrf: fix invalid pointer leading to undef behavior
|
||||
* :github:`93839` I3C: STM32: Has a Mutex deadlock on DAA Failure
|
||||
* :github:`94000` EXT2 fs_stat on mount point fails with a NULL pointer dereference.
|
||||
* :github:`94047` Shell device name tab completion for regulator parents show incorrect names
|
||||
* :github:`94063` SPI loopback tests failing on MAX32 SoCs.
|
||||
* :github:`94083` stm32: u3: low clock frequency for the RNG periphera
|
||||
* :github:`94093` Build error when OCRAM node is disabled in device tree (status = "disabled") [NXP RT1061]
|
||||
* :github:`94107` ppp link-layer address configuration is wrong
|
||||
* :github:`94325` iar: incorrect assembler optimzation flag
|
||||
* :github:`94473` LVGL Widgets Demo stopped working in v4.1 on mimxrt1060_evk@A
|
||||
* :github:`94702` Locally Administered Address (LAA) bit missing for STM32 ethernet driver
|
||||
* :github:`94703` Locally Administered Address (LAA) bit set on wrong index for NXP i.MX ethernet driver
|
||||
* :github:`94774` modules/picolibc: Roll back unnecessary changes, synchronize with SDK 0.17.4
|
||||
* :github:`94812` ``nocache`` data is included in ROM section
|
||||
* :github:`94842` iar: Zephyr 4.2 fails with IAR EWARM 9.70.1
|
||||
* :github:`94954` Spurious error log "No valid legacy adv to resume" in bt_hci_le_enh_conn_complete when using bt_le_ext_adv_start()
|
||||
* :github:`95113` gpio_pin_get_config for STM32 returns wrong flags value for input pins
|
||||
* :github:`95146` i2c: stm32: non-RTIO driver fixes on PM and on STM32F7 from Zephyr v4.3
|
||||
* :github:`95297` Links to the pyOCD repository are outdated
|
||||
* :github:`95456` Zephyr Netstack buffer leaks
|
||||
* :github:`95580` Picolibc module and SDK are not in sync for Zephyr 4.2.0
|
||||
* :github:`95721` Boards documentation: "arm" Architecture not specified at least for STM32MP13 and STM32N6 boards
|
||||
* :github:`95724` drivers: i2c: stm32: build error when using DMAs with st,stm32-i2c-v2 driver
|
||||
* :github:`95768` Possible TCP connection leak when creating a socket
|
||||
* :github:`95850` Applications do not watch MCUboot key file for changes
|
||||
* :github:`96087` TCP connection sends an incorrect seqnum FIN message
|
||||
* :github:`96172` arch: arm: switch to privilege stack in SVC handler
|
||||
* :github:`96768` incorrect i2c3 base address on stm32f303Xe
|
||||
|
||||
Zephyr 4.2.0
|
||||
############
|
||||
|
||||
@@ -317,6 +368,7 @@ New APIs and options
|
||||
* :kconfig:option:`CONFIG_LV_Z_COLOR_MONO_HW_INVERSION`
|
||||
|
||||
* LoRaWAN
|
||||
|
||||
* :c:func:`lorawan_request_link_check`
|
||||
|
||||
* Management
|
||||
|
||||
@@ -147,7 +147,7 @@ static int configure_hsfll(const struct device *dev, bool on)
|
||||
if (on) {
|
||||
int ret;
|
||||
|
||||
ret = clock_control_get_rate(dev, NULL, &spec.frequency);
|
||||
ret = clock_control_get_rate(config->auxpll, NULL, &spec.frequency);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
static char stdout_buff[_STDOUT_BUF_SIZE];
|
||||
static int n_pend; /* Number of pending characters in buffer */
|
||||
|
||||
#if defined(CONFIG_PRINTK) || defined(CONFIG_STDOUT_CONSOLE)
|
||||
static int print_char(int c)
|
||||
{
|
||||
int printnow = 0;
|
||||
@@ -36,6 +37,7 @@ static int print_char(int c)
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif /* defined(CONFIG_PRINTK) || defined(CONFIG_STDOUT_CONSOLE) */
|
||||
|
||||
/**
|
||||
* Ensure that whatever was written thru printk is displayed now
|
||||
|
||||
@@ -815,6 +815,12 @@ static void generate_mac(uint8_t *mac_addr)
|
||||
result_mac_32_bits = crc32_ieee((uint8_t *)unique_device_ID_12_bytes, 12);
|
||||
memcpy(&mac_addr[3], &result_mac_32_bits, 3);
|
||||
|
||||
/**
|
||||
* Set MAC address locally administered bit (LAA) as this is not assigned by the
|
||||
* manufacturer
|
||||
*/
|
||||
mac_addr[0] |= 0x02;
|
||||
|
||||
#endif /* NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0))) */
|
||||
#endif
|
||||
}
|
||||
@@ -845,6 +851,108 @@ static void RISAF_Config(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ETH_STM32_HAL_API_V1)
|
||||
static int eth_init_api_v1(const struct device *dev)
|
||||
{
|
||||
HAL_StatusTypeDef hal_ret = HAL_OK;
|
||||
struct eth_stm32_hal_dev_data *dev_data = dev->data;
|
||||
ETH_HandleTypeDef *heth = &dev_data->heth;
|
||||
|
||||
if (!ETH_STM32_AUTO_NEGOTIATION_ENABLE) {
|
||||
struct phy_link_state state;
|
||||
|
||||
phy_get_link_state(eth_stm32_phy_dev, &state);
|
||||
|
||||
heth->Init.DuplexMode = PHY_LINK_IS_FULL_DUPLEX(state.speed) ? ETH_MODE_FULLDUPLEX
|
||||
: ETH_MODE_HALFDUPLEX;
|
||||
heth->Init.Speed =
|
||||
PHY_LINK_IS_SPEED_100M(state.speed) ? ETH_SPEED_100M : ETH_SPEED_10M;
|
||||
}
|
||||
|
||||
hal_ret = HAL_ETH_Init(heth);
|
||||
if (hal_ret == HAL_TIMEOUT) {
|
||||
/* HAL Init time out. This could be linked to
|
||||
* a recoverable error. Log the issue and continue
|
||||
* driver initialization.
|
||||
*/
|
||||
LOG_WRN("HAL_ETH_Init timed out (cable not connected?)");
|
||||
} else if (hal_ret != HAL_OK) {
|
||||
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize semaphores */
|
||||
k_mutex_init(&dev_data->tx_mutex);
|
||||
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
|
||||
|
||||
HAL_ETH_DMATxDescListInit(heth, dma_tx_desc_tab, &dma_tx_buffer[0][0], ETH_TXBUFNB);
|
||||
HAL_ETH_DMARxDescListInit(heth, dma_rx_desc_tab, &dma_rx_buffer[0][0], ETH_RXBUFNB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#elif defined(CONFIG_ETH_STM32_HAL_API_V2)
|
||||
static int eth_init_api_v2(const struct device *dev)
|
||||
{
|
||||
HAL_StatusTypeDef hal_ret = HAL_OK;
|
||||
struct eth_stm32_hal_dev_data *dev_data = dev->data;
|
||||
ETH_HandleTypeDef *heth = &dev_data->heth;
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_ethernet)
|
||||
for (int ch = 0; ch < ETH_DMA_CH_CNT; ch++) {
|
||||
heth->Init.TxDesc[ch] = dma_tx_desc_tab[ch];
|
||||
heth->Init.RxDesc[ch] = dma_rx_desc_tab[ch];
|
||||
}
|
||||
#else
|
||||
heth->Init.TxDesc = dma_tx_desc_tab;
|
||||
heth->Init.RxDesc = dma_rx_desc_tab;
|
||||
#endif
|
||||
heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE;
|
||||
|
||||
hal_ret = HAL_ETH_Init(heth);
|
||||
if (hal_ret == HAL_TIMEOUT) {
|
||||
/* HAL Init time out. This could be linked to
|
||||
* a recoverable error. Log the issue and continue
|
||||
* driver initialization.
|
||||
*/
|
||||
LOG_ERR("HAL_ETH_Init Timed out");
|
||||
} else if (hal_ret != HAL_OK) {
|
||||
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PTP_CLOCK_STM32_HAL)
|
||||
/* Enable timestamping of RX packets. We enable all packets to be
|
||||
* timestamped to cover both IEEE 1588 and gPTP.
|
||||
*/
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
|
||||
heth->Instance->MACTSCR |= ETH_MACTSCR_TSENALL;
|
||||
#else
|
||||
heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSARFE;
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
|
||||
#endif /* CONFIG_PTP_CLOCK_STM32_HAL */
|
||||
|
||||
/* Initialize semaphores */
|
||||
k_mutex_init(&dev_data->tx_mutex);
|
||||
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
|
||||
k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT);
|
||||
|
||||
/* Tx config init: */
|
||||
memset(&tx_config, 0, sizeof(ETH_TxPacketConfig));
|
||||
tx_config.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
|
||||
tx_config.ChecksumCtrl = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM)
|
||||
? ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC
|
||||
: ETH_CHECKSUM_DISABLE;
|
||||
tx_config.CRCPadCtrl = ETH_CRC_PAD_INSERT;
|
||||
|
||||
/* prepare tx buffer header */
|
||||
for (uint16_t i = 0; i < ETH_TXBUFNB; ++i) {
|
||||
dma_tx_buffer_header[i].tx_buff.buffer = dma_tx_buffer[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
|
||||
|
||||
static int eth_initialize(const struct device *dev)
|
||||
{
|
||||
struct eth_stm32_hal_dev_data *dev_data = dev->data;
|
||||
@@ -891,41 +999,17 @@ static int eth_initialize(const struct device *dev)
|
||||
heth->Init.MACAddr = dev_data->mac_addr;
|
||||
|
||||
#if defined(CONFIG_ETH_STM32_HAL_API_V1)
|
||||
HAL_StatusTypeDef hal_ret = HAL_OK;
|
||||
ret = eth_init_api_v1(dev);
|
||||
#elif defined(CONFIG_ETH_STM32_HAL_API_V2)
|
||||
ret = eth_init_api_v2(dev);
|
||||
#else
|
||||
ret = 0;
|
||||
#endif /* CONFIG_ETH_STM32_HAL_API_V1 */
|
||||
|
||||
if (!ETH_STM32_AUTO_NEGOTIATION_ENABLE) {
|
||||
struct phy_link_state state;
|
||||
|
||||
phy_get_link_state(eth_stm32_phy_dev, &state);
|
||||
|
||||
heth->Init.DuplexMode = PHY_LINK_IS_FULL_DUPLEX(state.speed) ? ETH_MODE_FULLDUPLEX
|
||||
: ETH_MODE_HALFDUPLEX;
|
||||
heth->Init.Speed =
|
||||
PHY_LINK_IS_SPEED_100M(state.speed) ? ETH_SPEED_100M : ETH_SPEED_10M;
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
hal_ret = HAL_ETH_Init(heth);
|
||||
if (hal_ret == HAL_TIMEOUT) {
|
||||
/* HAL Init time out. This could be linked to */
|
||||
/* a recoverable error. Log the issue and continue */
|
||||
/* driver initialisation */
|
||||
LOG_WRN("HAL_ETH_Init timed out (cable not connected?)");
|
||||
} else if (hal_ret != HAL_OK) {
|
||||
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize semaphores */
|
||||
k_mutex_init(&dev_data->tx_mutex);
|
||||
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
|
||||
|
||||
HAL_ETH_DMATxDescListInit(heth, dma_tx_desc_tab,
|
||||
&dma_tx_buffer[0][0], ETH_TXBUFNB);
|
||||
HAL_ETH_DMARxDescListInit(heth, dma_rx_desc_tab,
|
||||
&dma_rx_buffer[0][0], ETH_RXBUFNB);
|
||||
|
||||
#endif /* !CONFIG_ETH_STM32_HAL_API_V1 */
|
||||
|
||||
LOG_DBG("MAC %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
dev_data->mac_addr[0], dev_data->mac_addr[1],
|
||||
dev_data->mac_addr[2], dev_data->mac_addr[3],
|
||||
@@ -982,68 +1066,6 @@ static void eth_stm32_mcast_filter(const struct device *dev, const struct ethern
|
||||
|
||||
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
|
||||
|
||||
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
|
||||
static int eth_init_api_v2(const struct device *dev)
|
||||
{
|
||||
HAL_StatusTypeDef hal_ret = HAL_OK;
|
||||
struct eth_stm32_hal_dev_data *dev_data = dev->data;
|
||||
ETH_HandleTypeDef *heth = &dev_data->heth;
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_ethernet)
|
||||
for (int ch = 0; ch < ETH_DMA_CH_CNT; ch++) {
|
||||
heth->Init.TxDesc[ch] = dma_tx_desc_tab[ch];
|
||||
heth->Init.RxDesc[ch] = dma_rx_desc_tab[ch];
|
||||
}
|
||||
#else
|
||||
heth->Init.TxDesc = dma_tx_desc_tab;
|
||||
heth->Init.RxDesc = dma_rx_desc_tab;
|
||||
#endif
|
||||
heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE;
|
||||
|
||||
hal_ret = HAL_ETH_Init(heth);
|
||||
if (hal_ret == HAL_TIMEOUT) {
|
||||
/* HAL Init time out. This could be linked to */
|
||||
/* a recoverable error. Log the issue and continue */
|
||||
/* driver initialisation */
|
||||
LOG_ERR("HAL_ETH_Init Timed out");
|
||||
} else if (hal_ret != HAL_OK) {
|
||||
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PTP_CLOCK_STM32_HAL)
|
||||
/* Enable timestamping of RX packets. We enable all packets to be
|
||||
* timestamped to cover both IEEE 1588 and gPTP.
|
||||
*/
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
|
||||
heth->Instance->MACTSCR |= ETH_MACTSCR_TSENALL;
|
||||
#else
|
||||
heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSARFE;
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
|
||||
#endif /* CONFIG_PTP_CLOCK_STM32_HAL */
|
||||
|
||||
/* Initialize semaphores */
|
||||
k_mutex_init(&dev_data->tx_mutex);
|
||||
k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
|
||||
k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT);
|
||||
|
||||
/* Tx config init: */
|
||||
memset(&tx_config, 0, sizeof(ETH_TxPacketConfig));
|
||||
tx_config.Attributes = ETH_TX_PACKETS_FEATURES_CSUM |
|
||||
ETH_TX_PACKETS_FEATURES_CRCPAD;
|
||||
tx_config.ChecksumCtrl = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM) ?
|
||||
ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC : ETH_CHECKSUM_DISABLE;
|
||||
tx_config.CRCPadCtrl = ETH_CRC_PAD_INSERT;
|
||||
|
||||
/* prepare tx buffer header */
|
||||
for (uint16_t i = 0; i < ETH_TXBUFNB; ++i) {
|
||||
dma_tx_buffer_header[i].tx_buff.buffer = dma_tx_buffer[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ETH_STM32_HAL_API_V2 */
|
||||
|
||||
static void set_mac_config(const struct device *dev, struct phy_link_state *state)
|
||||
{
|
||||
struct eth_stm32_hal_dev_data *dev_data = dev->data;
|
||||
@@ -1164,14 +1186,6 @@ static void eth_iface_init(struct net_if *iface)
|
||||
|
||||
ethernet_init(iface);
|
||||
|
||||
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
|
||||
/* This function requires the Ethernet interface to be
|
||||
* properly initialized. In auto-negotiation mode, it reads the speed
|
||||
* and duplex settings to configure the driver accordingly.
|
||||
*/
|
||||
eth_init_api_v2(dev);
|
||||
#endif
|
||||
|
||||
setup_mac_filter(heth);
|
||||
|
||||
net_if_carrier_off(iface);
|
||||
|
||||
@@ -62,10 +62,10 @@
|
||||
do { \
|
||||
uint32_t id = 0x001100; \
|
||||
\
|
||||
mac_addr[0] = FREESCALE_OUI_B0; \
|
||||
mac_addr[1] = FREESCALE_OUI_B1; \
|
||||
/* Set MAC address locally administered bit (LAA) */ \
|
||||
mac_addr[2] = FREESCALE_OUI_B2 | 0x02; \
|
||||
mac_addr[0] = FREESCALE_OUI_B0 | 0x02; \
|
||||
mac_addr[1] = FREESCALE_OUI_B1; \
|
||||
mac_addr[2] = FREESCALE_OUI_B2; \
|
||||
mac_addr[3] = (id >> 16) & 0xff; \
|
||||
mac_addr[4] = (id >> 8) & 0xff; \
|
||||
mac_addr[5] = (id + n) & 0xff; \
|
||||
|
||||
@@ -126,6 +126,12 @@ static int gpio_stm32_pincfg_to_flags(struct gpio_stm32_pin pin_cfg,
|
||||
if (pin_cfg.type == LL_GPIO_OUTPUT_OPENDRAIN) {
|
||||
flags |= GPIO_OPEN_DRAIN;
|
||||
}
|
||||
|
||||
if (pin_cfg.out_state == 0) {
|
||||
flags |= GPIO_OUTPUT_INIT_LOW;
|
||||
} else {
|
||||
flags |= GPIO_OUTPUT_INIT_HIGH;
|
||||
}
|
||||
} else if (pin_cfg.mode == LL_GPIO_MODE_INPUT) {
|
||||
flags |= GPIO_INPUT;
|
||||
#ifdef CONFIG_SOC_SERIES_STM32F1X
|
||||
@@ -142,12 +148,6 @@ static int gpio_stm32_pincfg_to_flags(struct gpio_stm32_pin pin_cfg,
|
||||
flags |= GPIO_PULL_DOWN;
|
||||
}
|
||||
|
||||
if (pin_cfg.out_state != 0) {
|
||||
flags |= GPIO_OUTPUT_HIGH;
|
||||
} else {
|
||||
flags |= GPIO_OUTPUT_LOW;
|
||||
}
|
||||
|
||||
*out_flags = flags;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <soc.h>
|
||||
#include <stm32_cache.h>
|
||||
#include <stm32_ll_i2c.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
|
||||
@@ -210,13 +210,16 @@ int i2c_stm32_target_register(const struct device *dev,
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM_DEVICE_RUNTIME)
|
||||
/* Mark device as active */
|
||||
(void)pm_device_runtime_get(dev);
|
||||
|
||||
#if !defined(CONFIG_SOC_SERIES_STM32F7X)
|
||||
if (pm_device_wakeup_is_capable(dev)) {
|
||||
/* Mark device as active */
|
||||
(void)pm_device_runtime_get(dev);
|
||||
/* Enable wake-up from stop */
|
||||
LOG_DBG("i2c: enabling wakeup from stop");
|
||||
LL_I2C_EnableWakeUpFromStop(cfg->i2c);
|
||||
}
|
||||
#endif /* !CONFIG_SOC_SERIES_STM32F7X */
|
||||
#endif /* defined(CONFIG_PM_DEVICE_RUNTIME) */
|
||||
|
||||
LL_I2C_Enable(i2c);
|
||||
@@ -299,15 +302,18 @@ int i2c_stm32_target_unregister(const struct device *dev,
|
||||
LL_I2C_Disable(i2c);
|
||||
|
||||
#if defined(CONFIG_PM_DEVICE_RUNTIME)
|
||||
#if !defined(CONFIG_SOC_SERIES_STM32F7X)
|
||||
if (pm_device_wakeup_is_capable(dev)) {
|
||||
/* Disable wake-up from STOP */
|
||||
LOG_DBG("i2c: disabling wakeup from stop");
|
||||
LL_I2C_DisableWakeUpFromStop(i2c);
|
||||
/* Release the device */
|
||||
(void)pm_device_runtime_put(dev);
|
||||
}
|
||||
#endif /* !CONFIG_SOC_SERIES_STM32F7X */
|
||||
#endif /* defined(CONFIG_PM_DEVICE_RUNTIME) */
|
||||
|
||||
/* Release the device */
|
||||
(void)pm_device_runtime_put(dev);
|
||||
|
||||
data->slave_attached = false;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1047,6 +1047,7 @@ static int i3c_stm32_do_daa(const struct device *dev)
|
||||
const struct i3c_stm32_config *config = dev->config;
|
||||
struct i3c_stm32_data *data = dev->data;
|
||||
I3C_TypeDef *i3c = config->i3c;
|
||||
int ret = 0;
|
||||
|
||||
k_mutex_lock(&data->bus_mutex, K_FOREVER);
|
||||
|
||||
@@ -1068,7 +1069,8 @@ static int i3c_stm32_do_daa(const struct device *dev)
|
||||
|
||||
/* Wait for DAA to finish */
|
||||
if (k_sem_take(&data->device_sync_sem, STM32_I3C_TRANSFER_TIMEOUT) != 0) {
|
||||
return -ETIMEDOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
goto i3c_stm32_do_daa_ending;
|
||||
}
|
||||
|
||||
if (data->msg_state == STM32_I3C_MSG_ERR) {
|
||||
@@ -1076,12 +1078,14 @@ static int i3c_stm32_do_daa(const struct device *dev)
|
||||
/* Enable TXFNF interrupt in case an error occurred before it was enabled by RXFNE
|
||||
*/
|
||||
LL_I3C_EnableIT_TXFNF(i3c);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto i3c_stm32_do_daa_ending;
|
||||
}
|
||||
|
||||
i3c_stm32_do_daa_ending:
|
||||
k_mutex_unlock(&data->bus_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I3C_STM32_DMA
|
||||
|
||||
@@ -23,7 +23,7 @@ BUILD_ASSERT(DT_PROP(FLEXRAM_DT_NODE, flexram_has_magic_addr),
|
||||
#define BANK_SIZE (DT_PROP(FLEXRAM_DT_NODE, flexram_bank_size) * 1024)
|
||||
#define NUM_BANKS DT_PROP(FLEXRAM_DT_NODE, flexram_num_ram_banks)
|
||||
|
||||
#define IS_CHILD_RAM_TYPE(node_id, compat) DT_NODE_HAS_COMPAT(node_id, compat)
|
||||
#define IS_CHILD_RAM_TYPE(node_id, compat) DT_NODE_HAS_COMPAT_STATUS(node_id, compat, okay)
|
||||
#define DOES_RAM_TYPE_EXIST(compat) \
|
||||
DT_FOREACH_CHILD_SEP_VARGS(FLEXRAM_DT_NODE, IS_CHILD_RAM_TYPE, (+), compat)
|
||||
|
||||
|
||||
@@ -974,17 +974,9 @@ static int ppp_driver_init(const struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct net_linkaddr *ppp_get_mac(struct ppp_driver_context *ppp)
|
||||
{
|
||||
(void)net_linkaddr_set(&ppp->ll_addr, ppp->mac_addr, sizeof(ppp->mac_addr));
|
||||
|
||||
return &ppp->ll_addr;
|
||||
}
|
||||
|
||||
static void ppp_iface_init(struct net_if *iface)
|
||||
{
|
||||
struct ppp_driver_context *ppp = net_if_get_device(iface)->data;
|
||||
struct net_linkaddr *ll_addr;
|
||||
|
||||
LOG_DBG("[%p] iface %p", ppp, iface);
|
||||
|
||||
@@ -997,11 +989,6 @@ static void ppp_iface_init(struct net_if *iface)
|
||||
ppp->init_done = true;
|
||||
ppp->iface = iface;
|
||||
|
||||
/* The mac address is not really used but network interface expects
|
||||
* to find one.
|
||||
*/
|
||||
ll_addr = ppp_get_mac(ppp);
|
||||
|
||||
if (CONFIG_PPP_MAC_ADDR[0] != 0) {
|
||||
if (net_bytes_from_str(ppp->mac_addr, sizeof(ppp->mac_addr),
|
||||
CONFIG_PPP_MAC_ADDR) < 0) {
|
||||
@@ -1018,7 +1005,10 @@ use_random_mac:
|
||||
ppp->mac_addr[5] = sys_rand8_get();
|
||||
}
|
||||
|
||||
net_if_set_link_addr(iface, ll_addr->addr, ll_addr->len,
|
||||
/* The MAC address is not really used, but the network interface expects to find one. */
|
||||
(void)net_linkaddr_set(&ppp->ll_addr, ppp->mac_addr, sizeof(ppp->mac_addr));
|
||||
|
||||
net_if_set_link_addr(iface, ppp->ll_addr.addr, ppp->ll_addr.len,
|
||||
NET_LINK_ETHERNET);
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_PPP_CAPTURE)) {
|
||||
|
||||
@@ -527,7 +527,12 @@ static bool device_is_regulator(const struct device *dev)
|
||||
return DEVICE_API_IS(regulator, dev);
|
||||
}
|
||||
|
||||
static void device_name_get(size_t idx, struct shell_static_entry *entry)
|
||||
static bool device_is_regulator_parent(const struct device *dev)
|
||||
{
|
||||
return DEVICE_API_IS(regulator_parent, dev);
|
||||
}
|
||||
|
||||
static void device_name_get_regulator(size_t idx, struct shell_static_entry *entry)
|
||||
{
|
||||
const struct device *dev = shell_device_filter(idx, device_is_regulator);
|
||||
|
||||
@@ -537,7 +542,18 @@ static void device_name_get(size_t idx, struct shell_static_entry *entry)
|
||||
entry->subcmd = NULL;
|
||||
}
|
||||
|
||||
SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
|
||||
static void device_name_get_regulator_parent(size_t idx, struct shell_static_entry *entry)
|
||||
{
|
||||
const struct device *dev = shell_device_filter(idx, device_is_regulator_parent);
|
||||
|
||||
entry->syntax = (dev != NULL) ? dev->name : NULL;
|
||||
entry->handler = NULL;
|
||||
entry->help = NULL;
|
||||
entry->subcmd = NULL;
|
||||
}
|
||||
|
||||
SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get_regulator);
|
||||
SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_parent, device_name_get_regulator_parent);
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(
|
||||
sub_regulator_cmds,
|
||||
@@ -579,12 +595,12 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
|
||||
2, 0),
|
||||
SHELL_CMD_ARG(errors, &dsub_device_name, SHELL_HELP("Get active errors", "<device>"),
|
||||
cmd_errors, 2, 0),
|
||||
SHELL_CMD_ARG(dvsset, &dsub_device_name,
|
||||
SHELL_CMD_ARG(dvsset, &dsub_device_name_parent,
|
||||
SHELL_HELP("Set dynamic voltage scaling state",
|
||||
"<device> <state identifier>"),
|
||||
cmd_dvsset, 3, 0),
|
||||
SHELL_CMD_ARG(shipmode, &dsub_device_name, SHELL_HELP("Enable ship mode", "<device>"),
|
||||
cmd_shipmode, 2, 0),
|
||||
SHELL_CMD_ARG(shipmode, &dsub_device_name_parent,
|
||||
SHELL_HELP("Enable ship mode", "<device>"), cmd_shipmode, 2, 0),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_CMD_REGISTER(regulator, &sub_regulator_cmds, "Regulator playground",
|
||||
|
||||
@@ -55,6 +55,19 @@ static int lis2dux12_freq_to_odr_val(const struct device *dev, uint16_t freq)
|
||||
int odr;
|
||||
|
||||
for (odr = LIS2DUX12_DT_ODR_OFF; odr < LIS2DUX12_DT_ODR_END; odr++) {
|
||||
/*
|
||||
* In case power-mode is HP, skip the ULP odrs in order to
|
||||
* avoid to erroneously break the loop sooner than expected.
|
||||
* In HP mode the correct ODRs must be found from
|
||||
* LIS2DUX12_DT_ODR_6Hz on.
|
||||
*/
|
||||
if ((cfg->pm == LIS2DUX12_OPER_MODE_HIGH_PERFORMANCE) &&
|
||||
((odr == LIS2DUX12_DT_ODR_1Hz_ULP) ||
|
||||
(odr == LIS2DUX12_DT_ODR_3Hz_ULP) ||
|
||||
(odr == LIS2DUX12_DT_ODR_25Hz_ULP))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (freq <= lis2dux12_odr_map[odr]) {
|
||||
break;
|
||||
}
|
||||
@@ -69,15 +82,6 @@ static int lis2dux12_freq_to_odr_val(const struct device *dev, uint16_t freq)
|
||||
return LIS2DUX12_DT_ODR_OFF;
|
||||
}
|
||||
|
||||
/* handle high performance mode */
|
||||
if (cfg->pm == LIS2DUX12_OPER_MODE_HIGH_PERFORMANCE) {
|
||||
if (odr < LIS2DUX12_DT_ODR_6Hz) {
|
||||
odr = LIS2DUX12_DT_ODR_6Hz;
|
||||
}
|
||||
|
||||
odr |= 0x10;
|
||||
}
|
||||
|
||||
return odr;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,19 @@ static int32_t st_lis2dux12_set_odr_raw(const struct device *dev, uint8_t odr)
|
||||
struct lis2dux12_data *data = dev->data;
|
||||
const struct lis2dux12_config *cfg = dev->config;
|
||||
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
|
||||
lis2dux12_md_t mode = {.odr = odr, .fs = data->range};
|
||||
lis2dux12_md_t mode;
|
||||
|
||||
/* handle high performance mode */
|
||||
if (cfg->pm == LIS2DUX12_OPER_MODE_HIGH_PERFORMANCE) {
|
||||
if (odr < LIS2DUX12_DT_ODR_6Hz) {
|
||||
odr = LIS2DUX12_DT_ODR_6Hz;
|
||||
}
|
||||
|
||||
odr |= 0x10;
|
||||
}
|
||||
|
||||
mode.odr = odr;
|
||||
mode.fs = data->range;
|
||||
|
||||
data->odr = odr;
|
||||
return lis2dux12_mode_set(ctx, &mode);
|
||||
|
||||
@@ -17,7 +17,19 @@ static int32_t st_lis2duxs12_set_odr_raw(const struct device *dev, uint8_t odr)
|
||||
struct lis2dux12_data *data = dev->data;
|
||||
const struct lis2dux12_config *cfg = dev->config;
|
||||
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
|
||||
lis2duxs12_md_t mode = {.odr = odr, .fs = data->range};
|
||||
lis2duxs12_md_t mode;
|
||||
|
||||
/* handle high performance mode */
|
||||
if (cfg->pm == LIS2DUX12_OPER_MODE_HIGH_PERFORMANCE) {
|
||||
if (odr < LIS2DUX12_DT_ODR_6Hz) {
|
||||
odr = LIS2DUX12_DT_ODR_6Hz;
|
||||
}
|
||||
|
||||
odr |= 0x10;
|
||||
}
|
||||
|
||||
mode.odr = odr;
|
||||
mode.fs = data->range;
|
||||
|
||||
data->odr = odr;
|
||||
return lis2duxs12_mode_set(ctx, &mode);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Analog Devices, Inc.
|
||||
* Copyright (c) 2024-2025 Analog Devices, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -27,6 +27,9 @@
|
||||
LOG_MODULE_REGISTER(spi_max32, CONFIG_SPI_LOG_LEVEL);
|
||||
#include "spi_context.h"
|
||||
|
||||
#define SPI_MAX32_MIN_WORD_BITS 2
|
||||
#define SPI_MAX32_MAX_WORD_BITS 16
|
||||
|
||||
#ifdef CONFIG_SPI_MAX32_DMA
|
||||
struct max32_spi_dma_config {
|
||||
const struct device *dev;
|
||||
@@ -87,9 +90,11 @@ static int spi_configure(const struct device *dev, const struct spi_config *conf
|
||||
mxc_spi_regs_t *regs = cfg->regs;
|
||||
struct max32_spi_data *data = dev->data;
|
||||
|
||||
#ifndef CONFIG_SPI_RTIO
|
||||
if (spi_context_configured(&data->ctx, config)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SPI_OP_MODE_GET(config->operation) & SPI_OP_MODE_SLAVE) {
|
||||
return -ENOTSUP;
|
||||
@@ -103,7 +108,7 @@ static int spi_configure(const struct device *dev, const struct spi_config *conf
|
||||
|
||||
ret = Wrap_MXC_SPI_Init(regs, master_mode, quad_mode, num_slaves, ss_polarity, spi_speed);
|
||||
if (ret) {
|
||||
return ret;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int cpol = (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) ? 1 : 0;
|
||||
@@ -119,12 +124,12 @@ static int spi_configure(const struct device *dev, const struct spi_config *conf
|
||||
ret = MXC_SPI_SetMode(regs, SPI_MODE_0);
|
||||
}
|
||||
if (ret) {
|
||||
return ret;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = MXC_SPI_SetDataSize(regs, SPI_WORD_SIZE_GET(config->operation));
|
||||
if (ret) {
|
||||
return ret;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SPI_EXTENDED_MODES)
|
||||
@@ -145,7 +150,7 @@ static int spi_configure(const struct device *dev, const struct spi_config *conf
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -163,7 +168,7 @@ static inline int spi_max32_get_dfs_shift(const struct spi_context *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
|
||||
static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req, uint8_t dfs_shift)
|
||||
{
|
||||
req->rxCnt = 0;
|
||||
req->txCnt = 0;
|
||||
@@ -172,9 +177,10 @@ static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
|
||||
MXC_SPI_SetSlave(spi, req->ssIdx);
|
||||
}
|
||||
|
||||
/* SPI_CTRL1 holds the number of words so apply dfs_shift first */
|
||||
if (req->rxData && req->rxLen) {
|
||||
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
|
||||
req->rxLen << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
|
||||
(req->rxLen >> dfs_shift) << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
|
||||
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
|
||||
} else {
|
||||
spi->ctrl1 &= ~MXC_F_SPI_CTRL1_RX_NUM_CHAR;
|
||||
@@ -183,7 +189,7 @@ static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
|
||||
|
||||
if (req->txLen) {
|
||||
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_TX_NUM_CHAR,
|
||||
req->txLen << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
|
||||
(req->txLen >> dfs_shift) << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
|
||||
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
|
||||
} else {
|
||||
spi->ctrl1 &= ~MXC_F_SPI_CTRL1_TX_NUM_CHAR;
|
||||
@@ -206,8 +212,8 @@ static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data
|
||||
MXC_SPI_ClearTXFIFO(spi);
|
||||
MXC_SPI_ClearRXFIFO(spi);
|
||||
|
||||
tx_len = req->txLen << dfs_shift;
|
||||
rx_len = req->rxLen << dfs_shift;
|
||||
tx_len = req->txLen;
|
||||
rx_len = req->rxLen;
|
||||
do {
|
||||
remain = tx_len - req->txCnt;
|
||||
if (remain > 0) {
|
||||
@@ -251,8 +257,6 @@ static int spi_max32_transceive(const struct device *dev)
|
||||
uint32_t len;
|
||||
uint8_t dfs_shift;
|
||||
|
||||
MXC_SPI_ClearTXFIFO(cfg->regs);
|
||||
|
||||
dfs_shift = spi_max32_get_dfs_shift(ctx);
|
||||
|
||||
len = spi_context_max_continuous_chunk(ctx);
|
||||
@@ -263,48 +267,64 @@ static int spi_max32_transceive(const struct device *dev)
|
||||
len = sqe->rx.buf_len;
|
||||
data->req.rxData = sqe->rx.buf;
|
||||
data->req.rxLen = sqe->rx.buf_len;
|
||||
if (data->req.rxData == NULL) {
|
||||
data->req.rxData = data->dummy;
|
||||
data->req.rxLen = 0;
|
||||
}
|
||||
data->req.txData = NULL;
|
||||
data->req.txLen = len >> dfs_shift;
|
||||
data->req.txLen = len;
|
||||
break;
|
||||
case RTIO_OP_TX:
|
||||
len = sqe->tx.buf_len;
|
||||
data->req.rxLen = 0;
|
||||
data->req.rxData = data->dummy;
|
||||
data->req.txData = (uint8_t *)sqe->tx.buf;
|
||||
data->req.txLen = len >> dfs_shift;
|
||||
data->req.txLen = len;
|
||||
break;
|
||||
case RTIO_OP_TINY_TX:
|
||||
len = sqe->tiny_tx.buf_len;
|
||||
data->req.txData = (uint8_t *)sqe->tiny_tx.buf;
|
||||
data->req.rxData = data->dummy;
|
||||
data->req.txLen = len >> dfs_shift;
|
||||
data->req.txLen = len;
|
||||
data->req.rxLen = 0;
|
||||
break;
|
||||
case RTIO_OP_TXRX:
|
||||
len = sqe->txrx.buf_len;
|
||||
data->req.txData = (uint8_t *)sqe->txrx.tx_buf;
|
||||
data->req.rxData = sqe->txrx.rx_buf;
|
||||
data->req.txLen = len >> dfs_shift;
|
||||
data->req.rxLen = len >> dfs_shift;
|
||||
data->req.txLen = len;
|
||||
data->req.rxLen = len;
|
||||
if (data->req.rxData == NULL) {
|
||||
data->req.rxData = data->dummy;
|
||||
data->req.rxLen = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
data->req.txLen = len >> dfs_shift;
|
||||
data->req.txLen = len;
|
||||
data->req.txData = (uint8_t *)ctx->tx_buf;
|
||||
data->req.rxLen = len >> dfs_shift;
|
||||
data->req.rxLen = len;
|
||||
data->req.rxData = ctx->rx_buf;
|
||||
|
||||
data->req.rxData = ctx->rx_buf;
|
||||
|
||||
data->req.rxLen = len >> dfs_shift;
|
||||
if (!data->req.rxData) {
|
||||
/* Pass a dummy buffer to HAL if receive buffer is NULL, otherwise
|
||||
* corrupt data is read during subsequent transactions.
|
||||
*/
|
||||
data->req.rxData = data->dummy;
|
||||
data->req.rxLen = 0;
|
||||
|
||||
if (!data->req.txData && !data->req.txLen) {
|
||||
/* Both RX and TX are NULL, nothing to do */
|
||||
spi_context_update_tx(&data->ctx, dfs_shift ? 2 : 1, len);
|
||||
spi_context_update_rx(&data->ctx, dfs_shift ? 2 : 1, len);
|
||||
if (!spi_context_tx_on(ctx) && !spi_context_rx_on(ctx)) {
|
||||
spi_context_complete(ctx, dev, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
data->req.spi = cfg->regs;
|
||||
@@ -312,15 +332,17 @@ static int spi_max32_transceive(const struct device *dev)
|
||||
data->req.ssDeassert = 0;
|
||||
data->req.txCnt = 0;
|
||||
data->req.rxCnt = 0;
|
||||
spi_max32_setup(cfg->regs, &data->req);
|
||||
spi_max32_setup(cfg->regs, &data->req, dfs_shift);
|
||||
#ifdef CONFIG_SPI_MAX32_INTERRUPT
|
||||
MXC_SPI_SetTXThreshold(cfg->regs, 1);
|
||||
MXC_SPI_SetTXThreshold(cfg->regs, 1 << dfs_shift);
|
||||
if (data->req.rxLen) {
|
||||
MXC_SPI_SetRXThreshold(cfg->regs, 2);
|
||||
MXC_SPI_SetRXThreshold(cfg->regs, 2 << dfs_shift);
|
||||
MXC_SPI_EnableInt(cfg->regs, ADI_MAX32_SPI_INT_EN_RX_THD);
|
||||
}
|
||||
MXC_SPI_EnableInt(cfg->regs, ADI_MAX32_SPI_INT_EN_TX_THD | ADI_MAX32_SPI_INT_EN_MST_DONE);
|
||||
|
||||
MXC_SPI_ClearTXFIFO(cfg->regs);
|
||||
MXC_SPI_ClearRXFIFO(cfg->regs);
|
||||
if (!data->req.txData) {
|
||||
data->req.txCnt =
|
||||
MXC_SPI_WriteTXFIFO(cfg->regs, data->dummy, MIN(len, sizeof(data->dummy)));
|
||||
@@ -334,8 +356,8 @@ static int spi_max32_transceive(const struct device *dev)
|
||||
if (ret) {
|
||||
ret = -EIO;
|
||||
} else {
|
||||
spi_context_update_tx(ctx, 1, len);
|
||||
spi_context_update_rx(ctx, 1, len);
|
||||
spi_context_update_tx(ctx, dfs_shift ? 2 : 1, len);
|
||||
spi_context_update_rx(ctx, dfs_shift ? 2 : 1, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -366,7 +388,7 @@ static int transceive(const struct device *dev, const struct spi_config *config,
|
||||
ret = spi_configure(dev, config);
|
||||
if (ret != 0) {
|
||||
spi_context_release(ctx, ret);
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1);
|
||||
@@ -418,9 +440,20 @@ static int transceive(const struct device *dev, const struct spi_config *config,
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct spi_rtio *rtio_ctx = data->rtio_ctx;
|
||||
/* Guard against unsupported word lengths here, as spi_configure is
|
||||
* called at a later stage
|
||||
*/
|
||||
if ((SPI_WORD_SIZE_GET(config->operation) < SPI_MAX32_MIN_WORD_BITS) ||
|
||||
(SPI_WORD_SIZE_GET(config->operation) > SPI_MAX32_MAX_WORD_BITS)) {
|
||||
ret = -ENOTSUP;
|
||||
} else {
|
||||
if (tx_bufs || rx_bufs) {
|
||||
struct spi_rtio *rtio_ctx = data->rtio_ctx;
|
||||
|
||||
ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
|
||||
}
|
||||
}
|
||||
|
||||
ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
|
||||
#endif
|
||||
spi_context_release(ctx, ret);
|
||||
return ret;
|
||||
@@ -434,9 +467,10 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
|
||||
const struct device *spi_dev = data->dev;
|
||||
const struct max32_spi_config *config = spi_dev->config;
|
||||
uint32_t len;
|
||||
uint8_t dfs = spi_max32_get_dfs_shift(&data->ctx) ? 2 : 1;
|
||||
|
||||
if (status < 0) {
|
||||
LOG_ERR("DMA callback error with channel %d.", channel);
|
||||
LOG_ERR("DMA callback error for channel %u: %d", channel, status);
|
||||
} else {
|
||||
/* identify the origin of this callback */
|
||||
if (channel == config->tx_dma.channel) {
|
||||
@@ -447,14 +481,14 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
|
||||
}
|
||||
if ((data->dma_stat & SPI_MAX32_DMA_DONE_FLAG) == SPI_MAX32_DMA_DONE_FLAG) {
|
||||
len = spi_context_max_continuous_chunk(&data->ctx);
|
||||
spi_context_update_tx(&data->ctx, 1, len);
|
||||
spi_context_update_rx(&data->ctx, 1, len);
|
||||
spi_context_update_tx(&data->ctx, dfs, len);
|
||||
spi_context_update_rx(&data->ctx, dfs, len);
|
||||
spi_context_complete(&data->ctx, spi_dev, status == 0 ? 0 : -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
|
||||
uint8_t word_shift)
|
||||
uint8_t dfs_shift)
|
||||
{
|
||||
int ret;
|
||||
const struct max32_spi_config *config = dev->config;
|
||||
@@ -467,9 +501,9 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
|
||||
dma_cfg.user_data = (void *)data;
|
||||
dma_cfg.dma_slot = config->tx_dma.slot;
|
||||
dma_cfg.block_count = 1;
|
||||
dma_cfg.source_data_size = 1U << word_shift;
|
||||
dma_cfg.source_burst_length = 1U;
|
||||
dma_cfg.dest_data_size = 1U << word_shift;
|
||||
dma_cfg.source_data_size = 1U << dfs_shift;
|
||||
dma_cfg.source_burst_length = 1U << dfs_shift;
|
||||
dma_cfg.dest_data_size = 1U << dfs_shift;
|
||||
dma_cfg.head_block = &dma_blk;
|
||||
dma_blk.block_size = len;
|
||||
if (buf) {
|
||||
@@ -489,7 +523,7 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
|
||||
}
|
||||
|
||||
static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
|
||||
uint8_t word_shift)
|
||||
uint8_t dfs_shift)
|
||||
{
|
||||
int ret;
|
||||
const struct max32_spi_config *config = dev->config;
|
||||
@@ -502,9 +536,9 @@ static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, u
|
||||
dma_cfg.user_data = (void *)data;
|
||||
dma_cfg.dma_slot = config->rx_dma.slot;
|
||||
dma_cfg.block_count = 1;
|
||||
dma_cfg.source_data_size = 1U << word_shift;
|
||||
dma_cfg.source_burst_length = 1U;
|
||||
dma_cfg.dest_data_size = 1U << word_shift;
|
||||
dma_cfg.source_data_size = 1U << dfs_shift;
|
||||
dma_cfg.source_burst_length = 1U << dfs_shift;
|
||||
dma_cfg.dest_data_size = 1U << dfs_shift;
|
||||
dma_cfg.head_block = &dma_blk;
|
||||
dma_blk.block_size = len;
|
||||
if (buf) {
|
||||
@@ -540,6 +574,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
|
||||
spi_context_lock(ctx, async, cb, userdata, config);
|
||||
|
||||
MXC_SPI_ClearTXFIFO(spi);
|
||||
MXC_SPI_ClearRXFIFO(spi);
|
||||
|
||||
ret = dma_get_status(cfg->tx_dma.dev, cfg->tx_dma.channel, &status);
|
||||
if (ret < 0 || status.busy) {
|
||||
@@ -553,9 +588,14 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Word sizes less than 8-bits are not supported in DMA mode */
|
||||
if (SPI_WORD_SIZE_GET(config->operation) < 8) {
|
||||
ret = -ENOTSUP;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = spi_configure(dev, config);
|
||||
if (ret != 0) {
|
||||
ret = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@@ -581,12 +621,17 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
|
||||
dfs_shift = spi_max32_get_dfs_shift(ctx);
|
||||
word_count = len >> dfs_shift;
|
||||
|
||||
if (word_count == 0) {
|
||||
/* Nothing to do, continue */
|
||||
continue;
|
||||
}
|
||||
|
||||
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
|
||||
word_count << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
|
||||
spi->dma |= ADI_MAX32_SPI_DMA_RX_FIFO_CLEAR;
|
||||
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
|
||||
spi->dma |= ADI_MAX32_SPI_DMA_RX_DMA_EN;
|
||||
MXC_SPI_SetRXThreshold(spi, 0);
|
||||
MXC_SPI_SetRXThreshold(spi, dfs_shift ? 1 : 0);
|
||||
|
||||
ret = spi_max32_rx_dma_load(dev, ctx->rx_buf, len, dfs_shift);
|
||||
if (ret < 0) {
|
||||
@@ -598,7 +643,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
|
||||
spi->dma |= ADI_MAX32_SPI_DMA_TX_FIFO_CLEAR;
|
||||
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
|
||||
spi->dma |= ADI_MAX32_SPI_DMA_TX_DMA_EN;
|
||||
MXC_SPI_SetTXThreshold(spi, 1);
|
||||
MXC_SPI_SetTXThreshold(spi, 2);
|
||||
|
||||
ret = spi_max32_tx_dma_load(dev, ctx->tx_buf, len, dfs_shift);
|
||||
if (ret < 0) {
|
||||
@@ -754,6 +799,7 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
const struct device *dev = data->dev;
|
||||
uint32_t len;
|
||||
uint8_t dfs;
|
||||
|
||||
#ifdef CONFIG_SPI_RTIO
|
||||
struct spi_rtio *rtio_ctx = data->rtio_ctx;
|
||||
@@ -762,9 +808,10 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
|
||||
spi_max32_iodev_complete(data->dev, 0);
|
||||
}
|
||||
#endif
|
||||
dfs = spi_max32_get_dfs_shift(ctx) ? 2 : 1;
|
||||
len = spi_context_max_continuous_chunk(ctx);
|
||||
spi_context_update_tx(ctx, 1, len);
|
||||
spi_context_update_rx(ctx, 1, len);
|
||||
spi_context_update_tx(ctx, dfs, len);
|
||||
spi_context_update_rx(ctx, dfs, len);
|
||||
#ifdef CONFIG_SPI_ASYNC
|
||||
if (ctx->asynchronous && ((spi_context_tx_on(ctx) || spi_context_rx_on(ctx)))) {
|
||||
k_work_submit(&data->async_work);
|
||||
@@ -804,12 +851,11 @@ static void spi_max32_isr(const struct device *dev)
|
||||
mxc_spi_req_t *req = &data->req;
|
||||
mxc_spi_regs_t *spi = cfg->regs;
|
||||
uint32_t flags, remain;
|
||||
uint8_t dfs_shift = spi_max32_get_dfs_shift(&data->ctx);
|
||||
|
||||
flags = MXC_SPI_GetFlags(spi);
|
||||
MXC_SPI_ClearFlags(spi);
|
||||
|
||||
remain = (req->txLen << dfs_shift) - req->txCnt;
|
||||
remain = req->txLen - req->txCnt;
|
||||
if (flags & ADI_MAX32_SPI_INT_FL_TX_THD) {
|
||||
if (remain) {
|
||||
if (!data->req.txData) {
|
||||
@@ -824,10 +870,10 @@ static void spi_max32_isr(const struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
remain = (req->rxLen << dfs_shift) - req->rxCnt;
|
||||
remain = req->rxLen - req->rxCnt;
|
||||
if (remain) {
|
||||
req->rxCnt += MXC_SPI_ReadRXFIFO(spi, &req->rxData[req->rxCnt], remain);
|
||||
remain = (req->rxLen << dfs_shift) - req->rxCnt;
|
||||
remain = req->rxLen - req->rxCnt;
|
||||
if (remain >= MXC_SPI_FIFO_DEPTH) {
|
||||
MXC_SPI_SetRXThreshold(spi, 2);
|
||||
} else {
|
||||
|
||||
@@ -132,7 +132,10 @@ static uint8_t lpspi_calc_delay_scaler(uint32_t desired_delay_ns,
|
||||
delay_cycles = (uint64_t)prescaled_clock * desired_delay_ns;
|
||||
delay_cycles = DIV_ROUND_UP(delay_cycles, NSEC_PER_SEC);
|
||||
|
||||
/* what the min_cycles parameter is about is that
|
||||
/* clamp to minimally possible cycles to avoid underflow */
|
||||
delay_cycles = MAX(delay_cycles, min_cycles);
|
||||
|
||||
/* what the min_cycles parameter is about is that
|
||||
* PCSSCK and SCKPSC are +1 cycles of the programmed value,
|
||||
* while DBT is +2 cycles of the programmed value.
|
||||
* So this calculates the value to program to the register.
|
||||
|
||||
@@ -429,9 +429,6 @@ static int usb_dc_stm32_clock_enable(void)
|
||||
LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI);
|
||||
#elif defined(CONFIG_SOC_SERIES_STM32U5X)
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_USBPHY);
|
||||
/* Both OTG HS and USBPHY sleep clock MUST be disabled here at the same time */
|
||||
LL_AHB2_GRP1_DisableClockStopSleep(LL_AHB2_GRP1_PERIPH_OTG_HS |
|
||||
LL_AHB2_GRP1_PERIPH_USBPHY);
|
||||
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_otghs)
|
||||
/* Reset specific configuration bits before setting new values */
|
||||
USB1_HS_PHYC->USBPHYC_CR &= ~USB_USBPHYC_CR_FSEL_Msk;
|
||||
|
||||
@@ -5,6 +5,7 @@ config UDC_MAX32
|
||||
bool "MAX32 USB device controller driver"
|
||||
default y
|
||||
depends on DT_HAS_ADI_MAX32_USBHS_ENABLED
|
||||
select UDC_DRIVER_HAS_HIGH_SPEED_SUPPORT
|
||||
help
|
||||
MAX32 USB device controller driver.
|
||||
|
||||
|
||||
@@ -1143,9 +1143,6 @@ static int priv_clock_enable(void)
|
||||
LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI);
|
||||
#elif defined(CONFIG_SOC_SERIES_STM32U5X)
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_USBPHY);
|
||||
/* Both OTG HS and USBPHY sleep clock MUST be disabled here at the same time */
|
||||
LL_AHB2_GRP1_DisableClockStopSleep(LL_AHB2_GRP1_PERIPH_OTG_HS |
|
||||
LL_AHB2_GRP1_PERIPH_USBPHY);
|
||||
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_otghs)
|
||||
/* Reset specific configuration bits before setting new values */
|
||||
USB1_HS_PHYC->USBPHYC_CR &= ~USB_USBPHYC_CR_FSEL_Msk;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
i2c3: i2c@4007800 {
|
||||
i2c3: i2c@40007800 {
|
||||
compatible = "st,stm32-i2c-v2";
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
reg = <0x40008000 0x400>;
|
||||
clocks = <&rcc STM32_CLOCK(APB1, 20U)>;
|
||||
resets = <&rctl STM32_RESET(APB1L, 20U)>;
|
||||
interrupts = <28 0>;
|
||||
interrupts = <29 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
reg = <0x40008400 0x400>;
|
||||
clocks = <&rcc STM32_CLOCK(APB1, 7U)>;
|
||||
resets = <&rctl STM32_RESET(APB1L, 7U)>;
|
||||
interrupts = <29 0>;
|
||||
interrupts = <28 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -881,8 +881,7 @@
|
||||
|
||||
wkup-pin@8 {
|
||||
reg = <0x8>;
|
||||
wkup-gpios = <&gpiof 2 STM32_PWR_WKUP_EVT_SRC_0>,
|
||||
<&gpioa 7 STM32_PWR_WKUP_EVT_SRC_1>,
|
||||
wkup-gpios = <&gpioa 7 STM32_PWR_WKUP_EVT_SRC_1>,
|
||||
<&gpiob 10 STM32_PWR_WKUP_EVT_SRC_2>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -77,3 +77,11 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pwr {
|
||||
wkup-pin@8 {
|
||||
wkup-gpios = <&gpiof 2 STM32_PWR_WKUP_EVT_SRC_0>,
|
||||
<&gpioa 7 STM32_PWR_WKUP_EVT_SRC_1>,
|
||||
<&gpiob 10 STM32_PWR_WKUP_EVT_SRC_2>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,6 +26,41 @@
|
||||
#define _EXC_RETURN_SPSEL_Msk (1 << 2)
|
||||
#define _EXC_RETURN_FTYPE_Msk (1 << 4)
|
||||
|
||||
/*
|
||||
* Cortex-M Exception Stack Frame Layouts
|
||||
*
|
||||
* When an exception is taken, the processor automatically pushes
|
||||
* registers to the current stack. The layout depends on whether
|
||||
* the FPU is active.
|
||||
*/
|
||||
|
||||
/* Basic hardware-saved exception stack frame (no FPU context):
|
||||
* R0-R3 (4 x 4B = 16B)
|
||||
* R12 (4B)
|
||||
* LR (4B)
|
||||
* Return address (4B)
|
||||
* RETPSR (4B)
|
||||
*--------------------------
|
||||
* Total: 32 bytes
|
||||
*/
|
||||
#define _EXC_HW_SAVED_BASIC_SF_SIZE (32)
|
||||
#define _EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET (24)
|
||||
#define _EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET (28)
|
||||
|
||||
/* Extended hardware saved stack frame consists of:
|
||||
* R0-R3 (16B)
|
||||
* R12 (4B)
|
||||
* LR (R14) (4B)
|
||||
* Return address (4B)
|
||||
* RETPSR (4B)
|
||||
* S0-S15 (16 x 4B = 64B)
|
||||
* FPSCR (4B)
|
||||
* Reserved (4B)
|
||||
*--------------------------
|
||||
* Total: 104 bytes
|
||||
*/
|
||||
#define _EXC_HW_SAVED_EXTENDED_SF_SIZE (104)
|
||||
|
||||
#else
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -237,14 +237,21 @@ extern char __sg_size[];
|
||||
* with a MPU. Start and end will be aligned for memory management/protection
|
||||
* hardware for the target architecture.
|
||||
*
|
||||
* All the functions with '__nocache' keyword will be placed into this
|
||||
* section.
|
||||
* All the variables with '__nocache' keyword will be placed into the nocache
|
||||
* section, variables with '__nocache_load' keyword will be placed into the
|
||||
* nocache section that is loaded from ROM.
|
||||
*/
|
||||
#ifdef CONFIG_NOCACHE_MEMORY
|
||||
extern char _nocache_ram_start[];
|
||||
extern char _nocache_ram_end[];
|
||||
extern char _nocache_ram_size[];
|
||||
extern char _nocache_load_start[];
|
||||
extern char _nocache_noload_ram_start[];
|
||||
extern char _nocache_noload_ram_end[];
|
||||
extern char _nocache_noload_ram_size[];
|
||||
extern char _nocache_load_ram_start[];
|
||||
extern char _nocache_load_ram_end[];
|
||||
extern char _nocache_load_ram_size[];
|
||||
extern char _nocache_load_rom_start[];
|
||||
#endif /* CONFIG_NOCACHE_MEMORY */
|
||||
|
||||
/* Memory owned by the kernel. Start and end will be aligned for memory
|
||||
|
||||
@@ -53,9 +53,11 @@
|
||||
|
||||
#if defined(CONFIG_NOCACHE_MEMORY)
|
||||
#define __nocache __in_section_unique(_NOCACHE_SECTION_NAME)
|
||||
#define __nocache_load __in_section_unique(_NOCACHE_LOAD_SECTION_NAME)
|
||||
#define __nocache_noinit __nocache
|
||||
#else
|
||||
#define __nocache
|
||||
#define __nocache_load
|
||||
#define __nocache_noinit __noinit
|
||||
#endif /* CONFIG_NOCACHE_MEMORY */
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
|
||||
#ifdef CONFIG_NOCACHE_MEMORY
|
||||
#define _NOCACHE_SECTION_NAME nocache
|
||||
#define _NOCACHE_LOAD_SECTION_NAME nocache_load
|
||||
#endif
|
||||
|
||||
/* Symbol table section */
|
||||
|
||||
@@ -248,9 +248,8 @@ void z_bss_zero(void)
|
||||
((uintptr_t) &__gcov_bss_end - (uintptr_t) &__gcov_bss_start));
|
||||
#endif /* CONFIG_COVERAGE_GCOV */
|
||||
#ifdef CONFIG_NOCACHE_MEMORY
|
||||
z_early_memset(&_nocache_ram_start, 0,
|
||||
(uintptr_t) &_nocache_ram_end
|
||||
- (uintptr_t) &_nocache_ram_start);
|
||||
z_early_memset(&_nocache_ram_start, 0,
|
||||
(uintptr_t)&_nocache_ram_end - (uintptr_t)&_nocache_ram_start);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ void z_data_copy(void)
|
||||
#endif /* CONFIG_ARCH_HAS_RAMFUNC_SUPPORT */
|
||||
#ifdef CONFIG_ARCH_HAS_NOCACHE_MEMORY_SUPPORT
|
||||
#if CONFIG_NOCACHE_MEMORY
|
||||
z_early_memcpy(&_nocache_ram_start, &_nocache_load_start,
|
||||
(uintptr_t) &_nocache_ram_size);
|
||||
z_early_memcpy(&_nocache_load_ram_start, &_nocache_load_rom_start,
|
||||
(uintptr_t) &_nocache_load_ram_size);
|
||||
#endif /* CONFIG_NOCACHE_MEMORY */
|
||||
#endif /* CONFIG_ARCH_HAS_NOCACHE_MEMORY_SUPPORT */
|
||||
#if DT_NODE_HAS_STATUS_OKAY(DT_CHOSEN(zephyr_ccm))
|
||||
|
||||
@@ -130,7 +130,7 @@ zephyr_interface_library_named(mbedTLS)
|
||||
# if address sanitizer is enabled, as such switch default optimization level
|
||||
# to speed
|
||||
set_property(SOURCE ${ZEPHYR_CURRENT_MODULE_DIR}/mbedtls/library/bignum.c APPEND PROPERTY COMPILE_OPTIONS
|
||||
"${OPTIMIZE_FOR_SPEED_FLAG}")
|
||||
"${COMPILER_OPTIMIZE_FOR_SPEED_FLAG}")
|
||||
endif ()
|
||||
|
||||
zephyr_library_link_libraries(mbedTLS)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_LV_COLOR_DEPTH_32=y
|
||||
CONFIG_LV_Z_MEM_POOL_SIZE=75264
|
||||
CONFIG_LV_Z_MEM_POOL_SIZE=81920
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CONFIG_MAIN_STACK_SIZE=4096
|
||||
CONFIG_MAIN_STACK_SIZE=6144
|
||||
CONFIG_LOG=y
|
||||
CONFIG_SHELL=y
|
||||
|
||||
|
||||
@@ -518,7 +518,11 @@ def try_making_symlink(source: str, link: str):
|
||||
source (str): The path to the source file.
|
||||
link (str): The path where the symbolic link should be created.
|
||||
"""
|
||||
if os.path.exists(link):
|
||||
symlink_error = None
|
||||
|
||||
try:
|
||||
os.symlink(source, link)
|
||||
except FileExistsError:
|
||||
if os.path.islink(link):
|
||||
if os.readlink(link) == source:
|
||||
# Link is already set up
|
||||
@@ -529,19 +533,24 @@ def try_making_symlink(source: str, link: str):
|
||||
# File contents are the same
|
||||
return
|
||||
|
||||
# link exists, but points to a different file, remove the link. We'll
|
||||
# try to create a new one below
|
||||
os.remove(link)
|
||||
|
||||
# Create the symlink
|
||||
try:
|
||||
os.symlink(source, link)
|
||||
# link exists, but points to a different file. We'll create a new link
|
||||
# and replace it atomically with the old one
|
||||
temp_filename = f"{link}.{os.urandom(8).hex()}"
|
||||
try:
|
||||
os.symlink(source, temp_filename)
|
||||
os.replace(temp_filename, link)
|
||||
except OSError as e:
|
||||
symlink_error = e
|
||||
except OSError as e:
|
||||
logger.error(
|
||||
"Error creating symlink: %s, attempting to copy.", str(e)
|
||||
)
|
||||
shutil.copy(source, link)
|
||||
symlink_error = e
|
||||
|
||||
if symlink_error:
|
||||
logger.error(
|
||||
"Error creating symlink: %s, attempting to copy.", str(symlink_error)
|
||||
)
|
||||
temp_filename = f"{link}.{os.urandom(8).hex()}"
|
||||
shutil.copy(source, temp_filename)
|
||||
os.replace(temp_filename, link)
|
||||
|
||||
def choose_gcov_tool(options, is_system_gcov):
|
||||
gcov_tool = None
|
||||
|
||||
@@ -221,10 +221,10 @@ add_subdirectory_ifdef(
|
||||
|
||||
zephyr_library_compile_options_ifdef(
|
||||
CONFIG_BT_CTLR_OPTIMIZE_FOR_SIZE
|
||||
${OPTIMIZE_FOR_SIZE_FLAG}
|
||||
${COMPILER_OPTIMIZE_FOR_SIZE_FLAG}
|
||||
)
|
||||
|
||||
zephyr_library_compile_options_ifdef(
|
||||
CONFIG_BT_CTLR_OPTIMIZE_FOR_SPEED
|
||||
${OPTIMIZE_FOR_SPEED_FLAG}
|
||||
${COMPILER_OPTIMIZE_FOR_SPEED_FLAG}
|
||||
)
|
||||
|
||||
@@ -122,5 +122,5 @@ zephyr_include_directories(
|
||||
|
||||
zephyr_library_compile_options_ifdef(
|
||||
CONFIG_BT_CTLR_OPTIMIZE_FOR_SPEED
|
||||
${OPTIMIZE_FOR_SPEED_FLAG}
|
||||
${COMPILER_OPTIMIZE_FOR_SPEED_FLAG}
|
||||
)
|
||||
|
||||
@@ -55,5 +55,5 @@ zephyr_library_include_directories(
|
||||
|
||||
zephyr_library_compile_options_ifdef(
|
||||
CONFIG_BT_CTLR_OPTIMIZE_FOR_SPEED
|
||||
${OPTIMIZE_FOR_SPEED_FLAG}
|
||||
${COMPILER_OPTIMIZE_FOR_SPEED_FLAG}
|
||||
)
|
||||
|
||||
@@ -1529,7 +1529,7 @@ void bt_le_adv_resume(void)
|
||||
int err;
|
||||
|
||||
if (!adv) {
|
||||
LOG_ERR("No valid legacy adv to resume");
|
||||
LOG_DBG("No valid legacy adv to resume");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -598,12 +598,11 @@ static int ext2_stat(struct fs_mount_t *mountp, const char *path, struct fs_dire
|
||||
}
|
||||
|
||||
uint32_t offset = args.offset;
|
||||
struct ext2_inode *parent = args.parent;
|
||||
struct ext2_file dir = {.f_inode = parent, .f_off = offset};
|
||||
struct ext2_file dir = {.f_inode = args.parent ? args.parent : args.inode, .f_off = offset};
|
||||
|
||||
rc = ext2_get_direntry(&dir, entry);
|
||||
|
||||
ext2_inode_drop(parent);
|
||||
ext2_inode_drop(args.parent);
|
||||
ext2_inode_drop(args.inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -634,6 +634,13 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto,
|
||||
k_sem_give(&contexts_lock);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == -EADDRINUSE &&
|
||||
!net_if_is_ip_offloaded(net_if_get_default()) &&
|
||||
proto == IPPROTO_TCP) {
|
||||
/* Free the TCP context that we allocated earlier */
|
||||
net_tcp_put(&contexts[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -2354,6 +2354,19 @@ int net_pkt_set_data(struct net_pkt *pkt,
|
||||
return net_pkt_write(pkt, access->data, access->size);
|
||||
}
|
||||
|
||||
void net_pkt_tx_init(struct net_pkt *pkt)
|
||||
{
|
||||
memset(pkt, 0, sizeof(struct net_pkt));
|
||||
|
||||
pkt->atomic_ref = ATOMIC_INIT(1);
|
||||
pkt->slab = &tx_pkts;
|
||||
|
||||
net_pkt_set_ipv6_next_hdr(pkt, 255);
|
||||
net_pkt_set_priority(pkt, TX_DEFAULT_PRIORITY);
|
||||
net_pkt_set_vlan_tag(pkt, NET_VLAN_TAG_UNSPEC);
|
||||
net_pkt_cursor_init(pkt);
|
||||
}
|
||||
|
||||
void net_pkt_init(void)
|
||||
{
|
||||
#if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
|
||||
@@ -414,3 +414,10 @@ static inline void net_pkt_print_buffer_info(struct net_pkt *pkt, const char *st
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize externally allocated TX packet.
|
||||
*
|
||||
* @param pkt The network packet to initialize.
|
||||
*/
|
||||
void net_pkt_tx_init(struct net_pkt *pkt);
|
||||
|
||||
@@ -794,10 +794,15 @@ static void tcp_conn_release(struct k_work *work)
|
||||
tcp_send_queue_flush(conn);
|
||||
|
||||
(void)k_work_cancel_delayable(&conn->send_data_timer);
|
||||
tcp_pkt_unref(conn->send_data);
|
||||
if (conn->send_data.frags != NULL) {
|
||||
net_pkt_frag_unref(conn->send_data.frags);
|
||||
}
|
||||
|
||||
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT) {
|
||||
tcp_pkt_unref(conn->queue_recv_data);
|
||||
if (conn->queue_recv_data != NULL) {
|
||||
net_buf_unref(conn->queue_recv_data);
|
||||
conn->queue_recv_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
(void)k_work_cancel_delayable(&conn->timewait_timer);
|
||||
@@ -1136,8 +1141,7 @@ static size_t tcp_check_pending_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
{
|
||||
size_t pending_len = 0;
|
||||
|
||||
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT &&
|
||||
!net_pkt_is_empty(conn->queue_recv_data)) {
|
||||
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT && conn->queue_recv_data != NULL) {
|
||||
/* Some potentential cases:
|
||||
* Note: MI = MAX_INT
|
||||
* Packet | Queued| End off | Gap size | Required handling
|
||||
@@ -1159,10 +1163,10 @@ static size_t tcp_check_pending_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
int32_t gap_size;
|
||||
uint32_t end_offset;
|
||||
|
||||
pending_seq = tcp_get_seq(conn->queue_recv_data->buffer);
|
||||
pending_seq = tcp_get_seq(conn->queue_recv_data);
|
||||
end_offset = expected_seq - pending_seq;
|
||||
gap_size = (int32_t)(pending_seq - th_seq(th) - ((uint32_t)len));
|
||||
pending_len = net_pkt_get_len(conn->queue_recv_data);
|
||||
pending_len = net_buf_frags_len(conn->queue_recv_data);
|
||||
if (end_offset < pending_len) {
|
||||
if (end_offset) {
|
||||
net_pkt_remove_tail(pkt, end_offset);
|
||||
@@ -1173,15 +1177,15 @@ static size_t tcp_check_pending_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
expected_seq, pending_len);
|
||||
|
||||
net_buf_frag_add(pkt->buffer,
|
||||
conn->queue_recv_data->buffer);
|
||||
conn->queue_recv_data->buffer = NULL;
|
||||
conn->queue_recv_data);
|
||||
conn->queue_recv_data = NULL;
|
||||
|
||||
k_work_cancel_delayable(&conn->recv_queue_timer);
|
||||
} else {
|
||||
/* Check if the queued data is just a section of the incoming data */
|
||||
if (gap_size <= 0) {
|
||||
net_buf_unref(conn->queue_recv_data->buffer);
|
||||
conn->queue_recv_data->buffer = NULL;
|
||||
net_buf_unref(conn->queue_recv_data);
|
||||
conn->queue_recv_data = NULL;
|
||||
|
||||
k_work_cancel_delayable(&conn->recv_queue_timer);
|
||||
}
|
||||
@@ -1684,7 +1688,7 @@ static int tcp_send_data(struct tcp *conn)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = tcp_pkt_peek(pkt, conn->send_data, conn->unacked_len, len);
|
||||
ret = tcp_pkt_peek(pkt, &conn->send_data, conn->unacked_len, len);
|
||||
if (ret < 0) {
|
||||
tcp_pkt_unref(pkt);
|
||||
ret = -ENOBUFS;
|
||||
@@ -1770,11 +1774,11 @@ static void tcp_cleanup_recv_queue(struct k_work *work)
|
||||
k_mutex_lock(&conn->lock, K_FOREVER);
|
||||
|
||||
NET_DBG("Cleanup recv queue conn %p len %zd seq %u", conn,
|
||||
net_pkt_get_len(conn->queue_recv_data),
|
||||
tcp_get_seq(conn->queue_recv_data->buffer));
|
||||
net_buf_frags_len(conn->queue_recv_data),
|
||||
tcp_get_seq(conn->queue_recv_data));
|
||||
|
||||
net_buf_unref(conn->queue_recv_data->buffer);
|
||||
conn->queue_recv_data->buffer = NULL;
|
||||
net_buf_unref(conn->queue_recv_data);
|
||||
conn->queue_recv_data = NULL;
|
||||
|
||||
k_mutex_unlock(&conn->lock);
|
||||
}
|
||||
@@ -2021,21 +2025,7 @@ static struct tcp *tcp_conn_alloc(void)
|
||||
}
|
||||
|
||||
memset(conn, 0, sizeof(*conn));
|
||||
|
||||
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT) {
|
||||
conn->queue_recv_data = tcp_rx_pkt_alloc(conn, 0);
|
||||
if (conn->queue_recv_data == NULL) {
|
||||
NET_ERR("Cannot allocate %s queue for conn %p", "recv",
|
||||
conn);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
conn->send_data = tcp_pkt_alloc(conn, 0);
|
||||
if (conn->send_data == NULL) {
|
||||
NET_ERR("Cannot allocate %s queue for conn %p", "send", conn);
|
||||
goto fail;
|
||||
}
|
||||
net_pkt_tx_init(&conn->send_data);
|
||||
|
||||
k_mutex_init(&conn->lock);
|
||||
k_fifo_init(&conn->recv_data);
|
||||
@@ -2087,15 +2077,6 @@ out:
|
||||
NET_DBG("conn: %p", conn);
|
||||
|
||||
return conn;
|
||||
|
||||
fail:
|
||||
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT && conn->queue_recv_data) {
|
||||
tcp_pkt_unref(conn->queue_recv_data);
|
||||
conn->queue_recv_data = NULL;
|
||||
}
|
||||
|
||||
k_mem_slab_free(&tcp_conns_slab, (void *)conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int net_tcp_get(struct net_context *context)
|
||||
@@ -2545,7 +2526,7 @@ static void tcp_queue_recv_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
NET_DBG("Queuing data: conn %p", conn);
|
||||
}
|
||||
|
||||
if (!net_pkt_is_empty(conn->queue_recv_data)) {
|
||||
if (conn->queue_recv_data != NULL) {
|
||||
/* Place the data to correct place in the list. If the data
|
||||
* would not be sequential, then drop this packet.
|
||||
*
|
||||
@@ -2575,9 +2556,9 @@ static void tcp_queue_recv_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
uint32_t end_offset;
|
||||
size_t pending_len;
|
||||
|
||||
pending_seq = tcp_get_seq(conn->queue_recv_data->buffer);
|
||||
pending_seq = tcp_get_seq(conn->queue_recv_data);
|
||||
end_offset = seq - pending_seq;
|
||||
pending_len = net_pkt_get_len(conn->queue_recv_data);
|
||||
pending_len = net_buf_frags_len(conn->queue_recv_data);
|
||||
if (end_offset < pending_len) {
|
||||
if (end_offset < len) {
|
||||
if (end_offset) {
|
||||
@@ -2586,16 +2567,16 @@ static void tcp_queue_recv_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
|
||||
/* Put new data before the pending data */
|
||||
net_buf_frag_add(pkt->buffer,
|
||||
conn->queue_recv_data->buffer);
|
||||
conn->queue_recv_data);
|
||||
NET_DBG("Adding at before queue, end_offset %i, pending_len %zu",
|
||||
end_offset, pending_len);
|
||||
conn->queue_recv_data->buffer = pkt->buffer;
|
||||
conn->queue_recv_data = pkt->buffer;
|
||||
inserted = true;
|
||||
}
|
||||
} else {
|
||||
struct net_buf *last;
|
||||
|
||||
last = net_buf_frag_last(conn->queue_recv_data->buffer);
|
||||
last = net_buf_frag_last(conn->queue_recv_data);
|
||||
pending_seq = tcp_get_seq(last);
|
||||
|
||||
start_offset = pending_seq - seq_start;
|
||||
@@ -2607,20 +2588,20 @@ static void tcp_queue_recv_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
/* The queued data is irrelevant since the new packet overlaps the
|
||||
* new packet, take the new packet as contents
|
||||
*/
|
||||
net_buf_unref(conn->queue_recv_data->buffer);
|
||||
conn->queue_recv_data->buffer = pkt->buffer;
|
||||
net_buf_unref(conn->queue_recv_data);
|
||||
conn->queue_recv_data = pkt->buffer;
|
||||
inserted = true;
|
||||
} else {
|
||||
if (end_offset < len) {
|
||||
if (end_offset) {
|
||||
net_pkt_remove_tail(conn->queue_recv_data,
|
||||
end_offset);
|
||||
net_buf_remove_mem(conn->queue_recv_data,
|
||||
end_offset);
|
||||
}
|
||||
|
||||
/* Put new data after pending data */
|
||||
NET_DBG("Adding at end of queue, start %i, end %i, len %zu",
|
||||
start_offset, end_offset, len);
|
||||
net_buf_frag_add(conn->queue_recv_data->buffer,
|
||||
net_buf_frag_add(conn->queue_recv_data,
|
||||
pkt->buffer);
|
||||
inserted = true;
|
||||
}
|
||||
@@ -2629,18 +2610,18 @@ static void tcp_queue_recv_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
|
||||
if (inserted) {
|
||||
NET_DBG("All pending data: conn %p", conn);
|
||||
if (check_seq_list(conn->queue_recv_data->buffer) == false) {
|
||||
if (check_seq_list(conn->queue_recv_data) == false) {
|
||||
NET_ERR("Incorrect order in out of order sequence for conn %p",
|
||||
conn);
|
||||
/* error in sequence list, drop it */
|
||||
net_buf_unref(conn->queue_recv_data->buffer);
|
||||
conn->queue_recv_data->buffer = NULL;
|
||||
net_buf_unref(conn->queue_recv_data);
|
||||
conn->queue_recv_data = NULL;
|
||||
}
|
||||
} else {
|
||||
NET_DBG("Cannot add new data to queue");
|
||||
}
|
||||
} else {
|
||||
net_pkt_append_buffer(conn->queue_recv_data, pkt->buffer);
|
||||
conn->queue_recv_data = pkt->buffer;
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
@@ -2657,7 +2638,7 @@ static void tcp_queue_recv_data(struct tcp *conn, struct net_pkt *pkt,
|
||||
}
|
||||
|
||||
static enum net_verdict tcp_data_received(struct tcp *conn, struct net_pkt *pkt,
|
||||
size_t *len, bool psh)
|
||||
size_t *len, bool psh, bool fin)
|
||||
{
|
||||
enum net_verdict ret;
|
||||
|
||||
@@ -2670,6 +2651,13 @@ static enum net_verdict tcp_data_received(struct tcp *conn, struct net_pkt *pkt,
|
||||
net_stats_update_tcp_seg_recv(conn->iface);
|
||||
conn_ack(conn, *len);
|
||||
|
||||
/* In case FIN was received, don't send ACK just yet, FIN,ACK will be
|
||||
* sent instead.
|
||||
*/
|
||||
if (fin) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delay ACK response in case of small window or missing PSH,
|
||||
* as described in RFC 813.
|
||||
*/
|
||||
@@ -2805,7 +2793,9 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||
/* send ACK for non-RST packet */
|
||||
if (FL(&fl, &, RST)) {
|
||||
net_stats_update_tcp_seg_rsterr(net_pkt_iface(pkt));
|
||||
} else if ((len > 0) || FL(&fl, &, FIN)) {
|
||||
} else if ((len > 0) || FL(&fl, &, FIN) ||
|
||||
/* Keep-alive probe */
|
||||
((len == 0) && FL(&fl, &, ACK))) {
|
||||
tcp_out(conn, ACK);
|
||||
}
|
||||
k_mutex_unlock(&conn->lock);
|
||||
@@ -3078,37 +3068,8 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||
}
|
||||
|
||||
break;
|
||||
case TCP_ESTABLISHED:
|
||||
/* full-close */
|
||||
if (FL(&fl, &, FIN, th_seq(th) == conn->ack)) {
|
||||
if (len) {
|
||||
verdict = tcp_data_get(conn, pkt, &len);
|
||||
if (verdict == NET_OK) {
|
||||
/* net_pkt owned by the recv fifo now */
|
||||
pkt = NULL;
|
||||
}
|
||||
} else {
|
||||
verdict = NET_OK;
|
||||
}
|
||||
|
||||
conn_ack(conn, + len + 1);
|
||||
keep_alive_timer_stop(conn);
|
||||
|
||||
if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) {
|
||||
uint32_t len_acked = th_ack(th) - conn->seq;
|
||||
|
||||
conn_seq(conn, + len_acked);
|
||||
}
|
||||
|
||||
tcp_out(conn, FIN | ACK);
|
||||
conn_seq(conn, + 1);
|
||||
tcp_setup_retransmission(conn);
|
||||
|
||||
tcp_setup_last_ack_timer(conn);
|
||||
next = TCP_LAST_ACK;
|
||||
|
||||
break;
|
||||
}
|
||||
case TCP_ESTABLISHED: {
|
||||
bool fin = FL(&fl, &, FIN, th_seq(th) == conn->ack);
|
||||
|
||||
/* Whatever we've received, we know that peer is alive, so reset
|
||||
* the keepalive timer.
|
||||
@@ -3163,7 +3124,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||
NET_DBG("conn: %p len_acked=%u", conn, len_acked);
|
||||
|
||||
if ((conn->send_data_total < len_acked) ||
|
||||
(tcp_pkt_pull(conn->send_data,
|
||||
(tcp_pkt_pull(&conn->send_data,
|
||||
len_acked) < 0)) {
|
||||
NET_ERR("conn: %p, Invalid len_acked=%u "
|
||||
"(total=%zu)", conn, len_acked,
|
||||
@@ -3214,11 +3175,21 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||
|
||||
/* We are closing the connection, send a FIN to peer */
|
||||
if (conn->in_close && conn->send_data_total == 0) {
|
||||
next = TCP_FIN_WAIT_1;
|
||||
|
||||
k_work_reschedule_for_queue(&tcp_work_q,
|
||||
&conn->fin_timer,
|
||||
FIN_TIMEOUT);
|
||||
if (fin) {
|
||||
/* If FIN was also present in the processed
|
||||
* packet, acknowledge that and jump directly
|
||||
* to TCP_LAST_ACK.
|
||||
*/
|
||||
conn_ack(conn, + 1);
|
||||
next = TCP_LAST_ACK;
|
||||
tcp_setup_last_ack_timer(conn);
|
||||
} else {
|
||||
/* Otherwise, wait for FIN in TCP_FIN_WAIT_1 */
|
||||
next = TCP_FIN_WAIT_1;
|
||||
k_work_reschedule_for_queue(&tcp_work_q,
|
||||
&conn->fin_timer,
|
||||
FIN_TIMEOUT);
|
||||
}
|
||||
|
||||
tcp_out(conn, FIN | ACK);
|
||||
conn_seq(conn, + 1);
|
||||
@@ -3246,7 +3217,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||
if (len > 0) {
|
||||
bool psh = FL(&fl, &, PSH);
|
||||
|
||||
verdict = tcp_data_received(conn, pkt, &len, psh);
|
||||
verdict = tcp_data_received(conn, pkt, &len, psh, fin);
|
||||
if (verdict == NET_OK) {
|
||||
/* net_pkt owned by the recv fifo now */
|
||||
pkt = NULL;
|
||||
@@ -3289,7 +3260,19 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||
k_sem_give(&conn->tx_sem);
|
||||
}
|
||||
|
||||
/* Finally, after all Data/ACK processing, check for FIN flag. */
|
||||
if (fin) {
|
||||
keep_alive_timer_stop(conn);
|
||||
conn_ack(conn, + 1);
|
||||
tcp_out(conn, FIN | ACK);
|
||||
conn_seq(conn, + 1);
|
||||
tcp_setup_retransmission(conn);
|
||||
tcp_setup_last_ack_timer(conn);
|
||||
next = TCP_LAST_ACK;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TCP_CLOSE_WAIT:
|
||||
/* Half-close is not supported, so do nothing here */
|
||||
break;
|
||||
@@ -3652,7 +3635,7 @@ int net_tcp_queue(struct net_context *context, const void *data, size_t len,
|
||||
for (int i = 0; i < msg->msg_iovlen; i++) {
|
||||
int iovlen = MIN(msg->msg_iov[i].iov_len, len);
|
||||
|
||||
ret = tcp_pkt_append(conn->send_data,
|
||||
ret = tcp_pkt_append(&conn->send_data,
|
||||
msg->msg_iov[i].iov_base,
|
||||
iovlen);
|
||||
if (ret < 0) {
|
||||
@@ -3671,7 +3654,7 @@ int net_tcp_queue(struct net_context *context, const void *data, size_t len,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = tcp_pkt_append(conn->send_data, data, len);
|
||||
ret = tcp_pkt_append(&conn->send_data, data, len);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
({ \
|
||||
NET_DBG("conn: %p total=%zd, unacked_len=%d, " \
|
||||
"send_win=%hu, mss=%hu", \
|
||||
(_conn), net_pkt_get_len((_conn)->send_data), \
|
||||
(_conn), net_pkt_get_len(&(_conn)->send_data), \
|
||||
_conn->unacked_len, _conn->send_win, \
|
||||
(uint16_t)conn_mss((_conn))); \
|
||||
NET_DBG("conn: %p send_data_timer=%hu, send_data_retries=%hu", \
|
||||
@@ -258,8 +258,8 @@ typedef void (*net_tcp_closed_cb_t)(struct tcp *conn, void *user_data);
|
||||
struct tcp { /* TCP connection */
|
||||
sys_snode_t next;
|
||||
struct net_context *context;
|
||||
struct net_pkt *send_data;
|
||||
struct net_pkt *queue_recv_data;
|
||||
struct net_pkt send_data;
|
||||
struct net_buf *queue_recv_data;
|
||||
struct net_if *iface;
|
||||
void *recv_user_data;
|
||||
sys_slist_t send_queue;
|
||||
|
||||
@@ -2106,6 +2106,8 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname,
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPV6_MULTICAST_HOPS:
|
||||
ret = net_context_get_option(ctx,
|
||||
NET_OPT_MCAST_HOP_LIMIT,
|
||||
|
||||
8
tests/arch/arm/arm_user_stack_test/CMakeLists.txt
Normal file
8
tests/arch/arm/arm_user_stack_test/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(arm_user_stack_test)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_ARM_MPU=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_ARM_MPU=y
|
||||
1
tests/arch/arm/arm_user_stack_test/prj.conf
Normal file
1
tests/arch/arm/arm_user_stack_test/prj.conf
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_ZTEST=y
|
||||
104
tests/arch/arm/arm_user_stack_test/src/main.c
Normal file
104
tests/arch/arm/arm_user_stack_test/src/main.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright The Zephyr Project Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FPU_SHARING
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include <zephyr/ztest.h>
|
||||
#include <zephyr/ztest_error_hook.h>
|
||||
#include <zephyr/syscall_list.h>
|
||||
|
||||
struct k_thread th0, th1;
|
||||
K_THREAD_STACK_DEFINE(stk0, 2048);
|
||||
K_THREAD_STACK_DEFINE(stk1, 2048);
|
||||
|
||||
ZTEST_BMEM int attack_stack[128];
|
||||
ZTEST_BMEM uint64_t sys_ret; /* 64 syscalls take result address in r0 */
|
||||
|
||||
volatile int kernel_secret;
|
||||
volatile int *const attack_sp = &attack_stack[128];
|
||||
const int sysno = K_SYSCALL_K_UPTIME_TICKS;
|
||||
k_tid_t low_tid, hi_tid;
|
||||
|
||||
void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
|
||||
{
|
||||
ztest_test_pass();
|
||||
k_thread_abort(low_tid);
|
||||
|
||||
/* This check is to handle a case where low prio thread has started and
|
||||
* resulted in a fault while changing the sp but
|
||||
* the high prio thread is not created yet
|
||||
*/
|
||||
if (hi_tid) {
|
||||
k_thread_abort(hi_tid);
|
||||
}
|
||||
}
|
||||
|
||||
void attack_entry(void)
|
||||
{
|
||||
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
|
||||
/* kernel_secret can only be updated in privilege mode so updating it here should result in
|
||||
* a fault. If it doesn't we fail the test.
|
||||
*/
|
||||
kernel_secret = 1;
|
||||
|
||||
printf("Changed the kernel_secret so marking test as failed\n");
|
||||
ztest_test_fail();
|
||||
|
||||
k_thread_abort(low_tid);
|
||||
k_thread_abort(hi_tid);
|
||||
}
|
||||
|
||||
void low_fn(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
#ifdef CONFIG_FPU_SHARING
|
||||
double x = 1.2345;
|
||||
double y = 6.789;
|
||||
|
||||
/* some random fp stuff so that an extended stack frame is saved on svc */
|
||||
zassert_equal(x, 1.2345);
|
||||
zassert_equal(y, 6.789);
|
||||
#endif
|
||||
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
|
||||
attack_stack[0] = 1;
|
||||
__asm__ volatile("mov sp, %0;"
|
||||
"1:;"
|
||||
"ldr r0, =sys_ret;"
|
||||
"ldr r6, =sysno;"
|
||||
"ldr r6, [r6];"
|
||||
"svc 3;"
|
||||
"b 1b;" ::"r"(attack_sp));
|
||||
}
|
||||
|
||||
void hi_fn(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
|
||||
while (1) {
|
||||
attack_sp[-2] = (int)attack_entry;
|
||||
k_msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
ZTEST(arm_user_stack_test, test_arm_user_stack_corruption)
|
||||
{
|
||||
low_tid = k_thread_create(&th0, stk0, K_THREAD_STACK_SIZEOF(stk0), low_fn, NULL, NULL, NULL,
|
||||
2,
|
||||
#ifdef CONFIG_FPU_SHARING
|
||||
K_INHERIT_PERMS | K_USER | K_FP_REGS,
|
||||
#else
|
||||
K_INHERIT_PERMS | K_USER,
|
||||
#endif
|
||||
K_NO_WAIT);
|
||||
|
||||
k_msleep(6); /* let low_fn start looping */
|
||||
hi_tid = k_thread_create(&th1, stk1, K_THREAD_STACK_SIZEOF(stk1), hi_fn, NULL, NULL, NULL,
|
||||
1, K_INHERIT_PERMS | K_USER, K_NO_WAIT);
|
||||
|
||||
k_thread_join(&th0, K_FOREVER);
|
||||
k_thread_join(&th1, K_FOREVER);
|
||||
}
|
||||
|
||||
ZTEST_SUITE(arm_user_stack_test, NULL, NULL, NULL, NULL, NULL);
|
||||
14
tests/arch/arm/arm_user_stack_test/testcase.yaml
Normal file
14
tests/arch/arm/arm_user_stack_test/testcase.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
common:
|
||||
tags:
|
||||
- arm
|
||||
tests:
|
||||
arch.arm.user.stack:
|
||||
filter: CONFIG_CPU_CORTEX_M
|
||||
extra_configs:
|
||||
- CONFIG_USERSPACE=y
|
||||
arch.arm.user.stack.float:
|
||||
filter: CONFIG_CPU_CORTEX_M and CONFIG_CPU_HAS_FPU
|
||||
extra_configs:
|
||||
- CONFIG_USERSPACE=y
|
||||
- CONFIG_FPU=y
|
||||
- CONFIG_FPU_SHARING=y
|
||||
@@ -11,7 +11,7 @@
|
||||
slow@0 {
|
||||
compatible = "test-spi-loopback-slow";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <128000>;
|
||||
spi-max-frequency = <150000>;
|
||||
};
|
||||
fast@0 {
|
||||
compatible = "test-spi-loopback-fast";
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
slow@0 {
|
||||
compatible = "test-spi-loopback-slow";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <128000>;
|
||||
spi-max-frequency = <125000>;
|
||||
};
|
||||
fast@0 {
|
||||
compatible = "test-spi-loopback-fast";
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
slow@0 {
|
||||
compatible = "test-spi-loopback-slow";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <128000>;
|
||||
spi-max-frequency = <125000>;
|
||||
};
|
||||
fast@0 {
|
||||
compatible = "test-spi-loopback-fast";
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
slow@0 {
|
||||
compatible = "test-spi-loopback-slow";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <128000>;
|
||||
spi-max-frequency = <125000>;
|
||||
};
|
||||
fast@0 {
|
||||
compatible = "test-spi-loopback-fast";
|
||||
|
||||
@@ -2349,7 +2349,7 @@ ZTEST(net_socket_tcp, test_connect_and_wait_for_v4_poll)
|
||||
zassert_equal(ret, 0, "close failed, %d", errno);
|
||||
}
|
||||
|
||||
ZTEST(net_socket_tcp, test_so_keepalive)
|
||||
ZTEST(net_socket_tcp, test_so_keepalive_opt)
|
||||
{
|
||||
struct sockaddr_in bind_addr4;
|
||||
int sock, ret;
|
||||
@@ -2430,55 +2430,92 @@ ZTEST(net_socket_tcp, test_so_keepalive)
|
||||
test_context_cleanup();
|
||||
}
|
||||
|
||||
ZTEST(net_socket_tcp, test_keepalive_timeout)
|
||||
static void test_prepare_keepalive_socks(int *c_sock, int *s_sock, int *new_sock)
|
||||
{
|
||||
struct sockaddr_in c_saddr, s_saddr;
|
||||
int c_sock, s_sock, new_sock;
|
||||
uint8_t rx_buf;
|
||||
int optval;
|
||||
int ret;
|
||||
|
||||
prepare_sock_tcp_v4(MY_IPV4_ADDR, ANY_PORT, &c_sock, &c_saddr);
|
||||
prepare_sock_tcp_v4(MY_IPV4_ADDR, SERVER_PORT, &s_sock, &s_saddr);
|
||||
prepare_sock_tcp_v4(MY_IPV4_ADDR, ANY_PORT, c_sock, &c_saddr);
|
||||
prepare_sock_tcp_v4(MY_IPV4_ADDR, SERVER_PORT, s_sock, &s_saddr);
|
||||
|
||||
/* Enable keep-alive on both ends and set timeouts/retries to minimum */
|
||||
optval = 1;
|
||||
ret = zsock_setsockopt(c_sock, SOL_SOCKET, SO_KEEPALIVE,
|
||||
ret = zsock_setsockopt(*c_sock, SOL_SOCKET, SO_KEEPALIVE,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
ret = zsock_setsockopt(s_sock, SOL_SOCKET, SO_KEEPALIVE,
|
||||
ret = zsock_setsockopt(*s_sock, SOL_SOCKET, SO_KEEPALIVE,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
|
||||
optval = 1;
|
||||
ret = zsock_setsockopt(c_sock, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
ret = zsock_setsockopt(*c_sock, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
ret = zsock_setsockopt(s_sock, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
ret = zsock_setsockopt(*s_sock, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
|
||||
optval = 1;
|
||||
ret = zsock_setsockopt(c_sock, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
ret = zsock_setsockopt(*c_sock, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
ret = zsock_setsockopt(s_sock, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
ret = zsock_setsockopt(*s_sock, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
|
||||
optval = 1;
|
||||
ret = zsock_setsockopt(c_sock, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
ret = zsock_setsockopt(*c_sock, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
ret = zsock_setsockopt(s_sock, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
ret = zsock_setsockopt(*s_sock, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
&optval, sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
|
||||
/* Establish connection */
|
||||
test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
|
||||
test_listen(s_sock);
|
||||
test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
|
||||
test_accept(s_sock, &new_sock, NULL, NULL);
|
||||
test_bind(*s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
|
||||
test_listen(*s_sock);
|
||||
test_connect(*c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
|
||||
test_accept(*s_sock, new_sock, NULL, NULL);
|
||||
}
|
||||
|
||||
ZTEST(net_socket_tcp, test_keepalive)
|
||||
{
|
||||
int c_sock, s_sock, new_sock;
|
||||
struct timeval optval = {
|
||||
.tv_sec = 2,
|
||||
.tv_usec = 500000,
|
||||
};
|
||||
uint8_t rx_buf;
|
||||
int ret;
|
||||
|
||||
test_prepare_keepalive_socks(&c_sock, &s_sock, &new_sock);
|
||||
|
||||
ret = zsock_setsockopt(c_sock, SOL_SOCKET, SO_RCVTIMEO, &optval,
|
||||
sizeof(optval));
|
||||
zassert_equal(ret, 0, "setsockopt failed (%d)", errno);
|
||||
|
||||
/* recv() should fail, but due to receive timeout (no data), not
|
||||
* connection timeout (keepalive).
|
||||
*/
|
||||
ret = zsock_recv(c_sock, &rx_buf, sizeof(rx_buf), 0);
|
||||
zassert_equal(ret, -1, "recv() should've failed");
|
||||
zassert_equal(errno, EAGAIN, "wrong errno value, %d", errno);
|
||||
|
||||
test_close(c_sock);
|
||||
test_close(new_sock);
|
||||
test_close(s_sock);
|
||||
|
||||
test_context_cleanup();
|
||||
}
|
||||
|
||||
ZTEST(net_socket_tcp, test_keepalive_timeout)
|
||||
{
|
||||
int c_sock, s_sock, new_sock;
|
||||
uint8_t rx_buf;
|
||||
int ret;
|
||||
|
||||
test_prepare_keepalive_socks(&c_sock, &s_sock, &new_sock);
|
||||
|
||||
/* Kill communication - expect that connection will be closed after
|
||||
* a timeout period.
|
||||
|
||||
@@ -116,6 +116,7 @@ static enum test_case_no {
|
||||
TEST_CLIENT_FIN_ACK_WITH_DATA = 18,
|
||||
TEST_CLIENT_SEQ_VALIDATION = 19,
|
||||
TEST_SERVER_ACK_VALIDATION = 20,
|
||||
TEST_SERVER_FIN_ACK_AFTER_DATA = 21,
|
||||
} test_case_no;
|
||||
|
||||
static enum test_state t_state;
|
||||
@@ -142,6 +143,7 @@ static void handle_syn_invalid_ack(sa_family_t af, struct tcphdr *th);
|
||||
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th);
|
||||
static void handle_client_seq_validation_test(sa_family_t af, struct tcphdr *th);
|
||||
static void handle_server_ack_validation_test(struct net_pkt *pkt);
|
||||
static void handle_server_fin_ack_after_data_test(sa_family_t af, struct tcphdr *th);
|
||||
|
||||
static void verify_flags(struct tcphdr *th, uint8_t flags,
|
||||
const char *fun, int line)
|
||||
@@ -494,6 +496,9 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
|
||||
case TEST_SERVER_ACK_VALIDATION:
|
||||
handle_server_ack_validation_test(pkt);
|
||||
break;
|
||||
case TEST_SERVER_FIN_ACK_AFTER_DATA:
|
||||
handle_server_fin_ack_after_data_test(net_pkt_family(pkt), &th);
|
||||
break;
|
||||
default:
|
||||
zassert_true(false, "Undefined test case");
|
||||
}
|
||||
@@ -3002,4 +3007,204 @@ ZTEST(net_tcp, test_server_ack_validation)
|
||||
net_context_put(accepted_ctx);
|
||||
}
|
||||
|
||||
#define TEST_FIN_ACK_AFTER_DATA_REQ "request"
|
||||
#define TEST_FIN_ACK_AFTER_DATA_RSP "test data response"
|
||||
|
||||
/* In this test we check that FIN,ACK packet acknowledging latest data is
|
||||
* handled correctly by the TCP stack.
|
||||
*/
|
||||
static void handle_server_fin_ack_after_data_test(sa_family_t af, struct tcphdr *th)
|
||||
{
|
||||
struct net_pkt *reply = NULL;
|
||||
|
||||
zassert_false(th == NULL && t_state != T_SYN,
|
||||
"NULL pkt only expected in T_SYN state");
|
||||
|
||||
switch (t_state) {
|
||||
case T_SYN:
|
||||
reply = prepare_syn_packet(af, htons(MY_PORT), htons(PEER_PORT));
|
||||
seq++;
|
||||
t_state = T_SYN_ACK;
|
||||
break;
|
||||
case T_SYN_ACK:
|
||||
test_verify_flags(th, SYN | ACK);
|
||||
zassert_equal(ntohl(th->th_ack), seq,
|
||||
"Unexpected ACK in T_SYN_ACK, got %d, expected %d",
|
||||
ntohl(th->th_ack), seq);
|
||||
device_initial_seq = ntohl(th->th_seq);
|
||||
ack = ntohl(th->th_seq) + 1U;
|
||||
t_state = T_DATA_ACK;
|
||||
|
||||
/* Dummy "request" packet */
|
||||
reply = prepare_data_packet(af, htons(MY_PORT), htons(PEER_PORT),
|
||||
TEST_FIN_ACK_AFTER_DATA_REQ,
|
||||
sizeof(TEST_FIN_ACK_AFTER_DATA_REQ) - 1);
|
||||
seq += sizeof(TEST_FIN_ACK_AFTER_DATA_REQ) - 1;
|
||||
break;
|
||||
case T_DATA_ACK:
|
||||
test_verify_flags(th, ACK);
|
||||
t_state = T_DATA;
|
||||
zassert_equal(ntohl(th->th_seq), ack,
|
||||
"Unexpected SEQ in T_DATA_ACK, got %d, expected %d",
|
||||
get_rel_seq(th), ack);
|
||||
zassert_equal(ntohl(th->th_ack), seq,
|
||||
"Unexpected ACK in T_DATA_ACK, got %d, expected %d",
|
||||
ntohl(th->th_ack), seq);
|
||||
break;
|
||||
case T_DATA:
|
||||
test_verify_flags(th, PSH | ACK);
|
||||
zassert_equal(ntohl(th->th_seq), ack,
|
||||
"Unexpected SEQ in T_DATA, got %d, expected %d",
|
||||
get_rel_seq(th), ack);
|
||||
zassert_equal(ntohl(th->th_ack), seq,
|
||||
"Unexpected ACK in T_DATA, got %d, expected %d",
|
||||
ntohl(th->th_ack), seq);
|
||||
ack += sizeof(TEST_FIN_ACK_AFTER_DATA_RSP) - 1;
|
||||
t_state = T_FIN_ACK;
|
||||
|
||||
reply = prepare_fin_ack_packet(af, htons(MY_PORT), htons(PEER_PORT));
|
||||
seq++;
|
||||
break;
|
||||
case T_FIN_ACK:
|
||||
test_verify_flags(th, FIN | ACK);
|
||||
zassert_equal(ntohl(th->th_seq), ack,
|
||||
"Unexpected SEQ in T_FIN_ACK, got %d, expected %d",
|
||||
get_rel_seq(th), ack);
|
||||
zassert_equal(ntohl(th->th_ack), seq,
|
||||
"Unexpected ACK in T_FIN_ACK, got %d, expected %d",
|
||||
ntohl(th->th_ack), seq);
|
||||
|
||||
ack++;
|
||||
t_state = T_CLOSING;
|
||||
|
||||
reply = prepare_ack_packet(af, htons(MY_PORT), htons(PEER_PORT));
|
||||
seq++;
|
||||
break;
|
||||
case T_CLOSING:
|
||||
zassert_true(false, "Should not receive anything after final ACK");
|
||||
break;
|
||||
default:
|
||||
zassert_true(false, "%s unexpected state", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply != NULL) {
|
||||
zassert_ok(net_recv_data(net_iface, reply), "%s failed", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive callback to be installed in the accept handler */
|
||||
static void test_fin_ack_after_data_recv_cb(struct net_context *context,
|
||||
struct net_pkt *pkt,
|
||||
union net_ip_header *ip_hdr,
|
||||
union net_proto_header *proto_hdr,
|
||||
int status,
|
||||
void *user_data)
|
||||
{
|
||||
zassert_ok(status, "failed to recv the data");
|
||||
|
||||
if (pkt != NULL) {
|
||||
uint8_t buf[sizeof(TEST_FIN_ACK_AFTER_DATA_REQ)] = { 0 };
|
||||
int data_len = net_pkt_remaining_data(pkt);
|
||||
|
||||
zassert_equal(data_len, sizeof(TEST_FIN_ACK_AFTER_DATA_REQ) - 1,
|
||||
"Invalid packet length, %d", data_len);
|
||||
zassert_ok(net_pkt_read(pkt, buf, data_len));
|
||||
zassert_mem_equal(buf, TEST_FIN_ACK_AFTER_DATA_REQ, data_len);
|
||||
|
||||
net_pkt_unref(pkt);
|
||||
}
|
||||
|
||||
test_sem_give();
|
||||
}
|
||||
|
||||
static void test_fin_ack_after_data_accept_cb(struct net_context *ctx,
|
||||
struct sockaddr *addr,
|
||||
socklen_t addrlen,
|
||||
int status,
|
||||
void *user_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
zassert_ok(status, "failed to accept the conn");
|
||||
|
||||
/* set callback on newly created context */
|
||||
accepted_ctx = ctx;
|
||||
ret = net_context_recv(ctx, test_fin_ack_after_data_recv_cb,
|
||||
K_NO_WAIT, NULL);
|
||||
zassert_ok(ret, "Failed to recv data from peer");
|
||||
|
||||
/* Ref the context on the app behalf. */
|
||||
net_context_ref(ctx);
|
||||
}
|
||||
|
||||
/* Verify that the TCP stack replies with a valid FIN,ACK after the peer
|
||||
* acknowledges the latest data in the FIN packet.
|
||||
* Test case scenario IPv4
|
||||
* send SYN,
|
||||
* expect SYN ACK,
|
||||
* send ACK with Data,
|
||||
* expect ACK,
|
||||
* expect Data,
|
||||
* send FIN,ACK
|
||||
* expect FIN,ACK
|
||||
* send ACK
|
||||
* any failures cause test case to fail.
|
||||
*/
|
||||
ZTEST(net_tcp, test_server_fin_ack_after_data)
|
||||
{
|
||||
struct net_context *ctx;
|
||||
int ret;
|
||||
|
||||
test_case_no = TEST_SERVER_FIN_ACK_AFTER_DATA;
|
||||
|
||||
t_state = T_SYN;
|
||||
seq = ack = 0;
|
||||
|
||||
ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx);
|
||||
zassert_ok(ret, "Failed to get net_context");
|
||||
|
||||
net_context_ref(ctx);
|
||||
|
||||
ret = net_context_bind(ctx, (struct sockaddr *)&my_addr_s,
|
||||
sizeof(struct sockaddr_in));
|
||||
zassert_ok(ret, "Failed to bind net_context");
|
||||
|
||||
/* Put context into listening mode and install accept cb */
|
||||
ret = net_context_listen(ctx, 1);
|
||||
zassert_ok(ret, "Failed to listen on net_context");
|
||||
|
||||
ret = net_context_accept(ctx, test_fin_ack_after_data_accept_cb,
|
||||
K_NO_WAIT, NULL);
|
||||
zassert_ok(ret, "Failed to set accept on net_context");
|
||||
|
||||
/* Trigger the peer to send SYN */
|
||||
handle_server_fin_ack_after_data_test(AF_INET, NULL);
|
||||
|
||||
/* test_fin_ack_after_data_recv_cb will release the semaphore after
|
||||
* dummy request is read.
|
||||
*/
|
||||
test_sem_take(K_MSEC(100), __LINE__);
|
||||
|
||||
/* Send dummy "response" */
|
||||
ret = net_context_send(accepted_ctx, TEST_FIN_ACK_AFTER_DATA_RSP,
|
||||
sizeof(TEST_FIN_ACK_AFTER_DATA_RSP) - 1, NULL,
|
||||
K_NO_WAIT, NULL);
|
||||
zassert_equal(ret, sizeof(TEST_FIN_ACK_AFTER_DATA_RSP) - 1,
|
||||
"Failed to send data to peer %d", ret);
|
||||
|
||||
/* test_fin_ack_after_data_recv_cb will release the semaphore after
|
||||
* the connection is marked closed.
|
||||
*/
|
||||
test_sem_take(K_MSEC(100), __LINE__);
|
||||
|
||||
net_context_put(ctx);
|
||||
net_context_put(accepted_ctx);
|
||||
|
||||
/* Connection is in TIME_WAIT state, context will be released
|
||||
* after K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY), so wait for it.
|
||||
*/
|
||||
k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY));
|
||||
}
|
||||
|
||||
ZTEST_SUITE(net_tcp, NULL, presetup, NULL, NULL, NULL);
|
||||
|
||||
@@ -4,7 +4,6 @@ CONFIG_LOG=y
|
||||
CONFIG_LLEXT=y
|
||||
CONFIG_LLEXT_HEAP_SIZE=64
|
||||
CONFIG_LLEXT_EXPORT_DEVICES=y
|
||||
CONFIG_LLEXT_LOG_LEVEL_DBG=y
|
||||
|
||||
CONFIG_APPLICATION_DEFINED_SYSCALL=y
|
||||
|
||||
|
||||
Reference in New Issue
Block a user