arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Linaro, Limited
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2022-05-06 16:49:15 +08:00
|
|
|
#include <zephyr/kernel.h>
|
2019-10-24 23:08:21 +08:00
|
|
|
#include <kernel_internal.h>
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
|
|
|
|
extern const int _k_neg_eagain;
|
|
|
|
|
2019-10-04 01:08:13 +08:00
|
|
|
/* The 'key' actually represents the BASEPRI register
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
* prior to disabling interrupts via the BASEPRI mechanism.
|
|
|
|
*
|
2019-11-08 04:43:29 +08:00
|
|
|
* arch_swap() itself does not do much.
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
*
|
|
|
|
* It simply stores the intlock key (the BASEPRI value) parameter into
|
|
|
|
* current->basepri, and then triggers a PendSV exception, which does
|
|
|
|
* the heavy lifting of context switching.
|
|
|
|
|
|
|
|
* This is the only place we have to save BASEPRI since the other paths to
|
2019-10-01 03:31:07 +08:00
|
|
|
* z_arm_pendsv all come from handling an interrupt, which means we know the
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
* interrupts were not locked: in that case the BASEPRI value is 0.
|
|
|
|
*
|
2019-11-08 04:43:29 +08:00
|
|
|
* Given that arch_swap() is called to effect a cooperative context switch,
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
* only the caller-saved integer registers need to be saved in the thread of the
|
|
|
|
* outgoing thread. This is all performed by the hardware, which stores it in
|
2019-10-01 03:31:07 +08:00
|
|
|
* its exception stack frame, created when handling the z_arm_pendsv exception.
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
*
|
|
|
|
* On ARMv6-M, the intlock key is represented by the PRIMASK register,
|
|
|
|
* as BASEPRI is not available.
|
|
|
|
*/
|
2019-11-08 04:43:29 +08:00
|
|
|
int arch_swap(unsigned int key)
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
{
|
|
|
|
/* store off key and return value */
|
|
|
|
_current->arch.basepri = key;
|
|
|
|
_current->arch.swap_return_value = _k_neg_eagain;
|
|
|
|
|
2018-06-25 21:15:14 +08:00
|
|
|
#if defined(CONFIG_CPU_CORTEX_M)
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
/* set pending bit to make sure we will take a PendSV exception */
|
|
|
|
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
|
|
|
|
|
|
|
|
/* clear mask or enable all irqs to take a pendsv */
|
|
|
|
irq_unlock(0);
|
2021-10-30 07:24:17 +08:00
|
|
|
#elif defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A)
|
2019-10-01 03:31:07 +08:00
|
|
|
z_arm_cortex_r_svc();
|
2018-06-25 21:15:14 +08:00
|
|
|
irq_unlock(key);
|
|
|
|
#endif
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
|
2019-03-06 21:42:32 +08:00
|
|
|
/* Context switch is performed here. Returning implies the
|
|
|
|
* thread has been context-switched-in again.
|
|
|
|
*/
|
arch: arm: Change method of __swap processing
This patch reworks the current ARM __swap() function into a C function.
Due to some issues with using svc calls withing fault handlers, we
needed to change the way we initiate a swap by removing the dependence
on svc #0.
Before __swap() is called, the system has already done an irq_lock().
Upon return from __swap(), the equivalent of an irq_lock() is done due
to restoration of the key value from the irq_lock preceeding the call.
For ARM V6M (M0/M0+), the pendsv bit is toggled and the irqs are
enabled. There is no priority masking in v6m, so it's just a global
enable. For ARM V7M, the priority mask has to be set to 0x0 to allow
for the pendsv IRQ to be taken. This is done for both via a call to
irq_unlock(0).
After this unlock, a pendsv irq will be taken, either at the tail end
of the current irq handling if we are in handler mode, or immediately
due to the pendsv being asserted (no other outstanding irqs). The next
thread will be scheduled.
Upon return from the context switch to the original
thread, the priority mask will already be correct due to the pendsv
processing.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
2018-02-22 14:22:45 +08:00
|
|
|
return _current->arch.swap_return_value;
|
|
|
|
}
|